Add discard confirmation prompt for project settings (#8373)

This commit is contained in:
ian
2021-09-29 06:58:16 +08:00
committed by GitHub
parent ec32c9e0fe
commit ff99d0aad8
5 changed files with 241 additions and 5 deletions

View File

@@ -80,6 +80,19 @@
<div v-md="t('page_help_settings_datamodel_fields')" class="page-description" />
</sidebar-detail>
</template>
<v-dialog v-model="confirmLeave" @esc="confirmLeave = false">
<v-card>
<v-card-title>{{ t('unsaved_changes') }}</v-card-title>
<v-card-text>{{ t('unsaved_changes_copy') }}</v-card-text>
<v-card-actions>
<v-button secondary @click="discardAndLeave">
{{ t('discard_changes') }}
</v-button>
<v-button @click="confirmLeave = false">{{ t('keep_editing') }}</v-button>
</v-card-actions>
</v-card>
</v-dialog>
</private-view>
</template>
@@ -91,8 +104,9 @@ import { useCollection } from '@directus/shared/composables';
import FieldsManagement from './components/fields-management.vue';
import useItem from '@/composables/use-item';
import { useRouter } from 'vue-router';
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } from 'vue-router';
import { useCollectionsStore, useFieldsStore } from '@/stores';
import unsavedChanges from '@/composables/unsaved-changes';
export default defineComponent({
components: { SettingsNavigation, FieldsManagement },
@@ -131,6 +145,26 @@ export default defineComponent({
const confirmDelete = ref(false);
const isSavable = computed(() => {
if (hasEdits.value === true) return true;
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);
return {
t,
collectionInfo,
@@ -150,6 +184,10 @@ export default defineComponent({
deleteAndQuit,
saveAndQuit,
hasEdits,
isSavable,
confirmLeave,
leaveTo,
discardAndLeave,
};
async function deleteAndQuit() {
@@ -165,6 +203,13 @@ export default defineComponent({
await fieldsStore.hydrate();
router.push(`/settings/data-model`);
}
function discardAndLeave() {
if (!leaveTo.value) return;
edits.value = {};
confirmLeave.value = false;
router.push(leaveTo.value);
}
},
});
</script>

View File

@@ -113,6 +113,19 @@
</sidebar-detail>
</div>
</template>
<v-dialog v-model="confirmLeave" @esc="confirmLeave = false">
<v-card>
<v-card-title>{{ t('unsaved_changes') }}</v-card-title>
<v-card-text>{{ t('unsaved_changes_copy') }}</v-card-text>
<v-card-actions>
<v-button secondary @click="discardAndLeave">
{{ t('discard_changes') }}
</v-button>
<v-button @click="confirmLeave = false">{{ t('keep_editing') }}</v-button>
</v-card-actions>
</v-card>
</v-dialog>
</private-view>
</component>
</template>
@@ -126,9 +139,10 @@ import { Preset, Filter } from '@directus/shared/types';
import api from '@/api';
import { useCollectionsStore, usePresetsStore } from '@/stores';
import { getLayouts } from '@/layouts';
import { useRouter } from 'vue-router';
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } from 'vue-router';
import { unexpectedError } from '@/utils/unexpected-error';
import { useLayout } from '@/composables/use-layout';
import unsavedChanges from '@/composables/unsaved-changes';
type FormattedPreset = {
id: number;
@@ -184,6 +198,26 @@ export default defineComponent({
const { layoutWrapper } = useLayout(layout);
const isSavable = computed(() => {
if (hasEdits.value === true) return true;
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);
return {
t,
backLink,
@@ -205,6 +239,10 @@ export default defineComponent({
confirmDelete,
updateFilters,
searchQuery,
isSavable,
confirmLeave,
leaveTo,
discardAndLeave,
};
function useSave() {
@@ -496,6 +534,13 @@ export default defineComponent({
return { fields };
}
function discardAndLeave() {
if (!leaveTo.value) return;
edits.value = {};
confirmLeave.value = false;
router.push(leaveTo.value);
}
},
});
</script>

View File

@@ -24,6 +24,19 @@
<template #sidebar>
<project-info-sidebar-detail />
</template>
<v-dialog v-model="confirmLeave" @esc="confirmLeave = false">
<v-card>
<v-card-title>{{ t('unsaved_changes') }}</v-card-title>
<v-card-text>{{ t('unsaved_changes_copy') }}</v-card-text>
<v-card-actions>
<v-button secondary @click="discardAndLeave">
{{ t('discard_changes') }}
</v-button>
<v-button @click="confirmLeave = false">{{ t('keep_editing') }}</v-button>
</v-card-actions>
</v-card>
</v-dialog>
</private-view>
</template>
@@ -35,12 +48,16 @@ import { useCollection } from '@directus/shared/composables';
import { useSettingsStore, useServerStore } from '@/stores';
import ProjectInfoSidebarDetail from './components/project-info-sidebar-detail.vue';
import { clone } from 'lodash';
import unsavedChanges from '@/composables/unsaved-changes';
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } from 'vue-router';
export default defineComponent({
components: { SettingsNavigation, ProjectInfoSidebarDetail },
setup() {
const { t } = useI18n();
const router = useRouter();
const settingsStore = useSettingsStore();
const serverStore = useServerStore();
@@ -54,7 +71,39 @@ export default defineComponent({
const saving = ref(false);
return { t, fields, initialValues, edits, noEdits, saving, save };
const isSavable = computed(() => {
if (noEdits.value === true) return false;
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);
return {
t,
fields,
initialValues,
edits,
noEdits,
saving,
isSavable,
confirmLeave,
leaveTo,
save,
discardAndLeave,
};
async function save() {
if (edits.value === null) return;
@@ -65,6 +114,13 @@ export default defineComponent({
saving.value = false;
initialValues.value = clone(settingsStore.settings);
}
function discardAndLeave() {
if (!leaveTo.value) return;
edits.value = {};
confirmLeave.value = false;
router.push(leaveTo.value);
}
},
});
</script>

View File

@@ -84,6 +84,19 @@
<role-info-sidebar-detail :role="item" />
<revisions-drawer-detail collection="directus_roles" :primary-key="primaryKey" />
</template>
<v-dialog v-model="confirmLeave" @esc="confirmLeave = false">
<v-card>
<v-card-title>{{ t('unsaved_changes') }}</v-card-title>
<v-card-text>{{ t('unsaved_changes_copy') }}</v-card-text>
<v-card-actions>
<v-button secondary @click="discardAndLeave">
{{ t('discard_changes') }}
</v-button>
<v-button @click="confirmLeave = false">{{ t('keep_editing') }}</v-button>
</v-card-actions>
</v-card>
</v-dialog>
</private-view>
</template>
@@ -92,13 +105,14 @@ import { useI18n } from 'vue-i18n';
import { defineComponent, computed, toRefs, ref } from 'vue';
import SettingsNavigation from '../../../components/navigation.vue';
import { useRouter } from 'vue-router';
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } from 'vue-router';
import RevisionsDrawerDetail from '@/views/private/components/revisions-drawer-detail';
import useItem from '@/composables/use-item';
import { useUserStore } from '@/stores/';
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 unsavedChanges from '@/composables/unsaved-changes';
export default defineComponent({
name: 'RolesItem',
@@ -149,6 +163,26 @@ export default defineComponent({
return !!values.app_access;
});
const isSavable = computed(() => {
if (hasEdits.value === true) return true;
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);
return {
t,
item,
@@ -165,6 +199,10 @@ export default defineComponent({
adminEnabled,
userInviteModalActive,
appAccess,
isSavable,
confirmLeave,
leaveTo,
discardAndLeave,
};
/**
@@ -184,6 +222,13 @@ export default defineComponent({
await remove();
router.push(`/settings/roles`);
}
function discardAndLeave() {
if (!leaveTo.value) return;
edits.value = {};
confirmLeave.value = false;
router.push(leaveTo.value);
}
},
});
</script>

View File

@@ -64,6 +64,19 @@
</sidebar-detail>
<revisions-drawer-detail v-if="isNew === false" collection="directus_webhooks" :primary-key="primaryKey" />
</template>
<v-dialog v-model="confirmLeave" @esc="confirmLeave = false">
<v-card>
<v-card-title>{{ t('unsaved_changes') }}</v-card-title>
<v-card-text>{{ t('unsaved_changes_copy') }}</v-card-text>
<v-card-actions>
<v-button secondary @click="discardAndLeave">
{{ t('discard_changes') }}
</v-button>
<v-button @click="confirmLeave = false">{{ t('keep_editing') }}</v-button>
</v-card-actions>
</v-card>
</v-dialog>
</private-view>
</template>
@@ -72,10 +85,11 @@ import { useI18n } from 'vue-i18n';
import { defineComponent, computed, toRefs, ref } from 'vue';
import SettingsNavigation from '../../components/navigation.vue';
import { useRouter } from 'vue-router';
import { useRouter, onBeforeRouteUpdate, onBeforeRouteLeave, NavigationGuard } 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 unsavedChanges from '@/composables/unsaved-changes';
export default defineComponent({
name: 'WebhooksItem',
@@ -117,6 +131,26 @@ export default defineComponent({
return item.value?.name;
});
const isSavable = computed(() => {
if (hasEdits.value === true) return true;
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);
return {
t,
item,
@@ -136,6 +170,10 @@ export default defineComponent({
isBatch,
title,
validationErrors,
isSavable,
confirmLeave,
leaveTo,
discardAndLeave,
};
async function saveAndQuit() {
@@ -161,6 +199,13 @@ export default defineComponent({
await remove();
router.push(`/settings/webhooks`);
}
function discardAndLeave() {
if (!leaveTo.value) return;
edits.value = {};
confirmLeave.value = false;
router.push(leaveTo.value);
}
},
});
</script>