import { api } from 'boot/services'; import { merge } from 'lodash'; import { CREATE_TABLE, DELETE_TABLE, FETCH_TABLES, SAVE_TABLE_CHANGES, SAVE_TABLE_SETTINGS, FETCH_TABLE, INITIAL_SETTINGS, CANCEL_IMPORT, } from './constants'; import dashboardState from './state'; import { Settings, TableType, type Table } from './models'; import { QTableColumn } from 'quasar'; import { applySettingsPolicy } from 'src/helpers/settingsPolicyHelper'; /** * Stored settings -> the settings this plugin renders: defaults filled in for * sections older tables never stored, the pre-0.3 boolean `grid` normalized, * and settings owned by vTables Pro reset to their defaults (they stay * untouched in the database, see src/helpers/settingsPolicyHelper.ts). */ function toRenderedSettings(stored: Settings | null | undefined): Settings { const settings = (stored ?? {}) as Settings; if (typeof (settings as any)?.general?.grid === 'boolean') { const old = (settings as any).general.grid; settings.general.grid = { desktop: old, tablet: old, mobile: old }; } const initialSettings = JSON.parse(JSON.stringify(INITIAL_SETTINGS)); return applySettingsPolicy(merge(initialSettings, settings)); } export default { async [FETCH_TABLES]({ search, perPage, page, order, orderby, }: { search: string; perPage: number; page: number; order?: 'ASC' | 'DESC'; orderby?: string; }) { const { response, error } = await api.fetchTables({ page, perPage, search, order, orderby, }); if (error) { return { error }; } const tables = response.data?.tables.map((el: Table) => ({ ...el, shortcode: `[vtables id=${el.id}]`, settings: toRenderedSettings(el.settings), })); dashboardState.tables.value = tables; dashboardState.totalPerQuery.value = response.data?.total; if (!search) { dashboardState.totalInDb.value = response.data?.total; } return { response }; }, async [FETCH_TABLE](id: string) { const { response, error } = await api.fetchTable(id); if (error) { return { error }; } // Pro-only tables come back as metadata; nothing to render here. if (response.data?.requires_pro) { return { response }; } const { source } = response.data; const settings = response.data.settings ?? {}; settings.columns = settings.columns ?? {}; settings.columns.visibleColumns = settings.columns.visibleColumns ?? []; const newColumns = source.columns.reduce( (acc: string[], el: QTableColumn) => { if (dashboardState.selectedTable.value) { const isColumnPresent = dashboardState.selectedTable.value.source.columns.find( (col: QTableColumn) => col.name === el.name ); if (isColumnPresent) { return acc; } const columnNotIncludedInVisibleColumns = !dashboardState.selectedTable.value?.settings.columns.visibleColumns.includes( el.name ); if (columnNotIncludedInVisibleColumns) { acc.push(el.name); } } return acc; }, [] ); if (newColumns.length) { settings.columns.visibleColumns = [ ...settings.columns.visibleColumns, ...newColumns, ]; } response.data = { ...response.data, shortcode: `[vtables id=${response.data.id}]`, settings: toRenderedSettings(settings), }; // Server-mode tables ship page 1 under `first_page` with an empty `source.rows`. // Fold it into the canonical rows location so all readers stay uniform. if (response.data.server_mode && Array.isArray(response.data.first_page)) { response.data.source.rows = response.data.first_page; } return { response }; }, async [SAVE_TABLE_CHANGES](payload: { id: string; title: string; source?: Record; fileSize?: string; }) { const { response, error } = await api.saveTableChanges(payload); if (error) { return { error }; } if (dashboardState.selectedTable.value) { const tableId = dashboardState.selectedTable.value.id; const tableToUpdate = dashboardState.tables.value.find( (el: Table) => el.id === tableId ); if (tableToUpdate && response.success) { tableToUpdate.title = response.data.title; tableToUpdate.updated_at = response.data.updated_at; if (payload.source) { tableToUpdate.file_size = response.data.file_size; } } } return { response }; }, async [SAVE_TABLE_SETTINGS](payload: { id: string; settings: Record; }) { const { response, error } = await api.saveTableSettings(payload); if (error) { return { error }; } if (dashboardState.selectedTable.value) { const tableId = dashboardState.selectedTable.value.id; const tableToUpdate = dashboardState.tables.value.find( (el: Table) => el.id === tableId ); if (tableToUpdate && response.success) { tableToUpdate.updated_at = response.data.updated_at; } } return { response }; }, async [DELETE_TABLE](id: string) { const { error } = await api.deleteTable(id); if (error) { return { error }; } dashboardState.tables.value = dashboardState.tables.value.filter( (table: Table) => Number(table.id) !== Number(id) ); if (!dashboardState.tables.value.length) { dashboardState.totalInDb.value = 0; } }, async [CREATE_TABLE](payload: { title: string; source: Record; fileSize: string; settings: Settings; tableType?: TableType; }) { const { response, error } = await api.createTable(payload); if (error) { return { error }; } return { response }; }, async [CANCEL_IMPORT](tableId: string | number) { const { response, error } = await api.cancelImport(tableId); if (error) { return { error }; } dashboardState.tables.value = dashboardState.tables.value.filter( (table: Table) => Number(table.id) !== Number(tableId) ); return { response }; }, };