Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 32 additions & 4 deletions adminforth/spa/src/views/CreateView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

<BreadcrumbsWithButtons>
<!-- save and cancle -->
<button @click="$router.back()"
<button @click="() => {cancelButtonClicked = true; $router.back()}"
class="af-cancel-button flex items-center py-1 px-3 me-2 text-sm font-medium rounded-default text-lightCreateViewButtonText focus:outline-none bg-lightCreateViewButtonBackground rounded border border-lightCreateViewButtonBorder hover:bg-lightCreateViewButtonBackgroundHover hover:text-lightCreateViewButtonTextHover focus:z-10 focus:ring-4 focus:ring-lightCreateViewButtonFocusRing dark:focus:ring-darkCreateViewButtonFocusRing dark:bg-darkCreateViewButtonBackground dark:text-darkCreateViewButtonText dark:border-darkCreateViewButtonBorder dark:hover:text-darkCreateViewButtonTextHover dark:hover:bg-darkCreateViewButtonBackgroundHover"
>
{{ $t('Cancel') }}
Expand Down Expand Up @@ -81,8 +81,8 @@ import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
import { useCoreStore } from '@/stores/core';
import { callAdminForthApi, getCustomComponent,checkAcessByAllowedActions, initThreeDotsDropdown, checkShowIf } from '@/utils';
import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
import { onMounted, onBeforeMount, ref, watch, nextTick } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { onMounted, onBeforeMount, onBeforeUnmount, ref, watch, nextTick } from 'vue';
import { useRoute, useRouter, onBeforeRouteLeave } from 'vue-router';
import { computed } from 'vue';
import { showErrorTost } from '@/composables/useFrontendApi';
import ThreeDotsMenu from '@/components/ThreeDotsMenu.vue';
Expand All @@ -103,7 +103,7 @@ const router = useRouter();
const record = ref({});

const coreStore = useCoreStore();
const { clearSaveInterceptors, runSaveInterceptors, alert } = useAdminforth();
const { clearSaveInterceptors, runSaveInterceptors, alert, confirm } = useAdminforth();

const { t } = useI18n();

Expand All @@ -113,11 +113,38 @@ const initialValues = ref({});

const readonlyColumns = ref([]);

const cancelButtonClicked = ref(false);
const wasSaveSuccessful = ref(false);

async function onUpdateRecord(newRecord: any) {
record.value = newRecord;
}

function checkIfWeCanLeavePage() {
return wasSaveSuccessful.value || cancelButtonClicked.value || JSON.stringify(record.value) === JSON.stringify(initialValues.value);
}

function onBeforeUnload(event: BeforeUnloadEvent) {
if (!checkIfWeCanLeavePage()) {
event.preventDefault();
event.returnValue = '';
}
}

window.addEventListener('beforeunload', onBeforeUnload);

onBeforeUnmount(() => {
window.removeEventListener('beforeunload', onBeforeUnload);
});

onBeforeRouteLeave(async (to, from, next) => {
if (!checkIfWeCanLeavePage()) {
const answer = await confirm({message: t('There are unsaved changes. Are you sure you want to leave this page?'), yes: 'Yes', no: 'No'});
if (!answer) return next(false);
}
next();
});

onBeforeMount(() => {
clearSaveInterceptors(route.params.resourceId as string);
});
Expand Down Expand Up @@ -202,6 +229,7 @@ async function saveRecord() {
showErrorTost(response.error);
} else {
saving.value = false;
wasSaveSuccessful.value = true;
if (route.query.returnTo) {
router.push(<string>route.query.returnTo);
} else {
Expand Down
68 changes: 51 additions & 17 deletions adminforth/spa/src/views/EditView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@

<BreadcrumbsWithButtons>
<!-- save and cancle -->
<button @click="$router.back()"
<button @click="() => {cancelButtonClicked = true; $router.back()}"
class="flex items-center py-1 px-3 me-2 text-sm font-medium text-lightEditViewButtonText rounded-default focus:outline-none bg-lightEditViewButtonBackground rounded border border-lightEditViewButtonBorder hover:bg-lightEditViewButtonBackgroundHover hover:text-lightEditViewButtonTextHover focus:z-10 focus:ring-4 focus:ring-lightEditViewButtonFocusRing dark:focus:ring-darkEditViewButtonFocusRing dark:bg-darkEditViewButtonBackground dark:text-darkEditViewButtonText dark:border-darkEditViewButtonBorder dark:hover:text-darkEditViewButtonTextHover dark:hover:bg-darkEditViewButtonBackgroundHover"
>
{{ $t('Cancel') }}
Expand Down Expand Up @@ -76,8 +76,8 @@ import SingleSkeletLoader from '@/components/SingleSkeletLoader.vue';
import { useCoreStore } from '@/stores/core';
import { callAdminForthApi, getCustomComponent,checkAcessByAllowedActions, initThreeDotsDropdown } from '@/utils';
import { IconFloppyDiskSolid } from '@iconify-prerendered/vue-flowbite';
import { computed, onMounted, onBeforeMount, ref, type Ref, nextTick, watch } from 'vue';
import { useRoute, useRouter } from 'vue-router';
import { computed, onMounted, onBeforeMount, ref, type Ref, nextTick, watch, onBeforeUnmount } from 'vue';
import { useRoute, useRouter, onBeforeRouteLeave } from 'vue-router';
import { showErrorTost } from '@/composables/useFrontendApi';
import ThreeDotsMenu from '@/components/ThreeDotsMenu.vue';
import { useAdminforth } from '@/adminforth';
Expand All @@ -87,7 +87,7 @@ import type { AdminForthResourceColumn } from '@/types/Back';

const { t } = useI18n();
const coreStore = useCoreStore();
const { clearSaveInterceptors, runSaveInterceptors, alert } = useAdminforth();
const { clearSaveInterceptors, runSaveInterceptors, alert, confirm } = useAdminforth();

const isValid = ref(false);
const validating = ref(false);
Expand All @@ -101,6 +101,36 @@ const saving = ref(false);

const record: Ref<Record<string, any>> = ref({});

const initialRecord = computed(() => coreStore.record);
const wasSaveSuccessful = ref(false);
const cancelButtonClicked = ref(false);

function onBeforeUnload(event: BeforeUnloadEvent) {
if (!checkIfWeCanLeavePage()) {
event.preventDefault();
event.returnValue = '';
}
}

function checkIfWeCanLeavePage() {
return wasSaveSuccessful.value || cancelButtonClicked.value || JSON.stringify(record.value) === JSON.stringify(initialRecord.value);
}

window.addEventListener('beforeunload', onBeforeUnload);

onBeforeUnmount(() => {
window.removeEventListener('beforeunload', onBeforeUnload);
});

onBeforeRouteLeave(async (to, from, next) => {
if (!checkIfWeCanLeavePage()) {
const answer = await confirm({message: t('There are unsaved changes. Are you sure you want to leave this page?'), yes: 'Yes', no: 'No'});
if (!answer) return next(false);
}
next();
});


watch(record, (newVal) => {
console.log('Record updated:', newVal);
}, { deep: true });
Expand Down Expand Up @@ -198,24 +228,28 @@ async function saveRecord() {
if (columnIsUpdated) {
updates[key] = record.value[key];
}
saving.value = false;
}

const resp = await callAdminForthApi({
method: 'POST',
path: `/update_record`,
body: {
resourceId: route.params.resourceId,
recordId: route.params.primaryKey,
record: updates,
meta: {
...(interceptorConfirmationResult ? { confirmationResult: interceptorConfirmationResult } : {}),
let resp = null;
try {
resp = await callAdminForthApi({
method: 'POST',
path: `/update_record`,
body: {
resourceId: route.params.resourceId,
recordId: route.params.primaryKey,
record: updates,
meta: {
...(interceptorConfirmationResult ? { confirmationResult: interceptorConfirmationResult } : {}),
},
},
},
});
});
} finally {
saving.value = false;
}
if (resp.error && resp.error !== 'Operation aborted by hook') {
showErrorTost(resp.error);
} else {
wasSaveSuccessful.value = true;
alert({
message: t('Record updated successfully'),
variant: 'success',
Expand Down