Browse Source

Merge pull request #5813 from nocodb/revise/cell-context

revise: grid context menu
pull/5824/head
Raju Udava 2 years ago committed by GitHub
parent
commit
6eeedd176c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 27
      packages/nc-gui/components/smartsheet/Grid.vue
  2. 4
      packages/nc-gui/composables/useMultiSelect/cellRange.ts
  3. 1
      packages/nc-gui/composables/useMultiSelect/index.ts
  4. 78
      packages/nc-gui/composables/useViewData.ts

27
packages/nc-gui/components/smartsheet/Grid.vue

@ -124,6 +124,7 @@ const {
removeRowIfNew,
navigateToSiblingRow,
getExpandedRowIndex,
deleteRangeOfRows,
} = useViewData(meta, view, xWhere)
const { getMeta } = useMetas()
@ -199,6 +200,7 @@ const {
isCellActive,
tbodyEl,
resetSelectedRange,
selectedRange,
} = useMultiSelect(
meta,
fields,
@ -794,6 +796,14 @@ const confirmDeleteRow = (row: number) => {
},
})
}
const deleteSelectedRangeOfRows = () => {
deleteRangeOfRows(selectedRange).then(() => {
clearSelectedRange()
activeCell.row = null
activeCell.col = null
})
}
</script>
<template>
@ -1015,14 +1025,24 @@ const confirmDeleteRow = (row: number) => {
<template v-if="!isLocked && hasEditPermission" #overlay>
<a-menu class="shadow !rounded !py-0" @click="contextMenu = false">
<a-menu-item v-if="contextMenuTarget" @click="confirmDeleteRow(contextMenuTarget.row)">
<a-menu-item
v-if="contextMenuTarget && (selectedRange.isSingleCell() || selectedRange.isSingleRow())"
@click="confirmDeleteRow(contextMenuTarget.row)"
>
<div v-e="['a:row:delete']" class="nc-project-menu-item">
<!-- Delete Row -->
{{ $t('activity.deleteRow') }}
</div>
</a-menu-item>
<a-menu-item @click="deleteSelectedRows">
<a-menu-item v-else-if="contextMenuTarget" @click="deleteSelectedRangeOfRows">
<div v-e="['a:row:delete']" class="nc-project-menu-item">
<!-- Delete Rows -->
Delete Rows
</div>
</a-menu-item>
<a-menu-item v-if="data.some((r) => r.rowMeta.selected)" @click="deleteSelectedRows">
<div v-e="['a:row:delete-bulk']" class="nc-project-menu-item">
<!-- Delete Selected Rows -->
{{ $t('activity.deleteSelectedRow') }}
@ -1033,6 +1053,7 @@ const confirmDeleteRow = (row: number) => {
<a-menu-item
v-if="
contextMenuTarget &&
selectedRange.isSingleCell() &&
(fields[contextMenuTarget.col].uidt === UITypes.LinkToAnotherRecord ||
!isVirtualCol(fields[contextMenuTarget.col]))
"
@ -1041,7 +1062,7 @@ const confirmDeleteRow = (row: number) => {
<div v-e="['a:row:clear']" class="nc-project-menu-item">{{ $t('activity.clearCell') }}</div>
</a-menu-item>
<a-menu-item v-if="contextMenuTarget" @click="addEmptyRow(contextMenuTarget.row + 1)">
<a-menu-item v-if="contextMenuTarget && selectedRange.isSingleCell()" @click="addEmptyRow(contextMenuTarget.row + 1)">
<div v-e="['a:row:insert']" class="nc-project-menu-item">
<!-- Insert New Row -->
{{ $t('activity.insertRow') }}

4
packages/nc-gui/composables/useMultiSelect/cellRange.ts

@ -20,6 +20,10 @@ export class CellRange {
return !this.isEmpty() && this._start?.col === this._end?.col && this._start?.row === this._end?.row
}
isSingleRow() {
return !this.isEmpty() && this._start?.row === this._end?.row
}
get start(): Cell {
return {
row: Math.min(this._start?.row ?? NaN, this._end?.row ?? NaN),

1
packages/nc-gui/composables/useMultiSelect/index.ts

@ -445,5 +445,6 @@ export function useMultiSelect(
handleCellClick,
tbodyEl,
resetSelectedRange,
selectedRange,
}
}

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

@ -1,6 +1,7 @@
import { UITypes, ViewTypes } from 'nocodb-sdk'
import type { Api, ColumnType, FormColumnType, FormType, GalleryType, PaginatedType, TableType, ViewType } from 'nocodb-sdk'
import type { ComputedRef, Ref } from 'vue'
import type { CellRange } from '#imports'
import {
IsPublicInj,
NOCO,
@ -615,6 +616,82 @@ export function useViewData(
await syncPagination()
}
async function deleteRangeOfRows(cellRange: CellRange) {
if (!cellRange._start || !cellRange._end) return
const start = Math.max(cellRange._start.row, cellRange._end.row)
const end = Math.min(cellRange._start.row, cellRange._end.row)
// plus one because we want to include the end row
let row = start + 1
const removedRowsData: { id?: string; row: Row; rowIndex: number }[] = []
while (row--) {
try {
const { row: rowObj, rowMeta } = formattedData.value[row] as Record<string, any>
if (!rowMeta.new) {
const id = meta?.value?.columns
?.filter((c) => c.pk)
.map((c) => rowObj[c.title as string])
.join('___')
const successfulDeletion = await deleteRowById(id as string)
if (!successfulDeletion) {
continue
}
removedRowsData.push({ id, row: clone(formattedData.value[row]), rowIndex: row })
}
formattedData.value.splice(row, 1)
} catch (e: any) {
return message.error(`${t('msg.error.deleteRowFailed')}: ${await extractSdkResponseErrorMsg(e)}`)
}
if (row === end) break
}
addUndo({
redo: {
fn: async function redo(this: UndoRedoAction, removedRowsData: { id?: string; row: Row; rowIndex: number }[]) {
for (const { id, row } of removedRowsData) {
await deleteRowById(id as string)
const pk: Record<string, string> = rowPkData(row.row, meta?.value?.columns as ColumnType[])
const rowIndex = findIndexByPk(pk)
if (rowIndex !== -1) formattedData.value.splice(rowIndex, 1)
paginationData.value.totalRows = paginationData.value.totalRows! - 1
}
await syncPagination()
},
args: [removedRowsData],
},
undo: {
fn: async function undo(
this: UndoRedoAction,
removedRowsData: { id?: string; row: Row; rowIndex: number }[],
pg: { page: number; pageSize: number },
) {
for (const { row, rowIndex } of removedRowsData.slice().reverse()) {
const pkData = rowPkData(row.row, meta.value?.columns as ColumnType[])
row.row = { ...pkData, ...row.row }
await insertRow(row, {}, {}, true)
if (rowIndex !== -1 && pg.pageSize === paginationData.value.pageSize) {
if (pg.page === paginationData.value.page) {
formattedData.value.splice(rowIndex, 0, row)
} else {
await changePage(pg.page)
}
} else {
await loadData()
}
}
},
args: [removedRowsData, { page: paginationData.value.page, pageSize: paginationData.value.pageSize }],
},
scope: defineViewScope({ view: viewMeta.value }),
})
await syncCount()
await syncPagination()
}
async function loadFormView() {
if (!viewMeta?.value?.id) return
try {
@ -728,6 +805,7 @@ export function useViewData(
deleteRow,
deleteRowById,
deleteSelectedRows,
deleteRangeOfRows,
updateOrSaveRow,
selectedAllRecords,
syncCount,

Loading…
Cancel
Save