@platforma-sdk/ui-vue 1.29.9 → 1.29.13
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 +18 -0
- package/dist/lib.js +9477 -9003
- package/dist/lib.js.map +1 -1
- package/dist/lib.umd.cjs +27 -27
- package/dist/lib.umd.cjs.map +1 -1
- package/dist/src/components/PlAgDataTable/PlAgDataTable.vue.d.ts.map +1 -1
- package/dist/src/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts +78 -0
- package/dist/src/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts.map +1 -0
- package/dist/src/components/PlAgDataTable/index.d.ts +1 -0
- package/dist/src/components/PlAgDataTable/index.d.ts.map +1 -1
- package/dist/src/components/PlAgDataTable/sources/common.d.ts +21 -0
- package/dist/src/components/PlAgDataTable/sources/common.d.ts.map +1 -0
- package/dist/src/components/PlAgDataTable/sources/table-source-v2.d.ts +16 -0
- package/dist/src/components/PlAgDataTable/sources/table-source-v2.d.ts.map +1 -0
- package/dist/src/components/PlAgDataTable/sources/table-source.d.ts +4 -15
- package/dist/src/components/PlAgDataTable/sources/table-source.d.ts.map +1 -1
- package/dist/src/components/PlAgDataTable/types.d.ts +14 -2
- package/dist/src/components/PlAgDataTable/types.d.ts.map +1 -1
- package/dist/src/lib.d.ts +2 -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/components/PlAgDataTable/PlAgDataTable.vue +10 -6
- package/src/components/PlAgDataTable/PlAgDataTableV2.vue +539 -0
- package/src/components/PlAgDataTable/index.ts +1 -0
- package/src/components/PlAgDataTable/sources/common.ts +127 -0
- package/src/components/PlAgDataTable/sources/table-source-heterogeneous.ts +2 -2
- package/src/components/PlAgDataTable/sources/table-source-v2.ts +260 -0
- package/src/components/PlAgDataTable/sources/table-source.ts +2 -115
- package/src/components/PlAgDataTable/types.ts +19 -1
- package/src/lib.ts +2 -1
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@platforma-sdk/ui-vue",
|
|
3
|
-
"version": "1.29.
|
|
3
|
+
"version": "1.29.13",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/lib.umd.cjs",
|
|
6
6
|
"module": "dist/lib.js",
|
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
"canonicalize": "~2.1.0",
|
|
24
24
|
"ag-grid-enterprise": "^33.0.4",
|
|
25
25
|
"ag-grid-vue3": "^33.0.4",
|
|
26
|
-
"@
|
|
27
|
-
"@
|
|
26
|
+
"@milaboratories/uikit": "^2.2.67",
|
|
27
|
+
"@platforma-sdk/model": "^1.29.13"
|
|
28
28
|
},
|
|
29
29
|
"devDependencies": {
|
|
30
30
|
"@faker-js/faker": "^9.2.0",
|
|
@@ -19,6 +19,8 @@ import {
|
|
|
19
19
|
} from 'ag-grid-enterprise';
|
|
20
20
|
import { AgGridVue } from 'ag-grid-vue3';
|
|
21
21
|
import { PlDropdownLine } from '@milaboratories/uikit';
|
|
22
|
+
import type {
|
|
23
|
+
PTableColumnSpecJson } from '@platforma-sdk/model';
|
|
22
24
|
import {
|
|
23
25
|
getAxisId,
|
|
24
26
|
getRawPlatformaInstance,
|
|
@@ -28,6 +30,7 @@ import {
|
|
|
28
30
|
type PTableColumnSpec,
|
|
29
31
|
type PTableRecordFilter,
|
|
30
32
|
type PTableSorting,
|
|
33
|
+
parsePTableColumnId,
|
|
31
34
|
} from '@platforma-sdk/model';
|
|
32
35
|
import canonicalize from 'canonicalize';
|
|
33
36
|
import * as lodash from 'lodash';
|
|
@@ -36,7 +39,8 @@ import { AgGridTheme } from '../../lib';
|
|
|
36
39
|
import PlOverlayLoading from './PlAgOverlayLoading.vue';
|
|
37
40
|
import PlOverlayNoRows from './PlAgOverlayNoRows.vue';
|
|
38
41
|
import { updateXsvGridOptions } from './sources/file-source';
|
|
39
|
-
import {
|
|
42
|
+
import { type PlAgCellButtonAxisParams, makeRowId } from './sources/common';
|
|
43
|
+
import { updatePFrameGridOptions } from './sources/table-source';
|
|
40
44
|
import type { PlAgDataTableController, PlDataTableSettings, PlAgDataTableRow, PTableRowKey, PlDataTableSettingsPTable } from './types';
|
|
41
45
|
import { PlAgGridColumnManager } from '../PlAgGridColumnManager';
|
|
42
46
|
import { autoSizeRowNumberColumn, PlAgDataTableRowNumberColId } from './sources/row-number';
|
|
@@ -108,12 +112,12 @@ const emit = defineEmits<{
|
|
|
108
112
|
function makeSorting(state?: SortState): PTableSorting[] {
|
|
109
113
|
return (
|
|
110
114
|
state?.sortModel.map((item) => {
|
|
111
|
-
const { spec, ...column } =
|
|
115
|
+
const { spec, ...column } = parsePTableColumnId(item.colId as PTableColumnSpecJson);
|
|
112
116
|
const _ = spec;
|
|
113
117
|
return {
|
|
114
118
|
column,
|
|
115
119
|
ascending: item.sort === 'asc',
|
|
116
|
-
naAndAbsentAreLeastValues:
|
|
120
|
+
naAndAbsentAreLeastValues: item.sort === 'asc',
|
|
117
121
|
};
|
|
118
122
|
}) ?? []
|
|
119
123
|
);
|
|
@@ -321,7 +325,7 @@ const makePartialState = (state: GridState) => {
|
|
|
321
325
|
sourceId: gridState.value.sourceId,
|
|
322
326
|
columnOrder: state.columnOrder,
|
|
323
327
|
sort: state.sort,
|
|
324
|
-
columnVisibility: state.columnVisibility,
|
|
328
|
+
columnVisibility: state.columnVisibility as { hiddenColIds: PTableColumnSpecJson[] } | undefined,
|
|
325
329
|
};
|
|
326
330
|
};
|
|
327
331
|
|
|
@@ -370,7 +374,7 @@ watch(
|
|
|
370
374
|
.filter((colId) => colId !== undefined)
|
|
371
375
|
.filter((colId) => colId !== PlAgDataTableRowNumberColId)
|
|
372
376
|
.filter((colId) => !isColumnSelectionCol(colId))
|
|
373
|
-
.map((colId) =>
|
|
377
|
+
.map((colId) => parsePTableColumnId(colId as PTableColumnSpecJson)) ?? [];
|
|
374
378
|
emit('columnsChanged', columns);
|
|
375
379
|
}
|
|
376
380
|
if (!lodash.isEqual(options.loadingOverlayComponentParams, oldOptions.loadingOverlayComponentParams) && options.loading) {
|
|
@@ -451,7 +455,7 @@ watch(
|
|
|
451
455
|
showCellButtonForAxisId: props.showCellButtonForAxisId,
|
|
452
456
|
cellButtonInvokeRowsOnDoubleClick: props.cellButtonInvokeRowsOnDoubleClick,
|
|
453
457
|
trigger: (key?: PTableRowKey) => emit('cellButtonClicked', key),
|
|
454
|
-
},
|
|
458
|
+
} satisfies PlAgCellButtonAxisParams,
|
|
455
459
|
).catch((err) => {
|
|
456
460
|
gridApi.updateGridOptions({
|
|
457
461
|
loading: false,
|
|
@@ -0,0 +1,539 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import {
|
|
3
|
+
type ColDef,
|
|
4
|
+
type ColGroupDef,
|
|
5
|
+
type GridApi,
|
|
6
|
+
type GridOptions,
|
|
7
|
+
type GridReadyEvent,
|
|
8
|
+
type GridState,
|
|
9
|
+
type ManagedGridOptionKey,
|
|
10
|
+
type ManagedGridOptions,
|
|
11
|
+
type SortState,
|
|
12
|
+
type StateUpdatedEvent,
|
|
13
|
+
ModuleRegistry,
|
|
14
|
+
ClientSideRowModelModule,
|
|
15
|
+
ClipboardModule,
|
|
16
|
+
CellSelectionModule,
|
|
17
|
+
ServerSideRowModelModule,
|
|
18
|
+
isColumnSelectionCol,
|
|
19
|
+
} from 'ag-grid-enterprise';
|
|
20
|
+
import { AgGridVue } from 'ag-grid-vue3';
|
|
21
|
+
import { PlDropdownLine } from '@milaboratories/uikit';
|
|
22
|
+
import type {
|
|
23
|
+
PTableColumnSpecJson } from '@platforma-sdk/model';
|
|
24
|
+
import {
|
|
25
|
+
getAxisId,
|
|
26
|
+
getRawPlatformaInstance,
|
|
27
|
+
type PlDataTableGridStateWithoutSheets,
|
|
28
|
+
type AxisId,
|
|
29
|
+
type PlDataTableState,
|
|
30
|
+
type PTableColumnSpec,
|
|
31
|
+
type PTableRecordFilter,
|
|
32
|
+
type PTableSorting,
|
|
33
|
+
parsePTableColumnId,
|
|
34
|
+
} from '@platforma-sdk/model';
|
|
35
|
+
import canonicalize from 'canonicalize';
|
|
36
|
+
import * as lodash from 'lodash';
|
|
37
|
+
import { computed, nextTick, ref, shallowRef, toRefs, watch } from 'vue';
|
|
38
|
+
import { AgGridTheme } from '../../lib';
|
|
39
|
+
import PlOverlayLoading from './PlAgOverlayLoading.vue';
|
|
40
|
+
import PlOverlayNoRows from './PlAgOverlayNoRows.vue';
|
|
41
|
+
import { type PlAgCellButtonAxisParams, makeRowId } from './sources/common';
|
|
42
|
+
import { updatePFrameGridOptions } from './sources/table-source-v2';
|
|
43
|
+
import type { PlAgDataTableController, PlAgDataTableSettings, PlAgDataTableRow, PTableRowKey, PlAgDataTableSettingsPTable } from './types';
|
|
44
|
+
import { PlAgGridColumnManager } from '../PlAgGridColumnManager';
|
|
45
|
+
import { autoSizeRowNumberColumn, PlAgDataTableRowNumberColId } from './sources/row-number';
|
|
46
|
+
import { focusRow, makeOnceTracker, trackFirstDataRendered } from './sources/focus-row';
|
|
47
|
+
import PlAgCsvExporter from '../PlAgCsvExporter/PlAgCsvExporter.vue';
|
|
48
|
+
import { Deferred, isJsonEqual } from '@milaboratories/helpers';
|
|
49
|
+
|
|
50
|
+
ModuleRegistry.registerModules([
|
|
51
|
+
ClientSideRowModelModule,
|
|
52
|
+
ClipboardModule,
|
|
53
|
+
ServerSideRowModelModule,
|
|
54
|
+
CellSelectionModule,
|
|
55
|
+
]);
|
|
56
|
+
|
|
57
|
+
const tableState = defineModel<PlDataTableState>({ default: { gridState: {} } });
|
|
58
|
+
const selectedRows = defineModel<PTableRowKey[]>('selectedRows');
|
|
59
|
+
const props = defineProps<{
|
|
60
|
+
settings?: Readonly<PlAgDataTableSettings>;
|
|
61
|
+
/**
|
|
62
|
+
* The showColumnsPanel prop controls the display of a button that activates
|
|
63
|
+
* the columns management panel in the table. To make the button functional
|
|
64
|
+
* and visible, you must also include the PlAgDataTableToolsPanel component in your layout.
|
|
65
|
+
* This component serves as the target for teleporting the button.
|
|
66
|
+
*/
|
|
67
|
+
showColumnsPanel?: boolean;
|
|
68
|
+
/**
|
|
69
|
+
* Css width of the Column Manager (Panel) modal (default value is `368px`)
|
|
70
|
+
*/
|
|
71
|
+
columnsPanelWidth?: string;
|
|
72
|
+
/**
|
|
73
|
+
* The showExportButton prop controls the display of a button that allows
|
|
74
|
+
* to export table data in CSV format. To make the button functional
|
|
75
|
+
* and visible, you must also include the PlAgDataTableToolsPanel component in your layout.
|
|
76
|
+
* This component serves as the target for teleporting the button.
|
|
77
|
+
*/
|
|
78
|
+
showExportButton?: boolean;
|
|
79
|
+
/**
|
|
80
|
+
* Force use of client-side row model.
|
|
81
|
+
* Required for reliable work of focusRow.
|
|
82
|
+
* Auto-enabled when selectedRows provided.
|
|
83
|
+
*/
|
|
84
|
+
clientSideModel?: boolean;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The AxisId property is used to configure and display the PlAgTextAndButtonCell component
|
|
88
|
+
*/
|
|
89
|
+
showCellButtonForAxisId?: AxisId;
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* If cellButtonInvokeRowsOnDoubleClick = true, clicking a button inside the row
|
|
93
|
+
* triggers the doubleClick event for the entire row.
|
|
94
|
+
*
|
|
95
|
+
* If cellButtonInvokeRowsOnDoubleClick = false, the doubleClick event for the row
|
|
96
|
+
* is not triggered, but will triggered cellButtonClicked event with (key: PTableRowKey) argument.
|
|
97
|
+
*/
|
|
98
|
+
cellButtonInvokeRowsOnDoubleClick?: boolean;
|
|
99
|
+
}>();
|
|
100
|
+
const { settings } = toRefs(props);
|
|
101
|
+
const emit = defineEmits<{
|
|
102
|
+
rowDoubleClicked: [key?: PTableRowKey];
|
|
103
|
+
columnsChanged: [columns: PTableColumnSpec[]];
|
|
104
|
+
cellButtonClicked: [key?: PTableRowKey];
|
|
105
|
+
}>();
|
|
106
|
+
|
|
107
|
+
/** State upgrader */ (() => {
|
|
108
|
+
if (!tableState.value.pTableParams) tableState.value.pTableParams = {};
|
|
109
|
+
})();
|
|
110
|
+
|
|
111
|
+
function makeSorting(state?: SortState): PTableSorting[] {
|
|
112
|
+
return (
|
|
113
|
+
state?.sortModel.map((item) => {
|
|
114
|
+
const { spec, ...column } = parsePTableColumnId(item.colId as PTableColumnSpecJson);
|
|
115
|
+
const _ = spec;
|
|
116
|
+
return {
|
|
117
|
+
column,
|
|
118
|
+
ascending: item.sort === 'asc',
|
|
119
|
+
naAndAbsentAreLeastValues: item.sort === 'asc',
|
|
120
|
+
};
|
|
121
|
+
}) ?? []
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
const gridState = computed<PlDataTableGridStateWithoutSheets>({
|
|
126
|
+
get: () => {
|
|
127
|
+
const state = tableState.value;
|
|
128
|
+
return {
|
|
129
|
+
sourceId: state.gridState.sourceId,
|
|
130
|
+
columnOrder: state.gridState.columnOrder,
|
|
131
|
+
sort: state.gridState.sort,
|
|
132
|
+
columnVisibility: state.gridState.columnVisibility,
|
|
133
|
+
};
|
|
134
|
+
},
|
|
135
|
+
set: (gridState) => {
|
|
136
|
+
// do not apply driver sorting for client side rendering
|
|
137
|
+
const sorting
|
|
138
|
+
= settings.value?.sourceType !== 'ptable' || gridOptions.value.rowModelType === 'clientSide' ? undefined : makeSorting(gridState.sort);
|
|
139
|
+
|
|
140
|
+
const oldState = tableState.value;
|
|
141
|
+
|
|
142
|
+
const newState = {
|
|
143
|
+
...oldState,
|
|
144
|
+
gridState: { ...oldState.gridState, ...gridState },
|
|
145
|
+
pTableParams: { ...oldState.pTableParams, sorting },
|
|
146
|
+
};
|
|
147
|
+
|
|
148
|
+
// Note: the table constantly emits an unchanged state, so I added this
|
|
149
|
+
if (!isJsonEqual(oldState, newState)) {
|
|
150
|
+
tableState.value = newState;
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
const makeSheetId = (axis: AxisId) => canonicalize(getAxisId(axis))!;
|
|
156
|
+
|
|
157
|
+
function makeFilters(sheetsState: Record<string, string | number>): PTableRecordFilter[] | undefined {
|
|
158
|
+
if (settings.value?.sourceType !== 'ptable') return undefined;
|
|
159
|
+
return (
|
|
160
|
+
settings.value.sheets?.map((sheet) => ({
|
|
161
|
+
type: 'bySingleColumnV2',
|
|
162
|
+
column: {
|
|
163
|
+
type: 'axis',
|
|
164
|
+
id: sheet.axis,
|
|
165
|
+
},
|
|
166
|
+
predicate: {
|
|
167
|
+
operator: 'Equal',
|
|
168
|
+
reference: sheetsState[makeSheetId(sheet.axis)],
|
|
169
|
+
},
|
|
170
|
+
})) ?? []
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const sheetsState = computed({
|
|
175
|
+
get: () => tableState.value.gridState.sheets ?? {},
|
|
176
|
+
set: (sheetsState) => {
|
|
177
|
+
const filters = makeFilters(sheetsState);
|
|
178
|
+
|
|
179
|
+
const oldState = tableState.value;
|
|
180
|
+
tableState.value = {
|
|
181
|
+
...oldState,
|
|
182
|
+
gridState: { ...oldState.gridState, sheets: sheetsState },
|
|
183
|
+
pTableParams: { ...oldState.pTableParams, filters },
|
|
184
|
+
};
|
|
185
|
+
},
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
const hasSheets = (
|
|
189
|
+
settings?: Readonly<PlAgDataTableSettings>,
|
|
190
|
+
): settings is PlAgDataTableSettingsPTable => {
|
|
191
|
+
return settings?.sourceType === 'ptable'
|
|
192
|
+
&& !!settings.sheets
|
|
193
|
+
&& settings.sheets.length > 0;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
watch(
|
|
197
|
+
() => settings.value,
|
|
198
|
+
(settings, oldSettings) => {
|
|
199
|
+
if (settings?.sourceType !== 'ptable' || !settings.sheets) {
|
|
200
|
+
sheetsState.value = {};
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (oldSettings && oldSettings.sourceType === 'ptable' && lodash.isEqual(settings.sheets, oldSettings.sheets)) return;
|
|
205
|
+
|
|
206
|
+
const oldSheetsState = sheetsState.value;
|
|
207
|
+
const newSheetsState: Record<string, string | number> = {};
|
|
208
|
+
for (const sheet of settings.sheets) {
|
|
209
|
+
const sheetId = makeSheetId(sheet.axis);
|
|
210
|
+
newSheetsState[sheetId] = oldSheetsState[sheetId] ?? sheet.defaultValue ?? sheet.options[0]?.value;
|
|
211
|
+
}
|
|
212
|
+
sheetsState.value = newSheetsState;
|
|
213
|
+
},
|
|
214
|
+
{ immediate: true },
|
|
215
|
+
);
|
|
216
|
+
|
|
217
|
+
const gridApi = shallowRef<GridApi>();
|
|
218
|
+
|
|
219
|
+
const gridApiDef = shallowRef(new Deferred<GridApi>());
|
|
220
|
+
|
|
221
|
+
const firstDataRenderedTracker = makeOnceTracker<GridApi<PlAgDataTableRow>>();
|
|
222
|
+
const gridOptions = shallowRef<GridOptions<PlAgDataTableRow>>({
|
|
223
|
+
animateRows: false,
|
|
224
|
+
suppressColumnMoveAnimation: true,
|
|
225
|
+
cellSelection: selectedRows.value === undefined,
|
|
226
|
+
initialState: gridState.value,
|
|
227
|
+
autoSizeStrategy: { type: 'fitCellContents' },
|
|
228
|
+
rowSelection: selectedRows.value !== undefined
|
|
229
|
+
? {
|
|
230
|
+
mode: 'multiRow',
|
|
231
|
+
checkboxes: false,
|
|
232
|
+
headerCheckbox: false,
|
|
233
|
+
enableClickSelection: false,
|
|
234
|
+
}
|
|
235
|
+
: undefined,
|
|
236
|
+
selectionColumnDef: {
|
|
237
|
+
mainMenuItems: [],
|
|
238
|
+
contextMenuItems: [],
|
|
239
|
+
pinned: 'left',
|
|
240
|
+
lockPinned: true,
|
|
241
|
+
suppressSizeToFit: true,
|
|
242
|
+
suppressAutoSize: true,
|
|
243
|
+
sortable: false,
|
|
244
|
+
resizable: false,
|
|
245
|
+
},
|
|
246
|
+
onRowDataUpdated: (event) => {
|
|
247
|
+
const selectedRowsValue = selectedRows.value;
|
|
248
|
+
if (selectedRowsValue) {
|
|
249
|
+
const nodes = selectedRowsValue
|
|
250
|
+
.map((rowKey) => event.api.getRowNode(makeRowId(rowKey)))
|
|
251
|
+
.filter((node) => !!node);
|
|
252
|
+
event.api.setNodesSelected({ nodes, newValue: true });
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
onSelectionChanged: (event) => {
|
|
256
|
+
if (selectedRows.value) {
|
|
257
|
+
selectedRows.value = event.api.getSelectedNodes()
|
|
258
|
+
.map((rowNode) => rowNode.data?.key)
|
|
259
|
+
.filter((rowKey) => !!rowKey);
|
|
260
|
+
}
|
|
261
|
+
},
|
|
262
|
+
onRowDoubleClicked: (event) => {
|
|
263
|
+
if (event.data && event.data.key) emit('rowDoubleClicked', event.data.key);
|
|
264
|
+
},
|
|
265
|
+
defaultColDef: {
|
|
266
|
+
suppressHeaderMenuButton: true,
|
|
267
|
+
sortingOrder: ['desc', 'asc', null],
|
|
268
|
+
},
|
|
269
|
+
maintainColumnOrder: true,
|
|
270
|
+
localeText: {
|
|
271
|
+
loadingError: '...',
|
|
272
|
+
},
|
|
273
|
+
rowModelType: 'clientSide',
|
|
274
|
+
maxBlocksInCache: 1000,
|
|
275
|
+
// cacheBlockSize: 100,
|
|
276
|
+
blockLoadDebounceMillis: 500,
|
|
277
|
+
serverSideSortAllLevels: true,
|
|
278
|
+
suppressServerSideFullWidthLoadingRow: true,
|
|
279
|
+
getRowId: (params) => params.data.id,
|
|
280
|
+
loading: true,
|
|
281
|
+
loadingOverlayComponentParams: { notReady: true },
|
|
282
|
+
loadingOverlayComponent: PlOverlayLoading,
|
|
283
|
+
noRowsOverlayComponent: PlOverlayNoRows,
|
|
284
|
+
defaultCsvExportParams: {
|
|
285
|
+
allColumns: true,
|
|
286
|
+
suppressQuotes: true,
|
|
287
|
+
fileName: 'table.csv',
|
|
288
|
+
},
|
|
289
|
+
});
|
|
290
|
+
|
|
291
|
+
const onGridReady = (event: GridReadyEvent) => {
|
|
292
|
+
const api = event.api;
|
|
293
|
+
trackFirstDataRendered(api, firstDataRenderedTracker);
|
|
294
|
+
autoSizeRowNumberColumn(api);
|
|
295
|
+
gridApi.value = new Proxy(api, {
|
|
296
|
+
get(target, prop, receiver) {
|
|
297
|
+
switch (prop) {
|
|
298
|
+
case 'setGridOption':
|
|
299
|
+
return (key: ManagedGridOptionKey, value: GridOptions[ManagedGridOptionKey]) => {
|
|
300
|
+
const options = gridOptions.value;
|
|
301
|
+
options[key] = value;
|
|
302
|
+
gridOptions.value = options;
|
|
303
|
+
api.setGridOption(key, value);
|
|
304
|
+
};
|
|
305
|
+
case 'updateGridOptions':
|
|
306
|
+
return (options: ManagedGridOptions) => {
|
|
307
|
+
gridOptions.value = {
|
|
308
|
+
...gridOptions.value,
|
|
309
|
+
...options,
|
|
310
|
+
};
|
|
311
|
+
api.updateGridOptions(options);
|
|
312
|
+
};
|
|
313
|
+
default:
|
|
314
|
+
return Reflect.get(target, prop, receiver);
|
|
315
|
+
}
|
|
316
|
+
},
|
|
317
|
+
});
|
|
318
|
+
|
|
319
|
+
gridApiDef.value.resolve(gridApi.value);
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
const makePartialState = (state: GridState) => {
|
|
323
|
+
return {
|
|
324
|
+
sourceId: gridState.value.sourceId,
|
|
325
|
+
columnOrder: state.columnOrder,
|
|
326
|
+
sort: state.sort,
|
|
327
|
+
columnVisibility: state.columnVisibility as { hiddenColIds: PTableColumnSpecJson[] } | undefined,
|
|
328
|
+
};
|
|
329
|
+
};
|
|
330
|
+
|
|
331
|
+
const onStateUpdated = (event: StateUpdatedEvent) => {
|
|
332
|
+
gridOptions.value.initialState = gridState.value = makePartialState(event.state);
|
|
333
|
+
event.api.autoSizeColumns(event.api.getAllDisplayedColumns().filter((column) => column.getColId() !== PlAgDataTableRowNumberColId));
|
|
334
|
+
};
|
|
335
|
+
|
|
336
|
+
const onGridPreDestroyed = () => {
|
|
337
|
+
gridOptions.value.initialState = gridState.value = makePartialState(gridApi.value!.getState());
|
|
338
|
+
gridApi.value = undefined;
|
|
339
|
+
gridApiDef.value = new Deferred<GridApi>();
|
|
340
|
+
};
|
|
341
|
+
|
|
342
|
+
defineExpose<PlAgDataTableController>({
|
|
343
|
+
focusRow: (rowKey) => focusRow(makeRowId(rowKey), firstDataRenderedTracker),
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
const reloadKey = ref(0);
|
|
347
|
+
watch(
|
|
348
|
+
() => [gridApi.value, gridState.value] as const,
|
|
349
|
+
(state, oldState) => {
|
|
350
|
+
if (lodash.isEqual(state, oldState)) return;
|
|
351
|
+
|
|
352
|
+
const [gridApi, gridState] = state;
|
|
353
|
+
if (!gridApi) return;
|
|
354
|
+
|
|
355
|
+
const selfState = makePartialState(gridApi.getState());
|
|
356
|
+
if (lodash.isEqual(gridState, selfState)) return;
|
|
357
|
+
|
|
358
|
+
gridOptions.value.initialState = gridState;
|
|
359
|
+
++reloadKey.value;
|
|
360
|
+
},
|
|
361
|
+
);
|
|
362
|
+
watch(
|
|
363
|
+
() => gridOptions.value,
|
|
364
|
+
(options, oldOptions) => {
|
|
365
|
+
if (!oldOptions) return;
|
|
366
|
+
if (options.rowModelType != oldOptions.rowModelType) ++reloadKey.value;
|
|
367
|
+
if (options.columnDefs && !lodash.isEqual(options.columnDefs, oldOptions.columnDefs)) {
|
|
368
|
+
const isColDef = (def: ColDef | ColGroupDef): def is ColDef => !('children' in def);
|
|
369
|
+
const colDefs = options.columnDefs?.filter(isColDef) ?? [];
|
|
370
|
+
const columns
|
|
371
|
+
= colDefs
|
|
372
|
+
.map((def) => def.colId)
|
|
373
|
+
.filter((colId) => colId !== undefined)
|
|
374
|
+
.filter((colId) => colId !== PlAgDataTableRowNumberColId)
|
|
375
|
+
.filter((colId) => !isColumnSelectionCol(colId))
|
|
376
|
+
.map((colId) => parsePTableColumnId(colId as PTableColumnSpecJson)) ?? [];
|
|
377
|
+
emit('columnsChanged', columns);
|
|
378
|
+
}
|
|
379
|
+
if (!lodash.isEqual(options.loadingOverlayComponentParams, oldOptions.loadingOverlayComponentParams) && options.loading) {
|
|
380
|
+
gridApi.value?.setGridOption('loading', false);
|
|
381
|
+
nextTick(() => gridApi.value?.setGridOption('loading', true));
|
|
382
|
+
}
|
|
383
|
+
},
|
|
384
|
+
{ immediate: true },
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
const onSheetChanged = (sheetId: string, newValue: string | number) => {
|
|
388
|
+
const state = sheetsState.value;
|
|
389
|
+
if (state[sheetId] === newValue) return;
|
|
390
|
+
state[sheetId] = newValue;
|
|
391
|
+
sheetsState.value = state;
|
|
392
|
+
return gridApi.value?.updateGridOptions({
|
|
393
|
+
loading: true,
|
|
394
|
+
loadingOverlayComponentParams: { notReady: false },
|
|
395
|
+
});
|
|
396
|
+
};
|
|
397
|
+
|
|
398
|
+
let oldSettings: PlAgDataTableSettings | undefined = undefined;
|
|
399
|
+
|
|
400
|
+
watch(
|
|
401
|
+
() => [settings.value] as const,
|
|
402
|
+
async (state) => {
|
|
403
|
+
try {
|
|
404
|
+
const [settings] = state;
|
|
405
|
+
|
|
406
|
+
const gridApi = await gridApiDef.value.promise;
|
|
407
|
+
|
|
408
|
+
if (gridApi.isDestroyed()) {
|
|
409
|
+
console.warn('gridApi is destroyed');
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (lodash.isEqual(settings, oldSettings)) {
|
|
414
|
+
return;
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
oldSettings = settings;
|
|
418
|
+
|
|
419
|
+
const sourceType = settings?.sourceType;
|
|
420
|
+
|
|
421
|
+
switch (sourceType) {
|
|
422
|
+
case undefined:
|
|
423
|
+
return gridApi.updateGridOptions({
|
|
424
|
+
loading: true,
|
|
425
|
+
loadingOverlayComponentParams: { notReady: true },
|
|
426
|
+
columnDefs: [],
|
|
427
|
+
rowData: undefined,
|
|
428
|
+
datasource: undefined,
|
|
429
|
+
});
|
|
430
|
+
|
|
431
|
+
case 'ptable': {
|
|
432
|
+
if (!settings?.model) {
|
|
433
|
+
return gridApi.updateGridOptions({
|
|
434
|
+
loading: true,
|
|
435
|
+
loadingOverlayComponentParams: { notReady: false },
|
|
436
|
+
columnDefs: [],
|
|
437
|
+
rowData: undefined,
|
|
438
|
+
datasource: undefined,
|
|
439
|
+
});
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
gridApi.updateGridOptions({
|
|
443
|
+
loading: true,
|
|
444
|
+
loadingOverlayComponentParams: { notReady: false },
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
const options = await updatePFrameGridOptions(
|
|
448
|
+
getRawPlatformaInstance().pFrameDriver,
|
|
449
|
+
settings.model,
|
|
450
|
+
settings.sheets ?? [],
|
|
451
|
+
!!props.clientSideModel || !!selectedRows.value,
|
|
452
|
+
gridState,
|
|
453
|
+
{
|
|
454
|
+
showCellButtonForAxisId: props.showCellButtonForAxisId,
|
|
455
|
+
cellButtonInvokeRowsOnDoubleClick: props.cellButtonInvokeRowsOnDoubleClick,
|
|
456
|
+
trigger: (key?: PTableRowKey) => emit('cellButtonClicked', key),
|
|
457
|
+
} satisfies PlAgCellButtonAxisParams,
|
|
458
|
+
).catch((err) => {
|
|
459
|
+
gridApi.updateGridOptions({
|
|
460
|
+
loading: false,
|
|
461
|
+
loadingOverlayComponentParams: { notReady: false },
|
|
462
|
+
});
|
|
463
|
+
throw err;
|
|
464
|
+
});
|
|
465
|
+
|
|
466
|
+
return gridApi.updateGridOptions({
|
|
467
|
+
loading: false,
|
|
468
|
+
loadingOverlayComponentParams: { notReady: false },
|
|
469
|
+
...options,
|
|
470
|
+
});
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
default:
|
|
474
|
+
throw Error(`unsupported source type: ${sourceType satisfies never}`);
|
|
475
|
+
}
|
|
476
|
+
} catch (error: unknown) {
|
|
477
|
+
// How should we handle possible errors?
|
|
478
|
+
console.trace(error);
|
|
479
|
+
}
|
|
480
|
+
},
|
|
481
|
+
{ immediate: true, deep: true },
|
|
482
|
+
);
|
|
483
|
+
</script>
|
|
484
|
+
|
|
485
|
+
<template>
|
|
486
|
+
<div class="ap-ag-data-table-container">
|
|
487
|
+
<PlAgGridColumnManager v-if="gridApi && showColumnsPanel" :api="gridApi" :width="columnsPanelWidth" />
|
|
488
|
+
<PlAgCsvExporter v-if="gridApi && showExportButton" :api="gridApi" />
|
|
489
|
+
<div
|
|
490
|
+
v-if="hasSheets(settings) || $slots['before-sheets'] || $slots['after-sheets']"
|
|
491
|
+
class="ap-ag-data-table-sheets"
|
|
492
|
+
>
|
|
493
|
+
<slot name="before-sheets" />
|
|
494
|
+
<template
|
|
495
|
+
v-if="hasSheets(settings)"
|
|
496
|
+
>
|
|
497
|
+
<PlDropdownLine
|
|
498
|
+
v-for="(sheet, i) in settings.sheets"
|
|
499
|
+
:key="i"
|
|
500
|
+
:model-value="sheetsState[makeSheetId(sheet.axis)]"
|
|
501
|
+
:options="sheet.options"
|
|
502
|
+
:prefix="(sheet.axis.annotations?.['pl7.app/label']?.trim() ?? `Unlabeled axis ${i}`) + ':'"
|
|
503
|
+
@update:model-value="(newValue) => onSheetChanged(makeSheetId(sheet.axis), newValue)"
|
|
504
|
+
/>
|
|
505
|
+
</template>
|
|
506
|
+
<slot name="after-sheets" />
|
|
507
|
+
</div>
|
|
508
|
+
<AgGridVue
|
|
509
|
+
:key="reloadKey"
|
|
510
|
+
:theme="AgGridTheme"
|
|
511
|
+
class="ap-ag-data-table-grid"
|
|
512
|
+
:grid-options="gridOptions"
|
|
513
|
+
@grid-ready="onGridReady"
|
|
514
|
+
@state-updated="onStateUpdated"
|
|
515
|
+
@grid-pre-destroyed="onGridPreDestroyed"
|
|
516
|
+
/>
|
|
517
|
+
</div>
|
|
518
|
+
</template>
|
|
519
|
+
|
|
520
|
+
<style lang="css" scoped>
|
|
521
|
+
.ap-ag-data-table-container {
|
|
522
|
+
display: flex;
|
|
523
|
+
flex-direction: column;
|
|
524
|
+
height: 100%;
|
|
525
|
+
gap: 12px;
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
.ap-ag-data-table-sheets {
|
|
529
|
+
display: flex;
|
|
530
|
+
flex-direction: row;
|
|
531
|
+
gap: 12px;
|
|
532
|
+
flex-wrap: wrap;
|
|
533
|
+
z-index: 3;
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
.ap-ag-data-table-grid {
|
|
537
|
+
flex: 1;
|
|
538
|
+
}
|
|
539
|
+
</style>
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
export { default as PlDataTable } from './PlAgDataTable.vue';
|
|
2
|
+
export { default as PlDataTableV2 } from './PlAgDataTableV2.vue';
|
|
2
3
|
export { default as PlAgOverlayLoading } from './PlAgOverlayLoading.vue';
|
|
3
4
|
export { default as PlAgOverlayNoRows } from './PlAgOverlayNoRows.vue';
|
|
4
5
|
|