@morscherlab/mint-sdk 1.2.0-beta.9 → 1.2.1
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 +30 -0
- package/dist/{ExperimentPopover-oL0fg_A0.js → ExperimentPopover-CJdNlCZb.js} +21 -14
- package/dist/ExperimentPopover-CJdNlCZb.js.map +1 -0
- package/dist/{ExperimentSelectorModal-BeEOomw_.js → ExperimentSelectorModal-DHE9k8TP.js} +5 -5
- package/dist/{ExperimentSelectorModal-BeEOomw_.js.map → ExperimentSelectorModal-DHE9k8TP.js.map} +1 -1
- package/dist/{SettingsModal-Dphh3RrI.js → SettingsModal-DOcCf0Vo.js} +41 -18
- package/dist/SettingsModal-DOcCf0Vo.js.map +1 -0
- package/dist/{Skeleton-DxtwJ5gt.js → Skeleton-jhF9wUkU.js} +19 -9
- package/dist/Skeleton-jhF9wUkU.js.map +1 -0
- package/dist/__tests__/apiErrors.test.d.ts +1 -0
- package/dist/__tests__/components/FileBrowserModal.test.d.ts +1 -0
- package/dist/__tests__/components/FilePicker.state.test.d.ts +1 -0
- package/dist/__tests__/components/FilePicker.test.d.ts +1 -0
- package/dist/__tests__/components/FormField.test.d.ts +1 -0
- package/dist/__tests__/components/NumberInput.test.d.ts +1 -0
- package/dist/__tests__/components/PlotlyChart.test.d.ts +1 -0
- package/dist/__tests__/components/iconButtonIconSizing.test.d.ts +1 -0
- package/dist/__tests__/composables/localFiles.test.d.ts +1 -0
- package/dist/__tests__/composables/useFileBrowser.test.d.ts +1 -0
- package/dist/__tests__/composables/usePickerSelection.test.d.ts +1 -0
- package/dist/__tests__/composables/usePlatformFilePickerAdapter.test.d.ts +1 -0
- package/dist/__tests__/styles/tokenOnlyColors.test.d.ts +1 -0
- package/dist/apiErrors.d.ts +26 -0
- package/dist/components/AppSidebar.vue.d.ts +7 -7
- package/dist/components/BaseInput.vue.d.ts +1 -1
- package/dist/components/BasePill.vue.d.ts +3 -0
- package/dist/components/BaseSelect.vue.d.ts +1 -1
- package/dist/components/BaseTabs.vue.d.ts +1 -4
- package/dist/components/BaseTextarea.vue.d.ts +1 -1
- package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
- package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +2 -2
- package/dist/components/ConcentrationInput.vue.d.ts +1 -1
- package/dist/components/DatePicker.vue.d.ts +1 -1
- package/dist/components/DateTimePicker.vue.d.ts +1 -1
- package/dist/components/FileBrowserModal.vue.d.ts +99 -0
- package/dist/components/FilePicker.vue.d.ts +32 -0
- package/dist/components/FileUploader.vue.d.ts +8 -2
- package/dist/components/FormField.vue.d.ts +8 -1
- package/dist/components/FormulaInput.vue.d.ts +1 -1
- package/dist/components/GeneratedPlotlyResult.vue.d.ts +1 -3
- package/dist/components/MobileSupportGate.vue.d.ts +1 -1
- package/dist/components/MoleculeInput.vue.d.ts +1 -1
- package/dist/components/NumberInput.vue.d.ts +1 -1
- package/dist/components/PlotlyChart.vue.d.ts +59 -0
- package/dist/components/PluginWorkspaceView.props.d.ts +3 -3
- package/dist/components/ResourceCard.vue.d.ts +1 -1
- package/dist/components/SecretInput.vue.d.ts +1 -1
- package/dist/components/SequenceInput.vue.d.ts +1 -1
- package/dist/components/StatusIndicator.vue.d.ts +1 -1
- package/dist/components/TagsInput.vue.d.ts +1 -1
- package/dist/components/TimePicker.vue.d.ts +1 -1
- package/dist/components/TimeRangeInput.vue.d.ts +1 -1
- package/dist/components/UnitInput.vue.d.ts +1 -1
- package/dist/components/WellPlate.vue.d.ts +1 -1
- package/dist/components/fileBrowserPresentation.d.ts +10 -0
- package/dist/components/index.d.ts +4 -0
- package/dist/components/index.js +8 -8
- package/dist/components/internal/FileBrowserDialogInternal.vue.d.ts +34 -0
- package/dist/components/internal/FileBrowserListingInternal.vue.d.ts +25 -0
- package/dist/components/internal/FileBrowserToolbarInternal.vue.d.ts +26 -0
- package/dist/components/internal/FilePickerPreviewInternal.vue.d.ts +18 -0
- package/dist/components/internal/FilePickerTreeInternal.vue.d.ts +31 -0
- package/dist/{components-CgAUzF8F.js → components-Cp8DcNrU.js} +4363 -1730
- package/dist/components-Cp8DcNrU.js.map +1 -0
- package/dist/composables/filePicker/localFiles.d.ts +3 -0
- package/dist/composables/filePicker/usePickerNavigation.d.ts +96 -0
- package/dist/composables/filePicker/usePickerSelection.d.ts +31 -0
- package/dist/composables/filePicker/validation.d.ts +5 -0
- package/dist/composables/index.d.ts +2 -0
- package/dist/composables/index.js +10 -10
- package/dist/composables/pluginWorkspaceModel.d.ts +0 -3
- package/dist/composables/useApi.d.ts +14 -7
- package/dist/composables/useFileBrowser.d.ts +55 -0
- package/dist/composables/useFilePicker.d.ts +189 -0
- package/dist/composables/usePlatformFilePickerAdapter.d.ts +11 -0
- package/dist/composables/useToast.d.ts +22 -1
- package/dist/{composables-B_pia3hO.js → composables-D_4qqOlp.js} +300 -11
- package/dist/composables-D_4qqOlp.js.map +1 -0
- package/dist/{errors-_W0-LbA6.js → errors-BLuqMee5.js} +78 -15
- package/dist/errors-BLuqMee5.js.map +1 -0
- package/dist/{experiment-Cwl9AYxw.js → experiment-CVDRAnqp.js} +2 -2
- package/dist/{experiment-Cwl9AYxw.js.map → experiment-CVDRAnqp.js.map} +1 -1
- package/dist/{experiment-utils-DV3DrvE_.js → experiment-utils-CV2Wza3z.js} +1 -1
- package/dist/{experiment-utils-DV3DrvE_.js.map → experiment-utils-CV2Wza3z.js.map} +1 -1
- package/dist/index.d.ts +1 -0
- package/dist/index.js +15 -15
- package/dist/install.js +2 -2
- package/dist/stores/index.js +2 -2
- package/dist/styles.css +2957 -1708
- package/dist/templates/index.js +2 -2
- package/dist/{templates-Qq113pyZ.js → templates-Dd9bBSs6.js} +2 -2
- package/dist/{templates-Qq113pyZ.js.map → templates-Dd9bBSs6.js.map} +1 -1
- package/dist/types/components.d.ts +21 -0
- package/dist/types/fileBrowserTypes.d.ts +77 -0
- package/dist/types/filePicker.d.ts +77 -0
- package/dist/types/form-builder.d.ts +2 -0
- package/dist/types/generated-ui.d.ts +2 -0
- package/dist/types/index.d.ts +3 -1
- package/dist/{useControlSchema-aMZlb4Sc.js → useControlSchema-BB2GRPhW.js} +190 -105
- package/dist/useControlSchema-BB2GRPhW.js.map +1 -0
- package/dist/{useDropdownState-DitCtrTT.js → useDropdownState-C7hRiVQf.js} +2 -2
- package/dist/{useDropdownState-DitCtrTT.js.map → useDropdownState-C7hRiVQf.js.map} +1 -1
- package/dist/{useExperimentSelector-I8HC8hUu.js → useExperimentSelector-G_CAOFTX.js} +4 -4
- package/dist/{useExperimentSelector-I8HC8hUu.js.map → useExperimentSelector-G_CAOFTX.js.map} +1 -1
- package/dist/{useFormBuilder-TCxNnqeb.js → useFormBuilder-BnGSdSRG.js} +2 -2
- package/dist/{useFormBuilder-TCxNnqeb.js.map → useFormBuilder-BnGSdSRG.js.map} +1 -1
- package/dist/{useProtocolTemplates-BmX_iVBR.js → validation-CTxuzLIX.js} +70 -13
- package/dist/validation-CTxuzLIX.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/apiErrors.test.ts +81 -0
- package/src/__tests__/components/AppSidebar.test.ts +84 -94
- package/src/__tests__/components/AppToastContainer.test.ts +55 -1
- package/src/__tests__/components/BioTemplatePresetWorkspaceView.test.ts +0 -21
- package/src/__tests__/components/ControlWorkspaceView.test.ts +0 -2
- package/src/__tests__/components/DoseDesignWorkspaceView.test.ts +0 -2
- package/src/__tests__/components/ExperimentPopover.test.ts +30 -0
- package/src/__tests__/components/FileBrowserModal.test.ts +460 -0
- package/src/__tests__/components/FilePicker.state.test.ts +287 -0
- package/src/__tests__/components/FilePicker.test.ts +487 -0
- package/src/__tests__/components/FormBuilder.test.ts +26 -0
- package/src/__tests__/components/FormField.test.ts +26 -0
- package/src/__tests__/components/GeneratedPathInput.test.ts +18 -0
- package/src/__tests__/components/GeneratedPlotlyResult.test.ts +52 -5
- package/src/__tests__/components/NumberInput.test.ts +105 -0
- package/src/__tests__/components/PlotlyChart.test.ts +305 -0
- package/src/__tests__/components/PluginWorkspaceView.internal.test.ts +1 -2
- package/src/__tests__/components/PluginWorkspaceView.test.ts +1 -2
- package/src/__tests__/components/SegmentedControl.test.ts +19 -0
- package/src/__tests__/components/iconButtonIconSizing.test.ts +18 -0
- package/src/__tests__/composables/localFiles.test.ts +57 -0
- package/src/__tests__/composables/useApi.test.ts +92 -9
- package/src/__tests__/composables/useFileBrowser.test.ts +305 -0
- package/src/__tests__/composables/useGeneratedAnalysis.test.ts +7 -2
- package/src/__tests__/composables/usePickerSelection.test.ts +98 -0
- package/src/__tests__/composables/usePlatformFilePickerAdapter.test.ts +67 -0
- package/src/__tests__/composables/usePluginClient.test.ts +3 -0
- package/src/__tests__/generatedUi.test.ts +111 -0
- package/src/__tests__/styles/tokenOnlyColors.test.ts +16 -0
- package/src/apiErrors.ts +85 -0
- package/src/components/AppLayout.story.vue +1 -1
- package/src/components/AppSidebar.story.vue +7 -10
- package/src/components/AppSidebar.vue +178 -58
- package/src/components/AppToastContainer.vue +65 -23
- package/src/components/BasePill.story.vue +2 -0
- package/src/components/BasePill.vue +4 -0
- package/src/components/BaseTabs.story.vue +0 -42
- package/src/components/BaseTabs.vue +3 -6
- package/src/components/ExperimentPopover.vue +10 -2
- package/src/components/FileBrowserModal.story.vue +203 -0
- package/src/components/FileBrowserModal.vue +384 -0
- package/src/components/FilePicker.story.vue +44 -0
- package/src/components/FilePicker.vue +284 -0
- package/src/components/FileUploader.vue +42 -15
- package/src/components/FormField.vue +10 -3
- package/src/components/GeneratedPathInput.vue +11 -7
- package/src/components/GeneratedPlotlyResult.vue +34 -69
- package/src/components/GeneratedResultRenderer.vue +0 -5
- package/src/components/NumberInput.story.vue +32 -13
- package/src/components/NumberInput.vue +116 -55
- package/src/components/PlotlyChart.story.vue +61 -0
- package/src/components/PlotlyChart.vue +233 -0
- package/src/components/PluginWorkspaceView.props.ts +3 -3
- package/src/components/SegmentedControl.vue +2 -2
- package/src/components/fileBrowserPresentation.ts +39 -0
- package/src/components/index.ts +5 -0
- package/src/components/internal/FileBrowserDialogInternal.vue +75 -0
- package/src/components/internal/FileBrowserListingInternal.vue +197 -0
- package/src/components/internal/FileBrowserToolbarInternal.vue +136 -0
- package/src/components/internal/FilePickerPreviewInternal.vue +100 -0
- package/src/components/internal/FilePickerTreeInternal.vue +238 -0
- package/src/components/internal/FormFieldRendererInternal.vue +17 -0
- package/src/components/internal/WorkspaceSidebarInternal.vue +1 -2
- package/src/composables/filePicker/localFiles.ts +65 -0
- package/src/composables/filePicker/usePickerNavigation.ts +220 -0
- package/src/composables/filePicker/usePickerSelection.ts +270 -0
- package/src/composables/filePicker/validation.ts +41 -0
- package/src/composables/index.ts +7 -0
- package/src/composables/pluginWorkspaceModel.ts +0 -3
- package/src/composables/useApi.ts +57 -13
- package/src/composables/useFileBrowser.ts +314 -0
- package/src/composables/useFilePicker.ts +366 -0
- package/src/composables/useGeneratedAnalysis.ts +10 -17
- package/src/composables/usePlatformFilePickerAdapter.ts +104 -0
- package/src/composables/usePluginClient.ts +3 -0
- package/src/composables/usePluginWorkspace.ts +1 -2
- package/src/composables/useToast.ts +21 -5
- package/src/generated/schema.ts +58 -18
- package/src/index.ts +3 -0
- package/src/styles/components/app-sidebar.css +282 -121
- package/src/styles/components/file-browser-modal.css +489 -0
- package/src/styles/components/file-picker.css +502 -0
- package/src/styles/components/form-builder.css +1 -1
- package/src/styles/components/form-field.css +28 -0
- package/src/styles/components/icon-button.css +9 -0
- package/src/styles/components/number-input.css +73 -91
- package/src/styles/components/pill.css +49 -51
- package/src/styles/components/segmented-control.css +16 -11
- package/src/styles/components/tabs.css +18 -34
- package/src/styles/components/toast.css +136 -27
- package/src/styles/index.css +3 -0
- package/src/styles/variables.css +25 -5
- package/src/types/components.ts +23 -0
- package/src/types/fileBrowserTypes.ts +85 -0
- package/src/types/filePicker.ts +72 -0
- package/src/types/form-builder.ts +2 -0
- package/src/types/generated-ui.ts +2 -0
- package/src/types/index.ts +16 -0
- package/dist/ExperimentPopover-oL0fg_A0.js.map +0 -1
- package/dist/SettingsModal-Dphh3RrI.js.map +0 -1
- package/dist/Skeleton-DxtwJ5gt.js.map +0 -1
- package/dist/components-CgAUzF8F.js.map +0 -1
- package/dist/composables-B_pia3hO.js.map +0 -1
- package/dist/errors-_W0-LbA6.js.map +0 -1
- package/dist/useControlSchema-aMZlb4Sc.js.map +0 -1
- package/dist/useProtocolTemplates-BmX_iVBR.js.map +0 -1
|
@@ -1,17 +1,25 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
/** Preferred toast container driven by useToast,
|
|
2
|
+
/** Preferred toast container driven by useToast: title/detail, up to two actions, TTL or indeterminate bar, click-to-close. */
|
|
3
3
|
import { useToast } from '../composables/useToast'
|
|
4
|
-
import type { Toast } from '../types'
|
|
4
|
+
import type { Toast, ToastAction } from '../types'
|
|
5
5
|
|
|
6
6
|
const { toasts, dismiss } = useToast()
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
8
|
+
function title(toast: Toast): string {
|
|
9
|
+
return toast.title ?? toast.message
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function actions(toast: Toast): ToastAction[] {
|
|
13
|
+
return (toast.actions ?? []).slice(0, 2)
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
function progress(toast: Toast): NonNullable<Toast['progress']> {
|
|
17
|
+
return toast.progress ?? 'ttl'
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function runAction(toast: Toast, action: ToastAction) {
|
|
21
|
+
action.onClick()
|
|
22
|
+
dismiss(toast.id)
|
|
15
23
|
}
|
|
16
24
|
</script>
|
|
17
25
|
|
|
@@ -22,36 +30,70 @@ const accentColors: Record<Toast['type'], string> = {
|
|
|
22
30
|
<div
|
|
23
31
|
v-for="toast in toasts"
|
|
24
32
|
:key="toast.id"
|
|
25
|
-
:class="[
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
33
|
+
:class="[
|
|
34
|
+
'mint-toast__item',
|
|
35
|
+
`mint-toast__item--${toast.type}`,
|
|
36
|
+
(toast.count ?? 1) > 1 ? 'mint-toast__item--stacked' : '',
|
|
37
|
+
]"
|
|
38
|
+
:role="toast.type === 'error' || toast.type === 'warning' ? 'alert' : 'status'"
|
|
30
39
|
@click="dismiss(toast.id)"
|
|
31
40
|
>
|
|
32
41
|
<!-- Lucide circle-check -->
|
|
33
|
-
<svg v-if="toast.type === 'success'" class="mint-toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
|
42
|
+
<svg v-if="toast.type === 'success'" class="mint-toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
34
43
|
<circle cx="12" cy="12" r="10" /><path d="m9 12 2 2 4-4" />
|
|
35
44
|
</svg>
|
|
36
45
|
<!-- Lucide circle-x -->
|
|
37
|
-
<svg v-else-if="toast.type === 'error'" class="mint-toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
|
46
|
+
<svg v-else-if="toast.type === 'error'" class="mint-toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
38
47
|
<circle cx="12" cy="12" r="10" /><path d="m15 9-6 6" /><path d="m9 9 6 6" />
|
|
39
48
|
</svg>
|
|
40
49
|
<!-- Lucide triangle-alert -->
|
|
41
|
-
<svg v-else-if="toast.type === 'warning'" class="mint-toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
|
50
|
+
<svg v-else-if="toast.type === 'warning'" class="mint-toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
42
51
|
<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3" /><path d="M12 9v4" /><path d="M12 17h.01" />
|
|
43
52
|
</svg>
|
|
44
53
|
<!-- Lucide info -->
|
|
45
|
-
<svg v-else class="mint-toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"
|
|
54
|
+
<svg v-else class="mint-toast__icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
|
|
46
55
|
<circle cx="12" cy="12" r="10" /><path d="M12 16v-4" /><path d="M12 8h.01" />
|
|
47
56
|
</svg>
|
|
48
|
-
|
|
57
|
+
|
|
58
|
+
<div class="mint-toast__body">
|
|
59
|
+
<div class="mint-toast__title">
|
|
60
|
+
<span class="mint-toast__message">{{ title(toast) }}</span>
|
|
61
|
+
<span v-if="(toast.count ?? 1) > 1" class="mint-toast__count">×{{ toast.count }}</span>
|
|
62
|
+
</div>
|
|
63
|
+
<div v-if="toast.detail" class="mint-toast__detail">{{ toast.detail }}</div>
|
|
64
|
+
<div v-if="actions(toast).length" class="mint-toast__actions">
|
|
65
|
+
<button
|
|
66
|
+
v-for="action in actions(toast)"
|
|
67
|
+
:key="action.label"
|
|
68
|
+
type="button"
|
|
69
|
+
:class="['mint-toast__action', action.primary ? 'mint-toast__action--primary' : '']"
|
|
70
|
+
@click.stop="runAction(toast, action)"
|
|
71
|
+
>
|
|
72
|
+
{{ action.label }}
|
|
73
|
+
</button>
|
|
74
|
+
</div>
|
|
75
|
+
</div>
|
|
76
|
+
|
|
77
|
+
<button
|
|
78
|
+
v-if="toast.dismissible !== false"
|
|
79
|
+
type="button"
|
|
80
|
+
class="mint-toast__close"
|
|
81
|
+
aria-label="Dismiss"
|
|
82
|
+
@click.stop="dismiss(toast.id)"
|
|
83
|
+
>
|
|
84
|
+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.2" stroke-linecap="round" aria-hidden="true">
|
|
85
|
+
<path d="M18 6 6 18" /><path d="m6 6 12 12" />
|
|
86
|
+
</svg>
|
|
87
|
+
</button>
|
|
88
|
+
|
|
49
89
|
<span
|
|
90
|
+
v-if="progress(toast) === 'ttl'"
|
|
50
91
|
class="mint-toast__progress"
|
|
51
|
-
:style="{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
92
|
+
:style="{ animationDuration: `${toast.duration ?? 3500}ms` }"
|
|
93
|
+
/>
|
|
94
|
+
<span
|
|
95
|
+
v-else-if="progress(toast) === 'indeterminate'"
|
|
96
|
+
class="mint-toast__progress mint-toast__progress--indeterminate"
|
|
55
97
|
/>
|
|
56
98
|
</div>
|
|
57
99
|
</TransitionGroup>
|
|
@@ -16,6 +16,7 @@ const sizes: PillSize[] = ['sm', 'md', 'lg']
|
|
|
16
16
|
:size="state.size"
|
|
17
17
|
:removable="state.removable"
|
|
18
18
|
:disabled="state.disabled"
|
|
19
|
+
:dot="state.dot"
|
|
19
20
|
@remove="() => console.log('Remove clicked')"
|
|
20
21
|
>
|
|
21
22
|
{{ state.label }}
|
|
@@ -37,6 +38,7 @@ const sizes: PillSize[] = ['sm', 'md', 'lg']
|
|
|
37
38
|
/>
|
|
38
39
|
<HstCheckbox v-model="state.removable" title="Removable" />
|
|
39
40
|
<HstCheckbox v-model="state.disabled" title="Disabled" />
|
|
41
|
+
<HstCheckbox v-model="state.dot" title="Status dot" />
|
|
40
42
|
</template>
|
|
41
43
|
</Variant>
|
|
42
44
|
|
|
@@ -28,6 +28,8 @@ interface Props {
|
|
|
28
28
|
disabled?: boolean
|
|
29
29
|
/** Show icon slot */
|
|
30
30
|
icon?: boolean
|
|
31
|
+
/** Leading status dot in the pill's tone color */
|
|
32
|
+
dot?: boolean
|
|
31
33
|
}
|
|
32
34
|
|
|
33
35
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -37,6 +39,7 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
37
39
|
removable: false,
|
|
38
40
|
disabled: false,
|
|
39
41
|
icon: false,
|
|
42
|
+
dot: false,
|
|
40
43
|
})
|
|
41
44
|
|
|
42
45
|
/**
|
|
@@ -64,6 +67,7 @@ function handleRemove(event: MouseEvent) {
|
|
|
64
67
|
{ 'mint-pill--disabled': disabled, 'mint-pill--with-icon': icon },
|
|
65
68
|
]"
|
|
66
69
|
>
|
|
70
|
+
<span v-if="dot" class="mint-pill__dot" aria-hidden="true" />
|
|
67
71
|
<span v-if="icon" class="mint-pill__icon">
|
|
68
72
|
<slot name="icon" />
|
|
69
73
|
</span>
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
import { ref } from 'vue'
|
|
3
2
|
import BaseTabs from './BaseTabs.vue'
|
|
4
3
|
import type { TabItem } from '../types'
|
|
5
4
|
|
|
6
|
-
const activeTab = ref('overview')
|
|
7
5
|
|
|
8
6
|
const basicTabs: TabItem[] = [
|
|
9
7
|
{ id: 'overview', label: 'Overview' },
|
|
@@ -25,12 +23,9 @@ const tabsWithIcons: TabItem[] = [
|
|
|
25
23
|
{ id: 'analysis', label: 'Analysis', icon: '\u{1F52C}' },
|
|
26
24
|
]
|
|
27
25
|
|
|
28
|
-
const variants = ['underline', 'pills'] as const
|
|
29
|
-
|
|
30
26
|
function initPlayground() {
|
|
31
27
|
return {
|
|
32
28
|
activeTab: 'overview',
|
|
33
|
-
variant: 'underline' as const,
|
|
34
29
|
}
|
|
35
30
|
}
|
|
36
31
|
</script>
|
|
@@ -43,7 +38,6 @@ function initPlayground() {
|
|
|
43
38
|
<BaseTabs
|
|
44
39
|
v-model="state.activeTab"
|
|
45
40
|
:tabs="basicTabs"
|
|
46
|
-
:variant="state.variant"
|
|
47
41
|
/>
|
|
48
42
|
<p style="margin-top: 1rem; font-size: 0.875rem; color: var(--text-muted, #94a3b8);">
|
|
49
43
|
Active tab: <code>{{ state.activeTab }}</code>
|
|
@@ -52,11 +46,6 @@ function initPlayground() {
|
|
|
52
46
|
</template>
|
|
53
47
|
|
|
54
48
|
<template #controls="{ state }">
|
|
55
|
-
<HstSelect
|
|
56
|
-
v-model="state.variant"
|
|
57
|
-
title="Variant"
|
|
58
|
-
:options="variants.map(v => ({ label: v, value: v }))"
|
|
59
|
-
/>
|
|
60
49
|
<HstSelect
|
|
61
50
|
v-model="state.activeTab"
|
|
62
51
|
title="Active Tab"
|
|
@@ -65,27 +54,11 @@ function initPlayground() {
|
|
|
65
54
|
</template>
|
|
66
55
|
</Variant>
|
|
67
56
|
|
|
68
|
-
<Variant title="All Variants">
|
|
69
|
-
<div style="padding: 2rem; display: flex; flex-direction: column; gap: 2rem;">
|
|
70
|
-
<div v-for="variant in variants" :key="variant">
|
|
71
|
-
<p style="margin: 0 0 0.5rem; font-size: 0.75rem; color: var(--text-muted, #94a3b8); text-transform: uppercase; letter-spacing: 0.05em;">
|
|
72
|
-
{{ variant }}
|
|
73
|
-
</p>
|
|
74
|
-
<BaseTabs
|
|
75
|
-
v-model="activeTab"
|
|
76
|
-
:tabs="basicTabs"
|
|
77
|
-
:variant="variant"
|
|
78
|
-
/>
|
|
79
|
-
</div>
|
|
80
|
-
</div>
|
|
81
|
-
</Variant>
|
|
82
|
-
|
|
83
57
|
<Variant title="With Badges">
|
|
84
58
|
<div style="padding: 2rem;">
|
|
85
59
|
<BaseTabs
|
|
86
60
|
model-value="inbox"
|
|
87
61
|
:tabs="tabsWithBadges"
|
|
88
|
-
variant="underline"
|
|
89
62
|
/>
|
|
90
63
|
</div>
|
|
91
64
|
</Variant>
|
|
@@ -95,7 +68,6 @@ function initPlayground() {
|
|
|
95
68
|
<BaseTabs
|
|
96
69
|
model-value="plate"
|
|
97
70
|
:tabs="tabsWithIcons"
|
|
98
|
-
variant="pills"
|
|
99
71
|
/>
|
|
100
72
|
</div>
|
|
101
73
|
</Variant>
|
|
@@ -105,23 +77,9 @@ function initPlayground() {
|
|
|
105
77
|
<BaseTabs
|
|
106
78
|
model-value="inbox"
|
|
107
79
|
:tabs="tabsWithBadges"
|
|
108
|
-
variant="underline"
|
|
109
80
|
/>
|
|
110
81
|
</div>
|
|
111
82
|
</Variant>
|
|
112
83
|
|
|
113
|
-
<Variant title="Pills — matches SegmentedControl.card">
|
|
114
|
-
<div style="padding: 2rem; display: flex; justify-content: center;">
|
|
115
|
-
<BaseTabs
|
|
116
|
-
v-model="activeTab"
|
|
117
|
-
variant="pills"
|
|
118
|
-
:tabs="[
|
|
119
|
-
{ id: 'overview', label: 'Overview' },
|
|
120
|
-
{ id: 'samples', label: 'Samples' },
|
|
121
|
-
{ id: 'results', label: 'Results' },
|
|
122
|
-
]"
|
|
123
|
-
/>
|
|
124
|
-
</div>
|
|
125
|
-
</Variant>
|
|
126
84
|
</Story>
|
|
127
85
|
</template>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
|
-
/** Renders
|
|
2
|
+
/** Renders an underline tab bar with mono count badges, icons, and disabled tab support. */
|
|
3
3
|
import { computed, type ComponentPublicInstance } from 'vue'
|
|
4
4
|
import type { TabItem, TabItemInput } from '../types'
|
|
5
5
|
import { normalizeItemInput } from '../utils/items'
|
|
@@ -8,12 +8,9 @@ import { useRovingFocus } from '../composables/useRovingFocus'
|
|
|
8
8
|
interface Props {
|
|
9
9
|
modelValue: string
|
|
10
10
|
tabs: TabItemInput[]
|
|
11
|
-
variant?: 'underline' | 'pills'
|
|
12
11
|
}
|
|
13
12
|
|
|
14
|
-
const props =
|
|
15
|
-
variant: 'underline',
|
|
16
|
-
})
|
|
13
|
+
const props = defineProps<Props>()
|
|
17
14
|
|
|
18
15
|
const emit = defineEmits<{
|
|
19
16
|
'update:modelValue': [value: string]
|
|
@@ -55,7 +52,7 @@ const { handleKeydown } = useRovingFocus({
|
|
|
55
52
|
</script>
|
|
56
53
|
|
|
57
54
|
<template>
|
|
58
|
-
<div
|
|
55
|
+
<div class="mint-tabs mint-tabs--underline" role="tablist">
|
|
59
56
|
<button
|
|
60
57
|
v-for="tab in normalizedTabs"
|
|
61
58
|
:id="`mint-tab-${tab.id}`"
|
|
@@ -63,6 +63,14 @@ const { isOpen, rootRef: popoverRef, triggerRef, close, toggle } = useDropdownSt
|
|
|
63
63
|
const showSuccess = ref(false)
|
|
64
64
|
const showConfirm = ref(false)
|
|
65
65
|
|
|
66
|
+
function handleTriggerClick() {
|
|
67
|
+
if (!hasExperiment.value && !isUnresolved.value) {
|
|
68
|
+
handleSelect()
|
|
69
|
+
return
|
|
70
|
+
}
|
|
71
|
+
toggle()
|
|
72
|
+
}
|
|
73
|
+
|
|
66
74
|
function handleSelect() {
|
|
67
75
|
emit('select')
|
|
68
76
|
close()
|
|
@@ -115,7 +123,7 @@ onUnmounted(() => {
|
|
|
115
123
|
{ 'mint-experiment-popover__split--with-save': showSave && experimentName },
|
|
116
124
|
]"
|
|
117
125
|
>
|
|
118
|
-
<!-- Left: experiment trigger (opens popover). Prefer the human-readable
|
|
126
|
+
<!-- Left: experiment trigger (selects when empty, otherwise opens popover). Prefer the human-readable
|
|
119
127
|
name; the formal code, when present, stays in the detail panel. -->
|
|
120
128
|
<button
|
|
121
129
|
ref="triggerRef"
|
|
@@ -131,7 +139,7 @@ onUnmounted(() => {
|
|
|
131
139
|
:aria-label="isUnresolved ? triggerLabel : undefined"
|
|
132
140
|
:aria-busy="isResolving || undefined"
|
|
133
141
|
:aria-expanded="isOpen"
|
|
134
|
-
@click.stop="
|
|
142
|
+
@click.stop="handleTriggerClick"
|
|
135
143
|
>
|
|
136
144
|
<!-- Flask icon -->
|
|
137
145
|
<svg class="mint-experiment-popover__trigger-icon" aria-hidden="true" fill="none" stroke="currentColor" viewBox="0 0 24 24">
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { ref } from 'vue'
|
|
3
|
+
import FileBrowserModal from './FileBrowserModal.vue'
|
|
4
|
+
import type { FileEntry, FileSelection, ServerMount } from '../types/fileBrowserTypes'
|
|
5
|
+
|
|
6
|
+
const isOpen = ref(true)
|
|
7
|
+
|
|
8
|
+
const mounts: ServerMount[] = [
|
|
9
|
+
{
|
|
10
|
+
id: 'instrument-qe',
|
|
11
|
+
label: '/mnt/instrument-qe',
|
|
12
|
+
count: 4,
|
|
13
|
+
children: [
|
|
14
|
+
{
|
|
15
|
+
id: 'instrument-qe/2026-07',
|
|
16
|
+
label: '2026-07',
|
|
17
|
+
count: 12,
|
|
18
|
+
children: [
|
|
19
|
+
{ id: 'instrument-qe/2026-07/raw', label: 'raw', count: '1.2k' },
|
|
20
|
+
{ id: 'instrument-qe/2026-07/converted', label: 'converted', count: 840 },
|
|
21
|
+
{ id: 'instrument-qe/2026-07/logs', label: 'logs', count: 36 },
|
|
22
|
+
],
|
|
23
|
+
},
|
|
24
|
+
{ id: 'instrument-qe/2026-06', label: '2026-06', count: 9 },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
{ id: 'nas-shared', label: '/mnt/nas-shared', count: 18 },
|
|
28
|
+
{ id: 'scratch', label: '/mnt/scratch', count: 7 },
|
|
29
|
+
{ id: 'sequencer-01', label: '/mnt/sequencer-01', available: false },
|
|
30
|
+
]
|
|
31
|
+
|
|
32
|
+
const entries: FileEntry[] = [
|
|
33
|
+
{ name: 'calibration', path: '2026-07/hypoxia-run3/raw/calibration', kind: 'directory', child_count: 2 },
|
|
34
|
+
{ name: 'blanks', path: '2026-07/hypoxia-run3/raw/blanks', kind: 'directory', child_count: 6 },
|
|
35
|
+
{
|
|
36
|
+
name: 'HeLa_norm_0h_r1.raw',
|
|
37
|
+
path: '2026-07/hypoxia-run3/raw/HeLa_norm_0h_r1.raw',
|
|
38
|
+
kind: 'file',
|
|
39
|
+
size_bytes: 2_040_109_465,
|
|
40
|
+
extension: '.raw',
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
name: 'HeLa_norm_0h_r2.raw',
|
|
44
|
+
path: '2026-07/hypoxia-run3/raw/HeLa_norm_0h_r2.raw',
|
|
45
|
+
kind: 'file',
|
|
46
|
+
size_bytes: 2_040_109_465,
|
|
47
|
+
extension: '.raw',
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'HeLa_hypoxia_1pct_6h_r1.raw',
|
|
51
|
+
path: '2026-07/hypoxia-run3/raw/HeLa_hypoxia_1pct_6h_r1.raw',
|
|
52
|
+
kind: 'file',
|
|
53
|
+
size_bytes: 2_254_857_830,
|
|
54
|
+
extension: '.raw',
|
|
55
|
+
},
|
|
56
|
+
{
|
|
57
|
+
name: 'HeLa_hypoxia_1pct_6h_r2.raw',
|
|
58
|
+
path: '2026-07/hypoxia-run3/raw/HeLa_hypoxia_1pct_6h_r2.raw',
|
|
59
|
+
kind: 'file',
|
|
60
|
+
size_bytes: 2_254_857_830,
|
|
61
|
+
extension: '.raw',
|
|
62
|
+
},
|
|
63
|
+
{
|
|
64
|
+
name: 'HeLa_hypoxia_1pct_24h_r1.mzML',
|
|
65
|
+
path: '2026-07/hypoxia-run3/raw/HeLa_hypoxia_1pct_24h_r1.mzML',
|
|
66
|
+
kind: 'file',
|
|
67
|
+
size_bytes: 882_900_992,
|
|
68
|
+
extension: '.mzml',
|
|
69
|
+
},
|
|
70
|
+
{
|
|
71
|
+
name: 'acquisition_log.txt',
|
|
72
|
+
path: '2026-07/hypoxia-run3/raw/acquisition_log.txt',
|
|
73
|
+
kind: 'file',
|
|
74
|
+
size_bytes: 49_152,
|
|
75
|
+
extension: '.txt',
|
|
76
|
+
matches_type_rules: false,
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'sequence_table.csv',
|
|
80
|
+
path: '2026-07/hypoxia-run3/raw/sequence_table.csv',
|
|
81
|
+
kind: 'file',
|
|
82
|
+
size_bytes: 12_288,
|
|
83
|
+
extension: '.csv',
|
|
84
|
+
matches_type_rules: false,
|
|
85
|
+
},
|
|
86
|
+
]
|
|
87
|
+
|
|
88
|
+
const breadcrumbs = [
|
|
89
|
+
{ label: '/mnt/instrument-qe', path: '' },
|
|
90
|
+
{ label: '2026-07', path: '2026-07' },
|
|
91
|
+
{ label: 'hypoxia-run3', path: '2026-07/hypoxia-run3' },
|
|
92
|
+
{ label: 'raw', path: '2026-07/hypoxia-run3/raw' },
|
|
93
|
+
]
|
|
94
|
+
|
|
95
|
+
const selected: FileSelection[] = [
|
|
96
|
+
{ mount_id: 'instrument-qe/2026-07/raw', path: '2026-07/hypoxia-run3/raw/blanks', name: 'blanks', kind: 'directory', child_count: 6 },
|
|
97
|
+
{
|
|
98
|
+
mount_id: 'instrument-qe/2026-07/raw',
|
|
99
|
+
path: '2026-07/hypoxia-run3/raw/HeLa_norm_0h_r1.raw',
|
|
100
|
+
name: 'HeLa_norm_0h_r1.raw',
|
|
101
|
+
kind: 'file',
|
|
102
|
+
size_bytes: 2_040_109_465,
|
|
103
|
+
},
|
|
104
|
+
{
|
|
105
|
+
mount_id: 'instrument-qe/2026-07/raw',
|
|
106
|
+
path: '2026-07/hypoxia-run3/raw/HeLa_hypoxia_1pct_6h_r1.raw',
|
|
107
|
+
name: 'HeLa_hypoxia_1pct_6h_r1.raw',
|
|
108
|
+
kind: 'file',
|
|
109
|
+
size_bytes: 2_254_857_830,
|
|
110
|
+
},
|
|
111
|
+
{
|
|
112
|
+
mount_id: 'instrument-qe/2026-07/raw',
|
|
113
|
+
path: '2026-07/hypoxia-run3/raw/HeLa_hypoxia_1pct_6h_r2.raw',
|
|
114
|
+
name: 'HeLa_hypoxia_1pct_6h_r2.raw',
|
|
115
|
+
kind: 'file',
|
|
116
|
+
size_bytes: 2_254_857_830,
|
|
117
|
+
},
|
|
118
|
+
]
|
|
119
|
+
|
|
120
|
+
function initState() {
|
|
121
|
+
return {
|
|
122
|
+
open: true,
|
|
123
|
+
title: 'Select raw data',
|
|
124
|
+
contextCode: 'MM-EXP-014',
|
|
125
|
+
subtitle: '13C glucose tracing — HeLa, 24h',
|
|
126
|
+
dimNonMatching: true,
|
|
127
|
+
showLocalPicker: true,
|
|
128
|
+
loading: false,
|
|
129
|
+
selected,
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
</script>
|
|
133
|
+
|
|
134
|
+
<template>
|
|
135
|
+
<Story title="Experiment/FileBrowserModal">
|
|
136
|
+
<Variant title="Playground" :init-state="initState">
|
|
137
|
+
<template #default="{ state }">
|
|
138
|
+
<div style="padding: 2rem;">
|
|
139
|
+
<FileBrowserModal
|
|
140
|
+
v-model="state.open"
|
|
141
|
+
:mounts="mounts"
|
|
142
|
+
mount-id="instrument-qe/2026-07/raw"
|
|
143
|
+
path="2026-07/hypoxia-run3/raw"
|
|
144
|
+
parent="2026-07/hypoxia-run3"
|
|
145
|
+
:entries="entries"
|
|
146
|
+
:breadcrumbs="breadcrumbs"
|
|
147
|
+
:selected="state.selected"
|
|
148
|
+
:type-rules="['.raw', '.mzML']"
|
|
149
|
+
:total-count="1284"
|
|
150
|
+
:match-count="9"
|
|
151
|
+
:loading="state.loading"
|
|
152
|
+
:title="state.title"
|
|
153
|
+
:context-code="state.contextCode"
|
|
154
|
+
:subtitle="state.subtitle"
|
|
155
|
+
:dim-non-matching="state.dimNonMatching"
|
|
156
|
+
:show-local-picker="state.showLocalPicker"
|
|
157
|
+
confirm-label="Mount 4 items"
|
|
158
|
+
@update:selected="state.selected = $event"
|
|
159
|
+
/>
|
|
160
|
+
</div>
|
|
161
|
+
</template>
|
|
162
|
+
<template #controls="{ state }">
|
|
163
|
+
<HstCheckbox v-model="state.open" title="Open" />
|
|
164
|
+
<HstText v-model="state.title" title="Title" />
|
|
165
|
+
<HstText v-model="state.contextCode" title="Context code" />
|
|
166
|
+
<HstText v-model="state.subtitle" title="Subtitle" />
|
|
167
|
+
<HstCheckbox v-model="state.dimNonMatching" title="Dim non-matching" />
|
|
168
|
+
<HstCheckbox v-model="state.showLocalPicker" title="Show local picker" />
|
|
169
|
+
<HstCheckbox v-model="state.loading" title="Loading" />
|
|
170
|
+
</template>
|
|
171
|
+
</Variant>
|
|
172
|
+
|
|
173
|
+
<Variant title="Empty folder">
|
|
174
|
+
<div style="padding: 2rem;">
|
|
175
|
+
<FileBrowserModal
|
|
176
|
+
:model-value="isOpen"
|
|
177
|
+
:mounts="mounts"
|
|
178
|
+
mount-id="scratch"
|
|
179
|
+
path=""
|
|
180
|
+
:parent="null"
|
|
181
|
+
:entries="[]"
|
|
182
|
+
:breadcrumbs="[{ label: '/mnt/scratch', path: '' }]"
|
|
183
|
+
title="Select raw data"
|
|
184
|
+
/>
|
|
185
|
+
</div>
|
|
186
|
+
</Variant>
|
|
187
|
+
|
|
188
|
+
<Variant title="Offline mount">
|
|
189
|
+
<div style="padding: 2rem;">
|
|
190
|
+
<FileBrowserModal
|
|
191
|
+
:model-value="isOpen"
|
|
192
|
+
:mounts="mounts"
|
|
193
|
+
mount-id="sequencer-01"
|
|
194
|
+
path=""
|
|
195
|
+
:parent="null"
|
|
196
|
+
:entries="[]"
|
|
197
|
+
error="This mount is offline. Check that the share is reachable from the MINT server."
|
|
198
|
+
title="Select raw data"
|
|
199
|
+
/>
|
|
200
|
+
</div>
|
|
201
|
+
</Variant>
|
|
202
|
+
</Story>
|
|
203
|
+
</template>
|