@platforma-sdk/ui-vue 1.63.12 → 1.65.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/.turbo/turbo-build.log +38 -32
- package/.turbo/turbo-formatter$colon$check.log +2 -2
- package/.turbo/turbo-linter$colon$check.log +2 -2
- package/.turbo/turbo-types$colon$check.log +1 -1
- package/CHANGELOG.md +24 -0
- package/dist/components/PlAdvancedFilter/FilterEditor.js.map +1 -1
- package/dist/components/PlAdvancedFilter/FilterEditor.style.js.map +1 -1
- package/dist/components/PlAdvancedFilter/FilterEditor.vue.d.ts +3 -8
- package/dist/components/PlAdvancedFilter/FilterEditor.vue.d.ts.map +1 -1
- package/dist/components/PlAdvancedFilter/FilterEditor.vue2.js +164 -151
- package/dist/components/PlAdvancedFilter/FilterEditor.vue2.js.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.js.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.style.js +8 -7
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.style.js.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.css +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.d.ts +24 -8
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue.d.ts.map +1 -1
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js +176 -110
- package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js.map +1 -1
- package/dist/components/PlAdvancedFilter/types.d.ts +2 -0
- package/dist/components/PlAdvancedFilter/types.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.style.js.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js +116 -109
- package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js.map +1 -1
- package/dist/components/PlAgDataTable/compositions/useFilterableColumns.js +3 -3
- package/dist/components/PlAgDataTable/compositions/useFilterableColumns.js.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-source-v2.d.ts +6 -5
- package/dist/components/PlAgDataTable/sources/table-source-v2.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-source-v2.js +122 -88
- package/dist/components/PlAgDataTable/sources/table-source-v2.js.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-state-v2.d.ts +6 -3
- package/dist/components/PlAgDataTable/sources/table-state-v2.d.ts.map +1 -1
- package/dist/components/PlAgDataTable/sources/table-state-v2.js +182 -97
- package/dist/components/PlAgDataTable/sources/table-state-v2.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.style.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue.d.ts.map +1 -1
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue2.js +37 -42
- package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue2.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/useFilteredItems.d.ts +5 -5
- package/dist/components/PlAgGridColumnManager/useFilteredItems.d.ts.map +1 -1
- package/dist/components/PlAgGridColumnManager/useFilteredItems.js +2 -2
- package/dist/components/PlAgGridColumnManager/useFilteredItems.js.map +1 -1
- package/dist/components/PlAgGridColumnManager/useGridColumns.js +14 -0
- package/dist/components/PlAgGridColumnManager/useGridColumns.js.map +1 -0
- package/dist/components/PlAnnotations/components/FilterSidebar.js.map +1 -1
- package/dist/components/PlAnnotations/components/FilterSidebar.style.js.map +1 -1
- package/dist/components/PlAnnotations/components/FilterSidebar.vue.d.ts.map +1 -1
- package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js +7 -4
- package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js.map +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.js.map +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.style.js +5 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.style.js.map +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue.css +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue.d.ts +7 -9
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue.d.ts.map +1 -1
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js +72 -47
- package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/lib/util/helpers/dist/functions.js.map +1 -1
- package/dist/lib/util/helpers/dist/objects.js +4 -1
- package/dist/lib/util/helpers/dist/objects.js.map +1 -1
- package/package.json +8 -7
- package/src/components/PlAdvancedFilter/FilterEditor.vue +99 -55
- package/src/components/PlAdvancedFilter/PlAdvancedFilter.vue +163 -95
- package/src/components/PlAdvancedFilter/types.ts +6 -1
- package/src/components/PlAgDataTable/PlAgDataTableV2.vue +26 -7
- package/src/components/PlAgDataTable/compositions/useFilterableColumns.ts +4 -4
- package/src/components/PlAgDataTable/sources/table-source-v2.ts +231 -131
- package/src/components/PlAgDataTable/sources/table-state-v2.ts +249 -70
- package/src/components/PlAgGridColumnManager/PlAgGridColumnManager.vue +17 -35
- package/src/components/PlAgGridColumnManager/useFilteredItems.ts +9 -11
- package/src/components/PlAgGridColumnManager/useGridColumns.ts +26 -0
- package/src/components/PlAnnotations/components/FilterSidebar.vue +3 -2
- package/src/components/PlTableFilters/PlTableFiltersV2.vue +76 -26
- package/src/index.ts +4 -0
|
@@ -1,30 +1,32 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
AxesSpec,
|
|
3
3
|
PTableColumnId,
|
|
4
|
+
PTableColumnSpecAxis,
|
|
4
5
|
PTableColumnSpecColumn,
|
|
6
|
+
PTableHandle,
|
|
5
7
|
PTableValue,
|
|
6
8
|
} from "@platforma-sdk/model";
|
|
7
9
|
import {
|
|
8
10
|
canonicalizeJson,
|
|
9
11
|
getAxisId,
|
|
10
|
-
isColumnOptional,
|
|
11
12
|
pTableValue,
|
|
12
13
|
type PFrameDriver,
|
|
13
14
|
type PlDataTableSheet,
|
|
14
15
|
type PTableVector,
|
|
15
16
|
type AxisId,
|
|
16
|
-
type PlDataTableModel,
|
|
17
17
|
type PTableColumnSpec,
|
|
18
18
|
type PTableKey,
|
|
19
19
|
type PlTableColumnId,
|
|
20
20
|
type PlTableColumnIdJson,
|
|
21
21
|
isLabelColumn as isLabelColumnSpec,
|
|
22
|
+
isLinkerColumn as isLinkerColumnSpec,
|
|
22
23
|
isColumnHidden,
|
|
24
|
+
isColumnOptional,
|
|
23
25
|
matchAxisId,
|
|
24
26
|
readAnnotation,
|
|
27
|
+
readAnnotationJson,
|
|
25
28
|
Annotation,
|
|
26
29
|
ValueType,
|
|
27
|
-
readAnnotationJson,
|
|
28
30
|
getPTableColumnId,
|
|
29
31
|
} from "@platforma-sdk/model";
|
|
30
32
|
import type {
|
|
@@ -47,6 +49,7 @@ import { getColumnRenderingSpec } from "./value-rendering";
|
|
|
47
49
|
import type { Ref } from "vue";
|
|
48
50
|
import { isJsonEqual } from "@milaboratories/helpers";
|
|
49
51
|
import type { DeferredCircular } from "./focus-row";
|
|
52
|
+
import { isNil, uniq } from "es-toolkit";
|
|
50
53
|
|
|
51
54
|
export function isLabelColumn(column: PTableColumnSpec): column is PTableColumnSpecColumn {
|
|
52
55
|
return column.type === "column" && isLabelColumnSpec(column.spec);
|
|
@@ -56,20 +59,24 @@ export function isLabelColumn(column: PTableColumnSpec): column is PTableColumnS
|
|
|
56
59
|
function columns2rows(
|
|
57
60
|
fields: number[],
|
|
58
61
|
columns: PTableVector[],
|
|
59
|
-
|
|
60
|
-
|
|
62
|
+
fieldResultMapping: number[],
|
|
63
|
+
axesResultIndices: number[],
|
|
61
64
|
): PlAgDataTableV2Row[] {
|
|
62
65
|
const rowData: PlAgDataTableV2Row[] = [];
|
|
63
66
|
for (let iRow = 0; iRow < columns[0].data.length; ++iRow) {
|
|
64
|
-
const axesKey: PTableKey =
|
|
65
|
-
pTableValue(columns[resultMapping[iAxis]], iRow),
|
|
66
|
-
);
|
|
67
|
+
const axesKey: PTableKey = axesResultIndices.map((ri) => pTableValue(columns[ri], iRow));
|
|
67
68
|
const id = canonicalizeJson<PlTableRowId>(axesKey);
|
|
68
|
-
const row
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
69
|
+
const row = fields.reduce<PlAgDataTableV2Row>(
|
|
70
|
+
(acc, field, iCol) => {
|
|
71
|
+
acc[field.toString() as `${number}`] =
|
|
72
|
+
fieldResultMapping[iCol] === -1
|
|
73
|
+
? PTableHidden
|
|
74
|
+
: pTableValue(columns[fieldResultMapping[iCol]], iRow);
|
|
75
|
+
return acc;
|
|
76
|
+
},
|
|
77
|
+
{ id, axesKey },
|
|
78
|
+
);
|
|
79
|
+
|
|
73
80
|
rowData.push(row);
|
|
74
81
|
}
|
|
75
82
|
return rowData;
|
|
@@ -79,16 +86,18 @@ function columns2rows(
|
|
|
79
86
|
export async function calculateGridOptions({
|
|
80
87
|
generation,
|
|
81
88
|
pfDriver,
|
|
82
|
-
model,
|
|
83
89
|
sheets,
|
|
90
|
+
fullTableHandle,
|
|
91
|
+
visibleTableHandle,
|
|
84
92
|
dataRenderedTracker,
|
|
85
93
|
hiddenColIds,
|
|
86
94
|
cellButtonAxisParams,
|
|
87
95
|
}: {
|
|
88
|
-
generation: Ref<number>;
|
|
89
|
-
pfDriver: PFrameDriver;
|
|
90
|
-
model: PlDataTableModel;
|
|
91
96
|
sheets: PlDataTableSheet[];
|
|
97
|
+
pfDriver: PFrameDriver;
|
|
98
|
+
generation: Ref<number>;
|
|
99
|
+
fullTableHandle: PTableHandle;
|
|
100
|
+
visibleTableHandle: PTableHandle;
|
|
92
101
|
dataRenderedTracker: DeferredCircular<GridApi<PlAgDataTableV2Row>>;
|
|
93
102
|
hiddenColIds?: PlTableColumnIdJson[];
|
|
94
103
|
cellButtonAxisParams?: PlAgCellButtonAxisParams;
|
|
@@ -98,129 +107,60 @@ export async function calculateGridOptions({
|
|
|
98
107
|
}
|
|
99
108
|
> {
|
|
100
109
|
const stateGeneration = generation.value;
|
|
101
|
-
const stateChangedError = new Error("table state generation changed");
|
|
102
110
|
|
|
103
111
|
// get specs of the full table
|
|
104
|
-
const
|
|
105
|
-
|
|
112
|
+
const [tableSpecs, visibleTableSpecs] = await Promise.all([
|
|
113
|
+
pfDriver.getSpec(fullTableHandle),
|
|
114
|
+
pfDriver.getSpec(visibleTableHandle),
|
|
115
|
+
]);
|
|
106
116
|
|
|
107
|
-
|
|
108
|
-
const pt = model.visibleTableHandle;
|
|
109
|
-
const dataSpecs = await pfDriver.getSpec(pt);
|
|
110
|
-
if (stateGeneration !== generation.value) throw stateChangedError;
|
|
117
|
+
if (stateGeneration !== generation.value) throw new Error("table state generation changed");
|
|
111
118
|
|
|
112
|
-
//
|
|
113
|
-
const
|
|
114
|
-
canonicalizeJson<PTableColumnId>(getPTableColumnId(spec));
|
|
115
|
-
const dataSpecsMap = new Map(dataSpecs.entries().map(([i, spec]) => [specId(spec), i]));
|
|
116
|
-
const specsToDataSpecsMapping = new Map(
|
|
117
|
-
specs.entries().map(([i, spec]) => {
|
|
118
|
-
const dataSpecIdx = dataSpecsMap.get(specId(spec)) ?? -1;
|
|
119
|
-
if (dataSpecIdx === -1 && spec.type === "axis")
|
|
120
|
-
throw new Error(`axis ${JSON.stringify(spec.spec)} not present in join result`);
|
|
121
|
-
return [i, dataSpecIdx];
|
|
122
|
-
}),
|
|
123
|
-
);
|
|
124
|
-
|
|
125
|
-
// gether indices of columns that would be displayed in the table
|
|
119
|
+
// index mapping from full specs to visible subset (hidden columns → -1)
|
|
120
|
+
const specsToVisibleSpecsMapping = buildSpecsToVisibleSpecsMapping(tableSpecs, visibleTableSpecs);
|
|
126
121
|
|
|
127
|
-
const
|
|
128
|
-
const isPartitionedAxis = (axisId: AxisId) => sheetAxesIds.some((id) => matchAxisId(id, axisId));
|
|
129
|
-
|
|
130
|
-
const labelColumns: { axisId: AxisId; labelColumnIdx: number }[] = [];
|
|
131
|
-
const setLabelColumnIndex = (axisId: AxisId, labelColumnIdx: number) => {
|
|
132
|
-
if (!labelColumns.some((info) => matchAxisId(info.axisId, axisId))) {
|
|
133
|
-
labelColumns.push({ axisId, labelColumnIdx });
|
|
134
|
-
} else {
|
|
135
|
-
console.warn(`multiple label columns match axisId: ${JSON.stringify(axisId)}`);
|
|
136
|
-
}
|
|
137
|
-
};
|
|
138
|
-
const getLabelColumnIndex = (axisId: AxisId) => {
|
|
139
|
-
return labelColumns.find((info) => matchAxisId(info.axisId, axisId))?.labelColumnIdx ?? -1;
|
|
140
|
-
};
|
|
122
|
+
const isPartitionedAxis = createPartitionedAxisPredicate(sheets);
|
|
141
123
|
|
|
142
|
-
//
|
|
143
|
-
|
|
144
|
-
.entries()
|
|
145
|
-
.filter(([i, spec]) => {
|
|
146
|
-
switch (spec.type) {
|
|
147
|
-
case "axis":
|
|
148
|
-
return !isPartitionedAxis(spec.id);
|
|
149
|
-
case "column":
|
|
150
|
-
if (isLabelColumnSpec(spec.spec)) {
|
|
151
|
-
const labeledAxisId = getAxisId(spec.spec.axesSpec[0]);
|
|
152
|
-
if (!isPartitionedAxis(labeledAxisId)) {
|
|
153
|
-
setLabelColumnIndex(labeledAxisId, i);
|
|
154
|
-
}
|
|
155
|
-
return false;
|
|
156
|
-
}
|
|
157
|
-
return !isColumnHidden(spec.spec);
|
|
158
|
-
}
|
|
159
|
-
})
|
|
160
|
-
.map(([i]) => i)
|
|
161
|
-
.toArray();
|
|
124
|
+
// label columns indexed by labeled axis (for axis→label replacement later)
|
|
125
|
+
const getLabelColumnIndex = collectLabelColumnsByAxis(tableSpecs, isPartitionedAxis);
|
|
162
126
|
|
|
163
|
-
//
|
|
164
|
-
|
|
165
|
-
|
|
127
|
+
// displayable column indices ordered: axes first, then columns by OrderPriority
|
|
128
|
+
const fields = sortIndicesByTypeAndPriority(
|
|
129
|
+
selectDisplayableIndices(tableSpecs, isPartitionedAxis),
|
|
130
|
+
tableSpecs,
|
|
131
|
+
);
|
|
166
132
|
|
|
167
|
-
|
|
168
|
-
|
|
133
|
+
// same as fields, but each axis replaced by its label column index when available
|
|
134
|
+
const indices = replaceAxesWithLabelColumns(fields, tableSpecs, getLabelColumnIndex);
|
|
169
135
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
});
|
|
136
|
+
// default hidden columns derived from Optional annotation when no saved state
|
|
137
|
+
const resolvedHiddenColIds =
|
|
138
|
+
hiddenColIds ?? computeDefaultHiddenColIds(fields, indices, tableSpecs);
|
|
174
139
|
|
|
175
|
-
// fields are indices of columns that would go to columnDefs
|
|
176
|
-
const fields = [...indices];
|
|
177
|
-
// replace axes with label columns
|
|
178
|
-
indices = indices.map((i) => {
|
|
179
|
-
const spec = specs[i];
|
|
180
|
-
if (spec.type === "axis") {
|
|
181
|
-
const labelColumnIdx = getLabelColumnIndex(spec.id);
|
|
182
|
-
if (labelColumnIdx !== -1) {
|
|
183
|
-
return labelColumnIdx;
|
|
184
|
-
}
|
|
185
|
-
}
|
|
186
|
-
return i;
|
|
187
|
-
});
|
|
188
140
|
const columnDefs: ColDef<PlAgDataTableV2Row, PTableValue | PTableHidden>[] = [
|
|
189
141
|
makeRowNumberColDef(),
|
|
190
142
|
...fields.map((field, index) =>
|
|
191
|
-
makeColDef(
|
|
143
|
+
makeColDef(
|
|
144
|
+
field,
|
|
145
|
+
tableSpecs[field],
|
|
146
|
+
tableSpecs[indices[index]],
|
|
147
|
+
resolvedHiddenColIds,
|
|
148
|
+
cellButtonAxisParams,
|
|
149
|
+
),
|
|
192
150
|
),
|
|
193
151
|
];
|
|
194
152
|
|
|
195
|
-
//
|
|
196
|
-
const
|
|
197
|
-
.values()
|
|
198
|
-
.filter((spec) => spec.type === "axis")
|
|
199
|
-
.map((spec) => spec.spec)
|
|
200
|
-
.toArray();
|
|
201
|
-
const axes = axesSpec
|
|
202
|
-
.keys()
|
|
203
|
-
.map((i) => {
|
|
204
|
-
let r = indices.indexOf(i);
|
|
205
|
-
if (r === -1) {
|
|
206
|
-
r = indices.length;
|
|
207
|
-
indices.push(i);
|
|
208
|
-
}
|
|
209
|
-
return r;
|
|
210
|
-
})
|
|
211
|
-
.toArray();
|
|
153
|
+
// axes — taken directly from visible table (always present as part of join)
|
|
154
|
+
const visibleAxes = collectVisibleAxes(visibleTableSpecs);
|
|
212
155
|
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
resultMapping.push(-1);
|
|
222
|
-
}
|
|
223
|
-
});
|
|
156
|
+
// request indices: non-hidden display fields + visible axes for row selection keys.
|
|
157
|
+
// Axes replaced by label columns request label data (display); original axis values
|
|
158
|
+
// are fetched via visibleAxes (row keys).
|
|
159
|
+
const { requestIndices, fieldResultMapping, axesResultIndices } = buildRequestIndices(
|
|
160
|
+
indices,
|
|
161
|
+
specsToVisibleSpecsMapping,
|
|
162
|
+
visibleAxes.map(([i]) => i),
|
|
163
|
+
);
|
|
224
164
|
|
|
225
165
|
let rowCount = -1;
|
|
226
166
|
let lastParams: IServerSideGetRowsParams | undefined = undefined;
|
|
@@ -229,7 +169,7 @@ export async function calculateGridOptions({
|
|
|
229
169
|
if (stateGeneration !== generation.value) return params.fail();
|
|
230
170
|
try {
|
|
231
171
|
if (rowCount === -1) {
|
|
232
|
-
const ptShape = await pfDriver.getShape(
|
|
172
|
+
const ptShape = await pfDriver.getShape(visibleTableHandle);
|
|
233
173
|
if (stateGeneration !== generation.value || params.api.isDestroyed())
|
|
234
174
|
return params.fail();
|
|
235
175
|
rowCount = ptShape.rows;
|
|
@@ -259,13 +199,13 @@ export async function calculateGridOptions({
|
|
|
259
199
|
) {
|
|
260
200
|
length = Math.min(rowCount, params.request.endRow) - params.request.startRow;
|
|
261
201
|
if (length > 0) {
|
|
262
|
-
const data = await pfDriver.getData(
|
|
202
|
+
const data = await pfDriver.getData(visibleTableHandle, requestIndices, {
|
|
263
203
|
offset: params.request.startRow,
|
|
264
204
|
length,
|
|
265
205
|
});
|
|
266
206
|
if (stateGeneration !== generation.value || params.api.isDestroyed())
|
|
267
207
|
return params.fail();
|
|
268
|
-
rowData = columns2rows(fields, data,
|
|
208
|
+
rowData = columns2rows(fields, data, fieldResultMapping, axesResultIndices);
|
|
269
209
|
}
|
|
270
210
|
}
|
|
271
211
|
|
|
@@ -287,7 +227,7 @@ export async function calculateGridOptions({
|
|
|
287
227
|
};
|
|
288
228
|
|
|
289
229
|
return {
|
|
290
|
-
axesSpec,
|
|
230
|
+
axesSpec: visibleAxes.map(([, { spec }]) => spec),
|
|
291
231
|
columnDefs,
|
|
292
232
|
serverSideDatasource,
|
|
293
233
|
};
|
|
@@ -324,16 +264,19 @@ export function makeColDef(
|
|
|
324
264
|
cellStyle.fontFamily = columnRenderingSpec.fontFamily;
|
|
325
265
|
}
|
|
326
266
|
}
|
|
267
|
+
const headerName =
|
|
268
|
+
readAnnotation(labeledSpec.spec, Annotation.Label)?.trim() ??
|
|
269
|
+
readAnnotation(spec.spec, Annotation.Label)?.trim() ??
|
|
270
|
+
`Unlabeled ${spec.type} ${iCol}`;
|
|
271
|
+
|
|
327
272
|
return {
|
|
328
273
|
colId,
|
|
329
274
|
mainMenuItems: defaultMainMenuItems,
|
|
330
275
|
context: spec,
|
|
331
276
|
field: `${iCol}`,
|
|
332
|
-
headerName
|
|
333
|
-
readAnnotation(labeledSpec.spec, Annotation.Label)?.trim() ??
|
|
334
|
-
`Unlabeled ${spec.type} ${iCol}`,
|
|
277
|
+
headerName,
|
|
335
278
|
lockPosition: spec.type === "axis",
|
|
336
|
-
hide: hiddenColIds
|
|
279
|
+
hide: hiddenColIds !== undefined && hiddenColIds.includes(colId),
|
|
337
280
|
valueFormatter: columnRenderingSpec.valueFormatter,
|
|
338
281
|
headerComponent: PlAgColumnHeader,
|
|
339
282
|
cellRendererSelector: cellButtonAxisParams?.showCellButtonForAxisId
|
|
@@ -388,3 +331,160 @@ export function makeColDef(
|
|
|
388
331
|
})(),
|
|
389
332
|
};
|
|
390
333
|
}
|
|
334
|
+
|
|
335
|
+
type LabelColumnLookup = (axisId: AxisId) => number;
|
|
336
|
+
|
|
337
|
+
/** Build index mapping from full tableSpecs to their position in visibleTableSpecs (missing → -1). */
|
|
338
|
+
function buildSpecsToVisibleSpecsMapping(
|
|
339
|
+
tableSpecs: PTableColumnSpec[],
|
|
340
|
+
visibleTableSpecs: PTableColumnSpec[],
|
|
341
|
+
): Map<number, number> {
|
|
342
|
+
const specId = (spec: PTableColumnSpec) =>
|
|
343
|
+
canonicalizeJson<PTableColumnId>(getPTableColumnId(spec));
|
|
344
|
+
const visibleSpecsMap = new Map(
|
|
345
|
+
visibleTableSpecs.entries().map(([i, spec]) => [specId(spec), i] as const),
|
|
346
|
+
);
|
|
347
|
+
return new Map(
|
|
348
|
+
tableSpecs.entries().map(([i, spec]) => {
|
|
349
|
+
const visibleSpecIdx = visibleSpecsMap.get(specId(spec));
|
|
350
|
+
return [i, isNil(visibleSpecIdx) ? -1 : visibleSpecIdx];
|
|
351
|
+
}),
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
/** Predicate that returns true when an axis is one of the sheet partition axes. */
|
|
356
|
+
function createPartitionedAxisPredicate(sheets: PlDataTableSheet[]): (axisId: AxisId) => boolean {
|
|
357
|
+
const sheetAxesIds = sheets.map((sheet) => getAxisId(sheet.axis));
|
|
358
|
+
return (axisId) => sheetAxesIds.some((id) => matchAxisId(id, axisId));
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
/**
|
|
362
|
+
* Collect label columns (skipping partitioned axes and duplicates) and return a
|
|
363
|
+
* lookup function that resolves labeled axisId → label column index (or -1).
|
|
364
|
+
*/
|
|
365
|
+
function collectLabelColumnsByAxis(
|
|
366
|
+
tableSpecs: PTableColumnSpec[],
|
|
367
|
+
isPartitionedAxis: (axisId: AxisId) => boolean,
|
|
368
|
+
): LabelColumnLookup {
|
|
369
|
+
const labelColumns: { axisId: AxisId; labelColumnIdx: number }[] = [];
|
|
370
|
+
for (const [i, spec] of tableSpecs.entries()) {
|
|
371
|
+
if (spec.type !== "column" || !isLabelColumnSpec(spec.spec)) continue;
|
|
372
|
+
const labeledAxisId = getAxisId(spec.spec.axesSpec[0]);
|
|
373
|
+
if (isPartitionedAxis(labeledAxisId)) continue;
|
|
374
|
+
if (labelColumns.some((info) => matchAxisId(info.axisId, labeledAxisId))) {
|
|
375
|
+
console.warn(`multiple label columns match axisId: ${JSON.stringify(labeledAxisId)}`);
|
|
376
|
+
continue;
|
|
377
|
+
}
|
|
378
|
+
labelColumns.push({ axisId: labeledAxisId, labelColumnIdx: i });
|
|
379
|
+
}
|
|
380
|
+
return (axisId) =>
|
|
381
|
+
labelColumns.find((info) => matchAxisId(info.axisId, axisId))?.labelColumnIdx ?? -1;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
/** Indices of columns to display: drop partitioned axes, label/linker columns, hidden columns. */
|
|
385
|
+
function selectDisplayableIndices(
|
|
386
|
+
tableSpecs: PTableColumnSpec[],
|
|
387
|
+
isPartitionedAxis: (axisId: AxisId) => boolean,
|
|
388
|
+
): number[] {
|
|
389
|
+
return tableSpecs
|
|
390
|
+
.entries()
|
|
391
|
+
.filter(([, spec]) => {
|
|
392
|
+
switch (spec.type) {
|
|
393
|
+
case "axis":
|
|
394
|
+
return !isPartitionedAxis(spec.id);
|
|
395
|
+
case "column":
|
|
396
|
+
return (
|
|
397
|
+
!isLabelColumnSpec(spec.spec) &&
|
|
398
|
+
!isColumnHidden(spec.spec) &&
|
|
399
|
+
!isLinkerColumnSpec(spec.spec)
|
|
400
|
+
);
|
|
401
|
+
}
|
|
402
|
+
})
|
|
403
|
+
.map(([i]) => i)
|
|
404
|
+
.toArray();
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
/** Sort: axes first, then columns by OrderPriority annotation (higher priority = further left). */
|
|
408
|
+
function sortIndicesByTypeAndPriority(indices: number[], tableSpecs: PTableColumnSpec[]): number[] {
|
|
409
|
+
const priorityOf = (i: number): number => {
|
|
410
|
+
const spec = tableSpecs[i];
|
|
411
|
+
return spec.type === "column"
|
|
412
|
+
? (readAnnotationJson(spec.spec, Annotation.Table.OrderPriority) ?? 0)
|
|
413
|
+
: 0;
|
|
414
|
+
};
|
|
415
|
+
return [...indices].sort((a, b) => {
|
|
416
|
+
if (tableSpecs[a].type !== tableSpecs[b].type) {
|
|
417
|
+
return tableSpecs[a].type === "axis" ? -1 : 1;
|
|
418
|
+
}
|
|
419
|
+
return priorityOf(b) - priorityOf(a);
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/** For each axis entry substitute the index of its matching label column when one exists. */
|
|
424
|
+
function replaceAxesWithLabelColumns(
|
|
425
|
+
fields: number[],
|
|
426
|
+
tableSpecs: PTableColumnSpec[],
|
|
427
|
+
getLabelColumnIndex: LabelColumnLookup,
|
|
428
|
+
): number[] {
|
|
429
|
+
return fields.map((i) => {
|
|
430
|
+
const spec = tableSpecs[i];
|
|
431
|
+
const labelIdx = spec.type === "axis" ? getLabelColumnIndex(spec.id) : -1;
|
|
432
|
+
return labelIdx === -1 ? i : labelIdx;
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
|
|
436
|
+
/** Default hidden col ids built from columns marked with the Optional annotation. */
|
|
437
|
+
function computeDefaultHiddenColIds(
|
|
438
|
+
fields: number[],
|
|
439
|
+
indices: number[],
|
|
440
|
+
tableSpecs: PTableColumnSpec[],
|
|
441
|
+
): PlTableColumnIdJson[] {
|
|
442
|
+
return fields.reduce<PlTableColumnIdJson[]>((acc, field, i) => {
|
|
443
|
+
const spec = tableSpecs[field];
|
|
444
|
+
if (spec.type !== "column" || !isColumnOptional(spec.spec)) return acc;
|
|
445
|
+
const labeledSpec = tableSpecs[indices[i]];
|
|
446
|
+
return [...acc, canonicalizeJson<PlTableColumnId>({ source: spec, labeled: labeledSpec })];
|
|
447
|
+
}, []);
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
/** Extract axis indices and specs from the visible table (always present as part of join). */
|
|
451
|
+
function collectVisibleAxes(
|
|
452
|
+
visibleTableSpecs: PTableColumnSpec[],
|
|
453
|
+
): [number, PTableColumnSpecAxis][] {
|
|
454
|
+
return visibleTableSpecs
|
|
455
|
+
.entries()
|
|
456
|
+
.filter((entry): entry is [number, PTableColumnSpecAxis] => entry[1].type === "axis")
|
|
457
|
+
.toArray();
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
/**
|
|
461
|
+
* Compose request indices for the visible table:
|
|
462
|
+
* non-hidden display fields first, then visible axes (deduplicated).
|
|
463
|
+
* Returns fieldResultMapping (display field → position in requestIndices, -1 if not requested)
|
|
464
|
+
* and axesResultIndices (visible axis → position in requestIndices).
|
|
465
|
+
*/
|
|
466
|
+
function buildRequestIndices(
|
|
467
|
+
indices: number[],
|
|
468
|
+
specsToVisibleSpecsMapping: Map<number, number>,
|
|
469
|
+
visibleAxesIndices: number[],
|
|
470
|
+
): {
|
|
471
|
+
requestIndices: number[];
|
|
472
|
+
fieldResultMapping: number[];
|
|
473
|
+
axesResultIndices: number[];
|
|
474
|
+
} {
|
|
475
|
+
const resolved = indices.map((displayField) => {
|
|
476
|
+
const idx = specsToVisibleSpecsMapping.get(displayField);
|
|
477
|
+
return idx === undefined || idx === -1 ? null : idx;
|
|
478
|
+
});
|
|
479
|
+
const requestedFields = resolved.filter((v): v is number => v !== null);
|
|
480
|
+
|
|
481
|
+
const fieldResultMapping: number[] = [];
|
|
482
|
+
let pos = 0;
|
|
483
|
+
for (const v of resolved) {
|
|
484
|
+
fieldResultMapping.push(v === null ? -1 : pos++);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
const requestIndices = uniq([...requestedFields, ...visibleAxesIndices]);
|
|
488
|
+
const axesResultIndices = visibleAxesIndices.map((vi) => requestIndices.indexOf(vi));
|
|
489
|
+
return { requestIndices, fieldResultMapping, axesResultIndices };
|
|
490
|
+
}
|