@morscherlab/mint-sdk 1.0.63 → 1.1.0-beta.2

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.
Files changed (165) hide show
  1. package/README.md +101 -2
  2. package/dist/EmptyState-D1c4RdC7.js +638 -0
  3. package/dist/EmptyState-D1c4RdC7.js.map +1 -0
  4. package/dist/{ExperimentPopover-BbPkIFsI.js → ExperimentPopover-BFw3QX8L.js} +10 -9
  5. package/dist/{ExperimentPopover-BbPkIFsI.js.map → ExperimentPopover-BFw3QX8L.js.map} +1 -1
  6. package/dist/{ExperimentSelectorModal-DZeSd-yr.js → ExperimentSelectorModal-B7w6k3Y8.js} +12 -216
  7. package/dist/ExperimentSelectorModal-B7w6k3Y8.js.map +1 -0
  8. package/dist/{SettingsModal-CJgLadsN.js → SettingsModal-DPDwCbXK.js} +12 -9
  9. package/dist/{SettingsModal-CJgLadsN.js.map → SettingsModal-DPDwCbXK.js.map} +1 -1
  10. package/dist/__tests__/components/GeneratedPlotlyResult.test.d.ts +1 -0
  11. package/dist/__tests__/components/GeneratedPluginView.test.d.ts +1 -0
  12. package/dist/__tests__/components/GeneratedResultRenderer.test.d.ts +1 -0
  13. package/dist/__tests__/components/InstrumentAlertLog.test.d.ts +1 -0
  14. package/dist/__tests__/composables/useGeneratedAnalysis.test.d.ts +1 -0
  15. package/dist/__tests__/generatedUi.test.d.ts +1 -0
  16. package/dist/{analysisArtifactTypes-Cu40dzSG.js → analysisArtifactTypes-ejqR8MX3.js} +1 -1
  17. package/dist/analysisArtifactTypes-ejqR8MX3.js.map +1 -0
  18. package/dist/{auth-DZAwEeis.js → auth-B87xM--s.js} +1 -1
  19. package/dist/{auth-DZAwEeis.js.map → auth-B87xM--s.js.map} +1 -1
  20. package/dist/chunk-BoAXSpZd.js +33 -0
  21. package/dist/components/AppSidebar.vue.d.ts +1 -1
  22. package/dist/components/AutoGroupModal.vue.d.ts +2 -2
  23. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  24. package/dist/components/CollapsibleCard.vue.d.ts +1 -1
  25. package/dist/components/ComponentBindingRenderer.vue.d.ts +1 -1
  26. package/dist/components/ConfirmDialog.vue.d.ts +1 -1
  27. package/dist/components/ExperimentDataViewer.vue.d.ts +1 -1
  28. package/dist/components/ExperimentTimeline.vue.d.ts +1 -1
  29. package/dist/components/FileUploader.vue.d.ts +4 -2
  30. package/dist/components/FitPanel.vue.d.ts +1 -1
  31. package/dist/components/FormActions.vue.d.ts +1 -1
  32. package/dist/components/FormBuilder.vue.d.ts +1 -1
  33. package/dist/components/GeneratedPathInput.vue.d.ts +12 -0
  34. package/dist/components/GeneratedPlotlyResult.vue.d.ts +11 -0
  35. package/dist/components/GeneratedPluginView.vue.d.ts +10 -0
  36. package/dist/components/GeneratedResultRenderer.vue.d.ts +6 -0
  37. package/dist/components/JobsStatusTray.vue.d.ts +5 -1
  38. package/dist/components/LcmsSequenceTable.vue.d.ts +1 -1
  39. package/dist/components/SampleLegend.vue.d.ts +1 -1
  40. package/dist/components/SampleSelector.vue.d.ts +2 -2
  41. package/dist/components/SettingsModal.vue.d.ts +1 -1
  42. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +2 -2
  43. package/dist/components/index.d.ts +4 -0
  44. package/dist/components/index.js +8 -9
  45. package/dist/components/internal/PlateMapEditorToolbarInternal.vue.d.ts +2 -2
  46. package/dist/{components-DdzHh3a_.js → components-UfkPN1bK.js} +2255 -2303
  47. package/dist/components-UfkPN1bK.js.map +1 -0
  48. package/dist/composables/index.d.ts +2 -3
  49. package/dist/composables/index.js +10 -11
  50. package/dist/composables/platformContextHelpers.d.ts +0 -2
  51. package/dist/composables/useAnalysisArtifacts.d.ts +1 -3
  52. package/dist/composables/useGeneratedAnalysis.d.ts +62 -0
  53. package/dist/composables/useJobsStatusTray.d.ts +48 -4
  54. package/dist/composables/usePlatformContext.d.ts +3 -0
  55. package/dist/composables/usePluginClient.d.ts +6 -3
  56. package/dist/{composables-BUUphBqg.js → composables-B512bWJP.js} +155 -74
  57. package/dist/composables-B512bWJP.js.map +1 -0
  58. package/dist/experiment-utils-CxkruZ3G.js +392 -0
  59. package/dist/experiment-utils-CxkruZ3G.js.map +1 -0
  60. package/dist/generated/schema.d.ts +7 -0
  61. package/dist/generated-ui/main.d.ts +0 -0
  62. package/dist/index.d.ts +1 -0
  63. package/dist/index.js +15 -18
  64. package/dist/index.js.map +1 -1
  65. package/dist/install.js +7 -8
  66. package/dist/install.js.map +1 -1
  67. package/dist/plotly.min-BR53hja4.js +180634 -0
  68. package/dist/plotly.min-BR53hja4.js.map +1 -0
  69. package/dist/stores/auth.d.ts +2 -2
  70. package/dist/stores/index.js +1 -1
  71. package/dist/styles.css +10543 -10404
  72. package/dist/templates/index.js +4 -3
  73. package/dist/templates/packs.d.ts +0 -1
  74. package/dist/{templates-CNbPQNID.js → templates-Cttbjbyc.js} +2 -4
  75. package/dist/templates-Cttbjbyc.js.map +1 -0
  76. package/dist/types/analysisArtifactTypes.d.ts +0 -8
  77. package/dist/types/form-builder.d.ts +1 -1
  78. package/dist/types/generated-ui.d.ts +170 -0
  79. package/dist/types/index.d.ts +2 -1
  80. package/dist/types/index.js +1 -1
  81. package/dist/types/instrument.d.ts +1 -0
  82. package/dist/types/jobs.d.ts +7 -1
  83. package/dist/types/platform.d.ts +2 -0
  84. package/dist/{useControlSchema-BZNdalmL.js → useControlSchema-Dallso-L.js} +1852 -171
  85. package/dist/useControlSchema-Dallso-L.js.map +1 -0
  86. package/dist/{useDropdownState-Bb-c_PeE.js → useDropdownState-gVaMXtwW.js} +2 -2
  87. package/dist/{useDropdownState-Bb-c_PeE.js.map → useDropdownState-gVaMXtwW.js.map} +1 -1
  88. package/dist/{useExperimentSelector-DRbj6vse.js → useExperimentSelector-BMjzNcf2.js} +4 -255
  89. package/dist/useExperimentSelector-BMjzNcf2.js.map +1 -0
  90. package/dist/{useFormBuilder-DKekvXRs.js → useFormBuilder-BXaaDI41.js} +2 -2
  91. package/dist/{useFormBuilder-DKekvXRs.js.map → useFormBuilder-BXaaDI41.js.map} +1 -1
  92. package/dist/{useAnalysisArtifacts-C3l0a0vu.js → useProtocolTemplates-BP7_4RGQ.js} +307 -475
  93. package/dist/useProtocolTemplates-BP7_4RGQ.js.map +1 -0
  94. package/package.json +7 -3
  95. package/src/__tests__/components/GeneratedPathInput.test.ts +132 -0
  96. package/src/__tests__/components/GeneratedPlotlyResult.test.ts +117 -0
  97. package/src/__tests__/components/GeneratedPluginView.test.ts +230 -0
  98. package/src/__tests__/components/GeneratedResultRenderer.test.ts +93 -0
  99. package/src/__tests__/components/InstrumentAlertLog.test.ts +59 -0
  100. package/src/__tests__/composables/formBuilderRegistry.test.ts +5 -1
  101. package/src/__tests__/composables/useAnalysisArtifacts.test.ts +1 -74
  102. package/src/__tests__/composables/useApi.test.ts +8 -0
  103. package/src/__tests__/composables/useGeneratedAnalysis.test.ts +1740 -0
  104. package/src/__tests__/composables/useJobsStatusTray.test.ts +179 -1
  105. package/src/__tests__/composables/usePlatformContext.test.ts +28 -0
  106. package/src/__tests__/composables/usePluginClient.test.ts +366 -20
  107. package/src/__tests__/composables/usePluginConfig.test.ts +323 -7
  108. package/src/__tests__/docs/extractDocsTemplates.test.ts +0 -1
  109. package/src/__tests__/generatedUi.test.ts +119 -0
  110. package/src/__tests__/templates/templates.test.ts +1 -1
  111. package/src/components/FileUploader.vue +49 -11
  112. package/src/components/GeneratedPathInput.vue +218 -0
  113. package/src/components/GeneratedPlotlyResult.vue +87 -0
  114. package/src/components/GeneratedPluginView.vue +279 -0
  115. package/src/components/GeneratedResultRenderer.vue +137 -0
  116. package/src/components/InstrumentAlertLog.vue +2 -2
  117. package/src/components/JobsStatusTray.vue +14 -8
  118. package/src/components/index.ts +4 -0
  119. package/src/composables/formBuilderRegistry.ts +2 -0
  120. package/src/composables/index.ts +18 -5
  121. package/src/composables/platformContextHelpers.ts +3 -10
  122. package/src/composables/useAnalysisArtifacts.ts +0 -48
  123. package/src/composables/useApi.ts +1 -0
  124. package/src/composables/useGeneratedAnalysis.ts +1252 -0
  125. package/src/composables/useJobsStatusTray.ts +234 -45
  126. package/src/composables/usePluginClient.ts +152 -25
  127. package/src/composables/usePluginConfig.ts +156 -20
  128. package/src/generated/schema.ts +130 -0
  129. package/src/generated-ui/main.ts +21 -0
  130. package/src/index.ts +3 -0
  131. package/src/jobs.ts +5 -0
  132. package/src/plotly-dist.d.ts +3 -0
  133. package/src/templates/packs.ts +0 -3
  134. package/src/types/analysisArtifactTypes.ts +0 -9
  135. package/src/types/form-builder.ts +1 -0
  136. package/src/types/generated-ui.ts +176 -0
  137. package/src/types/index.ts +2 -1
  138. package/src/types/instrument.ts +1 -0
  139. package/src/types/jobs.ts +10 -1
  140. package/src/types/platform.ts +2 -0
  141. package/dist/BaseButton-Dgqrze41.js +0 -74
  142. package/dist/BaseButton-Dgqrze41.js.map +0 -1
  143. package/dist/BaseModal-B9UA8Y_I.js +0 -165
  144. package/dist/BaseModal-B9UA8Y_I.js.map +0 -1
  145. package/dist/BaseSelect-ekgr9fDo.js +0 -179
  146. package/dist/BaseSelect-ekgr9fDo.js.map +0 -1
  147. package/dist/ExperimentPopover-Ryusjrhv.js +0 -4
  148. package/dist/ExperimentSelectorModal-Cg4-LXBD.js +0 -5
  149. package/dist/ExperimentSelectorModal-DZeSd-yr.js.map +0 -1
  150. package/dist/SettingsModal-Bl_9w2Y3.js +0 -5
  151. package/dist/analysisArtifactTypes-Cu40dzSG.js.map +0 -1
  152. package/dist/components-DdzHh3a_.js.map +0 -1
  153. package/dist/composables/analysisArtifactTarget.d.ts +0 -5
  154. package/dist/composables-BUUphBqg.js.map +0 -1
  155. package/dist/experiment-utils-Bfa7CwPU.js +0 -108
  156. package/dist/experiment-utils-Bfa7CwPU.js.map +0 -1
  157. package/dist/templates-CNbPQNID.js.map +0 -1
  158. package/dist/useAnalysisArtifacts-C3l0a0vu.js.map +0 -1
  159. package/dist/useControlSchema-BZNdalmL.js.map +0 -1
  160. package/dist/useEventListener-CfVkP9Xz.js +0 -57
  161. package/dist/useEventListener-CfVkP9Xz.js.map +0 -1
  162. package/dist/useExperimentSelector-DRbj6vse.js.map +0 -1
  163. package/src/__tests__/composables/analysisArtifactTarget.test.ts +0 -77
  164. package/src/composables/analysisArtifactTarget.ts +0 -53
  165. /package/dist/__tests__/{composables/analysisArtifactTarget.test.d.ts → components/GeneratedPathInput.test.d.ts} +0 -0
@@ -0,0 +1,137 @@
1
+ <script setup lang="ts">
2
+ import { computed } from 'vue'
3
+
4
+ import type { DataFrameColumn } from '../types'
5
+ import type { GeneratedAnalysisResult } from '../types/generated-ui'
6
+ import ChartContainer from './ChartContainer.vue'
7
+ import DataFrame from './DataFrame.vue'
8
+ import GeneratedPlotlyResult from './GeneratedPlotlyResult.vue'
9
+
10
+ const props = defineProps<{
11
+ result: GeneratedAnalysisResult
12
+ }>()
13
+
14
+ const tableColumns = computed<DataFrameColumn[]>(() => {
15
+ if (props.result.kind !== 'table') return []
16
+ return props.result.columns.map(key => ({
17
+ key,
18
+ label: humanize(key),
19
+ sortable: true,
20
+ }))
21
+ })
22
+
23
+ const formattedJson = computed(() => (
24
+ props.result.kind === 'json'
25
+ ? JSON.stringify(props.result.value, null, 2)
26
+ : ''
27
+ ))
28
+
29
+ const artifactHref = computed(() => {
30
+ if (props.result.kind !== 'artifact') return ''
31
+ if (props.result.download_url) return props.result.download_url
32
+ return props.result.data
33
+ ? `data:${props.result.media_type};base64,${props.result.data}`
34
+ : ''
35
+ })
36
+
37
+ function humanize(value: string): string {
38
+ return value.replace(/[_-]+/g, ' ').replace(/^\w/, character => character.toUpperCase())
39
+ }
40
+ </script>
41
+
42
+ <template>
43
+ <article class="mint-generated-result" aria-live="polite">
44
+ <p v-if="result.kind === 'text'" class="mint-generated-result__text">
45
+ {{ result.text }}
46
+ </p>
47
+
48
+ <pre v-else-if="result.kind === 'json'" class="mint-generated-result__json">{{ formattedJson }}</pre>
49
+
50
+ <DataFrame
51
+ v-else-if="result.kind === 'table'"
52
+ :data="result.rows"
53
+ :columns="tableColumns"
54
+ sortable
55
+ searchable
56
+ sticky-header
57
+ max-height="32rem"
58
+ />
59
+
60
+ <ChartContainer v-else-if="result.kind === 'image'" title="Analysis chart">
61
+ <img
62
+ class="mint-generated-result__image"
63
+ :src="`data:${result.media_type};base64,${result.data}`"
64
+ :alt="result.alt"
65
+ >
66
+ </ChartContainer>
67
+
68
+ <GeneratedPlotlyResult
69
+ v-else-if="result.kind === 'plotly'"
70
+ :spec="result.spec"
71
+ :fallback="result.fallback"
72
+ />
73
+
74
+ <a
75
+ v-else
76
+ class="mint-generated-result__artifact"
77
+ :href="artifactHref"
78
+ :download="result.name"
79
+ >
80
+ <span>{{ result.name }}</span>
81
+ <small>{{ result.media_type }}</small>
82
+ </a>
83
+ </article>
84
+ </template>
85
+
86
+ <style scoped>
87
+ .mint-generated-result {
88
+ width: 100%;
89
+ }
90
+
91
+ .mint-generated-result__text,
92
+ .mint-generated-result__json {
93
+ margin: 0;
94
+ color: var(--color-text-primary);
95
+ }
96
+
97
+ .mint-generated-result__text {
98
+ max-width: 72ch;
99
+ white-space: pre-wrap;
100
+ line-height: 1.65;
101
+ }
102
+
103
+ .mint-generated-result__json {
104
+ overflow: auto;
105
+ padding: 1rem;
106
+ border: 1px solid var(--color-border);
107
+ border-radius: 0.75rem;
108
+ background: var(--color-bg-secondary);
109
+ font-size: 0.8125rem;
110
+ line-height: 1.55;
111
+ white-space: pre-wrap;
112
+ }
113
+
114
+ .mint-generated-result__image {
115
+ display: block;
116
+ max-width: 100%;
117
+ height: auto;
118
+ margin: 0 auto;
119
+ }
120
+
121
+ .mint-generated-result__plotly {
122
+ width: 100%;
123
+ min-height: 24rem;
124
+ }
125
+
126
+ .mint-generated-result__artifact {
127
+ display: flex;
128
+ align-items: center;
129
+ justify-content: space-between;
130
+ gap: 1rem;
131
+ padding: 1rem;
132
+ border: 1px solid var(--color-border);
133
+ border-radius: 0.75rem;
134
+ color: var(--color-primary);
135
+ text-decoration: none;
136
+ }
137
+ </style>
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- /** Filterable instrument alert/event list with optional acknowledge actions. */
2
+ /** Filterable instrument alert/event list keyed by each alert's required stable event_key. */
3
3
  import { computed, ref } from 'vue'
4
4
  import type { InstrumentAlert, InstrumentAlertLevel } from '../types'
5
5
 
@@ -146,7 +146,7 @@ function alertDetail(alert: InstrumentAlert): string {
146
146
  <TransitionGroup name="mint-instrument-alert" tag="div" class="mint-instrument-alert-log__list">
147
147
  <div
148
148
  v-for="alert in filteredAlerts"
149
- :key="alert.id ?? `${alert.instrument_id}-${alert.rule ?? alert.message}-${alert.timestamp ?? ''}`"
149
+ :key="alert.event_key"
150
150
  class="mint-instrument-alert"
151
151
  :class="[
152
152
  levelConfig[alert.level]?.cssClass,
@@ -1,5 +1,5 @@
1
1
  <script setup lang="ts">
2
- /** Floating, adapter-driven job status tray for plugin and platform workflows. */
2
+ /** Floating, source-driven job status tray for plugin and platform workflows. */
3
3
  import { computed, nextTick, ref, toRef, useId } from 'vue'
4
4
 
5
5
  import {
@@ -7,8 +7,9 @@ import {
7
7
  normalizeJobPercent,
8
8
  } from '../jobs'
9
9
  import {
10
- useJobsStatusTray,
10
+ usePluginJobCenter,
11
11
  type JobsStatusTrayAdapter,
12
+ type PluginJobCenterSource,
12
13
  } from '../composables/useJobsStatusTray'
13
14
  import type { UsePluginEventStreamReturn } from '../composables/usePluginClient'
14
15
  import type {
@@ -18,8 +19,12 @@ import type {
18
19
  } from '../types/jobs'
19
20
 
20
21
  interface Props {
22
+ source?: PluginJobCenterSource
23
+ /** @deprecated Pass a source instead. */
21
24
  jobs?: readonly JobStateInput[]
25
+ /** @deprecated Pass source actions instead. */
22
26
  adapter?: JobsStatusTrayAdapter
27
+ /** @deprecated Event streams belong to the source runtime. */
23
28
  eventStream?: UsePluginEventStreamReturn<JobStreamData>
24
29
  loadOnMount?: boolean
25
30
  title?: string
@@ -42,7 +47,8 @@ const titleId = `${panelId}-title`
42
47
  const triggerRef = ref<HTMLButtonElement | null>(null)
43
48
  const panelRef = ref<HTMLElement | null>(null)
44
49
  const teleportTarget = computed(() => props.teleportTo || 'body')
45
- const tray = useJobsStatusTray({
50
+ const tray = usePluginJobCenter({
51
+ source: toRef(props, 'source'),
46
52
  jobs: toRef(props, 'jobs'),
47
53
  adapter: toRef(props, 'adapter'),
48
54
  eventStream: toRef(props, 'eventStream'),
@@ -50,7 +56,7 @@ const tray = useJobsStatusTray({
50
56
  })
51
57
  const canClear = computed(() => (
52
58
  tray.deletableJobs.value.length > 0
53
- && Boolean(props.adapter?.clearFinishedJobs || props.adapter?.deleteJob)
59
+ && tray.canClearFinished.value
54
60
  ))
55
61
 
56
62
  async function openTray(): Promise<void> {
@@ -201,7 +207,7 @@ async function clearFinished(): Promise<void> {
201
207
  </div>
202
208
  <div class="mint-jobs-tray__header-actions">
203
209
  <button
204
- v-if="adapter?.listJobs"
210
+ v-if="tray.canRefresh.value"
205
211
  type="button"
206
212
  class="mint-jobs-tray__icon-button"
207
213
  aria-label="Refresh jobs"
@@ -297,7 +303,7 @@ async function clearFinished(): Promise<void> {
297
303
  <span>{{ progressText(job) }}</span>
298
304
  <div class="mint-jobs-tray__job-actions">
299
305
  <button
300
- v-if="job.can_cancel && adapter?.cancelJob"
306
+ v-if="job.can_cancel && tray.canCancel.value"
301
307
  type="button"
302
308
  class="mint-jobs-tray__action mint-jobs-tray__action--danger"
303
309
  aria-label="Cancel job"
@@ -307,7 +313,7 @@ async function clearFinished(): Promise<void> {
307
313
  Cancel
308
314
  </button>
309
315
  <button
310
- v-if="job.can_delete && adapter?.deleteJob"
316
+ v-if="job.can_delete && tray.canDelete.value"
311
317
  type="button"
312
318
  class="mint-jobs-tray__icon-button mint-jobs-tray__icon-button--danger"
313
319
  aria-label="Delete job"
@@ -359,7 +365,7 @@ async function clearFinished(): Promise<void> {
359
365
  <div class="mint-jobs-tray__job-footer">
360
366
  <span>{{ formatTimestamp(job.completed_at || job.created_at) }}</span>
361
367
  <button
362
- v-if="job.can_delete && adapter?.deleteJob"
368
+ v-if="job.can_delete && tray.canDelete.value"
363
369
  type="button"
364
370
  class="mint-jobs-tray__icon-button mint-jobs-tray__icon-button--danger"
365
371
  aria-label="Delete job"
@@ -42,6 +42,9 @@ export { default as AppSidebar } from './AppSidebar.vue'
42
42
  export { default as AppLayout } from './AppLayout.vue'
43
43
  export { default as MobileSupportGate } from './MobileSupportGate.vue'
44
44
  export { default as PluginWorkspaceView } from './PluginWorkspaceView.vue'
45
+ export { default as GeneratedPluginView } from './GeneratedPluginView.vue'
46
+ export { default as GeneratedResultRenderer } from './GeneratedResultRenderer.vue'
47
+ export { default as GeneratedPlotlyResult } from './GeneratedPlotlyResult.vue'
45
48
  export { default as ComponentBindingRenderer } from './ComponentBindingRenderer.vue'
46
49
  export { default as ControlWorkspaceView } from './ControlWorkspaceView.vue'
47
50
  export { default as DoseDesignWorkspaceView } from './DoseDesignWorkspaceView.vue'
@@ -127,6 +130,7 @@ export { default as ResourceCard } from './ResourceCard.vue'
127
130
  // Experiment / analysis components
128
131
  export { default as ExperimentSelectorModal } from './ExperimentSelectorModal.vue'
129
132
  export { default as ArtifactSelectorModal } from './ArtifactSelectorModal.vue'
133
+ export { default as GeneratedPathInput } from './GeneratedPathInput.vue'
130
134
  export { default as ArtifactSaveDialog } from './ArtifactSaveDialog.vue'
131
135
  export { default as ExperimentPopover } from './ExperimentPopover.vue'
132
136
  export { default as FitPanel } from './FitPanel.vue'
@@ -15,6 +15,7 @@ import DatePicker from '../components/DatePicker.vue'
15
15
  import TimePicker from '../components/TimePicker.vue'
16
16
  import DateTimePicker from '../components/DateTimePicker.vue'
17
17
  import FileUploader from '../components/FileUploader.vue'
18
+ import GeneratedPathInput from '../components/GeneratedPathInput.vue'
18
19
  import FormulaInput from '../components/FormulaInput.vue'
19
20
  import SequenceInput from '../components/SequenceInput.vue'
20
21
  import MoleculeInput from '../components/MoleculeInput.vue'
@@ -49,6 +50,7 @@ const registry: Record<FormFieldType, RegistryEntry> = {
49
50
  time: { component: TimePicker, defaults: {}, vModel: true },
50
51
  datetime: { component: DateTimePicker, defaults: {}, vModel: true },
51
52
  file: { component: FileUploader, defaults: {}, vModel: false },
53
+ path: { component: GeneratedPathInput, defaults: {}, vModel: true },
52
54
  formula: { component: FormulaInput, defaults: {}, vModel: true },
53
55
  sequence: { component: SequenceInput, defaults: {}, vModel: true },
54
56
  molecule: { component: MoleculeInput, defaults: {}, vModel: true },
@@ -125,6 +125,18 @@ export {
125
125
  type UseDebouncedWatchReturn,
126
126
  } from './useDebouncedWatch'
127
127
  export { useFormBuilder, evaluateCondition } from './useFormBuilder'
128
+ export {
129
+ createGeneratedAnalysisTransport,
130
+ useGeneratedAnalysis,
131
+ usePluginJobs,
132
+ type GeneratedAnalysisTransport,
133
+ type GeneratedAnalysisOptions,
134
+ type PluginJobRequestOptions,
135
+ type PluginJobWaitOptions,
136
+ type UsePluginJobsOptions,
137
+ type UsePluginJobsReturn,
138
+ type UseGeneratedAnalysisReturn,
139
+ } from './useGeneratedAnalysis'
128
140
  export { useAutoGroup, DEFAULT_COLORS, extractSamplesFromDesignData } from './useAutoGroup'
129
141
  export {
130
142
  useReagentSeries,
@@ -147,11 +159,6 @@ export {
147
159
  type UseAnalysisArtifactsOptions,
148
160
  type UseAnalysisArtifactsReturn,
149
161
  } from './useAnalysisArtifacts'
150
- export {
151
- buildAnalysisArtifactTargetQuery,
152
- parseAnalysisArtifactTarget,
153
- } from './analysisArtifactTarget'
154
- export { resolveCurrentPluginId } from './platformContextHelpers'
155
162
  export {
156
163
  formatExperimentDate,
157
164
  formatExperimentStatus,
@@ -487,10 +494,16 @@ export {
487
494
  type UsePluginSettingsReturn,
488
495
  } from './usePluginClient'
489
496
  export {
497
+ combinePluginJobSources,
498
+ usePluginJobCenter,
490
499
  useJobsStatusTray,
500
+ type CombinedPluginJobCenterSource,
501
+ type PluginJobCenterSource,
491
502
  type JobsStatusTrayAdapter,
492
503
  type JobsStatusTrayTab,
493
504
  type JobStreamMessage,
505
+ type UsePluginJobCenterOptions,
506
+ type UsePluginJobCenterReturn,
494
507
  type UseJobsStatusTrayOptions,
495
508
  type UseJobsStatusTrayReturn,
496
509
  } from './useJobsStatusTray'
@@ -12,12 +12,6 @@ export function getInjectedPlatformContext(): PlatformContext | undefined {
12
12
  return (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__
13
13
  }
14
14
 
15
- /** Return the platform's canonical plugin identity for the mounted frontend. */
16
- export function resolveCurrentPluginId(): string | undefined {
17
- const pluginId = getInjectedPlatformContext()?.plugin?.id
18
- return typeof pluginId === 'string' && pluginId ? pluginId : undefined
19
- }
20
-
21
15
  export function getInjectedExperimentContext(): ExperimentAwarePlatformContext | undefined {
22
16
  return getInjectedPlatformContext() as ExperimentAwarePlatformContext | undefined
23
17
  }
@@ -44,11 +38,10 @@ export function currentExperimentIdFromContext(
44
38
 
45
39
  export function currentExperimentIdFromUrl(): number | undefined {
46
40
  if (typeof window === 'undefined') return undefined
47
- const location = window.location
48
- const params = new URLSearchParams(location?.search ?? '')
41
+ const params = new URLSearchParams(window.location.search)
49
42
  return parseExperimentId(params.get('experimentId') ?? params.get('experiment_id'))
50
- ?? experimentIdFromPath(location?.pathname ?? '')
51
- ?? experimentIdFromPath((location?.hash ?? '').replace(/^#\/?/, '/'))
43
+ ?? experimentIdFromPath(window.location.pathname)
44
+ ?? experimentIdFromPath(window.location.hash.replace(/^#\/?/, '/'))
52
45
  }
53
46
 
54
47
  export function resolveCurrentExperimentId(
@@ -19,7 +19,6 @@ import type {
19
19
  AnalysisArtifactMetadataUpdate,
20
20
  AnalysisArtifactStatusFilter,
21
21
  AnalysisArtifactSummary,
22
- AnalysisArtifactTarget,
23
22
  } from '../types/analysisArtifactTypes'
24
23
 
25
24
  export { ANALYSIS_FILE_ARTIFACT_SCHEMA } from '../types/analysisArtifactTypes'
@@ -68,8 +67,6 @@ export interface UseAnalysisArtifactsReturn {
68
67
  refresh: () => Promise<AnalysisArtifactSummary[]>
69
68
  /** Fetch one artifact with its result payload; null when it fails or is superseded. */
70
69
  getDetail: (artifactId: number) => Promise<AnalysisArtifactDetail | null>
71
- /** Resolve and fetch the exact stable artifact identity. */
72
- resolveTarget: (target: AnalysisArtifactTarget) => Promise<AnalysisArtifactDetail | null>
73
70
  /** Update display_name and/or note; resolves to the updated summary or null. */
74
71
  updateMetadata: (
75
72
  artifactId: number,
@@ -209,50 +206,6 @@ export function useAnalysisArtifacts(
209
206
  }
210
207
  }
211
208
 
212
- async function resolveTarget(
213
- target: AnalysisArtifactTarget,
214
- ): Promise<AnalysisArtifactDetail | null> {
215
- const experimentId = currentExperimentId.value
216
- if (experimentId !== target.experimentId) {
217
- request.setError(
218
- `Analysis artifact target belongs to experiment ${target.experimentId}, not `
219
- + `${experimentId ?? 'the current selection'}.`,
220
- )
221
- return null
222
- }
223
-
224
- const available = await list()
225
- const summary = available.find((artifact) => (
226
- artifact.plugin_id === target.artifactPluginId
227
- && artifact.artifact_key === target.artifactKey
228
- && artifact.status === 'active'
229
- ))
230
- if (!summary) {
231
- request.setError(
232
- `Analysis artifact ${target.artifactPluginId}/${target.artifactKey} is not available.`,
233
- )
234
- return null
235
- }
236
-
237
- const detail = await getDetail(summary.id)
238
- if (
239
- detail
240
- && (
241
- detail.experiment_id !== target.experimentId
242
- || detail.plugin_id !== target.artifactPluginId
243
- || detail.artifact_key !== target.artifactKey
244
- )
245
- ) {
246
- selectedDetail.value = null
247
- request.setError(
248
- `Analysis artifact ${target.artifactPluginId}/${target.artifactKey} did not `
249
- + 'match the requested identity.',
250
- )
251
- return null
252
- }
253
- return detail
254
- }
255
-
256
209
  async function mutate(
257
210
  action: string,
258
211
  operation: (experimentId: number) => Promise<AnalysisArtifactSummary>,
@@ -343,7 +296,6 @@ export function useAnalysisArtifacts(
343
296
  list,
344
297
  refresh: list,
345
298
  getDetail,
346
- resolveTarget,
347
299
  updateMetadata,
348
300
  archive,
349
301
  restore,
@@ -22,6 +22,7 @@ type MutableHeaders = Record<string, unknown> & {
22
22
  }
23
23
 
24
24
  function joinUrlPath(baseUrl: string, path: string): string {
25
+ if (/^https?:\/\//i.test(path)) return path
25
26
  if (!path) return baseUrl
26
27
  if (path.startsWith('?') || path.startsWith('#')) return `${baseUrl.replace(/\/+$/, '')}${path}`
27
28
  const normalizedBase = baseUrl.replace(/\/+$/, '')