@platforma-sdk/ui-vue 1.33.17 → 1.34.4
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 +20 -0
- package/dist/lib.css +1 -1
- package/dist/lib.js +8355 -8293
- package/dist/lib.js.map +1 -1
- package/dist/src/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue.d.ts +3 -2
- package/dist/src/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue.d.ts.map +1 -1
- package/dist/src/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue.d.ts.map +1 -1
- package/dist/src/components/PlMultiSequenceAlignment/Toolbar.vue.d.ts +7 -11
- package/dist/src/components/PlMultiSequenceAlignment/Toolbar.vue.d.ts.map +1 -1
- package/dist/src/components/PlMultiSequenceAlignment/data.d.ts +21 -12
- package/dist/src/components/PlMultiSequenceAlignment/data.d.ts.map +1 -1
- package/dist/src/components/PlMultiSequenceAlignment/migrations.d.ts +4 -0
- package/dist/src/components/PlMultiSequenceAlignment/migrations.d.ts.map +1 -0
- package/dist/src/components/PlMultiSequenceAlignment/multi-sequence-alignment.d.ts +0 -5
- package/dist/src/components/PlMultiSequenceAlignment/multi-sequence-alignment.d.ts.map +1 -1
- package/dist/src/components/PlMultiSequenceAlignment/types.d.ts +0 -4
- package/dist/src/components/PlMultiSequenceAlignment/types.d.ts.map +1 -1
- package/dist/tsconfig.lib.tsbuildinfo +1 -1
- package/package.json +7 -7
- package/src/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue +30 -37
- package/src/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue +68 -20
- package/src/components/PlMultiSequenceAlignment/Toolbar.vue +5 -5
- package/src/components/PlMultiSequenceAlignment/data.ts +140 -146
- package/src/components/PlMultiSequenceAlignment/migrations.ts +41 -0
- package/src/components/PlMultiSequenceAlignment/multi-sequence-alignment.ts +3 -14
- package/src/components/PlMultiSequenceAlignment/types.ts +0 -5
|
@@ -1,9 +1,6 @@
|
|
|
1
|
-
import
|
|
2
|
-
import type {
|
|
3
|
-
JoinEntry,
|
|
4
|
-
} from '@platforma-sdk/model';
|
|
1
|
+
import { isJsonEqual } from '@milaboratories/helpers';
|
|
2
|
+
import type { ListOptionNormalized } from '@milaboratories/uikit';
|
|
5
3
|
import {
|
|
6
|
-
type AxisId,
|
|
7
4
|
type CalculateTableDataRequest,
|
|
8
5
|
type CanonicalizedJson,
|
|
9
6
|
canonicalizeJson,
|
|
@@ -11,6 +8,7 @@ import {
|
|
|
11
8
|
getAxisId,
|
|
12
9
|
getRawPlatformaInstance,
|
|
13
10
|
isLabelColumn,
|
|
11
|
+
type JoinEntry,
|
|
14
12
|
matchAxisId,
|
|
15
13
|
parseJson,
|
|
16
14
|
type PColumnIdAndSpec,
|
|
@@ -18,20 +16,19 @@ import {
|
|
|
18
16
|
type PFrameHandle,
|
|
19
17
|
type PlSelectionModel,
|
|
20
18
|
type PObjectId,
|
|
21
|
-
type
|
|
22
|
-
type PTableColumnIdColumn,
|
|
23
|
-
type PTableColumnIdJson,
|
|
19
|
+
type PTableColumnId,
|
|
24
20
|
pTableValue,
|
|
25
|
-
stringifyPTableColumnId,
|
|
26
21
|
} from '@platforma-sdk/model';
|
|
27
22
|
import { computedAsync } from '@vueuse/core';
|
|
28
|
-
import { type MaybeRefOrGetter, toValue } from 'vue';
|
|
29
|
-
import
|
|
23
|
+
import { type MaybeRefOrGetter, ref, toValue } from 'vue';
|
|
24
|
+
import { multiSequenceAlignment } from './multi-sequence-alignment';
|
|
30
25
|
|
|
31
26
|
const getPFrameDriver = () => getRawPlatformaInstance().pFrameDriver;
|
|
32
27
|
|
|
33
28
|
const getEmptyOptions = () => ({ defaults: [], options: [] });
|
|
34
29
|
|
|
30
|
+
export const sequenceLimit = 1000;
|
|
31
|
+
|
|
35
32
|
export function useSequenceColumnsOptions(
|
|
36
33
|
params: MaybeRefOrGetter<{
|
|
37
34
|
pFrame: PFrameHandle | undefined;
|
|
@@ -41,7 +38,12 @@ export function useSequenceColumnsOptions(
|
|
|
41
38
|
const result = computedAsync(
|
|
42
39
|
() => getSequenceColumnsOptions(toValue(params)),
|
|
43
40
|
getEmptyOptions(),
|
|
44
|
-
{
|
|
41
|
+
{
|
|
42
|
+
onError: (error) => {
|
|
43
|
+
console.error(error);
|
|
44
|
+
result.value = getEmptyOptions();
|
|
45
|
+
},
|
|
46
|
+
},
|
|
45
47
|
);
|
|
46
48
|
return result;
|
|
47
49
|
}
|
|
@@ -58,26 +60,38 @@ export function useLabelColumnsOptions(
|
|
|
58
60
|
const result = computedAsync(
|
|
59
61
|
() => getLabelColumnsOptions(toValue(params)),
|
|
60
62
|
getEmptyOptions(),
|
|
61
|
-
{
|
|
63
|
+
{
|
|
64
|
+
onError: (error) => {
|
|
65
|
+
console.error(error);
|
|
66
|
+
result.value = getEmptyOptions();
|
|
67
|
+
},
|
|
68
|
+
},
|
|
62
69
|
);
|
|
63
70
|
return result;
|
|
64
71
|
}
|
|
65
72
|
|
|
66
|
-
export function
|
|
73
|
+
export function useMultipleAlignmentData(
|
|
67
74
|
params: MaybeRefOrGetter<{
|
|
68
75
|
pframe: PFrameHandle | undefined;
|
|
69
76
|
sequenceColumnIds: PObjectId[];
|
|
70
|
-
labelColumnIds:
|
|
77
|
+
labelColumnIds: PTableColumnId[];
|
|
71
78
|
linkerColumnPredicate: PColumnPredicate | undefined;
|
|
72
79
|
selection: PlSelectionModel | undefined;
|
|
73
80
|
}>,
|
|
74
81
|
) {
|
|
82
|
+
const loading = ref(true);
|
|
75
83
|
const result = computedAsync(
|
|
76
|
-
() =>
|
|
77
|
-
[],
|
|
78
|
-
{
|
|
84
|
+
() => getMultipleAlignmentData(toValue(params)),
|
|
85
|
+
{ sequences: [], labels: [] },
|
|
86
|
+
{
|
|
87
|
+
onError: (error) => {
|
|
88
|
+
console.error(error);
|
|
89
|
+
result.value = { sequences: [], labels: [] };
|
|
90
|
+
},
|
|
91
|
+
evaluating: loading,
|
|
92
|
+
},
|
|
79
93
|
);
|
|
80
|
-
return result;
|
|
94
|
+
return { data: result, loading };
|
|
81
95
|
}
|
|
82
96
|
|
|
83
97
|
async function getSequenceColumnsOptions({
|
|
@@ -87,7 +101,7 @@ async function getSequenceColumnsOptions({
|
|
|
87
101
|
pFrame: PFrameHandle | undefined;
|
|
88
102
|
sequenceColumnPredicate: (column: PColumnIdAndSpec) => boolean;
|
|
89
103
|
}): Promise<{
|
|
90
|
-
options:
|
|
104
|
+
options: ListOptionNormalized<PObjectId>[];
|
|
91
105
|
defaults: PObjectId[];
|
|
92
106
|
}> {
|
|
93
107
|
if (!pFrame) return getEmptyOptions();
|
|
@@ -103,85 +117,84 @@ async function getSequenceColumnsOptions({
|
|
|
103
117
|
return { options, defaults };
|
|
104
118
|
}
|
|
105
119
|
|
|
106
|
-
async function getLabelColumnsOptions(
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
options: ListOption<PTableColumnIdJson>[];
|
|
120
|
-
defaults: PTableColumnIdJson[];
|
|
120
|
+
async function getLabelColumnsOptions({
|
|
121
|
+
pFrame,
|
|
122
|
+
sequenceColumnIds,
|
|
123
|
+
labelColumnOptionPredicate,
|
|
124
|
+
}: {
|
|
125
|
+
pFrame: PFrameHandle | undefined;
|
|
126
|
+
sequenceColumnIds: PObjectId[];
|
|
127
|
+
labelColumnOptionPredicate:
|
|
128
|
+
| ((column: PColumnIdAndSpec) => boolean)
|
|
129
|
+
| undefined;
|
|
130
|
+
}): Promise<{
|
|
131
|
+
options: ListOptionNormalized<PTableColumnId>[];
|
|
132
|
+
defaults: PTableColumnId[];
|
|
121
133
|
}> {
|
|
122
134
|
if (!pFrame) return getEmptyOptions();
|
|
123
|
-
const processedAxes = new Set<CanonicalizedJson<AxisId>>();
|
|
124
|
-
const optionLabels = new Map<PTableColumnIdJson, string>();
|
|
125
135
|
const pFrameDriver = getPFrameDriver();
|
|
126
136
|
const columns = await pFrameDriver.listColumns(pFrame);
|
|
137
|
+
const optionMap = new Map<CanonicalizedJson<PTableColumnId>, string>();
|
|
127
138
|
for (const column of columns) {
|
|
128
139
|
if (sequenceColumnIds.includes(column.columnId)) {
|
|
129
140
|
for (const axisSpec of column.spec.axesSpec) {
|
|
130
141
|
const axisId = getAxisId(axisSpec);
|
|
131
|
-
const
|
|
132
|
-
if (
|
|
133
|
-
processedAxes.add(canonicalizedAxisId);
|
|
142
|
+
const axisIdJson = canonicalizeJson({ type: 'axis', id: axisId });
|
|
143
|
+
if (optionMap.has(axisIdJson)) continue;
|
|
134
144
|
const labelColumn = columns.find(
|
|
135
145
|
({ spec }) =>
|
|
136
146
|
isLabelColumn(spec)
|
|
137
147
|
&& matchAxisId(axisId, getAxisId(spec.axesSpec[0])),
|
|
138
148
|
);
|
|
139
|
-
|
|
149
|
+
optionMap.set(
|
|
140
150
|
labelColumn
|
|
141
151
|
? canonicalizeJson({ type: 'column', id: labelColumn.columnId })
|
|
142
|
-
:
|
|
152
|
+
: axisIdJson,
|
|
143
153
|
axisSpec.annotations?.['pl7.app/label'] ?? 'Unlabelled axis',
|
|
144
154
|
);
|
|
145
155
|
}
|
|
146
156
|
}
|
|
147
157
|
if (labelColumnOptionPredicate?.(column)) {
|
|
148
|
-
|
|
158
|
+
optionMap.set(
|
|
149
159
|
canonicalizeJson({ type: 'column', id: column.columnId }),
|
|
150
160
|
column.spec.annotations?.['pl7.app/label'] ?? 'Unlabelled column',
|
|
151
161
|
);
|
|
152
162
|
}
|
|
153
163
|
}
|
|
154
|
-
const options = Array.from(
|
|
155
|
-
([value, label]) => ({ label, value }),
|
|
164
|
+
const options = Array.from(optionMap).map(
|
|
165
|
+
([value, label]) => ({ label, value: parseJson(value) }),
|
|
156
166
|
);
|
|
157
167
|
const defaults = options
|
|
158
|
-
.filter((
|
|
159
|
-
const value = parseJson(option.value);
|
|
168
|
+
.filter(({ value }) => {
|
|
160
169
|
if (value.type === 'axis') return true;
|
|
161
|
-
|
|
162
|
-
const column = columns.find((c) => c.columnId === value.id);
|
|
170
|
+
const column = columns.find(({ columnId }) => columnId === value.id);
|
|
163
171
|
return column && isLabelColumn(column.spec);
|
|
164
172
|
})
|
|
165
|
-
.map((
|
|
173
|
+
.map(({ value }) => value);
|
|
166
174
|
return { options, defaults };
|
|
167
175
|
}
|
|
168
176
|
|
|
169
|
-
async function
|
|
177
|
+
async function getMultipleAlignmentData(
|
|
170
178
|
{
|
|
171
179
|
pframe,
|
|
172
180
|
sequenceColumnIds,
|
|
173
181
|
labelColumnIds,
|
|
174
182
|
linkerColumnPredicate,
|
|
175
|
-
selection
|
|
183
|
+
selection,
|
|
176
184
|
}: {
|
|
177
185
|
pframe: PFrameHandle | undefined;
|
|
178
186
|
sequenceColumnIds: PObjectId[];
|
|
179
|
-
labelColumnIds:
|
|
187
|
+
labelColumnIds: PTableColumnId[];
|
|
180
188
|
linkerColumnPredicate: PColumnPredicate | undefined;
|
|
181
189
|
selection: PlSelectionModel | undefined;
|
|
182
190
|
},
|
|
183
|
-
): Promise<
|
|
184
|
-
|
|
191
|
+
): Promise<{
|
|
192
|
+
sequences: string[][];
|
|
193
|
+
labels: string[][];
|
|
194
|
+
}> {
|
|
195
|
+
if (!pframe || sequenceColumnIds.length === 0) {
|
|
196
|
+
return { sequences: [], labels: [] };
|
|
197
|
+
}
|
|
185
198
|
|
|
186
199
|
const pFrameDriver = getPFrameDriver();
|
|
187
200
|
const columns = await pFrameDriver.listColumns(pframe);
|
|
@@ -189,18 +202,14 @@ async function getSequenceRows(
|
|
|
189
202
|
? columns.filter((c) => linkerColumnPredicate(c))
|
|
190
203
|
: [];
|
|
191
204
|
|
|
192
|
-
const
|
|
193
|
-
const filterColumn = createRowSelectionColumn(
|
|
194
|
-
FilterColumnId,
|
|
195
|
-
rowSelectionModel,
|
|
196
|
-
);
|
|
205
|
+
const filterColumn = createRowSelectionColumn({ selection });
|
|
197
206
|
|
|
198
207
|
// inner join of sequence columns
|
|
199
208
|
let primaryEntry: JoinEntry<PObjectId> = {
|
|
200
209
|
type: 'inner',
|
|
201
|
-
entries: sequenceColumnIds.map((
|
|
202
|
-
type: 'column'
|
|
203
|
-
column
|
|
210
|
+
entries: sequenceColumnIds.map((column) => ({
|
|
211
|
+
type: 'column',
|
|
212
|
+
column,
|
|
204
213
|
})),
|
|
205
214
|
};
|
|
206
215
|
|
|
@@ -209,127 +218,112 @@ async function getSequenceRows(
|
|
|
209
218
|
primaryEntry = {
|
|
210
219
|
type: 'outer',
|
|
211
220
|
primary: primaryEntry,
|
|
212
|
-
secondary: linkerColumns.map((
|
|
213
|
-
type: 'column'
|
|
214
|
-
column:
|
|
221
|
+
secondary: linkerColumns.map(({ columnId }) => ({
|
|
222
|
+
type: 'column',
|
|
223
|
+
column: columnId,
|
|
215
224
|
})),
|
|
216
225
|
};
|
|
217
226
|
}
|
|
218
227
|
|
|
219
228
|
// inner join with filters
|
|
220
|
-
if (filterColumn
|
|
229
|
+
if (filterColumn) {
|
|
221
230
|
primaryEntry = {
|
|
222
231
|
type: 'inner',
|
|
223
232
|
entries: [
|
|
224
233
|
primaryEntry,
|
|
225
234
|
{
|
|
226
|
-
type: 'inlineColumn'
|
|
235
|
+
type: 'inlineColumn',
|
|
227
236
|
column: filterColumn,
|
|
228
237
|
},
|
|
229
238
|
],
|
|
230
239
|
};
|
|
231
240
|
}
|
|
232
241
|
|
|
242
|
+
const secondaryEntry: JoinEntry<PObjectId>[] = labelColumnIds
|
|
243
|
+
.flatMap((column) => {
|
|
244
|
+
if (column.type !== 'column') return [];
|
|
245
|
+
return { type: 'column', column: column.id };
|
|
246
|
+
});
|
|
247
|
+
|
|
233
248
|
// left join with labels
|
|
234
|
-
const
|
|
249
|
+
const request: CalculateTableDataRequest<PObjectId> = {
|
|
235
250
|
src: {
|
|
236
251
|
type: 'outer',
|
|
237
252
|
primary: primaryEntry,
|
|
238
|
-
secondary:
|
|
239
|
-
...labelColumnIds.map((c) => parseJson(c))
|
|
240
|
-
.filter((c) => c.type === 'column')
|
|
241
|
-
.map((c) => c.id),
|
|
242
|
-
].map((c) => ({
|
|
243
|
-
type: 'column',
|
|
244
|
-
column: c,
|
|
245
|
-
})),
|
|
253
|
+
secondary: secondaryEntry,
|
|
246
254
|
},
|
|
247
255
|
filters: [],
|
|
248
|
-
sorting: sequenceColumnIds.map((
|
|
256
|
+
sorting: sequenceColumnIds.map((id) => ({
|
|
249
257
|
column: {
|
|
250
258
|
type: 'column',
|
|
251
|
-
id
|
|
259
|
+
id,
|
|
252
260
|
},
|
|
253
261
|
ascending: true,
|
|
254
262
|
naAndAbsentAreLeastValues: true,
|
|
255
263
|
})),
|
|
256
264
|
};
|
|
257
265
|
|
|
258
|
-
const
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
const spec = table[i].spec;
|
|
266
|
+
const table = await pFrameDriver.calculateTableData(
|
|
267
|
+
pframe,
|
|
268
|
+
JSON.parse(JSON.stringify(request)),
|
|
269
|
+
{
|
|
270
|
+
offset: 0,
|
|
271
|
+
length: sequenceLimit,
|
|
272
|
+
},
|
|
273
|
+
);
|
|
267
274
|
|
|
268
|
-
|
|
269
|
-
if (spec.id === FilterColumnId) continue;
|
|
275
|
+
const rowCount = table?.[0].data.data.length ?? 0;
|
|
270
276
|
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
277
|
+
const sequenceColumns = sequenceColumnIds.map((columnId) => {
|
|
278
|
+
const column = table.find(({ spec }) => spec.id === columnId);
|
|
279
|
+
if (!column) {
|
|
280
|
+
throw new Error(
|
|
281
|
+
`Can't find a sequence column (ID: \`${columnId}\`) in the calculateTableData output.`,
|
|
282
|
+
);
|
|
276
283
|
}
|
|
284
|
+
return column;
|
|
285
|
+
});
|
|
277
286
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
labelColumnsMap.set(i, labelIndex);
|
|
287
|
+
const labelColumns = labelColumnIds.map((labelColumn) => {
|
|
288
|
+
const column = table.find(({ spec }) => {
|
|
289
|
+
if (labelColumn.type === 'axis' && spec.type === 'axis') {
|
|
290
|
+
return isJsonEqual(labelColumn.id, spec.id);
|
|
291
|
+
}
|
|
292
|
+
if (labelColumn.type === 'column' && spec.type === 'column') {
|
|
293
|
+
return labelColumn.id === spec.id;
|
|
294
|
+
}
|
|
295
|
+
});
|
|
296
|
+
if (!column) {
|
|
297
|
+
throw new Error(
|
|
298
|
+
`Can't find a label column (ID: \`${labelColumn}\`) in the calculateTableData output.`,
|
|
299
|
+
);
|
|
292
300
|
}
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
labelColumnsMap.size !== labelColumnIds.length
|
|
296
|
-
|| sequenceColumnsMap.size !== sequenceColumnIds.length
|
|
297
|
-
) {
|
|
298
|
-
throw new Error('Some label or sequence columns are missing');
|
|
299
|
-
}
|
|
301
|
+
return column;
|
|
302
|
+
});
|
|
300
303
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
304
|
+
const alignedSequences = await Promise.all(
|
|
305
|
+
sequenceColumns.map((column) =>
|
|
306
|
+
multiSequenceAlignment(Array.from(
|
|
307
|
+
{ length: rowCount },
|
|
308
|
+
(_, row) =>
|
|
309
|
+
pTableValue(column.data, row, { na: '', absent: '' })?.toString()
|
|
310
|
+
?? '',
|
|
311
|
+
)),
|
|
312
|
+
),
|
|
305
313
|
);
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
314
|
+
|
|
315
|
+
const sequences = Array.from(
|
|
316
|
+
{ length: rowCount },
|
|
317
|
+
(_, row) => alignedSequences.map((column) => column[row]),
|
|
309
318
|
);
|
|
310
319
|
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
);
|
|
320
|
+
const labels = Array.from(
|
|
321
|
+
{ length: rowCount },
|
|
322
|
+
(_, row) =>
|
|
323
|
+
labelColumns.map((column) =>
|
|
324
|
+
pTableValue(column.data, row, { na: '', absent: '' })?.toString() ?? '',
|
|
325
|
+
),
|
|
326
|
+
);
|
|
319
327
|
|
|
320
|
-
|
|
321
|
-
if (labels.every(isValid) && sequences.every(isValid)) {
|
|
322
|
-
result.push({
|
|
323
|
-
labels,
|
|
324
|
-
sequence: sequences.join(''),
|
|
325
|
-
});
|
|
326
|
-
} else {
|
|
327
|
-
console.warn(
|
|
328
|
-
`skipping record at row ${iRow} because of invalid labels or sequences`,
|
|
329
|
-
labels,
|
|
330
|
-
sequences,
|
|
331
|
-
);
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
return result;
|
|
328
|
+
return { sequences, labels };
|
|
335
329
|
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type CanonicalizedJson,
|
|
3
|
+
parseJson,
|
|
4
|
+
type PlMultiSequenceAlignmentModel,
|
|
5
|
+
type PTableColumnId,
|
|
6
|
+
} from '@platforma-sdk/model';
|
|
7
|
+
import { type Ref } from 'vue';
|
|
8
|
+
|
|
9
|
+
const latestVersion = 1;
|
|
10
|
+
|
|
11
|
+
export function runMigrations(model: Ref<PlMultiSequenceAlignmentModel>) {
|
|
12
|
+
const currentVersion = getCurrentVersion(model.value);
|
|
13
|
+
try {
|
|
14
|
+
if (currentVersion < 1) {
|
|
15
|
+
const oldLabelColumnIds = model.value.labelColumnIds as unknown as
|
|
16
|
+
| CanonicalizedJson<PTableColumnId>[]
|
|
17
|
+
| undefined;
|
|
18
|
+
if (oldLabelColumnIds) {
|
|
19
|
+
model.value.labelColumnIds = oldLabelColumnIds
|
|
20
|
+
.map((id) => parseJson(id));
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
} catch (error) {
|
|
24
|
+
console.error(error);
|
|
25
|
+
model.value = {};
|
|
26
|
+
} finally {
|
|
27
|
+
model.value.version = latestVersion;
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* If a model has a version, return it.
|
|
33
|
+
* If it doesn't, but contains anything at all, that's version 0,
|
|
34
|
+
* which is a pre-versioning version.
|
|
35
|
+
* Otherwise, emtpy model is treated as the latest model.
|
|
36
|
+
*/
|
|
37
|
+
function getCurrentVersion(model: PlMultiSequenceAlignmentModel) {
|
|
38
|
+
if (model.version !== undefined) return model.version;
|
|
39
|
+
if (Object.keys(model).length) return 0;
|
|
40
|
+
return latestVersion;
|
|
41
|
+
}
|
|
@@ -1,20 +1,7 @@
|
|
|
1
|
-
/* eslint-disable @stylistic/indent */
|
|
2
1
|
import Aioli from '@milaboratories/biowasm-tools';
|
|
3
|
-
import { computedAsync, type MaybeRefOrGetter } from '@vueuse/core';
|
|
4
|
-
import { ref, toValue } from 'vue';
|
|
5
2
|
|
|
6
3
|
const cache = new Map<string, string[]>();
|
|
7
4
|
|
|
8
|
-
export function useAlignedSequences(sequences: MaybeRefOrGetter<string[]>) {
|
|
9
|
-
const loading = ref(false);
|
|
10
|
-
const data = computedAsync(
|
|
11
|
-
() => multiSequenceAlignment(toValue(sequences)),
|
|
12
|
-
[],
|
|
13
|
-
{ onError: () => (data.value = []), evaluating: loading },
|
|
14
|
-
);
|
|
15
|
-
return { data, loading };
|
|
16
|
-
}
|
|
17
|
-
|
|
18
5
|
export async function multiSequenceAlignment(
|
|
19
6
|
sequences: string[],
|
|
20
7
|
): Promise<string[]> {
|
|
@@ -29,7 +16,9 @@ export async function multiSequenceAlignment(
|
|
|
29
16
|
'input',
|
|
30
17
|
);
|
|
31
18
|
await CLI.mount(file);
|
|
32
|
-
await CLI.exec(
|
|
19
|
+
await CLI.exec(
|
|
20
|
+
'kalign -f fasta -i /shared/data/input -o /shared/data/output',
|
|
21
|
+
);
|
|
33
22
|
const output = await CLI.cat('/shared/data/output');
|
|
34
23
|
result = parseKalignOutput(output);
|
|
35
24
|
cache.set(inputHash, result);
|