Browse Source

Merge branch 'develop' into feat/pnpm

pull/5903/head
Wing-Kam Wong 1 year ago
parent
commit
63426d49d0
  1. 29
      packages/nc-gui/components/cell/DatePicker.vue
  2. 21
      packages/nc-gui/components/cell/DateTimePicker.vue
  3. 75
      packages/nc-gui/composables/useViewData.ts
  4. 24
      tests/playwright/tests/db/undo-redo.spec.ts

29
packages/nc-gui/components/cell/DatePicker.vue

@ -2,6 +2,7 @@
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { import {
ActiveCellInj, ActiveCellInj,
CellClickHookInj,
ColumnInj, ColumnInj,
EditModeInj, EditModeInj,
ReadonlyInj, ReadonlyInj,
@ -165,6 +166,31 @@ useSelectedCellKeyupListener(active, (e: KeyboardEvent) => {
break break
} }
}) })
// use the default date picker open sync only to close the picker
const updateOpen = (next: boolean) => {
if (open.value && !next) {
open.value = false
}
}
const cellClickHook = inject(CellClickHookInj, null)
const cellClickHandler = () => {
open.value = (active.value || editable.value) && !open.value
}
onMounted(() => {
cellClickHook?.on(cellClickHandler)
})
onUnmounted(() => {
cellClickHook?.on(cellClickHandler)
})
const clickHandler = () => {
if (cellClickHook) {
return
}
cellClickHandler()
}
</script> </script>
<template> <template>
@ -179,7 +205,8 @@ useSelectedCellKeyupListener(active, (e: KeyboardEvent) => {
:input-read-only="true" :input-read-only="true"
:dropdown-class-name="`${randomClass} nc-picker-date ${open ? 'active' : ''}`" :dropdown-class-name="`${randomClass} nc-picker-date ${open ? 'active' : ''}`"
:open="(readOnly || (localState && isPk)) && !active && !editable ? false : open" :open="(readOnly || (localState && isPk)) && !active && !editable ? false : open"
@click="open = (active || editable) && !open" @click="clickHandler"
@update:open="updateOpen"
> >
<template #suffixIcon></template> <template #suffixIcon></template>
</a-date-picker> </a-date-picker>

21
packages/nc-gui/components/cell/DateTimePicker.vue

@ -2,6 +2,7 @@
import dayjs from 'dayjs' import dayjs from 'dayjs'
import { import {
ActiveCellInj, ActiveCellInj,
CellClickHookInj,
ColumnInj, ColumnInj,
ReadonlyInj, ReadonlyInj,
dateFormats, dateFormats,
@ -213,6 +214,24 @@ useSelectedCellKeyupListener(active, (e: KeyboardEvent) => {
break break
} }
}) })
const cellClickHook = inject(CellClickHookInj, null)
const cellClickHandler = () => {
open.value = (active.value || editable.value) && !open.value
}
onMounted(() => {
cellClickHook?.on(cellClickHandler)
})
onUnmounted(() => {
cellClickHook?.on(cellClickHandler)
})
const clickHandler = () => {
if (cellClickHook) {
return
}
cellClickHandler()
}
</script> </script>
<template> <template>
@ -229,7 +248,7 @@ useSelectedCellKeyupListener(active, (e: KeyboardEvent) => {
:dropdown-class-name="`${randomClass} nc-picker-datetime ${open ? 'active' : ''}`" :dropdown-class-name="`${randomClass} nc-picker-datetime ${open ? 'active' : ''}`"
:open="readOnly || (localState && isPk) ? false : open && (active || editable)" :open="readOnly || (localState && isPk) ? false : open && (active || editable)"
:disabled="readOnly || (localState && isPk)" :disabled="readOnly || (localState && isPk)"
@click="open = (active || editable) && !open" @click="clickHandler"
@ok="open = !open" @ok="open = !open"
> >
<template #suffixIcon></template> <template #suffixIcon></template>

75
packages/nc-gui/composables/useViewData.ts

@ -1,5 +1,16 @@
import { UITypes, ViewTypes } from 'nocodb-sdk' import { UITypes, ViewTypes } from 'nocodb-sdk'
import type { Api, ColumnType, FormColumnType, FormType, GalleryType, PaginatedType, TableType, ViewType } from 'nocodb-sdk' import type {
Api,
ColumnType,
FormColumnType,
FormType,
GalleryType,
LinkToAnotherRecordType,
PaginatedType,
RelationTypes,
TableType,
ViewType,
} from 'nocodb-sdk'
import type { ComputedRef, Ref } from 'vue' import type { ComputedRef, Ref } from 'vue'
import type { CellRange } from '#imports' import type { CellRange } from '#imports'
import { import {
@ -54,7 +65,7 @@ export function useViewData(
const { appInfo } = $(useGlobal()) const { appInfo } = $(useGlobal())
const { getMeta } = useMetas() const { getMeta, metas } = useMetas()
const { addUndo, clone, defineViewScope } = useUndoRedo() const { addUndo, clone, defineViewScope } = useUndoRedo()
@ -335,7 +346,7 @@ export function useViewData(
try { try {
const id = extractPkFromRow(toUpdate.row, metaValue?.columns as ColumnType[]) const id = extractPkFromRow(toUpdate.row, metaValue?.columns as ColumnType[])
const updatedRowData = await $api.dbViewRow.update( const updatedRowData: Record<string, any> = await $api.dbViewRow.update(
NOCO, NOCO,
project?.value.id as string, project?.value.id as string,
metaValue?.id as string, metaValue?.id as string,
@ -575,6 +586,62 @@ export function useViewData(
$e('a:grid:pagination') $e('a:grid:pagination')
} }
const linkRecord = async (
rowId: string,
relatedRowId: string,
column: ColumnType,
type: RelationTypes,
{ metaValue = meta.value }: { metaValue?: TableType } = {},
) => {
try {
await $api.dbTableRow.nestedAdd(
NOCO,
project.value.title as string,
metaValue?.title as string,
rowId,
type as 'mm' | 'hm',
column.title as string,
relatedRowId,
)
} catch (e: any) {
message.error(await extractSdkResponseErrorMsg(e))
}
}
// Recover LTAR relations for a row using the row data
const recoverLTARRefs = async (row: Record<string, any>, { metaValue = meta.value }: { metaValue?: TableType } = {}) => {
const id = extractPkFromRow(row, metaValue?.columns as ColumnType[])
for (const column of metaValue?.columns ?? []) {
if (column.uidt !== UITypes.LinkToAnotherRecord) continue
const colOptions = column.colOptions as LinkToAnotherRecordType
const relatedTableMeta = metas.value?.[colOptions?.fk_related_model_id as string]
if (isHm(column) || isMm(column)) {
const relatedRows = (row[column.title!] ?? []) as Record<string, any>[]
for (const relatedRow of relatedRows) {
await linkRecord(
id,
extractPkFromRow(relatedRow, relatedTableMeta.columns as ColumnType[]),
column,
colOptions.type as RelationTypes,
{ metaValue },
)
}
} else if (isBt(column) && row[column.title!]) {
await linkRecord(
id,
extractPkFromRow(row[column.title!] as Record<string, any>, relatedTableMeta.columns as ColumnType[]),
column,
colOptions.type as RelationTypes,
{ metaValue },
)
}
}
}
async function deleteRowById( async function deleteRowById(
id: string, id: string,
{ metaValue = meta.value, viewMetaValue = viewMeta.value }: { metaValue?: TableType; viewMetaValue?: ViewType } = {}, { metaValue = meta.value, viewMetaValue = viewMeta.value }: { metaValue?: TableType; viewMetaValue?: ViewType } = {},
@ -638,6 +705,7 @@ export function useViewData(
const pkData = rowPkData(row.row, meta.value?.columns as ColumnType[]) const pkData = rowPkData(row.row, meta.value?.columns as ColumnType[])
row.row = { ...pkData, ...row.row } row.row = { ...pkData, ...row.row }
await insertRow(row, ltarState, {}, true) await insertRow(row, ltarState, {}, true)
recoverLTARRefs(row.row)
if (rowIndex !== -1 && pg.pageSize === paginationData.value.pageSize) { if (rowIndex !== -1 && pg.pageSize === paginationData.value.pageSize) {
if (pg.page === paginationData.value.page) { if (pg.page === paginationData.value.page) {
formattedData.value.splice(rowIndex, 0, row) formattedData.value.splice(rowIndex, 0, row)
@ -714,6 +782,7 @@ export function useViewData(
const pkData = rowPkData(row.row, meta.value?.columns as ColumnType[]) const pkData = rowPkData(row.row, meta.value?.columns as ColumnType[])
row.row = { ...pkData, ...row.row } row.row = { ...pkData, ...row.row }
await insertRow(row, {}, {}, true) await insertRow(row, {}, {}, true)
recoverLTARRefs(row.row)
if (rowIndex !== -1 && pg.pageSize === paginationData.value.pageSize) { if (rowIndex !== -1 && pg.pageSize === paginationData.value.pageSize) {
if (pg.page === paginationData.value.page) { if (pg.page === paginationData.value.page) {
formattedData.value.splice(rowIndex, 0, row) formattedData.value.splice(rowIndex, 0, row)

24
tests/playwright/tests/db/undo-redo.spec.ts

@ -5,6 +5,7 @@ import { Api, UITypes } from 'nocodb-sdk';
import { rowMixedValue } from '../../setup/xcdb-records'; import { rowMixedValue } from '../../setup/xcdb-records';
import { GridPage } from '../../pages/Dashboard/Grid'; import { GridPage } from '../../pages/Dashboard/Grid';
import { ToolbarPage } from '../../pages/Dashboard/common/Toolbar'; import { ToolbarPage } from '../../pages/Dashboard/common/Toolbar';
import { isSqlite } from '../../setup/db';
let dashboard: DashboardPage, let dashboard: DashboardPage,
grid: GridPage, grid: GridPage,
@ -589,6 +590,29 @@ test.describe('Undo Redo - LTAR', () => {
await undo({ page, values: ['Mumbai'] }); await undo({ page, values: ['Mumbai'] });
await undo({ page, values: [] }); await undo({ page, values: [] });
}); });
test('Row with links: Delete & Undo', async ({ page }) => {
// SQLite has foreign key constraint disabled by default & hence below test
// will work even for ext DB
if (!isSqlite(context)) test.skip();
await dashboard.closeTab({ title: 'Team & Auth' });
await dashboard.treeView.openTable({ title: 'Country' });
await grid.cell.inCellAdd({ index: 0, columnHeader: 'CityList' });
await dashboard.linkRecord.select('Mumbai');
await grid.cell.inCellAdd({ index: 0, columnHeader: 'CityList' });
await dashboard.linkRecord.select('Delhi');
await grid.deleteRow(0, 'Country');
await dashboard.rootPage.waitForTimeout(200);
await page.keyboard.press((await grid.isMacOs()) ? 'Meta+z' : 'Control+z');
await dashboard.rootPage.waitForTimeout(200);
await verifyRecords(['Mumbai', 'Delhi']);
await dashboard.rootPage.reload();
await verifyRecords(['Mumbai', 'Delhi']);
});
}); });
test.describe('Undo Redo - Select based', () => { test.describe('Undo Redo - Select based', () => {

Loading…
Cancel
Save