@morscherlab/mint-sdk 1.4.0-beta.9 → 1.4.0

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 (198) hide show
  1. package/README.md +14 -3
  2. package/dist/{AlertBox-B2Bgr3ei.js → AlertBox-DwgNTEqf.js} +3 -3
  3. package/dist/{AlertBox-B2Bgr3ei.js.map → AlertBox-DwgNTEqf.js.map} +1 -1
  4. package/dist/{AppSidebar-Dq9W1jE2.js → AppSidebar-CZZaxni0.js} +1103 -144
  5. package/dist/AppSidebar-CZZaxni0.js.map +1 -0
  6. package/dist/{ConfirmDialog-nbJj51is.js → ConfirmDialog-CjWoxAD1.js} +2 -2
  7. package/dist/{ConfirmDialog-nbJj51is.js.map → ConfirmDialog-CjWoxAD1.js.map} +1 -1
  8. package/dist/{ExperimentPopover-5T1fAq2L.js → ExperimentPopover-DujiuQIO.js} +5 -5
  9. package/dist/{ExperimentPopover-5T1fAq2L.js.map → ExperimentPopover-DujiuQIO.js.map} +1 -1
  10. package/dist/{ExperimentSelectorModal-65peG4Up.js → ExperimentSelectorModal-B4j4eUOJ.js} +114 -98
  11. package/dist/ExperimentSelectorModal-B4j4eUOJ.js.map +1 -0
  12. package/dist/{SegmentedControl-BtnnjWzs.js → SegmentedControl-DyUPH3I5.js} +2 -2
  13. package/dist/{SegmentedControl-BtnnjWzs.js.map → SegmentedControl-DyUPH3I5.js.map} +1 -1
  14. package/dist/{SettingsModal-483nyI6b.js → SettingsModal-D2MOOtuO.js} +26 -25
  15. package/dist/SettingsModal-D2MOOtuO.js.map +1 -0
  16. package/dist/__stories__/experiment-helpers.d.ts +10 -0
  17. package/dist/__tests__/components/AppTopBarOnboarding.test.d.ts +1 -0
  18. package/dist/__tests__/components/FloatingPanelsInModal.test.d.ts +1 -0
  19. package/dist/__tests__/composables/useFloatingPanel.test.d.ts +1 -0
  20. package/dist/__tests__/composables/useOnboarding.test.d.ts +1 -0
  21. package/dist/__tests__/styles/paletteTokens.test.d.ts +1 -0
  22. package/dist/__tests__/styles/v2AuditRules.test.d.ts +1 -0
  23. package/dist/components/AppTopBar.vue.d.ts +20 -5
  24. package/dist/components/BaseButton.vue.d.ts +4 -2
  25. package/dist/components/ExperimentSelectorModal.vue.d.ts +15 -1
  26. package/dist/components/JobsStatusTray.vue.d.ts +15 -4
  27. package/dist/components/PluginWorkspaceView.props.d.ts +3 -0
  28. package/dist/components/PluginWorkspaceView.vue.d.ts +3 -0
  29. package/dist/components/SmartGroupFieldRecipe.vue.d.ts +3 -3
  30. package/dist/components/internal/AppTopBarOnboardingInternal.vue.d.ts +7 -0
  31. package/dist/components/internal/AppTopBarPageSelectorInternal.vue.d.ts +2 -1
  32. package/dist/components/internal/AutoGroupModalInternal.vue.d.ts +2 -2
  33. package/dist/components/internal/OnboardingLayerInternal.vue.d.ts +7 -0
  34. package/dist/components/internal/WorkspaceShellInternal.vue.d.ts +8 -0
  35. package/dist/composables/pluginWorkspaceModel.d.ts +2 -2
  36. package/dist/composables/useFileImport.d.ts +7 -0
  37. package/dist/composables/useFloatingPanel.d.ts +29 -0
  38. package/dist/composables/useJobCenter.d.ts +41 -3
  39. package/dist/composables/useOnboarding.d.ts +119 -0
  40. package/dist/{controlSchemaModel-B8CTXagP.js → controlSchemaModel-Bsg0t5Ab.js} +2 -2
  41. package/dist/{controlSchemaModel-B8CTXagP.js.map → controlSchemaModel-Bsg0t5Ab.js.map} +1 -1
  42. package/dist/{data-CgILxDLW.js → data-Boeh4uPI.js} +13 -12
  43. package/dist/{data-CgILxDLW.js.map → data-Boeh4uPI.js.map} +1 -1
  44. package/dist/data.d.ts +1 -1
  45. package/dist/data.js +9 -9
  46. package/dist/{experiment-43OJtH7R.js → experiment-DyO54FQB.js} +25 -61
  47. package/dist/experiment-DyO54FQB.js.map +1 -0
  48. package/dist/{experimentStatus-Cqp6qNrR.js → experimentStatus-DCn2QKG7.js} +2 -2
  49. package/dist/{experimentStatus-Cqp6qNrR.js.map → experimentStatus-DCn2QKG7.js.map} +1 -1
  50. package/dist/index.js +20 -20
  51. package/dist/{install-BtLWTk6H.js → install-BEHp7Mo-.js} +15 -15
  52. package/dist/{install-BtLWTk6H.js.map → install-BEHp7Mo-.js.map} +1 -1
  53. package/dist/install.js +1 -1
  54. package/dist/{lab-MHzp-_J8.js → lab-D61eaX6f.js} +68 -61
  55. package/dist/{lab-MHzp-_J8.js.map → lab-D61eaX6f.js.map} +1 -1
  56. package/dist/lab.js +4 -4
  57. package/dist/{records-B6gpM_3e.js → records-D4aQXyZu.js} +193 -133
  58. package/dist/records-D4aQXyZu.js.map +1 -0
  59. package/dist/{runtime-7vfl_bI3.js → runtime-q-R0CNLh.js} +400 -33
  60. package/dist/runtime-q-R0CNLh.js.map +1 -0
  61. package/dist/runtime.d.ts +1 -1
  62. package/dist/runtime.js +7 -7
  63. package/dist/{shell-Cs9OJMnm.js → shell-6CGFvUUw.js} +10 -5
  64. package/dist/{shell-Cs9OJMnm.js.map → shell-6CGFvUUw.js.map} +1 -1
  65. package/dist/shell.d.ts +1 -0
  66. package/dist/shell.js +6 -6
  67. package/dist/stores/index.d.ts +1 -1
  68. package/dist/stores/index.js +2 -2
  69. package/dist/stores/settings.d.ts +4 -12
  70. package/dist/styles.css +1191 -479
  71. package/dist/types/components.d.ts +2 -0
  72. package/dist/types/index.d.ts +1 -1
  73. package/dist/types/jobs.d.ts +9 -0
  74. package/dist/types/platform.d.ts +1 -1
  75. package/dist/{useDropdownState-8yWMu-7_.js → useDropdownState-uFIz6Yv8.js} +16 -4
  76. package/dist/useDropdownState-uFIz6Yv8.js.map +1 -0
  77. package/dist/{useExperimentSamples-DHnxKFAF.js → useExperimentSamples-QEFoq4tf.js} +48 -6
  78. package/dist/useExperimentSamples-QEFoq4tf.js.map +1 -0
  79. package/dist/{useListReorder-BitdUhxn.js → useListReorder-DsuzwWGS.js} +122 -172
  80. package/dist/useListReorder-DsuzwWGS.js.map +1 -0
  81. package/dist/{useRackEditor-DiwCt77M.js → useRackEditor-KpZ4iJ6o.js} +22 -32
  82. package/dist/useRackEditor-KpZ4iJ6o.js.map +1 -0
  83. package/dist/useRealtime-B58Lo-Tm.js +508 -0
  84. package/dist/useRealtime-B58Lo-Tm.js.map +1 -0
  85. package/dist/{useRequest-D506eHi8.js → useRequest-BuDmW8Jc.js} +8 -37
  86. package/dist/useRequest-BuDmW8Jc.js.map +1 -0
  87. package/package.json +3 -2
  88. package/src/__stories__/experiment-helpers.ts +3 -3
  89. package/src/__tests__/components/ActionMenu.test.ts +2 -2
  90. package/src/__tests__/components/AppTopBar.test.ts +206 -1
  91. package/src/__tests__/components/AppTopBarOnboarding.test.ts +160 -0
  92. package/src/__tests__/components/AppTopBarPageSelector.test.ts +125 -9
  93. package/src/__tests__/components/BaseButton.test.ts +19 -0
  94. package/src/__tests__/components/BaseModal.test.ts +13 -0
  95. package/src/__tests__/components/ExperimentSelectorModal.test.ts +34 -1
  96. package/src/__tests__/components/FloatingPanelsInModal.test.ts +94 -0
  97. package/src/__tests__/components/GeneratedPluginView.test.ts +1 -1
  98. package/src/__tests__/components/JobsStatusTray.test.ts +373 -71
  99. package/src/__tests__/components/PluginWorkspaceView.test.ts +63 -1
  100. package/src/__tests__/components/SampleSelector.test.ts +20 -0
  101. package/src/__tests__/components/SettingsModal.test.ts +9 -2
  102. package/src/__tests__/composables/useFileImport.test.ts +36 -0
  103. package/src/__tests__/composables/useFloatingPanel.test.ts +68 -0
  104. package/src/__tests__/composables/useJobCenter.test.ts +262 -3
  105. package/src/__tests__/composables/useOnboarding.test.ts +317 -0
  106. package/src/__tests__/docs/frontendDocsCatalog.test.ts +4 -3
  107. package/src/__tests__/fixtures/table-import/cells.xlsx +0 -0
  108. package/src/__tests__/fixtures/table-import/samples.xlsx +0 -0
  109. package/src/__tests__/stores/settings.test.ts +21 -21
  110. package/src/__tests__/styles/cssTokens.test.ts +4 -1
  111. package/src/__tests__/styles/menusShellRefresh.test.ts +8 -2
  112. package/src/__tests__/styles/paletteTokens.test.ts +44 -0
  113. package/src/__tests__/styles/v2AuditRules.test.ts +104 -0
  114. package/src/components/ActionMenu.vue +6 -37
  115. package/src/components/AppTopBar.onboarding.story.vue +69 -0
  116. package/src/components/AppTopBar.story.vue +59 -4
  117. package/src/components/AppTopBar.vue +132 -10
  118. package/src/components/BaseButton.vue +16 -2
  119. package/src/components/BaseModal.vue +2 -1
  120. package/src/components/ExperimentSelectorModal.story.vue +38 -0
  121. package/src/components/ExperimentSelectorModal.vue +20 -1
  122. package/src/components/GeneratedPluginView.vue +4 -9
  123. package/src/components/GeneratedResultRenderer.vue +3 -4
  124. package/src/components/JobsStatusTray.story.vue +97 -43
  125. package/src/components/JobsStatusTray.vue +287 -290
  126. package/src/components/LayoutResizeHandle.story.vue +65 -4
  127. package/src/components/PluginWorkspaceView.props.ts +3 -0
  128. package/src/components/PluginWorkspaceView.vue +17 -0
  129. package/src/components/SampleSelector.story.vue +21 -6
  130. package/src/components/SampleSelector.vue +10 -3
  131. package/src/components/SectionCard.story.vue +33 -0
  132. package/src/components/SettingsModal.vue +7 -12
  133. package/src/components/Tooltip.vue +9 -32
  134. package/src/components/internal/AppTopBarOnboardingInternal.vue +172 -0
  135. package/src/components/internal/AppTopBarPageSelectorInternal.vue +140 -72
  136. package/src/components/internal/DatePickerDateInternal.vue +7 -45
  137. package/src/components/internal/DatePickerDateTimeInternal.vue +7 -1
  138. package/src/components/internal/DatePickerTimeInternal.vue +8 -1
  139. package/src/components/internal/NumberUnitInputInternal.vue +4 -18
  140. package/src/components/internal/OnboardingLayerInternal.vue +173 -0
  141. package/src/components/internal/SelectMultipleInternal.vue +6 -1
  142. package/src/components/internal/SelectSearchableInternal.vue +6 -1
  143. package/src/components/internal/WellEditPopupInternal.vue +11 -22
  144. package/src/components/internal/WorkspaceShellInternal.vue +12 -0
  145. package/src/composables/pluginWorkspaceModel.ts +2 -2
  146. package/src/composables/useFileImport.ts +51 -1
  147. package/src/composables/useFloatingPanel.ts +107 -0
  148. package/src/composables/useJobCenter.ts +188 -6
  149. package/src/composables/useOnboarding.ts +465 -0
  150. package/src/composables/usePluginWorkspace.ts +1 -1
  151. package/src/data.ts +1 -0
  152. package/src/runtime.ts +2 -1
  153. package/src/shell.ts +17 -0
  154. package/src/stores/index.ts +0 -2
  155. package/src/stores/settings.ts +20 -50
  156. package/src/styles/components/action-menu.css +1 -1
  157. package/src/styles/components/app-layout.css +6 -3
  158. package/src/styles/components/app-page-selector.css +120 -45
  159. package/src/styles/components/app-top-bar.css +165 -3
  160. package/src/styles/components/button.css +8 -0
  161. package/src/styles/components/dataframe.css +1 -1
  162. package/src/styles/components/date-picker.css +4 -2
  163. package/src/styles/components/datetime-picker.css +4 -4
  164. package/src/styles/components/experiment-selector-modal.css +13 -0
  165. package/src/styles/components/jobs-status-tray.css +134 -296
  166. package/src/styles/components/layout-resize-handle.css +59 -16
  167. package/src/styles/components/modal.css +3 -3
  168. package/src/styles/components/number-input.css +1 -1
  169. package/src/styles/components/onboarding.css +368 -0
  170. package/src/styles/components/progress-bar.css +3 -3
  171. package/src/styles/components/sample-selector.css +43 -0
  172. package/src/styles/components/searchable-select.css +3 -7
  173. package/src/styles/components/section-card.css +30 -6
  174. package/src/styles/components/settings-modal.css +7 -2
  175. package/src/styles/components/time-picker.css +3 -6
  176. package/src/styles/components/toast.css +1 -1
  177. package/src/styles/components/tooltip.css +2 -2
  178. package/src/styles/components/unit-input.css +1 -1
  179. package/src/styles/components/well-edit-popup.css +2 -2
  180. package/src/styles/index.css +1 -0
  181. package/src/styles/variables.css +153 -15
  182. package/src/types/components.ts +2 -0
  183. package/src/types/index.ts +1 -0
  184. package/src/types/jobs.ts +10 -0
  185. package/src/types/platform.ts +1 -1
  186. package/dist/AppSidebar-Dq9W1jE2.js.map +0 -1
  187. package/dist/ExperimentSelectorModal-65peG4Up.js.map +0 -1
  188. package/dist/SettingsModal-483nyI6b.js.map +0 -1
  189. package/dist/experiment-43OJtH7R.js.map +0 -1
  190. package/dist/records-B6gpM_3e.js.map +0 -1
  191. package/dist/runtime-7vfl_bI3.js.map +0 -1
  192. package/dist/useDropdownState-8yWMu-7_.js.map +0 -1
  193. package/dist/useExperimentSamples-DHnxKFAF.js.map +0 -1
  194. package/dist/useListReorder-BitdUhxn.js.map +0 -1
  195. package/dist/useRackEditor-DiwCt77M.js.map +0 -1
  196. package/dist/useRealtime-C3iy9QkU.js +0 -699
  197. package/dist/useRealtime-C3iy9QkU.js.map +0 -1
  198. package/dist/useRequest-D506eHi8.js.map +0 -1
@@ -0,0 +1 @@
1
+ {"version":3,"file":"runtime-q-R0CNLh.js","names":["$emit","$attrs"],"sources":["../src/composables/useToast.ts","../src/components/AppToastContainer.vue","../src/components/AppToastContainer.vue","../src/composables/useJobCenter.ts","../src/composables/controlWorkspaceOptions.ts","../src/composables/useControlWorkspace.ts","../src/components/internal/WorkspaceControlsInternal.vue","../src/components/internal/WorkspaceControlsInternal.vue","../src/components/internal/WorkspaceShellInternal.vue","../src/components/internal/WorkspaceShellInternal.vue","../src/components/internal/WorkspaceSidebarInternal.vue","../src/components/internal/WorkspaceSidebarInternal.vue","../src/components/PluginWorkspaceView.vue","../src/components/PluginWorkspaceView.vue","../src/components/Avatar.vue","../src/components/Avatar.vue","../src/generated/schema.ts","../src/components/GeneratedPluginView.vue","../src/components/GeneratedPluginView.vue","../src/components/internal/PlateEditorBindingInternal.vue","../src/components/internal/PlateEditorBindingInternal.vue","../src/components/ComponentBindingRenderer.vue","../src/components/ComponentBindingRenderer.vue","../src/components/RuntimeUpdateNotice.vue","../src/components/RuntimeUpdateNotice.vue","../src/composables/usePresence.ts","../src/utils/presenceAvatars.ts","../src/components/PresenceAvatars.vue","../src/components/PresenceAvatars.vue","../src/runtime.ts"],"sourcesContent":["import { ref } from 'vue'\nimport type { Toast, ToastOptions } from '../types'\n\nconst toasts = ref<Toast[]>([])\nlet nextId = 0\n\n/** Options of `success()`, `error()`, `warning()` and `info()`: the message is the title. */\ntype ToastMessageOptions = Omit<ToastOptions, 'title' | 'type'>\n\n/** Reactive global toast queue with success/error/warning/info variants and auto-dismiss timers. */\nexport function useToast() {\n /** Push a structured toast. `progress: 'indeterminate'` is the in-progress form and never auto-dismisses. */\n function push(options: ToastOptions): number {\n const id = nextId++\n const duration = options.duration ?? 3500\n toasts.value.push({\n id,\n type: 'success',\n ...options,\n message: options.message ?? options.title,\n duration,\n actions: options.actions?.slice(0, 2),\n })\n if (options.progress !== 'indeterminate') {\n setTimeout(() => dismiss(id), duration)\n }\n return id\n }\n\n function notify(type: Toast['type'], duration: number, message: string, options: ToastMessageOptions = {}): number {\n return push({ duration, ...options, title: message, type })\n }\n\n function success(message: string, options?: ToastMessageOptions): number {\n return notify('success', 3500, message, options)\n }\n\n function error(message: string, options?: ToastMessageOptions): number {\n return notify('error', 5000, message, options)\n }\n\n function warning(message: string, options?: ToastMessageOptions): number {\n return notify('warning', 4000, message, options)\n }\n\n function info(message: string, options?: ToastMessageOptions): number {\n return notify('info', 3500, message, options)\n }\n\n function dismiss(id: number) {\n toasts.value = toasts.value.filter(t => t.id !== id)\n }\n\n function clear() {\n toasts.value = []\n }\n\n return { toasts, push, success, error, warning, info, dismiss, clear }\n}\n","<script setup lang=\"ts\">\n/** Preferred toast container driven by useToast: title/detail, up to two actions, TTL or indeterminate bar, click-to-close. */\nimport { useToast } from '../composables/useToast'\nimport type { Toast, ToastAction } from '../types'\n\nconst { toasts, dismiss } = useToast()\n\nfunction title(toast: Toast): string {\n return toast.title ?? toast.message\n}\n\nfunction actions(toast: Toast): ToastAction[] {\n return (toast.actions ?? []).slice(0, 2)\n}\n\nfunction progress(toast: Toast): NonNullable<Toast['progress']> {\n return toast.progress ?? 'ttl'\n}\n\nfunction runAction(toast: Toast, action: ToastAction) {\n action.onClick()\n dismiss(toast.id)\n}\n</script>\n\n<template>\n <Teleport to=\"body\">\n <div class=\"mint-toast__container\">\n <TransitionGroup name=\"toast\">\n <div\n v-for=\"toast in toasts\"\n :key=\"toast.id\"\n :class=\"[\n 'mint-toast__item',\n `mint-toast__item--${toast.type}`,\n (toast.count ?? 1) > 1 ? 'mint-toast__item--stacked' : '',\n ]\"\n :role=\"toast.type === 'error' || toast.type === 'warning' ? 'alert' : 'status'\"\n @click=\"dismiss(toast.id)\"\n >\n <!-- Lucide circle-check -->\n <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\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"m9 12 2 2 4-4\" />\n </svg>\n <!-- Lucide circle-x -->\n <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\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"m15 9-6 6\" /><path d=\"m9 9 6 6\" />\n </svg>\n <!-- Lucide triangle-alert -->\n <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\">\n <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\" />\n </svg>\n <!-- Lucide info -->\n <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\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"M12 16v-4\" /><path d=\"M12 8h.01\" />\n </svg>\n\n <div class=\"mint-toast__body\">\n <div class=\"mint-toast__title\">\n <span class=\"mint-toast__message\">{{ title(toast) }}</span>\n <span v-if=\"(toast.count ?? 1) > 1\" class=\"mint-toast__count\">×{{ toast.count }}</span>\n </div>\n <div v-if=\"toast.detail\" class=\"mint-toast__detail\">{{ toast.detail }}</div>\n <div v-if=\"actions(toast).length\" class=\"mint-toast__actions\">\n <button\n v-for=\"action in actions(toast)\"\n :key=\"action.label\"\n type=\"button\"\n :class=\"['mint-toast__action', action.primary ? 'mint-toast__action--primary' : '']\"\n @click.stop=\"runAction(toast, action)\"\n >\n {{ action.label }}\n </button>\n </div>\n </div>\n\n <button\n v-if=\"toast.dismissible !== false\"\n type=\"button\"\n class=\"mint-toast__close\"\n aria-label=\"Dismiss\"\n @click.stop=\"dismiss(toast.id)\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" aria-hidden=\"true\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n\n <span\n v-if=\"progress(toast) === 'ttl'\"\n class=\"mint-toast__progress\"\n :style=\"{ animationDuration: `${toast.duration ?? 3500}ms` }\"\n />\n <span\n v-else-if=\"progress(toast) === 'indeterminate'\"\n class=\"mint-toast__progress mint-toast__progress--indeterminate\"\n />\n </div>\n </TransitionGroup>\n </div>\n </Teleport>\n</template>\n","<script setup lang=\"ts\">\n/** Preferred toast container driven by useToast: title/detail, up to two actions, TTL or indeterminate bar, click-to-close. */\nimport { useToast } from '../composables/useToast'\nimport type { Toast, ToastAction } from '../types'\n\nconst { toasts, dismiss } = useToast()\n\nfunction title(toast: Toast): string {\n return toast.title ?? toast.message\n}\n\nfunction actions(toast: Toast): ToastAction[] {\n return (toast.actions ?? []).slice(0, 2)\n}\n\nfunction progress(toast: Toast): NonNullable<Toast['progress']> {\n return toast.progress ?? 'ttl'\n}\n\nfunction runAction(toast: Toast, action: ToastAction) {\n action.onClick()\n dismiss(toast.id)\n}\n</script>\n\n<template>\n <Teleport to=\"body\">\n <div class=\"mint-toast__container\">\n <TransitionGroup name=\"toast\">\n <div\n v-for=\"toast in toasts\"\n :key=\"toast.id\"\n :class=\"[\n 'mint-toast__item',\n `mint-toast__item--${toast.type}`,\n (toast.count ?? 1) > 1 ? 'mint-toast__item--stacked' : '',\n ]\"\n :role=\"toast.type === 'error' || toast.type === 'warning' ? 'alert' : 'status'\"\n @click=\"dismiss(toast.id)\"\n >\n <!-- Lucide circle-check -->\n <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\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"m9 12 2 2 4-4\" />\n </svg>\n <!-- Lucide circle-x -->\n <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\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"m15 9-6 6\" /><path d=\"m9 9 6 6\" />\n </svg>\n <!-- Lucide triangle-alert -->\n <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\">\n <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\" />\n </svg>\n <!-- Lucide info -->\n <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\">\n <circle cx=\"12\" cy=\"12\" r=\"10\" /><path d=\"M12 16v-4\" /><path d=\"M12 8h.01\" />\n </svg>\n\n <div class=\"mint-toast__body\">\n <div class=\"mint-toast__title\">\n <span class=\"mint-toast__message\">{{ title(toast) }}</span>\n <span v-if=\"(toast.count ?? 1) > 1\" class=\"mint-toast__count\">×{{ toast.count }}</span>\n </div>\n <div v-if=\"toast.detail\" class=\"mint-toast__detail\">{{ toast.detail }}</div>\n <div v-if=\"actions(toast).length\" class=\"mint-toast__actions\">\n <button\n v-for=\"action in actions(toast)\"\n :key=\"action.label\"\n type=\"button\"\n :class=\"['mint-toast__action', action.primary ? 'mint-toast__action--primary' : '']\"\n @click.stop=\"runAction(toast, action)\"\n >\n {{ action.label }}\n </button>\n </div>\n </div>\n\n <button\n v-if=\"toast.dismissible !== false\"\n type=\"button\"\n class=\"mint-toast__close\"\n aria-label=\"Dismiss\"\n @click.stop=\"dismiss(toast.id)\"\n >\n <svg viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" stroke-width=\"2.2\" stroke-linecap=\"round\" aria-hidden=\"true\">\n <path d=\"M18 6 6 18\" /><path d=\"m6 6 12 12\" />\n </svg>\n </button>\n\n <span\n v-if=\"progress(toast) === 'ttl'\"\n class=\"mint-toast__progress\"\n :style=\"{ animationDuration: `${toast.duration ?? 3500}ms` }\"\n />\n <span\n v-else-if=\"progress(toast) === 'indeterminate'\"\n class=\"mint-toast__progress mint-toast__progress--indeterminate\"\n />\n </div>\n </TransitionGroup>\n </div>\n </Teleport>\n</template>\n","import {\n computed,\n onMounted,\n onUnmounted,\n ref,\n shallowRef,\n toValue,\n useId,\n watch,\n type ComputedRef,\n type MaybeRefOrGetter,\n type Ref,\n type ShallowRef,\n} from 'vue'\n\nimport { isActiveJobStatus, jobStatusLabel, normalizeJobPercent, normalizeJobState } from '../jobs'\nimport type {\n JobListPayload,\n JobState,\n JobStateInput,\n JobStatus,\n TopBarJob,\n} from '../types/jobs'\nimport { usePlatform } from './usePlatform'\n\n/** How long a job that just completed stays in the top-bar run slot. */\nconst FINISHED_HOLD_MS = 6000\n\n/**\n * The canonical owner of a collection of plugin jobs.\n *\n * Sources, rather than job-center UI, own polling, event streams, and all job\n * mutations. This keeps components and consumers on one reactive job graph.\n */\nexport interface PluginJobCenterSource {\n jobs: MaybeRefOrGetter<readonly JobStateInput[]>\n refresh?: () => Promise<JobListPayload | readonly JobStateInput[] | void>\n cancel?: (jobId: string) => Promise<JobStateInput | void>\n delete?: (jobId: string) => Promise<boolean | void>\n clear?: () => Promise<number | void>\n dispose?: () => void\n}\n\nexport interface CombinedPluginJobCenterSource extends PluginJobCenterSource {\n jobs: ComputedRef<readonly JobStateInput[]>\n}\n\n/**\n * Combines independent job runtimes without copying their reactive state.\n *\n * Job ids must be globally unique across the sources. A duplicate id throws\n * when jobs are read or an id-routed action is requested, rather than silently\n * dispatching a mutation to the wrong owner.\n */\nexport function combinePluginJobSources(\n sources: readonly PluginJobCenterSource[],\n): CombinedPluginJobCenterSource {\n const jobs = computed<readonly JobStateInput[]>(() => {\n const combined: JobStateInput[] = []\n const owners = new Set<string>()\n for (const source of sources) {\n for (const job of toValue(source.jobs)) {\n if (owners.has(job.job_id)) throw duplicatePluginJobId(job.job_id)\n owners.add(job.job_id)\n combined.push(job)\n }\n }\n return combined\n })\n\n function ownerFor(jobId: string): PluginJobCenterSource {\n let owner: PluginJobCenterSource | undefined\n for (const source of sources) {\n if (!toValue(source.jobs).some(job => job.job_id === jobId)) continue\n if (owner) throw duplicatePluginJobId(jobId)\n owner = source\n }\n if (!owner) throw new Error(`Unknown plugin job id: ${jobId}`)\n return owner\n }\n\n const combined: CombinedPluginJobCenterSource = { jobs }\n if (sources.some(source => source.refresh)) {\n combined.refresh = async () => {\n await Promise.all(sources.map(source => source.refresh?.()))\n return jobs.value\n }\n }\n if (sources.some(source => source.cancel)) {\n combined.cancel = async (jobId) => {\n const owner = ownerFor(jobId)\n if (!owner.cancel) throw new Error(`Job ${jobId} cannot be cancelled by its source`)\n return owner.cancel(jobId)\n }\n }\n if (sources.length > 0 && sources.every(source => source.delete)) {\n combined.delete = async (jobId) => {\n const owner = ownerFor(jobId)\n if (!owner.delete) throw new Error(`Job ${jobId} cannot be deleted by its source`)\n return owner.delete(jobId)\n }\n }\n // Never report a successful combined clear after mutating only a subset.\n // Without bulk support from every source, the job center can still fall\n // back to this source's id-routed delete method when all owners expose it.\n if (sources.length > 0 && sources.every(source => source.clear)) {\n combined.clear = async () => {\n const results = await Promise.all(\n sources.map(source => source.clear!()),\n )\n return results.every((result): result is number => typeof result === 'number')\n ? results.reduce((total, result) => total + result, 0)\n : undefined\n }\n }\n if (sources.some(source => source.dispose)) {\n combined.dispose = () => {\n const errors: unknown[] = []\n for (const source of sources) {\n try {\n source.dispose?.()\n } catch (cause) {\n errors.push(cause)\n }\n }\n if (errors.length === 1) throw errors[0]\n if (errors.length > 1) throw new PluginJobSourceDisposeError(errors)\n }\n }\n return combined\n}\n\nclass PluginJobSourceDisposeError extends Error {\n readonly cause: unknown\n readonly errors: readonly unknown[]\n\n constructor(errors: readonly unknown[]) {\n super('Failed to dispose plugin job sources')\n this.name = 'PluginJobSourceDisposeError'\n this.cause = errors[0]\n this.errors = Object.freeze([...errors])\n }\n}\n\nfunction duplicatePluginJobId(jobId: string): Error {\n return new Error(`Duplicate plugin job id across combined sources: ${jobId}`)\n}\n\nexport interface UseJobCenterOptions {\n source?: MaybeRefOrGetter<PluginJobCenterSource | undefined>\n loadOnMount?: boolean\n /**\n * Maps the job that the top-bar chip shows. It is called for the chosen own\n * active job AND for the held just-completed job, so check `job.status`.\n * `null` keeps the default mapping.\n */\n topBarJob?: (job: JobState) => TopBarJob | null\n /**\n * Overrides how a tray row looks: `status` (icon, awaiting-input tint and\n * pinning), `percent` (progress bar and value) and `message` (detail line).\n * A missing or `undefined` field, or a `null` status or message, keeps the\n * job's own; `percent: null` hides the bar and shows the time, and a status\n * alone keeps the job's own percent. The job's section, actions and counts\n * do not change.\n */\n rowJob?: (job: JobState) => JobRowOverride | null\n}\n\n/** A `rowJob` result; see `UseJobCenterOptions.rowJob`. */\nexport interface JobRowOverride {\n status?: JobStatus | null\n percent?: number | null\n message?: string | null\n}\n\n/** How a tray row shows a job; see `UseJobCenterReturn.rowView`. */\nexport interface JobRowView {\n status: JobStatus\n /** 0-100, rounded; `null` hides the progress bar and shows the time instead. */\n percent: number | null\n message: string\n}\n\nexport interface UseJobCenterReturn {\n /** The current source; a new identity is a new job list. */\n source: ComputedRef<PluginJobCenterSource | undefined>\n jobs: ComputedRef<JobState[]>\n activeJobs: ComputedRef<JobState[]>\n historyJobs: ComputedRef<JobState[]>\n deletableJobs: ComputedRef<JobState[]>\n featuredJob: ComputedRef<JobState | null>\n canRefresh: ComputedRef<boolean>\n canCancel: ComputedRef<boolean>\n canDelete: ComputedRef<boolean>\n canClearFinished: ComputedRef<boolean>\n /** DOM id of the JobsStatusTray panel, for `AppTopBar`'s `jobsPanelId` prop. */\n panelId: string\n /** The row view of a job, with the `rowJob` option applied. */\n rowView: (job: JobState) => JobRowView\n /** The viewer's own job for `AppTopBar`'s `job` prop. */\n topBarJob: ComputedRef<TopBarJob | null>\n /** Jobs in the list with status `completed`, for `AppTopBar`'s `jobsDone` prop. */\n completedCount: ComputedRef<number>\n isOpen: Ref<boolean>\n isLoading: Ref<boolean>\n error: ShallowRef<string | null>\n pendingJobIds: Ref<Set<string>>\n open: () => void\n close: () => void\n toggle: () => void\n /** The top-bar chip: with the tray closed and none of the viewer's jobs active, selects the held just-completed job; else toggles. */\n handleTopBarClick: (onSelect: (job: JobState) => void) => void\n refresh: () => Promise<boolean>\n cancelJob: (job: JobState) => Promise<boolean>\n deleteJob: (job: JobState) => Promise<boolean>\n clearFinished: () => Promise<boolean>\n isPending: (job: JobState) => boolean\n}\n\n/** The stored seen failures, or null when nothing is stored or storage is blocked. */\nfunction readSeenFailed(key: string): Set<string> | null {\n try {\n const parsed: unknown = JSON.parse(globalThis.localStorage?.getItem(key) ?? 'null')\n return Array.isArray(parsed) ? new Set(parsed.filter((id): id is string => typeof id === 'string')) : null\n } catch {\n return null\n }\n}\n\nfunction writeSeenFailed(key: string, seen: Set<string>): void {\n try {\n globalThis.localStorage?.setItem(key, JSON.stringify([...seen]))\n } catch {\n // Private windows and full storage: the state lasts until reload.\n }\n}\n\nfunction jobMessage(job: JobState): string {\n if (job.error) return job.error\n if (job.status === 'awaiting_input') {\n return job.progress.message || 'Waiting for external input'\n }\n if (job.status === 'queued' && job.queue_position > 0) {\n return `Queue position ${job.queue_position}`\n }\n return job.progress.message || job.progress.stage || jobStatusLabel(job.status)\n}\n\nfunction errorMessage(error: unknown, fallback: string): string {\n return error instanceof Error ? error.message : fallback\n}\n\n/**\n * Headless controller for plugin job presentation and actions.\n *\n * Every job list is derived directly from the source. The controller never\n * mirrors source jobs into another ref.\n */\nexport function useJobCenter(\n options: UseJobCenterOptions = {},\n): UseJobCenterReturn {\n const isOpen = ref(false)\n const isLoading = ref(false)\n const error = shallowRef<string | null>(null)\n const pendingJobIds = ref(new Set<string>())\n let requestGeneration = 0\n let active = true\n const source = computed(() => toValue(options.source))\n\n const jobs = computed<JobState[]>(() => {\n const currentSource = source.value\n return currentSource ? [...toValue(currentSource.jobs)].map(normalizeJobState) : []\n })\n const activeJobs = computed(() => jobs.value.filter(job => isActiveJobStatus(job.status)))\n const historyJobs = computed(() => jobs.value.filter(job => !isActiveJobStatus(job.status)))\n const deletableJobs = computed(() => historyJobs.value.filter(job => job.can_delete))\n const featuredJob = computed(() => activeJobs.value[0] ?? historyJobs.value[0] ?? null)\n const completedCount = computed(() => jobs.value.filter(job => job.status === 'completed').length)\n\n // Top-bar run slot: the viewer's own jobs only. Standalone or with auth off\n // (no signed-in user), every job is the viewer's.\n const { integrated, user, plugin, isAdmin } = usePlatform()\n const isOwnJob = (job: JobState) => {\n if (!integrated.value) return true\n // With no user, isAdmin is true only with auth off.\n if (user.value == null) return isAdmin.value\n return (job.owner_user_id ?? job.user_id) === String(user.value.id)\n }\n const ownActiveJobs = computed(() => activeJobs.value.filter(isOwnJob))\n const justFinished = shallowRef<JobState | null>(null)\n // The live held job; it drops out once the job leaves the list.\n const heldJob = computed(() => {\n const held = justFinished.value\n return held ? jobs.value.find(job => job.job_id === held.job_id) ?? null : null\n })\n let finishedTimer: ReturnType<typeof setTimeout> | undefined\n // Compare active jobs within one source only: a replaced source starts over.\n watch([source, ownActiveJobs], ([currentSource, now], [previousSource, before]) => {\n if (currentSource !== previousSource) {\n justFinished.value = null\n return\n }\n const nowIds = new Set(now.map(job => job.job_id))\n const left = new Set(before.filter(job => !nowIds.has(job.job_id)).map(job => job.job_id))\n const finished = jobs.value.find(job => left.has(job.job_id) && job.status === 'completed')\n if (!finished) return\n justFinished.value = finished\n clearTimeout(finishedTimer)\n finishedTimer = setTimeout(() => { justFinished.value = null }, FINISHED_HOLD_MS)\n })\n // ponytail: the seen set only grows; prune to listed jobs if the stored array ever matters.\n const seenFailedKey = `mint.jobs.${plugin.value?.id ?? 'standalone'}.seen-failed`\n const storedSeenFailed = readSeenFailed(seenFailedKey)\n const seenFailed = shallowRef(storedSeenFailed ?? new Set<string>())\n const unseenFailedJobs = computed(() => historyJobs.value.filter(job => (\n job.status === 'failed' && isOwnJob(job) && !seenFailed.value.has(job.job_id)\n )))\n function markFailedSeen(): void {\n seenFailed.value = new Set([...seenFailed.value, ...unseenFailedJobs.value.map(job => job.job_id)])\n writeSeenFailed(seenFailedKey, seenFailed.value)\n }\n // Nothing stored (new browser, cleared or blocked storage): the failures at the\n // initial load are the baseline, so only later failures alert. Without a load\n // step, the first non-empty list stands in for it.\n let hasBaseline = storedSeenFailed !== null\n let awaitingLoad = options.loadOnMount !== false && Boolean(source.value?.refresh)\n function takeBaseline(): void {\n if (hasBaseline || !active) return\n hasBaseline = true\n markFailedSeen()\n }\n watch(jobs, (list) => {\n if (!awaitingLoad && list.length > 0) takeBaseline()\n }, { immediate: true })\n // The open tray shows every failure, including one that happens while it is open.\n watch([isOpen, unseenFailedJobs], ([open, unseen]) => {\n if (open && unseen.length > 0) markFailedSeen()\n })\n const topBarJob = computed<TopBarJob | null>(() => {\n const own = ownActiveJobs.value\n const shown = own.find(job => job.status === 'awaiting_input') ?? own[0]\n if (shown) {\n return options.topBarJob?.(shown) ?? {\n status: shown.status,\n label: shown.progress.message || `${shown.name} ${jobStatusLabel(shown.status).toLowerCase()}`,\n percent: shown.status === 'running' ? normalizeJobPercent(shown.progress.percent) : null,\n }\n }\n const held = heldJob.value\n if (held) return options.topBarJob?.(held) ?? { status: 'completed', label: `${held.name} completed` }\n const failed = unseenFailedJobs.value.length\n return failed > 0 ? { status: 'failed', label: `${failed} failed` } : null\n })\n\n function rowView(job: JobState): JobRowView {\n const override = options.rowJob?.(job) ?? {}\n const status = override.status ?? job.status\n // Only an explicit percent changes the bar; a status override keeps the job's own.\n const percent = override.percent !== undefined\n ? override.percent\n : job.status === 'running' ? job.progress.percent : null\n return {\n status,\n percent: percent == null ? null : Math.round(normalizeJobPercent(percent)),\n message: override.message ?? jobMessage(job),\n }\n }\n\n function handleTopBarClick(onSelect: (job: JobState) => void): void {\n const finished = heldJob.value\n if (!isOpen.value && ownActiveJobs.value.length === 0 && finished) onSelect(finished)\n else isOpen.value = !isOpen.value\n }\n\n const canRefresh = computed(() => Boolean(source.value?.refresh))\n const canCancel = computed(() => Boolean(source.value?.cancel))\n const canDelete = computed(() => Boolean(source.value?.delete))\n const canClearFinished = computed(() => Boolean(\n source.value?.clear || source.value?.delete,\n ))\n\n function setPending(jobId: string, pending: boolean): void {\n const next = new Set(pendingJobIds.value)\n if (pending) next.add(jobId)\n else next.delete(jobId)\n pendingJobIds.value = next\n }\n\n async function refresh(): Promise<boolean> {\n const listJobs = source.value?.refresh\n if (!listJobs) return false\n const generation = ++requestGeneration\n isLoading.value = true\n error.value = null\n try {\n await listJobs()\n return active && generation === requestGeneration\n } catch (cause) {\n if (active && generation === requestGeneration) {\n error.value = errorMessage(cause, 'Failed to load jobs')\n }\n return false\n } finally {\n if (active && generation === requestGeneration) isLoading.value = false\n }\n }\n\n async function cancelJob(job: JobState): Promise<boolean> {\n const sourceCancel = source.value?.cancel\n if (!job.can_cancel || !sourceCancel || pendingJobIds.value.has(job.job_id)) {\n return false\n }\n setPending(job.job_id, true)\n error.value = null\n try {\n await sourceCancel(job.job_id)\n return active\n } catch (cause) {\n if (active) error.value = errorMessage(cause, 'Failed to cancel job')\n return false\n } finally {\n if (active) setPending(job.job_id, false)\n }\n }\n\n async function deleteJob(job: JobState): Promise<boolean> {\n const sourceDelete = source.value?.delete\n if (!job.can_delete || !sourceDelete || pendingJobIds.value.has(job.job_id)) {\n return false\n }\n setPending(job.job_id, true)\n error.value = null\n try {\n const deleted = await sourceDelete(job.job_id)\n return active && deleted !== false\n } catch (cause) {\n if (active) error.value = errorMessage(cause, 'Failed to delete job')\n return false\n } finally {\n if (active) setPending(job.job_id, false)\n }\n }\n\n async function clearFinished(): Promise<boolean> {\n const targets = deletableJobs.value\n if (targets.length === 0) return false\n error.value = null\n try {\n const currentSource = source.value\n if (currentSource?.clear) {\n const deleted = await currentSource.clear()\n if (!active) return false\n return typeof deleted !== 'number' || deleted === targets.length\n }\n if (!currentSource?.delete) return false\n const results = await Promise.all(targets.map(job => deleteJob(job)))\n return results.every(Boolean)\n } catch (cause) {\n if (active) error.value = errorMessage(cause, 'Failed to clear jobs')\n return false\n }\n }\n\n onMounted(() => {\n if (options.loadOnMount === false) return\n void refresh().then((loaded) => {\n awaitingLoad = false\n if (loaded || jobs.value.length > 0) takeBaseline()\n })\n })\n onUnmounted(() => {\n active = false\n requestGeneration += 1\n clearTimeout(finishedTimer)\n })\n\n return {\n source,\n jobs,\n activeJobs,\n historyJobs,\n deletableJobs,\n featuredJob,\n canRefresh,\n canCancel,\n canDelete,\n canClearFinished,\n panelId: `mint-jobs-tray-${useId()}`,\n rowView,\n topBarJob,\n completedCount,\n isOpen,\n isLoading,\n error,\n pendingJobIds,\n open: () => { isOpen.value = true },\n close: () => { isOpen.value = false },\n toggle: () => { isOpen.value = !isOpen.value },\n handleTopBarClick,\n refresh,\n cancelJob,\n deleteJob,\n clearFinished,\n isPending: job => pendingJobIds.value.has(job.job_id),\n }\n}\n","import type {\n ControlWorkspaceOptions,\n} from './controlSchemaTypes'\n\nexport function mergeControlWorkspaceOptions(\n base?: ControlWorkspaceOptions,\n override?: ControlWorkspaceOptions,\n): ControlWorkspaceOptions {\n return {\n ...(base ?? {}),\n ...(override ?? {}),\n initialValues: {\n ...(base?.initialValues ?? {}),\n ...(override?.initialValues ?? {}),\n },\n topBarSettings: {\n ...(base?.topBarSettings ?? {}),\n ...(override?.topBarSettings ?? {}),\n },\n }\n}\n","import {\n computed,\n reactive,\n ref,\n watch,\n} from 'vue'\nimport type {\n PillNavItem,\n TopBarSettingsConfig,\n} from '../types'\nimport {\n replaceRecord,\n} from './controlSchemaUtils'\nimport {\n mergeControlWorkspaceOptions,\n} from './controlWorkspaceOptions'\nimport {\n controlValuesToComponentBindings,\n controlValuesToComponentBindingsById,\n controlValuesToComponentProps,\n} from './controlComponentBindings'\nimport {\n isControlModelBinding,\n} from './controlSchemaModel'\nimport {\n useControlSchema,\n} from './useControlSchema'\nimport type {\n ControlComponentBinding,\n ControlComponentBindingsById,\n ControlComponentBindingsConfig,\n ControlComponentPropsByIdMap,\n ControlComponentPropsMap,\n ControlModelBinding,\n ControlSchema,\n ControlValues,\n ControlWorkspaceComponentBindings,\n ControlWorkspaceFormBinding,\n ControlWorkspaceOptions,\n ControlWorkspacePillNavBinding,\n ControlWorkspaceSidebarBinding,\n ControlWorkspaceTopBarBinding,\n ControlWorkspaceTopBarSettingsBinding,\n UseControlWorkspaceReturn,\n} from './controlSchemaTypes'\n\n/**\n * Prepare shared reactive values plus AppTopBar/AppSidebar/FormBuilder bindings from one simple controls data model.\n *\n * @example Recommended\n * ```ts\n * const workspace = useControlWorkspace(workspaceModel)\n * const { form, sidebar, topBar } = workspace.bindings\n * ```\n */\nexport function useControlWorkspace<TControls extends ControlSchema>(\n controlsOrModel: TControls | (ControlModelBinding & { controls: TControls }),\n options: ControlWorkspaceOptions = {},\n): UseControlWorkspaceReturn<TControls> {\n const model = isControlModelBinding<ControlModelBinding & { controls: TControls }>(controlsOrModel)\n ? controlsOrModel\n : undefined\n const controls: TControls = model ? model.controls : controlsOrModel as TControls\n const workspaceOptions = model\n ? mergeControlWorkspaceOptions(model.controlOptions, options)\n : options\n const { initialValues, topBarSettings, ...schemaOptions } = workspaceOptions\n const schema = useControlSchema(controls, schemaOptions)\n const activeView = ref(schema.defaultView)\n const values = reactive({\n ...schema.initialValues,\n ...(initialValues ?? {}),\n }) as ControlValues<TControls> & Record<string, unknown>\n\n function setActiveView(viewId: string) {\n syncActiveView(viewId)\n }\n\n function syncActiveView(viewId: string) {\n if (!schema.viewIds.includes(viewId)) return\n if (activeView.value !== viewId) activeView.value = viewId\n if (sidebar.activeView !== viewId) sidebar.activeView = viewId\n if (pillNav.currentItemId !== viewId) pillNav.currentItemId = viewId\n }\n\n function setValues(nextValues: Record<string, unknown>) {\n Object.assign(values, nextValues)\n }\n\n function resetValues(nextValues: Record<string, unknown> = {}) {\n replaceRecord(values, {\n ...schema.initialValues,\n ...nextValues,\n })\n }\n\n function getComponentProps(\n mapping?: ControlComponentPropsMap<ControlValues<TControls> & Record<string, unknown>>,\n ): Record<string, unknown> {\n return controlValuesToComponentProps(values, mapping)\n }\n\n function getComponentPropsById(\n mappings?: ControlComponentPropsByIdMap<ControlValues<TControls> & Record<string, unknown>>,\n ): Record<string, Record<string, unknown>> {\n if (mappings === undefined) return {}\n\n return Object.fromEntries(\n Object.entries(mappings).map(([id, mapping]) => [\n id,\n controlValuesToComponentProps(values, mapping),\n ]),\n )\n }\n\n function getComponentBindings(\n bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>,\n ): ControlComponentBinding[] {\n return controlValuesToComponentBindings(values, bindings)\n }\n\n function getComponentBindingsById(\n bindings?: ControlComponentBindingsConfig<ControlValues<TControls> & Record<string, unknown>>,\n ): ControlComponentBindingsById {\n return controlValuesToComponentBindingsById(values, bindings)\n }\n\n const componentProps = computed(() => (\n model?.componentProps === undefined ? {} : getComponentProps(model.componentProps)\n ))\n const componentPropsById = computed(() => getComponentPropsById(model?.componentPropsById))\n const componentBindings = computed(() => getComponentBindings(model?.componentBindings))\n const componentBindingsById = computed(() => getComponentBindingsById(model?.componentBindings))\n const form = {\n ...schema.form,\n modelValue: values,\n 'onUpdate:modelValue': setValues,\n } as ControlWorkspaceFormBinding\n\n const topBarSettingsConfig: TopBarSettingsConfig = {\n ...schema.topBarSettingsConfig,\n ...(topBarSettings ?? {}),\n values,\n }\n const sidebar = reactive({\n ...schema.sidebar,\n activeView: activeView.value,\n values,\n 'onUpdate:values': setValues,\n }) as ControlWorkspaceSidebarBinding\n const pillNav = reactive({\n items: schema.viewItems,\n currentItemId: activeView.value,\n onSelect: (item: PillNavItem) => setActiveView(item.id),\n }) as ControlWorkspacePillNavBinding\n const topBarSettingsBinding = {\n spec: { settings: topBarSettingsConfig },\n onSettingsValuesChange: setValues,\n } as ControlWorkspaceTopBarSettingsBinding\n const topBarProps = computed<ControlWorkspaceTopBarBinding>(() => ({\n spec: { pills: pillNav.items, settings: topBarSettingsConfig },\n pill: pillNav.currentItemId,\n onPillSelect: pillNav.onSelect,\n onSettingsValuesChange: setValues,\n }))\n const bindings: ControlWorkspaceComponentBindings = {\n form,\n sidebar,\n topBar: topBarProps,\n topBarSettings: topBarSettingsBinding,\n pillNav,\n componentBindings,\n componentBindingsById,\n componentProps,\n componentPropsById,\n }\n\n watch(activeView, syncActiveView, { flush: 'sync' })\n watch(() => sidebar.activeView, syncActiveView, { flush: 'sync' })\n watch(() => pillNav.currentItemId, syncActiveView, { flush: 'sync' })\n\n return {\n ...schema,\n schema,\n values,\n activeView,\n topBarSettingsConfig,\n form,\n sidebar,\n topBar: topBarProps,\n pillNav,\n topBarSettings: topBarSettingsBinding,\n bindings,\n componentBindings,\n componentBindingsById,\n componentProps,\n componentPropsById,\n setActiveView,\n setValues,\n resetValues,\n getComponentProps,\n getComponentPropsById,\n getComponentBindings,\n getComponentBindingsById,\n }\n}\n","<script setup lang=\"ts\">\n/**\n * Internal: renders PluginWorkspaceView's default (main content) slot bound to the\n * control-schema-derived scoped-slot payload (active view, values, component bindings/props).\n * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.\n */\nimport type { PluginWorkspaceControlsModel } from '../../composables/pluginWorkspaceModel'\n\ndefineProps<{\n controls: PluginWorkspaceControlsModel\n}>()\n\ndefineSlots<{\n default?: (props: PluginWorkspaceControlsModel) => unknown\n}>()\n</script>\n\n<template>\n <slot v-bind=\"controls\" />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Internal: renders PluginWorkspaceView's default (main content) slot bound to the\n * control-schema-derived scoped-slot payload (active view, values, component bindings/props).\n * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.\n */\nimport type { PluginWorkspaceControlsModel } from '../../composables/pluginWorkspaceModel'\n\ndefineProps<{\n controls: PluginWorkspaceControlsModel\n}>()\n\ndefineSlots<{\n default?: (props: PluginWorkspaceControlsModel) => unknown\n}>()\n</script>\n\n<template>\n <slot v-bind=\"controls\" />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Internal: AppLayout + AppTopBar for PluginWorkspaceView, driven by a single `shell` model.\n * Owns the responsive/collapse layout props and the top bar's default rendering; the caller\n * decides whether to override the `topbar`/`sidebar` slots and supplies the sidebar content.\n * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.\n */\nimport type {\n PillNavItem,\n PillNavOption,\n} from '../../types'\nimport AppLayout from '../AppLayout.vue'\nimport AppTopBar from '../AppTopBar.vue'\nimport type { PluginWorkspaceShellModel } from '../../composables/pluginWorkspaceModel'\nimport type { TopBarJob } from '../../types/jobs'\n\ndefineProps<{\n shell: PluginWorkspaceShellModel\n /** Passed to AppTopBar; undefined means no jobs control. */\n job?: TopBarJob | null\n jobsDone?: number\n jobsOpen?: boolean\n jobsPanelId?: string\n}>()\n\nconst emit = defineEmits<{\n 'pill-select': [item: PillNavItem]\n 'pill-option-select': [option: PillNavOption, item: PillNavItem]\n 'settings-values-change': [data: Record<string, unknown>]\n 'job-click': []\n}>()\n\nfunction handlePillOptionSelect(option: PillNavOption, item: PillNavItem) {\n emit('pill-option-select', option, item)\n}\n\ndefineSlots<{\n topbar?: (props: PluginWorkspaceShellModel['controls']) => unknown\n sidebar?: (props: PluginWorkspaceShellModel['controls']) => unknown\n default?: (props: PluginWorkspaceShellModel['controls']) => unknown\n icon?: (props: Record<string, unknown>) => unknown\n logo?: (props: Record<string, unknown>) => unknown\n nav?: (props: Record<string, unknown>) => unknown\n center?: (props: Record<string, unknown>) => unknown\n actions?: (props: Record<string, unknown>) => unknown\n 'settings-appearance'?: (props: Record<string, unknown>) => unknown\n}>()\n</script>\n\n<template>\n <AppLayout\n class=\"mint-plugin-workspace-view\"\n :sidebar-position=\"shell.sidebarPosition\"\n :sidebar-width=\"shell.sidebarWidth\"\n :floating=\"shell.floating\"\n :responsive-sidebar=\"shell.responsiveSidebar\"\n :sidebar-toggle-label=\"shell.sidebarToggleLabel\"\n :sidebar-close-label=\"shell.sidebarCloseLabel\"\n >\n <template #topbar>\n <slot name=\"topbar\" v-bind=\"shell.controls\">\n <AppTopBar\n v-if=\"shell.topBar\"\n :title=\"shell.title\"\n :subtitle=\"shell.subtitle\"\n :spec=\"shell.topBar\"\n :pill=\"shell.pill\"\n :job=\"job\"\n :jobs-done=\"jobsDone\"\n :jobs-open=\"jobsOpen\"\n :jobs-panel-id=\"jobsPanelId\"\n @job-click=\"emit('job-click')\"\n @pill-select=\"emit('pill-select', $event)\"\n @pill-option-select=\"handlePillOptionSelect\"\n @settings-values-change=\"emit('settings-values-change', $event)\"\n >\n <template\n v-for=\"slotName in shell.topBarSlotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppTopBar passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n </AppTopBar>\n </slot>\n </template>\n\n <template v-if=\"shell.hasSidebarSurface\" #sidebar>\n <slot name=\"sidebar\" v-bind=\"shell.controls\" />\n </template>\n\n <slot v-bind=\"shell.controls\" />\n </AppLayout>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Internal: AppLayout + AppTopBar for PluginWorkspaceView, driven by a single `shell` model.\n * Owns the responsive/collapse layout props and the top bar's default rendering; the caller\n * decides whether to override the `topbar`/`sidebar` slots and supplies the sidebar content.\n * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.\n */\nimport type {\n PillNavItem,\n PillNavOption,\n} from '../../types'\nimport AppLayout from '../AppLayout.vue'\nimport AppTopBar from '../AppTopBar.vue'\nimport type { PluginWorkspaceShellModel } from '../../composables/pluginWorkspaceModel'\nimport type { TopBarJob } from '../../types/jobs'\n\ndefineProps<{\n shell: PluginWorkspaceShellModel\n /** Passed to AppTopBar; undefined means no jobs control. */\n job?: TopBarJob | null\n jobsDone?: number\n jobsOpen?: boolean\n jobsPanelId?: string\n}>()\n\nconst emit = defineEmits<{\n 'pill-select': [item: PillNavItem]\n 'pill-option-select': [option: PillNavOption, item: PillNavItem]\n 'settings-values-change': [data: Record<string, unknown>]\n 'job-click': []\n}>()\n\nfunction handlePillOptionSelect(option: PillNavOption, item: PillNavItem) {\n emit('pill-option-select', option, item)\n}\n\ndefineSlots<{\n topbar?: (props: PluginWorkspaceShellModel['controls']) => unknown\n sidebar?: (props: PluginWorkspaceShellModel['controls']) => unknown\n default?: (props: PluginWorkspaceShellModel['controls']) => unknown\n icon?: (props: Record<string, unknown>) => unknown\n logo?: (props: Record<string, unknown>) => unknown\n nav?: (props: Record<string, unknown>) => unknown\n center?: (props: Record<string, unknown>) => unknown\n actions?: (props: Record<string, unknown>) => unknown\n 'settings-appearance'?: (props: Record<string, unknown>) => unknown\n}>()\n</script>\n\n<template>\n <AppLayout\n class=\"mint-plugin-workspace-view\"\n :sidebar-position=\"shell.sidebarPosition\"\n :sidebar-width=\"shell.sidebarWidth\"\n :floating=\"shell.floating\"\n :responsive-sidebar=\"shell.responsiveSidebar\"\n :sidebar-toggle-label=\"shell.sidebarToggleLabel\"\n :sidebar-close-label=\"shell.sidebarCloseLabel\"\n >\n <template #topbar>\n <slot name=\"topbar\" v-bind=\"shell.controls\">\n <AppTopBar\n v-if=\"shell.topBar\"\n :title=\"shell.title\"\n :subtitle=\"shell.subtitle\"\n :spec=\"shell.topBar\"\n :pill=\"shell.pill\"\n :job=\"job\"\n :jobs-done=\"jobsDone\"\n :jobs-open=\"jobsOpen\"\n :jobs-panel-id=\"jobsPanelId\"\n @job-click=\"emit('job-click')\"\n @pill-select=\"emit('pill-select', $event)\"\n @pill-option-select=\"handlePillOptionSelect\"\n @settings-values-change=\"emit('settings-values-change', $event)\"\n >\n <template\n v-for=\"slotName in shell.topBarSlotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppTopBar passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n </AppTopBar>\n </slot>\n </template>\n\n <template v-if=\"shell.hasSidebarSurface\" #sidebar>\n <slot name=\"sidebar\" v-bind=\"shell.controls\" />\n </template>\n\n <slot v-bind=\"shell.controls\" />\n </AppLayout>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Internal: AppSidebar for PluginWorkspaceView, driven by a single `sidebar` model covering\n * chrome, panels/forms, collapse behavior, and the compact control-schema props that drive\n * AppSidebar's auto-generated form.\n * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.\n */\nimport AppSidebar from '../AppSidebar.vue'\nimport type { PluginWorkspaceSidebarModel } from '../../composables/pluginWorkspaceModel'\n\ndefineProps<{\n sidebar: PluginWorkspaceSidebarModel\n}>()\n\ndefineEmits<{\n 'update:values': [values: Record<string, unknown>]\n 'update:collapsed': [value: boolean]\n 'update:toggle': [sectionId: string, value: boolean]\n 'section-action': [sectionId: string, actionId: string]\n 'form-submit': [sectionId: string, values: Record<string, unknown>]\n 'form-cancel': [sectionId: string]\n}>()\n\ndefineSlots<{\n header?: (props: Record<string, unknown>) => unknown\n collapsed?: (props: Record<string, unknown>) => unknown\n 'collapsed-footer'?: (props: Record<string, unknown>) => unknown\n footer?: (props: Record<string, unknown>) => unknown\n}>()\n</script>\n\n<template>\n <AppSidebar\n :spec=\"sidebar.spec\"\n :active-view=\"sidebar.activeView\"\n :values=\"sidebar.values\"\n :collapsed=\"sidebar.collapsed\"\n :form-loading=\"sidebar.formLoading\"\n :form-disabled=\"sidebar.formDisabled\"\n :form-readonly=\"sidebar.formReadonly\"\n @update:values=\"$emit('update:values', $event)\"\n @update:collapsed=\"$emit('update:collapsed', $event)\"\n @update:toggle=\"(sectionId, value) => $emit('update:toggle', sectionId, value)\"\n @section-action=\"(sectionId, actionId) => $emit('section-action', sectionId, actionId)\"\n @form-submit=\"(sectionId, values) => $emit('form-submit', sectionId, values)\"\n @form-cancel=\"$emit('form-cancel', $event)\"\n >\n <template\n v-for=\"slotName in sidebar.slotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppSidebar section-* passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n </AppSidebar>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Internal: AppSidebar for PluginWorkspaceView, driven by a single `sidebar` model covering\n * chrome, panels/forms, collapse behavior, and the compact control-schema props that drive\n * AppSidebar's auto-generated form.\n * Not part of the public SDK surface — see PluginWorkspaceView.vue for the public component.\n */\nimport AppSidebar from '../AppSidebar.vue'\nimport type { PluginWorkspaceSidebarModel } from '../../composables/pluginWorkspaceModel'\n\ndefineProps<{\n sidebar: PluginWorkspaceSidebarModel\n}>()\n\ndefineEmits<{\n 'update:values': [values: Record<string, unknown>]\n 'update:collapsed': [value: boolean]\n 'update:toggle': [sectionId: string, value: boolean]\n 'section-action': [sectionId: string, actionId: string]\n 'form-submit': [sectionId: string, values: Record<string, unknown>]\n 'form-cancel': [sectionId: string]\n}>()\n\ndefineSlots<{\n header?: (props: Record<string, unknown>) => unknown\n collapsed?: (props: Record<string, unknown>) => unknown\n 'collapsed-footer'?: (props: Record<string, unknown>) => unknown\n footer?: (props: Record<string, unknown>) => unknown\n}>()\n</script>\n\n<template>\n <AppSidebar\n :spec=\"sidebar.spec\"\n :active-view=\"sidebar.activeView\"\n :values=\"sidebar.values\"\n :collapsed=\"sidebar.collapsed\"\n :form-loading=\"sidebar.formLoading\"\n :form-disabled=\"sidebar.formDisabled\"\n :form-readonly=\"sidebar.formReadonly\"\n @update:values=\"$emit('update:values', $event)\"\n @update:collapsed=\"$emit('update:collapsed', $event)\"\n @update:toggle=\"(sectionId, value) => $emit('update:toggle', sectionId, value)\"\n @section-action=\"(sectionId, actionId) => $emit('section-action', sectionId, actionId)\"\n @form-submit=\"(sectionId, values) => $emit('form-submit', sectionId, values)\"\n @form-cancel=\"$emit('form-cancel', $event)\"\n >\n <template\n v-for=\"slotName in sidebar.slotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppSidebar section-* passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n </AppSidebar>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Standard plugin workspace shell that combines AppLayout, AppTopBar, and AppSidebar with LEAF-style defaults.\n *\n * The structure is one `:spec` built with `definePluginWorkspaceView()`: title,\n * top bar, sidebar (a `defineControlModel()` result generates its sections),\n * the experiment chip and its save action. The active pill, view, sidebar\n * values and collapse state are `v-model`s. It renders the toast container\n * unless `spec.toasts` is false.\n *\n * @example Recommended\n * ```vue\n * <PluginWorkspaceView :spec=\"workspace\" v-model:pill=\"tab\">\n * <router-view />\n * </PluginWorkspaceView>\n * ```\n */\nimport { computed, toValue, useSlots } from 'vue'\nimport type {\n PillNavItem,\n PillNavOption,\n} from '../types'\nimport type { JobState } from '../types/jobs'\nimport { useAppExperiment } from '../composables/useAppExperiment'\nimport { useJobCenter } from '../composables/useJobCenter'\nimport { usePluginWorkspace } from '../composables/usePluginWorkspace'\nimport AppToastContainer from './AppToastContainer.vue'\nimport JobsStatusTray from './JobsStatusTray.vue'\nimport WorkspaceControlsInternal from './internal/WorkspaceControlsInternal.vue'\nimport WorkspaceShellInternal from './internal/WorkspaceShellInternal.vue'\nimport WorkspaceSidebarInternal from './internal/WorkspaceSidebarInternal.vue'\nimport type {\n PluginWorkspaceForwardedSlotProps,\n PluginWorkspaceSlotProps,\n PluginWorkspaceViewEmits,\n PluginWorkspaceViewProps,\n} from './PluginWorkspaceView.props'\n\nconst props = withDefaults(defineProps<PluginWorkspaceViewProps>(), {\n spec: () => ({}),\n pill: undefined,\n view: undefined,\n values: undefined,\n sidebarCollapsed: undefined,\n formLoading: false,\n formDisabled: false,\n formReadonly: false,\n})\n\nconst emit = defineEmits<PluginWorkspaceViewEmits>()\n\ndefineSlots<{\n default?: (props: PluginWorkspaceSlotProps) => unknown\n topbar?: (props: PluginWorkspaceSlotProps) => unknown\n sidebar?: (props: PluginWorkspaceSlotProps) => unknown\n icon?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n logo?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n nav?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n center?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n actions?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n 'settings-appearance'?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n header?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n collapsed?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n 'collapsed-footer'?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n footer?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n}>()\n\nconst slots = useSlots()\n\n// The experiment chip is setup-time structure, like the rest of the spec.\nif (props.spec.experiment) {\n const save = props.spec.save\n useAppExperiment({\n onSelect: experiment => emit('experiment-select', experiment),\n onSave: save ? async () => (await save.handler()) ?? null : undefined,\n onDetach: () => emit('experiment-detach'),\n saveDisabled: computed(() => toValue(save?.disabled) ?? false),\n saveDisabledMessage: computed(() => toValue(save?.reason)),\n })\n}\n\n// The job center is setup-time structure too: no `jobs`, no jobs control.\nconst jobs = props.spec.jobs\nconst jobCenter = jobs ? useJobCenter({ source: jobs }) : null\n\nfunction handleJobSelect(job: JobState) {\n emit('job-select', job)\n}\n\nconst {\n shell,\n sidebar,\n controls,\n handleControlValuesUpdate,\n handlePillSelect,\n} = usePluginWorkspace({\n props,\n slots,\n emit,\n})\n\nfunction handleToggle(sectionId: string, value: boolean) {\n emit('update:toggle', sectionId, value)\n}\n\nfunction handleFormSubmit(sectionId: string, values: Record<string, unknown>) {\n emit('form-submit', sectionId, values)\n}\n\nfunction handleFormCancel(sectionId: string) {\n emit('form-cancel', sectionId)\n}\n\n</script>\n\n<template>\n <WorkspaceShellInternal\n :shell=\"shell\"\n :job=\"jobCenter ? jobCenter.topBarJob.value : undefined\"\n :jobs-done=\"jobCenter?.completedCount.value\"\n :jobs-open=\"jobCenter?.isOpen.value\"\n :jobs-panel-id=\"jobCenter?.panelId\"\n @job-click=\"jobCenter?.handleTopBarClick(handleJobSelect)\"\n @pill-select=\"handlePillSelect\"\n @pill-option-select=\"(option: PillNavOption, item: PillNavItem) => emit('pill-option-select', option, item)\"\n @settings-values-change=\"emit('settings-values-change', $event)\"\n >\n <template v-if=\"slots.topbar\" #topbar=\"scope\">\n <slot name=\"topbar\" v-bind=\"scope\" />\n </template>\n\n <template\n v-for=\"slotName in shell.topBarSlotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppTopBar passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n\n <template v-if=\"shell.hasSidebarSurface\" #sidebar=\"scope\">\n <slot name=\"sidebar\" v-bind=\"scope\">\n <WorkspaceSidebarInternal\n :sidebar=\"sidebar\"\n @update:values=\"handleControlValuesUpdate\"\n @update:collapsed=\"emit('update:sidebarCollapsed', $event)\"\n @update:toggle=\"handleToggle\"\n @section-action=\"(sectionId: string, actionId: string) => emit('section-action', sectionId, actionId)\"\n @form-submit=\"handleFormSubmit\"\n @form-cancel=\"handleFormCancel\"\n >\n <template\n v-for=\"slotName in sidebar.slotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppSidebar section-* passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n </WorkspaceSidebarInternal>\n </slot>\n </template>\n\n <template #default>\n <WorkspaceControlsInternal :controls=\"controls\">\n <template #default=\"controlsScope\">\n <slot v-bind=\"controlsScope\" />\n </template>\n </WorkspaceControlsInternal>\n <AppToastContainer v-if=\"spec.toasts !== false\" />\n <JobsStatusTray v-if=\"jobCenter\" :center=\"jobCenter\" @select=\"handleJobSelect\" />\n </template>\n </WorkspaceShellInternal>\n</template>\n","<script setup lang=\"ts\">\n/**\n * Standard plugin workspace shell that combines AppLayout, AppTopBar, and AppSidebar with LEAF-style defaults.\n *\n * The structure is one `:spec` built with `definePluginWorkspaceView()`: title,\n * top bar, sidebar (a `defineControlModel()` result generates its sections),\n * the experiment chip and its save action. The active pill, view, sidebar\n * values and collapse state are `v-model`s. It renders the toast container\n * unless `spec.toasts` is false.\n *\n * @example Recommended\n * ```vue\n * <PluginWorkspaceView :spec=\"workspace\" v-model:pill=\"tab\">\n * <router-view />\n * </PluginWorkspaceView>\n * ```\n */\nimport { computed, toValue, useSlots } from 'vue'\nimport type {\n PillNavItem,\n PillNavOption,\n} from '../types'\nimport type { JobState } from '../types/jobs'\nimport { useAppExperiment } from '../composables/useAppExperiment'\nimport { useJobCenter } from '../composables/useJobCenter'\nimport { usePluginWorkspace } from '../composables/usePluginWorkspace'\nimport AppToastContainer from './AppToastContainer.vue'\nimport JobsStatusTray from './JobsStatusTray.vue'\nimport WorkspaceControlsInternal from './internal/WorkspaceControlsInternal.vue'\nimport WorkspaceShellInternal from './internal/WorkspaceShellInternal.vue'\nimport WorkspaceSidebarInternal from './internal/WorkspaceSidebarInternal.vue'\nimport type {\n PluginWorkspaceForwardedSlotProps,\n PluginWorkspaceSlotProps,\n PluginWorkspaceViewEmits,\n PluginWorkspaceViewProps,\n} from './PluginWorkspaceView.props'\n\nconst props = withDefaults(defineProps<PluginWorkspaceViewProps>(), {\n spec: () => ({}),\n pill: undefined,\n view: undefined,\n values: undefined,\n sidebarCollapsed: undefined,\n formLoading: false,\n formDisabled: false,\n formReadonly: false,\n})\n\nconst emit = defineEmits<PluginWorkspaceViewEmits>()\n\ndefineSlots<{\n default?: (props: PluginWorkspaceSlotProps) => unknown\n topbar?: (props: PluginWorkspaceSlotProps) => unknown\n sidebar?: (props: PluginWorkspaceSlotProps) => unknown\n icon?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n logo?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n nav?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n center?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n actions?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n 'settings-appearance'?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n header?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n collapsed?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n 'collapsed-footer'?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n footer?: (props: PluginWorkspaceForwardedSlotProps) => unknown\n}>()\n\nconst slots = useSlots()\n\n// The experiment chip is setup-time structure, like the rest of the spec.\nif (props.spec.experiment) {\n const save = props.spec.save\n useAppExperiment({\n onSelect: experiment => emit('experiment-select', experiment),\n onSave: save ? async () => (await save.handler()) ?? null : undefined,\n onDetach: () => emit('experiment-detach'),\n saveDisabled: computed(() => toValue(save?.disabled) ?? false),\n saveDisabledMessage: computed(() => toValue(save?.reason)),\n })\n}\n\n// The job center is setup-time structure too: no `jobs`, no jobs control.\nconst jobs = props.spec.jobs\nconst jobCenter = jobs ? useJobCenter({ source: jobs }) : null\n\nfunction handleJobSelect(job: JobState) {\n emit('job-select', job)\n}\n\nconst {\n shell,\n sidebar,\n controls,\n handleControlValuesUpdate,\n handlePillSelect,\n} = usePluginWorkspace({\n props,\n slots,\n emit,\n})\n\nfunction handleToggle(sectionId: string, value: boolean) {\n emit('update:toggle', sectionId, value)\n}\n\nfunction handleFormSubmit(sectionId: string, values: Record<string, unknown>) {\n emit('form-submit', sectionId, values)\n}\n\nfunction handleFormCancel(sectionId: string) {\n emit('form-cancel', sectionId)\n}\n\n</script>\n\n<template>\n <WorkspaceShellInternal\n :shell=\"shell\"\n :job=\"jobCenter ? jobCenter.topBarJob.value : undefined\"\n :jobs-done=\"jobCenter?.completedCount.value\"\n :jobs-open=\"jobCenter?.isOpen.value\"\n :jobs-panel-id=\"jobCenter?.panelId\"\n @job-click=\"jobCenter?.handleTopBarClick(handleJobSelect)\"\n @pill-select=\"handlePillSelect\"\n @pill-option-select=\"(option: PillNavOption, item: PillNavItem) => emit('pill-option-select', option, item)\"\n @settings-values-change=\"emit('settings-values-change', $event)\"\n >\n <template v-if=\"slots.topbar\" #topbar=\"scope\">\n <slot name=\"topbar\" v-bind=\"scope\" />\n </template>\n\n <template\n v-for=\"slotName in shell.topBarSlotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppTopBar passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n\n <template v-if=\"shell.hasSidebarSurface\" #sidebar=\"scope\">\n <slot name=\"sidebar\" v-bind=\"scope\">\n <WorkspaceSidebarInternal\n :sidebar=\"sidebar\"\n @update:values=\"handleControlValuesUpdate\"\n @update:collapsed=\"emit('update:sidebarCollapsed', $event)\"\n @update:toggle=\"handleToggle\"\n @section-action=\"(sectionId: string, actionId: string) => emit('section-action', sectionId, actionId)\"\n @form-submit=\"handleFormSubmit\"\n @form-cancel=\"handleFormCancel\"\n >\n <template\n v-for=\"slotName in sidebar.slotNames\"\n :key=\"slotName\"\n #[slotName]=\"slotProps\"\n >\n <!-- @vue-ignore dynamic SDK slot forwarding for AppSidebar section-* passthrough slots -->\n <slot\n :name=\"slotName\"\n v-bind=\"slotProps ?? {}\"\n />\n </template>\n </WorkspaceSidebarInternal>\n </slot>\n </template>\n\n <template #default>\n <WorkspaceControlsInternal :controls=\"controls\">\n <template #default=\"controlsScope\">\n <slot v-bind=\"controlsScope\" />\n </template>\n </WorkspaceControlsInternal>\n <AppToastContainer v-if=\"spec.toasts !== false\" />\n <JobsStatusTray v-if=\"jobCenter\" :center=\"jobCenter\" @select=\"handleJobSelect\" />\n </template>\n </WorkspaceShellInternal>\n</template>\n","<script setup lang=\"ts\">\n/** Displays a user avatar as an image, a single derived initial, or a fallback icon, on a quiet accent face (or an explicit `color`) with an optional status dot. */\nimport { computed } from 'vue'\n\ninterface Props {\n name?: string\n initials?: string\n src?: string\n alt?: string\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n color?: string\n status?: 'online' | 'away' | 'busy' | 'offline'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n alt: '',\n size: 'md',\n})\n\n// Default: first letter of `name`, uppercased. Consumers wanting two letters\n// (e.g. role badges like \"PI\", \"QC\") pass `:initials=\"'XX'\"` explicitly.\nconst computedInitials = computed(() =>\n props.initials || props.name?.charAt(0).toUpperCase() || ''\n)\n\n// The quiet accent face lives in avatar.css; an explicit `color` fills the\n// face. That fill is a fixed hue (role badges), so the ink stays white in both\n// themes instead of following the theme-dependent --text-on-accent.\nconst faceStyle = computed(() =>\n props.color\n ? { backgroundColor: props.color, color: '#fff', boxShadow: 'none' }\n : undefined\n)\n</script>\n\n<template>\n <span\n :class=\"['mint-avatar', `mint-avatar--${size}`]\"\n role=\"img\"\n :aria-label=\"alt || name || 'User avatar'\"\n >\n <span\n class=\"mint-avatar__face\"\n :style=\"faceStyle\"\n >\n <img\n v-if=\"src\"\n :src=\"src\"\n :alt=\"alt || name || ''\"\n class=\"mint-avatar__image\"\n >\n <span v-else-if=\"computedInitials\" class=\"mint-avatar__initials\">\n {{ computedInitials }}\n </span>\n <svg\n v-else\n class=\"mint-avatar__fallback\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z\" />\n </svg>\n </span>\n <span\n v-if=\"status\"\n :class=\"['mint-avatar__status', `mint-avatar__status--${status}`]\"\n aria-hidden=\"true\"\n />\n </span>\n</template>\n","<script setup lang=\"ts\">\n/** Displays a user avatar as an image, a single derived initial, or a fallback icon, on a quiet accent face (or an explicit `color`) with an optional status dot. */\nimport { computed } from 'vue'\n\ninterface Props {\n name?: string\n initials?: string\n src?: string\n alt?: string\n size?: 'xs' | 'sm' | 'md' | 'lg' | 'xl'\n color?: string\n status?: 'online' | 'away' | 'busy' | 'offline'\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n alt: '',\n size: 'md',\n})\n\n// Default: first letter of `name`, uppercased. Consumers wanting two letters\n// (e.g. role badges like \"PI\", \"QC\") pass `:initials=\"'XX'\"` explicitly.\nconst computedInitials = computed(() =>\n props.initials || props.name?.charAt(0).toUpperCase() || ''\n)\n\n// The quiet accent face lives in avatar.css; an explicit `color` fills the\n// face. That fill is a fixed hue (role badges), so the ink stays white in both\n// themes instead of following the theme-dependent --text-on-accent.\nconst faceStyle = computed(() =>\n props.color\n ? { backgroundColor: props.color, color: '#fff', boxShadow: 'none' }\n : undefined\n)\n</script>\n\n<template>\n <span\n :class=\"['mint-avatar', `mint-avatar--${size}`]\"\n role=\"img\"\n :aria-label=\"alt || name || 'User avatar'\"\n >\n <span\n class=\"mint-avatar__face\"\n :style=\"faceStyle\"\n >\n <img\n v-if=\"src\"\n :src=\"src\"\n :alt=\"alt || name || ''\"\n class=\"mint-avatar__image\"\n >\n <span v-else-if=\"computedInitials\" class=\"mint-avatar__initials\">\n {{ computedInitials }}\n </span>\n <svg\n v-else\n class=\"mint-avatar__fallback\"\n viewBox=\"0 0 24 24\"\n fill=\"currentColor\"\n >\n <path d=\"M12 12c2.21 0 4-1.79 4-4s-1.79-4-4-4-4 1.79-4 4 1.79 4 4 4zm0 2c-2.67 0-8 1.34-8 4v2h16v-2c0-2.66-5.33-4-8-4z\" />\n </svg>\n </span>\n <span\n v-if=\"status\"\n :class=\"['mint-avatar__status', `mint-avatar__status--${status}`]\"\n aria-hidden=\"true\"\n />\n </span>\n</template>\n","import type {\n FormFieldSchema,\n FormFieldType,\n FormSchema,\n} from '../types/form-builder'\nimport type {\n GeneratedJsonSchema,\n GeneratedJobDefinition,\n} from '../types/generated-ui'\n\ntype GeneratedReference = 'path'\n\ninterface ResolvedGeneratedField {\n schema: GeneratedJsonSchema\n reference?: GeneratedReference\n hasDefault: boolean\n defaultValue?: unknown\n}\n\nexport function generatedJobFormSchema(definition: GeneratedJobDefinition): FormSchema & { sections: NonNullable<FormSchema['sections']> } {\n const root = definition.input_schema\n const required = new Set(root.required ?? [])\n const fields = Object.entries(root.properties ?? {}).map(([name, schema]) =>\n toFormField(name, resolveGeneratedField(root, schema), required.has(name)),\n )\n return {\n sections: [{\n id: definition.id,\n title: definition.title,\n description: definition.description || undefined,\n columns: 1,\n fields,\n }],\n actions: true,\n submitLabel: 'Run analysis',\n }\n}\n\nexport function generatedJobDefaults(definition: GeneratedJobDefinition): Record<string, unknown> {\n return Object.fromEntries(\n Object.entries(definition.input_schema.properties ?? {})\n .map(([name, schema]) => [name, resolveGeneratedField(definition.input_schema, schema)] as const)\n .filter(([, field]) => field.hasDefault)\n .map(([name, field]) => [name, structuredClone(field.defaultValue)]),\n )\n}\n\nexport function normalizeGeneratedJobInput(\n definition: GeneratedJobDefinition,\n values: Record<string, unknown>,\n): Record<string, unknown> {\n const normalized: Record<string, unknown> = {}\n for (const [name, value] of Object.entries(values)) {\n const field = definition.input_schema.properties?.[name]\n if (!field) continue\n const { schema, reference } = resolveGeneratedField(definition.input_schema, field)\n if (reference !== 'path' && Array.isArray(value) && ['integer', 'number'].includes(String(schema.items?.type))) {\n normalized[name] = value.map(item => {\n const numeric = typeof item === 'string' && item.trim() !== '' ? Number(item) : item\n return typeof numeric === 'number' && Number.isFinite(numeric) ? numeric : item\n })\n } else if (reference !== 'path' && Array.isArray(value) && schema.items?.type === 'boolean') {\n normalized[name] = value.map(item => item === 'true' ? true : item === 'false' ? false : item)\n } else {\n normalized[name] = value === undefined && allowsNull(schema) ? null : value\n }\n }\n return normalized\n}\n\nfunction toFormField(\n name: string,\n resolved: ResolvedGeneratedField,\n required: boolean,\n): FormFieldSchema {\n const { schema, reference } = resolved\n const validation: NonNullable<FormFieldSchema['validation']> = {}\n const allowsEmpty = schema.type === 'array' || (\n schema.type === 'string' && reference !== 'path'\n && !(schema.minLength && schema.minLength > 0)\n && (!schema.enum || schema.enum.includes(''))\n )\n if (required && !allowsNull(schema) && !allowsEmpty) validation.required = true\n if (schema.minimum !== undefined) validation.min = schema.minimum\n if (schema.maximum !== undefined) validation.max = schema.maximum\n if (schema.minLength !== undefined) validation.minLength = schema.minLength\n if (schema.maxLength !== undefined) validation.maxLength = schema.maxLength\n\n const props: Record<string, unknown> = {}\n if (schema.enum) props.options = [...schema.enum]\n if (schema.type === 'integer') {\n if (schema.exclusiveMinimum !== undefined) validation.min = Math.max(Number(validation.min ?? -Infinity), Math.floor(schema.exclusiveMinimum) + 1)\n if (schema.exclusiveMaximum !== undefined) validation.max = Math.min(Number(validation.max ?? Infinity), Math.ceil(schema.exclusiveMaximum) - 1)\n if (validation.min !== undefined) validation.min = Math.ceil(Number(validation.min))\n if (validation.max !== undefined) validation.max = Math.floor(Number(validation.max))\n if (schema.multipleOf && Number.isInteger(schema.multipleOf)) {\n if (validation.min !== undefined) validation.min = Math.ceil(Number(validation.min) / schema.multipleOf) * schema.multipleOf\n if (validation.max !== undefined) validation.max = Math.floor(Number(validation.max) / schema.multipleOf) * schema.multipleOf\n }\n props.step = 1\n }\n if (schema.type === 'integer' || schema.type === 'number') {\n if (validation.min !== undefined) props.min = validation.min\n if (validation.max !== undefined) props.max = validation.max\n if (schema.multipleOf !== undefined) props.step = schema.multipleOf\n }\n if (schema.type === 'array' && reference !== 'path') {\n if (schema.items?.enum) props.options = [...schema.items.enum]\n else props.allowDuplicates = true\n }\n if (reference === 'path' && schema.type === 'array') props.multiple = true\n return {\n name,\n label: schema.title || humanize(name),\n type: fieldType(schema, reference),\n defaultValue: resolved.hasDefault ? structuredClone(resolved.defaultValue) : undefined,\n disabled: Object.prototype.hasOwnProperty.call(schema, 'const') || undefined,\n hint: schema.description,\n validation,\n props,\n itemType: schema.items?.type === 'number' || schema.items?.type === 'integer' ? 'number' : undefined,\n }\n}\n\nfunction resolveGeneratedField(\n root: GeneratedJsonSchema,\n field: GeneratedJsonSchema,\n): ResolvedGeneratedField {\n const candidate = field.anyOf?.find(item => item.type !== 'null')\n ?? field.allOf?.[0]\n ?? field\n let schema = { ...candidate, ...field }\n if (candidate.$ref) {\n const referenceParts = candidate.$ref.split('/')\n const key = referenceParts[referenceParts.length - 1]\n const referenced = key ? root.$defs?.[key] : undefined\n if (!referenced) throw new Error(`Generated field reference is missing: ${candidate.$ref}`)\n schema = { ...referenced, ...candidate, ...field }\n }\n if (schema.items) schema.items = resolveGeneratedField(root, schema.items).schema\n const constant = Object.prototype.hasOwnProperty.call(schema, 'const')\n return {\n schema,\n reference: schema['x-mint-component'],\n hasDefault: constant || hasOwnDefault(field) || allowsNull(schema),\n defaultValue: constant ? schema.const : hasOwnDefault(field) ? field.default : null,\n }\n}\n\nfunction fieldType(schema: GeneratedJsonSchema, reference?: GeneratedReference): FormFieldType {\n if (reference === 'path') return 'path'\n if (schema.enum) return 'select'\n const type = Array.isArray(schema.type) ? schema.type.find(value => value !== 'null') : schema.type\n if (type === 'boolean') return 'toggle'\n if (type === 'number' || type === 'integer') return 'number'\n if (type === 'array') return schema.items?.enum ? 'multiselect' : 'tags'\n return 'text'\n}\n\nfunction hasOwnDefault(schema: GeneratedJsonSchema): boolean {\n return Object.prototype.hasOwnProperty.call(schema, 'default')\n}\n\nfunction allowsNull(schema: GeneratedJsonSchema): boolean {\n return schema.type === 'null' || (Array.isArray(schema.type) && schema.type.includes('null'))\n || !!schema.anyOf?.some(item => item.type === 'null')\n}\n\nfunction humanize(value: string): string {\n return value.replace(/[_-]+/g, ' ').replace(/^\\w/, character => character.toUpperCase())\n}\n","<script setup lang=\"ts\">\n/**\n * Standard generated workspace for a plugin that exposes an SDK job manifest.\n *\n * @example Recommended\n * ```vue\n * <GeneratedPluginView base-url=\"/api/peak-qc\" />\n * ```\n */\nimport { computed, onMounted, provide, reactive, ref, watch } from 'vue'\n\nimport { generatedJobDefaults, generatedJobFormSchema, normalizeGeneratedJobInput } from '../generated/schema'\nimport type { FormSchema } from '../types/form-builder'\nimport type {\n GeneratedAnalysisResult,\n GeneratedJobDefinition,\n} from '../types/generated-ui'\nimport type { PillNavItem, SidebarToolSection } from '../types'\nimport type { JobState } from '../types/jobs'\nimport {\n useJobsEndpoint,\n type GeneratedAnalysisTransport,\n} from '../composables/useJobsEndpoint'\nimport AlertBox from './AlertBox.vue'\nimport EmptyState from './EmptyState.vue'\nimport GeneratedResultRenderer from './GeneratedResultRenderer.vue'\nimport LoadingSpinner from './LoadingSpinner.vue'\nimport PluginWorkspaceView from './PluginWorkspaceView.vue'\nimport { GENERATED_JOBS_API_KEY } from './internal/generatedJobsApi'\nimport { definePluginWorkspaceView } from '../composables/componentSpecs'\nimport { providePluginIdentity } from '../composables/pluginIdentity'\n\ninterface Props {\n baseUrl: string\n showStandaloneLabel?: boolean\n transport?: GeneratedAnalysisTransport\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showStandaloneLabel: false,\n})\n\nconst generated = useJobsEndpoint({\n baseUrl: props.baseUrl,\n transport: props.transport,\n manifest: true,\n})\nprovide(GENERATED_JOBS_API_KEY, { baseUrl: props.baseUrl, transport: props.transport })\nconst activeDefinitionId = ref('')\nconst selectedJobId = ref('')\nconst valuesByDefinition = reactive<Record<string, Record<string, unknown>>>({})\nconst definitions = computed(() => generated.manifest.value?.jobs ?? [])\nconst activeDefinition = computed(() => (\n definitions.value.find(definition => definition.id === activeDefinitionId.value) ?? null\n))\n\nconst pillNav = computed<PillNavItem[]>(() => definitions.value.map(definition => ({\n id: definition.id,\n label: definition.title,\n})))\n\nconst panels = computed<Record<string, SidebarToolSection[]>>(() => Object.fromEntries(\n definitions.value.map(definition => [definition.id, [{\n id: definition.id,\n label: 'Parameters',\n subtitle: resourceSummary(definition),\n defaultOpen: true,\n }]]),\n))\n\nconst forms = computed<Record<string, FormSchema>>(() => Object.fromEntries(\n definitions.value.map(definition => [definition.id, generatedJobFormSchema(definition)]),\n))\n\nconst workspace = computed(() => definePluginWorkspaceView({\n title: generated.manifest.value?.ui.title ?? 'Analysis',\n subtitle: generated.manifest.value?.ui.subtitle || generated.manifest.value?.ui.description,\n // The platform shell renders the toasts around this view.\n toasts: false,\n topBar: {\n pills: pillNav.value,\n settings: false,\n standaloneLabel: props.showStandaloneLabel ? 'Standalone' : false,\n },\n sidebar: { title: 'Parameters', panels: panels.value, forms: forms.value },\n jobs: generated,\n}))\n\n// Seeds the standalone top bar icon; the title and subtitle above win over the seeded text.\nwatch(() => generated.manifest.value?.ui, (ui) => {\n if (ui) providePluginIdentity({ plugin: { name: ui.title, subtitle: ui.subtitle, description: ui.description, icon: ui.icon } })\n}, { immediate: true })\n\nconst currentValues = computed(() => valuesByDefinition[activeDefinitionId.value] ?? {})\nconst currentJob = computed(() => {\n const currentSessionId = generated.session.value?.id\n const currentDefinitionId = activeDefinitionId.value\n const selected = generated.jobs.value.find(candidate => (\n candidate.job_id === selectedJobId.value\n && candidate.status === 'completed'\n && candidate.metadata.definition_id === currentDefinitionId\n && candidate.metadata.has_result === true\n ))\n return selected ?? generated.jobs.value.find(candidate => (\n candidate.session_id === currentSessionId\n && candidate.status === 'completed'\n && candidate.metadata.definition_id === currentDefinitionId\n && candidate.metadata.has_result === true\n ))\n})\nconst currentResult = computed<GeneratedAnalysisResult | null>(() => (\n currentJob.value ? generated.resultForJob(currentJob.value.job_id) : null\n))\n\nwatch(definitions, (nextDefinitions) => {\n for (const definition of nextDefinitions) {\n valuesByDefinition[definition.id] ??= generatedJobDefaults(definition)\n }\n if (!nextDefinitions.some(definition => definition.id === activeDefinitionId.value)) {\n activeDefinitionId.value = nextDefinitions[0]?.id ?? ''\n }\n}, { immediate: true })\n\nwatch(currentJob, (job) => {\n if (job) void generated.result(job)\n}, { immediate: true })\n\nfunction updateValues(values: Record<string, unknown>): void {\n if (activeDefinitionId.value) valuesByDefinition[activeDefinitionId.value] = { ...values }\n}\n\nasync function submitJob(sectionId: string, values: Record<string, unknown>): Promise<void> {\n const definition = definitions.value.find(candidate => candidate.id === sectionId)\n if (!definition) return\n selectedJobId.value = ''\n valuesByDefinition[definition.id] = { ...values }\n await generated.submit(definition.id, normalizeGeneratedJobInput(definition, values))\n}\n\nfunction selectJob(job: JobState): void {\n selectedJobId.value = job.job_id\n activeDefinitionId.value = String(job.metadata.definition_id ?? activeDefinitionId.value)\n}\n\nfunction resourceSummary(definition: GeneratedJobDefinition): string {\n if (definition.lifecycle === 'service' || definition.profile?.kind === 'service') {\n return 'Host service'\n }\n if (definition.lifecycle === 'staged' || definition.profile?.kind === 'staged') {\n return 'Staged upload'\n }\n return `Up to ${definition.cpu} CPU`\n}\n\nonMounted(() => {\n void generated.refresh().catch(() => undefined)\n})\n</script>\n\n<template>\n <PluginWorkspaceView\n v-model:view=\"activeDefinitionId\"\n :spec=\"workspace\"\n :values=\"currentValues\"\n :form-loading=\"generated.isSubmitting.value\"\n :form-disabled=\"generated.isSubmitting.value\"\n @update:values=\"updateValues\"\n @form-submit=\"submitJob\"\n @job-select=\"selectJob\"\n >\n <main class=\"mint-generated-workspace\">\n <div v-if=\"generated.isLoading.value\" class=\"mint-generated-workspace__loading\">\n <LoadingSpinner size=\"lg\" />\n <span>Loading analysis workspace</span>\n </div>\n\n <template v-else>\n <AlertBox v-if=\"generated.error.value\" tone=\"error\">{{ generated.error.value }}</AlertBox>\n\n <header v-if=\"activeDefinition\" class=\"mint-generated-workspace__header\">\n <div>\n <p class=\"mint-generated-workspace__eyebrow\">Analysis result</p>\n <h1>{{ activeDefinition.title }}</h1>\n <p v-if=\"activeDefinition.description\">{{ activeDefinition.description }}</p>\n </div>\n <div class=\"mint-generated-workspace__resources\" aria-label=\"Job resource requirements\">\n <span>{{ resourceSummary(activeDefinition) }}</span>\n </div>\n </header>\n\n <section class=\"mint-generated-workspace__result\">\n <GeneratedResultRenderer\n v-if=\"currentResult\"\n :result=\"currentResult\"\n />\n <EmptyState\n v-else\n title=\"No result yet\"\n description=\"Set the parameters and run the analysis. Jobs continue independently if you switch tabs.\"\n size=\"md\"\n />\n </section>\n </template>\n </main>\n </PluginWorkspaceView>\n</template>\n\n<style scoped>\n.mint-generated-workspace {\n position: relative;\n min-width: 0;\n min-height: calc(100vh - 5rem);\n padding: clamp(1rem, 2.5vw, 2.5rem);\n background: var(--bg-primary);\n}\n\n.mint-generated-workspace__loading {\n display: flex;\n min-height: 24rem;\n align-items: center;\n justify-content: center;\n gap: 0.75rem;\n color: var(--text-secondary);\n}\n\n.mint-generated-workspace__header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 1.5rem;\n max-width: 76rem;\n margin: 0 auto 1.25rem;\n}\n\n.mint-generated-workspace__header h1 {\n margin: 0;\n color: var(--text-primary);\n font-size: clamp(1.35rem, 2vw, 1.8rem);\n line-height: 1.2;\n}\n\n.mint-generated-workspace__header p:not(.mint-generated-workspace__eyebrow) {\n margin: 0.4rem 0 0;\n color: var(--text-secondary);\n}\n\n.mint-generated-workspace__eyebrow {\n margin: 0 0 0.35rem;\n color: var(--text-secondary);\n font-size: 0.72rem;\n font-weight: 700;\n}\n\n.mint-generated-workspace__resources {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: 0.4rem;\n}\n\n.mint-generated-workspace__resources span {\n padding: 0.3rem 0.55rem;\n border: 1px solid var(--border-color);\n border-radius: 999px;\n background: var(--bg-secondary);\n color: var(--text-secondary);\n font-size: 0.75rem;\n font-weight: 600;\n}\n\n.mint-generated-workspace__result {\n max-width: 76rem;\n min-height: 24rem;\n margin: 0 auto;\n padding: clamp(1rem, 2vw, 1.75rem);\n border: 1px solid var(--border-color);\n border-radius: 1rem;\n background: var(--bg-secondary);\n box-shadow: var(--shadow-sm);\n}\n\n@media (max-width: 640px) {\n .mint-generated-workspace__header {\n flex-direction: column;\n }\n\n .mint-generated-workspace__resources {\n justify-content: flex-start;\n }\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * Standard generated workspace for a plugin that exposes an SDK job manifest.\n *\n * @example Recommended\n * ```vue\n * <GeneratedPluginView base-url=\"/api/peak-qc\" />\n * ```\n */\nimport { computed, onMounted, provide, reactive, ref, watch } from 'vue'\n\nimport { generatedJobDefaults, generatedJobFormSchema, normalizeGeneratedJobInput } from '../generated/schema'\nimport type { FormSchema } from '../types/form-builder'\nimport type {\n GeneratedAnalysisResult,\n GeneratedJobDefinition,\n} from '../types/generated-ui'\nimport type { PillNavItem, SidebarToolSection } from '../types'\nimport type { JobState } from '../types/jobs'\nimport {\n useJobsEndpoint,\n type GeneratedAnalysisTransport,\n} from '../composables/useJobsEndpoint'\nimport AlertBox from './AlertBox.vue'\nimport EmptyState from './EmptyState.vue'\nimport GeneratedResultRenderer from './GeneratedResultRenderer.vue'\nimport LoadingSpinner from './LoadingSpinner.vue'\nimport PluginWorkspaceView from './PluginWorkspaceView.vue'\nimport { GENERATED_JOBS_API_KEY } from './internal/generatedJobsApi'\nimport { definePluginWorkspaceView } from '../composables/componentSpecs'\nimport { providePluginIdentity } from '../composables/pluginIdentity'\n\ninterface Props {\n baseUrl: string\n showStandaloneLabel?: boolean\n transport?: GeneratedAnalysisTransport\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n showStandaloneLabel: false,\n})\n\nconst generated = useJobsEndpoint({\n baseUrl: props.baseUrl,\n transport: props.transport,\n manifest: true,\n})\nprovide(GENERATED_JOBS_API_KEY, { baseUrl: props.baseUrl, transport: props.transport })\nconst activeDefinitionId = ref('')\nconst selectedJobId = ref('')\nconst valuesByDefinition = reactive<Record<string, Record<string, unknown>>>({})\nconst definitions = computed(() => generated.manifest.value?.jobs ?? [])\nconst activeDefinition = computed(() => (\n definitions.value.find(definition => definition.id === activeDefinitionId.value) ?? null\n))\n\nconst pillNav = computed<PillNavItem[]>(() => definitions.value.map(definition => ({\n id: definition.id,\n label: definition.title,\n})))\n\nconst panels = computed<Record<string, SidebarToolSection[]>>(() => Object.fromEntries(\n definitions.value.map(definition => [definition.id, [{\n id: definition.id,\n label: 'Parameters',\n subtitle: resourceSummary(definition),\n defaultOpen: true,\n }]]),\n))\n\nconst forms = computed<Record<string, FormSchema>>(() => Object.fromEntries(\n definitions.value.map(definition => [definition.id, generatedJobFormSchema(definition)]),\n))\n\nconst workspace = computed(() => definePluginWorkspaceView({\n title: generated.manifest.value?.ui.title ?? 'Analysis',\n subtitle: generated.manifest.value?.ui.subtitle || generated.manifest.value?.ui.description,\n // The platform shell renders the toasts around this view.\n toasts: false,\n topBar: {\n pills: pillNav.value,\n settings: false,\n standaloneLabel: props.showStandaloneLabel ? 'Standalone' : false,\n },\n sidebar: { title: 'Parameters', panels: panels.value, forms: forms.value },\n jobs: generated,\n}))\n\n// Seeds the standalone top bar icon; the title and subtitle above win over the seeded text.\nwatch(() => generated.manifest.value?.ui, (ui) => {\n if (ui) providePluginIdentity({ plugin: { name: ui.title, subtitle: ui.subtitle, description: ui.description, icon: ui.icon } })\n}, { immediate: true })\n\nconst currentValues = computed(() => valuesByDefinition[activeDefinitionId.value] ?? {})\nconst currentJob = computed(() => {\n const currentSessionId = generated.session.value?.id\n const currentDefinitionId = activeDefinitionId.value\n const selected = generated.jobs.value.find(candidate => (\n candidate.job_id === selectedJobId.value\n && candidate.status === 'completed'\n && candidate.metadata.definition_id === currentDefinitionId\n && candidate.metadata.has_result === true\n ))\n return selected ?? generated.jobs.value.find(candidate => (\n candidate.session_id === currentSessionId\n && candidate.status === 'completed'\n && candidate.metadata.definition_id === currentDefinitionId\n && candidate.metadata.has_result === true\n ))\n})\nconst currentResult = computed<GeneratedAnalysisResult | null>(() => (\n currentJob.value ? generated.resultForJob(currentJob.value.job_id) : null\n))\n\nwatch(definitions, (nextDefinitions) => {\n for (const definition of nextDefinitions) {\n valuesByDefinition[definition.id] ??= generatedJobDefaults(definition)\n }\n if (!nextDefinitions.some(definition => definition.id === activeDefinitionId.value)) {\n activeDefinitionId.value = nextDefinitions[0]?.id ?? ''\n }\n}, { immediate: true })\n\nwatch(currentJob, (job) => {\n if (job) void generated.result(job)\n}, { immediate: true })\n\nfunction updateValues(values: Record<string, unknown>): void {\n if (activeDefinitionId.value) valuesByDefinition[activeDefinitionId.value] = { ...values }\n}\n\nasync function submitJob(sectionId: string, values: Record<string, unknown>): Promise<void> {\n const definition = definitions.value.find(candidate => candidate.id === sectionId)\n if (!definition) return\n selectedJobId.value = ''\n valuesByDefinition[definition.id] = { ...values }\n await generated.submit(definition.id, normalizeGeneratedJobInput(definition, values))\n}\n\nfunction selectJob(job: JobState): void {\n selectedJobId.value = job.job_id\n activeDefinitionId.value = String(job.metadata.definition_id ?? activeDefinitionId.value)\n}\n\nfunction resourceSummary(definition: GeneratedJobDefinition): string {\n if (definition.lifecycle === 'service' || definition.profile?.kind === 'service') {\n return 'Host service'\n }\n if (definition.lifecycle === 'staged' || definition.profile?.kind === 'staged') {\n return 'Staged upload'\n }\n return `Up to ${definition.cpu} CPU`\n}\n\nonMounted(() => {\n void generated.refresh().catch(() => undefined)\n})\n</script>\n\n<template>\n <PluginWorkspaceView\n v-model:view=\"activeDefinitionId\"\n :spec=\"workspace\"\n :values=\"currentValues\"\n :form-loading=\"generated.isSubmitting.value\"\n :form-disabled=\"generated.isSubmitting.value\"\n @update:values=\"updateValues\"\n @form-submit=\"submitJob\"\n @job-select=\"selectJob\"\n >\n <main class=\"mint-generated-workspace\">\n <div v-if=\"generated.isLoading.value\" class=\"mint-generated-workspace__loading\">\n <LoadingSpinner size=\"lg\" />\n <span>Loading analysis workspace</span>\n </div>\n\n <template v-else>\n <AlertBox v-if=\"generated.error.value\" tone=\"error\">{{ generated.error.value }}</AlertBox>\n\n <header v-if=\"activeDefinition\" class=\"mint-generated-workspace__header\">\n <div>\n <p class=\"mint-generated-workspace__eyebrow\">Analysis result</p>\n <h1>{{ activeDefinition.title }}</h1>\n <p v-if=\"activeDefinition.description\">{{ activeDefinition.description }}</p>\n </div>\n <div class=\"mint-generated-workspace__resources\" aria-label=\"Job resource requirements\">\n <span>{{ resourceSummary(activeDefinition) }}</span>\n </div>\n </header>\n\n <section class=\"mint-generated-workspace__result\">\n <GeneratedResultRenderer\n v-if=\"currentResult\"\n :result=\"currentResult\"\n />\n <EmptyState\n v-else\n title=\"No result yet\"\n description=\"Set the parameters and run the analysis. Jobs continue independently if you switch tabs.\"\n size=\"md\"\n />\n </section>\n </template>\n </main>\n </PluginWorkspaceView>\n</template>\n\n<style scoped>\n.mint-generated-workspace {\n position: relative;\n min-width: 0;\n min-height: calc(100vh - 5rem);\n padding: clamp(1rem, 2.5vw, 2.5rem);\n background: var(--bg-primary);\n}\n\n.mint-generated-workspace__loading {\n display: flex;\n min-height: 24rem;\n align-items: center;\n justify-content: center;\n gap: 0.75rem;\n color: var(--text-secondary);\n}\n\n.mint-generated-workspace__header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 1.5rem;\n max-width: 76rem;\n margin: 0 auto 1.25rem;\n}\n\n.mint-generated-workspace__header h1 {\n margin: 0;\n color: var(--text-primary);\n font-size: clamp(1.35rem, 2vw, 1.8rem);\n line-height: 1.2;\n}\n\n.mint-generated-workspace__header p:not(.mint-generated-workspace__eyebrow) {\n margin: 0.4rem 0 0;\n color: var(--text-secondary);\n}\n\n.mint-generated-workspace__eyebrow {\n margin: 0 0 0.35rem;\n color: var(--text-secondary);\n font-size: 0.72rem;\n font-weight: 700;\n}\n\n.mint-generated-workspace__resources {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: 0.4rem;\n}\n\n.mint-generated-workspace__resources span {\n padding: 0.3rem 0.55rem;\n border: 1px solid var(--border-color);\n border-radius: 999px;\n background: var(--bg-secondary);\n color: var(--text-secondary);\n font-size: 0.75rem;\n font-weight: 600;\n}\n\n.mint-generated-workspace__result {\n max-width: 76rem;\n min-height: 24rem;\n margin: 0 auto;\n padding: clamp(1rem, 2vw, 1.75rem);\n border: 1px solid var(--border-color);\n border-radius: 1rem;\n background: var(--bg-secondary);\n box-shadow: var(--shadow-sm);\n}\n\n@media (max-width: 640px) {\n .mint-generated-workspace__header {\n flex-direction: column;\n }\n\n .mint-generated-workspace__resources {\n justify-content: flex-start;\n }\n}\n</style>\n","<script setup lang=\"ts\">\n/** PlateEditor holding its own copy of the plates (useRackEditor), for ComponentBindingRenderer bindings. */\nimport { watch } from 'vue'\nimport type { PlateEditorSpec, Rack } from '../../types'\nimport { useRackEditor } from '../../composables/useRackEditor'\nimport PlateEditor from '../PlateEditor.vue'\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = defineProps<{\n modelValue: Rack[]\n activeRack?: string\n spec?: PlateEditorSpec\n}>()\n\nconst editor = useRackEditor(props.modelValue)\nconst { racks, activeRackId, plateEditorListeners, canUndo, canRedo } = editor\n// A new binding (template reloaded) replaces the local copy and its history, then reselects: the\n// activeRack watch may have run first, before its rack existed.\nwatch(() => props.modelValue, (next) => {\n racks.value = next.map(rack => ({ ...rack, wells: { ...rack.wells } }))\n editor.clearHistory()\n if (props.activeRack) editor.setActiveRack(props.activeRack)\n})\nwatch(() => props.activeRack, (id) => { if (id) editor.setActiveRack(id) }, { immediate: true })\n</script>\n\n<template>\n <PlateEditor\n v-bind=\"$attrs\"\n :spec=\"{ history: true, ...spec }\"\n :model-value=\"racks\"\n :active-rack=\"activeRackId\"\n :can-undo=\"canUndo\"\n :can-redo=\"canRedo\"\n v-on=\"plateEditorListeners\"\n />\n</template>\n","<script setup lang=\"ts\">\n/** PlateEditor holding its own copy of the plates (useRackEditor), for ComponentBindingRenderer bindings. */\nimport { watch } from 'vue'\nimport type { PlateEditorSpec, Rack } from '../../types'\nimport { useRackEditor } from '../../composables/useRackEditor'\nimport PlateEditor from '../PlateEditor.vue'\n\ndefineOptions({ inheritAttrs: false })\n\nconst props = defineProps<{\n modelValue: Rack[]\n activeRack?: string\n spec?: PlateEditorSpec\n}>()\n\nconst editor = useRackEditor(props.modelValue)\nconst { racks, activeRackId, plateEditorListeners, canUndo, canRedo } = editor\n// A new binding (template reloaded) replaces the local copy and its history, then reselects: the\n// activeRack watch may have run first, before its rack existed.\nwatch(() => props.modelValue, (next) => {\n racks.value = next.map(rack => ({ ...rack, wells: { ...rack.wells } }))\n editor.clearHistory()\n if (props.activeRack) editor.setActiveRack(props.activeRack)\n})\nwatch(() => props.activeRack, (id) => { if (id) editor.setActiveRack(id) }, { immediate: true })\n</script>\n\n<template>\n <PlateEditor\n v-bind=\"$attrs\"\n :spec=\"{ history: true, ...spec }\"\n :model-value=\"racks\"\n :active-rack=\"activeRackId\"\n :can-undo=\"canUndo\"\n :can-redo=\"canRedo\"\n v-on=\"plateEditorListeners\"\n />\n</template>\n","<script setup lang=\"ts\">\n/**\n * Render generated SDK component bindings such as WellPlate, DoseCalculator, DataFrame, and PlateEditor.\n *\n * @example Recommended\n * ```vue\n * <ComponentBindingRenderer :bindings=\"workspace.componentBindings.value\" />\n * ```\n */\nimport { computed, type Component } from 'vue'\nimport DataFrame from './DataFrame.vue'\nimport DoseCalculator from './DoseCalculator.vue'\nimport PlateEditorBindingInternal from './internal/PlateEditorBindingInternal.vue'\nimport ScheduleCalendar from './ScheduleCalendar.vue'\nimport WellPlate from './WellPlate.vue'\nimport { isRecord } from '../utils/records'\n\nexport interface ComponentBindingRendererBinding {\n id?: string\n component: string\n props?: Record<string, unknown> | readonly string[]\n propsObject?: Record<string, unknown>\n description?: string\n}\n\ntype ComponentBindingRendererLayout = 'grid' | 'stack'\n\ninterface Props {\n /** Single generated SDK component binding to render. */\n binding?: ComponentBindingRendererBinding\n /** Generated SDK component bindings to render. */\n bindings?: ComponentBindingRendererBinding[]\n /** Optional allow-list of component names, for example ['WellPlate', 'DataFrame']. */\n include?: string[]\n /** Optional deny-list of component names. */\n exclude?: string[]\n /** Compact child component sizing. */\n dense?: boolean\n /** Prefer preview-safe props for editable components. */\n readonly?: boolean\n /** Show component labels above each rendered component. */\n showHeaders?: boolean\n /** Show binding descriptions in each header. */\n showDescriptions?: boolean\n /** Grid or vertical stack layout. */\n layout?: ComponentBindingRendererLayout\n /** Message shown when no binding can be rendered. */\n emptyText?: string\n}\n\ntype RenderableBinding = ComponentBindingRendererBinding & {\n id: string\n componentImpl: Component\n normalizedProps: Record<string, unknown>\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n binding: undefined,\n bindings: () => [],\n include: () => [],\n exclude: () => [],\n dense: false,\n readonly: true,\n showHeaders: true,\n showDescriptions: true,\n layout: 'grid',\n emptyText: 'No renderable SDK component bindings.',\n})\n\nconst componentRegistry: Record<string, Component> = {\n DataFrame,\n DoseCalculator,\n // Holds its own copy of the plates: PlateEditor itself is controlled.\n PlateEditor: PlateEditorBindingInternal,\n ScheduleCalendar,\n WellPlate,\n}\n\nconst inputBindings = computed<ComponentBindingRendererBinding[]>(() => [\n ...(props.binding ? [props.binding] : []),\n ...props.bindings,\n])\n\nconst renderableBindings = computed<RenderableBinding[]>(() =>\n inputBindings.value\n .filter(binding => isIncluded(binding.component))\n .map((binding, index) => {\n const componentImpl = componentRegistry[binding.component]\n if (!componentImpl) return null\n return {\n ...binding,\n id: binding.id ?? `${binding.component}-${index + 1}`,\n componentImpl,\n normalizedProps: normalizeProps(binding),\n }\n })\n .filter((binding): binding is RenderableBinding => binding !== null)\n)\n\nconst rendererClasses = computed(() => [\n 'mint-component-binding-renderer',\n `mint-component-binding-renderer--${props.layout}`,\n props.dense ? 'mint-component-binding-renderer--dense' : '',\n])\n\nfunction isIncluded(componentName: string): boolean {\n if (props.include.length > 0 && !props.include.includes(componentName)) return false\n return !props.exclude.includes(componentName)\n}\n\nfunction baseProps(binding: ComponentBindingRendererBinding): Record<string, unknown> {\n if (binding.propsObject) return { ...binding.propsObject }\n if (isRecord(binding.props)) return { ...binding.props }\n return {}\n}\n\nfunction normalizeProps(binding: ComponentBindingRendererBinding): Record<string, unknown> {\n const base = baseProps(binding)\n\n switch (binding.component) {\n case 'WellPlate':\n case 'PlateEditor': {\n const spec = isRecord(base.spec) ? base.spec : {}\n return {\n ...base,\n spec: { ...spec, size: props.dense ? 'md' : (spec.size ?? 'fill') },\n readonly: props.readonly || Boolean(base.readonly),\n }\n }\n case 'DataFrame': {\n const spec = isRecord(base.spec) ? base.spec : {}\n return {\n ...base,\n spec: {\n ...spec,\n size: props.dense ? 'sm' : (spec.size ?? 'md'),\n maxHeight: spec.maxHeight ?? (props.dense ? '280px' : undefined),\n },\n }\n }\n case 'ScheduleCalendar':\n return {\n ...base,\n readonly: props.readonly || Boolean(base.readonly),\n showNavigation: props.dense ? false : (base.showNavigation ?? true),\n showViewToggle: props.dense ? false : (base.showViewToggle ?? true),\n }\n default:\n return base\n }\n}\n\n</script>\n\n<template>\n <div :class=\"rendererClasses\">\n <section\n v-for=\"renderableBinding in renderableBindings\"\n :key=\"renderableBinding.id\"\n class=\"mint-component-binding-renderer__item\"\n :data-component-binding-id=\"renderableBinding.id\"\n >\n <header\n v-if=\"showHeaders\"\n class=\"mint-component-binding-renderer__header\"\n >\n <div class=\"mint-component-binding-renderer__title-group\">\n <p class=\"mint-component-binding-renderer__component\">\n {{ renderableBinding.component }}\n </p>\n <p\n v-if=\"renderableBinding.id\"\n class=\"mint-component-binding-renderer__source\"\n >\n {{ renderableBinding.id }}\n </p>\n </div>\n <p\n v-if=\"showDescriptions && renderableBinding.description\"\n class=\"mint-component-binding-renderer__description\"\n >\n {{ renderableBinding.description }}\n </p>\n </header>\n\n <div class=\"mint-component-binding-renderer__body\">\n <component\n :is=\"renderableBinding.componentImpl\"\n v-bind=\"renderableBinding.normalizedProps\"\n />\n </div>\n </section>\n\n <p\n v-if=\"renderableBindings.length === 0\"\n class=\"mint-component-binding-renderer__empty\"\n >\n {{ emptyText }}\n </p>\n </div>\n</template>\n\n<style scoped>\n.mint-component-binding-renderer {\n display: grid;\n gap: 1rem;\n min-width: 0;\n}\n\n.mint-component-binding-renderer--grid {\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 28rem), 1fr));\n}\n\n.mint-component-binding-renderer--stack {\n grid-template-columns: minmax(0, 1fr);\n}\n\n.mint-component-binding-renderer--dense {\n gap: 0.75rem;\n}\n\n.mint-component-binding-renderer__item {\n min-width: 0;\n overflow: hidden;\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 0.5rem;\n background: var(--bg-card, #ffffff);\n box-shadow: var(--shadow-sm, 0 1px 2px rgb(15 23 42 / 0.06));\n}\n\n.mint-component-binding-renderer__header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 1rem;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--border-color, #e5e7eb);\n background: var(--bg-secondary, #f8fafc);\n}\n\n.mint-component-binding-renderer__title-group {\n min-width: 0;\n}\n\n.mint-component-binding-renderer__component {\n margin: 0;\n color: var(--text-primary, #0f172a);\n font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace);\n font-size: 0.8125rem;\n font-weight: 600;\n}\n\n.mint-component-binding-renderer__source,\n.mint-component-binding-renderer__description,\n.mint-component-binding-renderer__empty {\n margin: 0;\n color: var(--text-secondary, #475569);\n font-size: 0.75rem;\n line-height: 1.4;\n}\n\n.mint-component-binding-renderer__description {\n max-width: 24rem;\n text-align: right;\n}\n\n.mint-component-binding-renderer__body {\n min-width: 0;\n padding: 1rem;\n}\n\n.mint-component-binding-renderer--dense .mint-component-binding-renderer__header,\n.mint-component-binding-renderer--dense .mint-component-binding-renderer__body {\n padding: 0.75rem;\n}\n\n.mint-component-binding-renderer__empty {\n padding: 1rem;\n border: 1px dashed var(--border-color, #e5e7eb);\n border-radius: 0.5rem;\n background: var(--bg-secondary, #f8fafc);\n text-align: center;\n}\n\n@media (max-width: 720px) {\n .mint-component-binding-renderer__header {\n display: block;\n }\n\n .mint-component-binding-renderer__description {\n max-width: none;\n margin-top: 0.25rem;\n text-align: left;\n }\n}\n</style>\n","<script setup lang=\"ts\">\n/**\n * Render generated SDK component bindings such as WellPlate, DoseCalculator, DataFrame, and PlateEditor.\n *\n * @example Recommended\n * ```vue\n * <ComponentBindingRenderer :bindings=\"workspace.componentBindings.value\" />\n * ```\n */\nimport { computed, type Component } from 'vue'\nimport DataFrame from './DataFrame.vue'\nimport DoseCalculator from './DoseCalculator.vue'\nimport PlateEditorBindingInternal from './internal/PlateEditorBindingInternal.vue'\nimport ScheduleCalendar from './ScheduleCalendar.vue'\nimport WellPlate from './WellPlate.vue'\nimport { isRecord } from '../utils/records'\n\nexport interface ComponentBindingRendererBinding {\n id?: string\n component: string\n props?: Record<string, unknown> | readonly string[]\n propsObject?: Record<string, unknown>\n description?: string\n}\n\ntype ComponentBindingRendererLayout = 'grid' | 'stack'\n\ninterface Props {\n /** Single generated SDK component binding to render. */\n binding?: ComponentBindingRendererBinding\n /** Generated SDK component bindings to render. */\n bindings?: ComponentBindingRendererBinding[]\n /** Optional allow-list of component names, for example ['WellPlate', 'DataFrame']. */\n include?: string[]\n /** Optional deny-list of component names. */\n exclude?: string[]\n /** Compact child component sizing. */\n dense?: boolean\n /** Prefer preview-safe props for editable components. */\n readonly?: boolean\n /** Show component labels above each rendered component. */\n showHeaders?: boolean\n /** Show binding descriptions in each header. */\n showDescriptions?: boolean\n /** Grid or vertical stack layout. */\n layout?: ComponentBindingRendererLayout\n /** Message shown when no binding can be rendered. */\n emptyText?: string\n}\n\ntype RenderableBinding = ComponentBindingRendererBinding & {\n id: string\n componentImpl: Component\n normalizedProps: Record<string, unknown>\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n binding: undefined,\n bindings: () => [],\n include: () => [],\n exclude: () => [],\n dense: false,\n readonly: true,\n showHeaders: true,\n showDescriptions: true,\n layout: 'grid',\n emptyText: 'No renderable SDK component bindings.',\n})\n\nconst componentRegistry: Record<string, Component> = {\n DataFrame,\n DoseCalculator,\n // Holds its own copy of the plates: PlateEditor itself is controlled.\n PlateEditor: PlateEditorBindingInternal,\n ScheduleCalendar,\n WellPlate,\n}\n\nconst inputBindings = computed<ComponentBindingRendererBinding[]>(() => [\n ...(props.binding ? [props.binding] : []),\n ...props.bindings,\n])\n\nconst renderableBindings = computed<RenderableBinding[]>(() =>\n inputBindings.value\n .filter(binding => isIncluded(binding.component))\n .map((binding, index) => {\n const componentImpl = componentRegistry[binding.component]\n if (!componentImpl) return null\n return {\n ...binding,\n id: binding.id ?? `${binding.component}-${index + 1}`,\n componentImpl,\n normalizedProps: normalizeProps(binding),\n }\n })\n .filter((binding): binding is RenderableBinding => binding !== null)\n)\n\nconst rendererClasses = computed(() => [\n 'mint-component-binding-renderer',\n `mint-component-binding-renderer--${props.layout}`,\n props.dense ? 'mint-component-binding-renderer--dense' : '',\n])\n\nfunction isIncluded(componentName: string): boolean {\n if (props.include.length > 0 && !props.include.includes(componentName)) return false\n return !props.exclude.includes(componentName)\n}\n\nfunction baseProps(binding: ComponentBindingRendererBinding): Record<string, unknown> {\n if (binding.propsObject) return { ...binding.propsObject }\n if (isRecord(binding.props)) return { ...binding.props }\n return {}\n}\n\nfunction normalizeProps(binding: ComponentBindingRendererBinding): Record<string, unknown> {\n const base = baseProps(binding)\n\n switch (binding.component) {\n case 'WellPlate':\n case 'PlateEditor': {\n const spec = isRecord(base.spec) ? base.spec : {}\n return {\n ...base,\n spec: { ...spec, size: props.dense ? 'md' : (spec.size ?? 'fill') },\n readonly: props.readonly || Boolean(base.readonly),\n }\n }\n case 'DataFrame': {\n const spec = isRecord(base.spec) ? base.spec : {}\n return {\n ...base,\n spec: {\n ...spec,\n size: props.dense ? 'sm' : (spec.size ?? 'md'),\n maxHeight: spec.maxHeight ?? (props.dense ? '280px' : undefined),\n },\n }\n }\n case 'ScheduleCalendar':\n return {\n ...base,\n readonly: props.readonly || Boolean(base.readonly),\n showNavigation: props.dense ? false : (base.showNavigation ?? true),\n showViewToggle: props.dense ? false : (base.showViewToggle ?? true),\n }\n default:\n return base\n }\n}\n\n</script>\n\n<template>\n <div :class=\"rendererClasses\">\n <section\n v-for=\"renderableBinding in renderableBindings\"\n :key=\"renderableBinding.id\"\n class=\"mint-component-binding-renderer__item\"\n :data-component-binding-id=\"renderableBinding.id\"\n >\n <header\n v-if=\"showHeaders\"\n class=\"mint-component-binding-renderer__header\"\n >\n <div class=\"mint-component-binding-renderer__title-group\">\n <p class=\"mint-component-binding-renderer__component\">\n {{ renderableBinding.component }}\n </p>\n <p\n v-if=\"renderableBinding.id\"\n class=\"mint-component-binding-renderer__source\"\n >\n {{ renderableBinding.id }}\n </p>\n </div>\n <p\n v-if=\"showDescriptions && renderableBinding.description\"\n class=\"mint-component-binding-renderer__description\"\n >\n {{ renderableBinding.description }}\n </p>\n </header>\n\n <div class=\"mint-component-binding-renderer__body\">\n <component\n :is=\"renderableBinding.componentImpl\"\n v-bind=\"renderableBinding.normalizedProps\"\n />\n </div>\n </section>\n\n <p\n v-if=\"renderableBindings.length === 0\"\n class=\"mint-component-binding-renderer__empty\"\n >\n {{ emptyText }}\n </p>\n </div>\n</template>\n\n<style scoped>\n.mint-component-binding-renderer {\n display: grid;\n gap: 1rem;\n min-width: 0;\n}\n\n.mint-component-binding-renderer--grid {\n grid-template-columns: repeat(auto-fit, minmax(min(100%, 28rem), 1fr));\n}\n\n.mint-component-binding-renderer--stack {\n grid-template-columns: minmax(0, 1fr);\n}\n\n.mint-component-binding-renderer--dense {\n gap: 0.75rem;\n}\n\n.mint-component-binding-renderer__item {\n min-width: 0;\n overflow: hidden;\n border: 1px solid var(--border-color, #e5e7eb);\n border-radius: 0.5rem;\n background: var(--bg-card, #ffffff);\n box-shadow: var(--shadow-sm, 0 1px 2px rgb(15 23 42 / 0.06));\n}\n\n.mint-component-binding-renderer__header {\n display: flex;\n align-items: flex-start;\n justify-content: space-between;\n gap: 1rem;\n padding: 0.75rem 1rem;\n border-bottom: 1px solid var(--border-color, #e5e7eb);\n background: var(--bg-secondary, #f8fafc);\n}\n\n.mint-component-binding-renderer__title-group {\n min-width: 0;\n}\n\n.mint-component-binding-renderer__component {\n margin: 0;\n color: var(--text-primary, #0f172a);\n font-family: var(--font-mono, ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas, monospace);\n font-size: 0.8125rem;\n font-weight: 600;\n}\n\n.mint-component-binding-renderer__source,\n.mint-component-binding-renderer__description,\n.mint-component-binding-renderer__empty {\n margin: 0;\n color: var(--text-secondary, #475569);\n font-size: 0.75rem;\n line-height: 1.4;\n}\n\n.mint-component-binding-renderer__description {\n max-width: 24rem;\n text-align: right;\n}\n\n.mint-component-binding-renderer__body {\n min-width: 0;\n padding: 1rem;\n}\n\n.mint-component-binding-renderer--dense .mint-component-binding-renderer__header,\n.mint-component-binding-renderer--dense .mint-component-binding-renderer__body {\n padding: 0.75rem;\n}\n\n.mint-component-binding-renderer__empty {\n padding: 1rem;\n border: 1px dashed var(--border-color, #e5e7eb);\n border-radius: 0.5rem;\n background: var(--bg-secondary, #f8fafc);\n text-align: center;\n}\n\n@media (max-width: 720px) {\n .mint-component-binding-renderer__header {\n display: block;\n }\n\n .mint-component-binding-renderer__description {\n max-width: none;\n margin-top: 0.25rem;\n text-align: left;\n }\n}\n</style>\n","<script setup lang=\"ts\">\nimport { RefreshCw } from 'lucide-vue-next'\n\ndefineProps<{\n visible: boolean\n}>()\n\nconst emit = defineEmits<{\n reload: []\n}>()\n</script>\n\n<template>\n <div v-if=\"visible\" class=\"mint-runtime-update\" role=\"status\">\n <RefreshCw :size=\"16\" aria-hidden=\"true\" />\n <span>A new version is ready.</span>\n <button type=\"button\" @click=\"emit('reload')\">\n Reload now\n </button>\n </div>\n</template>\n\n<style scoped>\n.mint-runtime-update {\n position: fixed;\n right: 20px;\n bottom: 20px;\n z-index: 1200;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n color: var(--text-primary);\n background: var(--bg-card);\n border: 1px solid var(--border-color);\n border-radius: 10px;\n box-shadow: 0 10px 28px rgb(15 23 42 / 16%);\n font-size: 13px;\n font-weight: 500;\n}\n\n.mint-runtime-update button {\n padding: 5px 9px;\n color: var(--text-on-accent);\n background: var(--color-primary);\n border: 0;\n border-radius: 6px;\n font: inherit;\n cursor: pointer;\n}\n</style>\n","<script setup lang=\"ts\">\nimport { RefreshCw } from 'lucide-vue-next'\n\ndefineProps<{\n visible: boolean\n}>()\n\nconst emit = defineEmits<{\n reload: []\n}>()\n</script>\n\n<template>\n <div v-if=\"visible\" class=\"mint-runtime-update\" role=\"status\">\n <RefreshCw :size=\"16\" aria-hidden=\"true\" />\n <span>A new version is ready.</span>\n <button type=\"button\" @click=\"emit('reload')\">\n Reload now\n </button>\n </div>\n</template>\n\n<style scoped>\n.mint-runtime-update {\n position: fixed;\n right: 20px;\n bottom: 20px;\n z-index: 1200;\n display: flex;\n align-items: center;\n gap: 10px;\n padding: 10px 12px;\n color: var(--text-primary);\n background: var(--bg-card);\n border: 1px solid var(--border-color);\n border-radius: 10px;\n box-shadow: 0 10px 28px rgb(15 23 42 / 16%);\n font-size: 13px;\n font-weight: 500;\n}\n\n.mint-runtime-update button {\n padding: 5px 9px;\n color: var(--text-on-accent);\n background: var(--color-primary);\n border: 0;\n border-radius: 6px;\n font: inherit;\n cursor: pointer;\n}\n</style>\n","import {\n getCurrentScope,\n onScopeDispose,\n readonly,\n ref,\n toValue,\n watch,\n type MaybeRefOrGetter,\n type Ref,\n} from 'vue'\nimport { useApi } from './useApi'\nimport { currentPresence, subscribeRealtime, type RealtimeEvent } from './useRealtime'\n\n/**\n * What a viewer does on a topic. The platform accepts a fixed set per topic\n * kind: `experiment:{id}` takes all four labels, `project:{id}` only\n * `viewing` and `editing`. `editing` means a form with unsaved edits is open;\n * it is a hint, not a lock.\n */\nexport type PresenceActivity = 'viewing' | 'viewing_design' | 'viewing_results' | 'editing'\n\n/** One user with an open realtime stream on the topic. */\nexport interface PresenceViewer {\n user_id: string\n activity: PresenceActivity\n}\n\nexport interface UsePresenceReturn {\n /** The viewers, `editing` first, at most 20; the current user is included. Empty while the stream is closed. */\n viewers: Readonly<Ref<readonly PresenceViewer[]>>\n /** Every viewer, also those beyond the 20 in `viewers`. */\n count: Readonly<Ref<number>>\n /** True while the shared realtime stream is open. */\n connected: Readonly<Ref<boolean>>\n /** Unsubscribe; also runs when the calling component or effect scope is disposed. */\n stop: () => void\n}\n\n/**\n * Who else views an `experiment:{id}` or `project:{id}` topic (RFC #439).\n *\n * Built on `useRealtime`: the tab's open stream on the topic is its presence,\n * and `presence.changed` events update `viewers`. When `activity` is given,\n * the label is sent to `POST /api/presence/activity` when the call starts on\n * an open stream, each time the stream opens and each time the label changes;\n * `stop` (also the end of the calling scope) sets it back to `viewing`.\n * Without it, the platform shows the tab as `viewing`. Like `useRealtime`, it needs the platform's `realtime`\n * feature flag; check that flag first.\n *\n * @example\n * const { viewers } = usePresence(\n * () => `experiment:${id.value}`,\n * () => (dirty.value ? 'editing' : 'viewing'),\n * )\n */\nexport function usePresence(\n topic: MaybeRefOrGetter<string>,\n activity?: MaybeRefOrGetter<PresenceActivity>,\n): UsePresenceReturn {\n const viewers = ref<readonly PresenceViewer[]>([])\n const count = ref(0)\n const api = activity === undefined ? null : useApi({ baseUrl: '/api' })\n\n function report(label = toValue(activity)): void {\n // Presence is a hint: a failed report never reaches the view.\n api?.post('/presence/activity', { topic: toValue(topic), activity: label }).catch(() => {})\n }\n\n function show(event: RealtimeEvent | undefined): void {\n viewers.value = (event?.viewers ?? []) as PresenceViewer[]\n count.value = event?.count ?? 0\n }\n\n const realtime = subscribeRealtime(() => [toValue(topic)], (event) => {\n // ponytail: a resync after a queue overflow keeps the last viewers until\n // the next change; read the presence over REST here if that shows.\n if (event.type === 'resync') report()\n else if (event.type === 'presence.changed' && event.topic === toValue(topic)) show(event)\n }, true)\n\n // When the tab's open stream already views the topic, no open and no resync follow.\n function load(): void {\n const current = currentPresence(toValue(topic))\n show(current)\n if (current) report()\n }\n load()\n const stopTopic = watch(() => toValue(topic), load)\n // A closed stream shows nobody; the server sends the viewers again at the next open.\n const stopConnected = watch(realtime.connected, (open) => { if (!open) show(undefined) })\n // While the stream is closed the report waits for the resync of the next open.\n const stopActivity = watch(() => toValue(activity), () => {\n if (realtime.connected.value) report()\n })\n\n let stopped = false\n function stop(): void {\n if (stopped) return\n stopped = true\n stopTopic()\n stopConnected()\n stopActivity()\n // The stream can stay open on the topic for other callers: drop this caller's label.\n if (realtime.connected.value && toValue(activity) !== 'viewing') report('viewing')\n realtime.stop()\n }\n if (getCurrentScope()) onScopeDispose(stop)\n\n return { viewers: readonly(viewers), count: readonly(count), connected: realtime.connected, stop }\n}\n","import type { PresenceActivity } from '../composables/usePresence'\n\n/** One person on a presence topic, with the name to show. */\nexport interface PresencePerson {\n id: string\n name: string\n activity: PresenceActivity\n}\n\nexport interface PresenceArrangement {\n /** Every other person, `editing` first. */\n others: PresencePerson[]\n /** The people that get an avatar. */\n shown: PresencePerson[]\n /** The other people without an avatar (the `+N`). */\n overflow: number\n /** All other people, also those the platform did not list. */\n total: number\n}\n\nexport const PRESENCE_ACTIVITY_LABELS: Record<PresenceActivity, string> = {\n viewing: 'viewing',\n viewing_design: 'viewing design',\n viewing_results: 'viewing results',\n editing: 'editing',\n}\n\n/**\n * Remove the current user, sort `editing` first (the sort is stable, so the\n * platform order stays otherwise) and keep at most `max` avatars.\n * `count` is the platform's total, the current user included.\n */\nexport function arrangePresence(\n people: readonly PresencePerson[],\n options: { selfId?: string | null; count?: number; max?: number } = {},\n): PresenceArrangement {\n const max = options.max ?? 4\n const selfListed = people.some(person => person.id === options.selfId)\n const others = people\n .filter(person => person.id !== options.selfId)\n .sort((a, b) => Number(b.activity === 'editing') - Number(a.activity === 'editing'))\n // ponytail: past the platform's 20-viewer cap an unlisted current user counts as other.\n const total = Math.max(others.length, (options.count ?? people.length) - (selfListed ? 1 : 0))\n const shown = others.slice(0, max)\n return { others, shown, overflow: total - shown.length, total }\n}\n\n/** \"6 other people here: Alice Chen editing, Chen Li viewing design, and 4 more\". */\nexport function presenceSummary({ shown, overflow, total }: PresenceArrangement): string {\n const names = shown.map(person => `${person.name} ${PRESENCE_ACTIVITY_LABELS[person.activity]}`)\n if (overflow > 0) names.push(`and ${overflow} more`)\n return `${total} other ${total === 1 ? 'person' : 'people'} here: ${names.join(', ')}`\n}\n","<script setup lang=\"ts\">\n/** Who else is on a presence topic: at most `max` avatars (editing first), then `+N`; one button opens the list of each person and activity. */\nimport { computed, useId, useTemplateRef, watch, type Component } from 'vue'\nimport { ChartColumn, Eye, FlaskConical, Pencil } from 'lucide-vue-next'\nimport Avatar from './Avatar.vue'\nimport { useDropdownState } from '../composables/useDropdownState'\nimport { useEventListener } from '../composables/useEventListener'\nimport type { PresenceActivity } from '../composables/usePresence'\nimport {\n PRESENCE_ACTIVITY_LABELS,\n arrangePresence,\n presenceSummary,\n type PresencePerson,\n} from '../utils/presenceAvatars'\n\ninterface Props {\n /** The people on the topic, for example `usePresence().viewers` with names. */\n people: PresencePerson[]\n /** The current user; never shown. */\n selfId?: string | null\n /** All people on the topic (`usePresence().count`), when the list is capped. */\n count?: number\n /** Accessible name of the list. */\n label?: string\n /** Most avatars before `+N`. */\n max?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n selfId: null,\n count: undefined,\n label: 'People here',\n max: 4,\n})\n\nconst ACTIVITY_ICONS: Record<PresenceActivity, Component> = {\n viewing: Eye,\n viewing_design: FlaskConical,\n viewing_results: ChartColumn,\n editing: Pencil,\n}\n\nconst arrangement = computed(() => arrangePresence(props.people, {\n selfId: props.selfId,\n count: props.count,\n max: props.max,\n}))\nconst summary = computed(() => presenceSummary(arrangement.value))\nconst unlisted = computed(() => arrangement.value.total - arrangement.value.others.length)\n\nconst root = useTemplateRef<HTMLElement>('root')\nconst { isOpen, toggle, close } = useDropdownState({\n rootRef: root,\n triggerRef: useTemplateRef<HTMLElement>('trigger'),\n closeOnEscape: false,\n})\n// Escape closes the list from anywhere, but takes the focus back to the button only from within it.\nuseEventListener(() => document, 'keydown', (event) => {\n if (event.key === 'Escape') close(root.value?.contains(event.target as Node) ?? false)\n})\n// The root unmounts when nobody else is here; the list must not reopen on its own when someone comes back.\nwatch(() => arrangement.value.total, (total) => { if (total === 0) close() })\nconst panelId = `mint-presence-${useId()}`\n</script>\n\n<template>\n <div v-if=\"arrangement.total > 0\" ref=\"root\" class=\"mint-presence\">\n <button\n ref=\"trigger\"\n type=\"button\"\n class=\"mint-presence__trigger\"\n :aria-expanded=\"isOpen\"\n :aria-controls=\"isOpen ? panelId : undefined\"\n :aria-label=\"summary\"\n @click=\"toggle\"\n >\n <span class=\"mint-presence__stack\" aria-hidden=\"true\">\n <span\n v-for=\"person in arrangement.shown\"\n :key=\"person.id\"\n :class=\"['mint-presence__avatar', { 'mint-presence__avatar--editing': person.activity === 'editing' }]\"\n >\n <Avatar :name=\"person.name\" size=\"xs\" />\n <span v-if=\"person.activity === 'editing'\" class=\"mint-presence__badge\"><Pencil /></span>\n </span>\n <span v-if=\"arrangement.overflow > 0\" class=\"mint-presence__more\">+{{ arrangement.overflow }}</span>\n </span>\n </button>\n\n <div v-if=\"isOpen\" :id=\"panelId\" class=\"mint-popover mint-presence__panel\">\n <div class=\"mint-presence__head\">Here now <span class=\"mint-presence__count\">{{ arrangement.total }}</span></div>\n <ul class=\"mint-presence__list\" :aria-label=\"label\">\n <li v-for=\"person in arrangement.others\" :key=\"person.id\" class=\"mint-presence__row\">\n <span\n :class=\"['mint-presence__avatar', { 'mint-presence__avatar--editing': person.activity === 'editing' }]\"\n aria-hidden=\"true\"\n >\n <Avatar :name=\"person.name\" size=\"xs\" />\n <span v-if=\"person.activity === 'editing'\" class=\"mint-presence__badge\"><Pencil /></span>\n </span>\n <span class=\"mint-presence__name\">{{ person.name }}</span>\n <span :class=\"['mint-presence__activity', { 'mint-presence__activity--editing': person.activity === 'editing' }]\">\n <component :is=\"ACTIVITY_ICONS[person.activity]\" aria-hidden=\"true\" />\n {{ PRESENCE_ACTIVITY_LABELS[person.activity] }}\n </span>\n </li>\n </ul>\n <p v-if=\"unlisted > 0\" class=\"mint-presence__rest\">and {{ unlisted }} more</p>\n <p class=\"mint-presence__foot\">\n <slot name=\"footer\">Editing is a hint, not a lock. You can still edit.</slot>\n </p>\n </div>\n </div>\n</template>\n","<script setup lang=\"ts\">\n/** Who else is on a presence topic: at most `max` avatars (editing first), then `+N`; one button opens the list of each person and activity. */\nimport { computed, useId, useTemplateRef, watch, type Component } from 'vue'\nimport { ChartColumn, Eye, FlaskConical, Pencil } from 'lucide-vue-next'\nimport Avatar from './Avatar.vue'\nimport { useDropdownState } from '../composables/useDropdownState'\nimport { useEventListener } from '../composables/useEventListener'\nimport type { PresenceActivity } from '../composables/usePresence'\nimport {\n PRESENCE_ACTIVITY_LABELS,\n arrangePresence,\n presenceSummary,\n type PresencePerson,\n} from '../utils/presenceAvatars'\n\ninterface Props {\n /** The people on the topic, for example `usePresence().viewers` with names. */\n people: PresencePerson[]\n /** The current user; never shown. */\n selfId?: string | null\n /** All people on the topic (`usePresence().count`), when the list is capped. */\n count?: number\n /** Accessible name of the list. */\n label?: string\n /** Most avatars before `+N`. */\n max?: number\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n selfId: null,\n count: undefined,\n label: 'People here',\n max: 4,\n})\n\nconst ACTIVITY_ICONS: Record<PresenceActivity, Component> = {\n viewing: Eye,\n viewing_design: FlaskConical,\n viewing_results: ChartColumn,\n editing: Pencil,\n}\n\nconst arrangement = computed(() => arrangePresence(props.people, {\n selfId: props.selfId,\n count: props.count,\n max: props.max,\n}))\nconst summary = computed(() => presenceSummary(arrangement.value))\nconst unlisted = computed(() => arrangement.value.total - arrangement.value.others.length)\n\nconst root = useTemplateRef<HTMLElement>('root')\nconst { isOpen, toggle, close } = useDropdownState({\n rootRef: root,\n triggerRef: useTemplateRef<HTMLElement>('trigger'),\n closeOnEscape: false,\n})\n// Escape closes the list from anywhere, but takes the focus back to the button only from within it.\nuseEventListener(() => document, 'keydown', (event) => {\n if (event.key === 'Escape') close(root.value?.contains(event.target as Node) ?? false)\n})\n// The root unmounts when nobody else is here; the list must not reopen on its own when someone comes back.\nwatch(() => arrangement.value.total, (total) => { if (total === 0) close() })\nconst panelId = `mint-presence-${useId()}`\n</script>\n\n<template>\n <div v-if=\"arrangement.total > 0\" ref=\"root\" class=\"mint-presence\">\n <button\n ref=\"trigger\"\n type=\"button\"\n class=\"mint-presence__trigger\"\n :aria-expanded=\"isOpen\"\n :aria-controls=\"isOpen ? panelId : undefined\"\n :aria-label=\"summary\"\n @click=\"toggle\"\n >\n <span class=\"mint-presence__stack\" aria-hidden=\"true\">\n <span\n v-for=\"person in arrangement.shown\"\n :key=\"person.id\"\n :class=\"['mint-presence__avatar', { 'mint-presence__avatar--editing': person.activity === 'editing' }]\"\n >\n <Avatar :name=\"person.name\" size=\"xs\" />\n <span v-if=\"person.activity === 'editing'\" class=\"mint-presence__badge\"><Pencil /></span>\n </span>\n <span v-if=\"arrangement.overflow > 0\" class=\"mint-presence__more\">+{{ arrangement.overflow }}</span>\n </span>\n </button>\n\n <div v-if=\"isOpen\" :id=\"panelId\" class=\"mint-popover mint-presence__panel\">\n <div class=\"mint-presence__head\">Here now <span class=\"mint-presence__count\">{{ arrangement.total }}</span></div>\n <ul class=\"mint-presence__list\" :aria-label=\"label\">\n <li v-for=\"person in arrangement.others\" :key=\"person.id\" class=\"mint-presence__row\">\n <span\n :class=\"['mint-presence__avatar', { 'mint-presence__avatar--editing': person.activity === 'editing' }]\"\n aria-hidden=\"true\"\n >\n <Avatar :name=\"person.name\" size=\"xs\" />\n <span v-if=\"person.activity === 'editing'\" class=\"mint-presence__badge\"><Pencil /></span>\n </span>\n <span class=\"mint-presence__name\">{{ person.name }}</span>\n <span :class=\"['mint-presence__activity', { 'mint-presence__activity--editing': person.activity === 'editing' }]\">\n <component :is=\"ACTIVITY_ICONS[person.activity]\" aria-hidden=\"true\" />\n {{ PRESENCE_ACTIVITY_LABELS[person.activity] }}\n </span>\n </li>\n </ul>\n <p v-if=\"unlisted > 0\" class=\"mint-presence__rest\">and {{ unlisted }} more</p>\n <p class=\"mint-presence__foot\">\n <slot name=\"footer\">Editing is a hint, not a lock. You can still edit.</slot>\n </p>\n </div>\n </div>\n</template>\n","// Generated-UI runtime components (`@morscherlab/mint-sdk/runtime`).\n\n// Layout components\nexport { default as GeneratedPluginView } from './components/GeneratedPluginView.vue'\nexport { default as GeneratedResultRenderer } from './components/GeneratedResultRenderer.vue'\nexport { default as GeneratedPlotlyResult } from './components/GeneratedPlotlyResult.vue'\nexport { default as ComponentBindingRenderer } from './components/ComponentBindingRenderer.vue'\n/** Modal picker over the read-only server mounts, recording paths rather than copying data. */\nexport { default as GeneratedPathInput } from './components/GeneratedPathInput.vue'\n\n// Feedback components\nexport { default as RuntimeUpdateNotice } from './components/RuntimeUpdateNotice.vue'\n\n// The realtime event stream (`GET /api/events`, behind the `realtime` feature flag).\nexport {\n useRealtime,\n type RealtimeEvent,\n type RealtimeHandler,\n type UseRealtimeReturn,\n} from './composables/useRealtime'\nexport {\n usePresence,\n type PresenceActivity,\n type PresenceViewer,\n type UsePresenceReturn,\n} from './composables/usePresence'\n/** Avatar stack of the other people on a presence topic, with a list of each person and activity. */\nexport { default as PresenceAvatars } from './components/PresenceAvatars.vue'\nexport type { PresencePerson } from './utils/presenceAvatars'\n\n// HTTP client and plugin endpoint helpers. Generated clients (`@/generated/mint-plugin`)\n// build on these; plugin code uses the generated `useClient`, `useSettings` and `useJobs`.\nexport {\n AuthenticationRequiredError,\n useApi,\n type ApiClientOptions,\n type UseApiReturn,\n} from './composables/useApi'\nexport {\n buildEndpointUrl,\n createClient,\n downloadEndpoint,\n pluginFormDataFromPayload,\n resolvePluginBaseUrl,\n uploadEndpoint,\n useEventStream,\n useSettingsEndpoint,\n type BuildEndpointUrlOptions,\n type CreateClientOptions,\n type DownloadEndpointOptions,\n type EventStreamMessage,\n type PluginClientRequestOptions,\n type PluginContract,\n type PluginContractSettings,\n type PluginEndpointContract,\n type PluginEndpointDefinition,\n type PluginEndpointRequestOptions,\n type PluginFormDataPayload,\n type PluginFormDataValue,\n type PluginHttpMethod,\n type PluginNavItemContract,\n type StreamOptions,\n type UseEventStreamReturn,\n type UseSettingsEndpointOptions,\n type UseSettingsEndpointReturn,\n} from './composables/createClient'\nexport {\n createGeneratedAnalysisTransport,\n useJobsEndpoint,\n type GeneratedAnalysisTransport,\n type PluginJobRequestOptions,\n type PluginJobWaitOptions,\n type UseJobsEndpointOptions,\n type UseJobsEndpointReturn,\n} from './composables/useJobsEndpoint'\nexport {\n combinePluginJobSources,\n useJobCenter,\n type CombinedPluginJobCenterSource,\n type JobRowOverride,\n type JobRowView,\n type PluginJobCenterSource,\n type UseJobCenterOptions,\n type UseJobCenterReturn,\n} from './composables/useJobCenter'\nexport { controlsTo, type ControlsTarget } from './composables/controlSchemaAdapters'\nexport { controlBindings } from './composables/controlComponentBindings'\n\n// Forms, control schemas, job helpers and platform context helpers\nexport {\n useForm,\n type ValidationRule,\n type FieldRules,\n type FieldState,\n type UseFormReturn,\n} from './composables/useForm'\nexport {\n useFormBuilder,\n evaluateCondition,\n} from './composables/useFormBuilder'\nexport {\n getFieldRegistryEntry,\n getTypeDefault,\n type RegistryEntry,\n} from './composables/formBuilderRegistry'\nexport {\n defineControlComponentBindings,\n defineControls,\n getDefaultControlView,\n getControlDefaults,\n useControlSchema,\n useControlWorkspace,\n type ControlFormSchema,\n type ControlFormBinding,\n type ControlSettingsBinding,\n type ControlSidebarBinding,\n type ControlTopBarSettingsBinding,\n type ControlValues,\n type UseControlSchemaReturn,\n type ControlWorkspaceAppTopBarPillBinding,\n type ControlWorkspaceComponentBindings,\n type ControlWorkspaceFormBinding,\n type ControlWorkspacePillNavBinding,\n type ControlWorkspaceSidebarBinding,\n type ControlWorkspaceTopBarBinding,\n type ControlWorkspaceTopBarSettingsBinding,\n type UseControlWorkspaceReturn,\n} from './composables/useControlSchema'\nexport {\n resolveCurrentPluginId,\n} from './composables/platformContextHelpers'\nexport {\n resolveJobCapabilities,\n normalizeJobPercent,\n normalizeJobState,\n isActiveJobStatus,\n isTerminalJobStatus,\n jobStatusLabel,\n type JobCapabilityInput,\n type JobCapabilities,\n} from './jobs'\nexport {\n generatedJobFormSchema,\n generatedJobDefaults,\n normalizeGeneratedJobInput,\n} from './generated/schema'\n"],"mappings":"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"}
package/dist/runtime.d.ts CHANGED
@@ -13,7 +13,7 @@ export type { PresencePerson } from './utils/presenceAvatars';
13
13
  export { AuthenticationRequiredError, useApi, type ApiClientOptions, type UseApiReturn, } from './composables/useApi';
14
14
  export { buildEndpointUrl, createClient, downloadEndpoint, pluginFormDataFromPayload, resolvePluginBaseUrl, uploadEndpoint, useEventStream, useSettingsEndpoint, type BuildEndpointUrlOptions, type CreateClientOptions, type DownloadEndpointOptions, type EventStreamMessage, type PluginClientRequestOptions, type PluginContract, type PluginContractSettings, type PluginEndpointContract, type PluginEndpointDefinition, type PluginEndpointRequestOptions, type PluginFormDataPayload, type PluginFormDataValue, type PluginHttpMethod, type PluginNavItemContract, type StreamOptions, type UseEventStreamReturn, type UseSettingsEndpointOptions, type UseSettingsEndpointReturn, } from './composables/createClient';
15
15
  export { createGeneratedAnalysisTransport, useJobsEndpoint, type GeneratedAnalysisTransport, type PluginJobRequestOptions, type PluginJobWaitOptions, type UseJobsEndpointOptions, type UseJobsEndpointReturn, } from './composables/useJobsEndpoint';
16
- export { combinePluginJobSources, useJobCenter, type CombinedPluginJobCenterSource, type JobsStatusTrayTab, type PluginJobCenterSource, type UseJobCenterOptions, type UseJobCenterReturn, } from './composables/useJobCenter';
16
+ export { combinePluginJobSources, useJobCenter, type CombinedPluginJobCenterSource, type JobRowOverride, type JobRowView, type PluginJobCenterSource, type UseJobCenterOptions, type UseJobCenterReturn, } from './composables/useJobCenter';
17
17
  export { controlsTo, type ControlsTarget } from './composables/controlSchemaAdapters';
18
18
  export { controlBindings } from './composables/controlComponentBindings';
19
19
  export { useForm, type ValidationRule, type FieldRules, type FieldState, type UseFormReturn, } from './composables/useForm';
package/dist/runtime.js CHANGED
@@ -1,8 +1,8 @@
1
- import { i as AuthenticationRequiredError, o as useApi } from "./experiment-43OJtH7R.js";
2
- import { c as isTerminalJobStatus, d as normalizeJobState, f as resolveJobCapabilities, l as jobStatusLabel, o as resolveCurrentPluginId, s as isActiveJobStatus, u as normalizeJobPercent } from "./records-B6gpM_3e.js";
3
- import { A as createGeneratedAnalysisTransport, D as GeneratedPathInput_default, _ as getFieldRegistryEntry, j as useJobsEndpoint, v as getTypeDefault } from "./useListReorder-BitdUhxn.js";
4
- import { a as GeneratedPlotlyResult_default, c as downloadEndpoint, d as useEventStream, f as useSettingsEndpoint, i as GeneratedResultRenderer_default, l as pluginFormDataFromPayload, m as resolvePluginBaseUrl, o as createClient, p as buildEndpointUrl, u as uploadEndpoint } from "./useRackEditor-DiwCt77M.js";
5
- import { a as ComponentBindingRenderer_default, c as generatedJobFormSchema, f as useControlWorkspace, i as RuntimeUpdateNotice_default, l as normalizeGeneratedJobInput, n as PresenceAvatars_default, o as GeneratedPluginView_default, r as usePresence, s as generatedJobDefaults } from "./runtime-7vfl_bI3.js";
6
- import { A as getDefaultControlView, C as controlBindings, D as controlsTo, S as useControlSchema, b as defineControls, d as useForm, l as useFormBuilder, u as evaluateCondition, x as getControlDefaults, y as defineControlComponentBindings } from "./AppSidebar-Dq9W1jE2.js";
7
- import { a as combinePluginJobSources, o as useJobCenter, r as useRealtime } from "./useRealtime-C3iy9QkU.js";
1
+ import { i as AuthenticationRequiredError, o as useApi } from "./experiment-DyO54FQB.js";
2
+ import { d as isActiveJobStatus, f as isTerminalJobStatus, g as resolveJobCapabilities, h as normalizeJobState, m as normalizeJobPercent, o as resolveCurrentPluginId, p as jobStatusLabel } from "./records-D4aQXyZu.js";
3
+ import { A as useJobsEndpoint, E as GeneratedPathInput_default, _ as getTypeDefault, g as getFieldRegistryEntry, k as createGeneratedAnalysisTransport } from "./useListReorder-DsuzwWGS.js";
4
+ import { a as GeneratedPlotlyResult_default, c as downloadEndpoint, d as useEventStream, f as useSettingsEndpoint, i as GeneratedResultRenderer_default, l as pluginFormDataFromPayload, m as resolvePluginBaseUrl, o as createClient, p as buildEndpointUrl, u as uploadEndpoint } from "./useRackEditor-KpZ4iJ6o.js";
5
+ import { a as ComponentBindingRenderer_default, c as generatedJobFormSchema, f as useControlWorkspace, i as RuntimeUpdateNotice_default, l as normalizeGeneratedJobInput, m as useJobCenter, n as PresenceAvatars_default, o as GeneratedPluginView_default, p as combinePluginJobSources, r as usePresence, s as generatedJobDefaults } from "./runtime-q-R0CNLh.js";
6
+ import { D as useControlSchema, E as getControlDefaults, F as getDefaultControlView, M as controlsTo, O as controlBindings, T as defineControls, d as useForm, l as useFormBuilder, u as evaluateCondition, w as defineControlComponentBindings } from "./AppSidebar-CZZaxni0.js";
7
+ import { r as useRealtime } from "./useRealtime-B58Lo-Tm.js";
8
8
  export { AuthenticationRequiredError, ComponentBindingRenderer_default as ComponentBindingRenderer, GeneratedPathInput_default as GeneratedPathInput, GeneratedPlotlyResult_default as GeneratedPlotlyResult, GeneratedPluginView_default as GeneratedPluginView, GeneratedResultRenderer_default as GeneratedResultRenderer, PresenceAvatars_default as PresenceAvatars, RuntimeUpdateNotice_default as RuntimeUpdateNotice, buildEndpointUrl, combinePluginJobSources, controlBindings, controlsTo, createClient, createGeneratedAnalysisTransport, defineControlComponentBindings, defineControls, downloadEndpoint, evaluateCondition, generatedJobDefaults, generatedJobFormSchema, getControlDefaults, getDefaultControlView, getFieldRegistryEntry, getTypeDefault, isActiveJobStatus, isTerminalJobStatus, jobStatusLabel, normalizeGeneratedJobInput, normalizeJobPercent, normalizeJobState, pluginFormDataFromPayload, resolveCurrentPluginId, resolveJobCapabilities, resolvePluginBaseUrl, uploadEndpoint, useApi, useControlSchema, useControlWorkspace, useEventStream, useForm, useFormBuilder, useJobCenter, useJobsEndpoint, usePresence, useRealtime, useSettingsEndpoint };
@@ -1,7 +1,7 @@
1
- import { i as useEventListener, o as __exportAll, r as useFocusTrap } from "./useDropdownState-8yWMu-7_.js";
2
- import { E as useMenuKeyboard, H as useListSelection, R as useRovingFocus, U as useSelectionLimit } from "./records-B6gpM_3e.js";
3
- import { B as compareSortValues, V as useSortedItems, i as useReorderAnnouncer, n as reorderList, r as useListReorder, t as REORDER_ANNOUNCER_STYLE } from "./useListReorder-BitdUhxn.js";
4
- import { _ as AppLayout_default, f as AppTopBar_default, t as AppSidebar_default, v as usePluginWorkspace } from "./AppSidebar-Dq9W1jE2.js";
1
+ import { i as useEventListener, o as __exportAll, r as useFocusTrap } from "./useDropdownState-uFIz6Yv8.js";
2
+ import { E as useMenuKeyboard, H as useListSelection, R as useRovingFocus, U as useSelectionLimit } from "./records-D4aQXyZu.js";
3
+ import { B as compareSortValues, V as useSortedItems, i as useReorderAnnouncer, n as reorderList, r as useListReorder, t as REORDER_ANNOUNCER_STYLE } from "./useListReorder-DsuzwWGS.js";
4
+ import { C as usePluginWorkspace, S as AppLayout_default, _ as provideOnboarding, f as AppTopBar_default, g as defineOnboarding, h as ONBOARDING_KEY, m as ANCHOR_WAIT_MS, t as AppSidebar_default, v as useOnboarding } from "./AppSidebar-CZZaxni0.js";
5
5
  import { t as useDebouncedWatch } from "./useDebouncedWatch-BPwyl6eS.js";
6
6
  import { t as useExpansionSet } from "./useExpansionSet-CvoNMZJi.js";
7
7
  import { computed, createElementBlock, createElementVNode, defineComponent, normalizeClass, onBeforeUnmount, openBlock, shallowRef, toValue, watch } from "vue";
@@ -167,12 +167,16 @@ function useManualLayoutResize(options) {
167
167
  //#endregion
168
168
  //#region src/shell.ts
169
169
  var shell_exports = /* @__PURE__ */ __exportAll({
170
+ ANCHOR_WAIT_MS: () => ANCHOR_WAIT_MS,
170
171
  AppLayout: () => AppLayout_default,
171
172
  AppSidebar: () => AppSidebar_default,
172
173
  AppTopBar: () => AppTopBar_default,
173
174
  LayoutResizeHandle: () => LayoutResizeHandle_default,
175
+ ONBOARDING_KEY: () => ONBOARDING_KEY,
174
176
  REORDER_ANNOUNCER_STYLE: () => REORDER_ANNOUNCER_STYLE,
175
177
  compareSortValues: () => compareSortValues,
178
+ defineOnboarding: () => defineOnboarding,
179
+ provideOnboarding: () => provideOnboarding,
176
180
  reorderList: () => reorderList,
177
181
  resizedLeadingPanelWidth: () => resizedLeadingPanelWidth,
178
182
  resizedTrailingPanelWidth: () => resizedTrailingPanelWidth,
@@ -185,6 +189,7 @@ var shell_exports = /* @__PURE__ */ __exportAll({
185
189
  useListSelection: () => useListSelection,
186
190
  useManualLayoutResize: () => useManualLayoutResize,
187
191
  useMenuKeyboard: () => useMenuKeyboard,
192
+ useOnboarding: () => useOnboarding,
188
193
  usePluginWorkspace: () => usePluginWorkspace,
189
194
  useReorderAnnouncer: () => useReorderAnnouncer,
190
195
  useRovingFocus: () => useRovingFocus,
@@ -194,4 +199,4 @@ var shell_exports = /* @__PURE__ */ __exportAll({
194
199
  //#endregion
195
200
  export { useManualLayoutResize as a, resizedVerticalSplitPercent as i, resizedLeadingPanelWidth as n, LayoutResizeHandle_default as o, resizedTrailingPanelWidth as r, shell_exports as t };
196
201
 
197
- //# sourceMappingURL=shell-Cs9OJMnm.js.map
202
+ //# sourceMappingURL=shell-6CGFvUUw.js.map