@morscherlab/mint-sdk 1.4.11 → 1.4.13
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/dist/{AlertBox-CIhqsWbN.js → AlertBox-CexONPhA.js} +2 -2
- package/dist/{AlertBox-CIhqsWbN.js.map → AlertBox-CexONPhA.js.map} +1 -1
- package/dist/{AppSidebar-DbftYDAY.js → AppSidebar-CIBehlYL.js} +16 -9
- package/dist/{AppSidebar-DbftYDAY.js.map → AppSidebar-CIBehlYL.js.map} +1 -1
- package/dist/{ExperimentPopover-BM92LlrQ.js → ExperimentPopover-CzV1--OY.js} +2 -2
- package/dist/{ExperimentPopover-BM92LlrQ.js.map → ExperimentPopover-CzV1--OY.js.map} +1 -1
- package/dist/{ExperimentSelectorModal-BOLK-Gl4.js → ExperimentSelectorModal-CUkKmgfr.js} +3 -3
- package/dist/{ExperimentSelectorModal-BOLK-Gl4.js.map → ExperimentSelectorModal-CUkKmgfr.js.map} +1 -1
- package/dist/{SegmentedControl-Dz41vAFM.js → SegmentedControl-C-sckoJZ.js} +2 -2
- package/dist/{SegmentedControl-Dz41vAFM.js.map → SegmentedControl-C-sckoJZ.js.map} +1 -1
- package/dist/{SettingsModal-CKWC1JNV.js → SettingsModal-jW7Z4i_1.js} +6 -6
- package/dist/{SettingsModal-CKWC1JNV.js.map → SettingsModal-jW7Z4i_1.js.map} +1 -1
- package/dist/composables/usePluginWorkspace.d.ts +2 -0
- package/dist/{controlSchemaModel-C20f-1_T.js → controlSchemaModel-C_XqpkgE.js} +2 -2
- package/dist/{controlSchemaModel-C20f-1_T.js.map → controlSchemaModel-C_XqpkgE.js.map} +1 -1
- package/dist/{data-C72M20rh.js → data-8G-U6Pb0.js} +9 -9
- package/dist/{data-C72M20rh.js.map → data-8G-U6Pb0.js.map} +1 -1
- package/dist/data.js +7 -7
- package/dist/index.js +16 -16
- package/dist/{install-DbF7ddGl.js → install-CM33AZhf.js} +14 -38
- package/dist/install-CM33AZhf.js.map +1 -0
- package/dist/install.js +1 -1
- package/dist/{lab-B5sKmlWF.js → lab-CPJ7n7e5.js} +37 -166
- package/dist/lab-CPJ7n7e5.js.map +1 -0
- package/dist/lab.js +4 -4
- package/dist/{records-CWRztE5M.js → records-BAymyHAn.js} +10 -110
- package/dist/records-BAymyHAn.js.map +1 -0
- package/dist/{runtime-OBeh3Knt.js → runtime-PntKXQ7K.js} +93 -52
- package/dist/runtime-PntKXQ7K.js.map +1 -0
- package/dist/runtime.js +6 -6
- package/dist/{shell-DDgF2bug.js → shell-B-woqThX.js} +4 -4
- package/dist/{shell-DDgF2bug.js.map → shell-B-woqThX.js.map} +1 -1
- package/dist/shell.js +4 -4
- package/dist/styles.css +61 -105
- package/dist/{useExperimentSamples-Cz2v3V_q.js → useExperimentSamples-DEDAKa2E.js} +3 -3
- package/dist/{useExperimentSamples-Cz2v3V_q.js.map → useExperimentSamples-DEDAKa2E.js.map} +1 -1
- package/dist/{useListReorder-C--K06el.js → useListReorder-W1bzK_bo.js} +2 -2
- package/dist/{useListReorder-C--K06el.js.map → useListReorder-W1bzK_bo.js.map} +1 -1
- package/dist/{useRackEditor-Cba_0OfI.js → useRackEditor-BWOnob3i.js} +154 -25
- package/dist/useRackEditor-BWOnob3i.js.map +1 -0
- package/dist/{useRealtime-CNQbrS01.js → useRealtime-B0u_FvEH.js} +2 -2
- package/dist/{useRealtime-CNQbrS01.js.map → useRealtime-B0u_FvEH.js.map} +1 -1
- package/dist/{useRequest-Bfsh7gIm.js → useRequest-D9-3BS-3.js} +2 -2
- package/dist/{useRequest-Bfsh7gIm.js.map → useRequest-D9-3BS-3.js.map} +1 -1
- package/package.json +1 -1
- package/src/__tests__/components/PluginWorkspaceView.test.ts +19 -0
- package/src/__tests__/styles/menusShellRefresh.test.ts +5 -0
- package/src/components/FileUploader.vue +3 -35
- package/src/components/GeneratedPluginView.vue +35 -81
- package/src/components/GeneratedResultRenderer.vue +2 -1
- package/src/components/PlotlyChart.vue +1 -1
- package/src/components/PluginWorkspaceView.vue +2 -1
- package/src/composables/usePluginWorkspace.ts +14 -3
- package/src/generated-ui/main.ts +3 -1
- package/src/styles/components/alert-box.css +1 -1
- package/src/styles/components/app-sidebar.css +5 -5
- package/src/styles/components/app-top-bar.css +2 -1
- package/src/styles/components/button.css +3 -3
- package/src/styles/components/checkbox.css +1 -1
- package/src/styles/components/collapsible-card.css +1 -1
- package/src/styles/components/confirm-dialog.css +2 -2
- package/src/styles/components/file-uploader.css +3 -3
- package/src/styles/components/icon-button.css +3 -3
- package/src/styles/components/loading-spinner.css +1 -1
- package/src/styles/components/pill.css +1 -1
- package/src/styles/components/plugin-icon.css +1 -1
- package/src/styles/components/presence-avatars.css +4 -4
- package/src/styles/components/progress-bar.css +1 -1
- package/src/styles/components/sequence-input.css +1 -1
- package/src/styles/components/slider.css +1 -1
- package/src/styles/components/toggle.css +1 -1
- package/src/styles/variables.css +4 -0
- package/dist/install-DbF7ddGl.js.map +0 -1
- package/dist/lab-B5sKmlWF.js.map +0 -1
- package/dist/records-CWRztE5M.js.map +0 -1
- package/dist/runtime-OBeh3Knt.js.map +0 -1
- package/dist/useRackEditor-Cba_0OfI.js.map +0 -1
package/dist/shell.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { i as useEventListener, r as useFocusTrap } from "./useDropdownState-uFIz6Yv8.js";
|
|
2
|
-
import { E as useMenuKeyboard, H as useListSelection, R as useRovingFocus, U as useSelectionLimit } from "./records-
|
|
3
|
-
import { B as compareSortValues, V as useSortedItems, i as useReorderAnnouncer, n as reorderList, r as useListReorder, t as REORDER_ANNOUNCER_STYLE } from "./useListReorder-
|
|
4
|
-
import { C as usePluginWorkspace, S as AppLayout_default, _ as provideOnboarding, f as AppTopBar_default, g as defineOnboarding, h as ONBOARDING_KEY, m as ANCHOR_WAIT_MS, t as AppSidebar_default, v as useOnboarding } from "./AppSidebar-
|
|
2
|
+
import { E as useMenuKeyboard, H as useListSelection, R as useRovingFocus, U as useSelectionLimit } from "./records-BAymyHAn.js";
|
|
3
|
+
import { B as compareSortValues, V as useSortedItems, i as useReorderAnnouncer, n as reorderList, r as useListReorder, t as REORDER_ANNOUNCER_STYLE } from "./useListReorder-W1bzK_bo.js";
|
|
4
|
+
import { C as usePluginWorkspace, S as AppLayout_default, _ as provideOnboarding, f as AppTopBar_default, g as defineOnboarding, h as ONBOARDING_KEY, m as ANCHOR_WAIT_MS, t as AppSidebar_default, v as useOnboarding } from "./AppSidebar-CIBehlYL.js";
|
|
5
5
|
import { t as useDebouncedWatch } from "./useDebouncedWatch-BPwyl6eS.js";
|
|
6
6
|
import { t as useExpansionSet } from "./useExpansionSet-CvoNMZJi.js";
|
|
7
|
-
import { a as useManualLayoutResize, i as resizedVerticalSplitPercent, n as resizedLeadingPanelWidth, o as LayoutResizeHandle_default, r as resizedTrailingPanelWidth } from "./shell-
|
|
7
|
+
import { a as useManualLayoutResize, i as resizedVerticalSplitPercent, n as resizedLeadingPanelWidth, o as LayoutResizeHandle_default, r as resizedTrailingPanelWidth } from "./shell-B-woqThX.js";
|
|
8
8
|
export { ANCHOR_WAIT_MS, AppLayout_default as AppLayout, AppSidebar_default as AppSidebar, AppTopBar_default as AppTopBar, LayoutResizeHandle_default as LayoutResizeHandle, ONBOARDING_KEY, REORDER_ANNOUNCER_STYLE, compareSortValues, defineOnboarding, provideOnboarding, reorderList, resizedLeadingPanelWidth, resizedTrailingPanelWidth, resizedVerticalSplitPercent, useDebouncedWatch, useEventListener, useExpansionSet, useFocusTrap, useListReorder, useListSelection, useManualLayoutResize, useMenuKeyboard, useOnboarding, usePluginWorkspace, useReorderAnnouncer, useRovingFocus, useSelectionLimit, useSortedItems };
|
package/dist/styles.css
CHANGED
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
background: transparent;
|
|
19
19
|
}
|
|
20
20
|
|
|
21
|
-
.mint-plotly-chart__plot[data-v-
|
|
21
|
+
.mint-plotly-chart__plot[data-v-8d1b6790] {
|
|
22
22
|
width: 100%;
|
|
23
23
|
min-height: 24rem;
|
|
24
24
|
}
|
|
@@ -26,18 +26,18 @@
|
|
|
26
26
|
/* Plotly fills the hover label's trace-name box from plot/paper bgcolor combined over
|
|
27
27
|
white (inline style, no hoverlabel option), so it stays light in dark mode. The token
|
|
28
28
|
follows the theme; in light mode it resolves to the same white. */
|
|
29
|
-
.mint-plotly-chart__plot[data-v-
|
|
29
|
+
.mint-plotly-chart__plot[data-v-8d1b6790] .hovertext rect {
|
|
30
30
|
fill: var(--bg-card) !important;
|
|
31
31
|
}
|
|
32
|
-
.mint-plotly-chart__error[data-v-
|
|
32
|
+
.mint-plotly-chart__error[data-v-8d1b6790] {
|
|
33
33
|
margin: 0;
|
|
34
34
|
padding: 1rem;
|
|
35
35
|
border: 1px solid var(--mint-error-border);
|
|
36
|
-
border-radius:
|
|
36
|
+
border-radius: var(--radius-lg);
|
|
37
37
|
background: var(--mint-error-bg);
|
|
38
38
|
color: var(--mint-error-hover);
|
|
39
39
|
}
|
|
40
|
-
.mint-plotly-chart__error[data-v-
|
|
40
|
+
.mint-plotly-chart__error[data-v-8d1b6790] p {
|
|
41
41
|
margin: 0;
|
|
42
42
|
}
|
|
43
43
|
|
|
@@ -48,42 +48,43 @@
|
|
|
48
48
|
margin: 0 auto;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
-
.mint-generated-result[data-v-
|
|
51
|
+
.mint-generated-result[data-v-2406c0cc] {
|
|
52
52
|
width: 100%;
|
|
53
53
|
}
|
|
54
|
-
.mint-generated-result__text[data-v-
|
|
55
|
-
.mint-generated-result__json[data-v-
|
|
54
|
+
.mint-generated-result__text[data-v-2406c0cc],
|
|
55
|
+
.mint-generated-result__json[data-v-2406c0cc] {
|
|
56
56
|
margin: 0;
|
|
57
57
|
color: var(--text-primary);
|
|
58
58
|
}
|
|
59
|
-
.mint-generated-result__text[data-v-
|
|
59
|
+
.mint-generated-result__text[data-v-2406c0cc] {
|
|
60
60
|
max-width: 72ch;
|
|
61
61
|
white-space: pre-wrap;
|
|
62
62
|
line-height: 1.65;
|
|
63
63
|
}
|
|
64
|
-
.mint-generated-result__json[data-v-
|
|
64
|
+
.mint-generated-result__json[data-v-2406c0cc] {
|
|
65
65
|
overflow: auto;
|
|
66
66
|
padding: 0.75rem 1rem;
|
|
67
67
|
border-radius: var(--radius-md);
|
|
68
68
|
background: var(--bg-tertiary);
|
|
69
|
+
font-family: var(--font-mono);
|
|
69
70
|
font-size: 0.8125rem;
|
|
70
71
|
line-height: 1.55;
|
|
71
72
|
white-space: pre-wrap;
|
|
72
73
|
}
|
|
73
|
-
.mint-generated-result__image[data-v-
|
|
74
|
+
.mint-generated-result__image[data-v-2406c0cc] {
|
|
74
75
|
display: block;
|
|
75
76
|
max-width: 100%;
|
|
76
77
|
height: auto;
|
|
77
78
|
margin: 0 auto;
|
|
78
79
|
}
|
|
79
|
-
.mint-generated-result__artifact[data-v-
|
|
80
|
+
.mint-generated-result__artifact[data-v-2406c0cc] {
|
|
80
81
|
display: flex;
|
|
81
82
|
align-items: center;
|
|
82
83
|
justify-content: space-between;
|
|
83
84
|
gap: 1rem;
|
|
84
85
|
padding: 1rem;
|
|
85
86
|
border: 1px solid var(--border-color);
|
|
86
|
-
border-radius:
|
|
87
|
+
border-radius: var(--radius-lg);
|
|
87
88
|
color: var(--color-primary);
|
|
88
89
|
text-decoration: none;
|
|
89
90
|
}
|
|
@@ -121,77 +122,27 @@
|
|
|
121
122
|
overflow-wrap: anywhere;
|
|
122
123
|
}
|
|
123
124
|
|
|
124
|
-
.mint-generated-workspace[data-v-
|
|
125
|
-
position: relative;
|
|
125
|
+
.mint-generated-workspace[data-v-90271c34] {
|
|
126
126
|
min-width: 0;
|
|
127
|
-
min-height:
|
|
128
|
-
|
|
129
|
-
background: var(--bg-primary);
|
|
127
|
+
min-height: 0;
|
|
128
|
+
overflow-y: auto;
|
|
130
129
|
}
|
|
131
|
-
.mint-generated-workspace__loading[data-v-
|
|
130
|
+
.mint-generated-workspace__loading[data-v-90271c34] {
|
|
132
131
|
display: flex;
|
|
133
|
-
|
|
132
|
+
flex: 1;
|
|
134
133
|
align-items: center;
|
|
135
134
|
justify-content: center;
|
|
136
135
|
gap: 0.75rem;
|
|
137
136
|
color: var(--text-secondary);
|
|
138
137
|
}
|
|
139
|
-
.mint-generated-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
justify-content: space-between;
|
|
143
|
-
gap: 1.5rem;
|
|
144
|
-
max-width: 76rem;
|
|
145
|
-
margin: 0 auto 1.25rem;
|
|
146
|
-
}
|
|
147
|
-
.mint-generated-workspace__header h1[data-v-c8ff991b] {
|
|
148
|
-
margin: 0;
|
|
149
|
-
color: var(--text-primary);
|
|
150
|
-
font-size: clamp(1.35rem, 2vw, 1.8rem);
|
|
151
|
-
line-height: 1.2;
|
|
152
|
-
}
|
|
153
|
-
.mint-generated-workspace__header p[data-v-c8ff991b]:not(.mint-generated-workspace__eyebrow) {
|
|
154
|
-
margin: 0.4rem 0 0;
|
|
155
|
-
color: var(--text-secondary);
|
|
156
|
-
}
|
|
157
|
-
.mint-generated-workspace__eyebrow[data-v-c8ff991b] {
|
|
158
|
-
margin: 0 0 0.35rem;
|
|
159
|
-
color: var(--text-secondary);
|
|
160
|
-
font-size: 0.72rem;
|
|
161
|
-
font-weight: 700;
|
|
162
|
-
}
|
|
163
|
-
.mint-generated-workspace__resources[data-v-c8ff991b] {
|
|
164
|
-
display: flex;
|
|
165
|
-
flex-wrap: wrap;
|
|
166
|
-
justify-content: flex-end;
|
|
167
|
-
gap: 0.4rem;
|
|
168
|
-
}
|
|
169
|
-
.mint-generated-workspace__resources span[data-v-c8ff991b] {
|
|
170
|
-
padding: 0.3rem 0.55rem;
|
|
171
|
-
border: 1px solid var(--border-color);
|
|
172
|
-
border-radius: 999px;
|
|
173
|
-
background: var(--bg-secondary);
|
|
174
|
-
color: var(--text-secondary);
|
|
138
|
+
.mint-generated-workspace__resources[data-v-90271c34] {
|
|
139
|
+
color: var(--text-muted);
|
|
140
|
+
font-family: var(--font-mono);
|
|
175
141
|
font-size: 0.75rem;
|
|
176
|
-
font-weight: 600;
|
|
177
|
-
}
|
|
178
|
-
.mint-generated-workspace__result[data-v-c8ff991b] {
|
|
179
|
-
max-width: 76rem;
|
|
180
|
-
min-height: 24rem;
|
|
181
|
-
margin: 0 auto;
|
|
182
|
-
padding: clamp(1rem, 2vw, 1.75rem);
|
|
183
|
-
border: 1px solid var(--border-color);
|
|
184
|
-
border-radius: 1rem;
|
|
185
|
-
background: var(--bg-secondary);
|
|
186
|
-
box-shadow: var(--shadow-sm);
|
|
187
|
-
}
|
|
188
|
-
@media (max-width: 640px) {
|
|
189
|
-
.mint-generated-workspace__header[data-v-c8ff991b] {
|
|
190
|
-
flex-direction: column;
|
|
191
|
-
}
|
|
192
|
-
.mint-generated-workspace__resources[data-v-c8ff991b] {
|
|
193
|
-
justify-content: flex-start;
|
|
194
142
|
}
|
|
143
|
+
.mint-generated-workspace__description[data-v-90271c34] {
|
|
144
|
+
margin: 0 0 var(--mint-gutter);
|
|
145
|
+
color: var(--text-secondary);
|
|
195
146
|
}
|
|
196
147
|
|
|
197
148
|
.mint-component-binding-renderer[data-v-eeb93cc7] {
|
|
@@ -368,6 +319,10 @@
|
|
|
368
319
|
--mint-primary: var(--color-primary);
|
|
369
320
|
/* Text and icons on an accent fill (filled buttons, Save). */
|
|
370
321
|
--text-on-accent: #FFFFFF;
|
|
322
|
+
/* Text on a --mint-error fill (danger buttons); white in both themes, 3.76:1 on #EF4444. */
|
|
323
|
+
--text-on-danger: #FFFFFF;
|
|
324
|
+
/* Knob of a toggle or slider, and the mark of a disabled checkbox; white in both themes. */
|
|
325
|
+
--control-knob: #FFFFFF;
|
|
371
326
|
/* Retired hues, aliased to the accent until 1.5 (mint doctor warns on use). */
|
|
372
327
|
--color-cta: var(--color-primary);
|
|
373
328
|
--color-cta-hover: var(--color-primary-hover);
|
|
@@ -1467,7 +1422,7 @@ button, input, select, textarea {
|
|
|
1467
1422
|
.mint-alert__icon--info { background-color: var(--mint-info-bg); color: var(--mint-info); }
|
|
1468
1423
|
.mint-alert__icon--neutral { background-color: var(--bg-tertiary); color: var(--text-secondary); }
|
|
1469
1424
|
.mint-alert__icon--primary { background-color: var(--color-primary-soft); color: var(--color-primary); }
|
|
1470
|
-
.mint-alert__icon--cta { background-color: var(--color-primary-soft); color: var(--
|
|
1425
|
+
.mint-alert__icon--cta { background-color: var(--color-primary-soft); color: var(--_ink-primary); }
|
|
1471
1426
|
|
|
1472
1427
|
.mint-alert__content {
|
|
1473
1428
|
flex: 1;
|
|
@@ -1851,8 +1806,8 @@ button, input, select, textarea {
|
|
|
1851
1806
|
min-width: 1.375rem;
|
|
1852
1807
|
padding: 0.125rem 0.375rem;
|
|
1853
1808
|
border-radius: var(--radius);
|
|
1854
|
-
background: color-mix(in srgb, var(--color-
|
|
1855
|
-
color: var(--color-
|
|
1809
|
+
background: color-mix(in srgb, var(--color-primary) 14%, transparent);
|
|
1810
|
+
color: var(--color-primary);
|
|
1856
1811
|
font-size: 0.6875rem;
|
|
1857
1812
|
font-weight: 700;
|
|
1858
1813
|
line-height: 1.1;
|
|
@@ -2123,7 +2078,7 @@ button, input, select, textarea {
|
|
|
2123
2078
|
width: 11px;
|
|
2124
2079
|
height: 11px;
|
|
2125
2080
|
border-radius: 9999px;
|
|
2126
|
-
background:
|
|
2081
|
+
background: var(--control-knob);
|
|
2127
2082
|
box-shadow: var(--shadow-sm);
|
|
2128
2083
|
transition: left 180ms var(--mint-ease-out-quart);
|
|
2129
2084
|
}
|
|
@@ -2223,7 +2178,7 @@ button, input, select, textarea {
|
|
|
2223
2178
|
padding: 0 0.25rem;
|
|
2224
2179
|
border-radius: var(--radius);
|
|
2225
2180
|
background: var(--mint-sidebar-tone);
|
|
2226
|
-
color:
|
|
2181
|
+
color: var(--text-on-accent);
|
|
2227
2182
|
font-size: 0.6875rem;
|
|
2228
2183
|
font-weight: 700;
|
|
2229
2184
|
line-height: 1rem;
|
|
@@ -2246,7 +2201,7 @@ button, input, select, textarea {
|
|
|
2246
2201
|
.mint-sidebar__rail-badge--cta,
|
|
2247
2202
|
.mint-sidebar__tag--cta,
|
|
2248
2203
|
.mint-sidebar__group-action--cta {
|
|
2249
|
-
--mint-sidebar-tone: var(--color-
|
|
2204
|
+
--mint-sidebar-tone: var(--color-primary);
|
|
2250
2205
|
}
|
|
2251
2206
|
|
|
2252
2207
|
.mint-sidebar__rail-badge--success,
|
|
@@ -2469,7 +2424,8 @@ button, input, select, textarea {
|
|
|
2469
2424
|
.mint-topbar__plugin-name,
|
|
2470
2425
|
.mint-topbar__plugin-subtitle,
|
|
2471
2426
|
.mint-topbar-title,
|
|
2472
|
-
.mint-topbar-subtitle
|
|
2427
|
+
.mint-topbar-subtitle,
|
|
2428
|
+
.mint-topbar__title-only {
|
|
2473
2429
|
overflow: hidden;
|
|
2474
2430
|
text-overflow: ellipsis;
|
|
2475
2431
|
white-space: nowrap;
|
|
@@ -2762,17 +2718,17 @@ button, input, select, textarea {
|
|
|
2762
2718
|
}
|
|
2763
2719
|
|
|
2764
2720
|
.mint-button--cta {
|
|
2765
|
-
background-color: var(--color-
|
|
2721
|
+
background-color: var(--color-primary);
|
|
2766
2722
|
color: var(--text-on-accent);
|
|
2767
2723
|
}
|
|
2768
2724
|
|
|
2769
2725
|
.mint-button--cta:hover:not(.mint-button--disabled) {
|
|
2770
|
-
background-color: var(--color-
|
|
2726
|
+
background-color: var(--color-primary-hover);
|
|
2771
2727
|
}
|
|
2772
2728
|
|
|
2773
2729
|
.mint-button--danger {
|
|
2774
2730
|
background-color: var(--mint-error);
|
|
2775
|
-
color:
|
|
2731
|
+
color: var(--text-on-danger);
|
|
2776
2732
|
}
|
|
2777
2733
|
|
|
2778
2734
|
.mint-button--danger:hover:not(.mint-button--disabled) {
|
|
@@ -3009,7 +2965,7 @@ button, input, select, textarea {
|
|
|
3009
2965
|
.mint-checkbox__native:disabled + .mint-checkbox__box.mint-checkbox__box--indeterminate {
|
|
3010
2966
|
background-color: var(--text-muted);
|
|
3011
2967
|
border-color: var(--text-muted);
|
|
3012
|
-
color:
|
|
2968
|
+
color: var(--control-knob);
|
|
3013
2969
|
}
|
|
3014
2970
|
|
|
3015
2971
|
.mint-checkbox__box--sm {
|
|
@@ -3238,7 +3194,7 @@ button, input, select, textarea {
|
|
|
3238
3194
|
|
|
3239
3195
|
.mint-collapsible-card__badge--cta,
|
|
3240
3196
|
.mint-collapsible-card__action--cta {
|
|
3241
|
-
--mint-sidebar-badge-color: var(--color-
|
|
3197
|
+
--mint-sidebar-badge-color: var(--color-primary);
|
|
3242
3198
|
}
|
|
3243
3199
|
|
|
3244
3200
|
.mint-collapsible-card__badge--success,
|
|
@@ -3887,9 +3843,9 @@ button, input, select, textarea {
|
|
|
3887
3843
|
font-size: 0.6875rem;
|
|
3888
3844
|
font-weight: 700;
|
|
3889
3845
|
font-family: var(--font-mono);
|
|
3890
|
-
color: var(--
|
|
3891
|
-
background-color:
|
|
3892
|
-
border: 1px solid
|
|
3846
|
+
color: var(--text-secondary);
|
|
3847
|
+
background-color: var(--bg-tertiary);
|
|
3848
|
+
border: 1px solid var(--border-color);
|
|
3893
3849
|
}
|
|
3894
3850
|
|
|
3895
3851
|
.mint-file-uploader__file-meta {
|
|
@@ -4161,17 +4117,17 @@ button, input, select, textarea {
|
|
|
4161
4117
|
}
|
|
4162
4118
|
|
|
4163
4119
|
.mint-icon-button--cta {
|
|
4164
|
-
background-color: var(--color-
|
|
4120
|
+
background-color: var(--color-primary);
|
|
4165
4121
|
color: var(--text-on-accent);
|
|
4166
4122
|
}
|
|
4167
4123
|
|
|
4168
4124
|
.mint-icon-button--cta:hover:not(.mint-icon-button--disabled) {
|
|
4169
|
-
background-color: var(--color-
|
|
4125
|
+
background-color: var(--color-primary-hover);
|
|
4170
4126
|
}
|
|
4171
4127
|
|
|
4172
4128
|
.mint-icon-button--danger {
|
|
4173
4129
|
background-color: var(--mint-error);
|
|
4174
|
-
color:
|
|
4130
|
+
color: var(--text-on-danger);
|
|
4175
4131
|
}
|
|
4176
4132
|
|
|
4177
4133
|
.mint-icon-button--danger:hover:not(.mint-icon-button--disabled) {
|
|
@@ -7408,7 +7364,7 @@ button.mint-section-card__row:hover {
|
|
|
7408
7364
|
box-sizing: border-box;
|
|
7409
7365
|
transform: translateX(-50%) translateY(-50%);
|
|
7410
7366
|
border-radius: 9999px;
|
|
7411
|
-
background-color:
|
|
7367
|
+
background-color: var(--control-knob);
|
|
7412
7368
|
border: 1px solid color-mix(in srgb, var(--text-secondary) 40%, transparent);
|
|
7413
7369
|
box-shadow: var(--shadow-sm);
|
|
7414
7370
|
pointer-events: none;
|
|
@@ -8219,7 +8175,7 @@ html.dark .mint-toast__item {
|
|
|
8219
8175
|
top: 50%;
|
|
8220
8176
|
left: 2px;
|
|
8221
8177
|
border-radius: 9999px;
|
|
8222
|
-
background-color:
|
|
8178
|
+
background-color: var(--control-knob);
|
|
8223
8179
|
box-shadow: var(--shadow-sm);
|
|
8224
8180
|
transition: transform 180ms cubic-bezier(0.25, 1, 0.5, 1);
|
|
8225
8181
|
pointer-events: none;
|
|
@@ -11224,7 +11180,7 @@ html.dark .sg-summary code { background: rgba(255, 255, 255, 0.1); }
|
|
|
11224
11180
|
(soft-tint background, dot, outline border); `--mint-pill-ink` the text. A
|
|
11225
11181
|
`color` prop sets `--mint-pill-tone` inline. */
|
|
11226
11182
|
.mint-pill--primary { --mint-pill-tone: var(--color-primary); --mint-pill-ink: var(--color-primary-hover); }
|
|
11227
|
-
.mint-pill--cta { --mint-pill-tone: var(--color-
|
|
11183
|
+
.mint-pill--cta { --mint-pill-tone: var(--color-primary); --mint-pill-ink: var(--color-primary-hover); }
|
|
11228
11184
|
.mint-pill--success { --mint-pill-tone: var(--mint-success); --mint-pill-ink: var(--mint-success-hover); }
|
|
11229
11185
|
.mint-pill--warning { --mint-pill-tone: var(--mint-warning); --mint-pill-ink: var(--mint-warning-text); }
|
|
11230
11186
|
.mint-pill--error { --mint-pill-tone: var(--mint-error); --mint-pill-ink: var(--mint-error-hover); }
|
|
@@ -12348,7 +12304,7 @@ html.dark .mint-dataframe__loading {
|
|
|
12348
12304
|
|
|
12349
12305
|
/* Tones */
|
|
12350
12306
|
.mint-spinner--primary { color: var(--color-primary); }
|
|
12351
|
-
.mint-spinner--cta { color: var(--color-
|
|
12307
|
+
.mint-spinner--cta { color: var(--color-primary); }
|
|
12352
12308
|
.mint-spinner--success { color: var(--mint-success); }
|
|
12353
12309
|
.mint-spinner--warning { color: var(--mint-warning); }
|
|
12354
12310
|
.mint-spinner--error { color: var(--mint-error); }
|
|
@@ -12505,7 +12461,7 @@ html.dark .mint-dataframe__loading {
|
|
|
12505
12461
|
.mint-progress__bar--success { background-color: var(--mint-success); }
|
|
12506
12462
|
.mint-progress__bar--warning { background-color: var(--mint-warning); }
|
|
12507
12463
|
.mint-progress__bar--error { background-color: var(--mint-error); }
|
|
12508
|
-
.mint-progress__bar--cta { background-color: var(--color-
|
|
12464
|
+
.mint-progress__bar--cta { background-color: var(--color-primary); }
|
|
12509
12465
|
.mint-progress__bar--neutral { background-color: var(--text-muted); }
|
|
12510
12466
|
.mint-progress__bar--info { background-color: var(--color-primary); } /* 6b: progress fill is always primary; --mint-info is for the running dot */
|
|
12511
12467
|
|
|
@@ -12601,19 +12557,19 @@ html.dark .mint-dataframe__loading {
|
|
|
12601
12557
|
.mint-avatar__status--offline { background-color: var(--text-muted); }
|
|
12602
12558
|
/* PresenceAvatars: an avatar stack that opens a list of who is here.
|
|
12603
12559
|
* The editing cue is a ring plus a pencil badge, so it does not depend on
|
|
12604
|
-
* colour only. Light mode uses --color-
|
|
12605
|
-
* mode --color-
|
|
12560
|
+
* colour only. Light mode uses --color-primary-hover (3:1 on the card), dark
|
|
12561
|
+
* mode --color-primary. --mint-presence-surface is the colour the avatars are
|
|
12606
12562
|
* cut out of; set it when the stack sits on another surface. */
|
|
12607
12563
|
|
|
12608
12564
|
.mint-presence {
|
|
12609
|
-
--mint-presence-editing: var(--color-
|
|
12565
|
+
--mint-presence-editing: var(--color-primary-hover);
|
|
12610
12566
|
--mint-presence-surface: var(--bg-secondary);
|
|
12611
12567
|
position: relative;
|
|
12612
12568
|
display: inline-flex;
|
|
12613
12569
|
}
|
|
12614
12570
|
|
|
12615
12571
|
:where(html.dark) .mint-presence {
|
|
12616
|
-
--mint-presence-editing: var(--color-
|
|
12572
|
+
--mint-presence-editing: var(--color-primary);
|
|
12617
12573
|
}
|
|
12618
12574
|
|
|
12619
12575
|
.mint-presence__trigger {
|
|
@@ -13151,8 +13107,8 @@ html.dark .mint-dataframe__loading {
|
|
|
13151
13107
|
}
|
|
13152
13108
|
|
|
13153
13109
|
.mint-confirm__icon--cta {
|
|
13154
|
-
background-color: color-mix(in srgb, var(--color-
|
|
13155
|
-
color: var(--color-
|
|
13110
|
+
background-color: color-mix(in srgb, var(--color-primary) 12%, transparent);
|
|
13111
|
+
color: var(--color-primary);
|
|
13156
13112
|
}
|
|
13157
13113
|
|
|
13158
13114
|
.mint-confirm__icon--neutral {
|
|
@@ -14847,7 +14803,7 @@ html.dark .mint-stale-banner {
|
|
|
14847
14803
|
.mint-sequence-input__problem--error .mint-sequence-input__problem-shape { fill: var(--mint-error); }
|
|
14848
14804
|
|
|
14849
14805
|
.mint-sequence-input__problem-mark {
|
|
14850
|
-
stroke:
|
|
14806
|
+
stroke: var(--text-on-danger);
|
|
14851
14807
|
stroke-width: 1.6;
|
|
14852
14808
|
stroke-linecap: round;
|
|
14853
14809
|
}
|
|
@@ -18360,7 +18316,7 @@ button.mint-unit-input__unit:focus-visible {
|
|
|
18360
18316
|
/* Tones (deprecated with the tone/color props, removed in 1.5): the v2 tile no longer reads the variable. */
|
|
18361
18317
|
.mint-plugin-icon--neutral { --mint-plugin-icon-tone: var(--text-secondary); }
|
|
18362
18318
|
.mint-plugin-icon--primary { --mint-plugin-icon-tone: var(--color-primary); }
|
|
18363
|
-
.mint-plugin-icon--cta { --mint-plugin-icon-tone: var(--color-
|
|
18319
|
+
.mint-plugin-icon--cta { --mint-plugin-icon-tone: var(--color-primary); }
|
|
18364
18320
|
.mint-plugin-icon--success { --mint-plugin-icon-tone: var(--mint-success); }
|
|
18365
18321
|
.mint-plugin-icon--warning { --mint-plugin-icon-tone: var(--mint-warning); }
|
|
18366
18322
|
.mint-plugin-icon--error { --mint-plugin-icon-tone: var(--mint-error); }
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { o as useApi, r as readErrorMessage } from "./experiment-DyO54FQB.js";
|
|
2
|
-
import { _ as APP_EXPERIMENT_KEY, a as parseExperimentId, t as isRecord } from "./records-
|
|
3
|
-
import { t as useRequest } from "./useRequest-
|
|
2
|
+
import { _ as APP_EXPERIMENT_KEY, a as parseExperimentId, t as isRecord } from "./records-BAymyHAn.js";
|
|
3
|
+
import { t as useRequest } from "./useRequest-D9-3BS-3.js";
|
|
4
4
|
import { computed, inject, ref, shallowRef, toValue, watch } from "vue";
|
|
5
5
|
//#region src/composables/experimentDesignData.ts
|
|
6
6
|
function isPlatformDesignDataResponse(value) {
|
|
@@ -405,4 +405,4 @@ function useExperimentSamples(options = {}) {
|
|
|
405
405
|
//#endregion
|
|
406
406
|
export { readTableFileAsCsv as a, useExperimentData as c, unwrapExperimentDesignData as d, readFileAsText as i, extractSampleNamesFromDesignData as l, detectDelimiter as n, useFileImport as o, parseDelimitedText as r, validateImportFile as s, useExperimentSamples as t, extractSampleOptionsFromDesignData as u };
|
|
407
407
|
|
|
408
|
-
//# sourceMappingURL=useExperimentSamples-
|
|
408
|
+
//# sourceMappingURL=useExperimentSamples-DEDAKa2E.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"useExperimentSamples-Cz2v3V_q.js","names":[],"sources":["../src/composables/experimentDesignData.ts","../src/composables/useExperimentData.ts","../src/composables/useFileImport.ts","../src/composables/useExperimentSamples.ts"],"sourcesContent":["import type { SelectOption } from '../types'\nimport { isRecord } from '../utils/records'\n\nexport interface ExperimentDesignDataResponse {\n experiment_id?: number\n plugin_id?: string\n data?: Record<string, unknown>\n schema_version?: string\n updated_at?: string | null\n}\n\nexport interface ExtractExperimentSamplesOptions {\n includeControls?: boolean\n}\n\n\nfunction isPlatformDesignDataResponse(value: Record<string, unknown>): boolean {\n return (\n 'data' in value\n && (\n 'experiment_id' in value\n || 'plugin_id' in value\n || 'schema_version' in value\n || 'updated_at' in value\n )\n )\n}\n\n/** Return the plugin-defined design_data payload from common platform and plugin response shapes. */\nexport function unwrapExperimentDesignData(\n rawData: Record<string, unknown> | null | undefined,\n): Record<string, unknown> | null {\n if (!rawData) return null\n\n if (isRecord(rawData.data) && isPlatformDesignDataResponse(rawData)) {\n return rawData.data\n }\n\n if (isRecord(rawData.design_data)) {\n return rawData.design_data\n }\n\n if (isRecord(rawData.designData)) {\n return rawData.designData\n }\n\n return rawData\n}\n\nfunction shouldIncludeSample(record: Record<string, unknown>, options: ExtractExperimentSamplesOptions): boolean {\n if (options.includeControls) return true\n const rawType = record.sample_type ?? record.sampleType ?? record.type ?? record.well_type ?? record.wellType\n const type = typeof rawType === 'string' ? rawType.toLowerCase() : ''\n return !['blank', 'qc'].includes(type)\n}\n\nfunction readSampleValue(record: Record<string, unknown>): string | null {\n const candidates = [\n record.sample_name,\n record.sampleName,\n record.sample_id,\n record.sampleId,\n record.name,\n record.id,\n record.label,\n ]\n\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim()) {\n return candidate\n }\n if (typeof candidate === 'number' && Number.isFinite(candidate)) {\n return String(candidate)\n }\n }\n\n return null\n}\n\nfunction readSampleLabel(record: Record<string, unknown>, fallback: string): string {\n const label = record.name ?? record.label ?? record.sample_name ?? record.sampleName\n return typeof label === 'string' && label.trim() ? label : fallback\n}\n\nfunction readSampleDescription(record: Record<string, unknown>): string | undefined {\n const parts = [\n record.group,\n record.batch,\n record.batch_id,\n record.batchId,\n record.plate_id,\n record.plateId,\n record.well_id,\n record.wellId,\n ].filter((value): value is string | number =>\n (typeof value === 'string' && value.trim().length > 0)\n || typeof value === 'number',\n )\n\n return parts.length > 0 ? parts.map(String).join(' / ') : undefined\n}\n\nfunction addSampleRecord(\n options: SelectOption<string>[],\n seen: Set<string>,\n value: unknown,\n extractOptions: ExtractExperimentSamplesOptions,\n): void {\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (trimmed && !seen.has(trimmed)) {\n seen.add(trimmed)\n options.push({ value: trimmed, label: trimmed })\n }\n return\n }\n\n if (!isRecord(value) || !shouldIncludeSample(value, extractOptions)) return\n\n const sampleValue = readSampleValue(value)\n if (!sampleValue || seen.has(sampleValue)) return\n\n seen.add(sampleValue)\n options.push({\n value: sampleValue,\n label: readSampleLabel(value, sampleValue),\n description: readSampleDescription(value),\n })\n}\n\nfunction addSampleArray(\n options: SelectOption<string>[],\n seen: Set<string>,\n value: unknown,\n extractOptions: ExtractExperimentSamplesOptions,\n): void {\n if (!Array.isArray(value)) return\n for (const sample of value) {\n addSampleRecord(options, seen, sample, extractOptions)\n }\n}\n\n/** Extract selectable sample options from raw or wrapped experiment design_data. */\nexport function extractSampleOptionsFromDesignData(\n rawData: Record<string, unknown> | null | undefined,\n options: ExtractExperimentSamplesOptions = {},\n): SelectOption<string>[] {\n const designData = unwrapExperimentDesignData(rawData)\n if (!designData) return []\n\n const sampleOptions: SelectOption<string>[] = []\n const seen = new Set<string>()\n\n addSampleArray(sampleOptions, seen, designData.samples, options)\n\n if (isRecord(designData.templates)) {\n for (const template of Object.values(designData.templates)) {\n if (!isRecord(template)) continue\n const templateData = isRecord(template.data) ? template.data : template\n addSampleArray(sampleOptions, seen, templateData.samples, options)\n }\n }\n\n if (Array.isArray(designData.plates)) {\n for (const plate of designData.plates) {\n if (!isRecord(plate)) continue\n addSampleArray(sampleOptions, seen, plate.samples, options)\n }\n }\n\n return sampleOptions\n}\n\n/** Extract SampleSelector-compatible string values from raw or wrapped experiment design_data. */\nexport function extractSampleNamesFromDesignData(\n rawData: Record<string, unknown> | null | undefined,\n options: ExtractExperimentSamplesOptions = {},\n): string[] {\n return extractSampleOptionsFromDesignData(rawData, options).map(sample => sample.value)\n}\n","import { shallowRef, computed, type Ref, type ComputedRef } from 'vue'\nimport { useApi, type UseApiReturn } from './useApi'\nimport { useRequest } from './useRequest'\nimport {\n extractSampleNamesFromDesignData,\n extractSampleOptionsFromDesignData,\n unwrapExperimentDesignData,\n} from './experimentDesignData'\nimport type { TreeNode, SummaryData, SelectOption } from '../types'\n\nexport interface UseExperimentDataOptions {\n apiBaseUrl?: string\n immediate?: boolean\n}\n\nexport interface UseExperimentDataReturn {\n /** Raw experiment data response from `/experiments/{id}/data`, or null. */\n data: Ref<Record<string, unknown> | null>\n /** Plugin-defined design_data payload unwrapped from platform response shapes, or null. */\n designData: ComputedRef<Record<string, unknown> | null>\n /** Sample values extracted from design_data for SampleSelector-style components. */\n sampleNames: ComputedRef<string[]>\n /** Sample options extracted from design_data for select/dropdown components. */\n sampleOptions: ComputedRef<SelectOption<string>[]>\n /** Hierarchy tree rows normalised from `tree_data` or `treeData`. */\n treeData: ComputedRef<TreeNode[]>\n /** Table rows normalised from `table_data` or `tableData`. */\n tableData: ComputedRef<Record<string, unknown>[]>\n /** Summary payload normalised from `summary_data` or `summaryData`, or null. */\n summaryData: ComputedRef<SummaryData | null>\n /** Whether experiment data is currently loading. */\n isLoading: Ref<boolean>\n /** Error message from the last failed fetch, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful experiment data fetch, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Fetch experiment data for an experiment id. */\n fetch: (experimentId: number) => Promise<Record<string, unknown> | null>\n /** Refetch the most recently fetched experiment id. */\n refresh: () => Promise<void>\n /** Clear local experiment data and current fetch target. */\n clear: () => void\n}\n\n/** Fetches and normalises experiment output data (tree, table, summary) from the platform API. */\nexport function useExperimentData(\n options: UseExperimentDataOptions = {},\n): UseExperimentDataReturn {\n const data = shallowRef<Record<string, unknown> | null>(null)\n const request = useRequest('Failed to fetch experiment data')\n const isLoading = request.isLoading\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n let lastExperimentId: number | null = null\n let api: UseApiReturn | null = null\n\n function getApi(): UseApiReturn {\n api ??= useApi({ baseUrl: options.apiBaseUrl })\n return api\n }\n\n const designData = computed<Record<string, unknown> | null>(() =>\n unwrapExperimentDesignData(data.value),\n )\n\n const sampleNames = computed<string[]>(() =>\n extractSampleNamesFromDesignData(designData.value),\n )\n\n const sampleOptions = computed<SelectOption<string>[]>(() =>\n extractSampleOptionsFromDesignData(designData.value),\n )\n\n const treeData = computed<TreeNode[]>(() => {\n if (!designData.value) return []\n const tree = designData.value.tree_data ?? designData.value.treeData\n return Array.isArray(tree) ? tree as TreeNode[] : []\n })\n\n const tableData = computed<Record<string, unknown>[]>(() => {\n if (!designData.value) return []\n const table = designData.value.table_data ?? designData.value.tableData\n return Array.isArray(table) ? table as Record<string, unknown>[] : []\n })\n\n const summaryData = computed<SummaryData | null>(() => {\n if (!designData.value) return null\n const summary = designData.value.summary_data ?? designData.value.summaryData\n if (summary && typeof summary === 'object' && 'metadata' in (summary as Record<string, unknown>)) {\n return summary as SummaryData\n }\n return null\n })\n\n async function fetchData(experimentId: number): Promise<Record<string, unknown> | null> {\n lastExperimentId = experimentId\n try {\n data.value = await request.run(\n () => getApi().get<Record<string, unknown>>(`/experiments/${experimentId}/data`),\n { kind: 'load', errorMessage: 'Failed to fetch experiment data' },\n )\n return data.value\n } catch {\n data.value = null\n return null\n }\n }\n\n async function refresh(): Promise<void> {\n if (lastExperimentId !== null) {\n await fetchData(lastExperimentId)\n }\n }\n\n function clear(): void {\n data.value = null\n lastExperimentId = null\n request.clearError()\n }\n\n return {\n data,\n designData,\n sampleNames,\n sampleOptions,\n treeData,\n tableData,\n summaryData,\n isLoading,\n error,\n lastLoadedAt,\n fetch: fetchData,\n refresh,\n clear,\n }\n}\n","import { ref, shallowRef, type Ref, type ShallowRef } from 'vue'\nimport type { SheetData } from 'read-excel-file/universal'\nimport { readErrorMessage } from '../utils/errors'\n\nexport interface DelimitedTable {\n columns: string[]\n rows: Record<string, string>[]\n rawRows: string[][]\n delimiter: string\n}\n\nexport interface ParseDelimitedTextOptions {\n delimiter?: string\n headers?: readonly string[]\n hasHeaderRow?: boolean\n trim?: boolean\n}\n\nexport interface FileImportValidationOptions {\n accept?: string | readonly string[]\n maxSizeBytes?: number\n}\n\nexport interface FileImportOptions<TResult = string> extends FileImportValidationOptions {\n encoding?: string\n parse?: (text: string, file: File) => TResult | Promise<TResult>\n}\n\nexport interface UseFileImportReturn<TResult> {\n loading: ShallowRef<boolean>\n error: Ref<string | null>\n fileName: Ref<string>\n result: Ref<TResult | null>\n importFile: (file: File) => Promise<TResult>\n clear: () => void\n}\n\n/** Stateful file reader for plugin import flows with shared validation and error handling. */\nexport function useFileImport<TResult = string>(\n options: FileImportOptions<TResult> = {},\n): UseFileImportReturn<TResult> {\n const loading = shallowRef(false)\n const error = ref<string | null>(null)\n const fileName = ref('')\n const result = ref<TResult | null>(null) as Ref<TResult | null>\n\n function clear(): void {\n loading.value = false\n error.value = null\n fileName.value = ''\n result.value = null\n }\n\n async function importFile(file: File): Promise<TResult> {\n loading.value = true\n error.value = null\n fileName.value = file.name\n\n try {\n validateImportFile(file, options)\n const text = await readFileAsText(file, options.encoding)\n const parsed = options.parse\n ? await options.parse(text, file)\n : text as TResult\n result.value = parsed\n return parsed\n } catch (err) {\n const message = readErrorMessage(err, 'Failed to import file.')\n error.value = message\n throw err\n } finally {\n loading.value = false\n }\n }\n\n return {\n loading,\n error,\n fileName,\n result,\n importFile,\n clear,\n }\n}\n\nexport function validateImportFile(file: File, options: FileImportValidationOptions = {}): void {\n if (options.maxSizeBytes !== undefined && file.size > options.maxSizeBytes) {\n throw new Error(`File is too large. Maximum size is ${formatBytes(options.maxSizeBytes)}.`)\n }\n\n const accept = normalizeAccept(options.accept)\n if (accept.length === 0) return\n\n const name = file.name.toLowerCase()\n const type = file.type.toLowerCase()\n const matches = accept.some((entry) => {\n if (entry.startsWith('.')) return name.endsWith(entry)\n if (entry.endsWith('/*')) return type.startsWith(entry.slice(0, -1))\n return type === entry\n })\n\n if (!matches) {\n throw new Error(`Unsupported file type. Expected ${accept.join(', ')}.`)\n }\n}\n\nexport function readFileAsText(file: File, encoding?: string): Promise<string> {\n if (typeof FileReader === 'undefined' && typeof file.text === 'function') {\n return file.text()\n }\n\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.onload = () => resolve(String(reader.result ?? ''))\n reader.onerror = () => reject(reader.error ?? new Error('Failed to read file.'))\n reader.readAsText(file, encoding)\n })\n}\n\n/**\n * Read a `.csv`, `.tsv` or `.xlsx` upload as comma-delimited CSV text.\n * A `.csv` file (or any other extension) comes back unchanged. An `.xlsx`\n * file gives its first sheet; each cell is its stored value, so number\n * formats such as leading zeros are not applied. Dates become ISO text.\n */\nexport async function readTableFileAsCsv(file: File): Promise<string> {\n const name = file.name.toLowerCase()\n if (name.endsWith('.xlsx')) return rowsToCsv(await readFirstSheet(file))\n const text = await readFileAsText(file)\n return name.endsWith('.tsv') ? rowsToCsv(parseDelimitedRows(text, '\\t')) : text\n}\n\nasync function readFirstSheet(file: File): Promise<string[][]> {\n // Lazy import: plugins that never read .xlsx do not load the library.\n const { readSheet } = await import('read-excel-file/universal')\n let rows: SheetData<string>\n try {\n // Keep the stored text: no trim, and no float parse that rounds big numbers.\n rows = await readSheet(file, { trim: false, parseNumber: text => text })\n } catch {\n throw new Error(`${file.name} is not a valid .xlsx workbook.`)\n }\n return rows.map(row => row.map(formatCell))\n}\n\nfunction formatCell(value: unknown): string {\n if (value === null || value === undefined) return ''\n if (typeof value === 'boolean') return value ? 'TRUE' : 'FALSE'\n if (value instanceof Date) {\n // Excel stores dates as float day counts; round off the float error.\n const [date, time] = new Date(Math.round(value.getTime() / 1000) * 1000)\n .toISOString().slice(0, 19).split('T')\n if (date === '1899-12-30') return time // a time-only cell\n return time === '00:00:00' ? date : `${date}T${time}`\n }\n return String(value)\n}\n\nfunction rowsToCsv(rows: readonly (readonly string[])[]): string {\n return rows.map(row => row.map(quoteCsvField).join(',')).join('\\n')\n}\n\nfunction quoteCsvField(value: string): string {\n return /[\",\\r\\n]/.test(value) ? `\"${value.replace(/\"/g, '\"\"')}\"` : value\n}\n\nexport function parseDelimitedText(\n text: string,\n options: ParseDelimitedTextOptions = {},\n): DelimitedTable {\n const trim = options.trim ?? true\n const delimiter = options.delimiter ?? detectDelimiter(text)\n const rawRows = parseDelimitedRows(text, delimiter)\n .filter(row => row.some(cell => cell.trim().length > 0))\n .map(row => trim ? row.map(cell => cell.trim()) : row)\n\n const hasHeaderRow = options.hasHeaderRow ?? !options.headers\n const columns = options.headers\n ? [...options.headers]\n : hasHeaderRow\n ? rawRows[0] ?? []\n : createColumnNames(maxRowLength(rawRows))\n\n const dataRows = hasHeaderRow && !options.headers ? rawRows.slice(1) : rawRows\n const rows = dataRows.map(row => Object.fromEntries(\n columns.map((column, index) => [column, row[index] ?? '']),\n ))\n\n return {\n columns,\n rows,\n rawRows,\n delimiter,\n }\n}\n\nexport function detectDelimiter(text: string): string {\n const firstLine = text.split(/\\r?\\n/, 1)[0] ?? ''\n const commaCount = countChar(firstLine, ',')\n const tabCount = countChar(firstLine, '\\t')\n const semicolonCount = countChar(firstLine, ';')\n if (tabCount > commaCount && tabCount >= semicolonCount) return '\\t'\n if (semicolonCount > commaCount) return ';'\n return ','\n}\n\nfunction parseDelimitedRows(text: string, delimiter: string): string[][] {\n const rows: string[][] = []\n let row: string[] = []\n let field = ''\n let quoted = false\n\n for (let index = 0; index < text.length; index++) {\n const char = text[index]\n const next = text[index + 1]\n\n if (char === '\"') {\n if (quoted && next === '\"') {\n field += '\"'\n index++\n } else if (quoted || field === '') {\n quoted = !quoted\n } else {\n field += '\"' // a quote inside an unquoted field is text\n }\n continue\n }\n\n if (!quoted && char === delimiter) {\n row.push(field)\n field = ''\n continue\n }\n\n if (!quoted && (char === '\\n' || char === '\\r')) {\n if (char === '\\r' && next === '\\n') index++\n row.push(field)\n rows.push(row)\n row = []\n field = ''\n continue\n }\n\n field += char\n }\n\n row.push(field)\n rows.push(row)\n return rows\n}\n\nfunction normalizeAccept(accept: string | readonly string[] | undefined): string[] {\n if (!accept) return []\n const entries = typeof accept === 'string' ? accept.split(',') : [...accept]\n return entries\n .map((entry: string) => entry.trim().toLowerCase())\n .filter(Boolean)\n}\n\nfunction createColumnNames(count: number): string[] {\n return Array.from({ length: count }, (_, index) => `column_${index + 1}`)\n}\n\nfunction maxRowLength(rows: readonly string[][]): number {\n return rows.reduce((max, row) => Math.max(max, row.length), 0)\n}\n\nfunction countChar(value: string, char: string): number {\n return [...value].filter(candidate => candidate === char).length\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`\n return `${Math.round(bytes / (1024 * 1024))} MB`\n}\n","import {\n computed,\n inject,\n toValue,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n} from 'vue'\nimport type { SelectOption } from '../types'\nimport { APP_EXPERIMENT_KEY } from './useAppExperiment'\nimport {\n extractSampleNamesFromDesignData,\n extractSampleOptionsFromDesignData,\n unwrapExperimentDesignData,\n type ExtractExperimentSamplesOptions,\n} from './experimentDesignData'\nimport { parseExperimentId } from './platformContextHelpers'\nimport { useExperimentData } from './useExperimentData'\n\nexport type ExperimentIdSource = MaybeRefOrGetter<number | string | null | undefined>\nexport type ExperimentDesignDataSource = MaybeRefOrGetter<Record<string, unknown> | null | undefined>\n\nexport interface UseExperimentSamplesOptions extends ExtractExperimentSamplesOptions {\n /** Experiment id to load from `/experiments/{id}/data`; defaults to provided AppExperiment context. */\n experimentId?: ExperimentIdSource\n /** Pre-fetched design_data or full platform design-data response. */\n designData?: ExperimentDesignDataSource\n /** API base URL override for platform calls. */\n apiBaseUrl?: string\n /** Auto-load when an experiment id becomes available. Defaults to true. */\n immediate?: boolean\n /** Enable or disable automatic loading while keeping derived samples reactive. Defaults to true. */\n enabled?: MaybeRefOrGetter<boolean>\n /** Use `useAppExperiment` provided state when `experimentId` is not set. Defaults to true. */\n syncAppExperiment?: boolean\n}\n\nexport interface UseExperimentSamplesReturn {\n /** Experiment id currently used for automatic sample loading. */\n experimentId: ComputedRef<number | undefined>\n /** Raw `/experiments/{id}/data` response when loaded through the platform API. */\n data: Ref<Record<string, unknown> | null>\n /** Plugin-defined design_data payload from props or platform response. */\n designData: ComputedRef<Record<string, unknown> | null>\n /** SampleSelector-compatible string values extracted from design_data. */\n samples: ComputedRef<string[]>\n /** Select/dropdown-friendly sample options extracted from design_data. */\n sampleOptions: ComputedRef<SelectOption<string>[]>\n isLoading: Ref<boolean>\n error: Ref<string | null>\n lastLoadedAt: Ref<Date | null>\n /** Fetch samples for a specific experiment id, defaulting to the resolved id. */\n fetch: (experimentId?: number | string | null) => Promise<Record<string, unknown> | null>\n /** Refetch the current experiment id. */\n refresh: () => Promise<void>\n /** Clear fetched platform data. */\n clear: () => void\n}\n\n/** Loads experiment design_data and derives samples for SampleSelector-style UIs. */\nexport function useExperimentSamples(\n options: UseExperimentSamplesOptions = {},\n): UseExperimentSamplesReturn {\n const appExperiment = options.syncAppExperiment === false\n ? undefined\n : inject(APP_EXPERIMENT_KEY, undefined)\n const experimentData = useExperimentData({ apiBaseUrl: options.apiBaseUrl })\n\n const experimentId = computed<number | undefined>(() => {\n const explicitId = parseExperimentId(toValue(options.experimentId))\n return explicitId ?? parseExperimentId(appExperiment?.experimentId.value)\n })\n\n const explicitDesignData = computed<Record<string, unknown> | null>(() =>\n unwrapExperimentDesignData(toValue(options.designData) ?? null),\n )\n\n const designData = computed<Record<string, unknown> | null>(() =>\n explicitDesignData.value ?? experimentData.designData.value,\n )\n\n const extractOptions = computed<ExtractExperimentSamplesOptions>(() => ({\n includeControls: options.includeControls,\n }))\n\n const samples = computed<string[]>(() =>\n extractSampleNamesFromDesignData(designData.value, extractOptions.value),\n )\n\n const sampleOptions = computed<SelectOption<string>[]>(() =>\n extractSampleOptionsFromDesignData(designData.value, extractOptions.value),\n )\n\n const enabled = computed(() => toValue(options.enabled) ?? true)\n\n async function fetchSamples(\n id: number | string | null | undefined = experimentId.value,\n ): Promise<Record<string, unknown> | null> {\n const parsedId = parseExperimentId(id)\n if (parsedId === undefined) {\n experimentData.clear()\n return null\n }\n return experimentData.fetch(parsedId)\n }\n\n watch(\n () => ({\n designData: explicitDesignData.value,\n enabled: enabled.value,\n experimentId: experimentId.value,\n }),\n ({ designData: currentDesignData, enabled: isEnabled, experimentId: currentExperimentId }) => {\n if (options.immediate === false || !isEnabled) return\n if (currentDesignData) {\n experimentData.clear()\n return\n }\n if (currentExperimentId === undefined) {\n experimentData.clear()\n return\n }\n void experimentData.fetch(currentExperimentId)\n },\n { immediate: options.immediate !== false },\n )\n\n return {\n experimentId,\n data: experimentData.data,\n designData,\n samples,\n sampleOptions,\n isLoading: experimentData.isLoading,\n error: experimentData.error,\n lastLoadedAt: experimentData.lastLoadedAt,\n fetch: fetchSamples,\n refresh: experimentData.refresh,\n clear: experimentData.clear,\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"useExperimentSamples-DEDAKa2E.js","names":[],"sources":["../src/composables/experimentDesignData.ts","../src/composables/useExperimentData.ts","../src/composables/useFileImport.ts","../src/composables/useExperimentSamples.ts"],"sourcesContent":["import type { SelectOption } from '../types'\nimport { isRecord } from '../utils/records'\n\nexport interface ExperimentDesignDataResponse {\n experiment_id?: number\n plugin_id?: string\n data?: Record<string, unknown>\n schema_version?: string\n updated_at?: string | null\n}\n\nexport interface ExtractExperimentSamplesOptions {\n includeControls?: boolean\n}\n\n\nfunction isPlatformDesignDataResponse(value: Record<string, unknown>): boolean {\n return (\n 'data' in value\n && (\n 'experiment_id' in value\n || 'plugin_id' in value\n || 'schema_version' in value\n || 'updated_at' in value\n )\n )\n}\n\n/** Return the plugin-defined design_data payload from common platform and plugin response shapes. */\nexport function unwrapExperimentDesignData(\n rawData: Record<string, unknown> | null | undefined,\n): Record<string, unknown> | null {\n if (!rawData) return null\n\n if (isRecord(rawData.data) && isPlatformDesignDataResponse(rawData)) {\n return rawData.data\n }\n\n if (isRecord(rawData.design_data)) {\n return rawData.design_data\n }\n\n if (isRecord(rawData.designData)) {\n return rawData.designData\n }\n\n return rawData\n}\n\nfunction shouldIncludeSample(record: Record<string, unknown>, options: ExtractExperimentSamplesOptions): boolean {\n if (options.includeControls) return true\n const rawType = record.sample_type ?? record.sampleType ?? record.type ?? record.well_type ?? record.wellType\n const type = typeof rawType === 'string' ? rawType.toLowerCase() : ''\n return !['blank', 'qc'].includes(type)\n}\n\nfunction readSampleValue(record: Record<string, unknown>): string | null {\n const candidates = [\n record.sample_name,\n record.sampleName,\n record.sample_id,\n record.sampleId,\n record.name,\n record.id,\n record.label,\n ]\n\n for (const candidate of candidates) {\n if (typeof candidate === 'string' && candidate.trim()) {\n return candidate\n }\n if (typeof candidate === 'number' && Number.isFinite(candidate)) {\n return String(candidate)\n }\n }\n\n return null\n}\n\nfunction readSampleLabel(record: Record<string, unknown>, fallback: string): string {\n const label = record.name ?? record.label ?? record.sample_name ?? record.sampleName\n return typeof label === 'string' && label.trim() ? label : fallback\n}\n\nfunction readSampleDescription(record: Record<string, unknown>): string | undefined {\n const parts = [\n record.group,\n record.batch,\n record.batch_id,\n record.batchId,\n record.plate_id,\n record.plateId,\n record.well_id,\n record.wellId,\n ].filter((value): value is string | number =>\n (typeof value === 'string' && value.trim().length > 0)\n || typeof value === 'number',\n )\n\n return parts.length > 0 ? parts.map(String).join(' / ') : undefined\n}\n\nfunction addSampleRecord(\n options: SelectOption<string>[],\n seen: Set<string>,\n value: unknown,\n extractOptions: ExtractExperimentSamplesOptions,\n): void {\n if (typeof value === 'string') {\n const trimmed = value.trim()\n if (trimmed && !seen.has(trimmed)) {\n seen.add(trimmed)\n options.push({ value: trimmed, label: trimmed })\n }\n return\n }\n\n if (!isRecord(value) || !shouldIncludeSample(value, extractOptions)) return\n\n const sampleValue = readSampleValue(value)\n if (!sampleValue || seen.has(sampleValue)) return\n\n seen.add(sampleValue)\n options.push({\n value: sampleValue,\n label: readSampleLabel(value, sampleValue),\n description: readSampleDescription(value),\n })\n}\n\nfunction addSampleArray(\n options: SelectOption<string>[],\n seen: Set<string>,\n value: unknown,\n extractOptions: ExtractExperimentSamplesOptions,\n): void {\n if (!Array.isArray(value)) return\n for (const sample of value) {\n addSampleRecord(options, seen, sample, extractOptions)\n }\n}\n\n/** Extract selectable sample options from raw or wrapped experiment design_data. */\nexport function extractSampleOptionsFromDesignData(\n rawData: Record<string, unknown> | null | undefined,\n options: ExtractExperimentSamplesOptions = {},\n): SelectOption<string>[] {\n const designData = unwrapExperimentDesignData(rawData)\n if (!designData) return []\n\n const sampleOptions: SelectOption<string>[] = []\n const seen = new Set<string>()\n\n addSampleArray(sampleOptions, seen, designData.samples, options)\n\n if (isRecord(designData.templates)) {\n for (const template of Object.values(designData.templates)) {\n if (!isRecord(template)) continue\n const templateData = isRecord(template.data) ? template.data : template\n addSampleArray(sampleOptions, seen, templateData.samples, options)\n }\n }\n\n if (Array.isArray(designData.plates)) {\n for (const plate of designData.plates) {\n if (!isRecord(plate)) continue\n addSampleArray(sampleOptions, seen, plate.samples, options)\n }\n }\n\n return sampleOptions\n}\n\n/** Extract SampleSelector-compatible string values from raw or wrapped experiment design_data. */\nexport function extractSampleNamesFromDesignData(\n rawData: Record<string, unknown> | null | undefined,\n options: ExtractExperimentSamplesOptions = {},\n): string[] {\n return extractSampleOptionsFromDesignData(rawData, options).map(sample => sample.value)\n}\n","import { shallowRef, computed, type Ref, type ComputedRef } from 'vue'\nimport { useApi, type UseApiReturn } from './useApi'\nimport { useRequest } from './useRequest'\nimport {\n extractSampleNamesFromDesignData,\n extractSampleOptionsFromDesignData,\n unwrapExperimentDesignData,\n} from './experimentDesignData'\nimport type { TreeNode, SummaryData, SelectOption } from '../types'\n\nexport interface UseExperimentDataOptions {\n apiBaseUrl?: string\n immediate?: boolean\n}\n\nexport interface UseExperimentDataReturn {\n /** Raw experiment data response from `/experiments/{id}/data`, or null. */\n data: Ref<Record<string, unknown> | null>\n /** Plugin-defined design_data payload unwrapped from platform response shapes, or null. */\n designData: ComputedRef<Record<string, unknown> | null>\n /** Sample values extracted from design_data for SampleSelector-style components. */\n sampleNames: ComputedRef<string[]>\n /** Sample options extracted from design_data for select/dropdown components. */\n sampleOptions: ComputedRef<SelectOption<string>[]>\n /** Hierarchy tree rows normalised from `tree_data` or `treeData`. */\n treeData: ComputedRef<TreeNode[]>\n /** Table rows normalised from `table_data` or `tableData`. */\n tableData: ComputedRef<Record<string, unknown>[]>\n /** Summary payload normalised from `summary_data` or `summaryData`, or null. */\n summaryData: ComputedRef<SummaryData | null>\n /** Whether experiment data is currently loading. */\n isLoading: Ref<boolean>\n /** Error message from the last failed fetch, or null. */\n error: Ref<string | null>\n /** Timestamp of the last successful experiment data fetch, or null. */\n lastLoadedAt: Ref<Date | null>\n /** Fetch experiment data for an experiment id. */\n fetch: (experimentId: number) => Promise<Record<string, unknown> | null>\n /** Refetch the most recently fetched experiment id. */\n refresh: () => Promise<void>\n /** Clear local experiment data and current fetch target. */\n clear: () => void\n}\n\n/** Fetches and normalises experiment output data (tree, table, summary) from the platform API. */\nexport function useExperimentData(\n options: UseExperimentDataOptions = {},\n): UseExperimentDataReturn {\n const data = shallowRef<Record<string, unknown> | null>(null)\n const request = useRequest('Failed to fetch experiment data')\n const isLoading = request.isLoading\n const error = request.error\n const lastLoadedAt = request.lastLoadedAt\n let lastExperimentId: number | null = null\n let api: UseApiReturn | null = null\n\n function getApi(): UseApiReturn {\n api ??= useApi({ baseUrl: options.apiBaseUrl })\n return api\n }\n\n const designData = computed<Record<string, unknown> | null>(() =>\n unwrapExperimentDesignData(data.value),\n )\n\n const sampleNames = computed<string[]>(() =>\n extractSampleNamesFromDesignData(designData.value),\n )\n\n const sampleOptions = computed<SelectOption<string>[]>(() =>\n extractSampleOptionsFromDesignData(designData.value),\n )\n\n const treeData = computed<TreeNode[]>(() => {\n if (!designData.value) return []\n const tree = designData.value.tree_data ?? designData.value.treeData\n return Array.isArray(tree) ? tree as TreeNode[] : []\n })\n\n const tableData = computed<Record<string, unknown>[]>(() => {\n if (!designData.value) return []\n const table = designData.value.table_data ?? designData.value.tableData\n return Array.isArray(table) ? table as Record<string, unknown>[] : []\n })\n\n const summaryData = computed<SummaryData | null>(() => {\n if (!designData.value) return null\n const summary = designData.value.summary_data ?? designData.value.summaryData\n if (summary && typeof summary === 'object' && 'metadata' in (summary as Record<string, unknown>)) {\n return summary as SummaryData\n }\n return null\n })\n\n async function fetchData(experimentId: number): Promise<Record<string, unknown> | null> {\n lastExperimentId = experimentId\n try {\n data.value = await request.run(\n () => getApi().get<Record<string, unknown>>(`/experiments/${experimentId}/data`),\n { kind: 'load', errorMessage: 'Failed to fetch experiment data' },\n )\n return data.value\n } catch {\n data.value = null\n return null\n }\n }\n\n async function refresh(): Promise<void> {\n if (lastExperimentId !== null) {\n await fetchData(lastExperimentId)\n }\n }\n\n function clear(): void {\n data.value = null\n lastExperimentId = null\n request.clearError()\n }\n\n return {\n data,\n designData,\n sampleNames,\n sampleOptions,\n treeData,\n tableData,\n summaryData,\n isLoading,\n error,\n lastLoadedAt,\n fetch: fetchData,\n refresh,\n clear,\n }\n}\n","import { ref, shallowRef, type Ref, type ShallowRef } from 'vue'\nimport type { SheetData } from 'read-excel-file/universal'\nimport { readErrorMessage } from '../utils/errors'\n\nexport interface DelimitedTable {\n columns: string[]\n rows: Record<string, string>[]\n rawRows: string[][]\n delimiter: string\n}\n\nexport interface ParseDelimitedTextOptions {\n delimiter?: string\n headers?: readonly string[]\n hasHeaderRow?: boolean\n trim?: boolean\n}\n\nexport interface FileImportValidationOptions {\n accept?: string | readonly string[]\n maxSizeBytes?: number\n}\n\nexport interface FileImportOptions<TResult = string> extends FileImportValidationOptions {\n encoding?: string\n parse?: (text: string, file: File) => TResult | Promise<TResult>\n}\n\nexport interface UseFileImportReturn<TResult> {\n loading: ShallowRef<boolean>\n error: Ref<string | null>\n fileName: Ref<string>\n result: Ref<TResult | null>\n importFile: (file: File) => Promise<TResult>\n clear: () => void\n}\n\n/** Stateful file reader for plugin import flows with shared validation and error handling. */\nexport function useFileImport<TResult = string>(\n options: FileImportOptions<TResult> = {},\n): UseFileImportReturn<TResult> {\n const loading = shallowRef(false)\n const error = ref<string | null>(null)\n const fileName = ref('')\n const result = ref<TResult | null>(null) as Ref<TResult | null>\n\n function clear(): void {\n loading.value = false\n error.value = null\n fileName.value = ''\n result.value = null\n }\n\n async function importFile(file: File): Promise<TResult> {\n loading.value = true\n error.value = null\n fileName.value = file.name\n\n try {\n validateImportFile(file, options)\n const text = await readFileAsText(file, options.encoding)\n const parsed = options.parse\n ? await options.parse(text, file)\n : text as TResult\n result.value = parsed\n return parsed\n } catch (err) {\n const message = readErrorMessage(err, 'Failed to import file.')\n error.value = message\n throw err\n } finally {\n loading.value = false\n }\n }\n\n return {\n loading,\n error,\n fileName,\n result,\n importFile,\n clear,\n }\n}\n\nexport function validateImportFile(file: File, options: FileImportValidationOptions = {}): void {\n if (options.maxSizeBytes !== undefined && file.size > options.maxSizeBytes) {\n throw new Error(`File is too large. Maximum size is ${formatBytes(options.maxSizeBytes)}.`)\n }\n\n const accept = normalizeAccept(options.accept)\n if (accept.length === 0) return\n\n const name = file.name.toLowerCase()\n const type = file.type.toLowerCase()\n const matches = accept.some((entry) => {\n if (entry.startsWith('.')) return name.endsWith(entry)\n if (entry.endsWith('/*')) return type.startsWith(entry.slice(0, -1))\n return type === entry\n })\n\n if (!matches) {\n throw new Error(`Unsupported file type. Expected ${accept.join(', ')}.`)\n }\n}\n\nexport function readFileAsText(file: File, encoding?: string): Promise<string> {\n if (typeof FileReader === 'undefined' && typeof file.text === 'function') {\n return file.text()\n }\n\n return new Promise((resolve, reject) => {\n const reader = new FileReader()\n reader.onload = () => resolve(String(reader.result ?? ''))\n reader.onerror = () => reject(reader.error ?? new Error('Failed to read file.'))\n reader.readAsText(file, encoding)\n })\n}\n\n/**\n * Read a `.csv`, `.tsv` or `.xlsx` upload as comma-delimited CSV text.\n * A `.csv` file (or any other extension) comes back unchanged. An `.xlsx`\n * file gives its first sheet; each cell is its stored value, so number\n * formats such as leading zeros are not applied. Dates become ISO text.\n */\nexport async function readTableFileAsCsv(file: File): Promise<string> {\n const name = file.name.toLowerCase()\n if (name.endsWith('.xlsx')) return rowsToCsv(await readFirstSheet(file))\n const text = await readFileAsText(file)\n return name.endsWith('.tsv') ? rowsToCsv(parseDelimitedRows(text, '\\t')) : text\n}\n\nasync function readFirstSheet(file: File): Promise<string[][]> {\n // Lazy import: plugins that never read .xlsx do not load the library.\n const { readSheet } = await import('read-excel-file/universal')\n let rows: SheetData<string>\n try {\n // Keep the stored text: no trim, and no float parse that rounds big numbers.\n rows = await readSheet(file, { trim: false, parseNumber: text => text })\n } catch {\n throw new Error(`${file.name} is not a valid .xlsx workbook.`)\n }\n return rows.map(row => row.map(formatCell))\n}\n\nfunction formatCell(value: unknown): string {\n if (value === null || value === undefined) return ''\n if (typeof value === 'boolean') return value ? 'TRUE' : 'FALSE'\n if (value instanceof Date) {\n // Excel stores dates as float day counts; round off the float error.\n const [date, time] = new Date(Math.round(value.getTime() / 1000) * 1000)\n .toISOString().slice(0, 19).split('T')\n if (date === '1899-12-30') return time // a time-only cell\n return time === '00:00:00' ? date : `${date}T${time}`\n }\n return String(value)\n}\n\nfunction rowsToCsv(rows: readonly (readonly string[])[]): string {\n return rows.map(row => row.map(quoteCsvField).join(',')).join('\\n')\n}\n\nfunction quoteCsvField(value: string): string {\n return /[\",\\r\\n]/.test(value) ? `\"${value.replace(/\"/g, '\"\"')}\"` : value\n}\n\nexport function parseDelimitedText(\n text: string,\n options: ParseDelimitedTextOptions = {},\n): DelimitedTable {\n const trim = options.trim ?? true\n const delimiter = options.delimiter ?? detectDelimiter(text)\n const rawRows = parseDelimitedRows(text, delimiter)\n .filter(row => row.some(cell => cell.trim().length > 0))\n .map(row => trim ? row.map(cell => cell.trim()) : row)\n\n const hasHeaderRow = options.hasHeaderRow ?? !options.headers\n const columns = options.headers\n ? [...options.headers]\n : hasHeaderRow\n ? rawRows[0] ?? []\n : createColumnNames(maxRowLength(rawRows))\n\n const dataRows = hasHeaderRow && !options.headers ? rawRows.slice(1) : rawRows\n const rows = dataRows.map(row => Object.fromEntries(\n columns.map((column, index) => [column, row[index] ?? '']),\n ))\n\n return {\n columns,\n rows,\n rawRows,\n delimiter,\n }\n}\n\nexport function detectDelimiter(text: string): string {\n const firstLine = text.split(/\\r?\\n/, 1)[0] ?? ''\n const commaCount = countChar(firstLine, ',')\n const tabCount = countChar(firstLine, '\\t')\n const semicolonCount = countChar(firstLine, ';')\n if (tabCount > commaCount && tabCount >= semicolonCount) return '\\t'\n if (semicolonCount > commaCount) return ';'\n return ','\n}\n\nfunction parseDelimitedRows(text: string, delimiter: string): string[][] {\n const rows: string[][] = []\n let row: string[] = []\n let field = ''\n let quoted = false\n\n for (let index = 0; index < text.length; index++) {\n const char = text[index]\n const next = text[index + 1]\n\n if (char === '\"') {\n if (quoted && next === '\"') {\n field += '\"'\n index++\n } else if (quoted || field === '') {\n quoted = !quoted\n } else {\n field += '\"' // a quote inside an unquoted field is text\n }\n continue\n }\n\n if (!quoted && char === delimiter) {\n row.push(field)\n field = ''\n continue\n }\n\n if (!quoted && (char === '\\n' || char === '\\r')) {\n if (char === '\\r' && next === '\\n') index++\n row.push(field)\n rows.push(row)\n row = []\n field = ''\n continue\n }\n\n field += char\n }\n\n row.push(field)\n rows.push(row)\n return rows\n}\n\nfunction normalizeAccept(accept: string | readonly string[] | undefined): string[] {\n if (!accept) return []\n const entries = typeof accept === 'string' ? accept.split(',') : [...accept]\n return entries\n .map((entry: string) => entry.trim().toLowerCase())\n .filter(Boolean)\n}\n\nfunction createColumnNames(count: number): string[] {\n return Array.from({ length: count }, (_, index) => `column_${index + 1}`)\n}\n\nfunction maxRowLength(rows: readonly string[][]): number {\n return rows.reduce((max, row) => Math.max(max, row.length), 0)\n}\n\nfunction countChar(value: string, char: string): number {\n return [...value].filter(candidate => candidate === char).length\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) return `${bytes} B`\n if (bytes < 1024 * 1024) return `${Math.round(bytes / 1024)} KB`\n return `${Math.round(bytes / (1024 * 1024))} MB`\n}\n","import {\n computed,\n inject,\n toValue,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n} from 'vue'\nimport type { SelectOption } from '../types'\nimport { APP_EXPERIMENT_KEY } from './useAppExperiment'\nimport {\n extractSampleNamesFromDesignData,\n extractSampleOptionsFromDesignData,\n unwrapExperimentDesignData,\n type ExtractExperimentSamplesOptions,\n} from './experimentDesignData'\nimport { parseExperimentId } from './platformContextHelpers'\nimport { useExperimentData } from './useExperimentData'\n\nexport type ExperimentIdSource = MaybeRefOrGetter<number | string | null | undefined>\nexport type ExperimentDesignDataSource = MaybeRefOrGetter<Record<string, unknown> | null | undefined>\n\nexport interface UseExperimentSamplesOptions extends ExtractExperimentSamplesOptions {\n /** Experiment id to load from `/experiments/{id}/data`; defaults to provided AppExperiment context. */\n experimentId?: ExperimentIdSource\n /** Pre-fetched design_data or full platform design-data response. */\n designData?: ExperimentDesignDataSource\n /** API base URL override for platform calls. */\n apiBaseUrl?: string\n /** Auto-load when an experiment id becomes available. Defaults to true. */\n immediate?: boolean\n /** Enable or disable automatic loading while keeping derived samples reactive. Defaults to true. */\n enabled?: MaybeRefOrGetter<boolean>\n /** Use `useAppExperiment` provided state when `experimentId` is not set. Defaults to true. */\n syncAppExperiment?: boolean\n}\n\nexport interface UseExperimentSamplesReturn {\n /** Experiment id currently used for automatic sample loading. */\n experimentId: ComputedRef<number | undefined>\n /** Raw `/experiments/{id}/data` response when loaded through the platform API. */\n data: Ref<Record<string, unknown> | null>\n /** Plugin-defined design_data payload from props or platform response. */\n designData: ComputedRef<Record<string, unknown> | null>\n /** SampleSelector-compatible string values extracted from design_data. */\n samples: ComputedRef<string[]>\n /** Select/dropdown-friendly sample options extracted from design_data. */\n sampleOptions: ComputedRef<SelectOption<string>[]>\n isLoading: Ref<boolean>\n error: Ref<string | null>\n lastLoadedAt: Ref<Date | null>\n /** Fetch samples for a specific experiment id, defaulting to the resolved id. */\n fetch: (experimentId?: number | string | null) => Promise<Record<string, unknown> | null>\n /** Refetch the current experiment id. */\n refresh: () => Promise<void>\n /** Clear fetched platform data. */\n clear: () => void\n}\n\n/** Loads experiment design_data and derives samples for SampleSelector-style UIs. */\nexport function useExperimentSamples(\n options: UseExperimentSamplesOptions = {},\n): UseExperimentSamplesReturn {\n const appExperiment = options.syncAppExperiment === false\n ? undefined\n : inject(APP_EXPERIMENT_KEY, undefined)\n const experimentData = useExperimentData({ apiBaseUrl: options.apiBaseUrl })\n\n const experimentId = computed<number | undefined>(() => {\n const explicitId = parseExperimentId(toValue(options.experimentId))\n return explicitId ?? parseExperimentId(appExperiment?.experimentId.value)\n })\n\n const explicitDesignData = computed<Record<string, unknown> | null>(() =>\n unwrapExperimentDesignData(toValue(options.designData) ?? null),\n )\n\n const designData = computed<Record<string, unknown> | null>(() =>\n explicitDesignData.value ?? experimentData.designData.value,\n )\n\n const extractOptions = computed<ExtractExperimentSamplesOptions>(() => ({\n includeControls: options.includeControls,\n }))\n\n const samples = computed<string[]>(() =>\n extractSampleNamesFromDesignData(designData.value, extractOptions.value),\n )\n\n const sampleOptions = computed<SelectOption<string>[]>(() =>\n extractSampleOptionsFromDesignData(designData.value, extractOptions.value),\n )\n\n const enabled = computed(() => toValue(options.enabled) ?? true)\n\n async function fetchSamples(\n id: number | string | null | undefined = experimentId.value,\n ): Promise<Record<string, unknown> | null> {\n const parsedId = parseExperimentId(id)\n if (parsedId === undefined) {\n experimentData.clear()\n return null\n }\n return experimentData.fetch(parsedId)\n }\n\n watch(\n () => ({\n designData: explicitDesignData.value,\n enabled: enabled.value,\n experimentId: experimentId.value,\n }),\n ({ designData: currentDesignData, enabled: isEnabled, experimentId: currentExperimentId }) => {\n if (options.immediate === false || !isEnabled) return\n if (currentDesignData) {\n experimentData.clear()\n return\n }\n if (currentExperimentId === undefined) {\n experimentData.clear()\n return\n }\n void experimentData.fetch(currentExperimentId)\n },\n { immediate: options.immediate !== false },\n )\n\n return {\n experimentId,\n data: experimentData.data,\n designData,\n samples,\n sampleOptions,\n isLoading: experimentData.isLoading,\n error: experimentData.error,\n lastLoadedAt: experimentData.lastLoadedAt,\n fetch: fetchSamples,\n refresh: experimentData.refresh,\n clear: experimentData.clear,\n }\n}\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { a as BaseButton_default, n as BaseModal_default, o as __exportAll, r as useFocusTrap, t as useDropdownState } from "./useDropdownState-uFIz6Yv8.js";
|
|
2
2
|
import { d as MintApiError, f as mintApiErrorFromResponse, l as tryUseSettingsStore, t as useExperimentStore } from "./experiment-DyO54FQB.js";
|
|
3
|
-
import { C as formatExperimentDate, D as compareTime, E as useMenuKeyboard, F as toMinutes, G as normalizeOptionInput, K as BaseInput_default, M as formatTimeSlot, N as generateTimeSlots, T as FileUploader_default, V as BaseSelect_default, W as useFloatingPanel, c as SecretInput_default, d as isActiveJobStatus, h as normalizeJobState, i as getInjectedPlatformContext, j as formatTime, k as findNearestTimeSlotIndex, n as ResourcePickerListInternal_default, s as TagsInput_default, z as BaseCheckbox_default } from "./records-
|
|
3
|
+
import { C as formatExperimentDate, D as compareTime, E as useMenuKeyboard, F as toMinutes, G as normalizeOptionInput, K as BaseInput_default, M as formatTimeSlot, N as generateTimeSlots, T as FileUploader_default, V as BaseSelect_default, W as useFloatingPanel, c as SecretInput_default, d as isActiveJobStatus, h as normalizeJobState, i as getInjectedPlatformContext, j as formatTime, k as findNearestTimeSlotIndex, n as ResourcePickerListInternal_default, s as TagsInput_default, z as BaseCheckbox_default } from "./records-BAymyHAn.js";
|
|
4
4
|
import "./auth-SliLnFre.js";
|
|
5
5
|
import { getRoleInfo, hasAllPermissions, isAdminUser } from "./permissions.js";
|
|
6
6
|
import { Fragment, Teleport, Transition, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createStaticVNode, createTextVNode, createVNode, defineComponent, getCurrentInstance, getCurrentScope, inject, mergeProps, nextTick, normalizeClass, normalizeStyle, onBeforeUnmount, onMounted, onScopeDispose, onUnmounted, openBlock, ref, renderList, renderSlot, shallowRef, toDisplayString, toValue, unref, useAttrs, useId, useTemplateRef, vShow, watch, withCtx, withDirectives, withKeys, withModifiers } from "vue";
|
|
@@ -5253,4 +5253,4 @@ function useListReorder(options) {
|
|
|
5253
5253
|
//#endregion
|
|
5254
5254
|
export { useJobsEndpoint as A, compareSortValues as B, FormulaInput_default as C, _plugin_vue_export_helper_default as D, GeneratedPathInput_default as E, applySpecDefaults as F, BaseSlider_default as H, defineDataFrame as I, definePlateEditor as L, usePlatform as M, NumberInput_default as N, GENERATED_JOBS_API_KEY as O, DatePicker_default as P, definePluginWorkspaceView as R, useSequenceUtils as S, renderFormulaParts as T, BaseRadioGroup_default as U, useSortedItems as V, getTypeDefault as _, StepWizard_default as a, MoleculeInput_default as b, normalizeControls as c, numericValue as d, omitUndefined as f, getFieldRegistryEntry as g, replaceRecord as h, useReorderAnnouncer as i, createEventStream as j, createGeneratedAnalysisTransport as k, normalizeOption as l, recordValue as m, reorderList as n, defaultValueForControl as o, orderedUnique as p, useListReorder as r, normalizeControlDefinition as s, REORDER_ANNOUNCER_STYLE as t, humanize as u, ConcentrationInput_default as v, formula_exports as w, SequenceInput_default as x, useConcentrationUnits as y, defineWellPlate as z };
|
|
5255
5255
|
|
|
5256
|
-
//# sourceMappingURL=useListReorder-
|
|
5256
|
+
//# sourceMappingURL=useListReorder-W1bzK_bo.js.map
|