Browse Source

Merge pull request #8869 from nocodb/nc-fix/cover-image-issue

Nc fix: Reset gallery/kanban view cover image column id on deleting column
fix/override-id
Ramesh Mane 5 months ago committed by GitHub
parent
commit
eb0c3876c4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 14
      packages/nc-gui/components/smartsheet/Gallery.vue
  2. 14
      packages/nc-gui/components/smartsheet/Kanban.vue
  3. 24
      packages/nc-gui/components/smartsheet/details/Fields.vue
  4. 11
      packages/nc-gui/components/smartsheet/header/DeleteColumnModal.vue
  5. 12
      packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue
  6. 12
      packages/nc-gui/composables/useColumnCreateStore.ts
  7. 37
      packages/nc-gui/store/views.ts
  8. 69
      packages/nocodb/src/models/Column.ts

14
packages/nc-gui/components/smartsheet/Gallery.vue

@ -563,8 +563,20 @@ watch(
} }
&.nc-virtual-cell-lookup { &.nc-virtual-cell-lookup {
.nc-lookup-cell { .nc-lookup-cell {
@apply !h-5.5; &:has(.nc-attachment-wrapper) {
@apply !h-auto;
.nc-attachment-cell {
@apply !h-auto;
.nc-attachment-wrapper {
@apply py-0;
}
}
}
&:not(:has(.nc-attachment-wrapper)) {
@apply !h-5.5;
}
.nc-cell-lookup-scroll { .nc-cell-lookup-scroll {
@apply py-0 h-auto; @apply py-0 h-auto;
} }

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

@ -1315,8 +1315,20 @@ const handleSubmitRenameOrNewStack = async (loadMeta: boolean, stack?: any, stac
} }
&.nc-virtual-cell-lookup { &.nc-virtual-cell-lookup {
.nc-lookup-cell { .nc-lookup-cell {
@apply !h-5.5; &:has(.nc-attachment-wrapper) {
@apply !h-auto;
.nc-attachment-cell {
@apply !h-auto;
.nc-attachment-wrapper {
@apply py-0;
}
}
}
&:not(:has(.nc-attachment-wrapper)) {
@apply !h-5.5;
}
.nc-cell-lookup-scroll { .nc-cell-lookup-scroll {
@apply py-0 h-auto; @apply py-0 h-auto;
} }

24
packages/nc-gui/components/smartsheet/details/Fields.vue

@ -51,7 +51,9 @@ const { meta, view } = useSmartsheetStoreOrThrow()
const isLocked = inject(IsLockedInj, ref(false)) const isLocked = inject(IsLockedInj, ref(false))
const { openedViewsTab } = storeToRefs(useViewsStore()) const viewsStore = useViewsStore()
const { openedViewsTab } = storeToRefs(viewsStore)
const localMetaColumns = ref<ColumnType[] | undefined>([]) const localMetaColumns = ref<ColumnType[] | undefined>([])
@ -691,15 +693,25 @@ const saveChanges = async () => {
} }
} }
const deletedOrUpdatedColumnIds: Set<string> = new Set()
for (const op of ops.value) { for (const op of ops.value) {
if (op.op === 'add') { if (op.op === 'add') {
if (activeField.value && compareCols(activeField.value, op.column)) { if (activeField.value && compareCols(activeField.value, op.column)) {
changeField() changeField()
} }
} else if (op.op === 'delete') { } else if (op.op === 'delete') {
deletedOrUpdatedColumnIds.add(op.column.id as string)
if (activeField.value && compareCols(activeField.value, op.column)) { if (activeField.value && compareCols(activeField.value, op.column)) {
changeField() changeField()
} }
} else if (op.op === 'update') {
const originalColumn = meta.value?.columns?.find((c) => c.id === op.column.id) as ColumnType
if (originalColumn?.uidt === UITypes.Attachment && originalColumn?.uidt !== op.column.uidt) {
deletedOrUpdatedColumnIds.add(op.column.id as string)
}
} }
} }
@ -736,10 +748,20 @@ const saveChanges = async () => {
moveOps.value = [] moveOps.value = []
} }
for (const op of ops.value) {
// remove column id from deletedColumnIds if operation was failed
if (deletedOrUpdatedColumnIds.has(op.column.id as string) && (op.op === 'delete' || op.op === 'update')) {
deletedOrUpdatedColumnIds.delete(op.column.id as string)
}
}
await getMeta(meta.value.id, true) await getMeta(meta.value.id, true)
metaToLocal() metaToLocal()
// Update views if column is used as cover image
viewsStore.updateViewCoverImageColumnId({ metaId: meta.value.id as string, columnIds: deletedOrUpdatedColumnIds })
columnsHash.value = (await $api.dbTableColumn.hash(meta.value?.id)).hash columnsHash.value = (await $api.dbTableColumn.hash(meta.value?.id)).hash
visibilityOps.value = [] visibilityOps.value = []

11
packages/nc-gui/components/smartsheet/header/DeleteColumnModal.vue

@ -1,6 +1,6 @@
<script lang="ts" setup> <script lang="ts" setup>
import type { LinkToAnotherRecordType } from 'nocodb-sdk' import type { LinkToAnotherRecordType } from 'nocodb-sdk'
import { RelationTypes, isLinksOrLTAR, isVirtualCol } from 'nocodb-sdk' import { RelationTypes, ViewTypes, isLinksOrLTAR, isVirtualCol } from 'nocodb-sdk'
const props = defineProps<{ const props = defineProps<{
visible: boolean visible: boolean
@ -23,6 +23,8 @@ const { includeM2M } = useGlobal()
const { loadTables } = useBase() const { loadTables } = useBase()
const viewsStore = useViewsStore()
const isLoading = ref(false) const isLoading = ref(false)
const onDelete = async () => { const onDelete = async () => {
@ -45,6 +47,13 @@ const onDelete = async () => {
} }
} }
// Update views if column is used as cover image
viewsStore.updateViewCoverImageColumnId({
metaId: meta.value?.id as string,
columnIds: new Set([column?.value?.id as string]),
})
$e('a:column:delete') $e('a:column:delete')
visible.value = false visible.value = false

12
packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue

@ -158,17 +158,15 @@ const updateCoverImage = async (val?: string | null) => {
const coverImageColumnId = computed({ const coverImageColumnId = computed({
get: () => { get: () => {
const fk_cover_image_col_id = const fk_cover_image_col_id =
(activeView.value?.type === ViewTypes.GALLERY || (activeView.value?.type === ViewTypes.GALLERY || activeView.value?.type === ViewTypes.KANBAN) && activeView.value?.view
activeView.value?.type === ViewTypes.KANBAN || ? (activeView.value?.view as GalleryType | KanbanType).fk_cover_image_col_id
activeView.value?.type === ViewTypes.CALENDAR) &&
activeView.value?.view
? (activeView.value?.view as GalleryType).fk_cover_image_col_id
: undefined : undefined
// check if `fk_cover_image_col_id` is in `coverOptions` // check if `fk_cover_image_col_id` is in `coverOptions`
// e.g. in share view, users may not share the cover image column // e.g. in share view, users may not share the cover image column
if (coverOptions.value?.find((o) => o.value === fk_cover_image_col_id)) return fk_cover_image_col_id if (coverOptions.value?.find((o) => o.value === fk_cover_image_col_id)) return fk_cover_image_col_id
// set to `No Image` // set to `No Image` if fk_cover_image_col_id is null else undefiend (This will help to change value to no image for user)
return null return fk_cover_image_col_id === null ? null : undefined
}, },
set: async (val) => { set: async (val) => {
if (val !== coverImageColumnId.value) { if (val !== coverImageColumnId.value) {

12
packages/nc-gui/composables/useColumnCreateStore.ts

@ -42,7 +42,9 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState
const sqlUi = ref(meta.value?.source_id ? sqlUis.value[meta.value?.source_id] : Object.values(sqlUis.value)[0]) const sqlUi = ref(meta.value?.source_id ? sqlUis.value[meta.value?.source_id] : Object.values(sqlUis.value)[0])
const { activeView } = storeToRefs(useViewsStore()) const viewsStore = useViewsStore()
const { activeView } = storeToRefs(viewsStore)
const disableSubmitBtn = ref(false) const disableSubmitBtn = ref(false)
@ -291,6 +293,14 @@ const [useProvideColumnCreateStore, useColumnCreateStore] = createInjectionState
await $api.dbTableColumn.update(column.value?.id as string, formState.value) await $api.dbTableColumn.update(column.value?.id as string, formState.value)
await postSaveOrUpdateCbk?.({ update: true, colId: column.value?.id }) await postSaveOrUpdateCbk?.({ update: true, colId: column.value?.id })
if (meta.value?.id && column.value.uidt === UITypes.Attachment && column.value.uidt !== formState.value.uidt) {
viewsStore.updateViewCoverImageColumnId({
metaId: meta.value.id as string,
columnIds: new Set([column.value.id as string]),
})
}
// Column updated // Column updated
// message.success(t('msg.success.columnUpdated')) // message.success(t('msg.success.columnUpdated'))
} else { } else {

37
packages/nc-gui/store/views.ts

@ -1,4 +1,5 @@
import type { FilterType, SortType, ViewType, ViewTypes } from 'nocodb-sdk' import type { FilterType, SortType, ViewType, ViewTypes } from 'nocodb-sdk'
import { ViewTypes as _ViewTypes } from 'nocodb-sdk'
import { acceptHMRUpdate, defineStore } from 'pinia' import { acceptHMRUpdate, defineStore } from 'pinia'
import { useTitle } from '@vueuse/core' import { useTitle } from '@vueuse/core'
import type { ViewPageType } from '~/lib/types' import type { ViewPageType } from '~/lib/types'
@ -378,6 +379,41 @@ export const useViewsStore = defineStore('viewsStore', () => {
) )
} }
const updateViewCoverImageColumnId = ({ columnIds, metaId }: { columnIds: Set<string>; metaId: string }) => {
if (!viewsByTable.value.get(metaId)) return
let isColumnUsedAsCoverImage = false
for (const view of viewsByTable.value.get(metaId) || []) {
if (
[_ViewTypes.GALLERY, _ViewTypes.KANBAN].includes(view.type) &&
view.view?.fk_cover_image_col_id &&
columnIds.has(view.view?.fk_cover_image_col_id)
) {
isColumnUsedAsCoverImage = true
break
}
}
if (!isColumnUsedAsCoverImage) return
viewsByTable.value.set(
metaId,
(viewsByTable.value.get(metaId) || [])
.map((view) => {
if (
[_ViewTypes.GALLERY, _ViewTypes.KANBAN].includes(view.type) &&
view.view?.fk_cover_image_col_id &&
columnIds.has(view.view?.fk_cover_image_col_id)
) {
view.view.fk_cover_image_col_id = null
}
return view
})
.sort((a, b) => a.order! - b.order!),
)
}
refreshViewTabTitle.on(() => { refreshViewTabTitle.on(() => {
updateTabTitle() updateTabTitle()
}) })
@ -412,6 +448,7 @@ export const useViewsStore = defineStore('viewsStore', () => {
isActiveViewLocked, isActiveViewLocked,
preFillFormSearchParams, preFillFormSearchParams,
refreshViewTabTitle: refreshViewTabTitle.trigger, refreshViewTabTitle: refreshViewTabTitle.trigger,
updateViewCoverImageColumnId,
} }
}) })

69
packages/nocodb/src/models/Column.ts

@ -17,7 +17,7 @@ import Sort from '~/models/Sort';
import Filter from '~/models/Filter'; import Filter from '~/models/Filter';
import QrCodeColumn from '~/models/QrCodeColumn'; import QrCodeColumn from '~/models/QrCodeColumn';
import BarcodeColumn from '~/models/BarcodeColumn'; import BarcodeColumn from '~/models/BarcodeColumn';
import { LinksColumn } from '~/models'; import { GalleryView, KanbanView, LinksColumn } from '~/models';
import { extractProps } from '~/helpers/extractProps'; import { extractProps } from '~/helpers/extractProps';
import { NcError } from '~/helpers/catchError'; import { NcError } from '~/helpers/catchError';
import addFormulaErrorIfMissingColumn from '~/helpers/addFormulaErrorIfMissingColumn'; import addFormulaErrorIfMissingColumn from '~/helpers/addFormulaErrorIfMissingColumn';
@ -872,6 +872,8 @@ export default class Column<T = any> implements ColumnType {
await Filter.delete(context, filter.id, ncMeta); await Filter.delete(context, filter.id, ncMeta);
} }
} }
// Set Gallery & Kanban view `fk_cover_image_col_id` value to null
await Column.deleteCoverImageColumnId(context, id, ncMeta);
// Delete from view columns // Delete from view columns
let colOptionTableName = null; let colOptionTableName = null;
@ -1205,6 +1207,11 @@ export default class Column<T = any> implements ColumnType {
); );
} }
if (oldCol.uidt === UITypes.Attachment && oldCol.uidt !== column.uidt) {
// Set Gallery & Kanban view `fk_cover_image_col_id` value to null
await Column.deleteCoverImageColumnId(context, column.id, ncMeta);
}
// set meta // set meta
await ncMeta.metaUpdate( await ncMeta.metaUpdate(
context.workspace_id, context.workspace_id,
@ -1725,4 +1732,64 @@ export default class Column<T = any> implements ColumnType {
} }
} }
} }
private static async deleteCoverImageColumnId(
context: NcContext,
id: string,
ncMeta = Noco.ncMeta,
) {
const promises = [];
// Gallery views
const galleryViews: GalleryView[] = await ncMeta.metaList2(
context.workspace_id,
context.base_id,
MetaTable.GALLERY_VIEW,
{
condition: {
fk_cover_image_col_id: id,
},
},
);
for (const galleryView of galleryViews) {
promises.push(
GalleryView.update(
context,
galleryView.fk_view_id,
{
fk_cover_image_col_id: null,
},
ncMeta,
),
);
}
// Kanban views
const kanbanViews: KanbanView[] = await ncMeta.metaList2(
context.workspace_id,
context.base_id,
MetaTable.KANBAN_VIEW,
{
condition: {
fk_cover_image_col_id: id,
},
},
);
for (const kanbanView of kanbanViews) {
promises.push(
KanbanView.update(
context,
kanbanView.fk_view_id,
{
fk_cover_image_col_id: null,
},
ncMeta,
),
);
}
await Promise.all(promises);
}
} }

Loading…
Cancel
Save