@morscherlab/mld-sdk 0.7.7 → 0.7.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/components/ExperimentSelectorModal.vue.d.ts +20 -0
- package/dist/components/ExperimentSelectorModal.vue.js +164 -0
- package/dist/components/ExperimentSelectorModal.vue.js.map +1 -0
- package/dist/components/ExperimentSelectorModal.vue3.js +6 -0
- package/dist/components/ExperimentSelectorModal.vue3.js.map +1 -0
- package/dist/components/FitPanel.vue.d.ts +46 -0
- package/dist/components/FitPanel.vue.js +118 -0
- package/dist/components/FitPanel.vue.js.map +1 -0
- package/dist/components/FitPanel.vue3.js +6 -0
- package/dist/components/FitPanel.vue3.js.map +1 -0
- package/dist/components/index.d.ts +2 -0
- package/dist/components/index.js +6 -0
- package/dist/components/index.js.map +1 -1
- package/dist/composables/index.d.ts +1 -0
- package/dist/composables/index.js +2 -0
- package/dist/composables/index.js.map +1 -1
- package/dist/composables/useExperimentSelector.d.ts +20 -0
- package/dist/composables/useExperimentSelector.js +82 -0
- package/dist/composables/useExperimentSelector.js.map +1 -0
- package/dist/index.d.ts +3 -3
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/styles.css +294 -0
- package/dist/types/components.d.ts +30 -0
- package/dist/types/index.d.ts +1 -1
- package/package.json +1 -1
- package/src/components/ExperimentSelectorModal.vue +157 -0
- package/src/components/FitPanel.vue +119 -0
- package/src/components/index.ts +4 -0
- package/src/composables/index.ts +5 -0
- package/src/composables/useExperimentSelector.ts +113 -0
- package/src/index.ts +15 -0
- package/src/styles/components/experiment-selector-modal.css +101 -0
- package/src/styles/components/fit-panel.css +67 -0
- package/src/styles/index.css +2 -0
- package/src/types/components.ts +38 -0
- package/src/types/index.ts +8 -0
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { ModalSize, ExperimentSummary } from '../types';
|
|
2
|
+
interface Props {
|
|
3
|
+
modelValue: boolean;
|
|
4
|
+
experimentType?: string;
|
|
5
|
+
currentExperimentId?: number | null;
|
|
6
|
+
title?: string;
|
|
7
|
+
size?: ModalSize;
|
|
8
|
+
}
|
|
9
|
+
declare const _default: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
10
|
+
select: (experiment: ExperimentSummary) => any;
|
|
11
|
+
"update:modelValue": (value: boolean) => any;
|
|
12
|
+
}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
|
|
13
|
+
onSelect?: ((experiment: ExperimentSummary) => any) | undefined;
|
|
14
|
+
"onUpdate:modelValue"?: ((value: boolean) => any) | undefined;
|
|
15
|
+
}>, {
|
|
16
|
+
size: ModalSize;
|
|
17
|
+
title: string;
|
|
18
|
+
currentExperimentId: number | null;
|
|
19
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, any>;
|
|
20
|
+
export default _default;
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { defineComponent, watch, openBlock, createBlock, withCtx, createElementVNode, createVNode, unref, createElementBlock, toDisplayString, Fragment, renderList, normalizeClass, createCommentVNode, createTextVNode } from "vue";
|
|
2
|
+
import { useExperimentSelector } from "../composables/useExperimentSelector.js";
|
|
3
|
+
import _sfc_main$1 from "./BaseModal.vue.js";
|
|
4
|
+
/* empty css */
|
|
5
|
+
import _sfc_main$2 from "./BaseInput.vue.js";
|
|
6
|
+
/* empty css */
|
|
7
|
+
import _sfc_main$3 from "./BaseSelect.vue.js";
|
|
8
|
+
/* empty css */
|
|
9
|
+
import _sfc_main$6 from "./BasePill.vue.js";
|
|
10
|
+
/* empty css */
|
|
11
|
+
import _sfc_main$4 from "./LoadingSpinner.vue.js";
|
|
12
|
+
/* empty css */
|
|
13
|
+
import _sfc_main$5 from "./EmptyState.vue.js";
|
|
14
|
+
/* empty css */
|
|
15
|
+
const _hoisted_1 = { class: "mld-experiment-selector" };
|
|
16
|
+
const _hoisted_2 = { class: "mld-experiment-selector__filters" };
|
|
17
|
+
const _hoisted_3 = { class: "mld-experiment-selector__search" };
|
|
18
|
+
const _hoisted_4 = { class: "mld-experiment-selector__status-filter" };
|
|
19
|
+
const _hoisted_5 = {
|
|
20
|
+
key: 0,
|
|
21
|
+
class: "mld-experiment-selector__loading"
|
|
22
|
+
};
|
|
23
|
+
const _hoisted_6 = {
|
|
24
|
+
key: 1,
|
|
25
|
+
class: "mld-experiment-selector__error"
|
|
26
|
+
};
|
|
27
|
+
const _hoisted_7 = {
|
|
28
|
+
key: 3,
|
|
29
|
+
class: "mld-experiment-selector__list"
|
|
30
|
+
};
|
|
31
|
+
const _hoisted_8 = ["onClick"];
|
|
32
|
+
const _hoisted_9 = { class: "mld-experiment-selector__row-content" };
|
|
33
|
+
const _hoisted_10 = { class: "mld-experiment-selector__name" };
|
|
34
|
+
const _hoisted_11 = { class: "mld-experiment-selector__meta" };
|
|
35
|
+
const _hoisted_12 = { key: 0 };
|
|
36
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
37
|
+
__name: "ExperimentSelectorModal",
|
|
38
|
+
props: {
|
|
39
|
+
modelValue: { type: Boolean },
|
|
40
|
+
experimentType: {},
|
|
41
|
+
currentExperimentId: { default: null },
|
|
42
|
+
title: { default: "Select Experiment" },
|
|
43
|
+
size: { default: "md" }
|
|
44
|
+
},
|
|
45
|
+
emits: ["update:modelValue", "select"],
|
|
46
|
+
setup(__props, { emit: __emit }) {
|
|
47
|
+
const props = __props;
|
|
48
|
+
const emit = __emit;
|
|
49
|
+
const {
|
|
50
|
+
experiments,
|
|
51
|
+
filters,
|
|
52
|
+
isLoading,
|
|
53
|
+
error,
|
|
54
|
+
fetch: fetchExperiments
|
|
55
|
+
} = useExperimentSelector({
|
|
56
|
+
experimentType: props.experimentType
|
|
57
|
+
});
|
|
58
|
+
const statusOptions = [
|
|
59
|
+
{ value: "", label: "All statuses" },
|
|
60
|
+
{ value: "planned", label: "Planned" },
|
|
61
|
+
{ value: "ongoing", label: "Ongoing" },
|
|
62
|
+
{ value: "completed", label: "Completed" }
|
|
63
|
+
];
|
|
64
|
+
const statusVariantMap = {
|
|
65
|
+
planned: "default",
|
|
66
|
+
ongoing: "primary",
|
|
67
|
+
completed: "success"
|
|
68
|
+
};
|
|
69
|
+
function handleStatusChange(value) {
|
|
70
|
+
filters.status = String(value) || null;
|
|
71
|
+
}
|
|
72
|
+
function handleSelect(experiment) {
|
|
73
|
+
emit("select", experiment);
|
|
74
|
+
emit("update:modelValue", false);
|
|
75
|
+
}
|
|
76
|
+
function formatDate(dateStr) {
|
|
77
|
+
try {
|
|
78
|
+
return new Date(dateStr).toLocaleDateString(void 0, {
|
|
79
|
+
year: "numeric",
|
|
80
|
+
month: "short",
|
|
81
|
+
day: "numeric"
|
|
82
|
+
});
|
|
83
|
+
} catch {
|
|
84
|
+
return dateStr;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
watch(
|
|
88
|
+
() => props.modelValue,
|
|
89
|
+
(isOpen) => {
|
|
90
|
+
if (isOpen) fetchExperiments();
|
|
91
|
+
}
|
|
92
|
+
);
|
|
93
|
+
return (_ctx, _cache) => {
|
|
94
|
+
return openBlock(), createBlock(_sfc_main$1, {
|
|
95
|
+
"model-value": __props.modelValue,
|
|
96
|
+
title: __props.title,
|
|
97
|
+
size: __props.size,
|
|
98
|
+
"onUpdate:modelValue": _cache[1] || (_cache[1] = ($event) => emit("update:modelValue", $event))
|
|
99
|
+
}, {
|
|
100
|
+
default: withCtx(() => [
|
|
101
|
+
createElementVNode("div", _hoisted_1, [
|
|
102
|
+
createElementVNode("div", _hoisted_2, [
|
|
103
|
+
createElementVNode("div", _hoisted_3, [
|
|
104
|
+
createVNode(_sfc_main$2, {
|
|
105
|
+
modelValue: unref(filters).search,
|
|
106
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => unref(filters).search = $event),
|
|
107
|
+
placeholder: "Search experiments...",
|
|
108
|
+
size: "sm",
|
|
109
|
+
type: "search"
|
|
110
|
+
}, null, 8, ["modelValue"])
|
|
111
|
+
]),
|
|
112
|
+
createElementVNode("div", _hoisted_4, [
|
|
113
|
+
createVNode(_sfc_main$3, {
|
|
114
|
+
"model-value": unref(filters).status ?? "",
|
|
115
|
+
options: statusOptions,
|
|
116
|
+
size: "sm",
|
|
117
|
+
"onUpdate:modelValue": handleStatusChange
|
|
118
|
+
}, null, 8, ["model-value"])
|
|
119
|
+
])
|
|
120
|
+
]),
|
|
121
|
+
unref(isLoading) ? (openBlock(), createElementBlock("div", _hoisted_5, [
|
|
122
|
+
createVNode(_sfc_main$4, { size: "md" })
|
|
123
|
+
])) : unref(error) ? (openBlock(), createElementBlock("div", _hoisted_6, toDisplayString(unref(error)), 1)) : unref(experiments).length === 0 ? (openBlock(), createBlock(_sfc_main$5, {
|
|
124
|
+
key: 2,
|
|
125
|
+
title: "No experiments found",
|
|
126
|
+
description: "Try adjusting your search or filters.",
|
|
127
|
+
size: "sm"
|
|
128
|
+
})) : (openBlock(), createElementBlock("div", _hoisted_7, [
|
|
129
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(unref(experiments), (exp) => {
|
|
130
|
+
return openBlock(), createElementBlock("div", {
|
|
131
|
+
key: exp.id,
|
|
132
|
+
class: normalizeClass(["mld-experiment-selector__row", { "mld-experiment-selector__row--active": exp.id === __props.currentExperimentId }]),
|
|
133
|
+
onClick: ($event) => handleSelect(exp)
|
|
134
|
+
}, [
|
|
135
|
+
createElementVNode("div", _hoisted_9, [
|
|
136
|
+
createElementVNode("div", _hoisted_10, toDisplayString(exp.name), 1),
|
|
137
|
+
createElementVNode("div", _hoisted_11, [
|
|
138
|
+
exp.project ? (openBlock(), createElementBlock("span", _hoisted_12, toDisplayString(exp.project), 1)) : createCommentVNode("", true),
|
|
139
|
+
createElementVNode("span", null, toDisplayString(formatDate(exp.created_at)), 1)
|
|
140
|
+
])
|
|
141
|
+
]),
|
|
142
|
+
createVNode(_sfc_main$6, {
|
|
143
|
+
variant: statusVariantMap[exp.status],
|
|
144
|
+
size: "sm"
|
|
145
|
+
}, {
|
|
146
|
+
default: withCtx(() => [
|
|
147
|
+
createTextVNode(toDisplayString(exp.status), 1)
|
|
148
|
+
]),
|
|
149
|
+
_: 2
|
|
150
|
+
}, 1032, ["variant"])
|
|
151
|
+
], 10, _hoisted_8);
|
|
152
|
+
}), 128))
|
|
153
|
+
]))
|
|
154
|
+
])
|
|
155
|
+
]),
|
|
156
|
+
_: 1
|
|
157
|
+
}, 8, ["model-value", "title", "size"]);
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
});
|
|
161
|
+
export {
|
|
162
|
+
_sfc_main as default
|
|
163
|
+
};
|
|
164
|
+
//# sourceMappingURL=ExperimentSelectorModal.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExperimentSelectorModal.vue.js","sources":["../../src/components/ExperimentSelectorModal.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { watch } from 'vue'\nimport type { ModalSize, ExperimentSummary, ExperimentStatus, SelectOption } from '../types'\nimport { useExperimentSelector } from '../composables/useExperimentSelector'\nimport BaseModal from './BaseModal.vue'\nimport BaseInput from './BaseInput.vue'\nimport BaseSelect from './BaseSelect.vue'\nimport BasePill from './BasePill.vue'\nimport LoadingSpinner from './LoadingSpinner.vue'\nimport EmptyState from './EmptyState.vue'\n\ninterface Props {\n modelValue: boolean\n experimentType?: string\n currentExperimentId?: number | null\n title?: string\n size?: ModalSize\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n currentExperimentId: null,\n title: 'Select Experiment',\n size: 'md',\n})\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n select: [experiment: ExperimentSummary]\n}>()\n\nconst {\n experiments,\n filters,\n isLoading,\n error,\n fetch: fetchExperiments,\n} = useExperimentSelector({\n experimentType: props.experimentType,\n})\n\nconst statusOptions: SelectOption<string>[] = [\n { value: '', label: 'All statuses' },\n { value: 'planned', label: 'Planned' },\n { value: 'ongoing', label: 'Ongoing' },\n { value: 'completed', label: 'Completed' },\n]\n\nconst statusVariantMap: Record<ExperimentStatus, string> = {\n planned: 'default',\n ongoing: 'primary',\n completed: 'success',\n}\n\nfunction handleStatusChange(value: string | number) {\n filters.status = (String(value) || null) as ExperimentStatus | null\n}\n\nfunction handleSelect(experiment: ExperimentSummary) {\n emit('select', experiment)\n emit('update:modelValue', false)\n}\n\nfunction formatDate(dateStr: string): string {\n try {\n return new Date(dateStr).toLocaleDateString(undefined, {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n })\n } catch {\n return dateStr\n }\n}\n\n// Fetch on open\nwatch(\n () => props.modelValue,\n (isOpen) => {\n if (isOpen) fetchExperiments()\n },\n)\n</script>\n\n<template>\n <BaseModal\n :model-value=\"modelValue\"\n :title=\"title\"\n :size=\"size\"\n @update:model-value=\"emit('update:modelValue', $event)\"\n >\n <div class=\"mld-experiment-selector\">\n <!-- Filter bar -->\n <div class=\"mld-experiment-selector__filters\">\n <div class=\"mld-experiment-selector__search\">\n <BaseInput\n v-model=\"filters.search\"\n placeholder=\"Search experiments...\"\n size=\"sm\"\n type=\"search\"\n />\n </div>\n <div class=\"mld-experiment-selector__status-filter\">\n <BaseSelect\n :model-value=\"filters.status ?? ''\"\n :options=\"statusOptions\"\n size=\"sm\"\n @update:model-value=\"handleStatusChange\"\n />\n </div>\n </div>\n\n <!-- Loading -->\n <div v-if=\"isLoading\" class=\"mld-experiment-selector__loading\">\n <LoadingSpinner size=\"md\" />\n </div>\n\n <!-- Error -->\n <div v-else-if=\"error\" class=\"mld-experiment-selector__error\">\n {{ error }}\n </div>\n\n <!-- Empty -->\n <EmptyState\n v-else-if=\"experiments.length === 0\"\n title=\"No experiments found\"\n description=\"Try adjusting your search or filters.\"\n size=\"sm\"\n />\n\n <!-- Experiment list -->\n <div v-else class=\"mld-experiment-selector__list\">\n <div\n v-for=\"exp in experiments\"\n :key=\"exp.id\"\n class=\"mld-experiment-selector__row\"\n :class=\"{ 'mld-experiment-selector__row--active': exp.id === currentExperimentId }\"\n @click=\"handleSelect(exp)\"\n >\n <div class=\"mld-experiment-selector__row-content\">\n <div class=\"mld-experiment-selector__name\">{{ exp.name }}</div>\n <div class=\"mld-experiment-selector__meta\">\n <span v-if=\"exp.project\">{{ exp.project }}</span>\n <span>{{ formatDate(exp.created_at) }}</span>\n </div>\n </div>\n <BasePill :variant=\"statusVariantMap[exp.status] as any\" size=\"sm\">\n {{ exp.status }}\n </BasePill>\n </div>\n </div>\n </div>\n </BaseModal>\n</template>\n\n<style>\n@import '../styles/components/experiment-selector-modal.css';\n</style>\n"],"names":["_createBlock","BaseModal","_createElementVNode","_createVNode","BaseInput","_unref","BaseSelect","_openBlock","_createElementBlock","LoadingSpinner","_toDisplayString","EmptyState","_Fragment","_renderList","BasePill","_createTextVNode"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ExperimentSelectorModal.vue3.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { FitState, FitResultSummary } from '../types';
|
|
2
|
+
interface Props {
|
|
3
|
+
state?: FitState;
|
|
4
|
+
progress?: number;
|
|
5
|
+
progressLabel?: string;
|
|
6
|
+
indeterminate?: boolean;
|
|
7
|
+
results?: FitResultSummary[];
|
|
8
|
+
errorMessage?: string;
|
|
9
|
+
runLabel?: string;
|
|
10
|
+
cancelLabel?: string;
|
|
11
|
+
disabled?: boolean;
|
|
12
|
+
}
|
|
13
|
+
declare function __VLS_template(): {
|
|
14
|
+
attrs: Partial<{}>;
|
|
15
|
+
slots: {
|
|
16
|
+
controls?(_: {}): any;
|
|
17
|
+
results?(_: {}): any;
|
|
18
|
+
footer?(_: {}): any;
|
|
19
|
+
};
|
|
20
|
+
refs: {};
|
|
21
|
+
rootEl: HTMLDivElement;
|
|
22
|
+
};
|
|
23
|
+
type __VLS_TemplateResult = ReturnType<typeof __VLS_template>;
|
|
24
|
+
declare const __VLS_component: import('vue').DefineComponent<Props, {}, {}, {}, {}, import('vue').ComponentOptionsMixin, import('vue').ComponentOptionsMixin, {
|
|
25
|
+
cancel: () => any;
|
|
26
|
+
run: () => any;
|
|
27
|
+
}, string, import('vue').PublicProps, Readonly<Props> & Readonly<{
|
|
28
|
+
onCancel?: (() => any) | undefined;
|
|
29
|
+
onRun?: (() => any) | undefined;
|
|
30
|
+
}>, {
|
|
31
|
+
disabled: boolean;
|
|
32
|
+
progress: number;
|
|
33
|
+
indeterminate: boolean;
|
|
34
|
+
state: FitState;
|
|
35
|
+
results: FitResultSummary[];
|
|
36
|
+
cancelLabel: string;
|
|
37
|
+
progressLabel: string;
|
|
38
|
+
runLabel: string;
|
|
39
|
+
}, {}, {}, {}, string, import('vue').ComponentProvideOptions, false, {}, HTMLDivElement>;
|
|
40
|
+
declare const _default: __VLS_WithTemplateSlots<typeof __VLS_component, __VLS_TemplateResult["slots"]>;
|
|
41
|
+
export default _default;
|
|
42
|
+
type __VLS_WithTemplateSlots<T, S> = T & {
|
|
43
|
+
new (): {
|
|
44
|
+
$slots: S;
|
|
45
|
+
};
|
|
46
|
+
};
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { defineComponent, computed, openBlock, createElementBlock, renderSlot, createElementVNode, createBlock, withCtx, createTextVNode, toDisplayString, createCommentVNode, createVNode, Fragment, renderList, normalizeClass } from "vue";
|
|
2
|
+
import _sfc_main$1 from "./BaseButton.vue.js";
|
|
3
|
+
/* empty css */
|
|
4
|
+
import _sfc_main$2 from "./ProgressBar.vue.js";
|
|
5
|
+
/* empty css */
|
|
6
|
+
import _sfc_main$3 from "./AlertBox.vue.js";
|
|
7
|
+
/* empty css */
|
|
8
|
+
const _hoisted_1 = { class: "mld-fit-panel" };
|
|
9
|
+
const _hoisted_2 = { class: "mld-fit-panel__actions" };
|
|
10
|
+
const _hoisted_3 = {
|
|
11
|
+
key: 0,
|
|
12
|
+
class: "mld-fit-panel__progress"
|
|
13
|
+
};
|
|
14
|
+
const _hoisted_4 = {
|
|
15
|
+
key: 1,
|
|
16
|
+
class: "mld-fit-panel__results"
|
|
17
|
+
};
|
|
18
|
+
const _hoisted_5 = { class: "mld-fit-panel__result-list" };
|
|
19
|
+
const _hoisted_6 = { class: "mld-fit-panel__result-label" };
|
|
20
|
+
const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
21
|
+
__name: "FitPanel",
|
|
22
|
+
props: {
|
|
23
|
+
state: { default: "idle" },
|
|
24
|
+
progress: { default: 0 },
|
|
25
|
+
progressLabel: { default: "Fitting..." },
|
|
26
|
+
indeterminate: { type: Boolean, default: false },
|
|
27
|
+
results: { default: () => [] },
|
|
28
|
+
errorMessage: {},
|
|
29
|
+
runLabel: { default: "Run Fit" },
|
|
30
|
+
cancelLabel: { default: "Cancel" },
|
|
31
|
+
disabled: { type: Boolean, default: false }
|
|
32
|
+
},
|
|
33
|
+
emits: ["run", "cancel"],
|
|
34
|
+
setup(__props, { emit: __emit }) {
|
|
35
|
+
const props = __props;
|
|
36
|
+
const emit = __emit;
|
|
37
|
+
const isRunning = computed(() => props.state === "running");
|
|
38
|
+
const showRunButton = computed(() => !isRunning.value);
|
|
39
|
+
const showResults = computed(() => props.state === "completed" && props.results.length > 0);
|
|
40
|
+
const showError = computed(() => props.state === "error" && props.errorMessage);
|
|
41
|
+
function variantClass(variant) {
|
|
42
|
+
if (!variant || variant === "default") return "";
|
|
43
|
+
return `mld-fit-panel__result-value--${variant}`;
|
|
44
|
+
}
|
|
45
|
+
return (_ctx, _cache) => {
|
|
46
|
+
return openBlock(), createElementBlock("div", _hoisted_1, [
|
|
47
|
+
renderSlot(_ctx.$slots, "controls"),
|
|
48
|
+
createElementVNode("div", _hoisted_2, [
|
|
49
|
+
showRunButton.value ? (openBlock(), createBlock(_sfc_main$1, {
|
|
50
|
+
key: 0,
|
|
51
|
+
variant: "primary",
|
|
52
|
+
size: "sm",
|
|
53
|
+
disabled: __props.disabled,
|
|
54
|
+
"full-width": "",
|
|
55
|
+
onClick: _cache[0] || (_cache[0] = ($event) => emit("run"))
|
|
56
|
+
}, {
|
|
57
|
+
default: withCtx(() => [
|
|
58
|
+
createTextVNode(toDisplayString(__props.runLabel), 1)
|
|
59
|
+
]),
|
|
60
|
+
_: 1
|
|
61
|
+
}, 8, ["disabled"])) : createCommentVNode("", true),
|
|
62
|
+
isRunning.value ? (openBlock(), createBlock(_sfc_main$1, {
|
|
63
|
+
key: 1,
|
|
64
|
+
variant: "ghost",
|
|
65
|
+
size: "sm",
|
|
66
|
+
"full-width": "",
|
|
67
|
+
onClick: _cache[1] || (_cache[1] = ($event) => emit("cancel"))
|
|
68
|
+
}, {
|
|
69
|
+
default: withCtx(() => [
|
|
70
|
+
createTextVNode(toDisplayString(__props.cancelLabel), 1)
|
|
71
|
+
]),
|
|
72
|
+
_: 1
|
|
73
|
+
})) : createCommentVNode("", true)
|
|
74
|
+
]),
|
|
75
|
+
isRunning.value ? (openBlock(), createElementBlock("div", _hoisted_3, [
|
|
76
|
+
createVNode(_sfc_main$2, {
|
|
77
|
+
value: __props.progress,
|
|
78
|
+
label: __props.progressLabel,
|
|
79
|
+
indeterminate: __props.indeterminate,
|
|
80
|
+
"show-value": !__props.indeterminate,
|
|
81
|
+
size: "sm"
|
|
82
|
+
}, null, 8, ["value", "label", "indeterminate", "show-value"])
|
|
83
|
+
])) : createCommentVNode("", true),
|
|
84
|
+
showResults.value ? (openBlock(), createElementBlock("div", _hoisted_4, [
|
|
85
|
+
renderSlot(_ctx.$slots, "results", {}, () => [
|
|
86
|
+
createElementVNode("div", _hoisted_5, [
|
|
87
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.results, (item, idx) => {
|
|
88
|
+
return openBlock(), createElementBlock("div", {
|
|
89
|
+
key: idx,
|
|
90
|
+
class: "mld-fit-panel__result-row"
|
|
91
|
+
}, [
|
|
92
|
+
createElementVNode("span", _hoisted_6, toDisplayString(item.label), 1),
|
|
93
|
+
createElementVNode("span", {
|
|
94
|
+
class: normalizeClass(["mld-fit-panel__result-value", variantClass(item.variant)])
|
|
95
|
+
}, toDisplayString(item.value), 3)
|
|
96
|
+
]);
|
|
97
|
+
}), 128))
|
|
98
|
+
])
|
|
99
|
+
])
|
|
100
|
+
])) : createCommentVNode("", true),
|
|
101
|
+
showError.value ? (openBlock(), createBlock(_sfc_main$3, {
|
|
102
|
+
key: 2,
|
|
103
|
+
type: "error"
|
|
104
|
+
}, {
|
|
105
|
+
default: withCtx(() => [
|
|
106
|
+
createTextVNode(toDisplayString(__props.errorMessage), 1)
|
|
107
|
+
]),
|
|
108
|
+
_: 1
|
|
109
|
+
})) : createCommentVNode("", true),
|
|
110
|
+
renderSlot(_ctx.$slots, "footer")
|
|
111
|
+
]);
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
export {
|
|
116
|
+
_sfc_main as default
|
|
117
|
+
};
|
|
118
|
+
//# sourceMappingURL=FitPanel.vue.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FitPanel.vue.js","sources":["../../src/components/FitPanel.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { FitState, FitResultSummary } from '../types'\nimport BaseButton from './BaseButton.vue'\nimport ProgressBar from './ProgressBar.vue'\nimport AlertBox from './AlertBox.vue'\n\ninterface Props {\n state?: FitState\n progress?: number\n progressLabel?: string\n indeterminate?: boolean\n results?: FitResultSummary[]\n errorMessage?: string\n runLabel?: string\n cancelLabel?: string\n disabled?: boolean\n}\n\nconst props = withDefaults(defineProps<Props>(), {\n state: 'idle',\n progress: 0,\n progressLabel: 'Fitting...',\n indeterminate: false,\n results: () => [],\n runLabel: 'Run Fit',\n cancelLabel: 'Cancel',\n disabled: false,\n})\n\nconst emit = defineEmits<{\n run: []\n cancel: []\n}>()\n\nconst isRunning = computed(() => props.state === 'running')\nconst showRunButton = computed(() => !isRunning.value)\nconst showResults = computed(() => props.state === 'completed' && props.results.length > 0)\nconst showError = computed(() => props.state === 'error' && props.errorMessage)\n\nfunction variantClass(variant?: string): string {\n if (!variant || variant === 'default') return ''\n return `mld-fit-panel__result-value--${variant}`\n}\n</script>\n\n<template>\n <div class=\"mld-fit-panel\">\n <!-- Plugin controls slot -->\n <slot name=\"controls\" />\n\n <!-- Action bar -->\n <div class=\"mld-fit-panel__actions\">\n <BaseButton\n v-if=\"showRunButton\"\n variant=\"primary\"\n size=\"sm\"\n :disabled=\"disabled\"\n full-width\n @click=\"emit('run')\"\n >\n {{ runLabel }}\n </BaseButton>\n <BaseButton\n v-if=\"isRunning\"\n variant=\"ghost\"\n size=\"sm\"\n full-width\n @click=\"emit('cancel')\"\n >\n {{ cancelLabel }}\n </BaseButton>\n </div>\n\n <!-- Progress -->\n <div v-if=\"isRunning\" class=\"mld-fit-panel__progress\">\n <ProgressBar\n :value=\"progress\"\n :label=\"progressLabel\"\n :indeterminate=\"indeterminate\"\n :show-value=\"!indeterminate\"\n size=\"sm\"\n />\n </div>\n\n <!-- Results -->\n <div v-if=\"showResults\" class=\"mld-fit-panel__results\">\n <slot name=\"results\">\n <div class=\"mld-fit-panel__result-list\">\n <div\n v-for=\"(item, idx) in results\"\n :key=\"idx\"\n class=\"mld-fit-panel__result-row\"\n >\n <span class=\"mld-fit-panel__result-label\">{{ item.label }}</span>\n <span\n class=\"mld-fit-panel__result-value\"\n :class=\"variantClass(item.variant)\"\n >\n {{ item.value }}\n </span>\n </div>\n </div>\n </slot>\n </div>\n\n <!-- Error -->\n <AlertBox v-if=\"showError\" type=\"error\">\n {{ errorMessage }}\n </AlertBox>\n\n <!-- Footer slot -->\n <slot name=\"footer\" />\n </div>\n</template>\n\n<style>\n@import '../styles/components/fit-panel.css';\n</style>\n"],"names":["_openBlock","_createElementBlock","_renderSlot","_createElementVNode","_createBlock","BaseButton","_createVNode","ProgressBar","_Fragment","_renderList","_toDisplayString","AlertBox"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmBA,UAAM,QAAQ;AAWd,UAAM,OAAO;AAKb,UAAM,YAAY,SAAS,MAAM,MAAM,UAAU,SAAS;AAC1D,UAAM,gBAAgB,SAAS,MAAM,CAAC,UAAU,KAAK;AACrD,UAAM,cAAc,SAAS,MAAM,MAAM,UAAU,eAAe,MAAM,QAAQ,SAAS,CAAC;AAC1F,UAAM,YAAY,SAAS,MAAM,MAAM,UAAU,WAAW,MAAM,YAAY;AAE9E,aAAS,aAAa,SAA0B;AAC9C,UAAI,CAAC,WAAW,YAAY,UAAW,QAAO;AAC9C,aAAO,gCAAgC,OAAO;AAAA,IAChD;;AAIE,aAAAA,UAAA,GAAAC,mBAkEM,OAlEN,YAkEM;AAAA,QAhEJC,WAAwB,KAAA,QAAA,UAAA;AAAA,QAGxBC,mBAoBM,OApBN,YAoBM;AAAA,UAlBI,cAAA,sBADRC,YASaC,aAAA;AAAA;YAPX,SAAQ;AAAA,YACR,MAAK;AAAA,YACJ,UAAU,QAAA;AAAA,YACX,cAAA;AAAA,YACC,+CAAO,KAAI,KAAA;AAAA,UAAA;6BAEZ,MAAc;AAAA,8CAAX,QAAA,QAAQ,GAAA,CAAA;AAAA,YAAA;;;UAGL,UAAA,sBADRD,YAQaC,aAAA;AAAA;YANX,SAAQ;AAAA,YACR,MAAK;AAAA,YACL,cAAA;AAAA,YACC,+CAAO,KAAI,QAAA;AAAA,UAAA;6BAEZ,MAAiB;AAAA,8CAAd,QAAA,WAAW,GAAA,CAAA;AAAA,YAAA;;;;QAKP,UAAA,SAAXL,UAAA,GAAAC,mBAQM,OARN,YAQM;AAAA,UAPJK,YAMEC,aAAA;AAAA,YALC,OAAO,QAAA;AAAA,YACP,OAAO,QAAA;AAAA,YACP,eAAe,QAAA;AAAA,YACf,eAAa,QAAA;AAAA,YACd,MAAK;AAAA,UAAA;;QAKE,YAAA,SAAXP,UAAA,GAAAC,mBAkBM,OAlBN,YAkBM;AAAA,UAjBJC,WAgBO,4BAhBP,MAgBO;AAAA,YAfLC,mBAcM,OAdN,YAcM;AAAA,eAbJH,UAAA,IAAA,GAAAC,mBAYMO,UAAA,MAAAC,WAXkB,QAAA,SAAO,CAArB,MAAM,QAAG;oCADnBR,mBAYM,OAAA;AAAA,kBAVH,KAAK;AAAA,kBACN,OAAM;AAAA,gBAAA;kBAENE,mBAAiE,QAAjE,YAAiEO,gBAApB,KAAK,KAAK,GAAA,CAAA;AAAA,kBACvDP,mBAKO,QAAA;AAAA,oBAJL,uBAAM,+BACE,aAAa,KAAK,OAAO,CAAA,CAAA;AAAA,kBAAA,GAE9BO,gBAAA,KAAK,KAAK,GAAA,CAAA;AAAA,gBAAA;;;;;QAQP,UAAA,sBAAhBN,YAEWO,aAAA;AAAA;UAFgB,MAAK;AAAA,QAAA;2BAC9B,MAAkB;AAAA,4CAAf,QAAA,YAAY,GAAA,CAAA;AAAA,UAAA;;;QAIjBT,WAAsB,KAAA,QAAA,QAAA;AAAA,MAAA;;;;"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FitPanel.vue3.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;"}
|
|
@@ -76,3 +76,5 @@ export { default as DateTimePicker } from './DateTimePicker.vue';
|
|
|
76
76
|
export { default as TimeRangeInput } from './TimeRangeInput.vue';
|
|
77
77
|
export { default as ScheduleCalendar } from './ScheduleCalendar.vue';
|
|
78
78
|
export { default as ResourceCard } from './ResourceCard.vue';
|
|
79
|
+
export { default as ExperimentSelectorModal } from './ExperimentSelectorModal.vue';
|
|
80
|
+
export { default as FitPanel } from './FitPanel.vue';
|
package/dist/components/index.js
CHANGED
|
@@ -152,6 +152,10 @@ import { default as default78 } from "./ScheduleCalendar.vue.js";
|
|
|
152
152
|
/* empty css */
|
|
153
153
|
import { default as default79 } from "./ResourceCard.vue.js";
|
|
154
154
|
/* empty css */
|
|
155
|
+
import { default as default80 } from "./ExperimentSelectorModal.vue.js";
|
|
156
|
+
/* empty css */
|
|
157
|
+
import { default as default81 } from "./FitPanel.vue.js";
|
|
158
|
+
/* empty css */
|
|
155
159
|
export {
|
|
156
160
|
default25 as AlertBox,
|
|
157
161
|
default34 as AppContainer,
|
|
@@ -190,8 +194,10 @@ export {
|
|
|
190
194
|
default41 as EmptyState,
|
|
191
195
|
default75 as ExperimentCodeBadge,
|
|
192
196
|
default74 as ExperimentDataViewer,
|
|
197
|
+
default80 as ExperimentSelectorModal,
|
|
193
198
|
default51 as ExperimentTimeline,
|
|
194
199
|
default24 as FileUploader,
|
|
200
|
+
default81 as FitPanel,
|
|
195
201
|
default72 as FormActions,
|
|
196
202
|
default70 as FormBuilder,
|
|
197
203
|
default19 as FormField,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -18,4 +18,5 @@ export { useScheduleDrag } from './useScheduleDrag';
|
|
|
18
18
|
export { useFormBuilder, evaluateCondition } from './useFormBuilder';
|
|
19
19
|
export { useAutoGroup, DEFAULT_COLORS } from './useAutoGroup';
|
|
20
20
|
export { usePluginConfig, type UsePluginConfigReturn } from './usePluginConfig';
|
|
21
|
+
export { useExperimentSelector, type UseExperimentSelectorOptions, type UseExperimentSelectorReturn, } from './useExperimentSelector';
|
|
21
22
|
export { getFieldRegistryEntry, getTypeDefault, type RegistryEntry, } from './formBuilderRegistry';
|
|
@@ -18,6 +18,7 @@ import { useScheduleDrag } from "./useScheduleDrag.js";
|
|
|
18
18
|
import { evaluateCondition, useFormBuilder } from "./useFormBuilder.js";
|
|
19
19
|
import { DEFAULT_COLORS, useAutoGroup } from "./useAutoGroup.js";
|
|
20
20
|
import { usePluginConfig } from "./usePluginConfig.js";
|
|
21
|
+
import { useExperimentSelector } from "./useExperimentSelector.js";
|
|
21
22
|
import { getFieldRegistryEntry, getTypeDefault } from "./formBuilderRegistry.js";
|
|
22
23
|
export {
|
|
23
24
|
ATOMIC_WEIGHTS,
|
|
@@ -44,6 +45,7 @@ export {
|
|
|
44
45
|
useChemicalFormula,
|
|
45
46
|
useConcentrationUnits,
|
|
46
47
|
useDoseCalculator,
|
|
48
|
+
useExperimentSelector,
|
|
47
49
|
useForm,
|
|
48
50
|
useFormBuilder,
|
|
49
51
|
usePasskey,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { Ref } from 'vue';
|
|
2
|
+
import { ExperimentSummary, ExperimentFilters } from '../types';
|
|
3
|
+
export interface UseExperimentSelectorOptions {
|
|
4
|
+
experimentType?: string;
|
|
5
|
+
apiBaseUrl?: string;
|
|
6
|
+
limit?: number;
|
|
7
|
+
immediate?: boolean;
|
|
8
|
+
}
|
|
9
|
+
export interface UseExperimentSelectorReturn {
|
|
10
|
+
experiments: Ref<ExperimentSummary[]>;
|
|
11
|
+
total: Ref<number>;
|
|
12
|
+
selectedExperiment: Ref<ExperimentSummary | null>;
|
|
13
|
+
filters: ExperimentFilters;
|
|
14
|
+
isLoading: Ref<boolean>;
|
|
15
|
+
error: Ref<string | null>;
|
|
16
|
+
fetch: () => Promise<void>;
|
|
17
|
+
select: (experiment: ExperimentSummary) => void;
|
|
18
|
+
clear: () => void;
|
|
19
|
+
}
|
|
20
|
+
export declare function useExperimentSelector(options?: UseExperimentSelectorOptions): UseExperimentSelectorReturn;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { ref, reactive, watch } from "vue";
|
|
2
|
+
import { useApi } from "./useApi.js";
|
|
3
|
+
function useExperimentSelector(options = {}) {
|
|
4
|
+
const { limit = 100, immediate = false, experimentType, apiBaseUrl } = options;
|
|
5
|
+
const api = useApi({ baseUrl: apiBaseUrl });
|
|
6
|
+
const experiments = ref([]);
|
|
7
|
+
const total = ref(0);
|
|
8
|
+
const selectedExperiment = ref(null);
|
|
9
|
+
const isLoading = ref(false);
|
|
10
|
+
const error = ref(null);
|
|
11
|
+
const filters = reactive({
|
|
12
|
+
search: void 0,
|
|
13
|
+
status: void 0,
|
|
14
|
+
project: void 0
|
|
15
|
+
});
|
|
16
|
+
async function fetchExperiments() {
|
|
17
|
+
isLoading.value = true;
|
|
18
|
+
error.value = null;
|
|
19
|
+
try {
|
|
20
|
+
const params = new URLSearchParams();
|
|
21
|
+
if (experimentType) params.set("experiment_type", experimentType);
|
|
22
|
+
if (filters.status) params.set("status", filters.status);
|
|
23
|
+
if (filters.search) params.set("search", filters.search);
|
|
24
|
+
if (filters.project) params.set("project", filters.project);
|
|
25
|
+
params.set("limit", String(limit));
|
|
26
|
+
const query = params.toString();
|
|
27
|
+
const url = `/api/experiments${query ? `?${query}` : ""}`;
|
|
28
|
+
const data = await api.get(url);
|
|
29
|
+
experiments.value = data.experiments;
|
|
30
|
+
total.value = data.total;
|
|
31
|
+
} catch (e) {
|
|
32
|
+
error.value = e instanceof Error ? e.message : "Failed to fetch experiments";
|
|
33
|
+
experiments.value = [];
|
|
34
|
+
total.value = 0;
|
|
35
|
+
} finally {
|
|
36
|
+
isLoading.value = false;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function select(experiment) {
|
|
40
|
+
selectedExperiment.value = experiment;
|
|
41
|
+
}
|
|
42
|
+
function clear() {
|
|
43
|
+
selectedExperiment.value = null;
|
|
44
|
+
filters.search = void 0;
|
|
45
|
+
filters.status = void 0;
|
|
46
|
+
filters.project = void 0;
|
|
47
|
+
}
|
|
48
|
+
let debounceTimer = null;
|
|
49
|
+
watch(
|
|
50
|
+
() => filters.search,
|
|
51
|
+
() => {
|
|
52
|
+
if (debounceTimer) clearTimeout(debounceTimer);
|
|
53
|
+
debounceTimer = setTimeout(() => {
|
|
54
|
+
fetchExperiments();
|
|
55
|
+
}, 300);
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
watch(
|
|
59
|
+
() => [filters.status, filters.project],
|
|
60
|
+
() => {
|
|
61
|
+
fetchExperiments();
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
if (immediate) {
|
|
65
|
+
fetchExperiments();
|
|
66
|
+
}
|
|
67
|
+
return {
|
|
68
|
+
experiments,
|
|
69
|
+
total,
|
|
70
|
+
selectedExperiment,
|
|
71
|
+
filters,
|
|
72
|
+
isLoading,
|
|
73
|
+
error,
|
|
74
|
+
fetch: fetchExperiments,
|
|
75
|
+
select,
|
|
76
|
+
clear
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
export {
|
|
80
|
+
useExperimentSelector
|
|
81
|
+
};
|
|
82
|
+
//# sourceMappingURL=useExperimentSelector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useExperimentSelector.js","sources":["../../src/composables/useExperimentSelector.ts"],"sourcesContent":["import { ref, reactive, watch, type Ref } from 'vue'\nimport { useApi } from './useApi'\nimport type { ExperimentSummary, ExperimentListResponse, ExperimentFilters } from '../types'\n\nexport interface UseExperimentSelectorOptions {\n experimentType?: string\n apiBaseUrl?: string\n limit?: number\n immediate?: boolean\n}\n\nexport interface UseExperimentSelectorReturn {\n experiments: Ref<ExperimentSummary[]>\n total: Ref<number>\n selectedExperiment: Ref<ExperimentSummary | null>\n filters: ExperimentFilters\n isLoading: Ref<boolean>\n error: Ref<string | null>\n fetch: () => Promise<void>\n select: (experiment: ExperimentSummary) => void\n clear: () => void\n}\n\nexport function useExperimentSelector(\n options: UseExperimentSelectorOptions = {},\n): UseExperimentSelectorReturn {\n const { limit = 100, immediate = false, experimentType, apiBaseUrl } = options\n const api = useApi({ baseUrl: apiBaseUrl })\n\n const experiments = ref<ExperimentSummary[]>([])\n const total = ref(0)\n const selectedExperiment = ref<ExperimentSummary | null>(null)\n const isLoading = ref(false)\n const error = ref<string | null>(null)\n\n const filters: ExperimentFilters = reactive({\n search: undefined,\n status: undefined,\n project: undefined,\n })\n\n async function fetchExperiments(): Promise<void> {\n isLoading.value = true\n error.value = null\n try {\n const params = new URLSearchParams()\n if (experimentType) params.set('experiment_type', experimentType)\n if (filters.status) params.set('status', filters.status)\n if (filters.search) params.set('search', filters.search)\n if (filters.project) params.set('project', filters.project)\n params.set('limit', String(limit))\n\n const query = params.toString()\n const url = `/api/experiments${query ? `?${query}` : ''}`\n const data = await api.get<ExperimentListResponse>(url)\n experiments.value = data.experiments\n total.value = data.total\n } catch (e) {\n error.value = e instanceof Error ? e.message : 'Failed to fetch experiments'\n experiments.value = []\n total.value = 0\n } finally {\n isLoading.value = false\n }\n }\n\n function select(experiment: ExperimentSummary): void {\n selectedExperiment.value = experiment\n }\n\n function clear(): void {\n selectedExperiment.value = null\n filters.search = undefined\n filters.status = undefined\n filters.project = undefined\n }\n\n // Debounced watch on search filter\n let debounceTimer: ReturnType<typeof setTimeout> | null = null\n watch(\n () => filters.search,\n () => {\n if (debounceTimer) clearTimeout(debounceTimer)\n debounceTimer = setTimeout(() => {\n fetchExperiments()\n }, 300)\n },\n )\n\n // Immediate watch on status/project filters (no debounce needed)\n watch(\n () => [filters.status, filters.project],\n () => {\n fetchExperiments()\n },\n )\n\n if (immediate) {\n fetchExperiments()\n }\n\n return {\n experiments,\n total,\n selectedExperiment,\n filters,\n isLoading,\n error,\n fetch: fetchExperiments,\n select,\n clear,\n }\n}\n"],"names":[],"mappings":";;AAuBO,SAAS,sBACd,UAAwC,IACX;AAC7B,QAAM,EAAE,QAAQ,KAAK,YAAY,OAAO,gBAAgB,eAAe;AACvE,QAAM,MAAM,OAAO,EAAE,SAAS,YAAY;AAE1C,QAAM,cAAc,IAAyB,EAAE;AAC/C,QAAM,QAAQ,IAAI,CAAC;AACnB,QAAM,qBAAqB,IAA8B,IAAI;AAC7D,QAAM,YAAY,IAAI,KAAK;AAC3B,QAAM,QAAQ,IAAmB,IAAI;AAErC,QAAM,UAA6B,SAAS;AAAA,IAC1C,QAAQ;AAAA,IACR,QAAQ;AAAA,IACR,SAAS;AAAA,EAAA,CACV;AAED,iBAAe,mBAAkC;AAC/C,cAAU,QAAQ;AAClB,UAAM,QAAQ;AACd,QAAI;AACF,YAAM,SAAS,IAAI,gBAAA;AACnB,UAAI,eAAgB,QAAO,IAAI,mBAAmB,cAAc;AAChE,UAAI,QAAQ,OAAQ,QAAO,IAAI,UAAU,QAAQ,MAAM;AACvD,UAAI,QAAQ,OAAQ,QAAO,IAAI,UAAU,QAAQ,MAAM;AACvD,UAAI,QAAQ,QAAS,QAAO,IAAI,WAAW,QAAQ,OAAO;AAC1D,aAAO,IAAI,SAAS,OAAO,KAAK,CAAC;AAEjC,YAAM,QAAQ,OAAO,SAAA;AACrB,YAAM,MAAM,mBAAmB,QAAQ,IAAI,KAAK,KAAK,EAAE;AACvD,YAAM,OAAO,MAAM,IAAI,IAA4B,GAAG;AACtD,kBAAY,QAAQ,KAAK;AACzB,YAAM,QAAQ,KAAK;AAAA,IACrB,SAAS,GAAG;AACV,YAAM,QAAQ,aAAa,QAAQ,EAAE,UAAU;AAC/C,kBAAY,QAAQ,CAAA;AACpB,YAAM,QAAQ;AAAA,IAChB,UAAA;AACE,gBAAU,QAAQ;AAAA,IACpB;AAAA,EACF;AAEA,WAAS,OAAO,YAAqC;AACnD,uBAAmB,QAAQ;AAAA,EAC7B;AAEA,WAAS,QAAc;AACrB,uBAAmB,QAAQ;AAC3B,YAAQ,SAAS;AACjB,YAAQ,SAAS;AACjB,YAAQ,UAAU;AAAA,EACpB;AAGA,MAAI,gBAAsD;AAC1D;AAAA,IACE,MAAM,QAAQ;AAAA,IACd,MAAM;AACJ,UAAI,4BAA4B,aAAa;AAC7C,sBAAgB,WAAW,MAAM;AAC/B,yBAAA;AAAA,MACF,GAAG,GAAG;AAAA,IACR;AAAA,EAAA;AAIF;AAAA,IACE,MAAM,CAAC,QAAQ,QAAQ,QAAQ,OAAO;AAAA,IACtC,MAAM;AACJ,uBAAA;AAAA,IACF;AAAA,EAAA;AAGF,MAAI,WAAW;AACb,qBAAA;AAAA,EACF;AAEA,SAAO;AAAA,IACL;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA;AAAA,IACA,OAAO;AAAA,IACP;AAAA,IACA;AAAA,EAAA;AAEJ;"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { MLDSdk, default } from './install';
|
|
2
|
-
export { BaseButton, BaseInput, BaseTextarea, BaseSelect, BaseCheckbox, BaseToggle, BaseRadioGroup, BaseSlider, ColorSlider, BaseTabs, BaseModal, FormField, DatePicker, TimePicker, TagsInput, NumberInput, FileUploader, AlertBox, ToastNotification, IconButton, ThemeToggle, SettingsButton, CollapsibleCard, AppTopBar, AppSidebar, AppLayout, AppContainer, Skeleton, WellPlate, RackEditor, SampleLegend, PlateMapEditor, ExperimentTimeline, SampleSelector, GroupingModal, AutoGroupModal, GroupAssigner, MoleculeInput, ConcentrationInput, DoseCalculator, ReagentList, SampleHierarchyTree, ProtocolStepEditor, SegmentedControl, MultiSelect, BasePill, DropdownButton, Calendar, DataFrame, LoadingSpinner, Divider, StatusIndicator, ProgressBar, Avatar, EmptyState, Breadcrumb, Tooltip, ConfirmDialog, ChartContainer, SettingsModal, ScientificNumber, ChemicalFormula, FormulaInput, SequenceInput, UnitInput, StepWizard, AuditTrail, BatchProgressList, ExperimentDataViewer, ExperimentCodeBadge, DateTimePicker, TimeRangeInput, ScheduleCalendar, ResourceCard, } from './components';
|
|
3
|
-
export { useApi, useAuth, usePasskey, useTheme, useToast, usePlatformContext, useWellPlateEditor, useConcentrationUnits, useDoseCalculator, useProtocolTemplates, useRackEditor, useChemicalFormula, ATOMIC_WEIGHTS, useSequenceUtils, type ApiClientOptions, type UseWellPlateEditorOptions, type UseWellPlateEditorReturn, type UseRackEditorOptions, type UseRackEditorReturn, type ConcentrationValue, type ConcentrationUnit, type VolumeValue, type VolumeUnit, type StepTemplate, type FormulaParseResult, type FormulaPart, type SequenceType, type SequenceStats, parseTime, formatTime, generateTimeSlots, rangesOverlap, durationMinutes, formatDuration, isTimeInRange, findAvailableSlots, snapToSlot, addMinutes, compareTime, useScheduleDrag, usePluginConfig, type UsePluginConfigReturn, useAutoGroup, DEFAULT_COLORS, } from './composables';
|
|
2
|
+
export { BaseButton, BaseInput, BaseTextarea, BaseSelect, BaseCheckbox, BaseToggle, BaseRadioGroup, BaseSlider, ColorSlider, BaseTabs, BaseModal, FormField, DatePicker, TimePicker, TagsInput, NumberInput, FileUploader, AlertBox, ToastNotification, IconButton, ThemeToggle, SettingsButton, CollapsibleCard, AppTopBar, AppSidebar, AppLayout, AppContainer, Skeleton, WellPlate, RackEditor, SampleLegend, PlateMapEditor, ExperimentTimeline, SampleSelector, GroupingModal, AutoGroupModal, GroupAssigner, MoleculeInput, ConcentrationInput, DoseCalculator, ReagentList, SampleHierarchyTree, ProtocolStepEditor, SegmentedControl, MultiSelect, BasePill, DropdownButton, Calendar, DataFrame, LoadingSpinner, Divider, StatusIndicator, ProgressBar, Avatar, EmptyState, Breadcrumb, Tooltip, ConfirmDialog, ChartContainer, SettingsModal, ScientificNumber, ChemicalFormula, FormulaInput, SequenceInput, UnitInput, StepWizard, AuditTrail, BatchProgressList, ExperimentDataViewer, ExperimentCodeBadge, DateTimePicker, TimeRangeInput, ScheduleCalendar, ResourceCard, ExperimentSelectorModal, FitPanel, } from './components';
|
|
3
|
+
export { useApi, useAuth, usePasskey, useTheme, useToast, usePlatformContext, useWellPlateEditor, useConcentrationUnits, useDoseCalculator, useProtocolTemplates, useRackEditor, useChemicalFormula, ATOMIC_WEIGHTS, useSequenceUtils, type ApiClientOptions, type UseWellPlateEditorOptions, type UseWellPlateEditorReturn, type UseRackEditorOptions, type UseRackEditorReturn, type ConcentrationValue, type ConcentrationUnit, type VolumeValue, type VolumeUnit, type StepTemplate, type FormulaParseResult, type FormulaPart, type SequenceType, type SequenceStats, parseTime, formatTime, generateTimeSlots, rangesOverlap, durationMinutes, formatDuration, isTimeInRange, findAvailableSlots, snapToSlot, addMinutes, compareTime, useScheduleDrag, usePluginConfig, type UsePluginConfigReturn, useAutoGroup, DEFAULT_COLORS, useExperimentSelector, type UseExperimentSelectorOptions, type UseExperimentSelectorReturn, } from './composables';
|
|
4
4
|
export { useAuthStore, useSettingsStore, colorPalettes, type SettingsState, } from './stores';
|
|
5
|
-
export type { ContainerDirection, ButtonVariant, ButtonSize, InputType, ModalSize, AlertType, Toast, TabItem, SelectOption, RadioOption, FormFieldProps, SidebarToolSection, CollapsibleState, TopBarVariant, TopBarPage, TopBarTab, TopBarTabOption, TopBarSettingsConfig, WellPlateFormat, WellState, WellPlateSelectionMode, Well, HeatmapColorScale, HeatmapConfig, SlotPosition, WellExtendedData, WellEditData, WellEditField, WellLegendItem, Rack, SampleType, PlateMap, PlateMapEditorState, ProtocolStepType, ProtocolStepStatus, ProtocolStep, SampleGroup, GroupItem, OutlierAction, InputMode, OutlierInfo, ColumnInfo, MetadataRow, AutoGroupResult, ParsedCsvData, FileUploaderMode, SegmentedOption, SegmentedControlVariant, SegmentedControlSize, MultiSelectOption, MultiSelectSize, PillVariant, PillSize, CalendarSelectionMode, CalendarMarker, CalendarDayContext, SortDirection, SortState, DataFrameColumn, PaginationState, SpinnerSize, SpinnerVariant, DividerSpacing, StatusType, ProgressVariant, ProgressSize, AvatarSize, EmptyStateColor, EmptyStateSize, BreadcrumbItem, TooltipPosition, ConfirmVariant, SettingsTab, NumberNotation, TimePickerFormat, TimeRange, ScheduleView, ScheduleEventStatus, ScheduleEvent, ScheduleBlockedSlot, ScheduleSlotContext, ScheduleEventCreateContext, ScheduleEventUpdateContext, ResourceStatus, ResourceSpec, UnitOption, WizardStep, WizardStepState, AuditEntryType, AuditEntry, BatchItemStatus, BatchItem, BatchSummary, AuthConfig, UserInfo, LoginResponse, TokenVerifyResponse, RegisterRequest, UpdateProfileRequest, CredentialInfo, SummaryData, SummarySection, SummarySectionItem, TreeNode, TreeNodeType, PluginInfo, PluginNavItem, PluginSettings, PluginSettingField, PlatformContext, PlatformEventType, PlatformEvent, ThemeMode, ColorPalette, TableDensity, } from './types';
|
|
5
|
+
export type { ContainerDirection, ButtonVariant, ButtonSize, InputType, ModalSize, AlertType, Toast, TabItem, SelectOption, RadioOption, FormFieldProps, SidebarToolSection, CollapsibleState, TopBarVariant, TopBarPage, TopBarTab, TopBarTabOption, TopBarSettingsConfig, WellPlateFormat, WellState, WellPlateSelectionMode, Well, HeatmapColorScale, HeatmapConfig, SlotPosition, WellExtendedData, WellEditData, WellEditField, WellLegendItem, Rack, SampleType, PlateMap, PlateMapEditorState, ProtocolStepType, ProtocolStepStatus, ProtocolStep, SampleGroup, GroupItem, OutlierAction, InputMode, OutlierInfo, ColumnInfo, MetadataRow, AutoGroupResult, ParsedCsvData, FileUploaderMode, SegmentedOption, SegmentedControlVariant, SegmentedControlSize, MultiSelectOption, MultiSelectSize, PillVariant, PillSize, CalendarSelectionMode, CalendarMarker, CalendarDayContext, SortDirection, SortState, DataFrameColumn, PaginationState, SpinnerSize, SpinnerVariant, DividerSpacing, StatusType, ProgressVariant, ProgressSize, AvatarSize, EmptyStateColor, EmptyStateSize, BreadcrumbItem, TooltipPosition, ConfirmVariant, SettingsTab, NumberNotation, TimePickerFormat, TimeRange, ScheduleView, ScheduleEventStatus, ScheduleEvent, ScheduleBlockedSlot, ScheduleSlotContext, ScheduleEventCreateContext, ScheduleEventUpdateContext, ResourceStatus, ResourceSpec, ExperimentStatus, ExperimentSummary, ExperimentListResponse, ExperimentFilters, FitState, FitResultSummary, UnitOption, WizardStep, WizardStepState, AuditEntryType, AuditEntry, BatchItemStatus, BatchItem, BatchSummary, AuthConfig, UserInfo, LoginResponse, TokenVerifyResponse, RegisterRequest, UpdateProfileRequest, CredentialInfo, SummaryData, SummarySection, SummarySectionItem, TreeNode, TreeNodeType, PluginInfo, PluginNavItem, PluginSettings, PluginSettingField, PlatformContext, PlatformEventType, PlatformEvent, ThemeMode, ColorPalette, TableDensity, } from './types';
|
package/dist/index.js
CHANGED
|
@@ -147,6 +147,10 @@ import { default as default74 } from "./components/ScheduleCalendar.vue.js";
|
|
|
147
147
|
/* empty css */
|
|
148
148
|
import { default as default75 } from "./components/ResourceCard.vue.js";
|
|
149
149
|
/* empty css */
|
|
150
|
+
import { default as default76 } from "./components/ExperimentSelectorModal.vue.js";
|
|
151
|
+
/* empty css */
|
|
152
|
+
import { default as default77 } from "./components/FitPanel.vue.js";
|
|
153
|
+
/* empty css */
|
|
150
154
|
import { useApi } from "./composables/useApi.js";
|
|
151
155
|
import { useAuth } from "./composables/useAuth.js";
|
|
152
156
|
import { usePasskey } from "./composables/usePasskey.js";
|
|
@@ -164,6 +168,7 @@ import { addMinutes, compareTime, durationMinutes, findAvailableSlots, formatDur
|
|
|
164
168
|
import { useScheduleDrag } from "./composables/useScheduleDrag.js";
|
|
165
169
|
import { DEFAULT_COLORS, useAutoGroup } from "./composables/useAutoGroup.js";
|
|
166
170
|
import { usePluginConfig } from "./composables/usePluginConfig.js";
|
|
171
|
+
import { useExperimentSelector } from "./composables/useExperimentSelector.js";
|
|
167
172
|
import { useAuthStore } from "./stores/auth.js";
|
|
168
173
|
import { colorPalettes, useSettingsStore } from "./stores/settings.js";
|
|
169
174
|
export {
|
|
@@ -206,8 +211,10 @@ export {
|
|
|
206
211
|
default41 as EmptyState,
|
|
207
212
|
default71 as ExperimentCodeBadge,
|
|
208
213
|
default70 as ExperimentDataViewer,
|
|
214
|
+
default76 as ExperimentSelectorModal,
|
|
209
215
|
default51 as ExperimentTimeline,
|
|
210
216
|
default24 as FileUploader,
|
|
217
|
+
default77 as FitPanel,
|
|
211
218
|
default19 as FormField,
|
|
212
219
|
default64 as FormulaInput,
|
|
213
220
|
default55 as GroupAssigner,
|
|
@@ -264,6 +271,7 @@ export {
|
|
|
264
271
|
useChemicalFormula,
|
|
265
272
|
useConcentrationUnits,
|
|
266
273
|
useDoseCalculator,
|
|
274
|
+
useExperimentSelector,
|
|
267
275
|
usePasskey,
|
|
268
276
|
usePlatformContext,
|
|
269
277
|
usePluginConfig,
|