@morscherlab/mld-sdk 0.7.5 → 0.7.6
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/README.md +1 -1
- package/dist/__tests__/composables/useAutoGroup.test.d.ts +1 -0
- package/dist/components/AutoGroupModal.vue.js +522 -0
- package/dist/components/AutoGroupModal.vue.js.map +1 -0
- package/dist/components/AutoGroupModal.vue3.js +6 -0
- package/dist/components/AutoGroupModal.vue3.js.map +1 -0
- package/dist/components/FormActions.vue.d.ts +1 -1
- package/dist/components/GroupingModal.vue.js.map +1 -1
- package/dist/components/SampleSelector.vue.d.ts +5 -9
- package/dist/components/SampleSelector.vue.js +127 -255
- package/dist/components/SampleSelector.vue.js.map +1 -1
- package/dist/components/index.d.ts +1 -0
- package/dist/components/index.js +53 -50
- package/dist/components/index.js.map +1 -1
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/index.js +3 -0
- package/dist/composables/index.js.map +1 -1
- package/dist/composables/useAutoGroup.d.ts +80 -0
- package/dist/composables/useAutoGroup.js +397 -0
- package/dist/composables/useAutoGroup.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +48 -42
- package/dist/index.js.map +1 -1
- package/dist/styles.css +2652 -1788
- package/dist/types/auto-group.d.ts +31 -0
- package/dist/types/index.d.ts +1 -0
- package/package.json +1 -1
- package/src/__tests__/composables/useAutoGroup.test.ts +375 -0
- package/src/components/AutoGroupModal.story.vue +155 -0
- package/src/components/AutoGroupModal.vue +441 -0
- package/src/components/GroupingModal.vue +1 -0
- package/src/components/SampleSelector.story.vue +8 -31
- package/src/components/SampleSelector.vue +22 -137
- package/src/components/index.ts +1 -0
- package/src/composables/index.ts +1 -0
- package/src/composables/useAutoGroup.ts +495 -0
- package/src/index.ts +12 -0
- package/src/styles/components/auto-group-modal.css +501 -0
- package/src/styles/index.css +1 -0
- package/src/types/auto-group.ts +37 -0
- package/src/types/index.ts +11 -0
|
@@ -0,0 +1,397 @@
|
|
|
1
|
+
import { ref, computed } from "vue";
|
|
2
|
+
const DEFAULT_COLORS = [
|
|
3
|
+
"#3B82F6",
|
|
4
|
+
"#10B981",
|
|
5
|
+
"#F59E0B",
|
|
6
|
+
"#EF4444",
|
|
7
|
+
"#8B5CF6",
|
|
8
|
+
"#EC4899",
|
|
9
|
+
"#06B6D4",
|
|
10
|
+
"#84CC16",
|
|
11
|
+
"#F97316",
|
|
12
|
+
"#6366F1"
|
|
13
|
+
];
|
|
14
|
+
const DELIMITER_CANDIDATES = ["_", "-", "."];
|
|
15
|
+
function analyzeDelimiter(lines) {
|
|
16
|
+
if (lines.length === 0) {
|
|
17
|
+
return { delimiter: "_", dominantFieldCount: 1, minFieldCount: 1, consistency: 0 };
|
|
18
|
+
}
|
|
19
|
+
let bestDelimiter = "_";
|
|
20
|
+
let bestConsistency = -1;
|
|
21
|
+
let bestFieldCount = 1;
|
|
22
|
+
for (const candidate of DELIMITER_CANDIDATES) {
|
|
23
|
+
const fieldCounts = lines.map((line) => line.split(candidate).length);
|
|
24
|
+
const countFrequency = /* @__PURE__ */ new Map();
|
|
25
|
+
for (const count of fieldCounts) {
|
|
26
|
+
countFrequency.set(count, (countFrequency.get(count) ?? 0) + 1);
|
|
27
|
+
}
|
|
28
|
+
let modeCount = 1;
|
|
29
|
+
let modeFrequency = 0;
|
|
30
|
+
for (const [count, freq] of countFrequency) {
|
|
31
|
+
if (freq > modeFrequency || freq === modeFrequency && count > modeCount) {
|
|
32
|
+
modeCount = count;
|
|
33
|
+
modeFrequency = freq;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
const rawConsistency = modeFrequency / lines.length;
|
|
37
|
+
const consistency = modeCount > 1 ? rawConsistency : 0;
|
|
38
|
+
if (consistency > bestConsistency || consistency === bestConsistency && DELIMITER_CANDIDATES.indexOf(candidate) < DELIMITER_CANDIDATES.indexOf(bestDelimiter)) {
|
|
39
|
+
bestDelimiter = candidate;
|
|
40
|
+
bestConsistency = consistency;
|
|
41
|
+
bestFieldCount = modeCount;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
const bestFieldCounts = lines.map((line) => line.split(bestDelimiter).length);
|
|
45
|
+
const multiFieldCounts = bestFieldCounts.filter((c) => c >= 2);
|
|
46
|
+
const minFieldCount = multiFieldCounts.length > 0 ? Math.min(...multiFieldCounts) : 1;
|
|
47
|
+
return {
|
|
48
|
+
delimiter: bestDelimiter,
|
|
49
|
+
dominantFieldCount: bestFieldCount,
|
|
50
|
+
minFieldCount,
|
|
51
|
+
consistency: bestConsistency
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
function detectOutliers(lines, delimiter, minFieldCount) {
|
|
55
|
+
const outliers = [];
|
|
56
|
+
for (let i = 0; i < lines.length; i++) {
|
|
57
|
+
const fieldCount = lines[i].split(delimiter).length;
|
|
58
|
+
if (fieldCount < minFieldCount) {
|
|
59
|
+
outliers.push({
|
|
60
|
+
sample: lines[i],
|
|
61
|
+
index: i,
|
|
62
|
+
fieldCount,
|
|
63
|
+
action: "include"
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return outliers;
|
|
68
|
+
}
|
|
69
|
+
function extractColumns(samples, delimiter, minFieldCount) {
|
|
70
|
+
if (samples.length === 0) return [];
|
|
71
|
+
const suffixCount = minFieldCount - 1;
|
|
72
|
+
const rows = samples.map((s) => {
|
|
73
|
+
const parts = s.split(delimiter);
|
|
74
|
+
const splitAt = parts.length - suffixCount;
|
|
75
|
+
return [
|
|
76
|
+
parts.slice(0, splitAt).join(delimiter),
|
|
77
|
+
...parts.slice(splitAt)
|
|
78
|
+
];
|
|
79
|
+
});
|
|
80
|
+
const columnCount = minFieldCount;
|
|
81
|
+
const columns = [];
|
|
82
|
+
for (let col = 0; col < columnCount; col++) {
|
|
83
|
+
const values = rows.map((row) => row[col]);
|
|
84
|
+
const unique = [...new Set(values)];
|
|
85
|
+
columns.push({
|
|
86
|
+
index: col,
|
|
87
|
+
name: col === 0 ? "Condition" : `Field ${col + 1}`,
|
|
88
|
+
uniqueValues: unique,
|
|
89
|
+
cardinality: unique.length,
|
|
90
|
+
type: col === 0 ? "prefix" : "suffix"
|
|
91
|
+
});
|
|
92
|
+
}
|
|
93
|
+
return columns;
|
|
94
|
+
}
|
|
95
|
+
function parseCSVLine(line) {
|
|
96
|
+
const result = [];
|
|
97
|
+
let current = "";
|
|
98
|
+
let inQuotes = false;
|
|
99
|
+
for (let i = 0; i < line.length; i++) {
|
|
100
|
+
const char = line[i];
|
|
101
|
+
if (char === '"') {
|
|
102
|
+
inQuotes = !inQuotes;
|
|
103
|
+
} else if (char === "," && !inQuotes) {
|
|
104
|
+
result.push(current.trim());
|
|
105
|
+
current = "";
|
|
106
|
+
} else {
|
|
107
|
+
current += char;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
result.push(current.trim());
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
function parseCSV(text) {
|
|
114
|
+
const lines = text.trim().split("\n");
|
|
115
|
+
if (lines.length < 2) {
|
|
116
|
+
throw new Error("CSV must have at least a header and one data row");
|
|
117
|
+
}
|
|
118
|
+
const headers = parseCSVLine(lines[0]);
|
|
119
|
+
const rows = [];
|
|
120
|
+
for (let i = 1; i < lines.length; i++) {
|
|
121
|
+
const values = parseCSVLine(lines[i]);
|
|
122
|
+
if (values.length !== headers.length) continue;
|
|
123
|
+
const row = {};
|
|
124
|
+
headers.forEach((header, idx) => {
|
|
125
|
+
row[header] = values[idx];
|
|
126
|
+
});
|
|
127
|
+
rows.push(row);
|
|
128
|
+
}
|
|
129
|
+
const sampleKeywords = ["sample", "name", "id", "sample_name", "samplename"];
|
|
130
|
+
const sampleColumn = headers.find((h) => sampleKeywords.includes(h.toLowerCase())) ?? headers[0];
|
|
131
|
+
return { columns: headers, rows, sampleColumn };
|
|
132
|
+
}
|
|
133
|
+
function computeGroups(allSamples, columns, enabledFields, outlierActions, delimiter, minFieldCount) {
|
|
134
|
+
const excludedSamples = [];
|
|
135
|
+
const qcSamples = [];
|
|
136
|
+
const conformingSamples = [];
|
|
137
|
+
for (let i = 0; i < allSamples.length; i++) {
|
|
138
|
+
const action = outlierActions.get(i);
|
|
139
|
+
if (action === "exclude") {
|
|
140
|
+
excludedSamples.push(allSamples[i]);
|
|
141
|
+
} else if (action === "qc") {
|
|
142
|
+
qcSamples.push(allSamples[i]);
|
|
143
|
+
} else {
|
|
144
|
+
conformingSamples.push(allSamples[i]);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
const groupMap = /* @__PURE__ */ new Map();
|
|
148
|
+
const metadata = [];
|
|
149
|
+
const enabledIndices = [...enabledFields].sort((a, b) => a - b);
|
|
150
|
+
const suffixCount = minFieldCount - 1;
|
|
151
|
+
for (const sample of conformingSamples) {
|
|
152
|
+
const parts = sample.split(delimiter);
|
|
153
|
+
const splitAt = Math.max(1, parts.length - suffixCount);
|
|
154
|
+
const row = [
|
|
155
|
+
parts.slice(0, splitAt).join(delimiter),
|
|
156
|
+
...parts.slice(splitAt)
|
|
157
|
+
];
|
|
158
|
+
const keyParts = [];
|
|
159
|
+
for (const idx of enabledIndices) {
|
|
160
|
+
if (idx < row.length && idx < columns.length) {
|
|
161
|
+
keyParts.push(row[idx]);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
const groupKey = keyParts.join(" / ");
|
|
165
|
+
if (!groupMap.has(groupKey)) {
|
|
166
|
+
groupMap.set(groupKey, []);
|
|
167
|
+
}
|
|
168
|
+
groupMap.get(groupKey).push(sample);
|
|
169
|
+
const fields = {};
|
|
170
|
+
for (const col of columns) {
|
|
171
|
+
if (col.index < row.length) {
|
|
172
|
+
fields[col.name] = row[col.index];
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
metadata.push({ sampleName: sample, fields, group: groupKey });
|
|
176
|
+
}
|
|
177
|
+
const groups = [];
|
|
178
|
+
let colorIdx = 0;
|
|
179
|
+
for (const [name, samples] of groupMap) {
|
|
180
|
+
groups.push({
|
|
181
|
+
name,
|
|
182
|
+
color: DEFAULT_COLORS[colorIdx % DEFAULT_COLORS.length],
|
|
183
|
+
samples
|
|
184
|
+
});
|
|
185
|
+
colorIdx++;
|
|
186
|
+
}
|
|
187
|
+
if (qcSamples.length > 0) {
|
|
188
|
+
groups.push({
|
|
189
|
+
name: "QC",
|
|
190
|
+
color: "#6B7280",
|
|
191
|
+
samples: qcSamples
|
|
192
|
+
});
|
|
193
|
+
for (const sample of qcSamples) {
|
|
194
|
+
metadata.push({ sampleName: sample, fields: {}, group: "QC" });
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
return { groups, metadata, excludedSamples };
|
|
198
|
+
}
|
|
199
|
+
function useAutoGroup() {
|
|
200
|
+
const inputMode = ref("paste");
|
|
201
|
+
const rawText = ref("");
|
|
202
|
+
const csvData = ref(null);
|
|
203
|
+
const delimiter = ref("_");
|
|
204
|
+
const dominantFieldCount = ref(1);
|
|
205
|
+
const minFieldCount = ref(1);
|
|
206
|
+
const outliers = ref([]);
|
|
207
|
+
const fields = ref([]);
|
|
208
|
+
const fieldNames = ref({});
|
|
209
|
+
const enabledFields = ref(/* @__PURE__ */ new Set());
|
|
210
|
+
const samples = computed(() => {
|
|
211
|
+
if (inputMode.value === "csv" && csvData.value) {
|
|
212
|
+
return csvData.value.rows.map((r) => r[csvData.value.sampleColumn]);
|
|
213
|
+
}
|
|
214
|
+
return rawText.value.split("\n").map((l) => l.trim()).filter((l) => l.length > 0);
|
|
215
|
+
});
|
|
216
|
+
const hasOutliers = computed(() => outliers.value.length > 0);
|
|
217
|
+
const conformingSamples = computed(() => {
|
|
218
|
+
const outlierIndices = new Set(outliers.value.map((o) => o.index));
|
|
219
|
+
return samples.value.filter((_, i) => !outlierIndices.has(i));
|
|
220
|
+
});
|
|
221
|
+
const outlierActions = computed(() => {
|
|
222
|
+
const map = /* @__PURE__ */ new Map();
|
|
223
|
+
for (const o of outliers.value) {
|
|
224
|
+
map.set(o.index, o.action);
|
|
225
|
+
}
|
|
226
|
+
return map;
|
|
227
|
+
});
|
|
228
|
+
const effectiveColumns = computed(() => {
|
|
229
|
+
return fields.value.map((col) => ({
|
|
230
|
+
...col,
|
|
231
|
+
name: fieldNames.value[col.index] ?? col.name
|
|
232
|
+
}));
|
|
233
|
+
});
|
|
234
|
+
const groups = computed(() => {
|
|
235
|
+
if (effectiveColumns.value.length === 0 || enabledFields.value.size === 0) {
|
|
236
|
+
return [];
|
|
237
|
+
}
|
|
238
|
+
const result2 = computeGroups(
|
|
239
|
+
samples.value,
|
|
240
|
+
effectiveColumns.value,
|
|
241
|
+
enabledFields.value,
|
|
242
|
+
outlierActions.value,
|
|
243
|
+
delimiter.value,
|
|
244
|
+
minFieldCount.value
|
|
245
|
+
);
|
|
246
|
+
return result2.groups;
|
|
247
|
+
});
|
|
248
|
+
const metadata = computed(() => {
|
|
249
|
+
if (effectiveColumns.value.length === 0 || enabledFields.value.size === 0) {
|
|
250
|
+
return [];
|
|
251
|
+
}
|
|
252
|
+
return computeGroups(
|
|
253
|
+
samples.value,
|
|
254
|
+
effectiveColumns.value,
|
|
255
|
+
enabledFields.value,
|
|
256
|
+
outlierActions.value,
|
|
257
|
+
delimiter.value,
|
|
258
|
+
minFieldCount.value
|
|
259
|
+
).metadata;
|
|
260
|
+
});
|
|
261
|
+
const excludedSamples = computed(() => {
|
|
262
|
+
return computeGroups(
|
|
263
|
+
samples.value,
|
|
264
|
+
effectiveColumns.value,
|
|
265
|
+
enabledFields.value,
|
|
266
|
+
outlierActions.value,
|
|
267
|
+
delimiter.value,
|
|
268
|
+
minFieldCount.value
|
|
269
|
+
).excludedSamples;
|
|
270
|
+
});
|
|
271
|
+
const result = computed(() => ({
|
|
272
|
+
groups: groups.value,
|
|
273
|
+
metadata: metadata.value,
|
|
274
|
+
excludedSamples: excludedSamples.value
|
|
275
|
+
}));
|
|
276
|
+
function parseInput() {
|
|
277
|
+
if (inputMode.value === "csv" && csvData.value) {
|
|
278
|
+
parseCsvInput();
|
|
279
|
+
} else {
|
|
280
|
+
parsePasteInput();
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
function parsePasteInput() {
|
|
284
|
+
const lines = samples.value;
|
|
285
|
+
if (lines.length === 0) return;
|
|
286
|
+
const analysis = analyzeDelimiter(lines);
|
|
287
|
+
delimiter.value = analysis.delimiter;
|
|
288
|
+
dominantFieldCount.value = analysis.dominantFieldCount;
|
|
289
|
+
minFieldCount.value = analysis.minFieldCount;
|
|
290
|
+
outliers.value = detectOutliers(lines, analysis.delimiter, analysis.minFieldCount);
|
|
291
|
+
const conforming = lines.filter(
|
|
292
|
+
(_, i) => !outliers.value.some((o) => o.index === i)
|
|
293
|
+
);
|
|
294
|
+
fields.value = extractColumns(conforming, analysis.delimiter, analysis.minFieldCount);
|
|
295
|
+
fieldNames.value = {};
|
|
296
|
+
enabledFields.value = new Set(fields.value.map((f) => f.index));
|
|
297
|
+
}
|
|
298
|
+
function parseCsvInput() {
|
|
299
|
+
if (!csvData.value) return;
|
|
300
|
+
const csv = csvData.value;
|
|
301
|
+
const nonSampleCols = csv.columns.filter((c) => c !== csv.sampleColumn);
|
|
302
|
+
fields.value = nonSampleCols.map((col, i) => {
|
|
303
|
+
const values = csv.rows.map((r) => r[col]);
|
|
304
|
+
const unique = [...new Set(values)];
|
|
305
|
+
return {
|
|
306
|
+
index: i,
|
|
307
|
+
name: col,
|
|
308
|
+
uniqueValues: unique,
|
|
309
|
+
cardinality: unique.length
|
|
310
|
+
};
|
|
311
|
+
});
|
|
312
|
+
outliers.value = [];
|
|
313
|
+
delimiter.value = ",";
|
|
314
|
+
dominantFieldCount.value = csv.columns.length;
|
|
315
|
+
fieldNames.value = {};
|
|
316
|
+
for (const f of fields.value) {
|
|
317
|
+
fieldNames.value[f.index] = f.name;
|
|
318
|
+
}
|
|
319
|
+
enabledFields.value = new Set(fields.value.map((f) => f.index));
|
|
320
|
+
}
|
|
321
|
+
function setOutlierAction(index, action) {
|
|
322
|
+
const outlier = outliers.value.find((o) => o.index === index);
|
|
323
|
+
if (outlier) {
|
|
324
|
+
outlier.action = action;
|
|
325
|
+
outliers.value = [...outliers.value];
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
function setAllOutlierActions(action) {
|
|
329
|
+
for (const outlier of outliers.value) {
|
|
330
|
+
outlier.action = action;
|
|
331
|
+
}
|
|
332
|
+
outliers.value = [...outliers.value];
|
|
333
|
+
}
|
|
334
|
+
function toggleField(index) {
|
|
335
|
+
const newSet = new Set(enabledFields.value);
|
|
336
|
+
if (newSet.has(index)) {
|
|
337
|
+
newSet.delete(index);
|
|
338
|
+
} else {
|
|
339
|
+
newSet.add(index);
|
|
340
|
+
}
|
|
341
|
+
enabledFields.value = newSet;
|
|
342
|
+
}
|
|
343
|
+
function renameField(index, name) {
|
|
344
|
+
fieldNames.value = { ...fieldNames.value, [index]: name };
|
|
345
|
+
}
|
|
346
|
+
function reset() {
|
|
347
|
+
rawText.value = "";
|
|
348
|
+
csvData.value = null;
|
|
349
|
+
delimiter.value = "_";
|
|
350
|
+
dominantFieldCount.value = 1;
|
|
351
|
+
minFieldCount.value = 1;
|
|
352
|
+
outliers.value = [];
|
|
353
|
+
fields.value = [];
|
|
354
|
+
fieldNames.value = {};
|
|
355
|
+
enabledFields.value = /* @__PURE__ */ new Set();
|
|
356
|
+
}
|
|
357
|
+
return {
|
|
358
|
+
// State
|
|
359
|
+
inputMode,
|
|
360
|
+
rawText,
|
|
361
|
+
csvData,
|
|
362
|
+
delimiter,
|
|
363
|
+
dominantFieldCount,
|
|
364
|
+
minFieldCount,
|
|
365
|
+
outliers,
|
|
366
|
+
fields,
|
|
367
|
+
fieldNames,
|
|
368
|
+
enabledFields,
|
|
369
|
+
// Computed
|
|
370
|
+
samples,
|
|
371
|
+
hasOutliers,
|
|
372
|
+
conformingSamples,
|
|
373
|
+
groups,
|
|
374
|
+
metadata,
|
|
375
|
+
excludedSamples,
|
|
376
|
+
result,
|
|
377
|
+
effectiveColumns,
|
|
378
|
+
// Actions
|
|
379
|
+
parseInput,
|
|
380
|
+
setOutlierAction,
|
|
381
|
+
setAllOutlierActions,
|
|
382
|
+
toggleField,
|
|
383
|
+
renameField,
|
|
384
|
+
reset
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
export {
|
|
388
|
+
DEFAULT_COLORS,
|
|
389
|
+
analyzeDelimiter,
|
|
390
|
+
computeGroups,
|
|
391
|
+
detectOutliers,
|
|
392
|
+
extractColumns,
|
|
393
|
+
parseCSV,
|
|
394
|
+
parseCSVLine,
|
|
395
|
+
useAutoGroup
|
|
396
|
+
};
|
|
397
|
+
//# sourceMappingURL=useAutoGroup.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useAutoGroup.js","sources":["../../src/composables/useAutoGroup.ts"],"sourcesContent":["import { ref, computed } from 'vue'\nimport type {\n InputMode,\n OutlierAction,\n OutlierInfo,\n ColumnInfo,\n MetadataRow,\n AutoGroupResult,\n ParsedCsvData,\n} from '../types/auto-group'\nimport type { SampleGroup } from '../types/components'\n\nexport const DEFAULT_COLORS = [\n '#3B82F6', '#10B981', '#F59E0B', '#EF4444', '#8B5CF6',\n '#EC4899', '#06B6D4', '#84CC16', '#F97316', '#6366F1',\n]\n\nconst DELIMITER_CANDIDATES = ['_', '-', '.'] as const\n\n// --- Pure functions (exported for testing) ---\n\nexport function analyzeDelimiter(lines: string[]): {\n delimiter: string\n dominantFieldCount: number\n minFieldCount: number\n consistency: number\n} {\n if (lines.length === 0) {\n return { delimiter: '_', dominantFieldCount: 1, minFieldCount: 1, consistency: 0 }\n }\n\n let bestDelimiter = '_'\n let bestConsistency = -1\n let bestFieldCount = 1\n\n for (const candidate of DELIMITER_CANDIDATES) {\n const fieldCounts = lines.map(line => line.split(candidate).length)\n const countFrequency = new Map<number, number>()\n\n for (const count of fieldCounts) {\n countFrequency.set(count, (countFrequency.get(count) ?? 0) + 1)\n }\n\n // Find mode (most frequent field count)\n let modeCount = 1\n let modeFrequency = 0\n for (const [count, freq] of countFrequency) {\n if (freq > modeFrequency || (freq === modeFrequency && count > modeCount)) {\n modeCount = count\n modeFrequency = freq\n }\n }\n\n const rawConsistency = modeFrequency / lines.length\n // A delimiter that produces field count 1 didn't actually split anything\n const consistency = modeCount > 1 ? rawConsistency : 0\n\n if (\n consistency > bestConsistency ||\n (consistency === bestConsistency &&\n DELIMITER_CANDIDATES.indexOf(candidate) < DELIMITER_CANDIDATES.indexOf(bestDelimiter as typeof candidate))\n ) {\n bestDelimiter = candidate\n bestConsistency = consistency\n bestFieldCount = modeCount\n }\n }\n\n const bestFieldCounts = lines.map(line => line.split(bestDelimiter).length)\n const multiFieldCounts = bestFieldCounts.filter(c => c >= 2)\n const minFieldCount = multiFieldCounts.length > 0 ? Math.min(...multiFieldCounts) : 1\n\n return {\n delimiter: bestDelimiter,\n dominantFieldCount: bestFieldCount,\n minFieldCount,\n consistency: bestConsistency,\n }\n}\n\nexport function detectOutliers(\n lines: string[],\n delimiter: string,\n minFieldCount: number,\n): OutlierInfo[] {\n const outliers: OutlierInfo[] = []\n\n for (let i = 0; i < lines.length; i++) {\n const fieldCount = lines[i].split(delimiter).length\n if (fieldCount < minFieldCount) {\n outliers.push({\n sample: lines[i],\n index: i,\n fieldCount,\n action: 'include',\n })\n }\n }\n\n return outliers\n}\n\nexport function extractColumns(\n samples: string[],\n delimiter: string,\n minFieldCount: number,\n): ColumnInfo[] {\n if (samples.length === 0) return []\n\n const suffixCount = minFieldCount - 1\n const rows = samples.map(s => {\n const parts = s.split(delimiter)\n const splitAt = parts.length - suffixCount\n return [\n parts.slice(0, splitAt).join(delimiter),\n ...parts.slice(splitAt),\n ]\n })\n\n const columnCount = minFieldCount\n const columns: ColumnInfo[] = []\n for (let col = 0; col < columnCount; col++) {\n const values = rows.map(row => row[col])\n const unique = [...new Set(values)]\n columns.push({\n index: col,\n name: col === 0 ? 'Condition' : `Field ${col + 1}`,\n uniqueValues: unique,\n cardinality: unique.length,\n type: col === 0 ? 'prefix' : 'suffix',\n })\n }\n\n return columns\n}\n\nexport function parseCSVLine(line: string): string[] {\n const result: string[] = []\n let current = ''\n let inQuotes = false\n\n for (let i = 0; i < line.length; i++) {\n const char = line[i]\n if (char === '\"') {\n inQuotes = !inQuotes\n } else if (char === ',' && !inQuotes) {\n result.push(current.trim())\n current = ''\n } else {\n current += char\n }\n }\n result.push(current.trim())\n\n return result\n}\n\nexport function parseCSV(text: string): ParsedCsvData {\n const lines = text.trim().split('\\n')\n if (lines.length < 2) {\n throw new Error('CSV must have at least a header and one data row')\n }\n\n const headers = parseCSVLine(lines[0])\n const rows: Record<string, string>[] = []\n\n for (let i = 1; i < lines.length; i++) {\n const values = parseCSVLine(lines[i])\n if (values.length !== headers.length) continue\n const row: Record<string, string> = {}\n headers.forEach((header, idx) => {\n row[header] = values[idx]\n })\n rows.push(row)\n }\n\n // Auto-detect sample column\n const sampleKeywords = ['sample', 'name', 'id', 'sample_name', 'samplename']\n const sampleColumn =\n headers.find(h => sampleKeywords.includes(h.toLowerCase())) ?? headers[0]\n\n return { columns: headers, rows, sampleColumn }\n}\n\nexport function computeGroups(\n allSamples: string[],\n columns: ColumnInfo[],\n enabledFields: Set<number>,\n outlierActions: Map<number, OutlierAction>,\n delimiter: string,\n minFieldCount: number,\n): { groups: SampleGroup[]; metadata: MetadataRow[]; excludedSamples: string[] } {\n const excludedSamples: string[] = []\n const qcSamples: string[] = []\n const conformingSamples: string[] = []\n\n for (let i = 0; i < allSamples.length; i++) {\n const action = outlierActions.get(i)\n if (action === 'exclude') {\n excludedSamples.push(allSamples[i])\n } else if (action === 'qc') {\n qcSamples.push(allSamples[i])\n } else {\n conformingSamples.push(allSamples[i])\n }\n }\n\n // Build group map\n const groupMap = new Map<string, string[]>()\n const metadata: MetadataRow[] = []\n const enabledIndices = [...enabledFields].sort((a, b) => a - b)\n\n const suffixCount = minFieldCount - 1\n\n for (const sample of conformingSamples) {\n const parts = sample.split(delimiter)\n const splitAt = Math.max(1, parts.length - suffixCount)\n const row = [\n parts.slice(0, splitAt).join(delimiter),\n ...parts.slice(splitAt),\n ]\n\n // Build group key from enabled columns\n const keyParts: string[] = []\n for (const idx of enabledIndices) {\n if (idx < row.length && idx < columns.length) {\n keyParts.push(row[idx])\n }\n }\n const groupKey = keyParts.join(' / ')\n\n if (!groupMap.has(groupKey)) {\n groupMap.set(groupKey, [])\n }\n groupMap.get(groupKey)!.push(sample)\n\n // Build metadata row with ALL columns\n const fields: Record<string, string> = {}\n for (const col of columns) {\n if (col.index < row.length) {\n fields[col.name] = row[col.index]\n }\n }\n metadata.push({ sampleName: sample, fields, group: groupKey })\n }\n\n // Convert to SampleGroup[]\n const groups: SampleGroup[] = []\n let colorIdx = 0\n for (const [name, samples] of groupMap) {\n groups.push({\n name,\n color: DEFAULT_COLORS[colorIdx % DEFAULT_COLORS.length],\n samples,\n })\n colorIdx++\n }\n\n // QC group\n if (qcSamples.length > 0) {\n groups.push({\n name: 'QC',\n color: '#6B7280',\n samples: qcSamples,\n })\n for (const sample of qcSamples) {\n metadata.push({ sampleName: sample, fields: {}, group: 'QC' })\n }\n }\n\n return { groups, metadata, excludedSamples }\n}\n\n// --- Reactive composable ---\n\nexport function useAutoGroup() {\n const inputMode = ref<InputMode>('paste')\n const rawText = ref('')\n const csvData = ref<ParsedCsvData | null>(null)\n const delimiter = ref('_')\n const dominantFieldCount = ref(1)\n const minFieldCount = ref(1)\n const outliers = ref<OutlierInfo[]>([])\n const fields = ref<ColumnInfo[]>([])\n const fieldNames = ref<Record<number, string>>({})\n const enabledFields = ref(new Set<number>())\n\n const samples = computed(() => {\n if (inputMode.value === 'csv' && csvData.value) {\n return csvData.value.rows.map(r => r[csvData.value!.sampleColumn])\n }\n return rawText.value\n .split('\\n')\n .map(l => l.trim())\n .filter(l => l.length > 0)\n })\n\n const hasOutliers = computed(() => outliers.value.length > 0)\n\n const conformingSamples = computed(() => {\n const outlierIndices = new Set(outliers.value.map(o => o.index))\n return samples.value.filter((_, i) => !outlierIndices.has(i))\n })\n\n const outlierActions = computed(() => {\n const map = new Map<number, OutlierAction>()\n for (const o of outliers.value) {\n map.set(o.index, o.action)\n }\n return map\n })\n\n const effectiveColumns = computed(() => {\n return fields.value.map(col => ({\n ...col,\n name: fieldNames.value[col.index] ?? col.name,\n }))\n })\n\n const groups = computed(() => {\n if (effectiveColumns.value.length === 0 || enabledFields.value.size === 0) {\n return []\n }\n const result = computeGroups(\n samples.value,\n effectiveColumns.value,\n enabledFields.value,\n outlierActions.value,\n delimiter.value,\n minFieldCount.value,\n )\n return result.groups\n })\n\n const metadata = computed(() => {\n if (effectiveColumns.value.length === 0 || enabledFields.value.size === 0) {\n return []\n }\n return computeGroups(\n samples.value,\n effectiveColumns.value,\n enabledFields.value,\n outlierActions.value,\n delimiter.value,\n minFieldCount.value,\n ).metadata\n })\n\n const excludedSamples = computed(() => {\n return computeGroups(\n samples.value,\n effectiveColumns.value,\n enabledFields.value,\n outlierActions.value,\n delimiter.value,\n minFieldCount.value,\n ).excludedSamples\n })\n\n const result = computed<AutoGroupResult>(() => ({\n groups: groups.value,\n metadata: metadata.value,\n excludedSamples: excludedSamples.value,\n }))\n\n function parseInput() {\n if (inputMode.value === 'csv' && csvData.value) {\n parseCsvInput()\n } else {\n parsePasteInput()\n }\n }\n\n function parsePasteInput() {\n const lines = samples.value\n if (lines.length === 0) return\n\n const analysis = analyzeDelimiter(lines)\n delimiter.value = analysis.delimiter\n dominantFieldCount.value = analysis.dominantFieldCount\n minFieldCount.value = analysis.minFieldCount\n\n outliers.value = detectOutliers(lines, analysis.delimiter, analysis.minFieldCount)\n\n const conforming = lines.filter(\n (_, i) => !outliers.value.some(o => o.index === i)\n )\n fields.value = extractColumns(conforming, analysis.delimiter, analysis.minFieldCount)\n\n // Reset field names and enable all by default\n fieldNames.value = {}\n enabledFields.value = new Set(fields.value.map(f => f.index))\n }\n\n function parseCsvInput() {\n if (!csvData.value) return\n\n const csv = csvData.value\n const nonSampleCols = csv.columns.filter(c => c !== csv.sampleColumn)\n\n fields.value = nonSampleCols.map((col, i) => {\n const values = csv.rows.map(r => r[col])\n const unique = [...new Set(values)]\n return {\n index: i,\n name: col,\n uniqueValues: unique,\n cardinality: unique.length,\n }\n })\n\n // For CSV, no outliers\n outliers.value = []\n delimiter.value = ','\n dominantFieldCount.value = csv.columns.length\n\n fieldNames.value = {}\n for (const f of fields.value) {\n fieldNames.value[f.index] = f.name\n }\n enabledFields.value = new Set(fields.value.map(f => f.index))\n }\n\n function setOutlierAction(index: number, action: OutlierAction) {\n const outlier = outliers.value.find(o => o.index === index)\n if (outlier) {\n outlier.action = action\n // Trigger reactivity\n outliers.value = [...outliers.value]\n }\n }\n\n function setAllOutlierActions(action: OutlierAction) {\n for (const outlier of outliers.value) {\n outlier.action = action\n }\n outliers.value = [...outliers.value]\n }\n\n function toggleField(index: number) {\n const newSet = new Set(enabledFields.value)\n if (newSet.has(index)) {\n newSet.delete(index)\n } else {\n newSet.add(index)\n }\n enabledFields.value = newSet\n }\n\n function renameField(index: number, name: string) {\n fieldNames.value = { ...fieldNames.value, [index]: name }\n }\n\n function reset() {\n rawText.value = ''\n csvData.value = null\n delimiter.value = '_'\n dominantFieldCount.value = 1\n minFieldCount.value = 1\n outliers.value = []\n fields.value = []\n fieldNames.value = {}\n enabledFields.value = new Set()\n }\n\n return {\n // State\n inputMode,\n rawText,\n csvData,\n delimiter,\n dominantFieldCount,\n minFieldCount,\n outliers,\n fields,\n fieldNames,\n enabledFields,\n // Computed\n samples,\n hasOutliers,\n conformingSamples,\n groups,\n metadata,\n excludedSamples,\n result,\n effectiveColumns,\n // Actions\n parseInput,\n setOutlierAction,\n setAllOutlierActions,\n toggleField,\n renameField,\n reset,\n }\n}\n"],"names":["result"],"mappings":"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"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { MLDSdk, default } from './install';
|
|
2
|
-
export { BaseButton, BaseInput, BaseTextarea, BaseSelect, BaseCheckbox, BaseToggle, BaseRadioGroup, BaseSlider, ColorSlider, BaseTabs, BaseModal, FormField, DatePicker, TimePicker, TagsInput, NumberInput, FileUploader, AlertBox, ToastNotification, IconButton, ThemeToggle, SettingsButton, CollapsibleCard, AppTopBar, AppSidebar, AppLayout, AppContainer, Skeleton, WellPlate, RackEditor, SampleLegend, PlateMapEditor, ExperimentTimeline, SampleSelector, GroupingModal, GroupAssigner, MoleculeInput, ConcentrationInput, DoseCalculator, ReagentList, SampleHierarchyTree, ProtocolStepEditor, SegmentedControl, MultiSelect, BasePill, DropdownButton, Calendar, DataFrame, LoadingSpinner, Divider, StatusIndicator, ProgressBar, Avatar, EmptyState, Breadcrumb, Tooltip, ConfirmDialog, ChartContainer, SettingsModal, ScientificNumber, ChemicalFormula, FormulaInput, SequenceInput, UnitInput, StepWizard, AuditTrail, BatchProgressList, ExperimentDataViewer, ExperimentCodeBadge, DateTimePicker, TimeRangeInput, ScheduleCalendar, ResourceCard, } from './components';
|
|
3
|
-
export { useApi, useAuth, usePasskey, useTheme, useToast, usePlatformContext, useWellPlateEditor, useConcentrationUnits, useDoseCalculator, useProtocolTemplates, useRackEditor, useChemicalFormula, ATOMIC_WEIGHTS, useSequenceUtils, type ApiClientOptions, type UseWellPlateEditorOptions, type UseWellPlateEditorReturn, type UseRackEditorOptions, type UseRackEditorReturn, type ConcentrationValue, type ConcentrationUnit, type VolumeValue, type VolumeUnit, type StepTemplate, type FormulaParseResult, type FormulaPart, type SequenceType, type SequenceStats, parseTime, formatTime, generateTimeSlots, rangesOverlap, durationMinutes, formatDuration, isTimeInRange, findAvailableSlots, snapToSlot, addMinutes, compareTime, useScheduleDrag, usePluginConfig, type UsePluginConfigReturn, } from './composables';
|
|
2
|
+
export { BaseButton, BaseInput, BaseTextarea, BaseSelect, BaseCheckbox, BaseToggle, BaseRadioGroup, BaseSlider, ColorSlider, BaseTabs, BaseModal, FormField, DatePicker, TimePicker, TagsInput, NumberInput, FileUploader, AlertBox, ToastNotification, IconButton, ThemeToggle, SettingsButton, CollapsibleCard, AppTopBar, AppSidebar, AppLayout, AppContainer, Skeleton, WellPlate, RackEditor, SampleLegend, PlateMapEditor, ExperimentTimeline, SampleSelector, GroupingModal, AutoGroupModal, GroupAssigner, MoleculeInput, ConcentrationInput, DoseCalculator, ReagentList, SampleHierarchyTree, ProtocolStepEditor, SegmentedControl, MultiSelect, BasePill, DropdownButton, Calendar, DataFrame, LoadingSpinner, Divider, StatusIndicator, ProgressBar, Avatar, EmptyState, Breadcrumb, Tooltip, ConfirmDialog, ChartContainer, SettingsModal, ScientificNumber, ChemicalFormula, FormulaInput, SequenceInput, UnitInput, StepWizard, AuditTrail, BatchProgressList, ExperimentDataViewer, ExperimentCodeBadge, DateTimePicker, TimeRangeInput, ScheduleCalendar, ResourceCard, } from './components';
|
|
3
|
+
export { useApi, useAuth, usePasskey, useTheme, useToast, usePlatformContext, useWellPlateEditor, useConcentrationUnits, useDoseCalculator, useProtocolTemplates, useRackEditor, useChemicalFormula, ATOMIC_WEIGHTS, useSequenceUtils, type ApiClientOptions, type UseWellPlateEditorOptions, type UseWellPlateEditorReturn, type UseRackEditorOptions, type UseRackEditorReturn, type ConcentrationValue, type ConcentrationUnit, type VolumeValue, type VolumeUnit, type StepTemplate, type FormulaParseResult, type FormulaPart, type SequenceType, type SequenceStats, parseTime, formatTime, generateTimeSlots, rangesOverlap, durationMinutes, formatDuration, isTimeInRange, findAvailableSlots, snapToSlot, addMinutes, compareTime, useScheduleDrag, usePluginConfig, type UsePluginConfigReturn, useAutoGroup, DEFAULT_COLORS, } from './composables';
|
|
4
4
|
export { useAuthStore, useSettingsStore, colorPalettes, type SettingsState, } from './stores';
|
|
5
|
-
export type { ContainerDirection, ButtonVariant, ButtonSize, InputType, ModalSize, AlertType, Toast, TabItem, SelectOption, RadioOption, FormFieldProps, SidebarToolSection, CollapsibleState, TopBarVariant, TopBarPage, TopBarTab, TopBarTabOption, TopBarSettingsConfig, WellPlateFormat, WellState, WellPlateSelectionMode, Well, HeatmapColorScale, HeatmapConfig, SlotPosition, WellExtendedData, WellEditData, WellEditField, WellLegendItem, Rack, SampleType, PlateMap, PlateMapEditorState, ProtocolStepType, ProtocolStepStatus, ProtocolStep, SampleGroup, GroupItem, FileUploaderMode, SegmentedOption, SegmentedControlVariant, SegmentedControlSize, MultiSelectOption, MultiSelectSize, PillVariant, PillSize, CalendarSelectionMode, CalendarMarker, CalendarDayContext, SortDirection, SortState, DataFrameColumn, PaginationState, SpinnerSize, SpinnerVariant, DividerSpacing, StatusType, ProgressVariant, ProgressSize, AvatarSize, EmptyStateColor, EmptyStateSize, BreadcrumbItem, TooltipPosition, ConfirmVariant, SettingsTab, NumberNotation, TimePickerFormat, TimeRange, ScheduleView, ScheduleEventStatus, ScheduleEvent, ScheduleBlockedSlot, ScheduleSlotContext, ScheduleEventCreateContext, ScheduleEventUpdateContext, ResourceStatus, ResourceSpec, UnitOption, WizardStep, WizardStepState, AuditEntryType, AuditEntry, BatchItemStatus, BatchItem, BatchSummary, AuthConfig, UserInfo, LoginResponse, TokenVerifyResponse, RegisterRequest, UpdateProfileRequest, CredentialInfo, SummaryData, SummarySection, SummarySectionItem, TreeNode, TreeNodeType, PluginInfo, PluginNavItem, PluginSettings, PluginSettingField, PlatformContext, PlatformEventType, PlatformEvent, ThemeMode, ColorPalette, TableDensity, } from './types';
|
|
5
|
+
export type { ContainerDirection, ButtonVariant, ButtonSize, InputType, ModalSize, AlertType, Toast, TabItem, SelectOption, RadioOption, FormFieldProps, SidebarToolSection, CollapsibleState, TopBarVariant, TopBarPage, TopBarTab, TopBarTabOption, TopBarSettingsConfig, WellPlateFormat, WellState, WellPlateSelectionMode, Well, HeatmapColorScale, HeatmapConfig, SlotPosition, WellExtendedData, WellEditData, WellEditField, WellLegendItem, Rack, SampleType, PlateMap, PlateMapEditorState, ProtocolStepType, ProtocolStepStatus, ProtocolStep, SampleGroup, GroupItem, OutlierAction, InputMode, OutlierInfo, ColumnInfo, MetadataRow, AutoGroupResult, ParsedCsvData, FileUploaderMode, SegmentedOption, SegmentedControlVariant, SegmentedControlSize, MultiSelectOption, MultiSelectSize, PillVariant, PillSize, CalendarSelectionMode, CalendarMarker, CalendarDayContext, SortDirection, SortState, DataFrameColumn, PaginationState, SpinnerSize, SpinnerVariant, DividerSpacing, StatusType, ProgressVariant, ProgressSize, AvatarSize, EmptyStateColor, EmptyStateSize, BreadcrumbItem, TooltipPosition, ConfirmVariant, SettingsTab, NumberNotation, TimePickerFormat, TimeRange, ScheduleView, ScheduleEventStatus, ScheduleEvent, ScheduleBlockedSlot, ScheduleSlotContext, ScheduleEventCreateContext, ScheduleEventUpdateContext, ResourceStatus, ResourceSpec, UnitOption, WizardStep, WizardStepState, AuditEntryType, AuditEntry, BatchItemStatus, BatchItem, BatchSummary, AuthConfig, UserInfo, LoginResponse, TokenVerifyResponse, RegisterRequest, UpdateProfileRequest, CredentialInfo, SummaryData, SummarySection, SummarySectionItem, TreeNode, TreeNodeType, PluginInfo, PluginNavItem, PluginSettings, PluginSettingField, PlatformContext, PlatformEventType, PlatformEvent, ThemeMode, ColorPalette, TableDensity, } from './types';
|
package/dist/index.js
CHANGED
|
@@ -103,47 +103,49 @@ import { default as default52 } from "./components/SampleSelector.vue.js";
|
|
|
103
103
|
/* empty css */
|
|
104
104
|
import { default as default53 } from "./components/GroupingModal.vue.js";
|
|
105
105
|
/* empty css */
|
|
106
|
-
import { default as default54 } from "./components/
|
|
106
|
+
import { default as default54 } from "./components/AutoGroupModal.vue.js";
|
|
107
|
+
/* empty css */
|
|
108
|
+
import { default as default55 } from "./components/GroupAssigner.vue.js";
|
|
107
109
|
/* empty css */
|
|
108
|
-
import { default as
|
|
110
|
+
import { default as default56 } from "./components/MoleculeInput.vue.js";
|
|
109
111
|
/* empty css */
|
|
110
|
-
import { default as
|
|
112
|
+
import { default as default57 } from "./components/ConcentrationInput.vue.js";
|
|
111
113
|
/* empty css */
|
|
112
|
-
import { default as
|
|
114
|
+
import { default as default58 } from "./components/DoseCalculator.vue.js";
|
|
113
115
|
/* empty css */
|
|
114
|
-
import { default as
|
|
116
|
+
import { default as default59 } from "./components/ReagentList.vue.js";
|
|
115
117
|
/* empty css */
|
|
116
|
-
import { default as
|
|
118
|
+
import { default as default60 } from "./components/SampleHierarchyTree.vue.js";
|
|
117
119
|
/* empty css */
|
|
118
|
-
import { default as
|
|
120
|
+
import { default as default61 } from "./components/ProtocolStepEditor.vue.js";
|
|
119
121
|
/* empty css */
|
|
120
|
-
import { default as
|
|
122
|
+
import { default as default62 } from "./components/ScientificNumber.vue.js";
|
|
121
123
|
/* empty css */
|
|
122
|
-
import { default as
|
|
124
|
+
import { default as default63 } from "./components/ChemicalFormula.vue.js";
|
|
123
125
|
/* empty css */
|
|
124
|
-
import { default as
|
|
126
|
+
import { default as default64 } from "./components/FormulaInput.vue.js";
|
|
125
127
|
/* empty css */
|
|
126
|
-
import { default as
|
|
128
|
+
import { default as default65 } from "./components/SequenceInput.vue.js";
|
|
127
129
|
/* empty css */
|
|
128
|
-
import { default as
|
|
130
|
+
import { default as default66 } from "./components/UnitInput.vue.js";
|
|
129
131
|
/* empty css */
|
|
130
|
-
import { default as
|
|
132
|
+
import { default as default67 } from "./components/StepWizard.vue.js";
|
|
131
133
|
/* empty css */
|
|
132
|
-
import { default as
|
|
134
|
+
import { default as default68 } from "./components/AuditTrail.vue.js";
|
|
133
135
|
/* empty css */
|
|
134
|
-
import { default as
|
|
136
|
+
import { default as default69 } from "./components/BatchProgressList.vue.js";
|
|
135
137
|
/* empty css */
|
|
136
|
-
import { default as
|
|
138
|
+
import { default as default70 } from "./components/ExperimentDataViewer.vue.js";
|
|
137
139
|
/* empty css */
|
|
138
|
-
import { default as
|
|
140
|
+
import { default as default71 } from "./components/ExperimentCodeBadge.vue.js";
|
|
139
141
|
/* empty css */
|
|
140
|
-
import { default as
|
|
142
|
+
import { default as default72 } from "./components/DateTimePicker.vue.js";
|
|
141
143
|
/* empty css */
|
|
142
|
-
import { default as
|
|
144
|
+
import { default as default73 } from "./components/TimeRangeInput.vue.js";
|
|
143
145
|
/* empty css */
|
|
144
|
-
import { default as
|
|
146
|
+
import { default as default74 } from "./components/ScheduleCalendar.vue.js";
|
|
145
147
|
/* empty css */
|
|
146
|
-
import { default as
|
|
148
|
+
import { default as default75 } from "./components/ResourceCard.vue.js";
|
|
147
149
|
/* empty css */
|
|
148
150
|
import { useApi } from "./composables/useApi.js";
|
|
149
151
|
import { useAuth } from "./composables/useAuth.js";
|
|
@@ -160,6 +162,7 @@ import { ATOMIC_WEIGHTS, useChemicalFormula } from "./composables/useChemicalFor
|
|
|
160
162
|
import { useSequenceUtils } from "./composables/useSequenceUtils.js";
|
|
161
163
|
import { addMinutes, compareTime, durationMinutes, findAvailableSlots, formatDuration, formatTime, generateTimeSlots, isTimeInRange, parseTime, rangesOverlap, snapToSlot } from "./composables/useTimeUtils.js";
|
|
162
164
|
import { useScheduleDrag } from "./composables/useScheduleDrag.js";
|
|
165
|
+
import { DEFAULT_COLORS, useAutoGroup } from "./composables/useAutoGroup.js";
|
|
163
166
|
import { usePluginConfig } from "./composables/usePluginConfig.js";
|
|
164
167
|
import { useAuthStore } from "./stores/auth.js";
|
|
165
168
|
import { colorPalettes, useSettingsStore } from "./stores/settings.js";
|
|
@@ -170,7 +173,8 @@ export {
|
|
|
170
173
|
default33 as AppLayout,
|
|
171
174
|
default32 as AppSidebar,
|
|
172
175
|
default31 as AppTopBar,
|
|
173
|
-
|
|
176
|
+
default68 as AuditTrail,
|
|
177
|
+
default54 as AutoGroupModal,
|
|
174
178
|
default40 as Avatar,
|
|
175
179
|
default2 as BaseButton,
|
|
176
180
|
default6 as BaseCheckbox,
|
|
@@ -183,61 +187,62 @@ export {
|
|
|
183
187
|
default11 as BaseTabs,
|
|
184
188
|
default4 as BaseTextarea,
|
|
185
189
|
default7 as BaseToggle,
|
|
186
|
-
|
|
190
|
+
default69 as BatchProgressList,
|
|
187
191
|
default42 as Breadcrumb,
|
|
188
192
|
default17 as Calendar,
|
|
189
193
|
default45 as ChartContainer,
|
|
190
|
-
|
|
194
|
+
default63 as ChemicalFormula,
|
|
191
195
|
default30 as CollapsibleCard,
|
|
192
196
|
default10 as ColorSlider,
|
|
193
|
-
|
|
197
|
+
default57 as ConcentrationInput,
|
|
194
198
|
default44 as ConfirmDialog,
|
|
199
|
+
DEFAULT_COLORS,
|
|
195
200
|
default18 as DataFrame,
|
|
196
201
|
default20 as DatePicker,
|
|
197
|
-
|
|
202
|
+
default72 as DateTimePicker,
|
|
198
203
|
default37 as Divider,
|
|
199
|
-
|
|
204
|
+
default58 as DoseCalculator,
|
|
200
205
|
default16 as DropdownButton,
|
|
201
206
|
default41 as EmptyState,
|
|
202
|
-
|
|
203
|
-
|
|
207
|
+
default71 as ExperimentCodeBadge,
|
|
208
|
+
default70 as ExperimentDataViewer,
|
|
204
209
|
default51 as ExperimentTimeline,
|
|
205
210
|
default24 as FileUploader,
|
|
206
211
|
default19 as FormField,
|
|
207
|
-
|
|
208
|
-
|
|
212
|
+
default64 as FormulaInput,
|
|
213
|
+
default55 as GroupAssigner,
|
|
209
214
|
default53 as GroupingModal,
|
|
210
215
|
default27 as IconButton,
|
|
211
216
|
default36 as LoadingSpinner,
|
|
212
217
|
MLDSdk,
|
|
213
|
-
|
|
218
|
+
default56 as MoleculeInput,
|
|
214
219
|
default14 as MultiSelect,
|
|
215
220
|
default23 as NumberInput,
|
|
216
221
|
default50 as PlateMapEditor,
|
|
217
222
|
default39 as ProgressBar,
|
|
218
|
-
|
|
223
|
+
default61 as ProtocolStepEditor,
|
|
219
224
|
default48 as RackEditor,
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
225
|
+
default59 as ReagentList,
|
|
226
|
+
default75 as ResourceCard,
|
|
227
|
+
default60 as SampleHierarchyTree,
|
|
223
228
|
default49 as SampleLegend,
|
|
224
229
|
default52 as SampleSelector,
|
|
225
|
-
|
|
226
|
-
|
|
230
|
+
default74 as ScheduleCalendar,
|
|
231
|
+
default62 as ScientificNumber,
|
|
227
232
|
default13 as SegmentedControl,
|
|
228
|
-
|
|
233
|
+
default65 as SequenceInput,
|
|
229
234
|
default29 as SettingsButton,
|
|
230
235
|
default46 as SettingsModal,
|
|
231
236
|
default35 as Skeleton,
|
|
232
237
|
default38 as StatusIndicator,
|
|
233
|
-
|
|
238
|
+
default67 as StepWizard,
|
|
234
239
|
default22 as TagsInput,
|
|
235
240
|
default28 as ThemeToggle,
|
|
236
241
|
default21 as TimePicker,
|
|
237
|
-
|
|
242
|
+
default73 as TimeRangeInput,
|
|
238
243
|
default26 as ToastNotification,
|
|
239
244
|
default43 as Tooltip,
|
|
240
|
-
|
|
245
|
+
default66 as UnitInput,
|
|
241
246
|
default47 as WellPlate,
|
|
242
247
|
addMinutes,
|
|
243
248
|
colorPalettes,
|
|
@@ -255,6 +260,7 @@ export {
|
|
|
255
260
|
useApi,
|
|
256
261
|
useAuth,
|
|
257
262
|
useAuthStore,
|
|
263
|
+
useAutoGroup,
|
|
258
264
|
useChemicalFormula,
|
|
259
265
|
useConcentrationUnits,
|
|
260
266
|
useDoseCalculator,
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|