Browse Source

Nc fix/api call (#8841)

* fix: aggregate not loading

* fix: dulpicate call

* fix: scroll issue

* fix: scroll issue

* fix: random fix

* fix: test

* fix: remove console.log

* fix: set Timeout

* fix: enable none aggregation for fk

* fix: test debug

* fix: lookup attachment issue

* fix: skip system LTAR columns from aggregation

* fix: revert debug changes

* fix: if display value missing treat the first column as display value

* fix: disable system col aggregation if hidden

* fix: missing commit

* fix: exclude system column

* fix: rollup grouping/aggregation fix

---------

Co-authored-by: Pranav C <pranavxc@gmail.com>
pull/8845/head
Anbarasu 5 months ago committed by GitHub
parent
commit
d2c493aa7b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      packages/nc-gui/components/nc/PaginationV2.vue
  2. 8
      packages/nc-gui/components/smartsheet/grid/PaginationV2.vue
  3. 4
      packages/nc-gui/components/smartsheet/grid/Table.vue
  4. 4
      packages/nc-gui/components/smartsheet/grid/index.vue
  5. 45
      packages/nc-gui/composables/useViewAggregate.ts
  6. 2
      packages/nocodb-sdk/src/lib/aggregationHelper.ts
  7. 16
      packages/nocodb/src/db/BaseModelSqlv2.ts
  8. 1
      packages/nocodb/src/db/aggregation.ts
  9. 23
      packages/nocodb/src/db/generateLookupSelectQuery.ts
  10. 2
      packages/nocodb/src/services/data-table.service.ts
  11. 2
      packages/nocodb/src/services/public-datas.service.ts

2
packages/nc-gui/components/nc/PaginationV2.vue

@ -143,7 +143,7 @@ const pageSizeOptions = [
</NcButton> </NcButton>
<template #overlay> <template #overlay>
<NcMenu class="nc-scrollbar-thin nc-pagination-menu max-h-54 overflow-y-auto"> <NcMenu class="nc-scrollbar-md nc-pagination-menu max-h-54">
<NcSubMenu :key="`${localPageSize}page`" class="bg-gray-100 z-20 top-0 !sticky"> <NcSubMenu :key="`${localPageSize}page`" class="bg-gray-100 z-20 top-0 !sticky">
<template #title> <template #title>
<div class="rounded-lg text-[13px] font-medium w-full">{{ localPageSize }} / page</div> <div class="rounded-lg text-[13px] font-medium w-full">{{ localPageSize }} / page</div>

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

@ -84,10 +84,6 @@ const size = computed({
const renderAltOrOptlKey = () => { const renderAltOrOptlKey = () => {
return isMac() ? '⌥' : 'ALT' return isMac() ? '⌥' : 'ALT'
} }
onMounted(() => {
loadViewAggregate()
})
</script> </script>
<template> <template>
@ -95,7 +91,7 @@ onMounted(() => {
<div class="sticky flex items-center bg-gray-50 left-0"> <div class="sticky flex items-center bg-gray-50 left-0">
<NcDropdown <NcDropdown
:disabled="[UITypes.SpecificDBType, UITypes.ForeignKey].includes(displayFieldComputed.column?.uidt!) || isLocked" :disabled="[UITypes.SpecificDBType, UITypes.ForeignKey].includes(displayFieldComputed.column?.uidt!) || isLocked"
overlay-class-name="max-h-96 relative scroll-container nc-scrollbar-thin overflow-auto" overlay-class-name="max-h-96 relative scroll-container nc-scrollbar-md overflow-auto"
> >
<div <div
v-if="displayFieldComputed.field && displayFieldComputed.column?.id" v-if="displayFieldComputed.field && displayFieldComputed.column?.id"
@ -194,7 +190,7 @@ onMounted(() => {
<NcDropdown <NcDropdown
v-if="field && column?.id" v-if="field && column?.id"
:disabled="[UITypes.SpecificDBType, UITypes.ForeignKey].includes(column?.uidt!) || isLocked" :disabled="[UITypes.SpecificDBType, UITypes.ForeignKey].includes(column?.uidt!) || isLocked"
overlay-class-name="max-h-96 relative scroll-container nc-scrollbar-thin overflow-auto" overlay-class-name="max-h-96 relative scroll-container nc-scrollbar-md overflow-auto"
> >
<div <div
class="flex items-center overflow-x-hidden justify-end group hover:bg-gray-100 cursor-pointer text-gray-500 transition-all transition-linear px-3 py-2" class="flex items-center overflow-x-hidden justify-end group hover:bg-gray-100 cursor-pointer text-gray-500 transition-all transition-linear px-3 py-2"

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

@ -147,6 +147,8 @@ const { paste } = usePaste()
const { addLTARRef, syncLTARRefs, clearLTARCell, cleaMMCell } = useSmartsheetLtarHelpersOrThrow() const { addLTARRef, syncLTARRefs, clearLTARCell, cleaMMCell } = useSmartsheetLtarHelpersOrThrow()
const { loadViewAggregate } = useViewAggregateOrThrow()
// #Refs // #Refs
const smartTable = ref(null) const smartTable = ref(null)
@ -1522,7 +1524,7 @@ watch(
} }
isViewDataLoading.value = true isViewDataLoading.value = true
try { try {
await loadData?.() await Promise.allSettled([loadData?.(), loadViewAggregate()])
calculateSlices() calculateSlices()
} catch (e) { } catch (e) {
if (!axios.isCancel(e)) { if (!axios.isCancel(e)) {

4
packages/nc-gui/components/smartsheet/grid/index.vue

@ -31,6 +31,8 @@ const expandedFormRowState = ref<Record<string, any>>()
const tableRef = ref<typeof Table>() const tableRef = ref<typeof Table>()
useProvideViewAggregate(view, meta, xWhere)
const { const {
loadData, loadData,
paginationData, paginationData,
@ -79,8 +81,6 @@ provide(IsCalendarInj, ref(false))
provide(RowHeightInj, rowHeight) provide(RowHeightInj, rowHeight)
useProvideViewAggregate(view, meta, xWhere)
const isPublic = inject(IsPublicInj, ref(false)) const isPublic = inject(IsPublicInj, ref(false))
// reload table data reload hook as fallback to rowdatareload // reload table data reload hook as fallback to rowdatareload

45
packages/nc-gui/composables/useViewAggregate.ts

@ -71,26 +71,31 @@ const [useProvideViewAggregate, useViewAggregate] = useInjectionState(
type: string type: string
}>, }>,
) => { ) => {
if (!meta.value?.id || !view.value?.id) return // Wait for meta to be defined https://vueuse.org/shared/until/
await until(meta)
try { .toBeTruthy((c) => !!c, {
const data = !isPublic.value timeout: 10000,
? await api.dbDataTableAggregate.dbDataTableAggregate(meta.value.id, { })
viewId: view.value.id, .then(async () => {
where: where?.value, try {
...(fields ? { aggregation: fields } : {}), const data = !isPublic.value
}) ? await api.dbDataTableAggregate.dbDataTableAggregate(meta.value.id, {
: await fetchAggregatedData({ viewId: view.value.id,
where: where?.value, where: where?.value,
filtersArr: nestedFilters.value, ...(fields ? { aggregation: fields } : {}),
...(fields ? { aggregation: fields } : {}), })
}) : await fetchAggregatedData({
where: where?.value,
Object.assign(aggregations.value, data) filtersArr: nestedFilters.value,
} catch (error) { ...(fields ? { aggregation: fields } : {}),
console.log(error) })
message.error(await extractSdkResponseErrorMsgv2(error as any))
} Object.assign(aggregations.value, data)
} catch (error) {
console.log(error)
message.error(await extractSdkResponseErrorMsgv2(error as any))
}
})
} }
const updateAggregate = async (fieldId: string, agg: string) => { const updateAggregate = async (fieldId: string, agg: string) => {

2
packages/nocodb-sdk/src/lib/aggregationHelper.ts

@ -115,7 +115,7 @@ const getAvailableAggregations = (type: string, parsed_tree?): string[] => {
break; break;
case UITypes.SpecificDBType: case UITypes.SpecificDBType:
case UITypes.ForeignKey: case UITypes.ForeignKey:
return []; returnAggregations = [CommonAggregations.None];
} }
if (!returnAggregations.length) { if (!returnAggregations.length) {

16
packages/nocodb/src/db/BaseModelSqlv2.ts

@ -697,13 +697,18 @@ class BaseModelSqlv2 {
return await this.execAndParse(qb); return await this.execAndParse(qb);
} }
async aggregate(args: { filterArr?: Filter[]; where?: string }) { async aggregate(args: { filterArr?: Filter[]; where?: string }, view: View) {
try { try {
const { where, aggregation } = this._getListArgs(args as any); const { where, aggregation } = this._getListArgs(args as any);
const columns = await this.model.getColumns(this.context);
let viewColumns = ( let viewColumns = (
await GridViewColumn.list(this.context, this.viewId) await GridViewColumn.list(this.context, this.viewId)
).filter((c) => c.show); ).filter((c) => {
const col = columns.find((col) => col.id === c.fk_column_id);
return c.show && (view.show_system_fields || !isSystemColumn(col));
});
// By default, the aggregation is done based on the columns configured in the view // By default, the aggregation is done based on the columns configured in the view
// If the aggregation parameter is provided, only the columns mentioned in the aggregation parameter are considered // If the aggregation parameter is provided, only the columns mentioned in the aggregation parameter are considered
@ -721,8 +726,6 @@ class BaseModelSqlv2 {
.filter((c) => c.show); .filter((c) => c.show);
} }
const columns = await this.model.getColumns(this.context);
const aliasColObjMap = await this.model.getAliasColObjMap( const aliasColObjMap = await this.model.getAliasColObjMap(
this.context, this.context,
columns, columns,
@ -768,6 +771,11 @@ class BaseModelSqlv2 {
const col = columns.find((c) => c.id === viewColumn.fk_column_id); const col = columns.find((c) => c.id === viewColumn.fk_column_id);
if (!col) return null; if (!col) return null;
if (!viewColumn.aggregation) return;
// Skip system LTAR columns
if (isLinksOrLTAR(col) && col.system) return;
const aggSql = await applyAggregation({ const aggSql = await applyAggregation({
baseModelSqlv2: this, baseModelSqlv2: this,
aggregation: viewColumn.aggregation, aggregation: viewColumn.aggregation,

1
packages/nocodb/src/db/aggregation.ts

@ -162,6 +162,7 @@ export default async function applyAggregation({
column: column, column: column,
alias: null, alias: null,
model, model,
isAggregation: true,
}) })
).builder; ).builder;
break; break;

23
packages/nocodb/src/db/generateLookupSelectQuery.ts

@ -1,4 +1,4 @@
import { RelationTypes, UITypes } from 'nocodb-sdk'; import { isVirtualCol, RelationTypes, UITypes } from 'nocodb-sdk';
import type LookupColumn from '../models/LookupColumn'; import type LookupColumn from '../models/LookupColumn';
import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2'; import type { BaseModelSqlv2 } from '~/db/BaseModelSqlv2';
import type { import type {
@ -27,7 +27,7 @@ export async function getDisplayValueOfRefTable(
.getColOptions(context) .getColOptions(context)
.then((colOpt) => colOpt.getRelatedTable(context)) .then((colOpt) => colOpt.getRelatedTable(context))
.then((model) => model.getColumns(context)) .then((model) => model.getColumns(context))
.then((cols) => cols.find((col) => col.pv)); .then((cols) => cols.find((col) => col.pv) || cols[0]);
} }
// this function will generate the query for lookup column // this function will generate the query for lookup column
@ -41,12 +41,14 @@ export default async function generateLookupSelectQuery({
alias, alias,
model: _model, model: _model,
getAlias = getAliasGenerator('__lk_slt_'), getAlias = getAliasGenerator('__lk_slt_'),
isAggregation = false,
}: { }: {
column: Column; column: Column;
baseModelSqlv2: BaseModelSqlv2; baseModelSqlv2: BaseModelSqlv2;
alias: string; alias: string;
model: Model; model: Model;
getAlias?: ReturnType<typeof getAliasGenerator>; getAlias?: ReturnType<typeof getAliasGenerator>;
isAggregation?: boolean;
}): Promise<any> { }): Promise<any> {
const knex = baseModelSqlv2.dbDriver; const knex = baseModelSqlv2.dbDriver;
@ -298,11 +300,6 @@ export default async function generateLookupSelectQuery({
}); });
switch (lookupColumn.uidt) { switch (lookupColumn.uidt) {
case UITypes.Attachment:
NcError.badRequest(
'Group by using attachment column is not supported',
);
break;
case UITypes.Links: case UITypes.Links:
case UITypes.Rollup: case UITypes.Rollup:
{ {
@ -316,7 +313,9 @@ export default async function generateLookupSelectQuery({
alias: prevAlias, alias: prevAlias,
}) })
).builder; ).builder;
selectQb.select(knex.raw(builder).wrap('(', ')')); selectQb.select({
[lookupColumn.id]: knex.raw(builder).wrap('(', ')'),
});
} }
break; break;
case UITypes.Formula: case UITypes.Formula:
@ -349,6 +348,14 @@ export default async function generateLookupSelectQuery({
}); });
} }
break; break;
case UITypes.Attachment:
if (!isAggregation) {
NcError.badRequest(
'Group by using attachment column is not supported',
);
break;
}
// eslint-disable-next-line no-fallthrough
default: default:
{ {
selectQb.select( selectQb.select(

2
packages/nocodb/src/services/data-table.service.ts

@ -98,7 +98,7 @@ export class DataTableService {
listArgs.aggregation = JSON.parse(listArgs.aggregation); listArgs.aggregation = JSON.parse(listArgs.aggregation);
} catch (e) {} } catch (e) {}
const data = await baseModel.aggregate(listArgs); const data = await baseModel.aggregate(listArgs, view);
return data; return data;
} }

2
packages/nocodb/src/services/public-datas.service.ts

@ -138,7 +138,7 @@ export class PublicDatasService {
listArgs.aggregation = JSON.parse(listArgs.aggregation); listArgs.aggregation = JSON.parse(listArgs.aggregation);
} catch (e) {} } catch (e) {}
return await baseModel.aggregate(listArgs); return await baseModel.aggregate(listArgs, view);
} }
// todo: Handle the error case where view doesnt belong to model // todo: Handle the error case where view doesnt belong to model

Loading…
Cancel
Save