Create composable use-edits-guard (#11018)

This commit is contained in:
José Varela
2022-01-13 16:49:01 +00:00
committed by GitHub
parent 161c9c80ca
commit dc393ed9ba
12 changed files with 74 additions and 155 deletions

View File

@@ -1,4 +0,0 @@
import unsavedChanges from './unsaved-changes';
export { unsavedChanges };
export default unsavedChanges;

View File

@@ -1,18 +0,0 @@
import { onBeforeMount, onBeforeUnmount, Ref } from 'vue';
export default function unsavedChanges(isSavable: Ref<boolean>): void {
onBeforeMount(() => {
window.addEventListener('beforeunload', beforeUnload);
});
onBeforeUnmount(() => {
window.removeEventListener('beforeunload', beforeUnload);
});
function beforeUnload(event: BeforeUnloadEvent) {
if (isSavable.value) {
event.preventDefault();
event.returnValue = '';
return '';
}
}
}

View File

@@ -0,0 +1,4 @@
import { useEditsGuard } from './use-edits-guard';
export { useEditsGuard };
export default useEditsGuard;

View File

@@ -0,0 +1,36 @@
import { ref, Ref, onBeforeMount, onBeforeUnmount } from 'vue';
import { onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } from 'vue-router';
export function useEditsGuard(isSavable: Ref<boolean>) {
const confirmLeave = ref(false);
const leaveTo = ref<string | null>(null);
const beforeUnload = (event: BeforeUnloadEvent) => {
if (isSavable.value) {
event.preventDefault();
event.returnValue = '';
return '';
}
};
const editsGuard: NavigationGuard = (to) => {
if (isSavable.value) {
confirmLeave.value = true;
leaveTo.value = to.fullPath;
return false;
}
};
onBeforeMount(() => {
window.addEventListener('beforeunload', beforeUnload);
});
onBeforeUnmount(() => {
window.removeEventListener('beforeunload', beforeUnload);
});
onBeforeRouteUpdate(editsGuard);
onBeforeRouteLeave(editsGuard);
return { confirmLeave, leaveTo };
}

View File

@@ -212,9 +212,9 @@ import SharesSidebarDetail from '@/views/private/components/shares-sidebar-detai
import useItem from '@/composables/use-item';
import SaveOptions from '@/views/private/components/save-options';
import useShortcut from '@/composables/use-shortcut';
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } from 'vue-router';
import { useRouter } from 'vue-router';
import { usePermissions } from '@/composables/use-permissions';
import unsavedChanges from '@/composables/unsaved-changes';
import useEditsGuard from '@/composables/use-edits-guard';
import { useTitle } from '@/composables/use-title';
import { renderStringTemplate } from '@/utils/render-string-template';
import useTemplateData from '@/composables/use-template-data';
@@ -302,14 +302,10 @@ export default defineComponent({
return hasEdits.value;
});
unsavedChanges(isSavable);
const { confirmLeave, leaveTo } = useEditsGuard(isSavable);
const confirmDelete = ref(false);
const confirmArchive = ref(false);
const confirmLeave = ref(false);
const leaveTo = ref<string | null>(null);
const title = computed(() => {
if (te(`collection_names_singular.${props.collection}`)) {
return isNew.value
@@ -349,16 +345,6 @@ export default defineComponent({
useShortcut('meta+s', saveAndStay, form);
useShortcut('meta+shift+s', saveAndAddNew, form);
const editsGuard: NavigationGuard = (to) => {
if (hasEdits.value) {
confirmLeave.value = true;
leaveTo.value = to.fullPath;
return false;
}
};
onBeforeRouteUpdate(editsGuard);
onBeforeRouteLeave(editsGuard);
const { deleteAllowed, archiveAllowed, saveAllowed, updateAllowed, shareAllowed, fields, revisionsAllowed } =
usePermissions(collection, item, isNew);

View File

@@ -88,11 +88,11 @@
</v-button>
<v-button
v-tooltip.bottom="saveAllowed ? t('save') : t('not_allowed')"
v-tooltip.bottom="isSavable ? t('save') : t('not_allowed')"
rounded
icon
:loading="saving"
:disabled="hasEdits === false || saveAllowed === false"
:disabled="!isSavable"
@click="saveAndQuit"
>
<v-icon name="check" />
@@ -180,7 +180,7 @@
import { useI18n } from 'vue-i18n';
import { defineComponent, computed, toRefs, ref, watch, ComponentPublicInstance } from 'vue';
import FilesNavigation from '../components/navigation.vue';
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } from 'vue-router';
import { useRouter } from 'vue-router';
import RevisionsDrawerDetail from '@/views/private/components/revisions-drawer-detail';
import CommentsSidebarDetail from '@/views/private/components/comments-sidebar-detail';
import useItem from '@/composables/use-item';
@@ -198,7 +198,7 @@ import ReplaceFile from '../components/replace-file.vue';
import { usePermissions } from '@/composables/use-permissions';
import { notify } from '@/utils/notify';
import { unexpectedError } from '@/utils/unexpected-error';
import unsavedChanges from '@/composables/unsaved-changes';
import useEditsGuard from '@/composables/use-edits-guard';
export default defineComponent({
name: 'FilesItem',
@@ -249,7 +249,9 @@ export default defineComponent({
validationErrors,
} = useItem(ref('directus_files'), primaryKey);
unsavedChanges(hasEdits);
const isSavable = computed(() => saveAllowed.value && hasEdits.value);
const { confirmLeave, leaveTo } = useEditsGuard(isSavable);
const confirmDelete = ref(false);
const editActive = ref(false);
@@ -285,23 +287,10 @@ export default defineComponent({
else return '/files';
});
const confirmLeave = ref(false);
const leaveTo = ref<string | null>(null);
const { moveToDialogActive, moveToFolder, moving, selectedFolder } = useMovetoFolder();
useShortcut('meta+s', saveAndStay, form);
const editsGuard: NavigationGuard = (to) => {
if (hasEdits.value) {
confirmLeave.value = true;
leaveTo.value = to.fullPath;
return false;
}
};
onBeforeRouteUpdate(editsGuard);
onBeforeRouteLeave(editsGuard);
const { deleteAllowed, saveAllowed, updateAllowed, fields, revisionsAllowed } = usePermissions(
ref('directus_files'),
item,
@@ -353,6 +342,7 @@ export default defineComponent({
fieldsFiltered,
revisionsAllowed,
validationErrors,
isSavable,
};
function useBreadcrumb() {

View File

@@ -106,10 +106,10 @@ import { useCollection } from '@directus/shared/composables';
import FieldsManagement from './components/fields-management.vue';
import useItem from '@/composables/use-item';
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } from 'vue-router';
import { useRouter } from 'vue-router';
import { useCollectionsStore, useFieldsStore } from '@/stores';
import useShortcut from '@/composables/use-shortcut';
import unsavedChanges from '@/composables/unsaved-changes';
import useEditsGuard from '@/composables/use-edits-guard';
export default defineComponent({
components: { SettingsNavigation, FieldsManagement },
@@ -160,20 +160,7 @@ export default defineComponent({
return hasEdits.value;
});
unsavedChanges(isSavable);
const confirmLeave = ref(false);
const leaveTo = ref<string | null>(null);
const editsGuard: NavigationGuard = (to) => {
if (hasEdits.value) {
confirmLeave.value = true;
leaveTo.value = to.fullPath;
return false;
}
};
onBeforeRouteUpdate(editsGuard);
onBeforeRouteLeave(editsGuard);
const { confirmLeave, leaveTo } = useEditsGuard(isSavable);
return {
t,

View File

@@ -141,11 +141,11 @@ import { Preset, Filter } from '@directus/shared/types';
import api from '@/api';
import { useCollectionsStore, usePresetsStore } from '@/stores';
import { getLayouts } from '@/layouts';
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } from 'vue-router';
import { useRouter } from 'vue-router';
import { unexpectedError } from '@/utils/unexpected-error';
import { useLayout } from '@directus/shared/composables';
import useShortcut from '@/composables/use-shortcut';
import unsavedChanges from '@/composables/unsaved-changes';
import useEditsGuard from '@/composables/use-edits-guard';
import { isEqual } from 'lodash';
type FormattedPreset = {
@@ -210,20 +210,7 @@ export default defineComponent({
return hasEdits.value;
});
unsavedChanges(isSavable);
const confirmLeave = ref(false);
const leaveTo = ref<string | null>(null);
const editsGuard: NavigationGuard = (to) => {
if (hasEdits.value) {
confirmLeave.value = true;
leaveTo.value = to.fullPath;
return false;
}
};
onBeforeRouteUpdate(editsGuard);
onBeforeRouteLeave(editsGuard);
const { confirmLeave, leaveTo } = useEditsGuard(isSavable);
return {
t,

View File

@@ -49,8 +49,8 @@ import { useSettingsStore, useServerStore } from '@/stores';
import ProjectInfoSidebarDetail from './components/project-info-sidebar-detail.vue';
import { clone } from 'lodash';
import useShortcut from '@/composables/use-shortcut';
import unsavedChanges from '@/composables/unsaved-changes';
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } from 'vue-router';
import useEditsGuard from '@/composables/use-edits-guard';
import { useRouter } from 'vue-router';
export default defineComponent({
components: { SettingsNavigation, ProjectInfoSidebarDetail },
@@ -81,20 +81,7 @@ export default defineComponent({
return noEdits.value;
});
unsavedChanges(isSavable);
const confirmLeave = ref(false);
const leaveTo = ref<string | null>(null);
const editsGuard: NavigationGuard = (to) => {
if (!noEdits.value) {
confirmLeave.value = true;
leaveTo.value = to.fullPath;
return false;
}
};
onBeforeRouteUpdate(editsGuard);
onBeforeRouteLeave(editsGuard);
const { confirmLeave, leaveTo } = useEditsGuard(isSavable);
return {
t,

View File

@@ -107,7 +107,7 @@ import { useI18n } from 'vue-i18n';
import { defineComponent, computed, toRefs, ref } from 'vue';
import SettingsNavigation from '../../../components/navigation.vue';
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } from 'vue-router';
import { useRouter } from 'vue-router';
import RevisionsDrawerDetail from '@/views/private/components/revisions-drawer-detail';
import useItem from '@/composables/use-item';
import { useUserStore } from '@/stores/';
@@ -115,7 +115,7 @@ import RoleInfoSidebarDetail from './components/role-info-sidebar-detail.vue';
import PermissionsOverview from './components/permissions-overview.vue';
import UsersInvite from '@/views/private/components/users-invite';
import useShortcut from '@/composables/use-shortcut';
import unsavedChanges from '@/composables/unsaved-changes';
import useEditsGuard from '@/composables/use-edits-guard';
export default defineComponent({
name: 'RolesItem',
@@ -173,20 +173,7 @@ export default defineComponent({
return hasEdits.value;
});
unsavedChanges(isSavable);
const confirmLeave = ref(false);
const leaveTo = ref<string | null>(null);
const editsGuard: NavigationGuard = (to) => {
if (hasEdits.value) {
confirmLeave.value = true;
leaveTo.value = to.fullPath;
return false;
}
};
onBeforeRouteUpdate(editsGuard);
onBeforeRouteLeave(editsGuard);
const { confirmLeave, leaveTo } = useEditsGuard(isSavable);
return {
t,

View File

@@ -88,12 +88,12 @@ import { useI18n } from 'vue-i18n';
import { defineComponent, computed, toRefs, ref } from 'vue';
import SettingsNavigation from '../../components/navigation.vue';
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } from 'vue-router';
import { useRouter } from 'vue-router';
import RevisionsDrawerDetail from '@/views/private/components/revisions-drawer-detail';
import useItem from '@/composables/use-item';
import SaveOptions from '@/views/private/components/save-options';
import useShortcut from '@/composables/use-shortcut';
import unsavedChanges from '@/composables/unsaved-changes';
import useEditsGuard from '@/composables/use-edits-guard';
export default defineComponent({
name: 'WebhooksItem',
@@ -148,20 +148,7 @@ export default defineComponent({
return hasEdits.value;
});
unsavedChanges(isSavable);
const confirmLeave = ref(false);
const leaveTo = ref<string | null>(null);
const editsGuard: NavigationGuard = (to) => {
if (hasEdits.value) {
confirmLeave.value = true;
leaveTo.value = to.fullPath;
return false;
}
};
onBeforeRouteUpdate(editsGuard);
onBeforeRouteLeave(editsGuard);
const { confirmLeave, leaveTo } = useEditsGuard(isSavable);
return {
t,

View File

@@ -74,11 +74,11 @@
</v-dialog>
<v-button
v-tooltip.bottom="saveAllowed ? t('save') : t('not_allowed')"
v-tooltip.bottom="isSavable ? t('save') : t('not_allowed')"
rounded
icon
:loading="saving"
:disabled="hasEdits === false || saveAllowed === false"
:disabled="!isSavable"
@click="saveAndQuit"
>
<v-icon name="check" />
@@ -185,7 +185,7 @@ import { defineComponent, computed, toRefs, ref, watch, ComponentPublicInstance
import UsersNavigation from '../components/navigation.vue';
import { setLanguage } from '@/lang/set-language';
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } from 'vue-router';
import { useRouter } from 'vue-router';
import RevisionsDrawerDetail from '@/views/private/components/revisions-drawer-detail';
import CommentsSidebarDetail from '@/views/private/components/comments-sidebar-detail';
import useItem from '@/composables/use-item';
@@ -203,7 +203,7 @@ import { usePermissions } from '@/composables/use-permissions';
import { unexpectedError } from '@/utils/unexpected-error';
import { addTokenToURL } from '@/api';
import { useUserStore } from '@/stores';
import unsavedChanges from '@/composables/unsaved-changes';
import useEditsGuard from '@/composables/use-edits-guard';
export default defineComponent({
name: 'UsersItem',
@@ -260,7 +260,9 @@ export default defineComponent({
};
}
unsavedChanges(hasEdits);
const isSavable = computed(() => saveAllowed.value && hasEdits.value);
const { confirmLeave, leaveTo } = useEditsGuard(isSavable);
const confirmDelete = ref(false);
const confirmArchive = ref(false);
@@ -280,19 +282,6 @@ export default defineComponent({
const { loading: previewLoading, avatarSrc, roleName } = useUserPreview();
const confirmLeave = ref(false);
const leaveTo = ref<string | null>(null);
const editsGuard: NavigationGuard = (to) => {
if (hasEdits.value) {
confirmLeave.value = true;
leaveTo.value = to.fullPath;
return false;
}
};
onBeforeRouteUpdate(editsGuard);
onBeforeRouteLeave(editsGuard);
const { deleteAllowed, archiveAllowed, saveAllowed, updateAllowed, revisionsAllowed, fields } = usePermissions(
ref('directus_users'),
item,
@@ -376,6 +365,7 @@ export default defineComponent({
validationErrors,
revert,
avatarError,
isSavable,
};
function useBreadcrumb() {