@platforma-sdk/ui-vue 1.45.35 → 1.45.37

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.
Files changed (180) hide show
  1. package/.turbo/turbo-build.log +204 -235
  2. package/.turbo/turbo-type-check.log +1 -1
  3. package/CHANGELOG.md +13 -0
  4. package/dist/AgGridVue/useAgGridOptions.js +2 -3
  5. package/dist/AgGridVue/useAgGridOptions.js.map +1 -1
  6. package/dist/components/BlockLayout.vue2.js +3 -3
  7. package/dist/components/BlockLayout.vue2.js.map +1 -1
  8. package/dist/components/BlockLoader.vue.js.map +1 -1
  9. package/dist/components/LoaderPage.vue.js +2 -2
  10. package/dist/components/LoaderPage.vue.js.map +1 -1
  11. package/dist/components/NotFound.vue.js +3 -3
  12. package/dist/components/NotFound.vue.js.map +1 -1
  13. package/dist/components/PlAdvancedFilter/OperandButton.vue2.js.map +1 -1
  14. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js +73 -73
  15. package/dist/components/PlAdvancedFilter/PlAdvancedFilter.vue2.js.map +1 -1
  16. package/dist/components/PlAdvancedFilter/SingleFilter.vue2.js +100 -100
  17. package/dist/components/PlAdvancedFilter/SingleFilter.vue2.js.map +1 -1
  18. package/dist/components/PlAgCellFile/PlAgCellFile.vue.js.map +1 -1
  19. package/dist/components/PlAgCellProgress/PlAgCellProgress.vue.js.map +1 -1
  20. package/dist/components/PlAgCellStatusTag/PlAgCellStatusTag.vue.js +6 -6
  21. package/dist/components/PlAgCellStatusTag/PlAgCellStatusTag.vue.js.map +1 -1
  22. package/dist/components/PlAgChartHistogramCell/PlAgChartHistogramCell.vue.js.map +1 -1
  23. package/dist/components/PlAgChartStackedBarCell/PlAgChartStackedBarCell.vue.js.map +1 -1
  24. package/dist/components/PlAgColumnHeader/PlAgColumnHeader.vue.js +22 -22
  25. package/dist/components/PlAgColumnHeader/PlAgColumnHeader.vue.js.map +1 -1
  26. package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue.js +3 -3
  27. package/dist/components/PlAgCsvExporter/PlAgCsvExporter.vue.js.map +1 -1
  28. package/dist/components/PlAgDataTable/PlAgDataTableSheets.vue2.js.map +1 -1
  29. package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js +50 -50
  30. package/dist/components/PlAgDataTable/PlAgDataTableV2.vue2.js.map +1 -1
  31. package/dist/components/PlAgDataTable/PlAgOverlayLoading.vue.js.map +1 -1
  32. package/dist/components/PlAgDataTable/PlAgOverlayNoRows.vue.js.map +1 -1
  33. package/dist/components/PlAgDataTable/PlAgRowCount.vue.js +7 -8
  34. package/dist/components/PlAgDataTable/PlAgRowCount.vue.js.map +1 -1
  35. package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue2.js +35 -35
  36. package/dist/components/PlAgGridColumnManager/PlAgGridColumnManager.vue2.js.map +1 -1
  37. package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue.js +16 -17
  38. package/dist/components/PlAgRowNumCheckbox/PlAgRowNumCheckbox.vue.js.map +1 -1
  39. package/dist/components/PlAgRowNumHeader.vue.js +14 -15
  40. package/dist/components/PlAgRowNumHeader.vue.js.map +1 -1
  41. package/dist/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.vue.js +16 -16
  42. package/dist/components/PlAgTextAndButtonCell/PlAgTextAndButtonCell.vue.js.map +1 -1
  43. package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue2.js +6 -6
  44. package/dist/components/PlAnnotations/components/AnnotationsSidebar.vue2.js.map +1 -1
  45. package/dist/components/PlAnnotations/components/DynamicForm.vue2.js +57 -57
  46. package/dist/components/PlAnnotations/components/DynamicForm.vue2.js.map +1 -1
  47. package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js +6 -6
  48. package/dist/components/PlAnnotations/components/FilterSidebar.vue2.js.map +1 -1
  49. package/dist/components/PlAnnotations/components/PlAnnotations.vue2.js.map +1 -1
  50. package/dist/components/PlAnnotations/components/PlAnnotationsModal.vue2.js.map +1 -1
  51. package/dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue.js +7 -7
  52. package/dist/components/PlAppErrorNotificationAlert/PlAppErrorNotificationAlert.vue.js.map +1 -1
  53. package/dist/components/PlBtnExportArchive/Item.vue2.js +23 -23
  54. package/dist/components/PlBtnExportArchive/Item.vue2.js.map +1 -1
  55. package/dist/components/PlBtnExportArchive/PlBtnExportArchive.vue2.js.map +1 -1
  56. package/dist/components/PlBtnExportArchive/Summary.vue2.js +22 -22
  57. package/dist/components/PlBtnExportArchive/Summary.vue2.js.map +1 -1
  58. package/dist/components/PlTableFilters/PlTableAddFilterV2.vue.js +9 -9
  59. package/dist/components/PlTableFilters/PlTableAddFilterV2.vue.js.map +1 -1
  60. package/dist/components/PlTableFilters/PlTableFilterEntryV2.vue.js +3 -3
  61. package/dist/components/PlTableFilters/PlTableFilterEntryV2.vue.js.map +1 -1
  62. package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js +9 -9
  63. package/dist/components/PlTableFilters/PlTableFiltersV2.vue2.js.map +1 -1
  64. package/dist/components/ValueOrErrorsComponent.vue.js.map +1 -1
  65. package/dist/index.js +48 -50
  66. package/dist/index.js.map +1 -1
  67. package/dist/lib.d.ts +0 -1
  68. package/dist/plugins/Monetization/EndOfPeriod.vue2.js +9 -9
  69. package/dist/plugins/Monetization/EndOfPeriod.vue2.js.map +1 -1
  70. package/dist/plugins/Monetization/LimitCard.vue2.js +40 -40
  71. package/dist/plugins/Monetization/LimitCard.vue2.js.map +1 -1
  72. package/dist/plugins/Monetization/MonetizationSidebar.vue.js +3 -3
  73. package/dist/plugins/Monetization/MonetizationSidebar.vue.js.map +1 -1
  74. package/dist/plugins/Monetization/RunStatus.vue2.js +12 -12
  75. package/dist/plugins/Monetization/RunStatus.vue2.js.map +1 -1
  76. package/dist/plugins/Monetization/UserCabinetCard.vue2.js +22 -22
  77. package/dist/plugins/Monetization/UserCabinetCard.vue2.js.map +1 -1
  78. package/package.json +7 -8
  79. package/src/lib.ts +0 -2
  80. package/dist/assets/multi-sequence-alignment.worker-Cm0gZp19.js +0 -6
  81. package/dist/assets/multi-sequence-alignment.worker-Cm0gZp19.js.map +0 -1
  82. package/dist/assets/phylogenetic-tree.worker-4CrExYEo.js +0 -5
  83. package/dist/assets/phylogenetic-tree.worker-4CrExYEo.js.map +0 -1
  84. package/dist/components/PlMultiSequenceAlignment/Consensus.vue.d.ts +0 -9
  85. package/dist/components/PlMultiSequenceAlignment/Consensus.vue.js +0 -10
  86. package/dist/components/PlMultiSequenceAlignment/Consensus.vue.js.map +0 -1
  87. package/dist/components/PlMultiSequenceAlignment/Consensus.vue2.js +0 -122
  88. package/dist/components/PlMultiSequenceAlignment/Consensus.vue2.js.map +0 -1
  89. package/dist/components/PlMultiSequenceAlignment/Consensus.vue3.js +0 -9
  90. package/dist/components/PlMultiSequenceAlignment/Consensus.vue3.js.map +0 -1
  91. package/dist/components/PlMultiSequenceAlignment/Legend.vue.d.ts +0 -6
  92. package/dist/components/PlMultiSequenceAlignment/Legend.vue.js +0 -10
  93. package/dist/components/PlMultiSequenceAlignment/Legend.vue.js.map +0 -1
  94. package/dist/components/PlMultiSequenceAlignment/Legend.vue2.js +0 -28
  95. package/dist/components/PlMultiSequenceAlignment/Legend.vue2.js.map +0 -1
  96. package/dist/components/PlMultiSequenceAlignment/Legend.vue3.js +0 -13
  97. package/dist/components/PlMultiSequenceAlignment/Legend.vue3.js.map +0 -1
  98. package/dist/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue.d.ts +0 -25
  99. package/dist/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue.js +0 -10
  100. package/dist/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue.js.map +0 -1
  101. package/dist/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue2.js +0 -138
  102. package/dist/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue2.js.map +0 -1
  103. package/dist/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue3.js +0 -31
  104. package/dist/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue3.js.map +0 -1
  105. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue.d.ts +0 -8
  106. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue.js +0 -10
  107. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue.js.map +0 -1
  108. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue2.js +0 -77
  109. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue2.js.map +0 -1
  110. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue3.js +0 -9
  111. package/dist/components/PlMultiSequenceAlignment/PhylogeneticTree.vue3.js.map +0 -1
  112. package/dist/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue.d.ts +0 -71
  113. package/dist/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue.js +0 -10
  114. package/dist/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue.js.map +0 -1
  115. package/dist/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue2.js +0 -224
  116. package/dist/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue2.js.map +0 -1
  117. package/dist/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue3.js +0 -9
  118. package/dist/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue3.js.map +0 -1
  119. package/dist/components/PlMultiSequenceAlignment/SeqLogo.vue.d.ts +0 -8
  120. package/dist/components/PlMultiSequenceAlignment/SeqLogo.vue.js +0 -10
  121. package/dist/components/PlMultiSequenceAlignment/SeqLogo.vue.js.map +0 -1
  122. package/dist/components/PlMultiSequenceAlignment/SeqLogo.vue2.js +0 -127
  123. package/dist/components/PlMultiSequenceAlignment/SeqLogo.vue2.js.map +0 -1
  124. package/dist/components/PlMultiSequenceAlignment/SeqLogo.vue3.js +0 -9
  125. package/dist/components/PlMultiSequenceAlignment/SeqLogo.vue3.js.map +0 -1
  126. package/dist/components/PlMultiSequenceAlignment/Toolbar.vue.d.ts +0 -16
  127. package/dist/components/PlMultiSequenceAlignment/Toolbar.vue.js +0 -10
  128. package/dist/components/PlMultiSequenceAlignment/Toolbar.vue.js.map +0 -1
  129. package/dist/components/PlMultiSequenceAlignment/Toolbar.vue2.js +0 -228
  130. package/dist/components/PlMultiSequenceAlignment/Toolbar.vue2.js.map +0 -1
  131. package/dist/components/PlMultiSequenceAlignment/Toolbar.vue3.js +0 -19
  132. package/dist/components/PlMultiSequenceAlignment/Toolbar.vue3.js.map +0 -1
  133. package/dist/components/PlMultiSequenceAlignment/cell-size.d.ts +0 -4
  134. package/dist/components/PlMultiSequenceAlignment/cell-size.js +0 -8
  135. package/dist/components/PlMultiSequenceAlignment/cell-size.js.map +0 -1
  136. package/dist/components/PlMultiSequenceAlignment/chemical-properties.d.ts +0 -44
  137. package/dist/components/PlMultiSequenceAlignment/chemical-properties.js +0 -132
  138. package/dist/components/PlMultiSequenceAlignment/chemical-properties.js.map +0 -1
  139. package/dist/components/PlMultiSequenceAlignment/data.d.ts +0 -61
  140. package/dist/components/PlMultiSequenceAlignment/data.js +0 -370
  141. package/dist/components/PlMultiSequenceAlignment/data.js.map +0 -1
  142. package/dist/components/PlMultiSequenceAlignment/index.d.ts +0 -1
  143. package/dist/components/PlMultiSequenceAlignment/markup.d.ts +0 -16
  144. package/dist/components/PlMultiSequenceAlignment/markup.js +0 -84
  145. package/dist/components/PlMultiSequenceAlignment/markup.js.map +0 -1
  146. package/dist/components/PlMultiSequenceAlignment/migrations.d.ts +0 -3
  147. package/dist/components/PlMultiSequenceAlignment/migrations.js +0 -24
  148. package/dist/components/PlMultiSequenceAlignment/migrations.js.map +0 -1
  149. package/dist/components/PlMultiSequenceAlignment/multi-sequence-alignment.worker.d.ts +0 -6
  150. package/dist/components/PlMultiSequenceAlignment/phylogenetic-tree.worker.d.ts +0 -7
  151. package/dist/components/PlMultiSequenceAlignment/residue-counts.d.ts +0 -2
  152. package/dist/components/PlMultiSequenceAlignment/residue-counts.js +0 -13
  153. package/dist/components/PlMultiSequenceAlignment/residue-counts.js.map +0 -1
  154. package/dist/components/PlMultiSequenceAlignment/settings.d.ts +0 -2
  155. package/dist/components/PlMultiSequenceAlignment/settings.js +0 -9
  156. package/dist/components/PlMultiSequenceAlignment/settings.js.map +0 -1
  157. package/dist/components/PlMultiSequenceAlignment/types.d.ts +0 -5
  158. package/dist/components/PlMultiSequenceAlignment/useMiPlots.d.ts +0 -4
  159. package/dist/components/PlMultiSequenceAlignment/useMiPlots.js +0 -19
  160. package/dist/components/PlMultiSequenceAlignment/useMiPlots.js.map +0 -1
  161. package/src/components/PlMultiSequenceAlignment/Consensus.vue +0 -165
  162. package/src/components/PlMultiSequenceAlignment/Legend.vue +0 -44
  163. package/src/components/PlMultiSequenceAlignment/MultiSequenceAlignmentView.vue +0 -299
  164. package/src/components/PlMultiSequenceAlignment/PhylogeneticTree.vue +0 -110
  165. package/src/components/PlMultiSequenceAlignment/PlMultiSequenceAlignment.vue +0 -314
  166. package/src/components/PlMultiSequenceAlignment/README.md +0 -216
  167. package/src/components/PlMultiSequenceAlignment/SeqLogo.vue +0 -166
  168. package/src/components/PlMultiSequenceAlignment/Toolbar.vue +0 -228
  169. package/src/components/PlMultiSequenceAlignment/cell-size.ts +0 -4
  170. package/src/components/PlMultiSequenceAlignment/chemical-properties.ts +0 -199
  171. package/src/components/PlMultiSequenceAlignment/data.ts +0 -661
  172. package/src/components/PlMultiSequenceAlignment/index.ts +0 -1
  173. package/src/components/PlMultiSequenceAlignment/markup.ts +0 -141
  174. package/src/components/PlMultiSequenceAlignment/migrations.ts +0 -46
  175. package/src/components/PlMultiSequenceAlignment/multi-sequence-alignment.worker.ts +0 -54
  176. package/src/components/PlMultiSequenceAlignment/phylogenetic-tree.worker.ts +0 -89
  177. package/src/components/PlMultiSequenceAlignment/residue-counts.ts +0 -124
  178. package/src/components/PlMultiSequenceAlignment/settings.ts +0 -7
  179. package/src/components/PlMultiSequenceAlignment/types.ts +0 -3
  180. package/src/components/PlMultiSequenceAlignment/useMiPlots.ts +0 -23
@@ -1,661 +0,0 @@
1
- import { isJsonEqual } from '@milaboratories/helpers';
2
- import type { ListOptionNormalized } from '@milaboratories/uikit';
3
- import {
4
- Annotation,
5
- type CalculateTableDataRequest,
6
- type CalculateTableDataResponse,
7
- type CanonicalizedJson,
8
- canonicalizeJson,
9
- createRowSelectionColumn,
10
- ensureError,
11
- getAxisId,
12
- getRawPlatformaInstance,
13
- isLabelColumn,
14
- isLinkerColumn,
15
- type JoinEntry,
16
- matchAxisId,
17
- parseJson,
18
- type PColumnIdAndSpec,
19
- type PFrameHandle,
20
- type PlMultiSequenceAlignmentColorSchemeOption,
21
- type PlMultiSequenceAlignmentSettings,
22
- type PlSelectionModel,
23
- type PObjectId,
24
- type PTableColumnId,
25
- type PTableSorting,
26
- pTableValue,
27
- readAnnotation,
28
- readAnnotationJson,
29
- } from '@platforma-sdk/model';
30
- import { onWatcherCleanup, ref, watch } from 'vue';
31
- import { objectHash } from '../../objectHash';
32
- import { highlightByChemicalProperties } from './chemical-properties';
33
- import type { Markup } from './markup';
34
- import {
35
- highlightByMarkup,
36
- markupAlignedSequence,
37
- parseMarkup,
38
- } from './markup';
39
- import type * as MultiSequenceAlignmentWorker from './multi-sequence-alignment.worker';
40
- import type * as PhylogeneticTreeWorker from './phylogenetic-tree.worker';
41
- import { getResidueCounts } from './residue-counts';
42
- import type { HighlightLegend, ResidueCounts } from './types';
43
-
44
- const getPFrameDriver = () => getRawPlatformaInstance().pFrameDriver;
45
-
46
- export const SEQUENCE_LIMIT = 1000;
47
-
48
- export const useSequenceColumnsOptions = refreshOnDeepChange(
49
- getSequenceColumnsOptions,
50
- );
51
-
52
- export const useLabelColumnsOptions = refreshOnDeepChange(
53
- getLabelColumnsOptions,
54
- );
55
-
56
- export const useMarkupColumnsOptions = refreshOnDeepChange(
57
- getMarkupColumnsOptions,
58
- );
59
-
60
- export const useMultipleAlignmentData = refreshOnDeepChange(
61
- getMultipleAlignmentData,
62
- );
63
-
64
- async function getSequenceColumnsOptions({ pFrame, sequenceColumnPredicate }: {
65
- pFrame: PFrameHandle | undefined;
66
- sequenceColumnPredicate: (column: PColumnIdAndSpec) => boolean;
67
- }): Promise<OptionsWithDefaults<PObjectId> | undefined> {
68
- if (!pFrame) return;
69
-
70
- const pFrameDriver = getPFrameDriver();
71
- const columns = await pFrameDriver.listColumns(pFrame);
72
-
73
- const options = columns.values()
74
- .filter((column) => sequenceColumnPredicate(column))
75
- .map(({ spec, columnId }) => ({
76
- label: readAnnotation(spec, Annotation.Label) ?? 'Unlabeled column',
77
- value: columnId,
78
- }))
79
- .toArray();
80
-
81
- const defaults = options.map(({ value }) => value);
82
-
83
- return { options, defaults };
84
- }
85
-
86
- async function getLabelColumnsOptions({ pFrame, sequenceColumnIds }: {
87
- pFrame: PFrameHandle | undefined;
88
- sequenceColumnIds: PObjectId[] | undefined;
89
- }): Promise<OptionsWithDefaults<PTableColumnId> | undefined> {
90
- if (!pFrame || !sequenceColumnIds) return;
91
-
92
- const pFrameDriver = getPFrameDriver();
93
- const columns = await pFrameDriver.listColumns(pFrame);
94
-
95
- const sequenceColumnsAxes = new Map(
96
- sequenceColumnIds.values().flatMap((id) => {
97
- const column = columns.find(({ columnId }) => columnId === id);
98
- if (!column) {
99
- throw new Error(`Couldn't find sequence column (ID: \`${id}\`).`);
100
- }
101
- return column.spec.axesSpec.values()
102
- .map((spec) => [canonicalizeJson(getAxisId(spec)), spec]);
103
- }),
104
- );
105
-
106
- const optionMap = new Map<CanonicalizedJson<PTableColumnId>, string>();
107
- for (const [axisIdJson, axisSpec] of sequenceColumnsAxes.entries()) {
108
- const axisId = parseJson(axisIdJson);
109
- const labelColumn = columns.find(({ spec }) =>
110
- isLabelColumn(spec) && matchAxisId(axisId, getAxisId(spec.axesSpec[0])),
111
- );
112
- optionMap.set(
113
- labelColumn
114
- ? canonicalizeJson({ type: 'column', id: labelColumn.columnId })
115
- : canonicalizeJson({ type: 'axis', id: axisId }),
116
- readAnnotation(labelColumn?.spec, Annotation.Label)
117
- ?? readAnnotation(axisSpec, Annotation.Label)
118
- ?? 'Unlabeled axis',
119
- );
120
- }
121
-
122
- const { hits: compatibleColumns } = await pFrameDriver.findColumns(pFrame, {
123
- columnFilter: {},
124
- compatibleWith: sequenceColumnsAxes.keys()
125
- .map((axisIdJson) => parseJson(axisIdJson))
126
- .toArray(),
127
- strictlyCompatible: false,
128
- });
129
-
130
- for (const { columnId, spec } of compatibleColumns) {
131
- const columnIdJson = canonicalizeJson<PTableColumnId>({
132
- type: 'column',
133
- id: columnId,
134
- });
135
- if (optionMap.has(columnIdJson)) continue;
136
- optionMap.set(
137
- columnIdJson,
138
- readAnnotation(spec, Annotation.Label) ?? 'Unlabeled column',
139
- );
140
- }
141
-
142
- const options = optionMap.entries()
143
- .map(([value, label]) => ({ label, value: parseJson(value) }))
144
- .toArray();
145
-
146
- const defaults = options.values()
147
- .filter(({ value }) => {
148
- if (value.type === 'axis') return true;
149
- const column = columns.find(({ columnId }) => columnId === value.id);
150
- return column && isLabelColumn(column.spec);
151
- })
152
- .map(({ value }) => value)
153
- .toArray();
154
-
155
- return { options, defaults };
156
- }
157
-
158
- async function getMarkupColumnsOptions({ pFrame, sequenceColumnIds }: {
159
- pFrame: PFrameHandle | undefined;
160
- sequenceColumnIds: PObjectId[] | undefined;
161
- }): Promise<ListOptionNormalized<PObjectId[]>[] | undefined> {
162
- if (!pFrame || !sequenceColumnIds) return;
163
-
164
- const pFrameDriver = getPFrameDriver();
165
- const columns = await pFrameDriver.listColumns(pFrame);
166
-
167
- const sequenceColumns = sequenceColumnIds.map((columnId) => {
168
- const column = columns.find((column) => column.columnId === columnId);
169
- if (!column) {
170
- throw new Error(
171
- `Couldn't find sequence column (ID: \`${sequenceColumnIds[0]}\`).`,
172
- );
173
- }
174
- return column;
175
- });
176
-
177
- const columnPairs = sequenceColumns
178
- .flatMap((sequenceColumn) =>
179
- columns
180
- .filter((column) =>
181
- readAnnotationJson(column.spec, Annotation.Sequence.IsAnnotation)
182
- && isJsonEqual(sequenceColumn.spec.axesSpec, column.spec.axesSpec)
183
- && Object.entries(sequenceColumn.spec.domain ?? {})
184
- .every(([key, value]) => column.spec.domain?.[key] === value),
185
- )
186
- .map((markupColumn) => ({ markupColumn, sequenceColumn })),
187
- );
188
-
189
- const groupedByDomainDiff = Map.groupBy(
190
- columnPairs,
191
- ({ markupColumn, sequenceColumn }) => {
192
- const domainDiff = Object.fromEntries(
193
- Object.entries(markupColumn.spec.domain ?? {})
194
- .filter(([key]) => sequenceColumn.spec.domain?.[key] == undefined),
195
- );
196
- return canonicalizeJson(domainDiff);
197
- },
198
- );
199
-
200
- return groupedByDomainDiff.entries()
201
- .map(([domainDiffJson, columnPairs]) => ({
202
- label: Object.values(parseJson(domainDiffJson)).join(', '),
203
- value: columnPairs.map(({ markupColumn }) => markupColumn.columnId),
204
- }))
205
- .toArray();
206
- }
207
-
208
- async function getMultipleAlignmentData(
209
- {
210
- pFrame,
211
- sequenceColumnIds,
212
- labelColumnIds,
213
- selection,
214
- colorScheme,
215
- alignmentParams,
216
- shouldBuildPhylogeneticTree,
217
- }: {
218
- pFrame: PFrameHandle | undefined;
219
- sequenceColumnIds: PObjectId[] | undefined;
220
- labelColumnIds: PTableColumnId[] | undefined;
221
- selection: PlSelectionModel | undefined;
222
- colorScheme: PlMultiSequenceAlignmentColorSchemeOption;
223
- alignmentParams: PlMultiSequenceAlignmentSettings['alignmentParams'];
224
- shouldBuildPhylogeneticTree: boolean;
225
- },
226
- abortSignal: AbortSignal,
227
- ): Promise<MultipleAlignmentData | undefined> {
228
- if (!pFrame || !sequenceColumnIds?.length || !labelColumnIds) return;
229
-
230
- const table = await getTableData({
231
- pFrame,
232
- sequenceColumnIds,
233
- labelColumnIds,
234
- selection,
235
- colorScheme,
236
- });
237
-
238
- const rowCount = table.at(0)?.data.data.length ?? 0;
239
-
240
- if (rowCount < 2) return;
241
-
242
- const exceedsLimit = rowCount > SEQUENCE_LIMIT;
243
- const rawSequences = extractSequences(sequenceColumnIds, table);
244
- const labels = extractLabels(labelColumnIds, table);
245
- const markups = colorScheme.type === 'markup'
246
- ? extractMarkups(colorScheme.columnIds, table)
247
- : undefined;
248
-
249
- const highlightLegend: HighlightLegend = {};
250
-
251
- const alignedSequences = await Promise.all(
252
- rawSequences.map(async ({ name, rows }) => ({
253
- name,
254
- rows: await alignSequences(
255
- rows,
256
- JSON.parse(JSON.stringify(alignmentParams)),
257
- abortSignal,
258
- ),
259
- })),
260
- );
261
-
262
- let phylogeneticTree: PhylogeneticTreeWorker.TreeNodeData[] | undefined;
263
- if (shouldBuildPhylogeneticTree) {
264
- phylogeneticTree = await buildPhylogeneticTree(
265
- alignedSequences,
266
- abortSignal,
267
- );
268
- const rowOrder = phylogeneticTree.values()
269
- .filter(({ id }) => id >= 0)
270
- .map(({ id }) => id)
271
- .toArray();
272
- for (const sequencesColumn of alignedSequences) {
273
- sequencesColumn.rows = rowOrder.map((i) => sequencesColumn.rows[i]);
274
- }
275
- for (const labelsColumn of labels) {
276
- labelsColumn.rows = rowOrder.map((i) => labelsColumn.rows[i]);
277
- }
278
- for (const markupsColumn of markups ?? []) {
279
- markupsColumn.rows = rowOrder.map((i) => markupsColumn.rows[i]);
280
- }
281
- }
282
-
283
- const sequences = await Promise.all(
284
- alignedSequences.map(async ({ name, rows }, index) => {
285
- const residueCounts = getResidueCounts(rows);
286
- const image = generateHighlightImage({
287
- colorScheme,
288
- sequences: rows,
289
- residueCounts,
290
- markup: markups?.at(index),
291
- });
292
- if (image) {
293
- Object.assign(highlightLegend, image.legend);
294
- }
295
- return {
296
- name,
297
- rows,
298
- residueCounts,
299
- ...image && {
300
- highlightImageUrl: await blobToBase64(image.blob),
301
- },
302
- } satisfies MultipleAlignmentData['sequences'][number];
303
- }),
304
- );
305
-
306
- return {
307
- sequences,
308
- labels,
309
- ...Object.keys(highlightLegend).length && {
310
- highlightLegend,
311
- },
312
- ...phylogeneticTree && {
313
- phylogeneticTree,
314
- },
315
- exceedsLimit,
316
- };
317
- }
318
-
319
- async function getTableData(
320
- { pFrame, sequenceColumnIds, labelColumnIds, selection, colorScheme }: {
321
- pFrame: PFrameHandle;
322
- sequenceColumnIds: PObjectId[];
323
- labelColumnIds: PTableColumnId[];
324
- selection: PlSelectionModel | undefined;
325
- colorScheme: PlMultiSequenceAlignmentColorSchemeOption;
326
- },
327
- ): Promise<CalculateTableDataResponse> {
328
- const pFrameDriver = getPFrameDriver();
329
- const columns = await pFrameDriver.listColumns(pFrame);
330
- const linkerColumns = columns.filter((column) => isLinkerColumn(column.spec));
331
-
332
- const filterColumn = createRowSelectionColumn({ selection });
333
-
334
- // inner join of sequence columns
335
- let primaryEntry: JoinEntry<PObjectId> = {
336
- type: 'inner',
337
- entries: sequenceColumnIds.map((column) => ({
338
- type: 'column',
339
- column,
340
- })),
341
- };
342
-
343
- // if we have linkers, left join them
344
- if (linkerColumns.length > 0) {
345
- primaryEntry = {
346
- type: 'outer',
347
- primary: primaryEntry,
348
- secondary: linkerColumns.map(({ columnId }) => ({
349
- type: 'column',
350
- column: columnId,
351
- })),
352
- };
353
- }
354
-
355
- // inner join with filters
356
- if (filterColumn) {
357
- primaryEntry = {
358
- type: 'inner',
359
- entries: [
360
- primaryEntry,
361
- {
362
- type: 'inlineColumn',
363
- column: filterColumn,
364
- },
365
- ],
366
- };
367
- }
368
-
369
- // left join with labels
370
- const secondaryEntry: JoinEntry<PObjectId>[] = labelColumnIds
371
- .flatMap((column) => {
372
- if (column.type !== 'column') return [];
373
- return { type: 'column', column: column.id };
374
- });
375
-
376
- // and markup
377
- if (colorScheme.type === 'markup') {
378
- for (const column of colorScheme.columnIds) {
379
- secondaryEntry.push({ type: 'column', column });
380
- }
381
- }
382
-
383
- const sorting: PTableSorting[] = Array.from(
384
- new Set(
385
- sequenceColumnIds.values().flatMap((id) => {
386
- const column = columns.find(({ columnId }) => columnId === id);
387
- if (!column) {
388
- throw new Error(`Couldn't find sequence column (ID: ${id})`);
389
- }
390
- return column.spec.axesSpec
391
- .map((spec) => canonicalizeJson(getAxisId(spec)));
392
- }),
393
- ),
394
- )
395
- .sort()
396
- .map((id) => ({
397
- column: { type: 'axis', id: parseJson(id) },
398
- ascending: true,
399
- naAndAbsentAreLeastValues: true,
400
- }));
401
-
402
- const request: CalculateTableDataRequest<PObjectId> = {
403
- src: {
404
- type: 'outer',
405
- primary: primaryEntry,
406
- secondary: secondaryEntry,
407
- },
408
- filters: [],
409
- sorting,
410
- };
411
-
412
- return pFrameDriver.calculateTableData(
413
- pFrame,
414
- JSON.parse(JSON.stringify(request)),
415
- {
416
- offset: 0,
417
- // +1 is a hack to check whether the selection is over the limit
418
- length: SEQUENCE_LIMIT + 1,
419
- },
420
- );
421
- }
422
-
423
- const extractSequences = (
424
- columnIds: PObjectId[],
425
- table: CalculateTableDataResponse,
426
- ): { name: string; rows: string[] }[] =>
427
- columnIds.map((columnId) => {
428
- const column = table.find(({ spec }) => spec.id === columnId);
429
- if (!column) {
430
- throw new Error(`Couldn't find sequence column (ID: \`${columnId}\`).`);
431
- }
432
- const name = readAnnotation(column.spec.spec, Annotation.Label)
433
- ?? 'Unlabeled column';
434
- const rows = column.data.data
435
- .keys()
436
- .take(SEQUENCE_LIMIT)
437
- .map((row) =>
438
- pTableValue(column.data, row, { absent: '', na: '' })?.toString()
439
- ?? '',
440
- )
441
- .toArray();
442
- return { name, rows };
443
- });
444
-
445
- const extractLabels = (
446
- columnIds: PTableColumnId[],
447
- table: CalculateTableDataResponse,
448
- ): { rows: string[] }[] =>
449
- columnIds.map((columnId) => {
450
- const column = table.find(({ spec }) => {
451
- if (columnId.type === 'axis' && spec.type === 'axis') {
452
- return isJsonEqual(columnId.id, spec.id);
453
- }
454
- if (columnId.type === 'column' && spec.type === 'column') {
455
- return columnId.id === spec.id;
456
- }
457
- });
458
- if (!column) {
459
- throw new Error(`Couldn't find label column (ID: \`${columnId}\`).`);
460
- }
461
- const rows = column.data.data
462
- .keys()
463
- .take(SEQUENCE_LIMIT)
464
- .map((row) =>
465
- pTableValue(column.data, row, { absent: '', na: '' })?.toString()
466
- ?? '',
467
- )
468
- .toArray();
469
- return { rows };
470
- });
471
-
472
- const extractMarkups = (
473
- columnIds: PObjectId[],
474
- table: CalculateTableDataResponse,
475
- ): { labels: Record<string, string>; rows: Markup[] }[] =>
476
- columnIds.map((columnId) => {
477
- const column = table.find(({ spec }) => spec.id === columnId);
478
- if (!column) {
479
- throw new Error(`Couldn't find markup column (ID: \`${columnId}\`).`);
480
- }
481
- const labels = readAnnotationJson(
482
- column.spec.spec,
483
- Annotation.Sequence.Annotation.Mapping,
484
- ) ?? {};
485
- const rows = column.data.data
486
- .keys()
487
- .take(SEQUENCE_LIMIT)
488
- .map((row) =>
489
- parseMarkup(
490
- pTableValue(column.data, row, { absent: '', na: '' })?.toString()
491
- ?? '',
492
- ),
493
- )
494
- .toArray();
495
- return { labels, rows };
496
- });
497
-
498
- const alignSequences = (() => {
499
- const cache = new Map<string, string[]>();
500
- return async (
501
- sequences: string[],
502
- alignmentParams: PlMultiSequenceAlignmentSettings['alignmentParams'],
503
- abortSignal: AbortSignal,
504
- ): Promise<string[]> => {
505
- const hash = await objectHash([sequences, alignmentParams]);
506
- let result = cache.get(hash);
507
- if (result) return result;
508
- result = await runInWorker<
509
- MultiSequenceAlignmentWorker.RequestMessage,
510
- MultiSequenceAlignmentWorker.ResponseMessage
511
- >(
512
- new Worker(
513
- new URL('./multi-sequence-alignment.worker.ts', import.meta.url),
514
- { type: 'module' },
515
- ),
516
- { sequences, params: alignmentParams },
517
- abortSignal,
518
- );
519
- cache.set(hash, result);
520
- return result;
521
- };
522
- })();
523
-
524
- function generateHighlightImage(
525
- { colorScheme, sequences, residueCounts, markup }: {
526
- colorScheme: PlMultiSequenceAlignmentColorSchemeOption;
527
- sequences: string[];
528
- residueCounts: ResidueCounts;
529
- markup: { labels: Record<string, string>; rows: Markup[] } | undefined;
530
- },
531
- ): { blob: Blob; legend: HighlightLegend } | undefined {
532
- if (colorScheme.type === 'chemical-properties') {
533
- return highlightByChemicalProperties({ sequences, residueCounts });
534
- }
535
- if (colorScheme.type === 'markup') {
536
- if (!markup) {
537
- throw new Error('Missing markup data.');
538
- }
539
- return highlightByMarkup({
540
- markupRows: sequences.map((sequence, row) => {
541
- const markupRow = markup.rows.at(row);
542
- if (!markupRow) throw new Error(`Missing markup for row ${row}.`);
543
- return markupAlignedSequence(sequence, markupRow);
544
- }),
545
- columnCount: sequences.at(0)?.length ?? 0,
546
- labels: markup.labels,
547
- });
548
- }
549
- }
550
-
551
- const blobToBase64 = (blob: Blob): Promise<string> =>
552
- new Promise<string>((resolve, reject) => {
553
- const reader = new FileReader();
554
- reader.addEventListener('load', () => resolve(reader.result as string));
555
- reader.addEventListener('error', () => reject(reader.error));
556
- reader.readAsDataURL(blob);
557
- });
558
-
559
- const buildPhylogeneticTree = (() => {
560
- const cache = new Map<string, PhylogeneticTreeWorker.TreeNodeData[]>();
561
- return async (data: { rows: string[] }[], abortSignal: AbortSignal) => {
562
- const concatenatedSequences = data.at(0)?.rows
563
- .keys()
564
- .map((row) => data.map((column) => column.rows.at(row) ?? '').join(''))
565
- .toArray() ?? [];
566
- const hash = await objectHash(concatenatedSequences);
567
- let result = cache.get(hash);
568
- if (result) return result;
569
- result = await runInWorker<
570
- PhylogeneticTreeWorker.RequestMessage,
571
- PhylogeneticTreeWorker.ResponseMessage
572
- >(
573
- new Worker(
574
- new URL('./phylogenetic-tree.worker.ts', import.meta.url),
575
- { type: 'module' },
576
- ),
577
- concatenatedSequences,
578
- abortSignal,
579
- );
580
- cache.set(hash, result);
581
- return result;
582
- };
583
- })();
584
-
585
- const runInWorker = <RequestMessage, ResponseMessage>(
586
- worker: Worker,
587
- message: RequestMessage,
588
- abortSignal: AbortSignal,
589
- ) =>
590
- new Promise<ResponseMessage>((resolve, reject) => {
591
- worker.addEventListener('message', ({ data }) => {
592
- resolve(data);
593
- worker.terminate();
594
- });
595
- worker.addEventListener('error', ({ error, message }) => {
596
- reject(error ?? message);
597
- worker.terminate();
598
- });
599
- abortSignal.addEventListener('abort', () => {
600
- reject(abortSignal.reason);
601
- worker.terminate();
602
- });
603
- worker.postMessage(message);
604
- });
605
-
606
- function refreshOnDeepChange<T, P>(
607
- cb: (params: P, abortSignal: AbortSignal) => Promise<T>,
608
- ) {
609
- const data = ref<T>();
610
- const isLoading = ref(true);
611
- const error = ref<Error>();
612
- let requestId: symbol;
613
- return (paramsGetter: () => P) => {
614
- watch(paramsGetter, async (params, prevParams) => {
615
- if (isJsonEqual(params, prevParams)) return;
616
- const abortController = new AbortController();
617
- const currentRequestId = requestId = Symbol();
618
- onWatcherCleanup(() => {
619
- abortController.abort();
620
- });
621
- try {
622
- error.value = undefined;
623
- isLoading.value = true;
624
- const result = await cb(params, abortController.signal);
625
- if (currentRequestId === requestId) {
626
- data.value = result;
627
- }
628
- } catch (err) {
629
- console.error(err);
630
- if (currentRequestId === requestId) {
631
- error.value = ensureError(err);
632
- }
633
- } finally {
634
- if (currentRequestId === requestId) {
635
- isLoading.value = false;
636
- }
637
- }
638
- }, { immediate: true });
639
- return { data, isLoading, error };
640
- };
641
- }
642
-
643
- type MultipleAlignmentData = {
644
- sequences: {
645
- name: string;
646
- rows: string[];
647
- residueCounts: ResidueCounts;
648
- highlightImageUrl?: string;
649
- }[];
650
- labels: {
651
- rows: string[];
652
- }[];
653
- highlightLegend?: HighlightLegend;
654
- phylogeneticTree?: PhylogeneticTreeWorker.TreeNodeData[];
655
- exceedsLimit: boolean;
656
- };
657
-
658
- type OptionsWithDefaults<T> = {
659
- options: ListOptionNormalized<T>[];
660
- defaults: T[];
661
- };
@@ -1 +0,0 @@
1
- export { default as PlMultiSequenceAlignment } from './PlMultiSequenceAlignment.vue';