@morscherlab/mint-sdk 1.4.0-beta.13 → 1.4.0-beta.14

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 (55) hide show
  1. package/dist/{AlertBox-BdoZqANv.js → AlertBox-SnsbVow-.js} +3 -3
  2. package/dist/{AlertBox-BdoZqANv.js.map → AlertBox-SnsbVow-.js.map} +1 -1
  3. package/dist/{AppSidebar-CIXJBzDv.js → AppSidebar-Bi8g9mRt.js} +7 -7
  4. package/dist/{AppSidebar-CIXJBzDv.js.map → AppSidebar-Bi8g9mRt.js.map} +1 -1
  5. package/dist/{ConfirmDialog-nbJj51is.js → ConfirmDialog-CSls2Nuv.js} +2 -2
  6. package/dist/{ConfirmDialog-nbJj51is.js.map → ConfirmDialog-CSls2Nuv.js.map} +1 -1
  7. package/dist/{ExperimentPopover-CbD7BR_s.js → ExperimentPopover-ChKCrklH.js} +5 -5
  8. package/dist/{ExperimentPopover-CbD7BR_s.js.map → ExperimentPopover-ChKCrklH.js.map} +1 -1
  9. package/dist/{ExperimentSelectorModal-BbFtr1Fr.js → ExperimentSelectorModal-BqifjNaN.js} +5 -5
  10. package/dist/{ExperimentSelectorModal-BbFtr1Fr.js.map → ExperimentSelectorModal-BqifjNaN.js.map} +1 -1
  11. package/dist/{SegmentedControl-BkwYOKpG.js → SegmentedControl-hOgBVdju.js} +2 -2
  12. package/dist/{SegmentedControl-BkwYOKpG.js.map → SegmentedControl-hOgBVdju.js.map} +1 -1
  13. package/dist/{SettingsModal-CdhFMi8j.js → SettingsModal-jra_2u0o.js} +7 -7
  14. package/dist/{SettingsModal-CdhFMi8j.js.map → SettingsModal-jra_2u0o.js.map} +1 -1
  15. package/dist/components/BaseButton.vue.d.ts +4 -2
  16. package/dist/{controlSchemaModel-BF5g4wRC.js → controlSchemaModel-CIH5Hqpw.js} +2 -2
  17. package/dist/{controlSchemaModel-BF5g4wRC.js.map → controlSchemaModel-CIH5Hqpw.js.map} +1 -1
  18. package/dist/{data-DUt0TIp5.js → data-OZ94DhVC.js} +11 -11
  19. package/dist/{data-DUt0TIp5.js.map → data-OZ94DhVC.js.map} +1 -1
  20. package/dist/data.js +8 -8
  21. package/dist/{experimentStatus-Cqp6qNrR.js → experimentStatus-BFrKpHAH.js} +2 -2
  22. package/dist/{experimentStatus-Cqp6qNrR.js.map → experimentStatus-BFrKpHAH.js.map} +1 -1
  23. package/dist/index.js +18 -18
  24. package/dist/{install-Czoe1rA8.js → install-Bx_6KwJA.js} +15 -15
  25. package/dist/{install-Czoe1rA8.js.map → install-Bx_6KwJA.js.map} +1 -1
  26. package/dist/install.js +1 -1
  27. package/dist/{lab-B-pLwc5U.js → lab-ZDKlx1Oo.js} +10 -10
  28. package/dist/{lab-B-pLwc5U.js.map → lab-ZDKlx1Oo.js.map} +1 -1
  29. package/dist/lab.js +4 -4
  30. package/dist/{records-DnK_1Q_S.js → records-B4yl2oIu.js} +2 -2
  31. package/dist/{records-DnK_1Q_S.js.map → records-B4yl2oIu.js.map} +1 -1
  32. package/dist/{runtime-fPb_FEZr.js → runtime-BJvGms6h.js} +9 -9
  33. package/dist/{runtime-fPb_FEZr.js.map → runtime-BJvGms6h.js.map} +1 -1
  34. package/dist/runtime.js +6 -6
  35. package/dist/{shell-lDf_EY-x.js → shell-Czyrzk7l.js} +5 -5
  36. package/dist/{shell-lDf_EY-x.js.map → shell-Czyrzk7l.js.map} +1 -1
  37. package/dist/shell.js +5 -5
  38. package/dist/styles.css +8 -0
  39. package/dist/{useDropdownState-8yWMu-7_.js → useDropdownState-Bb2N4m40.js} +15 -3
  40. package/dist/useDropdownState-Bb2N4m40.js.map +1 -0
  41. package/dist/{useExperimentSamples-BGN1dmcR.js → useExperimentSamples-BLx29CkM.js} +3 -3
  42. package/dist/{useExperimentSamples-BGN1dmcR.js.map → useExperimentSamples-BLx29CkM.js.map} +1 -1
  43. package/dist/{useListReorder-DPynGrCj.js → useListReorder-C_8RYeVP.js} +3 -3
  44. package/dist/{useListReorder-DPynGrCj.js.map → useListReorder-C_8RYeVP.js.map} +1 -1
  45. package/dist/{useRackEditor-B2FrQA0p.js → useRackEditor-BhYlXKFM.js} +8 -8
  46. package/dist/{useRackEditor-B2FrQA0p.js.map → useRackEditor-BhYlXKFM.js.map} +1 -1
  47. package/dist/{useRealtime-yWjTTnc9.js → useRealtime-CUMbW_ln.js} +2 -2
  48. package/dist/{useRealtime-yWjTTnc9.js.map → useRealtime-CUMbW_ln.js.map} +1 -1
  49. package/dist/{useRequest-Dqw12k2s.js → useRequest-C9uwM79q.js} +3 -3
  50. package/dist/{useRequest-Dqw12k2s.js.map → useRequest-C9uwM79q.js.map} +1 -1
  51. package/package.json +1 -1
  52. package/src/__tests__/components/BaseButton.test.ts +19 -0
  53. package/src/components/BaseButton.vue +16 -2
  54. package/src/styles/components/button.css +8 -0
  55. package/dist/useDropdownState-8yWMu-7_.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"runtime-fPb_FEZr.js","names":["$emit","$attrs"],"sources":["../src/composables/useToast.ts","../src/components/AppToastContainer.vue","../src/components/AppToastContainer.vue","../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 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'\n\ndefineProps<{\n shell: PluginWorkspaceShellModel\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}>()\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 @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'\n\ndefineProps<{\n shell: PluginWorkspaceShellModel\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}>()\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 @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 { useAppExperiment } from '../composables/useAppExperiment'\nimport { usePluginWorkspace } from '../composables/usePluginWorkspace'\nimport AppToastContainer from './AppToastContainer.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\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 @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 </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 { useAppExperiment } from '../composables/useAppExperiment'\nimport { usePluginWorkspace } from '../composables/usePluginWorkspace'\nimport AppToastContainer from './AppToastContainer.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\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 @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 </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 GeneratedAnalysisJob,\n GeneratedAnalysisResult,\n GeneratedJobDefinition,\n} from '../types/generated-ui'\nimport type { PillNavItem, SidebarToolSection } from '../types'\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 JobsStatusTray from './JobsStatusTray.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}))\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: GeneratedAnalysisJob): 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 >\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\n <JobsStatusTray\n :source=\"generated\"\n :teleport-to=\"false\"\n @select=\"selectJob\"\n />\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 GeneratedAnalysisJob,\n GeneratedAnalysisResult,\n GeneratedJobDefinition,\n} from '../types/generated-ui'\nimport type { PillNavItem, SidebarToolSection } from '../types'\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 JobsStatusTray from './JobsStatusTray.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}))\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: GeneratedAnalysisJob): 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 >\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\n <JobsStatusTray\n :source=\"generated\"\n :teleport-to=\"false\"\n @select=\"selectJob\"\n />\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 JobsStatusTrayTab,\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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"}
1
+ {"version":3,"file":"runtime-BJvGms6h.js","names":["$emit","$attrs"],"sources":["../src/composables/useToast.ts","../src/components/AppToastContainer.vue","../src/components/AppToastContainer.vue","../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 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'\n\ndefineProps<{\n shell: PluginWorkspaceShellModel\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}>()\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 @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'\n\ndefineProps<{\n shell: PluginWorkspaceShellModel\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}>()\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 @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 { useAppExperiment } from '../composables/useAppExperiment'\nimport { usePluginWorkspace } from '../composables/usePluginWorkspace'\nimport AppToastContainer from './AppToastContainer.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\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 @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 </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 { useAppExperiment } from '../composables/useAppExperiment'\nimport { usePluginWorkspace } from '../composables/usePluginWorkspace'\nimport AppToastContainer from './AppToastContainer.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\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 @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 </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 GeneratedAnalysisJob,\n GeneratedAnalysisResult,\n GeneratedJobDefinition,\n} from '../types/generated-ui'\nimport type { PillNavItem, SidebarToolSection } from '../types'\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 JobsStatusTray from './JobsStatusTray.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}))\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: GeneratedAnalysisJob): 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 >\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\n <JobsStatusTray\n :source=\"generated\"\n :teleport-to=\"false\"\n @select=\"selectJob\"\n />\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 GeneratedAnalysisJob,\n GeneratedAnalysisResult,\n GeneratedJobDefinition,\n} from '../types/generated-ui'\nimport type { PillNavItem, SidebarToolSection } from '../types'\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 JobsStatusTray from './JobsStatusTray.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}))\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: GeneratedAnalysisJob): 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 >\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\n <JobsStatusTray\n :source=\"generated\"\n :teleport-to=\"false\"\n @select=\"selectJob\"\n />\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 JobsStatusTrayTab,\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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"}