Browse Source

Merge pull request #6645 from nocodb/nc-feat/view-columns-injection

feat: use view columns injection
pull/6750/head
Raju Udava 1 year ago committed by GitHub
parent
commit
d2667e28e1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      packages/nc-gui/components/shared-view/Gallery.vue
  2. 6
      packages/nc-gui/components/shared-view/Grid.vue
  3. 2
      packages/nc-gui/components/shared-view/Kanban.vue
  4. 2
      packages/nc-gui/components/shared-view/Map.vue
  5. 8
      packages/nc-gui/components/smartsheet/Form.vue
  6. 13
      packages/nc-gui/components/smartsheet/column/BarcodeOptions.vue
  7. 11
      packages/nc-gui/components/smartsheet/column/QrCodeOptions.vue
  8. 7
      packages/nc-gui/components/smartsheet/details/Fields.vue
  9. 8
      packages/nc-gui/components/smartsheet/grid/Table.vue
  10. 2
      packages/nc-gui/components/smartsheet/toolbar/CreateSort.vue
  11. 4
      packages/nc-gui/components/smartsheet/toolbar/FieldListAutoCompleteDropdown.vue
  12. 8
      packages/nc-gui/components/smartsheet/toolbar/FieldsMenu.vue
  13. 3
      packages/nc-gui/components/smartsheet/toolbar/GroupByMenu.vue
  14. 6
      packages/nc-gui/components/smartsheet/toolbar/MappedBy.vue
  15. 14
      packages/nc-gui/components/smartsheet/toolbar/SortListMenu.vue
  16. 4
      packages/nc-gui/components/smartsheet/toolbar/StackedBy.vue
  17. 3
      packages/nc-gui/components/tabs/Smartsheet.vue
  18. 97
      packages/nc-gui/composables/useGridViewColumn.ts
  19. 10
      packages/nc-gui/composables/useTableNew.ts
  20. 557
      packages/nc-gui/composables/useViewColumns.ts
  21. 2
      packages/nc-gui/composables/useViewFilters.ts
  22. 4
      packages/nc-gui/composables/useViewGroupBy.ts
  23. 2
      packages/nc-gui/pages/index/[typeOrId]/[baseId]/index/index/[viewId]/[[viewTitle]].vue
  24. 3
      packages/nc-gui/store/views.ts

2
packages/nc-gui/components/shared-view/Gallery.vue

@ -17,6 +17,8 @@ provide(FieldsInj, ref(meta.value?.columns || []))
provide(IsPublicInj, ref(true))
useProvideViewColumns(sharedView, meta, () => reloadEventHook?.trigger(), true)
useProvideSmartsheetStore(sharedView, meta, true, sorts, nestedFilters)
</script>

6
packages/nc-gui/components/shared-view/Grid.vue

@ -37,7 +37,7 @@ provide(FieldsInj, columns)
provide(IsPublicInj, ref(true))
provide(IsLockedInj, isLocked)
const { loadGridViewColumns } = useProvideGridViewColumn(sharedView, true)
useProvideViewColumns(sharedView, meta, () => reloadEventHook?.trigger(), true)
if (signedIn.value) {
try {
@ -55,10 +55,6 @@ watch(
immediate: true,
},
)
onMounted(async () => {
await loadGridViewColumns()
})
</script>
<template>

2
packages/nc-gui/components/shared-view/Kanban.vue

@ -25,6 +25,8 @@ provide(FieldsInj, ref(meta.value?.columns || []))
provide(IsPublicInj, ref(true))
useProvideViewColumns(sharedView, meta, () => reloadEventHook?.trigger(), true)
useProvideSmartsheetStore(sharedView, meta, true, sorts, nestedFilters)
useProvideKanbanViewStore(meta, sharedView, true)

2
packages/nc-gui/components/shared-view/Map.vue

@ -25,6 +25,8 @@ provide(FieldsInj, ref(meta.value?.columns || []))
provide(IsPublicInj, ref(true))
useProvideViewColumns(sharedView, meta, () => reloadEventHook?.trigger(), true)
useProvideSmartsheetStore(sharedView, meta, true, sorts, nestedFilters)
useProvideMapViewStore(meta, sharedView, true)

8
packages/nc-gui/components/smartsheet/Form.vue

@ -23,7 +23,7 @@ import {
useI18n,
useNuxtApp,
useRoles,
useViewColumns,
useViewColumnsOrThrow,
useViewData,
watch,
} from '#imports'
@ -58,16 +58,14 @@ const isPublic = inject(IsPublicInj, ref(false))
const { loadFormView, insertRow, formColumnData, formViewData, updateFormView } = useViewData(meta, view)
const reloadEventHook = createEventHook<boolean | void>()
provide(ReloadViewDataHookInj, reloadEventHook)
const reloadEventHook = inject(ReloadViewDataHookInj, createEventHook<boolean | void>())
reloadEventHook.on(async () => {
await loadFormView()
setFormData()
})
const { showAll, hideAll, saveOrUpdate } = useViewColumns(view, meta, async () => reloadEventHook.trigger())
const { showAll, hideAll, saveOrUpdate } = useViewColumnsOrThrow()
const { syncLTARRefs, row } = useProvideSmartsheetRowStore(
meta,

13
packages/nc-gui/components/smartsheet/column/BarcodeOptions.vue

@ -10,13 +10,7 @@ const props = defineProps<{
const emit = defineEmits(['update:modelValue'])
const meta = inject(MetaInj, ref())
const activeView = inject(ActiveViewInj, ref())
const reloadDataHook = inject(ReloadViewDataHookInj)!
const { fields, metaColumnById } = useViewColumns(activeView, meta, () => reloadDataHook.trigger())
const { fields, metaColumnById } = useViewColumnsOrThrow()
const vModel = useVModel(props, 'modelValue', emit)
@ -59,11 +53,12 @@ onMounted(() => {
...vModel.value.meta,
}
vModel.value.fk_barcode_value_column_id =
(column?.value?.colOptions as Record<string, any>)?.fk_barcode_value_column_id || columnsAllowedAsBarcodeValue.value?.[0]
(column?.value?.colOptions as Record<string, any>)?.fk_barcode_value_column_id ||
columnsAllowedAsBarcodeValue.value?.[0]?.value
})
watch(columnsAllowedAsBarcodeValue, (newColumnsAllowedAsBarcodeValue) => {
if (vModel.value.fk_barcode_value_column_id == null) {
if (vModel.value.fk_barcode_value_column_id === null) {
vModel.value.fk_barcode_value_column_id = newColumnsAllowedAsBarcodeValue?.[0]?.value
}
})

11
packages/nc-gui/components/smartsheet/column/QrCodeOptions.vue

@ -10,15 +10,9 @@ const props = defineProps<{
const emit = defineEmits(['update:modelValue'])
const meta = inject(MetaInj, ref())
const activeView = inject(ActiveViewInj, ref())
const { t } = useI18n()
const reloadDataHook = inject(ReloadViewDataHookInj)!
const { fields, metaColumnById } = useViewColumns(activeView, meta, () => reloadDataHook.trigger())
const { fields, metaColumnById } = useViewColumnsOrThrow()
const vModel = useVModel(props, 'modelValue', emit)
@ -40,7 +34,8 @@ const columnsAllowedAsQrValue = computed<SelectProps['options']>(() => {
onMounted(() => {
// set default value
vModel.value.fk_qr_value_column_id = (column?.value?.colOptions as Record<string, any>)?.fk_qr_value_column_id || ''
vModel.value.fk_qr_value_column_id =
(column?.value?.colOptions as Record<string, any>)?.fk_qr_value_column_id || columnsAllowedAsQrValue.value?.[0]?.value
})
setAdditionalValidations({

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

@ -45,12 +45,7 @@ const visibilityOps = ref<fieldsVisibilityOps[]>([])
const fieldsListWrapperDomRef = ref<HTMLElement>()
const {
fields: viewFields,
toggleFieldVisibility,
loadViewColumns,
isViewColumnsLoading,
} = useViewColumns(view, meta as Ref<TableType | undefined>)
const { fields: viewFields, toggleFieldVisibility, loadViewColumns, isViewColumnsLoading } = useViewColumnsOrThrow()
const loading = ref(false)

8
packages/nc-gui/components/smartsheet/grid/Table.vue

@ -28,7 +28,6 @@ import {
provide,
ref,
useEventListener,
useGridViewColumnOrThrow,
useI18n,
useMultiSelect,
useNuxtApp,
@ -36,6 +35,7 @@ import {
useRoute,
useSmartsheetStoreOrThrow,
useUndoRedo,
useViewColumnsOrThrow,
useViewsStore,
watch,
} from '#imports'
@ -123,8 +123,6 @@ const reloadViewDataHook = inject(ReloadViewDataHookInj, createEventHook())
const openNewRecordFormHook = inject(OpenNewRecordFormHookInj, createEventHook())
const { isViewColumnsLoading } = useViewColumns(view, meta, () => reloadViewDataHook.trigger())
const { isMobileMode } = useGlobal()
const scrollParent = inject(ScrollParentInj, ref<undefined>())
@ -141,6 +139,8 @@ const { getMeta } = useMetas()
const { addUndo, clone, defineViewScope } = useUndoRedo()
const { isViewColumnsLoading, updateGridViewColumn, gridViewCols, resizingColOldWith } = useViewColumnsOrThrow()
const {
predictingNextColumn,
predictedNextColumn,
@ -894,8 +894,6 @@ const saveOrUpdateRecords = async (args: { metaValue?: TableType; viewMetaValue?
}
// #Grid Resize
const { updateGridViewColumn, gridViewCols, resizingColOldWith } = useGridViewColumnOrThrow()
const onresize = (colID: string | undefined, event: any) => {
if (!colID) return
updateGridViewColumn(colID, { width: event.detail })

2
packages/nc-gui/components/smartsheet/toolbar/CreateSort.vue

@ -21,7 +21,7 @@ const activeView = inject(ActiveViewInj, ref())
const meta = inject(MetaInj, ref())
const { showSystemFields, metaColumnById } = useViewColumns(activeView, meta)
const { showSystemFields, metaColumnById } = useViewColumnsOrThrow(activeView, meta)
const { sorts } = useViewSorts(activeView)

4
packages/nc-gui/components/smartsheet/toolbar/FieldListAutoCompleteDropdown.vue

@ -2,7 +2,7 @@
import type { SelectProps } from 'ant-design-vue'
import type { ColumnType, LinkToAnotherRecordType } from 'nocodb-sdk'
import { RelationTypes, UITypes, isLinksOrLTAR, isSystemColumn, isVirtualCol } from 'nocodb-sdk'
import { ActiveViewInj, MetaInj, computed, inject, ref, resolveComponent, useViewColumns } from '#imports'
import { ActiveViewInj, MetaInj, computed, inject, ref, resolveComponent, useViewColumnsOrThrow } from '#imports'
const { modelValue, isSort, allowEmpty, ...restProps } = defineProps<{
modelValue?: string
@ -24,7 +24,7 @@ const localValue = computed({
const activeView = inject(ActiveViewInj, ref())
const { showSystemFields, metaColumnById } = useViewColumns(activeView, meta)
const { showSystemFields, metaColumnById } = useViewColumnsOrThrow()
const options = computed<SelectProps['options']>(() =>
(

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

@ -21,16 +21,12 @@ import {
useNuxtApp,
useSmartsheetStoreOrThrow,
useUndoRedo,
useViewColumns,
useViewColumnsOrThrow,
watch,
} from '#imports'
const meta = inject(MetaInj, ref())
const activeView = inject(ActiveViewInj, ref())
const reloadDataHook = inject(ReloadViewDataHookInj)!
const reloadViewMetaHook = inject(ReloadViewMetaHookInj, undefined)!
const rootFields = inject(FieldsInj)
@ -55,7 +51,7 @@ const {
metaColumnById,
loadViewColumns,
toggleFieldVisibility,
} = useViewColumns(activeView, meta, () => reloadDataHook.trigger())
} = useViewColumnsOrThrow()
const { eventBus } = useSmartsheetStoreOrThrow()

3
packages/nc-gui/components/smartsheet/toolbar/GroupByMenu.vue

@ -14,6 +14,7 @@ import {
useMetas,
useNuxtApp,
useSmartsheetStoreOrThrow,
useViewColumnsOrThrow,
} from '#imports'
const groupingUidt = [
@ -33,7 +34,7 @@ const meta = inject(MetaInj, ref())
const view = inject(ActiveViewInj, ref())
const isLocked = inject(IsLockedInj, ref(false))
const { gridViewCols, updateGridViewColumn } = useGridViewColumnOrThrow()
const { gridViewCols, updateGridViewColumn } = useViewColumnsOrThrow()
const { $e } = useNuxtApp()

6
packages/nc-gui/components/smartsheet/toolbar/MappedBy.vue

@ -12,7 +12,7 @@ import {
iconMap,
inject,
ref,
useViewColumns,
useViewColumnsOrThrow,
watch,
} from '#imports'
@ -22,13 +22,11 @@ const meta = inject(MetaInj, ref())
const activeView = inject(ActiveViewInj, ref())
const reloadDataHook = inject(ReloadViewDataHookInj)!
const isLocked = inject(IsLockedInj, ref(false))
const IsPublic = inject(IsPublicInj, ref(false))
const { fields, loadViewColumns, metaColumnById } = useViewColumns(activeView, meta, () => reloadDataHook.trigger())
const { fields, loadViewColumns, metaColumnById } = useViewColumnsOrThrow()
const { loadMapData, loadMapMeta, updateMapMeta, mapMetaData, geoDataFieldColumn } = useMapViewStoreOrThrow()

14
packages/nc-gui/components/smartsheet/toolbar/SortListMenu.vue

@ -28,7 +28,7 @@ const { eventBus } = useSmartsheetStoreOrThrow()
const { sorts, saveOrUpdate, loadSorts, addSort: _addSort, deleteSort } = useViewSorts(view, () => reloadDataHook?.trigger())
const { showSystemFields, metaColumnById } = useViewColumns(view, meta)
const { showSystemFields, metaColumnById } = useViewColumnsOrThrow()
const showCreateSort = ref(false)
@ -79,14 +79,6 @@ const getColumnUidtByID = (key?: string) => {
return columnByID.value[key]?.uidt || ''
}
watch(
() => view.value?.id,
(viewId) => {
if (viewId) loadSorts()
},
{ immediate: true },
)
const open = ref(false)
useMenuCloseOnEsc(open)
@ -105,6 +97,10 @@ watch(open, () => {
showCreateSort.value = false
}
})
onMounted(() => {
loadSorts()
})
</script>
<template>

4
packages/nc-gui/components/smartsheet/toolbar/StackedBy.vue

@ -14,7 +14,7 @@ import {
useKanbanViewStoreOrThrow,
useMenuCloseOnEsc,
useUndoRedo,
useViewColumns,
useViewColumnsOrThrow,
watch,
} from '#imports'
@ -30,7 +30,7 @@ const reloadDataHook = inject(ReloadViewDataHookInj)!
const isLocked = inject(IsLockedInj, ref(false))
const { fields, loadViewColumns, metaColumnById } = useViewColumns(activeView, meta, () => reloadDataHook.trigger())
const { fields, loadViewColumns, metaColumnById } = useViewColumnsOrThrow(activeView, meta)
const { kanbanMetaData, loadKanbanMeta, loadKanbanData, updateKanbanMeta, groupingField, groupingFieldColumn } =
useKanbanViewStoreOrThrow()

3
packages/nc-gui/components/tabs/Smartsheet.vue

@ -63,7 +63,6 @@ const openNewRecordFormHook = createEventHook<void>()
useProvideKanbanViewStore(meta, activeView)
useProvideMapViewStore(meta, activeView)
useProvideGridViewColumn(activeView)
// todo: move to store
provide(MetaInj, meta)
@ -80,6 +79,8 @@ provide(
computed(() => !isUIAllowed('dataEdit')),
)
useProvideViewColumns(activeView, meta, () => reloadEventHook?.trigger())
const grid = ref()
const onDrop = async (event: DragEvent) => {

97
packages/nc-gui/composables/useGridViewColumn.ts

@ -1,97 +0,0 @@
import type { ColumnType, GridColumnReqType, GridColumnType, ViewType } from 'nocodb-sdk'
import type { Ref } from 'vue'
import { IsPublicInj, computed, inject, ref, useMetas, useNuxtApp, useRoles, useUndoRedo, watch } from '#imports'
const [useProvideGridViewColumn, useGridViewColumn] = useInjectionState(
(view: Ref<(ViewType & { columns?: GridColumnType[] }) | undefined>, statePublic = false) => {
const { isUIAllowed } = useRoles()
const { $api } = useNuxtApp()
const { metas } = useMetas()
const { addUndo, defineViewScope } = useUndoRedo()
const gridViewCols = ref<Record<string, GridColumnType>>({})
const resizingColOldWith = ref('200px')
const isPublic = inject(IsPublicInj, ref(statePublic))
const columns = computed<ColumnType[]>(() => metas.value?.[view.value?.fk_model_id as string]?.columns || [])
const loadGridViewColumns = async () => {
if (!view.value?.id && !isPublic.value) return
const colsData: GridColumnType[] =
(isPublic.value ? view.value?.columns : await $api.dbView.gridColumnsList(view.value!.id!)) ?? []
gridViewCols.value = colsData.reduce<Record<string, GridColumnType>>(
(o, col) => ({
...o,
[col.fk_column_id as string]: col,
}),
{},
)
}
/** when columns changes(create/delete) reload grid columns
* or when view changes reload columns width */
watch(
[() => columns.value?.length, () => view.value?.id],
async (n) => {
if (n[1]) await loadGridViewColumns()
},
{ immediate: true },
)
const updateGridViewColumn = async (id: string, props: Partial<GridColumnReqType>, undo = false) => {
if (!undo) {
const oldProps = Object.keys(props).reduce<Partial<GridColumnReqType>>((o: any, k) => {
if (gridViewCols.value[id][k as keyof GridColumnType]) {
if (k === 'width') o[k] = `${resizingColOldWith.value}px`
else o[k] = gridViewCols.value[id][k as keyof GridColumnType]
}
return o
}, {})
addUndo({
redo: {
fn: (w: Partial<GridColumnReqType>) => updateGridViewColumn(id, w, true),
args: [props],
},
undo: {
fn: (w: Partial<GridColumnReqType>) => updateGridViewColumn(id, w, true),
args: [oldProps],
},
scope: defineViewScope({ view: view.value }),
})
}
// sync with server if allowed
if (!isPublic.value && isUIAllowed('viewFieldEdit') && gridViewCols.value[id]?.id) {
await $api.dbView.gridColumnUpdate(gridViewCols.value[id].id as string, {
...props,
})
}
if (gridViewCols.value?.[id]) {
Object.assign(gridViewCols.value[id], {
...gridViewCols.value[id],
...props,
})
} else {
// fallback to reload
await loadGridViewColumns()
}
}
return { loadGridViewColumns, updateGridViewColumn, gridViewCols, resizingColOldWith }
},
'useGridViewColumn',
)
export { useProvideGridViewColumn }
export function useGridViewColumnOrThrow() {
const gridViewColumn = useGridViewColumn()
if (gridViewColumn == null) throw new Error('Please call `useProvideGridViewColumn` on the appropriate parent component')
return gridViewColumn
}

10
packages/nc-gui/composables/useTableNew.ts

@ -56,8 +56,6 @@ export function useTableNew(param: { onTableCreate?: (tableMeta: TableType) => v
const tables = computed(() => baseTables.value.get(param.baseId) || [])
const base = computed(() => bases.value.get(param.baseId))
const { loadViews } = useViewsStore()
const openTable = async (table: TableType) => {
if (!table.base_id) return
@ -82,12 +80,10 @@ export function useTableNew(param: { onTableCreate?: (tableMeta: TableType) => v
baseIdOrBaseId = route.value.params.baseId as string
}
await loadViews({
tableId: table.id,
})
const views = viewsByTable.value.get(table.id as string) ?? []
getMeta(table.id as string, (route.value.params?.viewId as string) !== table.id)
if (openedViewsTab.value !== 'view' && views[0].id) {
await navigateTo({
path: `/${workspaceIdOrType}/${baseIdOrBaseId}/${table?.id}/${views[0].id}/${openedViewsTab.value}`,
@ -98,8 +94,6 @@ export function useTableNew(param: { onTableCreate?: (tableMeta: TableType) => v
path: `/${workspaceIdOrType}/${baseIdOrBaseId}/${table?.id}`,
query: route.value.query,
})
await getMeta(table.id as string)
}
const createTable = async () => {

557
packages/nc-gui/composables/useViewColumns.ts

@ -1,296 +1,363 @@
import { ViewTypes, isSystemColumn } from 'nocodb-sdk'
import type { ColumnType, MapType, TableType, ViewType } from 'nocodb-sdk'
import type { ColumnType, GridColumnReqType, GridColumnType, MapType, TableType, ViewType } from 'nocodb-sdk'
import type { ComputedRef, Ref } from 'vue'
import { IsPublicInj, computed, inject, ref, storeToRefs, useBase, useNuxtApp, useRoles, useUndoRedo, watch } from '#imports'
import { computed, ref, storeToRefs, useBase, useNuxtApp, useRoles, useUndoRedo, watch } from '#imports'
import type { Field } from '#imports'
export function useViewColumns(
view: Ref<ViewType | undefined>,
meta: Ref<TableType | undefined> | ComputedRef<TableType | undefined>,
reloadData?: () => void,
) {
const isPublic = inject(IsPublicInj, ref(false))
const [useProvideViewColumns, useViewColumns] = useInjectionState(
(
view: Ref<ViewType | undefined>,
meta: Ref<TableType | undefined> | ComputedRef<TableType | undefined>,
reloadData?: () => void,
isPublic = false,
) => {
const fields = ref<Field[]>()
const fields = ref<Field[]>()
const filterQuery = ref('')
const filterQuery = ref('')
const { $api, $e } = useNuxtApp()
const { $api, $e } = useNuxtApp()
const { isUIAllowed } = useRoles()
const { isUIAllowed } = useRoles()
const { isSharedBase } = storeToRefs(useBase())
const { isSharedBase } = storeToRefs(useBase())
const isViewColumnsLoading = ref(false)
const isViewColumnsLoading = ref(false)
const { addUndo, defineViewScope } = useUndoRedo()
const { addUndo, defineViewScope } = useUndoRedo()
const isLocalMode = computed(
() => isPublic || !isUIAllowed('viewFieldEdit') || !isUIAllowed('viewFieldEdit') || isSharedBase.value,
)
const isLocalMode = computed(
() => isPublic.value || !isUIAllowed('viewFieldEdit') || !isUIAllowed('viewFieldEdit') || isSharedBase.value,
)
const localChanges = ref<Field[]>([])
const localChanges = ref<Field[]>([])
const isColumnViewEssential = (column: ColumnType) => {
// TODO: consider at some point ti delegate this via a cleaner design pattern to view specific check logic
// which could be inside of a view specific helper class (and generalized via an interface)
// (on the other hand, the logic complexity is still very low atm - might be overkill)
return view.value?.type === ViewTypes.MAP && (view.value?.view as MapType)?.fk_geo_data_col_id === column.id
}
const isColumnViewEssential = (column: ColumnType) => {
// TODO: consider at some point ti delegate this via a cleaner design pattern to view specific check logic
// which could be inside of a view specific helper class (and generalized via an interface)
// (on the other hand, the logic complexity is still very low atm - might be overkill)
return view.value?.type === ViewTypes.MAP && (view.value?.view as MapType)?.fk_geo_data_col_id === column.id
}
const metaColumnById = computed<Record<string, ColumnType>>(() => {
if (!meta.value?.columns) return {}
const metaColumnById = computed<Record<string, ColumnType>>(() => {
if (!meta.value?.columns) return {}
return (meta.value.columns as ColumnType[]).reduce(
(acc, curr) => ({
...acc,
[curr.id!]: curr,
}),
{},
) as Record<string, ColumnType>
})
return (meta.value.columns as ColumnType[]).reduce(
(acc, curr) => ({
...acc,
[curr.id!]: curr,
}),
{},
) as Record<string, ColumnType>
})
const gridViewCols = ref<Record<string, GridColumnType>>({})
const loadViewColumns = async () => {
if (!meta || !view) return
const loadViewColumns = async () => {
if (!meta || !view) return
let order = 1
let order = 1
if (view.value?.id) {
const data = (isPublic.value ? meta.value?.columns : (await $api.dbViewColumn.list(view.value.id)).list) as any[]
if (view.value?.id) {
const data = (isPublic ? meta.value?.columns : (await $api.dbViewColumn.list(view.value.id)).list) as any[]
const fieldById = data.reduce<Record<string, any>>((acc, curr) => {
curr.show = !!curr.show
return {
...acc,
[curr.fk_column_id]: curr,
}
}, {})
fields.value = meta.value?.columns
?.map((column: ColumnType) => {
const currentColumnField = fieldById[column.id!] || {}
const fieldById = data.reduce<Record<string, any>>((acc, curr) => {
curr.show = !!curr.show
return {
title: column.title,
fk_column_id: column.id,
...currentColumnField,
show: currentColumnField.show || isColumnViewEssential(currentColumnField),
order: currentColumnField.order || order++,
system: isSystemColumn(metaColumnById?.value?.[currentColumnField.fk_column_id!]),
isViewEssentialField: isColumnViewEssential(column),
...acc,
[curr.fk_column_id]: curr,
}
})
.sort((a: Field, b: Field) => a.order - b.order)
if (isLocalMode.value && fields.value) {
for (const field of localChanges.value) {
const fieldIndex = fields.value.findIndex((f) => f.fk_column_id === field.fk_column_id)
if (fieldIndex !== undefined && fieldIndex > -1) {
fields.value[fieldIndex] = field
fields.value = fields.value.sort((a: Field, b: Field) => a.order - b.order)
}, {})
fields.value = meta.value?.columns
?.map((column: ColumnType) => {
const currentColumnField = fieldById[column.id!] || {}
return {
title: column.title,
fk_column_id: column.id,
...currentColumnField,
show: currentColumnField.show || isColumnViewEssential(currentColumnField),
order: currentColumnField.order || order++,
system: isSystemColumn(metaColumnById?.value?.[currentColumnField.fk_column_id!]),
isViewEssentialField: isColumnViewEssential(column),
}
})
.sort((a: Field, b: Field) => a.order - b.order)
if (isLocalMode.value && fields.value) {
for (const field of localChanges.value) {
const fieldIndex = fields.value.findIndex((f) => f.fk_column_id === field.fk_column_id)
if (fieldIndex !== undefined && fieldIndex > -1) {
fields.value[fieldIndex] = field
fields.value = fields.value.sort((a: Field, b: Field) => a.order - b.order)
}
}
}
const colsData: GridColumnType[] = (isPublic.value ? view.value?.columns : fields.value) ?? []
gridViewCols.value = colsData.reduce<Record<string, GridColumnType>>(
(o, col) => ({
...o,
[col.fk_column_id as string]: col,
}),
{},
)
}
}
}
const showAll = async (ignoreIds?: any) => {
if (isLocalMode.value) {
fields.value = fields.value?.map((field: Field) => ({
...field,
show: true,
}))
reloadData?.()
return
}
if (view?.value?.id) {
if (ignoreIds) {
await $api.dbView.showAllColumn(view.value.id, {
ignoreIds,
})
} else {
await $api.dbView.showAllColumn(view.value.id)
const showAll = async (ignoreIds?: any) => {
if (isLocalMode.value) {
fields.value = fields.value?.map((field: Field) => ({
...field,
show: true,
}))
reloadData?.()
return
}
if (view?.value?.id) {
if (ignoreIds) {
await $api.dbView.showAllColumn(view.value.id, {
ignoreIds,
})
} else {
await $api.dbView.showAllColumn(view.value.id)
}
}
await loadViewColumns()
reloadData?.()
$e('a:fields:show-all')
}
const hideAll = async (ignoreIds?: any) => {
if (isLocalMode.value) {
fields.value = fields.value?.map((field: Field) => ({
...field,
show: !!field.isViewEssentialField,
}))
reloadData?.()
return
}
if (view?.value?.id) {
if (ignoreIds) {
await $api.dbView.hideAllColumn(view.value.id, {
ignoreIds,
})
} else {
await $api.dbView.hideAllColumn(view.value.id)
}
}
await loadViewColumns()
reloadData?.()
$e('a:fields:show-all')
}
const hideAll = async (ignoreIds?: any) => {
if (isLocalMode.value) {
fields.value = fields.value?.map((field: Field) => ({
...field,
show: !!field.isViewEssentialField,
}))
await loadViewColumns()
reloadData?.()
return
$e('a:fields:show-all')
}
if (view?.value?.id) {
if (ignoreIds) {
await $api.dbView.hideAllColumn(view.value.id, {
ignoreIds,
const saveOrUpdate = async (field: any, index: number) => {
if (isLocalMode.value && fields.value) {
fields.value[index] = field
meta.value!.columns = meta.value!.columns?.map((column: ColumnType) => {
if (column.id === field.fk_column_id) {
return {
...column,
...field,
id: field.fk_column_id,
}
}
return column
})
} else {
await $api.dbView.hideAllColumn(view.value.id)
localChanges.value.push(field)
}
}
await loadViewColumns()
reloadData?.()
$e('a:fields:show-all')
}
if (isUIAllowed('viewFieldEdit')) {
if (field.id && view?.value?.id) {
await $api.dbViewColumn.update(view.value.id, field.id, field)
} else if (view.value?.id) {
const insertedField = (await $api.dbViewColumn.create(view.value.id, field)) as any
const saveOrUpdate = async (field: any, index: number) => {
if (isLocalMode.value && fields.value) {
fields.value[index] = field
meta.value!.columns = meta.value!.columns?.map((column: ColumnType) => {
if (column.id === field.fk_column_id) {
return {
...column,
...field,
id: field.fk_column_id,
}
/** update the field in fields if defined */
if (fields.value) fields.value[index] = insertedField
return insertedField
}
return column
})
}
localChanges.value.push(field)
await loadViewColumns()
reloadData?.()
}
if (isUIAllowed('viewFieldEdit')) {
if (field.id && view?.value?.id) {
await $api.dbViewColumn.update(view.value.id, field.id, field)
} else if (view.value?.id) {
const insertedField = (await $api.dbViewColumn.create(view.value.id, field)) as any
const showSystemFields = computed({
get() {
return (view.value?.show_system_fields as boolean) || false
},
set(v: boolean) {
if (view?.value?.id) {
if (!isLocalMode.value) {
$api.dbView
.update(view.value.id, {
show_system_fields: v,
})
.finally(() => {
loadViewColumns()
reloadData?.()
})
}
view.value.show_system_fields = v
}
$e('a:fields:system-fields')
},
})
/** update the field in fields if defined */
if (fields.value) fields.value[index] = insertedField
const filteredFieldList = computed(() => {
return (
fields.value?.filter((field: Field) => {
if (metaColumnById?.value?.[field.fk_column_id!]?.pv) return true
return insertedField
}
}
// hide system columns if not enabled
if (!showSystemFields.value && isSystemColumn(metaColumnById?.value?.[field.fk_column_id!])) {
return false
}
await loadViewColumns()
reloadData?.()
}
if (filterQuery.value === '') {
return true
} else {
return field.title.toLowerCase().includes(filterQuery.value.toLowerCase())
}
}) || []
)
})
const showSystemFields = computed({
get() {
return (view.value?.show_system_fields as boolean) || false
},
set(v: boolean) {
if (view?.value?.id) {
if (!isLocalMode.value) {
$api.dbView
.update(view.value.id, {
show_system_fields: v,
})
.finally(() => {
loadViewColumns()
reloadData?.()
})
}
view.value.show_system_fields = v
}
$e('a:fields:system-fields')
},
})
const filteredFieldList = computed(() => {
return (
fields.value?.filter((field: Field) => {
if (metaColumnById?.value?.[field.fk_column_id!]?.pv) return true
// hide system columns if not enabled
if (!showSystemFields.value && isSystemColumn(metaColumnById?.value?.[field.fk_column_id!])) {
return false
}
const sortedAndFilteredFields = computed<ColumnType[]>(() => {
return (fields?.value
?.filter((field: Field) => {
// hide system columns if not enabled
if (
!showSystemFields.value &&
metaColumnById.value &&
metaColumnById?.value?.[field.fk_column_id!] &&
isSystemColumn(metaColumnById.value?.[field.fk_column_id!]) &&
!metaColumnById.value?.[field.fk_column_id!]?.pv
) {
return false
}
return field.show && metaColumnById?.value?.[field.fk_column_id!]
})
?.sort((a: Field, b: Field) => a.order - b.order)
?.map((field: Field) => metaColumnById?.value?.[field.fk_column_id!]) || []) as ColumnType[]
})
if (filterQuery.value === '') {
return true
} else {
return field.title.toLowerCase().includes(filterQuery.value.toLowerCase())
}
}) || []
)
})
const sortedAndFilteredFields = computed<ColumnType[]>(() => {
return (fields?.value
?.filter((field: Field) => {
// hide system columns if not enabled
if (
!showSystemFields.value &&
metaColumnById.value &&
metaColumnById?.value?.[field.fk_column_id!] &&
isSystemColumn(metaColumnById.value?.[field.fk_column_id!]) &&
!metaColumnById.value?.[field.fk_column_id!]?.pv
) {
return false
}
return field.show && metaColumnById?.value?.[field.fk_column_id!]
})
?.sort((a: Field, b: Field) => a.order - b.order)
?.map((field: Field) => metaColumnById?.value?.[field.fk_column_id!]) || []) as ColumnType[]
})
const toggleFieldVisibility = (checked: boolean, field: any) => {
const fieldIndex = fields.value?.findIndex((f) => f.fk_column_id === field.fk_column_id)
if (!fieldIndex && fieldIndex !== 0) return
addUndo({
undo: {
fn: (v: boolean) => {
field.show = !v
saveOrUpdate(field, fieldIndex)
const toggleFieldVisibility = (checked: boolean, field: any) => {
const fieldIndex = fields.value?.findIndex((f) => f.fk_column_id === field.fk_column_id)
if (!fieldIndex && fieldIndex !== 0) return
addUndo({
undo: {
fn: (v: boolean) => {
field.show = !v
saveOrUpdate(field, fieldIndex)
},
args: [checked],
},
args: [checked],
},
redo: {
fn: (v: boolean) => {
field.show = v
saveOrUpdate(field, fieldIndex)
redo: {
fn: (v: boolean) => {
field.show = v
saveOrUpdate(field, fieldIndex)
},
args: [checked],
},
args: [checked],
},
scope: defineViewScope({ view: view.value }),
})
saveOrUpdate(field, fieldIndex)
}
// reload view columns when active view changes
// or when columns count changes(delete/add)
watch(
[() => view?.value?.id, () => meta.value?.columns?.length],
async ([newViewId]) => {
// reload only if view belongs to current table
if (newViewId && view.value?.fk_model_id === meta.value?.id) {
isViewColumnsLoading.value = true
try {
await loadViewColumns()
} catch (e) {
console.error(e)
scope: defineViewScope({ view: view.value }),
})
saveOrUpdate(field, fieldIndex)
}
// reload view columns when active view changes
// or when columns count changes(delete/add)
watch(
[() => view?.value?.id, () => meta.value?.columns?.length],
async ([newViewId]) => {
// reload only if view belongs to current table
if (newViewId && view.value?.fk_model_id === meta.value?.id) {
isViewColumnsLoading.value = true
try {
await loadViewColumns()
} catch (e) {
console.error(e)
}
isViewColumnsLoading.value = false
}
isViewColumnsLoading.value = false
},
{ immediate: true },
)
const resizingColOldWith = ref('200px')
const updateGridViewColumn = async (id: string, props: Partial<GridColumnReqType>, undo = false) => {
if (!undo) {
const oldProps = Object.keys(props).reduce<Partial<GridColumnReqType>>((o: any, k) => {
if (gridViewCols.value[id][k as keyof GridColumnType]) {
if (k === 'width') o[k] = `${resizingColOldWith.value}px`
else o[k] = gridViewCols.value[id][k as keyof GridColumnType]
}
return o
}, {})
addUndo({
redo: {
fn: (w: Partial<GridColumnReqType>) => updateGridViewColumn(id, w, true),
args: [props],
},
undo: {
fn: (w: Partial<GridColumnReqType>) => updateGridViewColumn(id, w, true),
args: [oldProps],
},
scope: defineViewScope({ view: view.value }),
})
}
// sync with server if allowed
if (!isPublic.value && isUIAllowed('viewFieldEdit') && gridViewCols.value[id]?.id) {
await $api.dbView.gridColumnUpdate(gridViewCols.value[id].id as string, {
...props,
})
}
if (gridViewCols.value?.[id]) {
Object.assign(gridViewCols.value[id], {
...gridViewCols.value[id],
...props,
})
} else {
// fallback to reload
await loadViewColumns()
}
},
{ immediate: true },
)
return {
fields,
loadViewColumns,
filteredFieldList,
filterQuery,
showAll,
hideAll,
saveOrUpdate,
sortedAndFilteredFields,
showSystemFields,
metaColumnById,
toggleFieldVisibility,
isViewColumnsLoading,
}
}
return {
fields,
loadViewColumns,
filteredFieldList,
filterQuery,
showAll,
hideAll,
saveOrUpdate,
sortedAndFilteredFields,
showSystemFields,
metaColumnById,
toggleFieldVisibility,
isViewColumnsLoading,
updateGridViewColumn,
gridViewCols,
resizingColOldWith,
}
},
'useViewColumnsOrThrow',
)
export { useProvideViewColumns }
export function useViewColumnsOrThrow() {
const viewColumns = useViewColumns()
if (viewColumns == null) throw new Error('Please call `useProvideViewColumns` on the appropriate parent component')
return viewColumns
}

2
packages/nc-gui/composables/useViewFilters.ts

@ -81,7 +81,7 @@ export function useViewFilters(
const activeView = inject(ActiveViewInj, ref())
const { showSystemFields, metaColumnById } = useViewColumns(activeView, meta)
const { showSystemFields, metaColumnById } = useViewColumnsOrThrow()
const options = computed<SelectProps['options']>(() =>
meta.value?.columns?.filter((c: ColumnType) => {

4
packages/nc-gui/composables/useViewGroupBy.ts

@ -1,6 +1,6 @@
import { type ColumnType, type SelectOptionsType, UITypes, type ViewType } from 'nocodb-sdk'
import type { Ref } from 'vue'
import { GROUP_BY_VARS, ref, storeToRefs, useApi, useBase } from '#imports'
import { GROUP_BY_VARS, ref, storeToRefs, useApi, useBase, useViewColumnsOrThrow } from '#imports'
import type { Group, GroupNestedIn, Row } from '#imports'
export const useViewGroupBy = (view: Ref<ViewType | undefined>, where?: ComputedRef<string | undefined>) => {
@ -12,7 +12,7 @@ export const useViewGroupBy = (view: Ref<ViewType | undefined>, where?: Computed
const meta = inject(MetaInj)
const { gridViewCols } = useGridViewColumnOrThrow()
const { gridViewCols } = useViewColumnsOrThrow()
const groupBy = computed<{ column: ColumnType; sort: string; order?: number }[]>(() => {
const tempGroupBy: { column: ColumnType; sort: string; order?: number }[] = []

2
packages/nc-gui/pages/index/[typeOrId]/[baseId]/index/index/[viewId]/[[viewTitle]].vue

@ -20,7 +20,7 @@ watch(
until(tables)
.toMatch((tables) => tables.length > 0)
.then(() => {
getMeta(viewId as string, true)
getMeta(viewId as string)
})
},
{ immediate: true },

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

@ -170,15 +170,12 @@ export const useViewsStore = defineStore('viewsStore', () => {
return
}
isViewsLoading.value = true
isViewDataLoading.value = true
try {
await loadViews()
} catch (e) {
console.error(e)
} finally {
isViewsLoading.value = false
}
},
{ immediate: true },

Loading…
Cancel
Save