@platforma-sdk/ui-vue 1.5.56 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +19 -0
- package/dist/lib.js +31293 -31207
- package/dist/lib.umd.cjs +72 -72
- package/dist/src/aggrid.d.ts.map +1 -1
- package/dist/src/components/PlAgDataTable/PlAgDataTable.vue.d.ts +1 -1
- package/dist/src/components/PlAgDataTable/PlAgDataTable.vue.d.ts.map +1 -1
- package/dist/src/components/PlAgDataTable/{OverlayLoading.vue.d.ts → PlAgOverlayLoading.vue.d.ts} +1 -1
- package/dist/src/components/PlAgDataTable/PlAgOverlayLoading.vue.d.ts.map +1 -0
- package/dist/src/components/PlAgDataTable/{OverlayNoRows.vue.d.ts → PlAgOverlayNoRows.vue.d.ts} +1 -1
- package/dist/src/components/PlAgDataTable/PlAgOverlayNoRows.vue.d.ts.map +1 -0
- package/dist/src/components/PlAgDataTable/index.d.ts +2 -0
- package/dist/src/components/PlAgDataTable/index.d.ts.map +1 -1
- package/dist/src/components/PlAgDataTable/sources/table-source-heterogeneous.d.ts +37 -0
- package/dist/src/components/PlAgDataTable/sources/table-source-heterogeneous.d.ts.map +1 -0
- package/dist/src/components/PlAgDataTable/sources/table-source.d.ts +6 -4
- package/dist/src/components/PlAgDataTable/sources/table-source.d.ts.map +1 -1
- package/dist/src/components/PlAgDataTable/types.d.ts +3 -3
- package/dist/src/components/PlAgDataTable/types.d.ts.map +1 -1
- package/dist/src/lib.d.ts +3 -1
- package/dist/src/lib.d.ts.map +1 -1
- package/dist/style.css +1 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/aggrid.ts +4 -2
- package/src/components/PlAgDataTable/PlAgDataTable.vue +70 -63
- package/src/components/PlAgDataTable/{OverlayLoading.vue → PlAgOverlayLoading.vue} +1 -1
- package/src/components/PlAgDataTable/{OverlayNoRows.vue → PlAgOverlayNoRows.vue} +1 -1
- package/src/components/PlAgDataTable/assets/loading-cat.png +0 -0
- package/src/components/PlAgDataTable/assets/no-data-cat.png +0 -0
- package/src/components/PlAgDataTable/index.ts +2 -0
- package/src/components/PlAgDataTable/sources/table-source-heterogeneous.ts +192 -0
- package/src/components/PlAgDataTable/sources/table-source.ts +56 -23
- package/src/components/PlAgDataTable/types.ts +3 -3
- package/src/lib.ts +3 -1
- package/dist/src/components/PlAgDataTable/OverlayLoading.vue.d.ts.map +0 -1
- package/dist/src/components/PlAgDataTable/OverlayNoRows.vue.d.ts.map +0 -1
- package/src/components/PlAgDataTable/assets/cat-in-bag.png +0 -0
- package/src/components/PlAgDataTable/assets/sad-cat.png +0 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platforma-sdk/ui-vue",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.6.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/lib.umd.cjs",
|
|
6
6
|
"module": "dist/lib.js",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"lru-cache": "^11.0.1",
|
|
22
22
|
"vue": "^3.5.11",
|
|
23
23
|
"canonicalize": "^2.0.0",
|
|
24
|
-
"@
|
|
25
|
-
"@
|
|
24
|
+
"@milaboratories/uikit": "^1.2.20",
|
|
25
|
+
"@platforma-sdk/model": "^1.6.0"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@ag-grid-community/client-side-row-model": "^32.2.2",
|
package/src/aggrid.ts
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
-
import { getEnvironmentValue } from '@platforma-sdk/model';
|
|
2
1
|
import { LicenseManager } from '@ag-grid-enterprise/core';
|
|
2
|
+
import { getEnvironmentValue } from '@platforma-sdk/model';
|
|
3
3
|
|
|
4
4
|
export function activateAgGrid() {
|
|
5
5
|
const agGridLicense = getEnvironmentValue('AGGRID_LICENSE');
|
|
6
6
|
if (agGridLicense) {
|
|
7
7
|
LicenseManager.setLicenseKey(agGridLicense);
|
|
8
|
-
console.log('
|
|
8
|
+
console.log('AG Grid Activated');
|
|
9
|
+
} else {
|
|
10
|
+
console.log('AG Grid License not found');
|
|
9
11
|
}
|
|
10
12
|
}
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
<script lang="ts" setup>
|
|
2
|
-
import './ag-theme.css';
|
|
3
2
|
import { ClientSideRowModelModule } from '@ag-grid-community/client-side-row-model';
|
|
4
|
-
import canonicalize from 'canonicalize';
|
|
5
3
|
import type { GridApi, GridOptions, SortState } from '@ag-grid-community/core';
|
|
6
4
|
import { ModuleRegistry } from '@ag-grid-community/core';
|
|
7
5
|
import { InfiniteRowModelModule } from '@ag-grid-community/infinite-row-model';
|
|
@@ -10,14 +8,21 @@ import { ClipboardModule } from '@ag-grid-enterprise/clipboard';
|
|
|
10
8
|
import { RangeSelectionModule } from '@ag-grid-enterprise/range-selection';
|
|
11
9
|
import { PlDropdownLine } from '@milaboratories/uikit';
|
|
12
10
|
import type { AxisId, PlDataTableState, PTableRecordFilter, PTableSorting } from '@platforma-sdk/model';
|
|
13
|
-
import { computed, ref, watch, shallowRef, toRefs } from 'vue';
|
|
14
|
-
import OverlayLoading from './OverlayLoading.vue';
|
|
15
|
-
import OverlayNoRows from './OverlayNoRows.vue';
|
|
16
|
-
import { updateXsvGridOptions } from './sources/file-source';
|
|
17
|
-
import { parseColId, makeSheets, updatePFrameGridOptions, enrichJoinWithLabelColumns } from './sources/table-source';
|
|
18
|
-
import type { PlDataTableSheet, PlDataTableSettings } from './types';
|
|
19
|
-
import * as lodash from 'lodash';
|
|
20
11
|
import { computedAsync } from '@vueuse/core';
|
|
12
|
+
import canonicalize from 'canonicalize';
|
|
13
|
+
import * as lodash from 'lodash';
|
|
14
|
+
import { computed, ref, shallowRef, toRefs, watch } from 'vue';
|
|
15
|
+
import './ag-theme.css';
|
|
16
|
+
import PlOverlayLoading from './PlAgOverlayLoading.vue';
|
|
17
|
+
import PlOverlayNoRows from './PlAgOverlayNoRows.vue';
|
|
18
|
+
import { updateXsvGridOptions } from './sources/file-source';
|
|
19
|
+
import {
|
|
20
|
+
enrichJoinWithLabelColumns,
|
|
21
|
+
makeSheets,
|
|
22
|
+
parseColId,
|
|
23
|
+
updatePFrameGridOptions
|
|
24
|
+
} from './sources/table-source';
|
|
25
|
+
import type { PlDataTableSettings, PlDataTableSheet } from './types';
|
|
21
26
|
|
|
22
27
|
ModuleRegistry.registerModules([ClientSideRowModelModule, ClipboardModule, InfiniteRowModelModule, RangeSelectionModule]);
|
|
23
28
|
|
|
@@ -30,15 +35,18 @@ const { settings } = toRefs(props);
|
|
|
30
35
|
watch(
|
|
31
36
|
() => settings.value,
|
|
32
37
|
async (settings, oldSettings) => {
|
|
33
|
-
if (
|
|
38
|
+
if (
|
|
39
|
+
settings.sourceType !== 'pframe' ||
|
|
40
|
+
!settings.pFrame ||
|
|
41
|
+
!settings.join
|
|
42
|
+
) return;
|
|
34
43
|
|
|
35
44
|
if (
|
|
36
45
|
oldSettings &&
|
|
37
46
|
oldSettings.sourceType === 'pframe' &&
|
|
38
47
|
lodash.isEqual(settings.pFrame, oldSettings.pFrame) &&
|
|
39
48
|
lodash.isEqual(settings.join, oldSettings.join)
|
|
40
|
-
)
|
|
41
|
-
return;
|
|
49
|
+
) return;
|
|
42
50
|
|
|
43
51
|
const platforma = window.platforma;
|
|
44
52
|
if (!platforma) throw Error('platforma not set');
|
|
@@ -46,7 +54,7 @@ watch(
|
|
|
46
54
|
const pfDriver = platforma.pFrameDriver;
|
|
47
55
|
if (!pfDriver) throw Error('platforma.pFrameDriver not set');
|
|
48
56
|
|
|
49
|
-
const enrichedJoin = await enrichJoinWithLabelColumns(pfDriver, settings.pFrame
|
|
57
|
+
const enrichedJoin = await enrichJoinWithLabelColumns(pfDriver, settings.pFrame, settings.join);
|
|
50
58
|
|
|
51
59
|
const state = tableState.value;
|
|
52
60
|
|
|
@@ -59,37 +67,39 @@ watch(
|
|
|
59
67
|
state.pTableParams.join = enrichedJoin;
|
|
60
68
|
|
|
61
69
|
tableState.value = state;
|
|
62
|
-
}
|
|
70
|
+
}
|
|
63
71
|
);
|
|
64
72
|
|
|
65
|
-
const sheets = computedAsync<PlDataTableSheet[]>(
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
73
|
+
const sheets = computedAsync<PlDataTableSheet[]>(
|
|
74
|
+
async () => {
|
|
75
|
+
const sourceType = settings.value.sourceType;
|
|
76
|
+
switch (sourceType) {
|
|
77
|
+
case 'pframe': {
|
|
78
|
+
const platforma = window.platforma;
|
|
79
|
+
if (!platforma) throw Error('platforma not set');
|
|
71
80
|
|
|
72
|
-
|
|
73
|
-
|
|
81
|
+
const pfDriver = platforma.pFrameDriver;
|
|
82
|
+
if (!pfDriver) throw Error('platforma.pFrameDriver not set');
|
|
74
83
|
|
|
75
|
-
|
|
76
|
-
|
|
84
|
+
if (!settings.value.pFrame) return [];
|
|
85
|
+
const pFrame = settings.value.pFrame;
|
|
77
86
|
|
|
78
|
-
|
|
79
|
-
|
|
87
|
+
const join = tableState.value.pTableParams?.join;
|
|
88
|
+
if (!join) return [];
|
|
80
89
|
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
90
|
+
return await makeSheets(pfDriver, pFrame, settings.value.sheetAxes, join);
|
|
91
|
+
}
|
|
92
|
+
case 'ptable': {
|
|
93
|
+
return settings.value.sheets ?? [];
|
|
94
|
+
}
|
|
95
|
+
case 'xsv': {
|
|
96
|
+
return [];
|
|
97
|
+
}
|
|
98
|
+
default: throw Error(`unsupported source type: ${sourceType satisfies never}`);
|
|
88
99
|
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}, []);
|
|
100
|
+
},
|
|
101
|
+
[]
|
|
102
|
+
);
|
|
93
103
|
|
|
94
104
|
function makeSorting(state?: SortState): PTableSorting[] | undefined {
|
|
95
105
|
if (settings.value.sourceType !== 'ptable' && settings.value.sourceType !== 'pframe') return undefined;
|
|
@@ -114,10 +124,12 @@ const gridState = computed({
|
|
|
114
124
|
};
|
|
115
125
|
},
|
|
116
126
|
set: (gridState) => {
|
|
117
|
-
const sorting = makeSorting(gridState.sort);
|
|
118
127
|
|
|
119
128
|
const state = tableState.value;
|
|
120
129
|
|
|
130
|
+
// do not apply driver sorting for client side rendering
|
|
131
|
+
const sorting = gridOptions.rowModelType === 'clientSide' ? undefined : makeSorting(gridState.sort);
|
|
132
|
+
|
|
121
133
|
state.gridState.columnOrder = gridState.columnOrder;
|
|
122
134
|
state.gridState.sort = gridState.sort;
|
|
123
135
|
|
|
@@ -144,13 +156,13 @@ function makeFilters(sheetsState: Record<string, string | number>): PTableRecord
|
|
|
144
156
|
type: 'bySingleColumn',
|
|
145
157
|
column: sheet.column
|
|
146
158
|
? {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
159
|
+
type: 'column',
|
|
160
|
+
id: sheet.column,
|
|
161
|
+
}
|
|
150
162
|
: {
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
163
|
+
type: 'axis',
|
|
164
|
+
id: sheet.axis,
|
|
165
|
+
},
|
|
154
166
|
predicate: {
|
|
155
167
|
operator: 'Equal',
|
|
156
168
|
reference: sheetsState[makeSheetId(sheet.axis)],
|
|
@@ -188,12 +200,7 @@ watch(
|
|
|
188
200
|
const [settings, sheets] = state;
|
|
189
201
|
if (oldState) {
|
|
190
202
|
const [oldSettings, oldSheets] = oldState;
|
|
191
|
-
if (
|
|
192
|
-
(settings.sourceType === 'ptable' || settings.sourceType === 'pframe') &&
|
|
193
|
-
settings.sourceType === oldSettings?.sourceType &&
|
|
194
|
-
lodash.isEqual(sheets, oldSheets)
|
|
195
|
-
)
|
|
196
|
-
return;
|
|
203
|
+
if ((settings.sourceType === 'ptable' || settings.sourceType === 'pframe') && settings.sourceType === oldSettings?.sourceType && lodash.isEqual(sheets, oldSheets)) return;
|
|
197
204
|
}
|
|
198
205
|
|
|
199
206
|
if (settings.sourceType !== 'ptable' && settings.sourceType !== 'pframe') {
|
|
@@ -217,7 +224,7 @@ const gridApi = shallowRef<GridApi>();
|
|
|
217
224
|
const gridOptions: GridOptions = {
|
|
218
225
|
animateRows: false,
|
|
219
226
|
suppressColumnMoveAnimation: true,
|
|
220
|
-
|
|
227
|
+
cellSelection: true,
|
|
221
228
|
initialState: tableState.value.gridState,
|
|
222
229
|
onGridReady: (event) => {
|
|
223
230
|
gridApi.value = event.api;
|
|
@@ -232,14 +239,14 @@ const gridOptions: GridOptions = {
|
|
|
232
239
|
onRowDataUpdated: (event) => {
|
|
233
240
|
event.api.autoSizeAllColumns();
|
|
234
241
|
},
|
|
235
|
-
rowModelType: 'infinite',
|
|
242
|
+
// rowModelType: 'infinite', // will be set with the first data set
|
|
236
243
|
maxBlocksInCache: 10000,
|
|
237
244
|
cacheBlockSize: 100,
|
|
238
245
|
getRowId: (params) => params.data.id,
|
|
239
246
|
loading: true,
|
|
240
247
|
loadingOverlayComponentParams: { notReady: true },
|
|
241
|
-
loadingOverlayComponent:
|
|
242
|
-
noRowsOverlayComponent:
|
|
248
|
+
loadingOverlayComponent: PlOverlayLoading,
|
|
249
|
+
noRowsOverlayComponent: PlOverlayNoRows,
|
|
243
250
|
};
|
|
244
251
|
|
|
245
252
|
const reloadKey = ref(0);
|
|
@@ -285,7 +292,7 @@ watch(
|
|
|
285
292
|
if (!pfDriver) throw Error('platforma.pFrameDriver not set');
|
|
286
293
|
|
|
287
294
|
const pTable = settings.pTable;
|
|
288
|
-
if (!pTable
|
|
295
|
+
if (!pTable) {
|
|
289
296
|
return gridApi.updateGridOptions({
|
|
290
297
|
loading: true,
|
|
291
298
|
loadingOverlayComponentParams: { notReady: true },
|
|
@@ -294,9 +301,9 @@ watch(
|
|
|
294
301
|
});
|
|
295
302
|
}
|
|
296
303
|
|
|
297
|
-
const options = await updatePFrameGridOptions(gridApi, pfDriver, pTable
|
|
304
|
+
const options = await updatePFrameGridOptions(gridApi, pfDriver, pTable, sheets);
|
|
298
305
|
return gridApi.updateGridOptions({
|
|
299
|
-
loading:
|
|
306
|
+
loading: options.rowModelType === 'infinite',
|
|
300
307
|
loadingOverlayComponentParams: { notReady: false },
|
|
301
308
|
...options,
|
|
302
309
|
});
|
|
@@ -335,13 +342,9 @@ watch(
|
|
|
335
342
|
<div class="ap-ag-data-table-container">
|
|
336
343
|
<Transition name="ap-ag-data-table-sheets-transition">
|
|
337
344
|
<div v-if="sheets.length > 0" class="ap-ag-data-table-sheets">
|
|
338
|
-
<PlDropdownLine
|
|
339
|
-
v-for="(sheet, i) in sheets"
|
|
340
|
-
:key="i"
|
|
341
|
-
:model-value="sheetsState[makeSheetId(sheet.axis)]"
|
|
345
|
+
<PlDropdownLine v-for="(sheet, i) in sheets" :key="i" :model-value="sheetsState[makeSheetId(sheet.axis)]"
|
|
342
346
|
:options="sheet.options"
|
|
343
|
-
@update:model-value="(newValue) => onSheetChanged(makeSheetId(sheet.axis), newValue)"
|
|
344
|
-
/>
|
|
347
|
+
@update:model-value="(newValue) => onSheetChanged(makeSheetId(sheet.axis), newValue)" />
|
|
345
348
|
</div>
|
|
346
349
|
</Transition>
|
|
347
350
|
<AgGridVue class="ap-ag-data-table-grid" :grid-options="gridOptions" />
|
|
@@ -355,14 +358,17 @@ watch(
|
|
|
355
358
|
height: 100%;
|
|
356
359
|
gap: 12px;
|
|
357
360
|
}
|
|
361
|
+
|
|
358
362
|
.ap-ag-data-table-sheets-transition-enter-active,
|
|
359
363
|
.ap-ag-data-table-sheets-transition-leave-active {
|
|
360
364
|
transition: all 0.2s ease-in-out;
|
|
361
365
|
}
|
|
366
|
+
|
|
362
367
|
.ap-ag-data-table-sheets-transition-enter-from,
|
|
363
368
|
.ap-ag-data-table-sheets-transition-leave-to {
|
|
364
369
|
margin-top: -52px;
|
|
365
370
|
}
|
|
371
|
+
|
|
366
372
|
.ap-ag-data-table-sheets {
|
|
367
373
|
display: flex;
|
|
368
374
|
flex-direction: row;
|
|
@@ -370,6 +376,7 @@ watch(
|
|
|
370
376
|
flex-wrap: wrap;
|
|
371
377
|
z-index: 3;
|
|
372
378
|
}
|
|
379
|
+
|
|
373
380
|
.ap-ag-data-table-grid {
|
|
374
381
|
flex: 1;
|
|
375
382
|
}
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,192 @@
|
|
|
1
|
+
import { ColDef, IDatasource, RowModelType } from '@ag-grid-community/core';
|
|
2
|
+
import { AxisSpec, getAxisId, PColumnSpec, PTableColumnSpec, PTableShape, PTableVector, PVectorDataString } from '@platforma-sdk/model';
|
|
3
|
+
import canonicalize from 'canonicalize';
|
|
4
|
+
import * as lodash from 'lodash';
|
|
5
|
+
import { defaultValueFormatter } from './table-source';
|
|
6
|
+
|
|
7
|
+
type HeterogeneousColumnInfo = {
|
|
8
|
+
/**
|
|
9
|
+
* Index of the column with heterogeneous axis in the p-table array
|
|
10
|
+
*/
|
|
11
|
+
columnIdx: number;
|
|
12
|
+
/**
|
|
13
|
+
* Index of the corresponding heterogeneous axis in the p-table array
|
|
14
|
+
*/
|
|
15
|
+
axisIdx: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
function getHeterogeneousAxes(spec: PColumnSpec): AxisSpec[] {
|
|
19
|
+
return spec.axesSpec.filter((axSpec) => axSpec.annotations?.['pl7.app/axisNature'] === 'heterogeneous');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Returns a list of columns containing heterogeneous axis (if a column contains multiple, all will be returned)
|
|
24
|
+
* @param specs p-table column specs
|
|
25
|
+
* @param indices indices of columns of interest in the spec array
|
|
26
|
+
* @returns list of columns
|
|
27
|
+
*/
|
|
28
|
+
export function getHeterogeneousColumns(specs: PTableColumnSpec[], indices: number[]): HeterogeneousColumnInfo[] {
|
|
29
|
+
const cols: HeterogeneousColumnInfo[] = [];
|
|
30
|
+
|
|
31
|
+
// check we have heterogeneous axis, which we need to transpose
|
|
32
|
+
for (const i of indices) {
|
|
33
|
+
if (specs[i].type === 'column') {
|
|
34
|
+
const hAxes = getHeterogeneousAxes(specs[i].spec);
|
|
35
|
+
|
|
36
|
+
for (const hAx of hAxes) {
|
|
37
|
+
if (hAx.type !== 'String') {
|
|
38
|
+
console.warn('heterogeneous axis with string type expected, got', hAx, 'skipping');
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const axisId = getAxisId(hAx);
|
|
43
|
+
const axisIdx = specs.findIndex((s) => lodash.isEqual(s.id, axisId));
|
|
44
|
+
|
|
45
|
+
if (axisIdx === -1) {
|
|
46
|
+
console.error('axis not found', i, axisId, specs);
|
|
47
|
+
throw Error('axis not found');
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
cols.push({ columnIdx: i, axisIdx: axisIdx });
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
return cols;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// auxiliary function to get a field for i-th axis-value
|
|
59
|
+
const hColumnField = (originalLength: number, i: number) => (originalLength + i).toString();
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Calculate GridOptions for p-table data source type
|
|
63
|
+
*
|
|
64
|
+
* @param hColumns heterogeneous columns list
|
|
65
|
+
* @param shape table shape
|
|
66
|
+
* @param columnDefs initial column definitions (with h-cols inside and no additional columns)
|
|
67
|
+
* @param data data array (including initial columns)
|
|
68
|
+
* @param fields fields corresponding to initial column defs
|
|
69
|
+
* @param indices indices in the original specs array
|
|
70
|
+
*/
|
|
71
|
+
export function updatePFrameGridOptionsHeterogeneousAxes(
|
|
72
|
+
hColumns: HeterogeneousColumnInfo[],
|
|
73
|
+
shape: PTableShape,
|
|
74
|
+
columnDefs: ColDef[],
|
|
75
|
+
data: PTableVector[],
|
|
76
|
+
fields: number[],
|
|
77
|
+
indices: number[],
|
|
78
|
+
): {
|
|
79
|
+
columnDefs: ColDef[];
|
|
80
|
+
datasource?: IDatasource;
|
|
81
|
+
rowModelType: RowModelType;
|
|
82
|
+
rowData?: unknown[];
|
|
83
|
+
} {
|
|
84
|
+
if (hColumns.length > 1) {
|
|
85
|
+
throw Error('hColumns.length > 1 is not supported');
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
const hColumn = hColumns[0];
|
|
89
|
+
|
|
90
|
+
// recalculate indices of h-cols to the positions in the resulting data
|
|
91
|
+
// index of axis & column in indices array
|
|
92
|
+
let axisIdx: number = -1;
|
|
93
|
+
let columnIdx: number = -1;
|
|
94
|
+
for (let i = 0; i < indices.length; ++i) {
|
|
95
|
+
if (indices[i] === hColumn.axisIdx) {
|
|
96
|
+
axisIdx = i;
|
|
97
|
+
}
|
|
98
|
+
if (indices[i] === hColumn.columnIdx) {
|
|
99
|
+
columnIdx = i;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// columns to add into the data table definition
|
|
104
|
+
const hAxisValues: string[] = (() => {
|
|
105
|
+
// only string data is supported
|
|
106
|
+
const allValues = data[axisIdx].data as PVectorDataString;
|
|
107
|
+
const notNull = allValues.filter((v) => v !== null);
|
|
108
|
+
return Array.from(new Set(notNull));
|
|
109
|
+
})();
|
|
110
|
+
|
|
111
|
+
// sort for canonicalization
|
|
112
|
+
hAxisValues.sort();
|
|
113
|
+
|
|
114
|
+
// remove heterogeneous column from the column defs
|
|
115
|
+
if (columnIdx > axisIdx) {
|
|
116
|
+
columnDefs.splice(columnIdx, 1);
|
|
117
|
+
columnDefs.splice(axisIdx, 1);
|
|
118
|
+
} else {
|
|
119
|
+
columnDefs.splice(axisIdx, 1);
|
|
120
|
+
columnDefs.splice(columnIdx, 1);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
// calculate row data
|
|
124
|
+
const rowData = calculateRowData(fields, data, axisIdx, columnIdx, hAxisValues, shape.rows);
|
|
125
|
+
|
|
126
|
+
// add additional column definitions
|
|
127
|
+
for (let i = 0; i < hAxisValues.length; ++i) {
|
|
128
|
+
const header = hAxisValues[i];
|
|
129
|
+
const id = header + '@' + i; // at least add i to avoid name clash with other columns
|
|
130
|
+
|
|
131
|
+
columnDefs.push({
|
|
132
|
+
colId: id,
|
|
133
|
+
field: hColumnField(data.length, i),
|
|
134
|
+
headerName: header,
|
|
135
|
+
valueFormatter: defaultValueFormatter,
|
|
136
|
+
});
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
return {
|
|
140
|
+
rowModelType: 'clientSide',
|
|
141
|
+
columnDefs,
|
|
142
|
+
rowData,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
/** calculate row data for the table with heterogeneous axis */
|
|
147
|
+
function calculateRowData(
|
|
148
|
+
fields: number[],
|
|
149
|
+
data: PTableVector[],
|
|
150
|
+
axisIdx: number,
|
|
151
|
+
columnIdx: number,
|
|
152
|
+
hAxisValues: string[],
|
|
153
|
+
nRows: number,
|
|
154
|
+
): unknown[] {
|
|
155
|
+
const uniqueRowsMap: Map<string, Record<string, any>> = new Map();
|
|
156
|
+
|
|
157
|
+
// transposed iRow
|
|
158
|
+
let iRowT = 0;
|
|
159
|
+
for (let iRow = 0; iRow < nRows; iRow++) {
|
|
160
|
+
const rowPart: Record<string, any> = {};
|
|
161
|
+
let k = 0;
|
|
162
|
+
for (let iCol = 0; iCol < data.length; ++iCol) {
|
|
163
|
+
if (iCol === axisIdx || iCol === columnIdx) continue;
|
|
164
|
+
const field = fields[iCol].toString();
|
|
165
|
+
rowPart[field] = data[iCol].data[iRow];
|
|
166
|
+
++k;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
let row: Record<string, any>;
|
|
170
|
+
const id = canonicalize(Object.values(rowPart)) ?? '';
|
|
171
|
+
if (!uniqueRowsMap.has(id)) {
|
|
172
|
+
uniqueRowsMap.set(id, rowPart);
|
|
173
|
+
row = rowPart;
|
|
174
|
+
row['id'] = iRowT.toString();
|
|
175
|
+
iRowT++;
|
|
176
|
+
} else {
|
|
177
|
+
row = uniqueRowsMap.get(id)!;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const idx = hAxisValues.indexOf(data[axisIdx].data[iRow] as string);
|
|
181
|
+
if (idx === -1) {
|
|
182
|
+
throw Error('index not found');
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
const field = hColumnField(data.length, idx);
|
|
186
|
+
row[field] = data[columnIdx].data[iRow];
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const result = Array.from(uniqueRowsMap.values());
|
|
190
|
+
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
@@ -1,22 +1,27 @@
|
|
|
1
|
-
import type { ColDef, GridApi, IDatasource, IGetRowsParams } from '@ag-grid-community/core';
|
|
2
|
-
import type { PFrameHandle, AxisId, PColumnIdAndSpec, JoinEntry, PObjectId } from '@platforma-sdk/model';
|
|
1
|
+
import type { ColDef, GridApi, IDatasource, IGetRowsParams, RowModelType } from '@ag-grid-community/core';
|
|
3
2
|
import {
|
|
4
|
-
type
|
|
5
|
-
type PValue,
|
|
3
|
+
type PColumnSpec,
|
|
6
4
|
type PFrameDriver,
|
|
7
5
|
type PTableColumnId,
|
|
8
6
|
type PTableColumnSpec,
|
|
9
7
|
type PTableHandle,
|
|
10
8
|
type PTableVector,
|
|
11
|
-
type
|
|
9
|
+
type PValue,
|
|
10
|
+
type ValueType,
|
|
11
|
+
AxisId,
|
|
12
12
|
getAxesId,
|
|
13
|
-
isValueNA,
|
|
14
13
|
isValueAbsent,
|
|
14
|
+
isValueNA,
|
|
15
|
+
JoinEntry,
|
|
15
16
|
mapJoinEntry,
|
|
17
|
+
PColumnIdAndSpec,
|
|
18
|
+
PFrameHandle,
|
|
19
|
+
PObjectId,
|
|
16
20
|
} from '@platforma-sdk/model';
|
|
17
|
-
import * as lodash from 'lodash';
|
|
18
21
|
import canonicalize from 'canonicalize';
|
|
22
|
+
import * as lodash from 'lodash';
|
|
19
23
|
import { type PlDataTableSheet } from '../types';
|
|
24
|
+
import { getHeterogeneousColumns, updatePFrameGridOptionsHeterogeneousAxes } from './table-source-heterogeneous';
|
|
20
25
|
|
|
21
26
|
/**
|
|
22
27
|
* Generate unique colId based on the column spec.
|
|
@@ -35,6 +40,17 @@ export function parseColId(str: string) {
|
|
|
35
40
|
return JSON.parse(str) as PTableColumnId;
|
|
36
41
|
}
|
|
37
42
|
|
|
43
|
+
export const defaultValueFormatter = (value: any) => {
|
|
44
|
+
if (!value) {
|
|
45
|
+
return 'ERROR';
|
|
46
|
+
} else if (value.value === undefined) {
|
|
47
|
+
return 'NULL';
|
|
48
|
+
} else if (value.value === null) {
|
|
49
|
+
return 'NA';
|
|
50
|
+
} else {
|
|
51
|
+
return value.value.toString();
|
|
52
|
+
}
|
|
53
|
+
};
|
|
38
54
|
/**
|
|
39
55
|
* Calculates column definition for a given p-table column
|
|
40
56
|
*/
|
|
@@ -44,17 +60,7 @@ function getColDef(iCol: number, spec: PTableColumnSpec): ColDef {
|
|
|
44
60
|
field: iCol.toString(),
|
|
45
61
|
headerName: spec.spec.annotations?.['pl7.app/label']?.trim() ?? 'Unlabeled ' + spec.type + ' ' + iCol.toString(),
|
|
46
62
|
lockPosition: spec.type === 'axis',
|
|
47
|
-
valueFormatter:
|
|
48
|
-
if (!value) {
|
|
49
|
-
return 'ERROR';
|
|
50
|
-
} else if (value.value === undefined) {
|
|
51
|
-
return 'NULL';
|
|
52
|
-
} else if (value.value === null) {
|
|
53
|
-
return 'NA';
|
|
54
|
-
} else {
|
|
55
|
-
return value.value.toString();
|
|
56
|
-
}
|
|
57
|
-
},
|
|
63
|
+
valueFormatter: defaultValueFormatter,
|
|
58
64
|
cellDataType: ((valueType: ValueType) => {
|
|
59
65
|
switch (valueType) {
|
|
60
66
|
case 'Int':
|
|
@@ -255,7 +261,7 @@ function columns2rows(fields: number[], columns: PTableVector[]): unknown[] {
|
|
|
255
261
|
}
|
|
256
262
|
|
|
257
263
|
// generate ID based on the axes information
|
|
258
|
-
row['id'] =
|
|
264
|
+
row['id'] = iRow.toString();
|
|
259
265
|
|
|
260
266
|
rowData.push(row);
|
|
261
267
|
}
|
|
@@ -263,6 +269,8 @@ function columns2rows(fields: number[], columns: PTableVector[]): unknown[] {
|
|
|
263
269
|
return rowData;
|
|
264
270
|
}
|
|
265
271
|
|
|
272
|
+
const isLabelColumn = (col: PTableColumnSpec) => col.type === 'column' && col.spec.axesSpec.length === 1 && col.spec.name === 'pl7.app/label';
|
|
273
|
+
|
|
266
274
|
/**
|
|
267
275
|
* Calculate GridOptions for p-table data source type
|
|
268
276
|
*/
|
|
@@ -273,31 +281,55 @@ export async function updatePFrameGridOptions(
|
|
|
273
281
|
sheets: PlDataTableSheet[],
|
|
274
282
|
): Promise<{
|
|
275
283
|
columnDefs: ColDef[];
|
|
276
|
-
datasource
|
|
284
|
+
datasource?: IDatasource;
|
|
285
|
+
rowModelType: RowModelType;
|
|
286
|
+
rowData?: unknown[];
|
|
277
287
|
}> {
|
|
278
288
|
const specs = await pfDriver.getSpec(pt);
|
|
289
|
+
|
|
290
|
+
// column indices in the specs array that we are going to process
|
|
279
291
|
const indices = [...specs.keys()].filter(
|
|
280
292
|
(i) => !lodash.find(sheets, (sheet) => lodash.isEqual(sheet.axis, specs[i].id) || lodash.isEqual(sheet.column, specs[i].id)),
|
|
281
293
|
);
|
|
282
294
|
const fields = lodash.cloneDeep(indices);
|
|
283
295
|
|
|
296
|
+
// get columns with heterogeneous axes
|
|
297
|
+
const hColumns = getHeterogeneousColumns(specs, indices);
|
|
298
|
+
|
|
299
|
+
// process label columns
|
|
284
300
|
for (let i = indices.length - 1; i >= 0; --i) {
|
|
285
301
|
const idx = indices[i];
|
|
286
|
-
if (!(specs[idx]
|
|
302
|
+
if (!isLabelColumn(specs[idx])) continue;
|
|
287
303
|
|
|
288
304
|
const axisId = getAxesId((specs[idx].spec as PColumnSpec).axesSpec)[0];
|
|
289
305
|
const axisIdx = lodash.findIndex(indices, (idx) => lodash.isEqual(specs[idx].id, axisId));
|
|
290
306
|
if (axisIdx === -1) continue;
|
|
291
307
|
|
|
308
|
+
// replace in h-columns
|
|
292
309
|
indices[axisIdx] = idx;
|
|
310
|
+
for (const hCol of hColumns) {
|
|
311
|
+
if (hCol.axisIdx === idx) {
|
|
312
|
+
hCol.axisIdx = axisIdx;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
// remove original axis
|
|
293
317
|
indices.splice(i, 1);
|
|
294
318
|
fields.splice(i, 1);
|
|
295
319
|
}
|
|
296
320
|
|
|
297
|
-
const columnDefs = fields.map((i) => getColDef(i, specs[i]));
|
|
298
|
-
|
|
299
321
|
const ptShape = await pfDriver.getShape(pt);
|
|
300
322
|
const rowCount = ptShape.rows;
|
|
323
|
+
const columnDefs = fields.map((i) => getColDef(i, specs[i]));
|
|
324
|
+
|
|
325
|
+
if (hColumns.length > 1) {
|
|
326
|
+
console.warn('Currently, only one heterogeneous axis is supported in the table, got', hColumns.length, ' transposition will not be applied.');
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
if (hColumns.length === 1) {
|
|
330
|
+
// return data
|
|
331
|
+
return updatePFrameGridOptionsHeterogeneousAxes(hColumns, ptShape, columnDefs, await pfDriver.getData(pt, indices), fields, indices);
|
|
332
|
+
}
|
|
301
333
|
|
|
302
334
|
let lastParams: IGetRowsParams | undefined = undefined;
|
|
303
335
|
const datasource = {
|
|
@@ -340,6 +372,7 @@ export async function updatePFrameGridOptions(
|
|
|
340
372
|
} satisfies IDatasource;
|
|
341
373
|
|
|
342
374
|
return {
|
|
375
|
+
rowModelType: 'infinite',
|
|
343
376
|
columnDefs,
|
|
344
377
|
datasource,
|
|
345
378
|
};
|