import { ComputedRef, Ref, ref } from 'vue'; import { Router } from 'vue-router'; import { useQuasar } from 'quasar'; import { useI18n } from 'vue-i18n'; import { buildSettingsPayloadForSave } from 'src/helpers/settingsSaveHelper'; import { usePendingRowChanges } from 'src/composables/usePendingRowChanges'; import type { Table } from '../stores/main/models'; interface Params { selectedTable: Ref; loading: Ref; isAdminPage: ComputedRef; saveTableChanges: (payload: any) => Promise; saveTableSettings: (payload: any) => Promise; deleteTable: (id: string) => Promise; router: Router; } export function useTableActions({ selectedTable, loading, isAdminPage, saveTableChanges, saveTableSettings, deleteTable, router, }: Params) { const $q = useQuasar(); const { t } = useI18n(); const { flushPendingRowChanges } = usePendingRowChanges(); const tableMaximized: Ref = ref(false); const showSettings: Ref = ref(false); const showTitleDialog: Ref = ref(false); const deleting: Ref = ref(false); async function goBack() { // Clear only after the navigation went through: the unsaved-changes guard // on the table page (TablePage's onBeforeRouteLeave) may cancel it, and // the table must stay rendered in that case. const failure = await router.push('/'); if (!failure) selectedTable.value = null; } async function updateTableName(title: string) { if (!selectedTable.value) return; selectedTable.value.title = title; showTitleDialog.value = false; } async function saveSettings() { if (!selectedTable.value?.settings) return; loading.value = true; // Server-mode row changes (cell edits, added/deleted rows) are staged in // memory until this Save; write them first. No-op when nothing is staged. // On failure the unwritten changes stay staged, so another Save retries. const { error: flushError } = await flushPendingRowChanges( selectedTable.value.id ); if (flushError) { loading.value = false; $q.notify({ type: 'negative', message: t('messages.unable_to_save_changes'), caption: t('messages.something_went_wrong'), }); return; } // Server-mode tables hold one page only; their rows are written by the // row endpoints above, never by replacing the whole source. const source = { ...selectedTable.value.source }; if (selectedTable.value.server_mode) { source.rows = []; } const { error: saveChangesError } = await saveTableChanges({ id: selectedTable.value.id, title: selectedTable.value.title, source, }); if (saveChangesError) { loading.value = false; $q.notify({ type: 'negative', message: t('messages.unable_to_save_changes'), caption: t('messages.something_went_wrong'), }); return; } const { error: saveSettingsError } = await saveTableSettings({ id: selectedTable.value.id, settings: buildSettingsPayloadForSave(selectedTable.value.settings), }); loading.value = false; if (saveSettingsError) { $q.notify({ type: 'negative', message: t('messages.unable_to_save_changes'), caption: t('messages.something_went_wrong'), }); return; } $q.notify({ type: 'positive', message: t('messages.changes_have_been_saved'), }); } function onShowSettings() { showSettings.value = !showSettings.value; } async function onDeleteTable(id: string) { deleting.value = true; await deleteTable(id); deleting.value = false; goBack(); } function toggleFullscreen(props: any) { props.toggleFullscreen(); tableMaximized.value = !tableMaximized.value; } function toggleTitleDialog() { if (isAdminPage.value) { showTitleDialog.value = true; } } return { tableMaximized, showSettings, showTitleDialog, deleting, goBack, updateTableName, saveSettings, onShowSettings, onDeleteTable, toggleFullscreen, toggleTitleDialog, }; }