@morscherlab/mint-sdk 1.5.0-beta.1 → 1.5.0-beta.10
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-Cai0w7gF.js} +3 -3
- package/dist/{AlertBox-CIhqsWbN.js.map → AlertBox-Cai0w7gF.js.map} +1 -1
- package/dist/{AppSidebar-BDrd7Kwn.js → AppSidebar-C-Vq5x4I.js} +410 -127
- package/dist/AppSidebar-C-Vq5x4I.js.map +1 -0
- package/dist/{ConfirmDialog-CjWoxAD1.js → ConfirmDialog-BjFsOpBe.js} +3 -3
- package/dist/ConfirmDialog-BjFsOpBe.js.map +1 -0
- package/dist/{ExperimentPopover-BM92LlrQ.js → ExperimentPopover-DYy_s0kI.js} +25 -37
- package/dist/ExperimentPopover-DYy_s0kI.js.map +1 -0
- package/dist/{ExperimentSelectorModal-LsB1ABmh.js → ExperimentSelectorModal-Bfh5bdkv.js} +37 -8
- package/dist/ExperimentSelectorModal-Bfh5bdkv.js.map +1 -0
- package/dist/{SegmentedControl-Dz41vAFM.js → SegmentedControl-B8KgyOjd.js} +2 -2
- package/dist/{SegmentedControl-Dz41vAFM.js.map → SegmentedControl-B8KgyOjd.js.map} +1 -1
- package/dist/{SettingsModal-C-MSR-bk.js → SettingsModal-DwfrD1ER.js} +7 -7
- package/dist/{SettingsModal-C-MSR-bk.js.map → SettingsModal-DwfrD1ER.js.map} +1 -1
- package/dist/__tests__/components/AppTopBarCompact.test.d.ts +1 -0
- package/dist/__tests__/components/AppTopBarCompactReset.test.d.ts +1 -0
- package/dist/__tests__/components/AutoGroupModal.experimentLoad.test.d.ts +1 -0
- package/dist/components/AppTopBar.compact.d.ts +5 -0
- package/dist/components/AppTopBar.vue.d.ts +17 -17
- package/dist/components/FormBuilder.vue.d.ts +1 -1
- package/dist/components/PluginIcon.vue.d.ts +2 -2
- package/dist/components/PluginWorkspaceView.vue.d.ts +4 -0
- package/dist/components/SectionCard.vue.d.ts +13 -1
- package/dist/components/SettingsModal.vue.d.ts +1 -1
- package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -2
- package/dist/components/internal/FormSchemaInternal.vue.d.ts +9 -9
- package/dist/components/internal/FormSectionRenderer.vue.d.ts +4 -4
- package/dist/components/internal/LucideIconInternal.vue.d.ts +17 -0
- package/dist/composables/appLayoutSidebar.d.ts +9 -0
- package/dist/composables/useExperimentSelector.d.ts +2 -0
- package/dist/composables/useOnboarding.d.ts +1 -1
- package/dist/composables/usePluginWorkspace.d.ts +2 -0
- package/dist/composables/useVersionedSave.d.ts +5 -2
- package/dist/{controlSchemaModel-BbXbMgc6.js → controlSchemaModel-BtFNZj8t.js} +2 -2
- package/dist/{controlSchemaModel-BbXbMgc6.js.map → controlSchemaModel-BtFNZj8t.js.map} +1 -1
- package/dist/{data-LzdkEZJ-.js → data-CJztFns8.js} +31 -15
- package/dist/{data-LzdkEZJ-.js.map → data-CJztFns8.js.map} +1 -1
- package/dist/data.js +8 -8
- package/dist/{experimentStatus-DCn2QKG7.js → experimentStatus-Deokk7Br.js} +2 -2
- package/dist/{experimentStatus-DCn2QKG7.js.map → experimentStatus-Deokk7Br.js.map} +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.js +15 -20
- package/dist/index.js.map +1 -1
- package/dist/{install-UTqrAgHe.js → install-Bk02tJ5M.js} +15 -40
- package/dist/install-Bk02tJ5M.js.map +1 -0
- package/dist/install.js +1 -1
- package/dist/{lab-CbdDLAVr.js → lab-BYhb_cJI.js} +47 -117
- package/dist/lab-BYhb_cJI.js.map +1 -0
- package/dist/lab.js +4 -4
- package/dist/{records-CWRztE5M.js → records-GtiVMlTQ.js} +207 -171
- package/dist/records-GtiVMlTQ.js.map +1 -0
- package/dist/{runtime-DrL6lKAb.js → runtime-aZPUPxoB.js} +112 -54
- package/dist/runtime-aZPUPxoB.js.map +1 -0
- package/dist/runtime.js +6 -6
- package/dist/{shell-Ch7cJnjo.js → shell-Bk9mD4Lc.js} +5 -5
- package/dist/{shell-Ch7cJnjo.js.map → shell-Bk9mD4Lc.js.map} +1 -1
- package/dist/shell.js +5 -5
- package/dist/styles.css +315 -134
- package/dist/styles.d.ts +1 -0
- package/dist/types/components.d.ts +22 -2
- package/dist/types/generated-ui.d.ts +2 -0
- package/dist/types/index.d.ts +2 -2
- package/dist/types/instrument.d.ts +5 -17
- package/dist/{useDropdownState-uFIz6Yv8.js → useDropdownState-CcBzUYZ6.js} +14 -5
- package/dist/useDropdownState-CcBzUYZ6.js.map +1 -0
- package/dist/{useExperimentSamples-Cz2v3V_q.js → useExperimentSamples-CpNXvpUn.js} +3 -3
- package/dist/{useExperimentSamples-Cz2v3V_q.js.map → useExperimentSamples-CpNXvpUn.js.map} +1 -1
- package/dist/{useListReorder-QqJc1dpX.js → useListReorder-Bp4EAI2w.js} +16 -4
- package/dist/useListReorder-Bp4EAI2w.js.map +1 -0
- package/dist/{useRackEditor-BHGM1Ngz.js → useRackEditor-i2bdPUFf.js} +156 -27
- package/dist/useRackEditor-i2bdPUFf.js.map +1 -0
- package/dist/{useRealtime-CNQbrS01.js → useRealtime-BLQEjbuq.js} +3 -3
- package/dist/{useRealtime-CNQbrS01.js.map → useRealtime-BLQEjbuq.js.map} +1 -1
- package/dist/useRequest-CXyPw3eh.js +76 -0
- package/dist/useRequest-CXyPw3eh.js.map +1 -0
- package/dist/utils/deprecation.d.ts +2 -0
- package/dist/utils/lucideIcon.d.ts +4 -0
- package/package.json +7 -4
- package/src/__tests__/components/AppTopBar.test.ts +102 -20
- package/src/__tests__/components/AppTopBarCompact.test.ts +65 -0
- package/src/__tests__/components/AppTopBarCompactReset.test.ts +24 -0
- package/src/__tests__/components/AppTopBarOnboarding.test.ts +10 -0
- package/src/__tests__/components/AutoGroupModal.experimentLoad.test.ts +58 -0
- package/src/__tests__/components/BaseModal.test.ts +33 -2
- package/src/__tests__/components/ConfirmDialog.test.ts +2 -2
- package/src/__tests__/components/ExperimentPopover.test.ts +32 -0
- package/src/__tests__/components/ExperimentSelectorModal.test.ts +16 -0
- package/src/__tests__/components/PluginWorkspaceView.test.ts +20 -1
- package/src/__tests__/components/SectionCard.test.ts +33 -0
- package/src/__tests__/components/deprecationTags.test.ts +4 -18
- package/src/__tests__/composables/useJobCenter.test.ts +35 -0
- package/src/__tests__/composables/useJobsEndpoint.test.ts +50 -0
- package/src/__tests__/composables/useOnboarding.test.ts +2 -2
- package/src/__tests__/composables/useVersionedSave.test.ts +71 -6
- package/src/__tests__/docs/frontendDocsCatalog.test.ts +3 -3
- package/src/__tests__/styles/menusShellRefresh.test.ts +10 -0
- package/src/components/AppLayout.story.vue +5 -5
- package/src/components/AppLayout.vue +13 -1
- package/src/components/AppSidebar.vue +2 -2
- package/src/components/AppTopBar.compact.ts +60 -0
- package/src/components/AppTopBar.story.vue +39 -14
- package/src/components/AppTopBar.vue +222 -89
- package/src/components/BaseModal.vue +16 -5
- package/src/components/CollapsibleCard.vue +1 -1
- package/src/components/ConfirmDialog.vue +1 -1
- package/src/components/ExperimentPopover.story.vue +2 -2
- package/src/components/ExperimentPopover.vue +6 -22
- package/src/components/ExperimentSelectorModal.vue +35 -0
- package/src/components/FileUploader.vue +3 -35
- package/src/components/GeneratedPluginView.vue +34 -81
- package/src/components/GeneratedResultRenderer.vue +2 -1
- package/src/components/InstrumentStatusPanels.vue +3 -3
- package/src/components/PlotlyChart.vue +1 -1
- package/src/components/PluginIcon.story.vue +2 -2
- package/src/components/PluginIcon.vue +2 -2
- package/src/components/PluginWorkspaceView.vue +10 -1
- package/src/components/SectionCard.vue +42 -6
- package/src/components/internal/AppTopBarOnboardingInternal.vue +30 -14
- package/src/components/internal/AppTopBarPageSelectorInternal.vue +12 -0
- package/src/components/internal/AutoGroupModalInternal.vue +14 -3
- package/src/components/internal/LucideIconInternal.vue +23 -0
- package/src/composables/appLayoutSidebar.ts +11 -0
- package/src/composables/index.ts +1 -2
- package/src/composables/useExperimentSelector.ts +4 -0
- package/src/composables/useJobCenter.ts +21 -1
- package/src/composables/useJobsEndpoint.ts +15 -4
- package/src/composables/useOnboarding.ts +3 -3
- package/src/composables/usePluginWorkspace.ts +15 -4
- package/src/composables/useVersionedSave.ts +32 -7
- package/src/generated-ui/main.ts +3 -1
- package/src/index.ts +0 -3
- package/src/styles/components/alert-box.css +1 -1
- package/src/styles/components/app-layout.css +5 -0
- package/src/styles/components/app-sidebar.css +5 -5
- package/src/styles/components/app-top-bar.css +130 -9
- 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/onboarding.css +39 -0
- package/src/styles/components/pill.css +1 -1
- package/src/styles/components/plugin-icon.css +2 -2
- package/src/styles/components/presence-avatars.css +4 -4
- package/src/styles/components/progress-bar.css +1 -1
- package/src/styles/components/section-card.css +65 -6
- 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 +10 -4
- package/src/types/components.ts +23 -2
- package/src/types/generated-ui.ts +2 -0
- package/src/types/index.ts +1 -1
- package/src/types/instrument.ts +5 -18
- package/src/utils/deprecation.ts +8 -0
- package/src/utils/lucideIcon.ts +25 -0
- package/src/utils/lucideIconIndex.d.ts +2 -0
- package/dist/AppSidebar-BDrd7Kwn.js.map +0 -1
- package/dist/ConfirmDialog-CjWoxAD1.js.map +0 -1
- package/dist/ExperimentPopover-BM92LlrQ.js.map +0 -1
- package/dist/ExperimentSelectorModal-LsB1ABmh.js.map +0 -1
- package/dist/deprecatedRootExports.d.ts +0 -191
- package/dist/install-UTqrAgHe.js.map +0 -1
- package/dist/lab-CbdDLAVr.js.map +0 -1
- package/dist/records-CWRztE5M.js.map +0 -1
- package/dist/runtime-DrL6lKAb.js.map +0 -1
- package/dist/useDropdownState-uFIz6Yv8.js.map +0 -1
- package/dist/useListReorder-QqJc1dpX.js.map +0 -1
- package/dist/useRackEditor-BHGM1Ngz.js.map +0 -1
- package/dist/useRequest-Bfsh7gIm.js +0 -215
- package/dist/useRequest-Bfsh7gIm.js.map +0 -1
- package/src/deprecatedRootExports.ts +0 -226
|
@@ -22,10 +22,12 @@ import {
|
|
|
22
22
|
type GeneratedAnalysisTransport,
|
|
23
23
|
} from '../composables/useJobsEndpoint'
|
|
24
24
|
import AlertBox from './AlertBox.vue'
|
|
25
|
+
import AppContainer from './AppContainer.vue'
|
|
25
26
|
import EmptyState from './EmptyState.vue'
|
|
26
27
|
import GeneratedResultRenderer from './GeneratedResultRenderer.vue'
|
|
27
28
|
import LoadingSpinner from './LoadingSpinner.vue'
|
|
28
29
|
import PluginWorkspaceView from './PluginWorkspaceView.vue'
|
|
30
|
+
import SectionCard from './SectionCard.vue'
|
|
29
31
|
import { GENERATED_JOBS_API_KEY } from './internal/generatedJobsApi'
|
|
30
32
|
import { definePluginWorkspaceView } from '../composables/componentSpecs'
|
|
31
33
|
import { providePluginIdentity } from '../composables/pluginIdentity'
|
|
@@ -48,6 +50,7 @@ const generated = useJobsEndpoint({
|
|
|
48
50
|
provide(GENERATED_JOBS_API_KEY, { baseUrl: props.baseUrl, transport: props.transport })
|
|
49
51
|
const activeDefinitionId = ref('')
|
|
50
52
|
const selectedJobId = ref('')
|
|
53
|
+
const sidebarCollapsed = ref(false)
|
|
51
54
|
const valuesByDefinition = reactive<Record<string, Record<string, unknown>>>({})
|
|
52
55
|
const definitions = computed(() => generated.manifest.value?.jobs ?? [])
|
|
53
56
|
const activeDefinition = computed(() => (
|
|
@@ -77,12 +80,21 @@ const workspace = computed(() => definePluginWorkspaceView({
|
|
|
77
80
|
subtitle: generated.manifest.value?.ui.subtitle || generated.manifest.value?.ui.description,
|
|
78
81
|
// The platform shell renders the toasts around this view.
|
|
79
82
|
toasts: false,
|
|
83
|
+
floating: true,
|
|
80
84
|
topBar: {
|
|
85
|
+
variant: 'card',
|
|
81
86
|
pills: pillNav.value,
|
|
82
87
|
settings: false,
|
|
83
88
|
standaloneLabel: props.showStandaloneLabel ? 'Standalone' : false,
|
|
84
89
|
},
|
|
85
|
-
sidebar: {
|
|
90
|
+
sidebar: {
|
|
91
|
+
title: 'Parameters',
|
|
92
|
+
width: '300px',
|
|
93
|
+
collapsible: true,
|
|
94
|
+
collapsedWidth: '3rem',
|
|
95
|
+
panels: panels.value,
|
|
96
|
+
forms: forms.value,
|
|
97
|
+
},
|
|
86
98
|
jobs: generated,
|
|
87
99
|
}))
|
|
88
100
|
|
|
@@ -160,6 +172,7 @@ onMounted(() => {
|
|
|
160
172
|
<template>
|
|
161
173
|
<PluginWorkspaceView
|
|
162
174
|
v-model:view="activeDefinitionId"
|
|
175
|
+
v-model:sidebar-collapsed="sidebarCollapsed"
|
|
163
176
|
:spec="workspace"
|
|
164
177
|
:values="currentValues"
|
|
165
178
|
:form-loading="generated.isSubmitting.value"
|
|
@@ -168,7 +181,7 @@ onMounted(() => {
|
|
|
168
181
|
@form-submit="submitJob"
|
|
169
182
|
@job-select="selectJob"
|
|
170
183
|
>
|
|
171
|
-
<
|
|
184
|
+
<AppContainer direction="column" gap="var(--mint-gutter)" class="mint-generated-workspace">
|
|
172
185
|
<div v-if="generated.isLoading.value" class="mint-generated-workspace__loading">
|
|
173
186
|
<LoadingSpinner size="lg" />
|
|
174
187
|
<span>Loading analysis workspace</span>
|
|
@@ -177,18 +190,15 @@ onMounted(() => {
|
|
|
177
190
|
<template v-else>
|
|
178
191
|
<AlertBox v-if="generated.error.value" tone="error">{{ generated.error.value }}</AlertBox>
|
|
179
192
|
|
|
180
|
-
<
|
|
181
|
-
<
|
|
182
|
-
<
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
</
|
|
186
|
-
<
|
|
187
|
-
|
|
188
|
-
</
|
|
189
|
-
</header>
|
|
190
|
-
|
|
191
|
-
<section class="mint-generated-workspace__result">
|
|
193
|
+
<SectionCard :title="activeDefinition?.title ?? 'Result'">
|
|
194
|
+
<template v-if="activeDefinition" #actions>
|
|
195
|
+
<span class="mint-generated-workspace__resources" aria-label="Job resource requirements">
|
|
196
|
+
{{ resourceSummary(activeDefinition) }}
|
|
197
|
+
</span>
|
|
198
|
+
</template>
|
|
199
|
+
<p v-if="activeDefinition?.description" class="mint-generated-workspace__description">
|
|
200
|
+
{{ activeDefinition.description }}
|
|
201
|
+
</p>
|
|
192
202
|
<GeneratedResultRenderer
|
|
193
203
|
v-if="currentResult"
|
|
194
204
|
:result="currentResult"
|
|
@@ -199,93 +209,36 @@ onMounted(() => {
|
|
|
199
209
|
description="Set the parameters and run the analysis. Jobs continue independently if you switch tabs."
|
|
200
210
|
size="md"
|
|
201
211
|
/>
|
|
202
|
-
</
|
|
212
|
+
</SectionCard>
|
|
203
213
|
</template>
|
|
204
|
-
</
|
|
214
|
+
</AppContainer>
|
|
205
215
|
</PluginWorkspaceView>
|
|
206
216
|
</template>
|
|
207
217
|
|
|
208
218
|
<style scoped>
|
|
209
219
|
.mint-generated-workspace {
|
|
210
|
-
position: relative;
|
|
211
220
|
min-width: 0;
|
|
212
|
-
min-height:
|
|
213
|
-
|
|
214
|
-
background: var(--bg-primary);
|
|
221
|
+
min-height: 0;
|
|
222
|
+
overflow-y: auto;
|
|
215
223
|
}
|
|
216
224
|
|
|
217
225
|
.mint-generated-workspace__loading {
|
|
218
226
|
display: flex;
|
|
219
|
-
|
|
227
|
+
flex: 1;
|
|
220
228
|
align-items: center;
|
|
221
229
|
justify-content: center;
|
|
222
230
|
gap: 0.75rem;
|
|
223
231
|
color: var(--text-secondary);
|
|
224
232
|
}
|
|
225
233
|
|
|
226
|
-
.mint-generated-workspace__header {
|
|
227
|
-
display: flex;
|
|
228
|
-
align-items: flex-start;
|
|
229
|
-
justify-content: space-between;
|
|
230
|
-
gap: 1.5rem;
|
|
231
|
-
max-width: 76rem;
|
|
232
|
-
margin: 0 auto 1.25rem;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
.mint-generated-workspace__header h1 {
|
|
236
|
-
margin: 0;
|
|
237
|
-
color: var(--text-primary);
|
|
238
|
-
font-size: clamp(1.35rem, 2vw, 1.8rem);
|
|
239
|
-
line-height: 1.2;
|
|
240
|
-
}
|
|
241
|
-
|
|
242
|
-
.mint-generated-workspace__header p:not(.mint-generated-workspace__eyebrow) {
|
|
243
|
-
margin: 0.4rem 0 0;
|
|
244
|
-
color: var(--text-secondary);
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
.mint-generated-workspace__eyebrow {
|
|
248
|
-
margin: 0 0 0.35rem;
|
|
249
|
-
color: var(--text-secondary);
|
|
250
|
-
font-size: 0.72rem;
|
|
251
|
-
font-weight: 700;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
234
|
.mint-generated-workspace__resources {
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
justify-content: flex-end;
|
|
258
|
-
gap: 0.4rem;
|
|
259
|
-
}
|
|
260
|
-
|
|
261
|
-
.mint-generated-workspace__resources span {
|
|
262
|
-
padding: 0.3rem 0.55rem;
|
|
263
|
-
border: 1px solid var(--border-color);
|
|
264
|
-
border-radius: 999px;
|
|
265
|
-
background: var(--bg-secondary);
|
|
266
|
-
color: var(--text-secondary);
|
|
235
|
+
color: var(--text-muted);
|
|
236
|
+
font-family: var(--font-mono);
|
|
267
237
|
font-size: 0.75rem;
|
|
268
|
-
font-weight: 600;
|
|
269
238
|
}
|
|
270
239
|
|
|
271
|
-
.mint-generated-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
margin: 0 auto;
|
|
275
|
-
padding: clamp(1rem, 2vw, 1.75rem);
|
|
276
|
-
border: 1px solid var(--border-color);
|
|
277
|
-
border-radius: 1rem;
|
|
278
|
-
background: var(--bg-secondary);
|
|
279
|
-
box-shadow: var(--shadow-sm);
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
@media (max-width: 640px) {
|
|
283
|
-
.mint-generated-workspace__header {
|
|
284
|
-
flex-direction: column;
|
|
285
|
-
}
|
|
286
|
-
|
|
287
|
-
.mint-generated-workspace__resources {
|
|
288
|
-
justify-content: flex-start;
|
|
289
|
-
}
|
|
240
|
+
.mint-generated-workspace__description {
|
|
241
|
+
margin: 0 0 var(--mint-gutter);
|
|
242
|
+
color: var(--text-secondary);
|
|
290
243
|
}
|
|
291
244
|
</style>
|
|
@@ -133,6 +133,7 @@ function humanize(value: string): string {
|
|
|
133
133
|
padding: 0.75rem 1rem;
|
|
134
134
|
border-radius: var(--radius-md);
|
|
135
135
|
background: var(--bg-tertiary);
|
|
136
|
+
font-family: var(--font-mono);
|
|
136
137
|
font-size: 0.8125rem;
|
|
137
138
|
line-height: 1.55;
|
|
138
139
|
white-space: pre-wrap;
|
|
@@ -152,7 +153,7 @@ function humanize(value: string): string {
|
|
|
152
153
|
gap: 1rem;
|
|
153
154
|
padding: 1rem;
|
|
154
155
|
border: 1px solid var(--border-color);
|
|
155
|
-
border-radius:
|
|
156
|
+
border-radius: var(--radius-lg);
|
|
156
157
|
color: var(--color-primary);
|
|
157
158
|
text-decoration: none;
|
|
158
159
|
}
|
|
@@ -105,11 +105,11 @@ function formatValue(value: string | number | boolean | null): string {
|
|
|
105
105
|
</template>
|
|
106
106
|
|
|
107
107
|
<style scoped>
|
|
108
|
-
.mint-status-panels__tabs { padding: 0
|
|
109
|
-
.mint-status-panels__body { padding: 0.75rem
|
|
108
|
+
.mint-status-panels__tabs { padding: 0 var(--mint-section-card-inset); }
|
|
109
|
+
.mint-status-panels__body { padding: 0.75rem var(--mint-section-card-inset); }
|
|
110
110
|
.mint-status-panels__bar { display: flex; flex-direction: column; gap: 0.5rem; }
|
|
111
111
|
.mint-status-panels__series { align-self: flex-end; }
|
|
112
|
-
.mint-status-panels__kv { margin: 0; padding: 0.25rem
|
|
112
|
+
.mint-status-panels__kv { margin: 0; padding: 0.25rem var(--mint-section-card-inset) 0.5rem; }
|
|
113
113
|
.mint-status-panels__kv-row {
|
|
114
114
|
display: flex;
|
|
115
115
|
align-items: baseline;
|
|
@@ -52,8 +52,8 @@ function initState() {
|
|
|
52
52
|
<HstText v-model="state.icon" title="icon" />
|
|
53
53
|
<HstSelect v-model="state.size" title="size" :options="['sm', 'md', 'topbar', 'lg']" />
|
|
54
54
|
<HstSelect v-model="state.variant" title="variant" :options="['solid', 'tinted']" />
|
|
55
|
-
<HstSelect v-model="state.tone" title="tone (deprecated, no effect; removed in
|
|
56
|
-
<HstText v-model="state.color" title="color (deprecated, no effect; removed in
|
|
55
|
+
<HstSelect v-model="state.tone" title="tone (deprecated, no effect; removed in 2.0)" :options="['', 'neutral', 'primary', 'cta', 'success', 'warning', 'error', 'info']" />
|
|
56
|
+
<HstText v-model="state.color" title="color (deprecated, no effect; removed in 2.0)" />
|
|
57
57
|
</template>
|
|
58
58
|
</Variant>
|
|
59
59
|
|
|
@@ -18,9 +18,9 @@ interface Props {
|
|
|
18
18
|
icon?: string
|
|
19
19
|
size?: 'sm' | 'md' | 'topbar' | 'lg'
|
|
20
20
|
variant?: 'solid' | 'tinted'
|
|
21
|
-
/** @deprecated v2 design: the tile is always the neutral accent-soft tile, so the tone has no visible effect. Removed in
|
|
21
|
+
/** @deprecated v2 design: the tile is always the neutral accent-soft tile, so the tone has no visible effect. Removed in 2.0. */
|
|
22
22
|
tone?: Tone
|
|
23
|
-
/** @deprecated v2 design: the tile is always the neutral accent-soft tile, so the color has no visible effect. Removed in
|
|
23
|
+
/** @deprecated v2 design: the tile is always the neutral accent-soft tile, so the color has no visible effect. Removed in 2.0. */
|
|
24
24
|
color?: string
|
|
25
25
|
}
|
|
26
26
|
|
|
@@ -24,6 +24,7 @@ import type { JobState } from '../types/jobs'
|
|
|
24
24
|
import { useAppExperiment } from '../composables/useAppExperiment'
|
|
25
25
|
import { useJobCenter } from '../composables/useJobCenter'
|
|
26
26
|
import { usePluginWorkspace } from '../composables/usePluginWorkspace'
|
|
27
|
+
import { warnDeprecatedOnce } from '../utils/deprecation'
|
|
27
28
|
import AppToastContainer from './AppToastContainer.vue'
|
|
28
29
|
import JobsStatusTray from './JobsStatusTray.vue'
|
|
29
30
|
import WorkspaceControlsInternal from './internal/WorkspaceControlsInternal.vue'
|
|
@@ -51,12 +52,16 @@ const emit = defineEmits<PluginWorkspaceViewEmits>()
|
|
|
51
52
|
|
|
52
53
|
defineSlots<{
|
|
53
54
|
default?: (props: PluginWorkspaceSlotProps) => unknown
|
|
55
|
+
/** @deprecated Configure the bar with `spec.topBar` and page icons; removed in 2.0. */
|
|
54
56
|
topbar?: (props: PluginWorkspaceSlotProps) => unknown
|
|
55
57
|
sidebar?: (props: PluginWorkspaceSlotProps) => unknown
|
|
56
58
|
icon?: (props: PluginWorkspaceForwardedSlotProps) => unknown
|
|
57
59
|
logo?: (props: PluginWorkspaceForwardedSlotProps) => unknown
|
|
60
|
+
/** @deprecated Removed in 2.0. */
|
|
58
61
|
nav?: (props: PluginWorkspaceForwardedSlotProps) => unknown
|
|
62
|
+
/** @deprecated Removed in 2.0. */
|
|
59
63
|
center?: (props: PluginWorkspaceForwardedSlotProps) => unknown
|
|
64
|
+
/** @deprecated Use `spec.topBar.actions`; removed in 2.0. */
|
|
60
65
|
actions?: (props: PluginWorkspaceForwardedSlotProps) => unknown
|
|
61
66
|
'settings-appearance'?: (props: PluginWorkspaceForwardedSlotProps) => unknown
|
|
62
67
|
header?: (props: PluginWorkspaceForwardedSlotProps) => unknown
|
|
@@ -66,6 +71,9 @@ defineSlots<{
|
|
|
66
71
|
}>()
|
|
67
72
|
|
|
68
73
|
const slots = useSlots()
|
|
74
|
+
if (slots.topbar) {
|
|
75
|
+
warnDeprecatedOnce('workspace.slot.topbar', 'PluginWorkspaceView #topbar is deprecated: configure spec.topBar and give pages icons. It is removed in 2.0.')
|
|
76
|
+
}
|
|
69
77
|
|
|
70
78
|
// The experiment chip is setup-time structure, like the rest of the spec.
|
|
71
79
|
if (props.spec.experiment) {
|
|
@@ -93,6 +101,7 @@ const {
|
|
|
93
101
|
controls,
|
|
94
102
|
handleControlValuesUpdate,
|
|
95
103
|
handlePillSelect,
|
|
104
|
+
handleSidebarCollapsedUpdate,
|
|
96
105
|
} = usePluginWorkspace({
|
|
97
106
|
props,
|
|
98
107
|
slots,
|
|
@@ -146,7 +155,7 @@ function handleFormCancel(sectionId: string) {
|
|
|
146
155
|
<WorkspaceSidebarInternal
|
|
147
156
|
:sidebar="sidebar"
|
|
148
157
|
@update:values="handleControlValuesUpdate"
|
|
149
|
-
@update:collapsed="
|
|
158
|
+
@update:collapsed="handleSidebarCollapsedUpdate"
|
|
150
159
|
@update:toggle="handleToggle"
|
|
151
160
|
@section-action="(sectionId: string, actionId: string) => emit('section-action', sectionId, actionId)"
|
|
152
161
|
@form-submit="handleFormSubmit"
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
/** One-card page region from the MINT 1.1 card system: 12px radius, the
|
|
3
3
|
* single --card-shadow token, a header strip (icon chip, title, mono count,
|
|
4
4
|
* actions), and hairline-separated content — no card-in-card. */
|
|
5
|
-
import { computed } from 'vue'
|
|
5
|
+
import { computed, useId } from 'vue'
|
|
6
6
|
import type { SectionCardAccent, SectionCardDivider } from '../types'
|
|
7
7
|
|
|
8
8
|
interface Props {
|
|
@@ -23,6 +23,8 @@ interface Props {
|
|
|
23
23
|
* definite height (a flex or grid track).
|
|
24
24
|
*/
|
|
25
25
|
fill?: boolean
|
|
26
|
+
/** The title toggles the body; bind `v-model:collapsed` to control or keep the state. */
|
|
27
|
+
collapsible?: boolean
|
|
26
28
|
}
|
|
27
29
|
|
|
28
30
|
const props = withDefaults(defineProps<Props>(), {
|
|
@@ -32,8 +34,14 @@ const props = withDefaults(defineProps<Props>(), {
|
|
|
32
34
|
uppercase: false,
|
|
33
35
|
divider: 'strong',
|
|
34
36
|
fill: false,
|
|
37
|
+
collapsible: false,
|
|
35
38
|
})
|
|
36
39
|
|
|
40
|
+
const collapsed = defineModel<boolean>('collapsed', { default: false })
|
|
41
|
+
const bodyId = useId()
|
|
42
|
+
/** `collapsed` hides content only on a card that also shows the toggle to open it again. */
|
|
43
|
+
const hidden = computed(() => props.collapsible && collapsed.value)
|
|
44
|
+
|
|
37
45
|
const iconPaths = computed(() =>
|
|
38
46
|
props.icon === undefined ? [] : Array.isArray(props.icon) ? props.icon : [props.icon],
|
|
39
47
|
)
|
|
@@ -41,6 +49,7 @@ const iconPaths = computed(() =>
|
|
|
41
49
|
const headerClasses = computed(() => [
|
|
42
50
|
'mint-section-card__header',
|
|
43
51
|
props.divider === 'light' ? 'mint-section-card__header--divider-light' : '',
|
|
52
|
+
hidden.value ? 'mint-section-card__header--collapsed' : '',
|
|
44
53
|
])
|
|
45
54
|
|
|
46
55
|
const titleClasses = computed(() => [
|
|
@@ -51,6 +60,7 @@ const titleClasses = computed(() => [
|
|
|
51
60
|
const cardClasses = computed(() => [
|
|
52
61
|
'mint-section-card',
|
|
53
62
|
props.fill ? 'mint-section-card--fill' : '',
|
|
63
|
+
hidden.value ? 'mint-section-card--collapsed' : '',
|
|
54
64
|
])
|
|
55
65
|
</script>
|
|
56
66
|
|
|
@@ -74,20 +84,46 @@ const cardClasses = computed(() => [
|
|
|
74
84
|
<path v-for="(d, i) in iconPaths" :key="i" :d="d" />
|
|
75
85
|
</svg>
|
|
76
86
|
</span>
|
|
77
|
-
|
|
78
|
-
<
|
|
87
|
+
<!-- Disclosure pattern: the button sits inside the heading, never the reverse. -->
|
|
88
|
+
<h2 :class="titleClasses">
|
|
89
|
+
<button
|
|
90
|
+
v-if="collapsible"
|
|
91
|
+
type="button"
|
|
92
|
+
class="mint-section-card__toggle"
|
|
93
|
+
:aria-expanded="!collapsed"
|
|
94
|
+
:aria-controls="bodyId"
|
|
95
|
+
@click="collapsed = !collapsed"
|
|
96
|
+
>
|
|
97
|
+
{{ title }}
|
|
98
|
+
<span v-if="count !== undefined" class="mint-section-card__count">{{ count }}</span>
|
|
99
|
+
<svg
|
|
100
|
+
class="mint-section-card__chevron"
|
|
101
|
+
viewBox="0 0 24 24"
|
|
102
|
+
fill="none"
|
|
103
|
+
stroke="currentColor"
|
|
104
|
+
stroke-width="2"
|
|
105
|
+
stroke-linecap="round"
|
|
106
|
+
stroke-linejoin="round"
|
|
107
|
+
aria-hidden="true"
|
|
108
|
+
>
|
|
109
|
+
<path d="m6 9 6 6 6-6" />
|
|
110
|
+
</svg>
|
|
111
|
+
</button>
|
|
112
|
+
<template v-else>{{ title }}</template>
|
|
113
|
+
</h2>
|
|
114
|
+
<span v-if="count !== undefined && !collapsible" class="mint-section-card__count">{{ count }}</span>
|
|
79
115
|
<div class="mint-section-card__spacer"></div>
|
|
80
116
|
<slot name="actions" />
|
|
81
117
|
</div>
|
|
82
118
|
<!-- Controls belong to the card's chrome, so they sit outside the body and
|
|
83
119
|
stay put while the body scrolls. -->
|
|
84
|
-
<div v-if="$slots.toolbar" class="mint-section-card__toolbar">
|
|
120
|
+
<div v-if="$slots.toolbar" v-show="!hidden" class="mint-section-card__toolbar">
|
|
85
121
|
<slot name="toolbar" />
|
|
86
122
|
</div>
|
|
87
|
-
<div class="mint-section-card__body">
|
|
123
|
+
<div :id="bodyId" v-show="!hidden" class="mint-section-card__body">
|
|
88
124
|
<slot />
|
|
89
125
|
</div>
|
|
90
|
-
<div v-if="$slots.footer" class="mint-section-card__footer">
|
|
126
|
+
<div v-if="$slots.footer" v-show="!hidden" class="mint-section-card__footer">
|
|
91
127
|
<slot name="footer" />
|
|
92
128
|
</div>
|
|
93
129
|
</section>
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'
|
|
7
7
|
import { autoUpdate, computePosition, offset, shift } from '@floating-ui/dom'
|
|
8
|
-
import { Check, CircleHelp, Play } from 'lucide-vue-next'
|
|
8
|
+
import { Check, CircleHelp, Play, X } from 'lucide-vue-next'
|
|
9
9
|
import { useEventListener } from '../../composables/useEventListener'
|
|
10
10
|
import type { OnboardingState } from '../../composables/useOnboarding'
|
|
11
11
|
import OnboardingLayerInternal from './OnboardingLayerInternal.vue'
|
|
@@ -50,6 +50,12 @@ watch(open, async (isOpen) => {
|
|
|
50
50
|
})
|
|
51
51
|
onBeforeUnmount(() => stopAutoUpdate?.())
|
|
52
52
|
|
|
53
|
+
// The close button removes itself, so focus moves on to Help instead of the page.
|
|
54
|
+
function hideChecklist() {
|
|
55
|
+
props.state.setChecklistHidden(true)
|
|
56
|
+
nextTick(() => helpButton.value?.focus())
|
|
57
|
+
}
|
|
58
|
+
|
|
53
59
|
function run(action: () => void) {
|
|
54
60
|
open.value = false
|
|
55
61
|
action()
|
|
@@ -66,19 +72,29 @@ useEventListener(document, 'keydown', (event) => {
|
|
|
66
72
|
|
|
67
73
|
<template>
|
|
68
74
|
<div v-if="hasContent" ref="root" class="mint-onboarding-help">
|
|
69
|
-
<
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
75
|
+
<span v-if="state.checklistVisible.value" class="mint-onboarding-help__chip-group">
|
|
76
|
+
<button
|
|
77
|
+
type="button"
|
|
78
|
+
class="mint-onboarding-help__chip"
|
|
79
|
+
:class="{ 'mint-onboarding-help__chip--open': open }"
|
|
80
|
+
data-onboarding="topbar-checklist"
|
|
81
|
+
:aria-expanded="open"
|
|
82
|
+
@click="toggle"
|
|
83
|
+
>
|
|
84
|
+
Getting started
|
|
85
|
+
<span class="mint-onboarding-help__count">{{ state.tasksDone.value }}/{{ state.tasks.value.length }}</span>
|
|
86
|
+
<span class="mint-onboarding-help__bar" aria-hidden="true"><span :style="{ width: `${progress}%` }" /></span>
|
|
87
|
+
</button>
|
|
88
|
+
<button
|
|
89
|
+
type="button"
|
|
90
|
+
class="mint-onboarding-help__chip-close"
|
|
91
|
+
aria-label="Hide checklist"
|
|
92
|
+
title="Hide checklist (Help can show it again)"
|
|
93
|
+
@click="hideChecklist"
|
|
94
|
+
>
|
|
95
|
+
<X :size="12" aria-hidden="true" />
|
|
96
|
+
</button>
|
|
97
|
+
</span>
|
|
82
98
|
<button
|
|
83
99
|
ref="helpButton"
|
|
84
100
|
type="button"
|
|
@@ -6,7 +6,9 @@ import { useMenuKeyboard } from '../../composables/useMenuKeyboard'
|
|
|
6
6
|
import type { PageSelectorItem, PageSelectorItemInput } from '../../types/components'
|
|
7
7
|
import { normalizeItemInput } from '../../utils/items'
|
|
8
8
|
import { isPluginIconFormat } from '../../utils/pluginIcon'
|
|
9
|
+
import { isLucideIconName } from '../../utils/lucideIcon'
|
|
9
10
|
import ActionItemInternal from './ActionItemInternal.vue'
|
|
11
|
+
import LucideIconInternal from './LucideIconInternal.vue'
|
|
10
12
|
import PluginIcon from '../PluginIcon.vue'
|
|
11
13
|
|
|
12
14
|
interface Props {
|
|
@@ -123,6 +125,11 @@ function handleSelect(page: PageSelectorItem) {
|
|
|
123
125
|
size="sm"
|
|
124
126
|
variant="solid"
|
|
125
127
|
/>
|
|
128
|
+
<LucideIconInternal v-else-if="isLucideIconName(current.icon)" :name="current.icon">
|
|
129
|
+
<template #fallback>
|
|
130
|
+
<span class="mint-page-selector__icon-fallback">{{ current.label.charAt(0) }}</span>
|
|
131
|
+
</template>
|
|
132
|
+
</LucideIconInternal>
|
|
126
133
|
<span v-else class="mint-page-selector__icon-fallback">{{ current.label.charAt(0) }}</span>
|
|
127
134
|
</slot>
|
|
128
135
|
</span>
|
|
@@ -180,6 +187,11 @@ function handleSelect(page: PageSelectorItem) {
|
|
|
180
187
|
size="sm"
|
|
181
188
|
variant="solid"
|
|
182
189
|
/>
|
|
190
|
+
<LucideIconInternal v-else-if="isLucideIconName(page.icon)" :name="page.icon">
|
|
191
|
+
<template #fallback>
|
|
192
|
+
<span class="mint-page-selector__icon-fallback">{{ page.label.charAt(0) }}</span>
|
|
193
|
+
</template>
|
|
194
|
+
</LucideIconInternal>
|
|
183
195
|
<span v-else class="mint-page-selector__icon-fallback">{{ page.label.charAt(0) }}</span>
|
|
184
196
|
</slot>
|
|
185
197
|
</span>
|
|
@@ -209,8 +209,12 @@ function close() {
|
|
|
209
209
|
emit('update:open', false)
|
|
210
210
|
}
|
|
211
211
|
|
|
212
|
+
// A close or a newer fetch makes the response of an earlier fetch obsolete.
|
|
213
|
+
let fetchGeneration = 0
|
|
214
|
+
|
|
212
215
|
async function fetchExperimentData() {
|
|
213
216
|
if (!props.experimentId && !props.designData) return
|
|
217
|
+
const generation = ++fetchGeneration
|
|
214
218
|
autoGroup.inputMode.value = 'experiment'
|
|
215
219
|
experimentError.value = null
|
|
216
220
|
experimentLoading.value = true
|
|
@@ -221,6 +225,7 @@ async function fetchExperimentData() {
|
|
|
221
225
|
} else {
|
|
222
226
|
const result = await api.get<Record<string, unknown>>(`/experiments/${props.experimentId}/data`)
|
|
223
227
|
pluginData = result.data as Record<string, unknown> | undefined
|
|
228
|
+
if (generation !== fetchGeneration) return
|
|
224
229
|
}
|
|
225
230
|
if (!pluginData || typeof pluginData !== 'object') {
|
|
226
231
|
experimentError.value = 'No design data found for this experiment'
|
|
@@ -232,9 +237,11 @@ async function fetchExperimentData() {
|
|
|
232
237
|
}
|
|
233
238
|
setQcRouting(qcRouting.value)
|
|
234
239
|
} catch (e) {
|
|
235
|
-
|
|
240
|
+
if (generation === fetchGeneration) {
|
|
241
|
+
experimentError.value = e instanceof Error ? e.message : 'Failed to fetch experiment data'
|
|
242
|
+
}
|
|
236
243
|
} finally {
|
|
237
|
-
experimentLoading.value = false
|
|
244
|
+
if (generation === fetchGeneration) experimentLoading.value = false
|
|
238
245
|
}
|
|
239
246
|
}
|
|
240
247
|
|
|
@@ -244,7 +251,11 @@ async function fetchExperimentData() {
|
|
|
244
251
|
watch(
|
|
245
252
|
() => props.open,
|
|
246
253
|
(open) => {
|
|
247
|
-
if (!open)
|
|
254
|
+
if (!open) {
|
|
255
|
+
fetchGeneration += 1
|
|
256
|
+
experimentLoading.value = false
|
|
257
|
+
return
|
|
258
|
+
}
|
|
248
259
|
activeWorkflow.value = props.initialMode
|
|
249
260
|
experimentError.value = null
|
|
250
261
|
qcAsOverlay.value = true
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
/** Internal: renders a Lucide icon by name; shows `fallback` until it loads or when the name is unknown. */
|
|
3
|
+
import { shallowRef, watchEffect, type Component } from 'vue'
|
|
4
|
+
import { loadLucideIcon } from '../../utils/lucideIcon'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<{
|
|
7
|
+
name: string
|
|
8
|
+
size?: number
|
|
9
|
+
}>()
|
|
10
|
+
|
|
11
|
+
const icon = shallowRef<Component>()
|
|
12
|
+
watchEffect(async (onCleanup) => {
|
|
13
|
+
let stale = false
|
|
14
|
+
onCleanup(() => { stale = true })
|
|
15
|
+
const loaded = await loadLucideIcon(props.name)
|
|
16
|
+
if (!stale) icon.value = loaded
|
|
17
|
+
})
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<component :is="icon" v-if="icon" :size="size ?? 14" aria-hidden="true" />
|
|
22
|
+
<slot v-else name="fallback" />
|
|
23
|
+
</template>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { ComputedRef, InjectionKey } from 'vue'
|
|
2
|
+
|
|
3
|
+
/** The responsive sidebar drawer of an AppLayout; its AppTopBar renders the drawer button. */
|
|
4
|
+
export interface AppLayoutSidebarDrawer {
|
|
5
|
+
open: ComputedRef<boolean>
|
|
6
|
+
toggle: () => void
|
|
7
|
+
openLabel: ComputedRef<string>
|
|
8
|
+
closeLabel: ComputedRef<string>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export const APP_LAYOUT_SIDEBAR_KEY: InjectionKey<AppLayoutSidebarDrawer> = Symbol('mint-app-layout-sidebar')
|
package/src/composables/index.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// Package-root composables: the L1 and L2 names of spec 3.3. Subpath composables are
|
|
2
|
-
// exported from `lab.ts`, `shell.ts`, `data.ts` and `runtime.ts
|
|
3
|
-
// keeps the other 1.3 root names until MINT 1.5.
|
|
2
|
+
// exported from `lab.ts`, `shell.ts`, `data.ts` and `runtime.ts`.
|
|
4
3
|
export { useTheme } from './useTheme'
|
|
5
4
|
export { useToast } from './useToast'
|
|
6
5
|
export { usePlatform } from './usePlatform'
|
|
@@ -30,6 +30,8 @@ export interface UseExperimentSelectorOptions {
|
|
|
30
30
|
immediate?: boolean
|
|
31
31
|
/** Keep `statusCounts` in step with the non-status filters (one stats request per change). */
|
|
32
32
|
withStatusCounts?: boolean
|
|
33
|
+
/** Filter values to start from, for example the ones a caller saved at the last visit. */
|
|
34
|
+
initialFilters?: Partial<ExperimentFilters>
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
export interface UseExperimentSelectorReturn {
|
|
@@ -89,6 +91,7 @@ export function useExperimentSelector(
|
|
|
89
91
|
allowedExperimentTypes: optionAllowedExperimentTypes,
|
|
90
92
|
apiBaseUrl,
|
|
91
93
|
withStatusCounts = false,
|
|
94
|
+
initialFilters,
|
|
92
95
|
} = options
|
|
93
96
|
const platformBase = apiBaseUrl ?? getPlatformApiUrl()
|
|
94
97
|
const api = useApi()
|
|
@@ -124,6 +127,7 @@ export function useExperimentSelector(
|
|
|
124
127
|
experimentType: undefined,
|
|
125
128
|
datePreset: undefined,
|
|
126
129
|
mine: undefined,
|
|
130
|
+
...initialFilters,
|
|
127
131
|
})
|
|
128
132
|
|
|
129
133
|
function normalizeExperimentTypes(values: string[] | null | undefined): string[] | null {
|