@morscherlab/mint-sdk 1.0.0-alpha.7 → 1.0.0-alpha.9
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 +15 -15
- package/dist/{auth-BYmxZdJl.js → auth-DsI0rQ7_.js} +6 -6
- package/dist/auth-DsI0rQ7_.js.map +1 -0
- package/dist/components/index.js +2 -2
- package/dist/{components-CKf-UpGi.js → components-CzbQQPCb.js} +1429 -1429
- package/dist/components-CzbQQPCb.js.map +1 -0
- package/dist/composables/index.js +2 -2
- package/dist/composables/usePlatformContext.d.ts +3 -3
- package/dist/{composables-D0QfFzq1.js → composables-BXklV5ii.js} +3 -3
- package/dist/{composables-D0QfFzq1.js.map → composables-BXklV5ii.js.map} +1 -1
- package/dist/index.js +4 -4
- package/dist/install.d.ts +3 -3
- package/dist/install.js +5 -5
- package/dist/install.js.map +1 -1
- package/dist/stores/auth.d.ts +1 -1
- package/dist/stores/index.js +1 -1
- package/dist/stores/settings.d.ts +1 -1
- package/dist/styles.css +5388 -5388
- package/dist/types/platform.d.ts +1 -1
- package/dist/{useScheduleDrag-DAJueTbK.js → useScheduleDrag-CxBeqYcu.js} +331 -331
- package/dist/useScheduleDrag-CxBeqYcu.js.map +1 -0
- package/package.json +2 -2
- package/src/__tests__/components/AppLayout.test.ts +23 -23
- package/src/__tests__/components/AppSidebar.test.ts +29 -29
- package/src/__tests__/components/AppTopBar.test.ts +45 -45
- package/src/__tests__/components/BaseInput.test.ts +2 -2
- package/src/__tests__/components/BasePill.test.ts +37 -37
- package/src/__tests__/components/Calendar.test.ts +52 -52
- package/src/__tests__/components/CollapsibleCard.test.ts +81 -81
- package/src/__tests__/components/DataFrame.test.ts +80 -80
- package/src/__tests__/components/DropdownButton.test.ts +80 -80
- package/src/__tests__/composables/usePlatformContext.test.ts +1 -1
- package/src/components/AlertBox.story.vue +1 -1
- package/src/components/AlertBox.vue +14 -14
- package/src/components/AppAvatarMenu.vue +26 -26
- package/src/components/AppContainer.vue +3 -3
- package/src/components/AppLayout.vue +7 -7
- package/src/components/AppPageSelector.vue +30 -30
- package/src/components/AppPillNav.vue +10 -10
- package/src/components/AppPluginSwitcher.vue +31 -31
- package/src/components/AppSidebar.vue +8 -8
- package/src/components/AppTopBar.story.vue +7 -7
- package/src/components/AppTopBar.vue +102 -102
- package/src/components/AuditTrail.vue +19 -19
- package/src/components/AutoGroupModal.vue +76 -76
- package/src/components/Avatar.vue +6 -6
- package/src/components/BaseButton.vue +6 -6
- package/src/components/BaseCheckbox.vue +9 -9
- package/src/components/BaseInput.vue +4 -4
- package/src/components/BaseModal.story.vue +1 -1
- package/src/components/BaseModal.vue +14 -14
- package/src/components/BasePill.vue +9 -9
- package/src/components/BaseRadioGroup.vue +21 -21
- package/src/components/BaseSelect.vue +6 -6
- package/src/components/BaseSlider.vue +8 -8
- package/src/components/BaseTabs.vue +7 -7
- package/src/components/BaseTextarea.vue +5 -5
- package/src/components/BaseToggle.vue +10 -10
- package/src/components/BatchProgressList.vue +25 -25
- package/src/components/Breadcrumb.vue +8 -8
- package/src/components/Calendar.vue +19 -19
- package/src/components/ChartContainer.vue +9 -9
- package/src/components/ChemicalFormula.vue +7 -7
- package/src/components/CollapsibleCard.vue +20 -20
- package/src/components/ColorSlider.vue +6 -6
- package/src/components/ConcentrationInput.vue +12 -12
- package/src/components/ConfirmDialog.story.vue +1 -1
- package/src/components/ConfirmDialog.vue +7 -7
- package/src/components/DataFrame.vue +40 -40
- package/src/components/DatePicker.vue +29 -29
- package/src/components/DateTimePicker.vue +41 -41
- package/src/components/Divider.vue +9 -9
- package/src/components/DoseCalculator.vue +66 -66
- package/src/components/DropdownButton.vue +19 -19
- package/src/components/EmptyState.vue +9 -9
- package/src/components/ExperimentCodeBadge.vue +3 -3
- package/src/components/ExperimentDataViewer.vue +25 -25
- package/src/components/ExperimentPopover.vue +35 -35
- package/src/components/ExperimentSelectorModal.vue +40 -40
- package/src/components/ExperimentTimeline.vue +48 -48
- package/src/components/FileUploader.vue +31 -31
- package/src/components/FitPanel.vue +9 -9
- package/src/components/FormActions.vue +1 -1
- package/src/components/FormBuilder.vue +2 -2
- package/src/components/FormField.vue +7 -7
- package/src/components/FormSection.vue +7 -7
- package/src/components/FormulaInput.vue +10 -10
- package/src/components/GroupAssigner.vue +40 -40
- package/src/components/GroupingModal.vue +45 -45
- package/src/components/IconButton.vue +6 -6
- package/src/components/LoadingSpinner.vue +5 -5
- package/src/components/MoleculeInput.vue +21 -21
- package/src/components/MultiSelect.vue +13 -13
- package/src/components/NumberInput.vue +13 -13
- package/src/components/PlateMapEditor.vue +63 -63
- package/src/components/ProgressBar.vue +18 -18
- package/src/components/ProtocolStepEditor.vue +57 -57
- package/src/components/RackEditor.vue +28 -28
- package/src/components/ReagentEditor.vue +61 -61
- package/src/components/ReagentList.vue +49 -49
- package/src/components/ResourceCard.vue +28 -28
- package/src/components/SampleHierarchyTree.vue +13 -13
- package/src/components/SampleLegend.vue +12 -12
- package/src/components/SampleSelector.vue +104 -104
- package/src/components/ScheduleCalendar.vue +42 -42
- package/src/components/ScientificNumber.vue +11 -11
- package/src/components/SegmentedControl.vue +12 -12
- package/src/components/SequenceInput.vue +32 -32
- package/src/components/SettingsButton.vue +5 -5
- package/src/components/SettingsModal.vue +17 -17
- package/src/components/StatusIndicator.vue +5 -5
- package/src/components/StepWizard.vue +16 -16
- package/src/components/TagsInput.vue +20 -20
- package/src/components/ThemeToggle.vue +3 -3
- package/src/components/TimePicker.vue +21 -21
- package/src/components/TimeRangeInput.vue +5 -5
- package/src/components/ToastNotification.vue +8 -8
- package/src/components/Tooltip.vue +7 -7
- package/src/components/UnitInput.vue +12 -12
- package/src/components/WellEditPopup.vue +28 -28
- package/src/components/WellPlate.vue +37 -37
- package/src/composables/useAppExperiment.ts +1 -1
- package/src/composables/usePlatformContext.ts +16 -16
- package/src/composables/useProtocolTemplates.ts +1 -1
- package/src/install.ts +3 -3
- package/src/stores/auth.ts +3 -3
- package/src/stores/settings.ts +2 -2
- package/src/styles/components/alert-box.css +30 -30
- package/src/styles/components/app-avatar-menu.css +23 -23
- package/src/styles/components/app-container.css +6 -6
- package/src/styles/components/app-layout.css +15 -15
- package/src/styles/components/app-page-selector.css +26 -26
- package/src/styles/components/app-pill-nav.css +7 -7
- package/src/styles/components/app-plugin-switcher.css +27 -27
- package/src/styles/components/app-sidebar.css +24 -24
- package/src/styles/components/app-top-bar.css +65 -65
- package/src/styles/components/audit-trail.css +29 -29
- package/src/styles/components/auto-group-modal.css +91 -91
- package/src/styles/components/avatar.css +15 -15
- package/src/styles/components/batch-progress-list.css +40 -40
- package/src/styles/components/breadcrumb.css +8 -8
- package/src/styles/components/button.css +31 -31
- package/src/styles/components/calendar.css +27 -27
- package/src/styles/components/chart-container.css +9 -9
- package/src/styles/components/checkbox.css +20 -20
- package/src/styles/components/chemical-formula.css +8 -8
- package/src/styles/components/collapsible-card.css +35 -35
- package/src/styles/components/color-slider.css +8 -8
- package/src/styles/components/concentration-input.css +27 -27
- package/src/styles/components/confirm-dialog.css +32 -32
- package/src/styles/components/dataframe.css +66 -66
- package/src/styles/components/date-picker.css +40 -40
- package/src/styles/components/datetime-picker.css +37 -37
- package/src/styles/components/divider.css +13 -13
- package/src/styles/components/dose-calculator.css +43 -43
- package/src/styles/components/dropdown-button.css +46 -46
- package/src/styles/components/empty-state.css +44 -44
- package/src/styles/components/experiment-code-badge.css +8 -8
- package/src/styles/components/experiment-data-viewer.css +23 -23
- package/src/styles/components/experiment-popover.css +97 -97
- package/src/styles/components/experiment-selector-modal.css +39 -39
- package/src/styles/components/experiment-timeline.css +98 -98
- package/src/styles/components/file-uploader.css +44 -44
- package/src/styles/components/fit-panel.css +12 -12
- package/src/styles/components/form-builder.css +11 -11
- package/src/styles/components/form-field.css +7 -7
- package/src/styles/components/formula-input.css +17 -17
- package/src/styles/components/group-assigner.css +26 -26
- package/src/styles/components/grouping-modal.css +51 -51
- package/src/styles/components/icon-button.css +41 -41
- package/src/styles/components/input.css +13 -13
- package/src/styles/components/loading-spinner.css +12 -12
- package/src/styles/components/modal.css +69 -69
- package/src/styles/components/molecule-input.css +27 -27
- package/src/styles/components/multi-select.css +23 -23
- package/src/styles/components/number-input.css +32 -32
- package/src/styles/components/pill.css +37 -37
- package/src/styles/components/plate-map-editor.css +67 -67
- package/src/styles/components/progress-bar.css +41 -41
- package/src/styles/components/protocol-step-editor.css +63 -63
- package/src/styles/components/rack-editor.css +34 -34
- package/src/styles/components/radio-group.css +41 -41
- package/src/styles/components/reagent-editor.css +70 -70
- package/src/styles/components/reagent-list.css +65 -65
- package/src/styles/components/resource-card.css +52 -52
- package/src/styles/components/sample-hierarchy-tree.css +56 -56
- package/src/styles/components/sample-legend.css +37 -37
- package/src/styles/components/sample-selector.css +121 -121
- package/src/styles/components/schedule-calendar.css +67 -67
- package/src/styles/components/scientific-number.css +11 -11
- package/src/styles/components/segmented-control.css +33 -33
- package/src/styles/components/select.css +11 -11
- package/src/styles/components/sequence-input.css +29 -29
- package/src/styles/components/settings-button.css +16 -16
- package/src/styles/components/settings-modal.css +14 -14
- package/src/styles/components/skeleton.css +2 -2
- package/src/styles/components/slider.css +10 -10
- package/src/styles/components/status-indicator.css +12 -12
- package/src/styles/components/step-wizard.css +32 -32
- package/src/styles/components/tabs.css +16 -16
- package/src/styles/components/tags-input.css +46 -46
- package/src/styles/components/textarea.css +17 -17
- package/src/styles/components/theme-toggle.css +13 -13
- package/src/styles/components/time-picker.css +28 -28
- package/src/styles/components/time-range-input.css +8 -8
- package/src/styles/components/toast.css +18 -18
- package/src/styles/components/toggle.css +27 -27
- package/src/styles/components/tooltip.css +18 -18
- package/src/styles/components/unit-input.css +25 -25
- package/src/styles/components/well-edit-popup.css +32 -32
- package/src/styles/components/well-plate.css +49 -49
- package/src/styles/index.css +1 -1
- package/src/styles/variables.css +3 -3
- package/src/types/platform.ts +6 -6
- package/dist/auth-BYmxZdJl.js.map +0 -1
- package/dist/components-CKf-UpGi.js.map +0 -1
- package/dist/useScheduleDrag-DAJueTbK.js.map +0 -1
|
@@ -45,9 +45,9 @@ function handleKeydown(event: KeyboardEvent) {
|
|
|
45
45
|
<template>
|
|
46
46
|
<span
|
|
47
47
|
:class="[
|
|
48
|
-
'
|
|
49
|
-
`
|
|
50
|
-
{ '
|
|
48
|
+
'mint-exp-code',
|
|
49
|
+
`mint-exp-code--${size}`,
|
|
50
|
+
{ 'mint-exp-code--copyable': copyable, 'mint-exp-code--copied': copied },
|
|
51
51
|
]"
|
|
52
52
|
:role="copyable ? 'button' : undefined"
|
|
53
53
|
:tabindex="copyable ? 0 : undefined"
|
|
@@ -137,9 +137,9 @@ function handleDownloadCsv() {
|
|
|
137
137
|
</script>
|
|
138
138
|
|
|
139
139
|
<template>
|
|
140
|
-
<div class="
|
|
141
|
-
<div class="
|
|
142
|
-
<div class="
|
|
140
|
+
<div class="mint-data-viewer">
|
|
141
|
+
<div class="mint-data-viewer__header">
|
|
142
|
+
<div class="mint-data-viewer__controls">
|
|
143
143
|
<SegmentedControl
|
|
144
144
|
v-model="viewMode"
|
|
145
145
|
:options="viewOptions"
|
|
@@ -148,7 +148,7 @@ function handleDownloadCsv() {
|
|
|
148
148
|
:full-width="false"
|
|
149
149
|
/>
|
|
150
150
|
</div>
|
|
151
|
-
<div class="
|
|
151
|
+
<div class="mint-data-viewer__actions">
|
|
152
152
|
<BaseButton
|
|
153
153
|
v-if="pluginRoutePrefix && experimentId"
|
|
154
154
|
variant="secondary"
|
|
@@ -174,9 +174,9 @@ function handleDownloadCsv() {
|
|
|
174
174
|
</div>
|
|
175
175
|
</div>
|
|
176
176
|
|
|
177
|
-
<div class="
|
|
178
|
-
<div v-if="isLoading" class="
|
|
179
|
-
<div class="
|
|
177
|
+
<div class="mint-data-viewer__content">
|
|
178
|
+
<div v-if="isLoading" class="mint-data-viewer__loading">
|
|
179
|
+
<div class="mint-data-viewer__skeleton">
|
|
180
180
|
<Skeleton width="40%" height="16px" />
|
|
181
181
|
<Skeleton width="100%" height="12px" />
|
|
182
182
|
<Skeleton width="100%" height="12px" />
|
|
@@ -185,16 +185,16 @@ function handleDownloadCsv() {
|
|
|
185
185
|
</div>
|
|
186
186
|
<template v-else>
|
|
187
187
|
<!-- Summary View -->
|
|
188
|
-
<div v-if="viewMode === 'summary' && mergedSummaryData" class="
|
|
188
|
+
<div v-if="viewMode === 'summary' && mergedSummaryData" class="mint-summary">
|
|
189
189
|
<!-- Metadata pills -->
|
|
190
|
-
<div v-if="metadataEntries.length" class="
|
|
190
|
+
<div v-if="metadataEntries.length" class="mint-summary__metadata">
|
|
191
191
|
<span
|
|
192
192
|
v-for="entry in metadataEntries"
|
|
193
193
|
:key="entry.key"
|
|
194
|
-
class="
|
|
194
|
+
class="mint-summary__pill"
|
|
195
195
|
>
|
|
196
|
-
<span class="
|
|
197
|
-
<span class="
|
|
196
|
+
<span class="mint-summary__pill-key">{{ entry.key }}</span>
|
|
197
|
+
<span class="mint-summary__pill-value">{{ entry.value }}</span>
|
|
198
198
|
</span>
|
|
199
199
|
</div>
|
|
200
200
|
|
|
@@ -202,29 +202,29 @@ function handleDownloadCsv() {
|
|
|
202
202
|
<div
|
|
203
203
|
v-for="section in mergedSummaryData.sections"
|
|
204
204
|
:key="section.key"
|
|
205
|
-
class="
|
|
205
|
+
class="mint-summary__section"
|
|
206
206
|
>
|
|
207
207
|
<!-- Group section: cards with embedded tables -->
|
|
208
208
|
<template v-if="section.type === 'group' && section.items">
|
|
209
209
|
<div
|
|
210
210
|
v-for="(item, idx) in section.items"
|
|
211
211
|
:key="idx"
|
|
212
|
-
class="
|
|
212
|
+
class="mint-summary__group-card"
|
|
213
213
|
>
|
|
214
|
-
<div class="
|
|
215
|
-
<span class="
|
|
216
|
-
<span class="
|
|
214
|
+
<div class="mint-summary__group-header">
|
|
215
|
+
<span class="mint-summary__group-label">{{ item.label }}</span>
|
|
216
|
+
<span class="mint-summary__group-count">
|
|
217
217
|
{{ item.item_count }} {{ item.item_key }}
|
|
218
218
|
</span>
|
|
219
219
|
</div>
|
|
220
|
-
<div v-if="item.metadata && Object.keys(item.metadata).length" class="
|
|
220
|
+
<div v-if="item.metadata && Object.keys(item.metadata).length" class="mint-summary__group-meta">
|
|
221
221
|
<span
|
|
222
222
|
v-for="(val, key) in item.metadata"
|
|
223
223
|
:key="String(key)"
|
|
224
|
-
class="
|
|
224
|
+
class="mint-summary__pill mint-summary__pill--sm"
|
|
225
225
|
>
|
|
226
|
-
<span class="
|
|
227
|
-
<span class="
|
|
226
|
+
<span class="mint-summary__pill-key">{{ String(key).replace(/_/g, ' ') }}</span>
|
|
227
|
+
<span class="mint-summary__pill-value">{{ val }}</span>
|
|
228
228
|
</span>
|
|
229
229
|
</div>
|
|
230
230
|
<DataFrame
|
|
@@ -241,9 +241,9 @@ function handleDownloadCsv() {
|
|
|
241
241
|
|
|
242
242
|
<!-- Table section: flat table -->
|
|
243
243
|
<template v-else-if="section.type === 'table' && section.rows">
|
|
244
|
-
<div class="
|
|
245
|
-
<span class="
|
|
246
|
-
<span class="
|
|
244
|
+
<div class="mint-summary__table-header">
|
|
245
|
+
<span class="mint-summary__section-label">{{ section.label }}</span>
|
|
246
|
+
<span class="mint-summary__section-count">{{ section.row_count }} rows</span>
|
|
247
247
|
</div>
|
|
248
248
|
<DataFrame
|
|
249
249
|
:data="section.rows"
|
|
@@ -275,7 +275,7 @@ function handleDownloadCsv() {
|
|
|
275
275
|
:searchable="true"
|
|
276
276
|
:sortable="true"
|
|
277
277
|
/>
|
|
278
|
-
<div v-else-if="viewMode === 'table'" class="
|
|
278
|
+
<div v-else-if="viewMode === 'table'" class="mint-data-viewer__empty">
|
|
279
279
|
No tabular data available. Use tree view.
|
|
280
280
|
</div>
|
|
281
281
|
</template>
|
|
@@ -105,12 +105,12 @@ function formatStatus(status: string): string {
|
|
|
105
105
|
</script>
|
|
106
106
|
|
|
107
107
|
<template>
|
|
108
|
-
<div ref="popoverRef" class="
|
|
108
|
+
<div ref="popoverRef" class="mint-experiment-popover">
|
|
109
109
|
<!-- Split trigger: experiment pill + inline save -->
|
|
110
110
|
<div
|
|
111
111
|
:class="[
|
|
112
|
-
'
|
|
113
|
-
{ '
|
|
112
|
+
'mint-experiment-popover__split',
|
|
113
|
+
{ 'mint-experiment-popover__split--with-save': showSave && experimentName },
|
|
114
114
|
]"
|
|
115
115
|
>
|
|
116
116
|
<!-- Left: experiment trigger (opens popover) — shows only the code for
|
|
@@ -118,15 +118,15 @@ function formatStatus(status: string): string {
|
|
|
118
118
|
<button
|
|
119
119
|
type="button"
|
|
120
120
|
:class="[
|
|
121
|
-
'
|
|
122
|
-
{ '
|
|
123
|
-
{ '
|
|
121
|
+
'mint-experiment-popover__trigger',
|
|
122
|
+
{ 'mint-experiment-popover__trigger--active': isOpen },
|
|
123
|
+
{ 'mint-experiment-popover__trigger--empty': !experimentCode && !experimentName },
|
|
124
124
|
]"
|
|
125
125
|
:title="experimentName || undefined"
|
|
126
126
|
@click.stop="toggle"
|
|
127
127
|
>
|
|
128
128
|
<!-- Flask icon -->
|
|
129
|
-
<svg class="
|
|
129
|
+
<svg class="mint-experiment-popover__trigger-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
130
130
|
<path
|
|
131
131
|
stroke-linecap="round"
|
|
132
132
|
stroke-linejoin="round"
|
|
@@ -135,11 +135,11 @@ function formatStatus(status: string): string {
|
|
|
135
135
|
/>
|
|
136
136
|
</svg>
|
|
137
137
|
<!-- Code preferred, name as fallback, "No experiment" as empty state -->
|
|
138
|
-
<span v-if="experimentCode" class="
|
|
139
|
-
<span v-else-if="experimentName" class="
|
|
140
|
-
<span v-else class="
|
|
138
|
+
<span v-if="experimentCode" class="mint-experiment-popover__trigger-code">{{ experimentCode }}</span>
|
|
139
|
+
<span v-else-if="experimentName" class="mint-experiment-popover__trigger-text">{{ experimentName }}</span>
|
|
140
|
+
<span v-else class="mint-experiment-popover__trigger-text">No experiment</span>
|
|
141
141
|
<!-- Chevron -->
|
|
142
|
-
<svg class="
|
|
142
|
+
<svg class="mint-experiment-popover__trigger-chevron" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
143
143
|
<path d="m6 9 6 6 6-6" />
|
|
144
144
|
</svg>
|
|
145
145
|
</button>
|
|
@@ -149,41 +149,41 @@ function formatStatus(status: string): string {
|
|
|
149
149
|
v-if="showSave && experimentName"
|
|
150
150
|
type="button"
|
|
151
151
|
:class="[
|
|
152
|
-
'
|
|
153
|
-
{ '
|
|
154
|
-
{ '
|
|
155
|
-
{ '
|
|
152
|
+
'mint-experiment-popover__save-trigger',
|
|
153
|
+
{ 'mint-experiment-popover__save-trigger--loading': saveLoading },
|
|
154
|
+
{ 'mint-experiment-popover__save-trigger--success': showSuccess },
|
|
155
|
+
{ 'mint-experiment-popover__save-trigger--disabled': saveDisabled && !showSuccess },
|
|
156
156
|
]"
|
|
157
157
|
:disabled="saveDisabled && !showSuccess"
|
|
158
158
|
:title="saveDisabled && saveDisabledMessage ? saveDisabledMessage : showSuccess && saveSuccessMessage ? saveSuccessMessage : 'Save to Experiment'"
|
|
159
159
|
@click.stop="handleSave"
|
|
160
160
|
>
|
|
161
161
|
<!-- Loading spinner -->
|
|
162
|
-
<span v-if="saveLoading" class="
|
|
162
|
+
<span v-if="saveLoading" class="mint-experiment-popover__spinner--inline" />
|
|
163
163
|
<!-- Success check -->
|
|
164
|
-
<svg v-else-if="showSuccess" class="
|
|
164
|
+
<svg v-else-if="showSuccess" class="mint-experiment-popover__save-trigger-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
165
165
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2.5" d="M5 13l4 4L19 7" />
|
|
166
166
|
</svg>
|
|
167
167
|
<!-- Save icon -->
|
|
168
|
-
<svg v-else class="
|
|
168
|
+
<svg v-else class="mint-experiment-popover__save-trigger-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
169
169
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7H5a2 2 0 00-2 2v9a2 2 0 002 2h14a2 2 0 002-2V9a2 2 0 00-2-2h-3m-1 4l-3 3m0 0l-3-3m3 3V4" />
|
|
170
170
|
</svg>
|
|
171
171
|
</button>
|
|
172
172
|
</div>
|
|
173
173
|
|
|
174
174
|
<!-- Popover panel -->
|
|
175
|
-
<div v-if="isOpen" class="
|
|
175
|
+
<div v-if="isOpen" class="mint-experiment-popover__panel">
|
|
176
176
|
<!-- Header -->
|
|
177
|
-
<div class="
|
|
178
|
-
<div class="
|
|
179
|
-
<div class="
|
|
180
|
-
{{ experimentName ? 'Linked experiment context' : 'Link to an
|
|
177
|
+
<div class="mint-experiment-popover__header">
|
|
178
|
+
<div class="mint-experiment-popover__title">Experiment</div>
|
|
179
|
+
<div class="mint-experiment-popover__subtitle">
|
|
180
|
+
{{ experimentName ? 'Linked experiment context' : 'Link to an MINT experiment' }}
|
|
181
181
|
</div>
|
|
182
182
|
</div>
|
|
183
183
|
|
|
184
184
|
<!-- No experiment selected -->
|
|
185
|
-
<div v-if="!experimentName" class="
|
|
186
|
-
<button type="button" class="
|
|
185
|
+
<div v-if="!experimentName" class="mint-experiment-popover__body">
|
|
186
|
+
<button type="button" class="mint-experiment-popover__select-btn" @click="handleSelect">
|
|
187
187
|
<svg width="14" height="14" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
188
188
|
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
|
|
189
189
|
</svg>
|
|
@@ -192,9 +192,9 @@ function formatStatus(status: string): string {
|
|
|
192
192
|
</div>
|
|
193
193
|
|
|
194
194
|
<!-- Experiment selected -->
|
|
195
|
-
<div v-else class="
|
|
196
|
-
<div class="
|
|
197
|
-
<div class="
|
|
195
|
+
<div v-else class="mint-experiment-popover__body">
|
|
196
|
+
<div class="mint-experiment-popover__card">
|
|
197
|
+
<div class="mint-experiment-popover__card-icon">
|
|
198
198
|
<svg fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
199
199
|
<path
|
|
200
200
|
stroke-linecap="round"
|
|
@@ -204,19 +204,19 @@ function formatStatus(status: string): string {
|
|
|
204
204
|
/>
|
|
205
205
|
</svg>
|
|
206
206
|
</div>
|
|
207
|
-
<div class="
|
|
208
|
-
<span v-if="experimentCode" class="
|
|
209
|
-
<div class="
|
|
210
|
-
<div v-if="experimentStatus" class="
|
|
207
|
+
<div class="mint-experiment-popover__card-info">
|
|
208
|
+
<span v-if="experimentCode" class="mint-experiment-popover__card-code">{{ experimentCode }}</span>
|
|
209
|
+
<div class="mint-experiment-popover__card-name">{{ experimentName }}</div>
|
|
210
|
+
<div v-if="experimentStatus" class="mint-experiment-popover__card-status">
|
|
211
211
|
{{ formatStatus(experimentStatus) }}
|
|
212
212
|
</div>
|
|
213
213
|
</div>
|
|
214
214
|
</div>
|
|
215
|
-
<div class="
|
|
216
|
-
<button type="button" class="
|
|
215
|
+
<div class="mint-experiment-popover__card-actions">
|
|
216
|
+
<button type="button" class="mint-experiment-popover__change-btn" @click="handleSelect">
|
|
217
217
|
Change
|
|
218
218
|
</button>
|
|
219
|
-
<button v-if="showDetach" type="button" class="
|
|
219
|
+
<button v-if="showDetach" type="button" class="mint-experiment-popover__detach-btn" @click="handleDetach">
|
|
220
220
|
Detach
|
|
221
221
|
</button>
|
|
222
222
|
</div>
|
|
@@ -129,7 +129,7 @@ function handleKeydown(event: KeyboardEvent) {
|
|
|
129
129
|
|
|
130
130
|
function scrollActiveIntoView() {
|
|
131
131
|
nextTick(() => {
|
|
132
|
-
const row = listRef.value?.querySelector('.
|
|
132
|
+
const row = listRef.value?.querySelector('.mint-experiment-selector__row--focused')
|
|
133
133
|
row?.scrollIntoView({ block: 'nearest' })
|
|
134
134
|
})
|
|
135
135
|
}
|
|
@@ -180,10 +180,10 @@ watch(
|
|
|
180
180
|
:size="size"
|
|
181
181
|
@update:model-value="emit('update:modelValue', $event)"
|
|
182
182
|
>
|
|
183
|
-
<div class="
|
|
183
|
+
<div class="mint-experiment-selector" @keydown="handleKeydown">
|
|
184
184
|
<!-- Filter bar row 1 -->
|
|
185
|
-
<div class="
|
|
186
|
-
<div class="
|
|
185
|
+
<div class="mint-experiment-selector__filters-row">
|
|
186
|
+
<div class="mint-experiment-selector__search">
|
|
187
187
|
<BaseInput
|
|
188
188
|
v-model="filters.search"
|
|
189
189
|
placeholder="Search experiments..."
|
|
@@ -191,7 +191,7 @@ watch(
|
|
|
191
191
|
type="search"
|
|
192
192
|
/>
|
|
193
193
|
</div>
|
|
194
|
-
<div class="
|
|
194
|
+
<div class="mint-experiment-selector__filter-select">
|
|
195
195
|
<BaseSelect
|
|
196
196
|
:model-value="filters.status ?? ''"
|
|
197
197
|
:options="EXPERIMENT_STATUS_OPTIONS"
|
|
@@ -199,7 +199,7 @@ watch(
|
|
|
199
199
|
@update:model-value="v => setFilter('status', v)"
|
|
200
200
|
/>
|
|
201
201
|
</div>
|
|
202
|
-
<div v-if="typeFilterOptions.length > 1" class="
|
|
202
|
+
<div v-if="typeFilterOptions.length > 1" class="mint-experiment-selector__filter-select">
|
|
203
203
|
<BaseSelect
|
|
204
204
|
:model-value="filters.experimentType ?? ''"
|
|
205
205
|
:options="typeFilterOptions"
|
|
@@ -208,8 +208,8 @@ watch(
|
|
|
208
208
|
/>
|
|
209
209
|
</div>
|
|
210
210
|
<button
|
|
211
|
-
class="
|
|
212
|
-
:class="{ '
|
|
211
|
+
class="mint-experiment-selector__filters-toggle"
|
|
212
|
+
:class="{ 'mint-experiment-selector__filters-toggle--active': hasActiveAdvancedFilters }"
|
|
213
213
|
type="button"
|
|
214
214
|
@click="showAdvanced = !showAdvanced"
|
|
215
215
|
>
|
|
@@ -218,13 +218,13 @@ watch(
|
|
|
218
218
|
<circle cx="6" cy="12" r="2" /><circle cx="10" cy="18" r="2" /><circle cx="6" cy="6" r="2" />
|
|
219
219
|
</svg>
|
|
220
220
|
Filters
|
|
221
|
-
<span v-if="hasActiveAdvancedFilters" class="
|
|
221
|
+
<span v-if="hasActiveAdvancedFilters" class="mint-experiment-selector__filters-dot" />
|
|
222
222
|
</button>
|
|
223
223
|
</div>
|
|
224
224
|
|
|
225
225
|
<!-- Filter bar row 2 (advanced, collapsible) -->
|
|
226
|
-
<div v-if="showAdvanced" class="
|
|
227
|
-
<div v-if="projectFilterOptions.length > 1" class="
|
|
226
|
+
<div v-if="showAdvanced" class="mint-experiment-selector__filters-advanced">
|
|
227
|
+
<div v-if="projectFilterOptions.length > 1" class="mint-experiment-selector__filter-select">
|
|
228
228
|
<BaseSelect
|
|
229
229
|
:model-value="filters.project ?? ''"
|
|
230
230
|
:options="projectFilterOptions"
|
|
@@ -232,7 +232,7 @@ watch(
|
|
|
232
232
|
@update:model-value="v => setFilter('project', v)"
|
|
233
233
|
/>
|
|
234
234
|
</div>
|
|
235
|
-
<div class="
|
|
235
|
+
<div class="mint-experiment-selector__filter-select">
|
|
236
236
|
<BaseSelect
|
|
237
237
|
:model-value="filters.datePreset ?? ''"
|
|
238
238
|
:options="DATE_PRESET_OPTIONS"
|
|
@@ -240,7 +240,7 @@ watch(
|
|
|
240
240
|
@update:model-value="v => setFilter('datePreset', v)"
|
|
241
241
|
/>
|
|
242
242
|
</div>
|
|
243
|
-
<div class="
|
|
243
|
+
<div class="mint-experiment-selector__filter-select">
|
|
244
244
|
<BaseSelect
|
|
245
245
|
:model-value="sortKey"
|
|
246
246
|
:options="SORT_OPTIONS"
|
|
@@ -248,20 +248,20 @@ watch(
|
|
|
248
248
|
@update:model-value="handleSortChange"
|
|
249
249
|
/>
|
|
250
250
|
</div>
|
|
251
|
-
<label class="
|
|
251
|
+
<label class="mint-experiment-selector__group-toggle">
|
|
252
252
|
<input
|
|
253
253
|
v-model="groupToggle"
|
|
254
254
|
type="checkbox"
|
|
255
|
-
class="
|
|
255
|
+
class="mint-experiment-selector__group-checkbox"
|
|
256
256
|
/>
|
|
257
257
|
Group by project
|
|
258
258
|
</label>
|
|
259
259
|
</div>
|
|
260
260
|
|
|
261
261
|
<!-- Loading skeleton -->
|
|
262
|
-
<div v-if="isLoading" class="
|
|
263
|
-
<div v-for="n in 4" :key="n" class="
|
|
264
|
-
<div class="
|
|
262
|
+
<div v-if="isLoading" class="mint-experiment-selector__skeleton">
|
|
263
|
+
<div v-for="n in 4" :key="n" class="mint-experiment-selector__skeleton-row">
|
|
264
|
+
<div class="mint-experiment-selector__skeleton-content">
|
|
265
265
|
<Skeleton :width="120 + n * 20" height="14px" />
|
|
266
266
|
<Skeleton width="80px" height="10px" />
|
|
267
267
|
</div>
|
|
@@ -270,7 +270,7 @@ watch(
|
|
|
270
270
|
</div>
|
|
271
271
|
|
|
272
272
|
<!-- Error -->
|
|
273
|
-
<div v-else-if="error" class="
|
|
273
|
+
<div v-else-if="error" class="mint-experiment-selector__error">
|
|
274
274
|
{{ error }}
|
|
275
275
|
</div>
|
|
276
276
|
|
|
@@ -283,37 +283,37 @@ watch(
|
|
|
283
283
|
/>
|
|
284
284
|
|
|
285
285
|
<!-- Experiment list: grouped mode -->
|
|
286
|
-
<div v-else-if="groupToggle" ref="listRef" class="
|
|
286
|
+
<div v-else-if="groupToggle" ref="listRef" class="mint-experiment-selector__list">
|
|
287
287
|
<template v-for="([groupName, groupExps]) in groupedByProject" :key="groupName">
|
|
288
288
|
<button
|
|
289
289
|
type="button"
|
|
290
|
-
class="
|
|
290
|
+
class="mint-experiment-selector__group-header"
|
|
291
291
|
@click="toggleGroup(groupName)"
|
|
292
292
|
>
|
|
293
293
|
<svg
|
|
294
|
-
class="
|
|
295
|
-
:class="{ '
|
|
294
|
+
class="mint-experiment-selector__group-chevron"
|
|
295
|
+
:class="{ 'mint-experiment-selector__group-chevron--collapsed': collapsedGroups.has(groupName) }"
|
|
296
296
|
width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
|
297
297
|
>
|
|
298
298
|
<polyline points="6 9 12 15 18 9" />
|
|
299
299
|
</svg>
|
|
300
|
-
<span class="
|
|
301
|
-
<span class="
|
|
300
|
+
<span class="mint-experiment-selector__group-name">{{ groupName }}</span>
|
|
301
|
+
<span class="mint-experiment-selector__group-count">{{ groupExps.length }}</span>
|
|
302
302
|
</button>
|
|
303
303
|
<template v-if="!collapsedGroups.has(groupName)">
|
|
304
304
|
<div
|
|
305
305
|
v-for="exp in groupExps"
|
|
306
306
|
:key="exp.id"
|
|
307
|
-
class="
|
|
307
|
+
class="mint-experiment-selector__row"
|
|
308
308
|
:class="{
|
|
309
|
-
'
|
|
310
|
-
'
|
|
309
|
+
'mint-experiment-selector__row--active': exp.id === currentExperimentId,
|
|
310
|
+
'mint-experiment-selector__row--focused': getFlatIndex(exp) === activeIndex,
|
|
311
311
|
}"
|
|
312
312
|
@click="handleSelect(exp)"
|
|
313
313
|
@mouseenter="activeIndex = getFlatIndex(exp)"
|
|
314
314
|
>
|
|
315
|
-
<div class="
|
|
316
|
-
<div class="
|
|
315
|
+
<div class="mint-experiment-selector__row-content">
|
|
316
|
+
<div class="mint-experiment-selector__name">
|
|
317
317
|
{{ exp.name }}
|
|
318
318
|
<ExperimentCodeBadge
|
|
319
319
|
v-if="exp.experiment_code"
|
|
@@ -322,7 +322,7 @@ watch(
|
|
|
322
322
|
:copyable="false"
|
|
323
323
|
/>
|
|
324
324
|
</div>
|
|
325
|
-
<div class="
|
|
325
|
+
<div class="mint-experiment-selector__meta">
|
|
326
326
|
<span>{{ formatExperimentDate(exp.created_at) }}</span>
|
|
327
327
|
</div>
|
|
328
328
|
</div>
|
|
@@ -335,20 +335,20 @@ watch(
|
|
|
335
335
|
</div>
|
|
336
336
|
|
|
337
337
|
<!-- Experiment list: flat mode -->
|
|
338
|
-
<div v-else ref="listRef" class="
|
|
338
|
+
<div v-else ref="listRef" class="mint-experiment-selector__list">
|
|
339
339
|
<div
|
|
340
340
|
v-for="(exp, idx) in experiments"
|
|
341
341
|
:key="exp.id"
|
|
342
|
-
class="
|
|
342
|
+
class="mint-experiment-selector__row"
|
|
343
343
|
:class="{
|
|
344
|
-
'
|
|
345
|
-
'
|
|
344
|
+
'mint-experiment-selector__row--active': exp.id === currentExperimentId,
|
|
345
|
+
'mint-experiment-selector__row--focused': idx === activeIndex,
|
|
346
346
|
}"
|
|
347
347
|
@click="handleSelect(exp)"
|
|
348
348
|
@mouseenter="activeIndex = idx"
|
|
349
349
|
>
|
|
350
|
-
<div class="
|
|
351
|
-
<div class="
|
|
350
|
+
<div class="mint-experiment-selector__row-content">
|
|
351
|
+
<div class="mint-experiment-selector__name">
|
|
352
352
|
{{ exp.name }}
|
|
353
353
|
<ExperimentCodeBadge
|
|
354
354
|
v-if="exp.experiment_code"
|
|
@@ -357,7 +357,7 @@ watch(
|
|
|
357
357
|
:copyable="false"
|
|
358
358
|
/>
|
|
359
359
|
</div>
|
|
360
|
-
<div class="
|
|
360
|
+
<div class="mint-experiment-selector__meta">
|
|
361
361
|
<span v-if="exp.project_name || exp.project">{{ exp.project_name || exp.project }}</span>
|
|
362
362
|
<span>{{ formatExperimentDate(exp.created_at) }}</span>
|
|
363
363
|
</div>
|
|
@@ -369,10 +369,10 @@ watch(
|
|
|
369
369
|
</div>
|
|
370
370
|
|
|
371
371
|
<!-- Footer: clear selection -->
|
|
372
|
-
<div v-if="currentExperimentId != null" class="
|
|
372
|
+
<div v-if="currentExperimentId != null" class="mint-experiment-selector__footer">
|
|
373
373
|
<button
|
|
374
374
|
type="button"
|
|
375
|
-
class="
|
|
375
|
+
class="mint-experiment-selector__clear-btn"
|
|
376
376
|
@click="handleDeselect"
|
|
377
377
|
>
|
|
378
378
|
Clear selection
|