diff --git a/packages/nc-gui/components/smartsheet/grid/GroupBy.vue b/packages/nc-gui/components/smartsheet/grid/GroupBy.vue index 3e1911a16a..b6a6146e88 100644 --- a/packages/nc-gui/components/smartsheet/grid/GroupBy.vue +++ b/packages/nc-gui/components/smartsheet/grid/GroupBy.vue @@ -108,16 +108,21 @@ onBeforeUnmount(async () => { reloadViewDataHook?.off(reloadViewDataHandler) }) -watch( - [() => vGroup.value.key], - async (n, o) => { - if (n !== o) { - if (!vGroup.value.nested) { - await _loadGroupData(vGroup.value, true) - } +watch([() => vGroup.value.key], async (n, o) => { + if (n !== o) { + if (!vGroup.value.nested) { + await _loadGroupData(vGroup.value, true) + } else if (vGroup.value.nested) { + await props.loadGroups({}, vGroup.value) } - }, -) + } +}) + +onMounted(async () => { + if (vGroup.value.root === true) { + await props.loadGroups({}, vGroup.value) + } +}) if (vGroup.value.root === true) provide(ScrollParentInj, wrapper) diff --git a/packages/nc-gui/composables/useViewGroupBy.ts b/packages/nc-gui/composables/useViewGroupBy.ts index 445a05f662..b2f08ae3d6 100644 --- a/packages/nc-gui/composables/useViewGroupBy.ts +++ b/packages/nc-gui/composables/useViewGroupBy.ts @@ -27,19 +27,19 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( const groupByLimit: number = 3 const { api } = useApi() - + const { appInfo } = useGlobal() - + const { base } = storeToRefs(useBase()) - + const { sharedView, fetchSharedViewData } = useSharedView() - + const { gridViewCols } = useViewColumnsOrThrow() - + const { getMeta } = useMetas() - + const sharedViewPassword = inject(SharedViewPasswordInj, ref(null)) - + const groupBy = computed<{ column: ColumnType; sort: string; order?: number }[]>(() => { const tempGroupBy: { column: ColumnType; sort: string; order?: number }[] = [] Object.values(gridViewCols.value).forEach((col) => { @@ -57,37 +57,37 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( tempGroupBy.sort((a, b) => (a.order ?? Infinity) - (b.order ?? Infinity)) return tempGroupBy }) - + const isGroupBy = computed(() => !!groupBy.value.length) - + const { isUIAllowed } = useRoles() - + const { sorts, nestedFilters } = useSmartsheetStoreOrThrow() - + const reloadViewDataHook = inject(ReloadViewDataHookInj, createEventHook()) - + const groupByGroupLimit = computed(() => { return appInfo.value.defaultGroupByLimit?.limitGroup || 10 }) - + const groupByRecordLimit = computed(() => { return appInfo.value.defaultGroupByLimit?.limitRecord || 10 }) - + const supportedLookups = ref([]) - + const fieldsToGroupBy = computed(() => (meta?.value?.columns || []).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({ key: 'root', color: 'root', @@ -99,12 +99,12 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( children: [], root: true, }) - + async function groupWrapperChangePage(page: number, groupWrapper?: Group) { groupWrapper = groupWrapper || rootGroup.value - + if (!groupWrapper) return - + groupWrapper.paginationData.page = page await loadGroups( { @@ -113,37 +113,37 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( groupWrapper, ) } - + const formatData = (list: Record[]) => list.map((row) => ({ row: { ...row }, oldRow: { ...row }, rowMeta: {}, })) - + const valueToTitle = (value: string, col: ColumnType) => { if (col.uidt === UITypes.Checkbox) { return value ? GROUP_BY_VARS.TRUE : GROUP_BY_VARS.FALSE } - + if ([UITypes.User, UITypes.CreatedBy, UITypes.LastModifiedBy].includes(col.uidt as UITypes)) { if (!value) { return GROUP_BY_VARS.NULL } } - + // convert to JSON string if non-string value if (value && typeof value === 'object') { value = JSON.stringify(value) } - + return value ?? GROUP_BY_VARS.NULL } - + const colors = ref(enumColor.light) - + const nextGroupColor = ref(colors.value[0]) - + const getNextColor = () => { const tempColor = nextGroupColor.value const index = colors.value.indexOf(nextGroupColor.value) @@ -154,7 +154,7 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( } return tempColor } - + const findKeyColor = (key?: string, col?: ColumnType): string => { if (col) { switch (col.uidt) { @@ -188,7 +188,7 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( } return key ? getNextColor() : 'gray' } - + const calculateNestedWhere = (nestedIn: GroupNestedIn[], existing = '') => { return nestedIn.reduce((acc, curr) => { if (curr.key === GROUP_BY_VARS.NULL) { @@ -214,30 +214,30 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( return acc }, existing) } - + async function loadGroups(params: any = {}, group?: Group) { try { group = group || rootGroup.value - + if (!base?.value?.id || !view.value?.id || !view.value?.fk_model_id || !group) return - + if (groupBy.value.length === 0) { group.children = [] return } - + if (group.nestedIn.length > groupBy.value.length) return - + if (group.nestedIn.length === 0) nextGroupColor.value = colors.value[0] const groupby = groupBy.value[group.nestedIn.length] - + const nestedWhere = calculateNestedWhere(group.nestedIn, where?.value) if (!groupby || !groupby.column.title) return - + if (isPublic && !sharedView.value?.uuid) { return } - + const response = !isPublic ? await api.dbViewRow.groupBy('noco', base.value.id, view.value.fk_model_id, view.value.id, { offset: ((group.paginationData.page ?? 0) - 1) * (group.paginationData.pageSize ?? groupByGroupLimit.value), @@ -267,7 +267,7 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( }, }, ) - + const tempList: Group[] = response.list.reduce((acc: Group[], curr: Record) => { const keyExists = acc.find( (a) => a.key === valueToTitle(curr[groupby.column.column_name!] ?? curr[groupby.column.title!], groupby.column), @@ -302,9 +302,9 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( } return acc }, []) - + if (!group.children) group.children = [] - + for (const temp of tempList) { const keyExists = group.children?.find((a) => a.key === temp.key) if (keyExists) { @@ -320,10 +320,10 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( } group.children.push(temp) } - + // clear rest of the children group.children = group.children.filter((c) => tempList.find((t) => t.key === c.key)) - + if (group.count <= (group.paginationData.pageSize ?? groupByGroupLimit.value)) { group.children.sort((a, b) => { const orderA = tempList.findIndex((t) => t.key === a.key) @@ -331,9 +331,9 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( return orderA - orderB }) } - + group.paginationData = response.pageInfo - + // to cater the case like when querying with a non-zero offset // the result page may point to the target page where the actual returned data don't display on const expectedPage = Math.max(1, Math.ceil(group.paginationData.totalRows! / group.paginationData.pageSize!)) @@ -344,25 +344,25 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( message.error(await extractSdkResponseErrorMsg(e)) } } - + async function loadGroupData(group: Group, force = false, params: any = {}) { try { if (!base?.value?.id || !view.value?.id || !view.value?.fk_model_id) return - + if (group.children && !force) return - + if (!group.paginationData) { group.paginationData = { page: 1, pageSize: groupByRecordLimit.value } } - + const nestedWhere = calculateNestedWhere(group.nestedIn, where?.value) - + const query = { offset: ((group.paginationData.page ?? 0) - 1) * (group.paginationData.pageSize ?? groupByRecordLimit.value), limit: group.paginationData.pageSize ?? groupByRecordLimit.value, where: `${nestedWhere}`, } - + const response = !isPublic ? await api.dbViewRow.list('noco', base.value.id, view.value.fk_model_id, view.value.id, { ...query, @@ -371,7 +371,7 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( ...(isUIAllowed('filterSync') ? {} : { filterArrJson: JSON.stringify(nestedFilters.value) }), } as any) : await fetchSharedViewData({ sortsArr: sorts.value, filtersArr: nestedFilters.value, ...query }) - + group.count = response.pageInfo.totalRows ?? 0 group.rows = formatData(response.list) group.paginationData = response.pageInfo @@ -379,7 +379,7 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( message.error(await extractSdkResponseErrorMsg(e)) } } - + const loadGroupPage = async (group: Group, p: number) => { if (!group.paginationData) { group.paginationData = { page: 1, pageSize: groupByRecordLimit.value } @@ -387,17 +387,17 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( group.paginationData.page = p await loadGroupData(group, true) } - + const refreshNested = (group?: Group, nestLevel = 0) => { group = group || rootGroup.value if (!group) return - + if (nestLevel < groupBy.value.length) { group.nested = true } else { group.nested = false } - + if (group.nested) { if (group?.rows) { group.rows = [] @@ -407,28 +407,26 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( group.children = [] } } - + if (nestLevel > groupBy.value.length) return - + for (const child of group.children || []) { refreshNested(child, nestLevel + 1) } } - + watch( () => groupBy.value.length, async () => { if (groupBy.value.length > 0) { rootGroup.value.paginationData = { page: 1, pageSize: groupByGroupLimit.value } rootGroup.value.column = {} as any - await loadGroups() refreshNested() nextTick(() => reloadViewDataHook?.trigger()) } }, - { immediate: true }, ) - + const findGroupByNestedIn = (nestedIn: GroupNestedIn[], group?: Group, nestLevel = 0): Group => { group = group || rootGroup.value if (nestLevel >= nestedIn.length) return group @@ -441,12 +439,12 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( } return group } - + const parentGroup = (group: Group) => { const parent = findGroupByNestedIn(group.nestedIn.slice(0, -1)) return parent } - + const modifyCount = (group: Group, countEffect: number) => { if (!group) return group.count += countEffect @@ -460,7 +458,7 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( if (group.root) return modifyCount(parentGroup(group), countEffect) } - + const findGroupForRow = (row: Row, group?: Group, nestLevel = 0): { found: boolean; group: Group } => { group = group || rootGroup.value if (group.nested) { @@ -475,7 +473,7 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( } return { found: true, group } } - + const redistributeRows = (group?: Group) => { group = group || rootGroup.value if (!group) return @@ -505,52 +503,51 @@ const [useProvideViewGroupBy, useViewGroupBy] = useInjectionState( group.children?.forEach((g) => redistributeRows(g)) } } - + 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() + + watch([() => view?.value?.id, () => meta.value?.columns], async ([newViewId]) => { + // reload only if view belongs to current table + if (newViewId && view.value?.fk_model_id === meta.value?.id) { + await loadAllowedLookups() + } }) - + return { rootGroup, groupBy,