Browse Source

feat(nc-gui): add & remove group by this field

pull/8309/head
Ramesh Mane 7 months ago
parent
commit
287725923f
  1. 20
      packages/nc-gui/components/smartsheet/header/Menu.vue
  2. 78
      packages/nc-gui/components/smartsheet/toolbar/GroupByMenu.vue
  3. 82
      packages/nc-gui/composables/useViewGroupBy.ts
  4. 3
      packages/nc-gui/lib/enums.ts

20
packages/nc-gui/components/smartsheet/header/Menu.vue

@ -52,6 +52,8 @@ const { addUndo, defineModelScope, defineViewScope } = useUndoRedo()
const showDeleteColumnModal = ref(false) const showDeleteColumnModal = ref(false)
const { gridViewCols } = useViewColumnsOrThrow()
const setAsDisplayValue = async () => { const setAsDisplayValue = async () => {
try { try {
const currentDisplayValue = meta?.value?.columns?.find((f) => f.pv) const currentDisplayValue = meta?.value?.columns?.find((f) => f.pv)
@ -296,8 +298,14 @@ const isDuplicateAllowed = computed(() => {
return column?.value && !column.value.system return column?.value && !column.value.system
}) })
const isGroupedByThisField = computed(() => {
return !!gridViewCols.value[column?.value?.id]?.group_by
})
const filterOrGroupByThisField = (event: SmartsheetStoreEvents) => { const filterOrGroupByThisField = (event: SmartsheetStoreEvents) => {
eventBus.emit(event) if (column?.value) {
eventBus.emit(event, column.value)
}
isOpen.value = false isOpen.value = false
} }
</script> </script>
@ -378,11 +386,17 @@ const filterOrGroupByThisField = (event: SmartsheetStoreEvents) => {
</div> </div>
</NcMenuItem> </NcMenuItem>
<NcMenuItem @click="filterOrGroupByThisField(SmartsheetStoreEvents.GROUP_BY_ADD)"> <NcMenuItem
@click="
filterOrGroupByThisField(
isGroupedByThisField ? SmartsheetStoreEvents.GROUP_BY_REMOVE : SmartsheetStoreEvents.GROUP_BY_ADD,
)
"
>
<div v-e="['a:field:add:groupby']" class="nc-column-groupby nc-header-menu-item"> <div v-e="['a:field:add:groupby']" class="nc-column-groupby nc-header-menu-item">
<component :is="iconMap.group" class="text-gray-700" /> <component :is="iconMap.group" class="text-gray-700" />
<!-- Group by this field --> <!-- Group by this field -->
Group by this field {{ isGroupedByThisField ? "Don't group by this field" : 'Group by this field' }}
</div> </div>
</NcMenuItem> </NcMenuItem>

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

@ -8,30 +8,26 @@ import {
computed, computed,
getSortDirectionOptions, getSortDirectionOptions,
inject, inject,
onMounted,
ref, ref,
useMenuCloseOnEsc, useMenuCloseOnEsc,
useMetas,
useNuxtApp, useNuxtApp,
useSmartsheetStoreOrThrow, useSmartsheetStoreOrThrow,
useViewColumnsOrThrow, useViewColumnsOrThrow,
watch, watch,
} from '#imports' } from '#imports'
const excludedGroupingUidt = [UITypes.Attachment]
const meta = inject(MetaInj, ref()) const meta = inject(MetaInj, ref())
const view = inject(ActiveViewInj, ref()) const view = inject(ActiveViewInj, ref())
const isLocked = inject(IsLockedInj, ref(false)) const isLocked = inject(IsLockedInj, ref(false))
const { gridViewCols, updateGridViewColumn, metaColumnById, showSystemFields } = useViewColumnsOrThrow() const { gridViewCols, updateGridViewColumn, metaColumnById, showSystemFields } = useViewColumnsOrThrow()
const { fieldsToGroupBy } = useViewGroupBy(view)
const { $e } = useNuxtApp() const { $e } = useNuxtApp()
const _groupBy = ref<{ fk_column_id?: string; sort: string; order: number }[]>([]) const _groupBy = ref<{ fk_column_id?: string; sort: string; order: number }[]>([])
const { getMeta } = useMetas()
const groupBy = computed<{ fk_column_id?: string; sort: string; order: number }[]>(() => { const groupBy = computed<{ fk_column_id?: string; sort: string; order: number }[]>(() => {
const tempGroupBy: { fk_column_id?: string; sort: string; order: number }[] = [] const tempGroupBy: { fk_column_id?: string; sort: string; order: number }[] = []
Object.values(gridViewCols.value).forEach((col) => { Object.values(gridViewCols.value).forEach((col) => {
@ -53,24 +49,8 @@ const { eventBus } = useSmartsheetStoreOrThrow()
const { isMobileMode } = useGlobal() const { isMobileMode } = useGlobal()
const supportedLookups = ref<string[]>([])
const showCreateGroupBy = ref(false) const showCreateGroupBy = ref(false)
const fieldsToGroupBy = computed(() => {
const fields = meta.value?.columns || []
return fields.filter((field) => {
if (excludedGroupingUidt.includes(field.uidt as UITypes)) return false
if (field.uidt === UITypes.Lookup) {
return field.id && supportedLookups.value.includes(field.id)
}
return true
})
})
const columns = computed(() => meta.value?.columns || []) const columns = computed(() => meta.value?.columns || [])
const columnByID = computed(() => const columnByID = computed(() =>
@ -152,6 +132,7 @@ const saveGroupBy = async () => {
} }
const addFieldToGroupBy = (column: ColumnType) => { const addFieldToGroupBy = (column: ColumnType) => {
console.log('groupByField', column)
_groupBy.value.push({ fk_column_id: column.id, sort: 'asc', order: _groupBy.value.length + 1 }) _groupBy.value.push({ fk_column_id: column.id, sort: 'asc', order: _groupBy.value.length + 1 })
saveGroupBy() saveGroupBy()
showCreateGroupBy.value = false showCreateGroupBy.value = false
@ -174,54 +155,19 @@ watch(open, () => {
} }
}) })
const loadAllowedLookups = async () => { eventBus.on(async (event, column) => {
const filteredLookupCols = [] if (!column?.id) return
try {
for (const col of meta.value?.columns || []) {
if (col.uidt !== UITypes.Lookup) continue
let nextCol: ColumnType = col
// check the lookup column is supported type or not
while (nextCol && nextCol.uidt === UITypes.Lookup) {
const lookupRelation = (await getMeta(nextCol.fk_model_id as string))?.columns?.find(
(c) => c.id === (nextCol?.colOptions as LookupType).fk_relation_column_id,
)
const relatedTableMeta = await getMeta(
(lookupRelation?.colOptions as LinkToAnotherRecordType).fk_related_model_id as string,
)
nextCol = relatedTableMeta?.columns?.find(
(c) => c.id === ((nextCol?.colOptions as LookupType).fk_lookup_column_id as string),
) as ColumnType
// if next column is same as root lookup column then break the loop
// since it's going to be a circular loop, and ignore the column
if (nextCol?.id === col.id) {
break
}
}
if (nextCol?.uidt !== UITypes.Attachment && col.id) filteredLookupCols.push(col.id) console.log('_groupBy', column, _groupBy.value)
}
supportedLookups.value = filteredLookupCols if (event === SmartsheetStoreEvents.GROUP_BY_ADD) {
} catch (e) { addFieldToGroupBy(column)
console.error(e) } else if (event === SmartsheetStoreEvents.GROUP_BY_REMOVE) {
} if (groupedByColumnIds.value.length === 0) return
}
onMounted(async () => { _groupBy.value = _groupBy.value.filter((g) => g.fk_column_id !== column.id)
await loadAllowedLookups()
})
watch(meta, async () => { await saveGroupBy()
await loadAllowedLookups()
})
eventBus.on(async (event, payload) => {
if (event === SmartsheetStoreEvents.GROUP_BY_ADD) {
open.value = true
} }
}) })
</script> </script>

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

@ -1,10 +1,13 @@
import { type ColumnType, type SelectOptionsType, UITypes, type ViewType } from 'nocodb-sdk' import { UITypes } from 'nocodb-sdk'
import type { ColumnType, SelectOptionsType, ViewType, LookupType, LinkToAnotherRecordType } from 'nocodb-sdk'
import type { Ref } from 'vue' import type { Ref } from 'vue'
import { message } from 'ant-design-vue' import { message } from 'ant-design-vue'
import { extractSdkResponseErrorMsg } from '../utils' import { extractSdkResponseErrorMsg } from '../utils'
import { GROUP_BY_VARS, ref, storeToRefs, useApi, useBase, useViewColumnsOrThrow } from '#imports' import { GROUP_BY_VARS, ref, storeToRefs, useApi, useBase, useViewColumnsOrThrow, useMetas } from '#imports'
import type { Group, GroupNestedIn, Row } from '#imports' import type { Group, GroupNestedIn, Row } from '#imports'
const excludedGroupingUidt = [UITypes.Attachment, UITypes.QrCode, UITypes.Barcode]
export const useViewGroupBy = (view: Ref<ViewType | undefined>, where?: ComputedRef<string | undefined>) => { export const useViewGroupBy = (view: Ref<ViewType | undefined>, where?: ComputedRef<string | undefined>) => {
const { api } = useApi() const { api } = useApi()
@ -18,6 +21,8 @@ export const useViewGroupBy = (view: Ref<ViewType | undefined>, where?: Computed
const { gridViewCols } = useViewColumnsOrThrow() const { gridViewCols } = useViewColumnsOrThrow()
const { getMeta } = useMetas()
const groupBy = computed<{ column: ColumnType; sort: string; order?: number }[]>(() => { const groupBy = computed<{ column: ColumnType; sort: string; order?: number }[]>(() => {
const tempGroupBy: { column: ColumnType; sort: string; order?: number }[] = [] const tempGroupBy: { column: ColumnType; sort: string; order?: number }[] = []
Object.values(gridViewCols.value).forEach((col) => { Object.values(gridViewCols.value).forEach((col) => {
@ -54,6 +59,22 @@ export const useViewGroupBy = (view: Ref<ViewType | undefined>, where?: Computed
return appInfo.value.defaultGroupByLimit?.limitRecord || 10 return appInfo.value.defaultGroupByLimit?.limitRecord || 10
}) })
const supportedLookups = ref<string[]>([])
const fieldsToGroupBy = computed(() => {
const fields = meta?.value?.columns || []
return fields.filter((field) => {
if (excludedGroupingUidt.includes(field.uidt as UITypes)) return false
if (field.uidt === UITypes.Lookup) {
return field.id && supportedLookups.value.includes(field.id)
}
return true
})
})
const rootGroup = ref<Group>({ const rootGroup = ref<Group>({
key: 'root', key: 'root',
color: 'root', color: 'root',
@ -464,5 +485,60 @@ export const useViewGroupBy = (view: Ref<ViewType | undefined>, where?: Computed
} }
} }
return { rootGroup, groupBy, isGroupBy, loadGroups, loadGroupData, loadGroupPage, groupWrapperChangePage, redistributeRows } const loadAllowedLookups = async () => {
const filteredLookupCols = []
try {
for (const col of meta?.value?.columns || []) {
if (col.uidt !== UITypes.Lookup) continue
let nextCol: ColumnType = col
// check the lookup column is supported type or not
while (nextCol && nextCol.uidt === UITypes.Lookup) {
const lookupRelation = (await getMeta(nextCol.fk_model_id as string))?.columns?.find(
(c) => c.id === (nextCol?.colOptions as LookupType).fk_relation_column_id,
)
const relatedTableMeta = await getMeta(
(lookupRelation?.colOptions as LinkToAnotherRecordType).fk_related_model_id as string,
)
nextCol = relatedTableMeta?.columns?.find(
(c) => c.id === ((nextCol?.colOptions as LookupType).fk_lookup_column_id as string),
) as ColumnType
// if next column is same as root lookup column then break the loop
// since it's going to be a circular loop, and ignore the column
if (nextCol?.id === col.id) {
break
}
}
if (nextCol?.uidt !== UITypes.Attachment && col.id) filteredLookupCols.push(col.id)
}
supportedLookups.value = filteredLookupCols
} catch (e) {
console.error(e)
}
}
onMounted(async () => {
await loadAllowedLookups()
})
watch(meta, async () => {
await loadAllowedLookups()
})
return {
rootGroup,
groupBy,
isGroupBy,
fieldsToGroupBy,
loadGroups,
loadGroupData,
loadGroupPage,
groupWrapperChangePage,
redistributeRows,
}
} }

3
packages/nc-gui/lib/enums.ts

@ -82,7 +82,8 @@ export enum SmartsheetStoreEvents {
MAPPED_BY_COLUMN_CHANGE = 'mapped-by-column-change', MAPPED_BY_COLUMN_CHANGE = 'mapped-by-column-change',
CLEAR_NEW_ROW = 'clear-new-row', CLEAR_NEW_ROW = 'clear-new-row',
GROUP_BY_ADD = 'group-by-add', GROUP_BY_ADD = 'group-by-add',
FILTER_ADD = 'filter-add' GROUP_BY_REMOVE = 'group-by-remove',
FILTER_ADD = 'filter-add',
} }
export enum DataSourcesSubTab { export enum DataSourcesSubTab {

Loading…
Cancel
Save