@platforma-sdk/ui-vue 1.30.26 → 1.30.38
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 +15 -0
- package/dist/assets/chemical-properties.worker-thYtrBDn.js.map +1 -0
- package/dist/lib.js +11603 -10388
- package/dist/lib.js.map +1 -1
- package/dist/lib.umd.cjs +36 -29
- package/dist/lib.umd.cjs.map +1 -1
- package/dist/src/components/PlAgDataTable/PlAgDataTable.vue.d.ts +2 -1
- package/dist/src/components/PlAgDataTable/PlAgDataTable.vue.d.ts.map +1 -1
- package/dist/src/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts +12 -12
- package/dist/src/components/PlAgDataTable/PlAgDataTableV2.vue.d.ts.map +1 -1
- package/dist/src/components/PlAgDataTable/sources/common.d.ts +6 -16
- package/dist/src/components/PlAgDataTable/sources/common.d.ts.map +1 -1
- package/dist/src/components/PlAgDataTable/sources/table-source-v2.d.ts +13 -4
- package/dist/src/components/PlAgDataTable/sources/table-source-v2.d.ts.map +1 -1
- package/dist/src/components/PlAgDataTable/sources/table-source.d.ts +12 -3
- package/dist/src/components/PlAgDataTable/sources/table-source.d.ts.map +1 -1
- package/dist/src/components/PlAgDataTable/types.d.ts +25 -5
- package/dist/src/components/PlAgDataTable/types.d.ts.map +1 -1
- package/dist/src/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue.d.ts +8 -0
- package/dist/src/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue.d.ts.map +1 -0
- package/dist/src/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue.d.ts +40 -0
- package/dist/src/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue.d.ts.map +1 -0
- package/dist/src/components/PlMultiSequenceAlignment/data.d.ts +86 -0
- package/dist/src/components/PlMultiSequenceAlignment/data.d.ts.map +1 -0
- package/dist/src/components/PlMultiSequenceAlignment/highlight/chemical-properties.d.ts +19 -0
- package/dist/src/components/PlMultiSequenceAlignment/highlight/chemical-properties.d.ts.map +1 -0
- package/dist/src/components/PlMultiSequenceAlignment/highlight/chemical-properties.worker.d.ts +9 -0
- package/dist/src/components/PlMultiSequenceAlignment/highlight/chemical-properties.worker.d.ts.map +1 -0
- package/dist/src/components/PlMultiSequenceAlignment/highlight/index.d.ts +7 -0
- package/dist/src/components/PlMultiSequenceAlignment/highlight/index.d.ts.map +1 -0
- package/dist/src/components/PlMultiSequenceAlignment/highlight/types.d.ts +6 -0
- package/dist/src/components/PlMultiSequenceAlignment/highlight/types.d.ts.map +1 -0
- package/dist/src/components/PlMultiSequenceAlignment/index.d.ts +2 -0
- package/dist/src/components/PlMultiSequenceAlignment/index.d.ts.map +1 -0
- package/dist/src/components/PlMultiSequenceAlignment/multi-sequence-alignment.d.ts +7 -0
- package/dist/src/components/PlMultiSequenceAlignment/multi-sequence-alignment.d.ts.map +1 -0
- package/dist/src/components/PlMultiSequenceAlignment/types.d.ts +6 -0
- package/dist/src/components/PlMultiSequenceAlignment/types.d.ts.map +1 -0
- package/dist/src/lib.d.ts +1 -0
- 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 +13 -11
- package/src/components/PlAgDataTable/PlAgDataTable.vue +8 -7
- package/src/components/PlAgDataTable/PlAgDataTableV2.vue +157 -86
- package/src/components/PlAgDataTable/sources/common.ts +7 -101
- package/src/components/PlAgDataTable/sources/table-source-v2.ts +106 -11
- package/src/components/PlAgDataTable/sources/table-source.ts +95 -2
- package/src/components/PlAgDataTable/types.ts +29 -5
- package/src/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue +135 -0
- package/src/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue +173 -0
- package/src/components/PlMultiSequenceAlignment/data.ts +404 -0
- package/src/components/PlMultiSequenceAlignment/highlight/chemical-properties.ts +78 -0
- package/src/components/PlMultiSequenceAlignment/highlight/chemical-properties.worker.ts +191 -0
- package/src/components/PlMultiSequenceAlignment/highlight/index.ts +25 -0
- package/src/components/PlMultiSequenceAlignment/highlight/types.ts +5 -0
- package/src/components/PlMultiSequenceAlignment/index.ts +1 -0
- package/src/components/PlMultiSequenceAlignment/multi-sequence-alignment.ts +134 -0
- package/src/components/PlMultiSequenceAlignment/types.ts +5 -0
- package/src/lib.ts +2 -0
- package/src/vite-env.d.ts +13 -0
- package/tsconfig.lib.json +3 -1
- package/vite.config.ts +5 -2
- package/vitest.config.ts +7 -0
|
@@ -1,35 +1,44 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ColDef,
|
|
3
|
+
ICellRendererParams,
|
|
3
4
|
IServerSideDatasource,
|
|
4
5
|
IServerSideGetRowsParams,
|
|
5
6
|
RowModelType,
|
|
6
7
|
} from 'ag-grid-enterprise';
|
|
7
8
|
import type {
|
|
9
|
+
AxisId,
|
|
8
10
|
PlDataTableGridStateWithoutSheets,
|
|
9
11
|
PlDataTableModel,
|
|
10
12
|
PTableColumnSpec,
|
|
13
|
+
PTableKey,
|
|
11
14
|
} from '@platforma-sdk/model';
|
|
12
15
|
import {
|
|
16
|
+
canonicalizeJson,
|
|
13
17
|
getAxisId,
|
|
18
|
+
isColumnOptional,
|
|
19
|
+
mapPTableValueToAxisKey,
|
|
14
20
|
pTableValue,
|
|
21
|
+
stringifyPTableColumnSpec,
|
|
15
22
|
type PColumnSpec,
|
|
16
23
|
type PFrameDriver,
|
|
17
24
|
type PlDataTableSheet,
|
|
18
25
|
type PTableVector,
|
|
19
26
|
} from '@platforma-sdk/model';
|
|
20
27
|
import * as lodash from 'lodash';
|
|
21
|
-
import type {
|
|
28
|
+
import type { PlAgDataTableV2Row, PTableKeyJson } from '../types';
|
|
22
29
|
import { makeRowNumberColDef, PlAgDataTableRowNumberColId } from './row-number';
|
|
23
30
|
import { objectHash } from '../../../objectHash';
|
|
24
31
|
import type { Ref } from 'vue';
|
|
25
32
|
import {
|
|
33
|
+
defaultValueFormatter,
|
|
26
34
|
isLabelColumn,
|
|
27
|
-
makeColDef,
|
|
28
|
-
makeRowId,
|
|
29
35
|
PTableHidden,
|
|
30
|
-
type PlAgCellButtonAxisParams,
|
|
31
36
|
} from './common';
|
|
32
37
|
import canonicalize from 'canonicalize';
|
|
38
|
+
import type { PlAgHeaderComponentType, PlAgHeaderComponentParams } from '../../PlAgColumnHeader';
|
|
39
|
+
import { PlAgColumnHeader } from '../../PlAgColumnHeader';
|
|
40
|
+
import { PlAgTextAndButtonCell } from '../../PlAgTextAndButtonCell';
|
|
41
|
+
import { defaultMainMenuItems } from './menu-items';
|
|
33
42
|
|
|
34
43
|
/** Convert columnar data from the driver to rows, used by ag-grid */
|
|
35
44
|
function columns2rows(
|
|
@@ -37,11 +46,15 @@ function columns2rows(
|
|
|
37
46
|
columns: PTableVector[],
|
|
38
47
|
axes: number[],
|
|
39
48
|
resultMapping: number[],
|
|
40
|
-
):
|
|
41
|
-
const rowData:
|
|
49
|
+
): PlAgDataTableV2Row[] {
|
|
50
|
+
const rowData: PlAgDataTableV2Row[] = [];
|
|
42
51
|
for (let iRow = 0; iRow < columns[0].data.length; ++iRow) {
|
|
43
|
-
const key = axes.map((iAxis) =>
|
|
44
|
-
|
|
52
|
+
const key = axes.map((iAxis) => {
|
|
53
|
+
return mapPTableValueToAxisKey(
|
|
54
|
+
pTableValue(columns[resultMapping[iAxis]], iRow),
|
|
55
|
+
);
|
|
56
|
+
});
|
|
57
|
+
const row: PlAgDataTableV2Row = { id: makeRowId(key), key };
|
|
45
58
|
fields.forEach((field, iCol) => {
|
|
46
59
|
row[field.toString() as `${number}`] = resultMapping[iCol] === -1
|
|
47
60
|
? PTableHidden
|
|
@@ -66,7 +79,7 @@ export async function updatePFrameGridOptions(
|
|
|
66
79
|
columnDefs: ColDef[];
|
|
67
80
|
serverSideDatasource?: IServerSideDatasource;
|
|
68
81
|
rowModelType: RowModelType;
|
|
69
|
-
rowData?:
|
|
82
|
+
rowData?: PlAgDataTableV2Row[];
|
|
70
83
|
}> {
|
|
71
84
|
const pt = model.tableHandle;
|
|
72
85
|
const specs = model.tableSpec;
|
|
@@ -153,7 +166,7 @@ export async function updatePFrameGridOptions(
|
|
|
153
166
|
|
|
154
167
|
const ptShape = await pfDriver.getShape(pt);
|
|
155
168
|
const rowCount = ptShape.rows;
|
|
156
|
-
const columnDefs: ColDef<
|
|
169
|
+
const columnDefs: ColDef<PlAgDataTableV2Row>[] = [
|
|
157
170
|
makeRowNumberColDef(),
|
|
158
171
|
...fields.map((i) => makeColDef(i, specs[i], columnVisibility?.hiddenColIds, cellButtonAxisParams)),
|
|
159
172
|
];
|
|
@@ -229,7 +242,7 @@ export async function updatePFrameGridOptions(
|
|
|
229
242
|
lastParams = params;
|
|
230
243
|
|
|
231
244
|
let length = 0;
|
|
232
|
-
let rowData:
|
|
245
|
+
let rowData: PlAgDataTableV2Row[] = [];
|
|
233
246
|
if (rowCount > 0 && params.request.startRow !== undefined && params.request.endRow !== undefined) {
|
|
234
247
|
length = Math.min(rowCount, params.request.endRow) - params.request.startRow;
|
|
235
248
|
if (length > 0) {
|
|
@@ -258,3 +271,85 @@ export async function updatePFrameGridOptions(
|
|
|
258
271
|
serverSideDatasource,
|
|
259
272
|
};
|
|
260
273
|
}
|
|
274
|
+
|
|
275
|
+
export type PlAgCellButtonAxisParams = {
|
|
276
|
+
showCellButtonForAxisId?: AxisId;
|
|
277
|
+
cellButtonInvokeRowsOnDoubleClick?: boolean;
|
|
278
|
+
trigger: (key?: PTableKey) => void;
|
|
279
|
+
};
|
|
280
|
+
|
|
281
|
+
/**
|
|
282
|
+
* Calculates column definition for a given p-table column
|
|
283
|
+
*/
|
|
284
|
+
export function makeColDef(
|
|
285
|
+
iCol: number,
|
|
286
|
+
spec: PTableColumnSpec,
|
|
287
|
+
hiddenColIds?: string[],
|
|
288
|
+
cellButtonAxisParams?: PlAgCellButtonAxisParams,
|
|
289
|
+
): ColDef {
|
|
290
|
+
const colId = stringifyPTableColumnSpec(spec);
|
|
291
|
+
const valueType = spec.type === 'axis' ? spec.spec.type : spec.spec.valueType;
|
|
292
|
+
return {
|
|
293
|
+
colId,
|
|
294
|
+
mainMenuItems: defaultMainMenuItems,
|
|
295
|
+
context: spec,
|
|
296
|
+
field: iCol.toString(),
|
|
297
|
+
headerName: spec.spec.annotations?.['pl7.app/label']?.trim() ?? 'Unlabeled ' + spec.type + ' ' + iCol.toString(),
|
|
298
|
+
lockPosition: spec.type === 'axis',
|
|
299
|
+
hide: hiddenColIds?.includes(colId) ?? isColumnOptional(spec.spec),
|
|
300
|
+
valueFormatter: defaultValueFormatter,
|
|
301
|
+
headerComponent: PlAgColumnHeader,
|
|
302
|
+
cellRendererSelector: cellButtonAxisParams?.showCellButtonForAxisId
|
|
303
|
+
? (params: ICellRendererParams) => {
|
|
304
|
+
if (spec.type !== 'axis') return;
|
|
305
|
+
|
|
306
|
+
const axisId = (params.colDef?.context as PTableColumnSpec)?.id as AxisId;
|
|
307
|
+
if (lodash.isEqual(axisId, cellButtonAxisParams.showCellButtonForAxisId)) {
|
|
308
|
+
return {
|
|
309
|
+
component: PlAgTextAndButtonCell,
|
|
310
|
+
params: {
|
|
311
|
+
invokeRowsOnDoubleClick: cellButtonAxisParams.cellButtonInvokeRowsOnDoubleClick,
|
|
312
|
+
onClick: (params: ICellRendererParams<PlAgDataTableV2Row>) => {
|
|
313
|
+
cellButtonAxisParams.trigger(params.data?.key);
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
};
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
: undefined,
|
|
320
|
+
headerComponentParams: {
|
|
321
|
+
type: ((): PlAgHeaderComponentType => {
|
|
322
|
+
switch (valueType) {
|
|
323
|
+
case 'Int':
|
|
324
|
+
case 'Long':
|
|
325
|
+
case 'Float':
|
|
326
|
+
case 'Double':
|
|
327
|
+
return 'Number';
|
|
328
|
+
case 'String':
|
|
329
|
+
case 'Bytes':
|
|
330
|
+
return 'Text';
|
|
331
|
+
default:
|
|
332
|
+
throw Error(`unsupported data type: ${valueType}`);
|
|
333
|
+
}
|
|
334
|
+
})(),
|
|
335
|
+
} satisfies PlAgHeaderComponentParams,
|
|
336
|
+
cellDataType: (() => {
|
|
337
|
+
switch (valueType) {
|
|
338
|
+
case 'Int':
|
|
339
|
+
case 'Long':
|
|
340
|
+
case 'Float':
|
|
341
|
+
case 'Double':
|
|
342
|
+
return 'number';
|
|
343
|
+
case 'String':
|
|
344
|
+
case 'Bytes':
|
|
345
|
+
return 'text';
|
|
346
|
+
default:
|
|
347
|
+
throw Error(`unsupported data type: ${valueType}`);
|
|
348
|
+
}
|
|
349
|
+
})(),
|
|
350
|
+
};
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
export function makeRowId(rowKey: PTableKey): PTableKeyJson {
|
|
354
|
+
return canonicalizeJson(rowKey);
|
|
355
|
+
}
|
|
@@ -1,15 +1,22 @@
|
|
|
1
1
|
import type {
|
|
2
2
|
ColDef,
|
|
3
|
+
ICellRendererParams,
|
|
3
4
|
IServerSideDatasource,
|
|
4
5
|
IServerSideGetRowsParams,
|
|
5
6
|
RowModelType,
|
|
6
7
|
} from 'ag-grid-enterprise';
|
|
7
8
|
import type {
|
|
9
|
+
AxisId,
|
|
8
10
|
PlDataTableGridStateWithoutSheets,
|
|
11
|
+
PTableColumnSpec,
|
|
12
|
+
PTableRowKey,
|
|
9
13
|
} from '@platforma-sdk/model';
|
|
10
14
|
import {
|
|
15
|
+
canonicalizeJson,
|
|
11
16
|
getAxisId,
|
|
17
|
+
isColumnOptional,
|
|
12
18
|
pTableValue,
|
|
19
|
+
stringifyPTableColumnSpec,
|
|
13
20
|
type PColumnSpec,
|
|
14
21
|
type PFrameDriver,
|
|
15
22
|
type PlDataTableSheet,
|
|
@@ -17,12 +24,16 @@ import {
|
|
|
17
24
|
type PTableVector,
|
|
18
25
|
} from '@platforma-sdk/model';
|
|
19
26
|
import * as lodash from 'lodash';
|
|
20
|
-
import type { PlAgDataTableRow } from '../types';
|
|
27
|
+
import type { PlAgDataTableRow, PTableRowKeyJson } from '../types';
|
|
21
28
|
import { makeRowNumberColDef, PlAgDataTableRowNumberColId } from './row-number';
|
|
22
29
|
import { getHeterogeneousColumns, updatePFrameGridOptionsHeterogeneousAxes } from './table-source-heterogeneous';
|
|
23
30
|
import { objectHash } from '../../../objectHash';
|
|
24
31
|
import type { Ref } from 'vue';
|
|
25
|
-
import {
|
|
32
|
+
import { defaultValueFormatter, isLabelColumn } from './common';
|
|
33
|
+
import { defaultMainMenuItems } from './menu-items';
|
|
34
|
+
import type { PlAgHeaderComponentParams, PlAgHeaderComponentType } from '../../PlAgColumnHeader';
|
|
35
|
+
import { PlAgColumnHeader } from '../../PlAgColumnHeader';
|
|
36
|
+
import { PlAgTextAndButtonCell } from '../../PlAgTextAndButtonCell';
|
|
26
37
|
|
|
27
38
|
/** Convert columnar data from the driver to rows, used by ag-grid */
|
|
28
39
|
function columns2rows(fields: number[], columns: PTableVector[], axes: number[]): PlAgDataTableRow[] {
|
|
@@ -246,3 +257,85 @@ export async function updatePFrameGridOptions(
|
|
|
246
257
|
serverSideDatasource,
|
|
247
258
|
};
|
|
248
259
|
}
|
|
260
|
+
|
|
261
|
+
export type PlAgCellButtonAxisParams = {
|
|
262
|
+
showCellButtonForAxisId?: AxisId;
|
|
263
|
+
cellButtonInvokeRowsOnDoubleClick?: boolean;
|
|
264
|
+
trigger: (key?: PTableRowKey) => void;
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
/**
|
|
268
|
+
* Calculates column definition for a given p-table column
|
|
269
|
+
*/
|
|
270
|
+
export function makeColDef(
|
|
271
|
+
iCol: number,
|
|
272
|
+
spec: PTableColumnSpec,
|
|
273
|
+
hiddenColIds?: string[],
|
|
274
|
+
cellButtonAxisParams?: PlAgCellButtonAxisParams,
|
|
275
|
+
): ColDef {
|
|
276
|
+
const colId = stringifyPTableColumnSpec(spec);
|
|
277
|
+
const valueType = spec.type === 'axis' ? spec.spec.type : spec.spec.valueType;
|
|
278
|
+
return {
|
|
279
|
+
colId,
|
|
280
|
+
mainMenuItems: defaultMainMenuItems,
|
|
281
|
+
context: spec,
|
|
282
|
+
field: iCol.toString(),
|
|
283
|
+
headerName: spec.spec.annotations?.['pl7.app/label']?.trim() ?? 'Unlabeled ' + spec.type + ' ' + iCol.toString(),
|
|
284
|
+
lockPosition: spec.type === 'axis',
|
|
285
|
+
hide: hiddenColIds?.includes(colId) ?? isColumnOptional(spec.spec),
|
|
286
|
+
valueFormatter: defaultValueFormatter,
|
|
287
|
+
headerComponent: PlAgColumnHeader,
|
|
288
|
+
cellRendererSelector: cellButtonAxisParams?.showCellButtonForAxisId
|
|
289
|
+
? (params: ICellRendererParams) => {
|
|
290
|
+
if (spec.type !== 'axis') return;
|
|
291
|
+
|
|
292
|
+
const axisId = (params.colDef?.context as PTableColumnSpec)?.id as AxisId;
|
|
293
|
+
if (lodash.isEqual(axisId, cellButtonAxisParams.showCellButtonForAxisId)) {
|
|
294
|
+
return {
|
|
295
|
+
component: PlAgTextAndButtonCell,
|
|
296
|
+
params: {
|
|
297
|
+
invokeRowsOnDoubleClick: cellButtonAxisParams.cellButtonInvokeRowsOnDoubleClick,
|
|
298
|
+
onClick: (prms: ICellRendererParams<PlAgDataTableRow>) => {
|
|
299
|
+
cellButtonAxisParams.trigger(prms.data?.key);
|
|
300
|
+
},
|
|
301
|
+
},
|
|
302
|
+
};
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
: undefined,
|
|
306
|
+
headerComponentParams: {
|
|
307
|
+
type: ((): PlAgHeaderComponentType => {
|
|
308
|
+
switch (valueType) {
|
|
309
|
+
case 'Int':
|
|
310
|
+
case 'Long':
|
|
311
|
+
case 'Float':
|
|
312
|
+
case 'Double':
|
|
313
|
+
return 'Number';
|
|
314
|
+
case 'String':
|
|
315
|
+
case 'Bytes':
|
|
316
|
+
return 'Text';
|
|
317
|
+
default:
|
|
318
|
+
throw Error(`unsupported data type: ${valueType}`);
|
|
319
|
+
}
|
|
320
|
+
})(),
|
|
321
|
+
} satisfies PlAgHeaderComponentParams,
|
|
322
|
+
cellDataType: (() => {
|
|
323
|
+
switch (valueType) {
|
|
324
|
+
case 'Int':
|
|
325
|
+
case 'Long':
|
|
326
|
+
case 'Float':
|
|
327
|
+
case 'Double':
|
|
328
|
+
return 'number';
|
|
329
|
+
case 'String':
|
|
330
|
+
case 'Bytes':
|
|
331
|
+
return 'text';
|
|
332
|
+
default:
|
|
333
|
+
throw Error(`unsupported data type: ${valueType}`);
|
|
334
|
+
}
|
|
335
|
+
})(),
|
|
336
|
+
};
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
export function makeRowId(rowKey: PTableRowKey): PTableRowKeyJson {
|
|
340
|
+
return canonicalizeJson(rowKey);
|
|
341
|
+
}
|
|
@@ -7,9 +7,12 @@ import type {
|
|
|
7
7
|
PlTableFilterType,
|
|
8
8
|
PTableColumnId,
|
|
9
9
|
PTableHandle,
|
|
10
|
+
PTableKey,
|
|
11
|
+
PTableRowKey,
|
|
10
12
|
PTableValue,
|
|
11
13
|
RemoteBlobHandleAndSize,
|
|
12
14
|
} from '@platforma-sdk/model';
|
|
15
|
+
import type { PTableHidden } from './sources/common';
|
|
13
16
|
|
|
14
17
|
export type PlDataTableSettingsPTable = {
|
|
15
18
|
/** The type of the source to feed the data into the table */
|
|
@@ -62,9 +65,6 @@ export type PlTableFiltersDefault = {
|
|
|
62
65
|
default: PlTableFilter;
|
|
63
66
|
};
|
|
64
67
|
|
|
65
|
-
/** Key is a set of all axes values, which means it is unique across rows */
|
|
66
|
-
export type PTableRowKey = PTableValue[];
|
|
67
|
-
|
|
68
68
|
/** PlAgDataTable controller contains all exported methods */
|
|
69
69
|
export type PlAgDataTableController = {
|
|
70
70
|
/**
|
|
@@ -74,8 +74,20 @@ export type PlAgDataTableController = {
|
|
|
74
74
|
focusRow: (rowKey: PTableRowKey) => Promise<void>;
|
|
75
75
|
};
|
|
76
76
|
|
|
77
|
-
/**
|
|
78
|
-
export type
|
|
77
|
+
/** PlAgDataTable controller contains all exported methods */
|
|
78
|
+
export type PlAgDataTableV2Controller = {
|
|
79
|
+
/**
|
|
80
|
+
* Scroll table to make row with provided key visible
|
|
81
|
+
* Warning: works reliably only in client side mode.
|
|
82
|
+
*/
|
|
83
|
+
focusRow: (rowKey: PTableKey) => Promise<void>;
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Canonicalized PTableValue array JSON string
|
|
88
|
+
* @deprecated Migrate to PlAgDataTableV2
|
|
89
|
+
*/
|
|
90
|
+
export type PTableRowKeyJson = CanonicalizedJson<PTableRowKey>;
|
|
79
91
|
|
|
80
92
|
/** PlAgDataTable row */
|
|
81
93
|
export type PlAgDataTableRow = {
|
|
@@ -87,6 +99,18 @@ export type PlAgDataTableRow = {
|
|
|
87
99
|
[field: `${number}` | `hC${number}`]: PTableValue;
|
|
88
100
|
};
|
|
89
101
|
|
|
102
|
+
export type PTableKeyJson = CanonicalizedJson<PTableKey>;
|
|
103
|
+
|
|
104
|
+
/** PlAgDataTableV2 row */
|
|
105
|
+
export type PlAgDataTableV2Row = {
|
|
106
|
+
/** Axis key is not present for heterogeneous axes */
|
|
107
|
+
key?: PTableKey;
|
|
108
|
+
/** Unique row identifier, created as canonicalize(key)! when key is present */
|
|
109
|
+
id: PTableKeyJson;
|
|
110
|
+
/** Row values by column; sheet axes and labeled axes are excluded */
|
|
111
|
+
[field: `${number}`]: PTableValue | PTableHidden;
|
|
112
|
+
};
|
|
113
|
+
|
|
90
114
|
export type PlAgOverlayLoadingParams = {
|
|
91
115
|
/**
|
|
92
116
|
* Required flag, that shows catInBag icon with message if `true`, shows PlSplash component if `false`.
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import { computed, reactive } from 'vue';
|
|
3
|
+
import { getCssBackgroundImage } from './highlight';
|
|
4
|
+
import {
|
|
5
|
+
chemicalPropertiesColors,
|
|
6
|
+
useChemicalPropertiesHighlight,
|
|
7
|
+
} from './highlight/chemical-properties';
|
|
8
|
+
import { useAlignedRows } from './multi-sequence-alignment';
|
|
9
|
+
import type { SequenceRow } from './types';
|
|
10
|
+
|
|
11
|
+
const { sequenceRows, highlight } = defineProps<{
|
|
12
|
+
sequenceRows: SequenceRow[];
|
|
13
|
+
highlight?: 'chemical-properties' | undefined;
|
|
14
|
+
}>();
|
|
15
|
+
|
|
16
|
+
const alignedRows = useAlignedRows(() => sequenceRows);
|
|
17
|
+
|
|
18
|
+
const chemicalPropertiesHighlight = reactive(
|
|
19
|
+
useChemicalPropertiesHighlight(() => {
|
|
20
|
+
if (highlight !== 'chemical-properties' || alignedRows.loading) {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
return sequenceRows.map(({ header }) => {
|
|
24
|
+
const row = alignedRows.value.get(header);
|
|
25
|
+
if (!row) {
|
|
26
|
+
console.error(`Missing aligned row for header ${header}`);
|
|
27
|
+
}
|
|
28
|
+
return alignedRows.value.get(header) ?? '';
|
|
29
|
+
});
|
|
30
|
+
}),
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
const columnCount = computed(
|
|
34
|
+
() => (sequenceRows.at(0)?.labels.length ?? 0) + 1,
|
|
35
|
+
);
|
|
36
|
+
const rowCount = computed(() => sequenceRows.length);
|
|
37
|
+
|
|
38
|
+
const selectedHighlight = computed(() => {
|
|
39
|
+
if (!highlight) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
switch (highlight) {
|
|
43
|
+
case 'chemical-properties':
|
|
44
|
+
return chemicalPropertiesHighlight;
|
|
45
|
+
default:
|
|
46
|
+
throw new Error(`Unknown highlight ${highlight}`);
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
const sequenceLetterSpacing = '12px';
|
|
51
|
+
</script>
|
|
52
|
+
|
|
53
|
+
<template>
|
|
54
|
+
<div v-if="!alignedRows.loading" :class="['pl-scrollable', $style.container]">
|
|
55
|
+
<div
|
|
56
|
+
v-if="selectedHighlight && !selectedHighlight.loading"
|
|
57
|
+
:class="$style.highlight"
|
|
58
|
+
:style="
|
|
59
|
+
{
|
|
60
|
+
backgroundImage: getCssBackgroundImage({
|
|
61
|
+
columns: selectedHighlight.data,
|
|
62
|
+
rowCount: sequenceRows.length,
|
|
63
|
+
colors: chemicalPropertiesColors,
|
|
64
|
+
}),
|
|
65
|
+
}
|
|
66
|
+
"
|
|
67
|
+
/>
|
|
68
|
+
<template
|
|
69
|
+
v-for="row of sequenceRows"
|
|
70
|
+
:key="row.header"
|
|
71
|
+
>
|
|
72
|
+
<div
|
|
73
|
+
v-for="(label, labelIndex) of row.labels"
|
|
74
|
+
:key="labelIndex"
|
|
75
|
+
:class="
|
|
76
|
+
[
|
|
77
|
+
$style.label,
|
|
78
|
+
labelIndex === row.labels.length - 1 && $style.last,
|
|
79
|
+
]
|
|
80
|
+
"
|
|
81
|
+
>
|
|
82
|
+
{{ label }}
|
|
83
|
+
</div>
|
|
84
|
+
<div :class="$style.sequence">
|
|
85
|
+
{{ alignedRows.value.get(row.header) }}
|
|
86
|
+
</div>
|
|
87
|
+
</template>
|
|
88
|
+
</div>
|
|
89
|
+
</template>
|
|
90
|
+
|
|
91
|
+
<style module>
|
|
92
|
+
.container {
|
|
93
|
+
flex: 1;
|
|
94
|
+
position: relative;
|
|
95
|
+
font-family: Spline Sans Mono;
|
|
96
|
+
text-wrap: nowrap;
|
|
97
|
+
display: grid;
|
|
98
|
+
grid-template-columns: repeat(v-bind(columnCount), min-content);
|
|
99
|
+
grid-template-rows: repeat(v-bind(rowCount), min-content);
|
|
100
|
+
justify-content: start;
|
|
101
|
+
column-gap: 16px;
|
|
102
|
+
line-height: calc(24 / 14);
|
|
103
|
+
|
|
104
|
+
* {
|
|
105
|
+
content-visibility: auto;
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
.highlight {
|
|
110
|
+
position: absolute;
|
|
111
|
+
grid-area: 1 / -2 / -1 / -1; /* all rows and last column */
|
|
112
|
+
inset: 0 calc(v-bind(sequenceLetterSpacing) / -2);
|
|
113
|
+
background-size: calc(100% - v-bind(sequenceLetterSpacing));
|
|
114
|
+
background-repeat: no-repeat;
|
|
115
|
+
z-index: -1;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.label {
|
|
119
|
+
background-color: white;
|
|
120
|
+
position: sticky;
|
|
121
|
+
inset-inline-start: 0;
|
|
122
|
+
text-align: end;
|
|
123
|
+
z-index: 1;
|
|
124
|
+
|
|
125
|
+
&.last {
|
|
126
|
+
padding-inline-end: 16px;
|
|
127
|
+
border-inline-end: 1px solid black;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
.sequence {
|
|
132
|
+
font-weight: 600;
|
|
133
|
+
letter-spacing: v-bind(sequenceLetterSpacing);
|
|
134
|
+
}
|
|
135
|
+
</style>
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
<script lang="ts" setup>
|
|
2
|
+
import {
|
|
3
|
+
PlAlert,
|
|
4
|
+
PlBtnGhost,
|
|
5
|
+
PlDropdownMulti,
|
|
6
|
+
PlIcon24,
|
|
7
|
+
PlSlideModal,
|
|
8
|
+
PlTooltip,
|
|
9
|
+
} from '@milaboratories/uikit';
|
|
10
|
+
import type {
|
|
11
|
+
PColumnPredicate,
|
|
12
|
+
PFrameHandle,
|
|
13
|
+
PlMultiSequenceAlignmentModel,
|
|
14
|
+
PlSelectionModel,
|
|
15
|
+
} from '@platforma-sdk/model';
|
|
16
|
+
import { computed, onMounted, reactive, ref } from 'vue';
|
|
17
|
+
import { useDataTableToolsPanelTarget } from '../PlAgDataTableToolsPanel';
|
|
18
|
+
import { useLabelColumns, useSequenceColumns, useSequenceRows } from './data';
|
|
19
|
+
import {
|
|
20
|
+
chemicalCategories,
|
|
21
|
+
chemicalPropertiesColors,
|
|
22
|
+
chemicalPropertiesLabels,
|
|
23
|
+
} from './highlight/chemical-properties';
|
|
24
|
+
import MultiSequenceAlignmentView from './MultiSequenceAlignmentView.vue';
|
|
25
|
+
|
|
26
|
+
const model = defineModel<PlMultiSequenceAlignmentModel>({ default: {} });
|
|
27
|
+
|
|
28
|
+
const props = defineProps<{
|
|
29
|
+
/**
|
|
30
|
+
* Handle to PFrame created using `createPFrameForGraphs`.
|
|
31
|
+
* Should contain all desired sequence and label columns.
|
|
32
|
+
*/
|
|
33
|
+
readonly pFrame: PFrameHandle | undefined;
|
|
34
|
+
/**
|
|
35
|
+
* Return true if column should be shown in sequence columns dropdown.
|
|
36
|
+
* By default, all sequence columns are selected.
|
|
37
|
+
*/
|
|
38
|
+
readonly sequenceColumnPredicate: PColumnPredicate;
|
|
39
|
+
/**
|
|
40
|
+
* Return true if column should be shown in label columns dropdown.
|
|
41
|
+
* By default, common axes of selected sequence columns are selected.
|
|
42
|
+
*/
|
|
43
|
+
readonly labelColumnOptionPredicate?: PColumnPredicate;
|
|
44
|
+
/**
|
|
45
|
+
* Sometimes sequence column and label column have disjoint axes.
|
|
46
|
+
* In this case you have to define `linkerColumnPredicate` to select columns
|
|
47
|
+
* connecting axes of sequence and label columns.
|
|
48
|
+
*/
|
|
49
|
+
readonly linkerColumnPredicate?: PColumnPredicate;
|
|
50
|
+
/**
|
|
51
|
+
* Row selection model (from `PlAgDataTableV2` or `GraphMaker`).
|
|
52
|
+
* If not provided or empty, all rows will be considered selected.
|
|
53
|
+
* Warning: should be forwarded as a field of `reactive` object
|
|
54
|
+
*/
|
|
55
|
+
readonly selection?: PlSelectionModel | undefined;
|
|
56
|
+
}>();
|
|
57
|
+
|
|
58
|
+
// SlidePanel visibility flag
|
|
59
|
+
const show = ref(false);
|
|
60
|
+
|
|
61
|
+
// Teleport open button to DataTableToolsPanel after mount
|
|
62
|
+
const mounted = ref(false);
|
|
63
|
+
onMounted(() => {
|
|
64
|
+
mounted.value = true;
|
|
65
|
+
});
|
|
66
|
+
const teleportTarget = useDataTableToolsPanelTarget();
|
|
67
|
+
|
|
68
|
+
const sequenceColumns = reactive(useSequenceColumns(() => ({
|
|
69
|
+
pframe: props.pFrame,
|
|
70
|
+
sequenceColumnPredicate: props.sequenceColumnPredicate,
|
|
71
|
+
})));
|
|
72
|
+
|
|
73
|
+
const labelColumns = reactive(useLabelColumns(() => ({
|
|
74
|
+
pframe: props.pFrame,
|
|
75
|
+
sequenceColumnIds: sequenceColumns.defaults,
|
|
76
|
+
labelColumnOptionPredicate: props.labelColumnOptionPredicate,
|
|
77
|
+
})));
|
|
78
|
+
|
|
79
|
+
const selectedSequenceColumnIds = computed({
|
|
80
|
+
get: () => model.value.sequenceColumnIds ?? sequenceColumns.defaults,
|
|
81
|
+
set: (value) => {
|
|
82
|
+
model.value.sequenceColumnIds = value;
|
|
83
|
+
},
|
|
84
|
+
});
|
|
85
|
+
const selectedLabelColumnIds = computed({
|
|
86
|
+
get: () => model.value.labelColumnIds ?? labelColumns.defaults,
|
|
87
|
+
set: (value) => {
|
|
88
|
+
model.value.labelColumnIds = value;
|
|
89
|
+
},
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
const sequenceRows = reactive(useSequenceRows(() => ({
|
|
93
|
+
pframe: props.pFrame,
|
|
94
|
+
sequenceColumnIds: selectedSequenceColumnIds.value,
|
|
95
|
+
labelColumnIds: selectedLabelColumnIds.value,
|
|
96
|
+
linkerColumnPredicate: props.linkerColumnPredicate,
|
|
97
|
+
selection: props.selection,
|
|
98
|
+
})));
|
|
99
|
+
</script>
|
|
100
|
+
|
|
101
|
+
<template>
|
|
102
|
+
<Teleport v-if="mounted && teleportTarget" :to="teleportTarget">
|
|
103
|
+
<PlBtnGhost icon="dna" @click.stop="show = true">
|
|
104
|
+
Multi Alignment
|
|
105
|
+
</PlBtnGhost>
|
|
106
|
+
</Teleport>
|
|
107
|
+
|
|
108
|
+
<PlSlideModal v-model="show" width="100%" :close-on-outside-click="false">
|
|
109
|
+
<template #title>
|
|
110
|
+
Multi Alignment
|
|
111
|
+
<PlTooltip :class="$style.tooltip" position="southwest">
|
|
112
|
+
<PlIcon24 name="info" />
|
|
113
|
+
<template #tooltip>
|
|
114
|
+
<div
|
|
115
|
+
v-for="category in chemicalCategories"
|
|
116
|
+
:key="category"
|
|
117
|
+
>
|
|
118
|
+
<span
|
|
119
|
+
:class="$style['color-sample']"
|
|
120
|
+
:style="
|
|
121
|
+
{
|
|
122
|
+
backgroundColor:
|
|
123
|
+
chemicalPropertiesColors[category],
|
|
124
|
+
}
|
|
125
|
+
"
|
|
126
|
+
/>
|
|
127
|
+
{{ chemicalPropertiesLabels[category] }}
|
|
128
|
+
</div>
|
|
129
|
+
</template>
|
|
130
|
+
</PlTooltip>
|
|
131
|
+
</template>
|
|
132
|
+
|
|
133
|
+
<PlDropdownMulti
|
|
134
|
+
v-model="selectedSequenceColumnIds"
|
|
135
|
+
label="Sequence Columns"
|
|
136
|
+
:options="sequenceColumns.options"
|
|
137
|
+
:disabled="sequenceColumns.loading"
|
|
138
|
+
clearable
|
|
139
|
+
/>
|
|
140
|
+
<PlDropdownMulti
|
|
141
|
+
v-model="selectedLabelColumnIds"
|
|
142
|
+
label="Label Columns"
|
|
143
|
+
:options="labelColumns.options"
|
|
144
|
+
:disabled="labelColumns.loading"
|
|
145
|
+
clearable
|
|
146
|
+
/>
|
|
147
|
+
|
|
148
|
+
<PlAlert v-if="sequenceRows.data.length < 2" type="warn">
|
|
149
|
+
Please select at least one sequence column and two or more rows to run
|
|
150
|
+
alignment
|
|
151
|
+
</PlAlert>
|
|
152
|
+
|
|
153
|
+
<MultiSequenceAlignmentView
|
|
154
|
+
v-else
|
|
155
|
+
:sequenceRows="sequenceRows.data"
|
|
156
|
+
highlight="chemical-properties"
|
|
157
|
+
/>
|
|
158
|
+
</PlSlideModal>
|
|
159
|
+
</template>
|
|
160
|
+
|
|
161
|
+
<style module>
|
|
162
|
+
.tooltip {
|
|
163
|
+
display: inline-flex;
|
|
164
|
+
}
|
|
165
|
+
.color-sample {
|
|
166
|
+
display: inline-block;
|
|
167
|
+
width: 12px;
|
|
168
|
+
height: 12px;
|
|
169
|
+
border: 1px solid #ccc;
|
|
170
|
+
margin-right: 8px;
|
|
171
|
+
vertical-align: middle;
|
|
172
|
+
}
|
|
173
|
+
</style>
|