Browse Source

feat(nc-gui): introduce delete row in kanban view

pull/3563/head
Wing-Kam Wong 2 years ago
parent
commit
ccc8a04e43
  1. 59
      packages/nc-gui/components/smartsheet/Kanban.vue
  2. 59
      packages/nc-gui/composables/useKanbanViewStore.ts

59
packages/nc-gui/components/smartsheet/Kanban.vue

@ -66,6 +66,7 @@ const {
deleteStack,
removeRowFromUncategorizedStack,
shouldScrollToRight,
deleteRow,
} = useKanbanViewStoreOrThrow()
const { isUIAllowed } = useUIPermission()
@ -82,6 +83,8 @@ provide(IsKanbanInj, ref(true))
provide(ReadonlyInj, !isUIAllowed('xcDatatableEditable'))
const hasEditPermission = $computed(() => isUIAllowed('xcDatatableEditable'))
const fields = inject(FieldsInj, ref([]))
const kanbanContainerRef = ref()
@ -105,7 +108,7 @@ reloadViewMetaHook?.on(async () => {
})
const expandForm = (row: RowType, state?: Record<string, any>) => {
if (!isUIAllowed('xcDatatableEditable')) return
if (!hasEditPermission) return
const rowId = extractPkFromRow(row.row, meta.value!.columns!)
@ -123,6 +126,25 @@ const expandForm = (row: RowType, state?: Record<string, any>) => {
}
}
const _contextMenu = ref(false)
const contextMenu = computed({
get: () => _contextMenu.value,
set: (val) => {
if (hasEditPermission) {
_contextMenu.value = val
}
},
})
const contextMenuTarget = ref<RowType | null>(null)
const showContextMenu = (e: MouseEvent, target?: RowType) => {
e.preventDefault()
if (target) {
contextMenuTarget.value = target
}
}
const expandedFormOnRowIdDlg = computed({
get() {
return !!route.query.rowId
@ -250,11 +272,19 @@ watch(
}
},
)
// reset context menu target on hide
watch(contextMenu, () => {
if (!contextMenu.value) {
contextMenuTarget.value = null
}
})
</script>
<template>
<div class="flex h-full bg-white px-2">
<div ref="kanbanContainerRef" class="nc-kanban-container flex my-4 px-3 overflow-x-scroll overflow-y-hidden">
<a-dropdown v-model:visible="contextMenu" :trigger="['contextmenu']" overlay-class-name="nc-dropdown-kanban-context-menu">
<!-- Draggable Stack -->
<Draggable
v-model="groupingFieldColOptions"
@ -276,8 +306,8 @@ watch(
:key="stack.id"
class="mx-4 !bg-[#f0f2f5] flex flex-col w-[280px] h-full rounded-[12px]"
:class="{
'not-draggable': stack.id === 'uncategorized' || isLocked || isPublic || !isUIAllowed('xcDatatableEditable'),
'!cursor-default': isLocked || !isUIAllowed('xcDatatableEditable'),
'not-draggable': stack.id === 'uncategorized' || isLocked || isPublic || !hasEditPermission,
'!cursor-default': isLocked || !hasEditPermission,
}"
:head-style="{ paddingBottom: '0px' }"
:body-style="{ padding: '0px', height: '100%' }"
@ -305,7 +335,7 @@ watch(
<template v-if="!isLocked" #overlay>
<a-menu class="ml-6 !text-sm !px-0 !py-2 !rounded">
<a-menu-item
v-if="isUIAllowed('xcDatatableEditable') && !isPublic"
v-if="hasEditPermission && !isPublic"
v-e="['c:kanban:add-new-record']"
@click="openNewRecordFormHook.trigger(stack.title === 'uncategorized' ? null : stack.title)"
>
@ -321,7 +351,7 @@ watch(
</div>
</a-menu-item>
<a-menu-item
v-if="stack.title !== 'uncategorized' && !isPublic && isUIAllowed('xcDatatableEditable')"
v-if="stack.title !== 'uncategorized' && !isPublic && hasEditPermission"
v-e="['c:kanban:delete-stack']"
@click="handleDeleteStackClick(stack.title, stackIdx)"
>
@ -358,11 +388,12 @@ watch(
:data-stack="stack.title"
class="!rounded-lg h-full overflow-hidden break-all max-w-[450px] shadow-lg"
:class="{
'not-draggable': isLocked || !isUIAllowed('xcDatatableEditable') || isPublic,
'!cursor-default': isLocked || !isUIAllowed('xcDatatableEditable') || isPublic,
'not-draggable': isLocked || !hasEditPermission || isPublic,
'!cursor-default': isLocked || !hasEditPermission || isPublic,
}"
:body-style="{ padding: '10px' }"
@click="expandFormClick($event, record)"
@contextmenu="showContextMenu($event, record)"
>
<div
v-for="col in fields"
@ -433,7 +464,7 @@ watch(
:style="`background-color: ${stack.color} !important`"
class="nc-kanban-stack nc-kanban-collapsed-stack mx-4 flex items-center w-[300px] h-[50px] rounded-[12px] cursor-pointer h-full !pr-[10px]"
:class="{
'not-draggable': stack.id === 'uncategorized' || isLocked || isPublic || !isUIAllowed('xcDatatableEditable'),
'not-draggable': stack.id === 'uncategorized' || isLocked || isPublic || !hasEditPermission,
}"
:body-style="{ padding: '0px', height: '100%', width: '100%', background: '#f0f2f5 !important' }"
>
@ -456,6 +487,18 @@ watch(
</div>
</template>
</Draggable>
<!-- Drop down Menu -->
<template v-if="!isLocked && hasEditPermission" #overlay>
<a-menu class="shadow !rounded !py-0" @click="contextMenu = false">
<a-menu-item v-if="contextMenuTarget" @click="deleteRow(contextMenuTarget)">
<div v-e="['a:row:delete']" class="nc-project-menu-item">
<!-- Delete Row -->
{{ $t('activity.deleteRow') }}
</div>
</a-menu-item>
</a-menu>
</template>
</a-dropdown>
</div>
</div>

59
packages/nc-gui/composables/useKanbanViewStore.ts

@ -441,6 +441,19 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
}
}
function removeRowFromTargetStack(row: Row) {
// primary key of Row to be deleted
const targetPrimaryKey = extractPkFromRow(row.row, meta!.value!.columns as ColumnType[])
// stack title of Row to be deleted
const stackTitle = row.row[groupingField.value] ?? 'uncategorized'
// remove target row from formattedData
formattedData.value[stackTitle] = formattedData.value[stackTitle].filter(
(ele) => extractPkFromRow(ele.row, meta!.value!.columns as ColumnType[]) !== targetPrimaryKey,
)
// decrease countByStack of target stack by 1
countByStack.value[stackTitle] -= 1
}
function removeRowFromUncategorizedStack() {
// remove the last record
formattedData.value.uncategorized.pop()
@ -448,6 +461,51 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
countByStack.value.uncategorized -= 1
}
async function deleteRow(row: Row) {
try {
if (!row.rowMeta.new) {
const id = (meta?.value?.columns as ColumnType[])
?.filter((c) => c.pk)
.map((c) => row.row[c.title!])
.join('___')
const deleted = await deleteRowById(id as string)
if (!deleted) {
return
}
}
// remove deleted row from state
removeRowFromTargetStack(row)
} catch (e: any) {
message.error(`${t('msg.error.deleteRowFailed')}: ${await extractSdkResponseErrorMsg(e)}`)
}
}
async function deleteRowById(id: string) {
if (!id) {
throw new Error("Delete not allowed for table which doesn't have primary Key")
}
const res: any = await $api.dbViewRow.delete(
'noco',
project.value.id as string,
meta.value?.id as string,
viewMeta.value?.id as string,
id,
)
if (res.message) {
message.info(
`Row delete failed: ${`Unable to delete row with ID ${id} because of the following:
\n${res.message.join('\n')}.\n
Clear the data first & try again`})}`,
)
return false
}
return true
}
return {
loadKanbanData,
loadMoreKanbanData,
@ -466,6 +524,7 @@ const [useProvideKanbanViewStore, useKanbanViewStore] = useInjectionState(
updateKanbanStackMeta,
removeRowFromUncategorizedStack,
shouldScrollToRight,
deleteRow,
}
},
'kanban-view-store',

Loading…
Cancel
Save