import type { Ref } from 'vue' import { type ColumnType, CommonAggregations, type FormulaType, type TableType, UITypes, type ViewType, ViewTypes, getAvailableAggregations, } from 'nocodb-sdk' const [useProvideViewAggregate, useViewAggregate] = useInjectionState( ( view: Ref, meta: Ref | ComputedRef, where?: ComputedRef, ) => { const { $api: api } = useNuxtApp() const fields = inject(FieldsInj, ref([])) const isPublic = inject(IsPublicInj, ref(false)) const { gridViewCols, updateGridViewColumn } = useViewColumnsOrThrow() const { nestedFilters } = useSmartsheetStoreOrThrow() const { isUIAllowed } = useRoles() const { fetchAggregatedData } = useSharedView() const aggregations = ref({}) as Ref> const reloadAggregate = inject(ReloadAggregateHookInj) const visibleFieldsComputed = computed(() => { const field = fields.value.map((field, index) => ({ field, index })).filter((f) => f.index !== 0) return field.map((f) => { const gridField = gridViewCols.value[f.field.id!] if (!gridField) { return { field: null, index: f.index } } return { value: aggregations.value[f.field.title!] ?? null, field: gridField, column: f.field, index: f.index, width: `${Number((gridField.width ?? '').replace('px', ''))}px` || '180px', } }) }) const displayFieldComputed = computed(() => { if (!fields.value?.length || !gridViewCols.value) return { field: null, width: '180px', } return { value: aggregations.value[fields.value[0].title] ?? null, column: fields.value[0], field: gridViewCols.value[fields.value[0].id!], width: `${Number((gridViewCols.value[fields.value[0]!.id!].width ?? '').replace('px', '')) + 64}px` || '244px', } }) const getAggregations = (column: ColumnType) => { if (column.uidt === UITypes.Formula && (column.colOptions as any)?.parsed_tree?.dataType) { return getAvailableAggregations(column.uidt!, (column.colOptions as any).parsed_tree) } return getAvailableAggregations(column.uidt!) } const loadViewAggregate = async ( fields?: Array<{ field: string type: string }>, ) => { // Wait for meta to be defined https://vueuse.org/shared/until/ await until(() => !!meta.value) .toBeTruthy({ timeout: 10000, }) .then(async () => { if (!view.value?.type || view.value?.type !== ViewTypes.GRID) return try { const data = !isPublic.value ? await api.dbDataTableAggregate.dbDataTableAggregate(meta.value.id, { viewId: view.value.id, where: where?.value, ...(isUIAllowed('filterSync') ? {} : { filterArrJson: JSON.stringify(nestedFilters.value) }), ...(fields ? { aggregation: fields } : {}), }) : await fetchAggregatedData({ where: where?.value, filtersArr: nestedFilters.value, ...(fields ? { aggregation: fields } : {}), }) Object.assign(aggregations.value, data) } catch (error) { console.log(error) message.error(await extractSdkResponseErrorMsgv2(error as any)) } }) } const updateAggregate = async (fieldId: string, agg: string) => { await reloadAggregate?.trigger({ fields: [ { title: fields.value.find((f) => f.id === fieldId)?.title ?? '', aggregation: agg, }, ], }) await updateGridViewColumn(fieldId, { aggregation: agg }) } const aggregateFormulaFields = computed(() => { return fields.value .filter((field) => { if (!field?.id || !field?.title) return false if ( !isFormula(field) || !gridViewCols.value[field.id] || !gridViewCols.value[field.id]?.aggregation || gridViewCols.value[field.id]?.aggregation === CommonAggregations.None || !(field.colOptions as FormulaType)?.formula_raw ) { return false } return true }) .map((field) => { return { id: field.id, aggregation: gridViewCols.value[field.id!]?.aggregation ?? CommonAggregations.None, formula_raw: (field.colOptions as FormulaType)?.formula_raw ?? '', } }) }) reloadAggregate?.on(async (_fields) => { if (!_fields || !_fields?.fields.length) { await loadViewAggregate() } if (_fields?.fields) { const fieldAggregateMapping = _fields.fields.reduce((acc, field) => { const f = fields.value.find((f) => f.title === field.title) if (!f?.id) return acc acc[f.id] = field.aggregation ?? gridViewCols.value[f.id].aggregation ?? CommonAggregations.None for (const formulaField of aggregateFormulaFields.value) { if (!acc[formulaField.id!] && formulaField.formula_raw.includes(field.title)) { acc[formulaField.id!] = formulaField.aggregation } } return acc }, {} as Record) await loadViewAggregate( Object.entries(fieldAggregateMapping).map(([field, type]) => ({ field, type, })), ) } }) return { loadViewAggregate, isPublic, updateAggregate, getAggregations, displayFieldComputed, visibleFieldsComputed, } }, ) export { useProvideViewAggregate } export function useViewAggregateOrThrow() { const viewAggregate = useViewAggregate() if (viewAggregate == null) throw new Error('Please call `useProvideViewAggregate` on the appropriate parent component') return viewAggregate }