@morscherlab/mint-sdk 1.0.56 → 1.0.57

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 (44) hide show
  1. package/dist/__tests__/components/ArtifactSaveDialog.test.d.ts +1 -0
  2. package/dist/__tests__/components/ArtifactSelectorModal.test.d.ts +1 -0
  3. package/dist/__tests__/composables/useAnalysisArtifacts.test.d.ts +1 -0
  4. package/dist/analysisArtifactTypes-Cu40dzSG.js +7 -0
  5. package/dist/analysisArtifactTypes-Cu40dzSG.js.map +1 -0
  6. package/dist/components/ArtifactSaveDialog.vue.d.ts +56 -0
  7. package/dist/components/ArtifactSelectorModal.vue.d.ts +41 -0
  8. package/dist/components/index.d.ts +2 -0
  9. package/dist/components/index.js +2 -2
  10. package/dist/{components-BQwOeyiy.js → components-PC3SVsaa.js} +1743 -1144
  11. package/dist/components-PC3SVsaa.js.map +1 -0
  12. package/dist/composables/index.d.ts +1 -0
  13. package/dist/composables/index.js +4 -3
  14. package/dist/composables/useAnalysisArtifacts.d.ts +59 -0
  15. package/dist/{composables-TpXyhRZZ.js → composables-OYTD0Y3r.js} +2 -2
  16. package/dist/{composables-TpXyhRZZ.js.map → composables-OYTD0Y3r.js.map} +1 -1
  17. package/dist/index.js +5 -4
  18. package/dist/index.js.map +1 -1
  19. package/dist/install.js +1 -1
  20. package/dist/styles.css +412 -0
  21. package/dist/types/analysisArtifactTypes.d.ts +100 -0
  22. package/dist/types/index.d.ts +2 -0
  23. package/dist/types/index.js +2 -0
  24. package/dist/{useJobsStatusTray-CVecN6Ao.js → useAnalysisArtifacts-Ob8UtVwl.js} +157 -2
  25. package/dist/useAnalysisArtifacts-Ob8UtVwl.js.map +1 -0
  26. package/package.json +1 -1
  27. package/src/__tests__/components/ArtifactSaveDialog.test.ts +516 -0
  28. package/src/__tests__/components/ArtifactSelectorModal.test.ts +178 -0
  29. package/src/__tests__/composables/useAnalysisArtifacts.test.ts +667 -0
  30. package/src/components/ArtifactSaveDialog.story.vue +293 -0
  31. package/src/components/ArtifactSaveDialog.vue +383 -0
  32. package/src/components/ArtifactSelectorModal.story.vue +295 -0
  33. package/src/components/ArtifactSelectorModal.vue +326 -0
  34. package/src/components/index.ts +2 -0
  35. package/src/composables/index.ts +6 -0
  36. package/src/composables/useAnalysisArtifacts.ts +305 -0
  37. package/src/styles/components/artifact-save-dialog.css +17 -0
  38. package/src/styles/components/artifact-selector-modal.css +216 -0
  39. package/src/styles/index.css +2 -0
  40. package/src/types/analysisArtifactTypes.ts +119 -0
  41. package/src/types/index.ts +17 -0
  42. package/dist/components-BQwOeyiy.js.map +0 -1
  43. package/dist/useJobsStatusTray-CVecN6Ao.js.map +0 -1
  44. /package/dist/{ExperimentPopover-8A4Rhffp.js → ExperimentPopover-Ryusjrhv.js} +0 -0
@@ -0,0 +1,100 @@
1
+ import { TreeNode } from './componentLabTypes';
2
+ import { SummaryData } from './componentWorkflowTypes';
3
+ /** Result schema identifier for file-backed analysis artifacts. */
4
+ export declare const ANALYSIS_FILE_ARTIFACT_SCHEMA = "mint.analysis_file.v1";
5
+ /** Known artifact lifecycle states; kept open for forward compatibility. */
6
+ export type AnalysisArtifactStatus = 'active' | 'archived' | (string & {});
7
+ /** Status filter vocabulary for artifact lists. */
8
+ export type AnalysisArtifactStatusFilter = 'active' | 'archived' | 'all';
9
+ /** Summary row returned by GET /experiments/{id}/analysis-artifacts. */
10
+ export interface AnalysisArtifactSummary {
11
+ id: number;
12
+ experiment_id: number;
13
+ plugin_id: string;
14
+ artifact_key: string;
15
+ display_name: string;
16
+ note?: string | null;
17
+ status: AnalysisArtifactStatus;
18
+ result_keys: string[];
19
+ created_at?: string | null;
20
+ updated_at?: string | null;
21
+ archived_at?: string | null;
22
+ archived_by?: number | null;
23
+ }
24
+ /** Full artifact returned by GET /experiments/{id}/analysis-artifacts/{artifactId}. */
25
+ export interface AnalysisArtifactDetail extends AnalysisArtifactSummary {
26
+ result: Record<string, unknown>;
27
+ tree: TreeNode[];
28
+ summary: SummaryData | null;
29
+ }
30
+ /** Response of GET /experiments/{id}/analysis-artifacts. */
31
+ export interface AnalysisArtifactListResponse {
32
+ artifacts: AnalysisArtifactSummary[];
33
+ }
34
+ /** Body of PATCH /experiments/{id}/analysis-artifacts/{artifactId}. */
35
+ export interface AnalysisArtifactMetadataUpdate {
36
+ display_name?: string;
37
+ /** undefined = keep, string = set, null = clear. */
38
+ note?: string | null;
39
+ }
40
+ /** How a save payload should be applied by the plugin backend. */
41
+ export type ArtifactSaveMode = 'create' | 'upsert' | 'update';
42
+ interface ArtifactSavePayloadBase {
43
+ experimentId: number;
44
+ artifactKey: string;
45
+ }
46
+ /**
47
+ * JSON artifact save — handler maps to save_analysis_artifact, which upserts by key.
48
+ * That call only assigns display_name/note when they are provided, and cannot clear
49
+ * either; use the metadata PATCH (useAnalysisArtifacts.updateMetadata) for that.
50
+ */
51
+ export interface JsonArtifactSavePayload extends ArtifactSavePayloadBase {
52
+ kind: 'json';
53
+ mode: 'create' | 'upsert';
54
+ result: Record<string, unknown>;
55
+ displayName?: string;
56
+ note?: string;
57
+ }
58
+ /** File artifact create — handler maps to save_analysis_file_artifact (create-only: a reused key conflicts). */
59
+ export interface FileArtifactCreatePayload extends ArtifactSavePayloadBase {
60
+ kind: 'file';
61
+ mode: 'create';
62
+ file: File;
63
+ /** Maps to the Python `kind=` argument (defaults to "file" backend-side). */
64
+ fileKind: string;
65
+ filename?: string;
66
+ displayName?: string;
67
+ note?: string;
68
+ contentType?: string;
69
+ metadata?: Record<string, unknown>;
70
+ }
71
+ /**
72
+ * File artifact replacement — handler maps to update_analysis_file_artifact
73
+ * (transactional CAS replace). `kind` and `filename` are immutable backend-side, so
74
+ * `fileKind` echoes the artifact's existing kind and no filename is carried. `note`
75
+ * is three-state: omitted preserves, null clears, a string sets. `metadata` REPLACES
76
+ * the previous result metadata rather than merging, so it always carries the full
77
+ * intended map — omitting it clears whatever was there.
78
+ */
79
+ export interface FileArtifactUpdatePayload extends ArtifactSavePayloadBase {
80
+ kind: 'file';
81
+ mode: 'update';
82
+ file: File;
83
+ fileKind: string;
84
+ note?: string | null;
85
+ contentType?: string;
86
+ metadata?: Record<string, unknown>;
87
+ }
88
+ export type ArtifactSavePayload = JsonArtifactSavePayload | FileArtifactCreatePayload | FileArtifactUpdatePayload;
89
+ /** Optional handler result; cleanupPending surfaces AnalysisFileArtifactUpdate.cleanup_pending. */
90
+ export interface ArtifactSaveResult {
91
+ artifact?: AnalysisArtifactSummary;
92
+ cleanupPending?: boolean;
93
+ }
94
+ /**
95
+ * Plugin-supplied save handler. The dialog never writes to the platform;
96
+ * the handler forwards the payload to the plugin backend, which calls
97
+ * save_analysis_artifact / save_analysis_file_artifact / update_analysis_file_artifact.
98
+ */
99
+ export type ArtifactSaveHandler = (payload: ArtifactSavePayload) => Promise<ArtifactSaveResult | void>;
100
+ export {};
@@ -1,4 +1,6 @@
1
1
  export type { ContainerDirection, ButtonVariant, ButtonSize, InputType, ModalSize, ModalVariant, AlertType, Toast, TabItem, TabItemInput, OptionPrimitive, SelectOption, SelectOptionInput, RadioOption, RadioOptionInput, FormFieldProps, SidebarBadgeTone, SidebarToolSection, SidebarToolSectionAction, CollapsibleState, TopBarVariant, TopBarSettingsConfig, PillNavOption, PillNavOptionInput, PillNavItem, PillNavItemInput, PageSelectorItem, PageSelectorItemInput, PluginSwitcherPlugin, PluginSwitcherInfo, AccountMenuItem, WellPlateFormat, WellState, WellPlateSelectionMode, WellPlateSize, WellShape, Well, HeatmapColorScale, HeatmapConfig, SlotPosition, WellExtendedData, WellEditData, WellEditField, WellSampleDropData, WellSampleDropContext, WellSampleDropParser, WellLegendItem, PlateCondition, ColumnCondition, RowCondition, Rack, RackSampleDropContext, RackSampleDropMapper, SampleType, PlateMap, PlateMapEditorState, ProtocolStepType, ProtocolStepStatus, ProtocolStep, SampleGroup, GroupItem, FileUploaderMode, SegmentedOption, SegmentedOptionInput, SegmentedControlVariant, SegmentedControlSize, MultiSelectOption, MultiSelectOptionInput, MultiSelectSize, PillVariant, PillColor, PillSize, CalendarSelectionMode, CalendarMarker, CalendarDayContext, SortDirection, SortState, DataFrameColumn, PaginationState, SpinnerSize, SpinnerVariant, DividerSpacing, StatusType, ProgressVariant, ProgressSize, AvatarSize, EmptyStateColor, EmptyStateSize, BreadcrumbItem, BreadcrumbItemInput, TooltipPosition, ConfirmVariant, SettingsTab, SettingsTabInput, SettingsModalLayout, SettingsGroup, SettingsModalSchema, SettingsUserType, SettingsAudience, SettingsAudienceInput, NumberNotation, UnitOption, WizardStep, WizardStepState, AuditEntryType, AuditEntry, BatchItemStatus, BatchItem, BatchSummary, TimePickerFormat, TimeRange, ScheduleView, ScheduleEventStatus, ScheduleEvent, ScheduleBlockedSlot, ScheduleSlotContext, ScheduleEventCreateContext, ScheduleEventUpdateContext, SummarySectionItem, SummarySection, SummaryData, ResourceStatus, ResourceSpec, MoleculeData, ExperimentStatus, DatePreset, ExperimentSortField, ExperimentTypeOption, ExperimentSummary, ExperimentListResponse, ExperimentFilters, FitState, FitResultSummary, StorageCondition, ReagentColumn, Reagent, TreeNodeType, BadgeVariant, TreeNode, } from './components';
2
+ export type { AnalysisArtifactStatus, AnalysisArtifactStatusFilter, AnalysisArtifactSummary, AnalysisArtifactDetail, AnalysisArtifactListResponse, AnalysisArtifactMetadataUpdate, ArtifactSaveMode, JsonArtifactSavePayload, FileArtifactCreatePayload, FileArtifactUpdatePayload, ArtifactSavePayload, ArtifactSaveResult, ArtifactSaveHandler, } from './analysisArtifactTypes';
3
+ export { ANALYSIS_FILE_ARTIFACT_SCHEMA } from './analysisArtifactTypes';
2
4
  export type { JobListPayload, JobProgress, JobSnapshotPayload, JobState, JobStateInput, JobStatus, JobStreamData, } from './jobs';
3
5
  export type { InstrumentAlert, InstrumentAlertBody, InstrumentAlertLevel, InstrumentState, InstrumentStatus, SampleInfo, SampleInfo as InstrumentSampleInfo, SequenceProgress, } from './instrument';
4
6
  export type { LcmsContainerType, LcmsPolarity, LcmsSequenceItem, LcmsSequenceTableColumn, } from '../lcms';
@@ -0,0 +1,2 @@
1
+ import { t as ANALYSIS_FILE_ARTIFACT_SCHEMA } from "../analysisArtifactTypes-Cu40dzSG.js";
2
+ export { ANALYSIS_FILE_ARTIFACT_SCHEMA };
@@ -4736,6 +4736,161 @@ function useJobsStatusTray(options = {}) {
4736
4736
  };
4737
4737
  }
4738
4738
  //#endregion
4739
- export { useTheme as $, useExpansionSet as A, extractSamplesFromDesignData as B, useExperimentSave as C, currentExperimentFromContext as D, useExperimentData as E, detectDelimiter as F, unwrapExperimentDesignData as G, parseCSV as H, parseDelimitedText as I, useDoseCalculator as J, DEFAULT_COLORS as K, readFileAsText as L, deriveShade as M, hexToHsl as N, getInjectedPlatformContext as O, hslToHex as P, useAppExperiment as Q, useFileImport as R, useTemplateCollection as S, useExperimentSamples as T, extractSampleNamesFromDesignData as U, useAutoGroup as V, extractSampleOptionsFromDesignData as W, useMobileSupportGate as X, DEFAULT_MOBILE_VIEWPORT_QUERY as Y, APP_EXPERIMENT_KEY as Z, useBioTemplateWorkspace as _, normalizeJobPercent as a, useSortedItems as at, useBioTemplateComponents as b, useProtocolTemplates as c, generateDilutionSeries as d, useToast as et, useReagentSeries as f, useBioTemplatePackWorkspace as g, useBioTemplatePresetWorkspace as h, jobStatusLabel as i, compareSortValues as it, useSampleGroups as j, resolveCurrentExperimentId as k, DEFAULT_PRESETS as l, useRackEditor as m, isActiveJobStatus as n, normalizeSearchQuery as nt, normalizeJobState as o, useGroupAssignment as p, useWellPlateEditor as q, isTerminalJobStatus as r, useTextSearch as rt, resolveJobCapabilities as s, useJobsStatusTray as t, candidateMatchesSearch as tt, DEFAULT_UNITS as u, getBioTemplateComponentProps as v, useScheduleDrag as w, useBioTemplateControls as x, toBioTemplateComponentPropsByComponent as y, validateImportFile as z };
4739
+ //#region src/composables/useAnalysisArtifacts.ts
4740
+ /** Lists and manages analysis artifacts through the user-facing platform API. */
4741
+ function useAnalysisArtifacts(options = {}) {
4742
+ const injectedContext = getInjectedPlatformContext();
4743
+ const api = useApi({ baseUrl: options.apiBaseUrl ?? injectedContext?.platformApiUrl });
4744
+ const currentExperimentId = computed(() => toValue(options.experimentId) ?? resolveCurrentExperimentId(injectedContext));
4745
+ const hasCurrentExperiment = computed(() => currentExperimentId.value !== void 0);
4746
+ const scopePluginId = computed(() => toValue(options.pluginId) ?? null);
4747
+ const request = useRequestSyncState("Analysis artifact request failed.");
4748
+ const fetchedArtifacts = ref([]);
4749
+ const selectedDetail = ref(null);
4750
+ const loadingCount = ref(0);
4751
+ const mutatingCount = ref(0);
4752
+ const isLoading = computed(() => loadingCount.value > 0);
4753
+ const isMutating = computed(() => mutatingCount.value > 0);
4754
+ const search = ref("");
4755
+ const statusFilter = ref("active");
4756
+ const pluginFilter = ref(null);
4757
+ const needsArchived = computed(() => Boolean(toValue(options.includeArchived)) || statusFilter.value !== "active");
4758
+ const artifacts = computed(() => scopePluginId.value ? fetchedArtifacts.value.filter((artifact) => artifact.plugin_id === scopePluginId.value) : fetchedArtifacts.value);
4759
+ const visibleArtifacts = computed(() => {
4760
+ const query = search.value.trim().toLowerCase();
4761
+ return artifacts.value.filter((artifact) => {
4762
+ if (statusFilter.value !== "all" && artifact.status !== statusFilter.value) return false;
4763
+ if (pluginFilter.value && artifact.plugin_id !== pluginFilter.value) return false;
4764
+ if (!query) return true;
4765
+ return artifact.display_name.toLowerCase().includes(query) || artifact.artifact_key.toLowerCase().includes(query);
4766
+ });
4767
+ });
4768
+ let listToken = 0;
4769
+ let detailToken = 0;
4770
+ const hasRequestedList = ref(false);
4771
+ function currentExperimentIdOrError(action) {
4772
+ const id = currentExperimentId.value;
4773
+ if (id === void 0) {
4774
+ request.setError(`No current experiment is selected for ${action}`);
4775
+ return;
4776
+ }
4777
+ return id;
4778
+ }
4779
+ function replaceArtifact(summary) {
4780
+ const index = fetchedArtifacts.value.findIndex((artifact) => artifact.id === summary.id);
4781
+ if (index >= 0) fetchedArtifacts.value.splice(index, 1, summary);
4782
+ }
4783
+ async function list() {
4784
+ const experimentId = currentExperimentIdOrError("listing analysis artifacts");
4785
+ if (experimentId === void 0) {
4786
+ fetchedArtifacts.value = [];
4787
+ return [];
4788
+ }
4789
+ const token = ++listToken;
4790
+ hasRequestedList.value = true;
4791
+ loadingCount.value += 1;
4792
+ request.clearError();
4793
+ try {
4794
+ const data = await api.get(`/experiments/${experimentId}/analysis-artifacts?include_archived=${needsArchived.value}`);
4795
+ if (token !== listToken) return artifacts.value;
4796
+ fetchedArtifacts.value = [...data?.artifacts ?? []];
4797
+ request.markLoaded();
4798
+ return artifacts.value;
4799
+ } catch (err) {
4800
+ if (token !== listToken) return [];
4801
+ request.setError(err);
4802
+ fetchedArtifacts.value = [];
4803
+ return [];
4804
+ } finally {
4805
+ loadingCount.value -= 1;
4806
+ }
4807
+ }
4808
+ async function getDetail(artifactId) {
4809
+ const experimentId = currentExperimentIdOrError("loading an analysis artifact");
4810
+ if (experimentId === void 0) return null;
4811
+ const token = ++detailToken;
4812
+ loadingCount.value += 1;
4813
+ request.clearError();
4814
+ try {
4815
+ const detail = await api.get(`/experiments/${experimentId}/analysis-artifacts/${artifactId}`);
4816
+ if (token !== detailToken) return null;
4817
+ selectedDetail.value = detail;
4818
+ request.markLoaded();
4819
+ return detail;
4820
+ } catch (err) {
4821
+ if (token !== detailToken) return null;
4822
+ request.setError(err);
4823
+ return null;
4824
+ } finally {
4825
+ loadingCount.value -= 1;
4826
+ }
4827
+ }
4828
+ async function mutate(action, operation) {
4829
+ const experimentId = currentExperimentIdOrError(action);
4830
+ if (experimentId === void 0) return null;
4831
+ mutatingCount.value += 1;
4832
+ request.clearError();
4833
+ try {
4834
+ const summary = await operation(experimentId);
4835
+ replaceArtifact(summary);
4836
+ request.markSaved();
4837
+ return summary;
4838
+ } catch (err) {
4839
+ request.setError(err);
4840
+ return null;
4841
+ } finally {
4842
+ mutatingCount.value -= 1;
4843
+ }
4844
+ }
4845
+ async function updateMetadata(artifactId, updates) {
4846
+ return mutate("updating artifact metadata", (experimentId) => api.patch(`/experiments/${experimentId}/analysis-artifacts/${artifactId}`, updates));
4847
+ }
4848
+ async function archive(artifactId) {
4849
+ return mutate("archiving an analysis artifact", (experimentId) => api.post(`/experiments/${experimentId}/analysis-artifacts/${artifactId}/archive`));
4850
+ }
4851
+ async function restore(artifactId) {
4852
+ return mutate("restoring an analysis artifact", (experimentId) => api.post(`/experiments/${experimentId}/analysis-artifacts/${artifactId}/restore`));
4853
+ }
4854
+ function hasArtifactKey(artifactKey) {
4855
+ return artifacts.value.some((artifact) => artifact.artifact_key === artifactKey);
4856
+ }
4857
+ /** Drop experiment-scoped state and orphan every in-flight response. */
4858
+ function clear() {
4859
+ listToken += 1;
4860
+ detailToken += 1;
4861
+ fetchedArtifacts.value = [];
4862
+ selectedDetail.value = null;
4863
+ request.clearError();
4864
+ }
4865
+ watch([currentExperimentId, needsArchived], ([experimentId], [previousExperimentId]) => {
4866
+ if (experimentId !== previousExperimentId) clear();
4867
+ if (experimentId === void 0) return;
4868
+ if (options.immediate || hasRequestedList.value) list();
4869
+ }, { immediate: options.immediate });
4870
+ return {
4871
+ artifacts,
4872
+ visibleArtifacts,
4873
+ selectedDetail,
4874
+ currentExperimentId,
4875
+ hasCurrentExperiment,
4876
+ isLoading,
4877
+ isMutating,
4878
+ error: request.error,
4879
+ lastLoadedAt: request.lastLoadedAt,
4880
+ search,
4881
+ statusFilter,
4882
+ pluginFilter,
4883
+ list,
4884
+ refresh: list,
4885
+ getDetail,
4886
+ updateMetadata,
4887
+ archive,
4888
+ restore,
4889
+ hasArtifactKey,
4890
+ clear
4891
+ };
4892
+ }
4893
+ //#endregion
4894
+ export { useAppExperiment as $, resolveCurrentExperimentId as A, validateImportFile as B, useTemplateCollection as C, useExperimentData as D, useExperimentSamples as E, hslToHex as F, extractSampleOptionsFromDesignData as G, useAutoGroup as H, detectDelimiter as I, useWellPlateEditor as J, unwrapExperimentDesignData as K, parseDelimitedText as L, useSampleGroups as M, deriveShade as N, currentExperimentFromContext as O, hexToHsl as P, APP_EXPERIMENT_KEY as Q, readFileAsText as R, useBioTemplateControls as S, useScheduleDrag as T, parseCSV as U, extractSamplesFromDesignData as V, extractSampleNamesFromDesignData as W, DEFAULT_MOBILE_VIEWPORT_QUERY as X, useDoseCalculator as Y, useMobileSupportGate as Z, useBioTemplatePackWorkspace as _, jobStatusLabel as a, compareSortValues as at, toBioTemplateComponentPropsByComponent as b, resolveJobCapabilities as c, DEFAULT_UNITS as d, useTheme as et, generateDilutionSeries as f, useBioTemplatePresetWorkspace as g, useRackEditor as h, isTerminalJobStatus as i, useTextSearch as it, useExpansionSet as j, getInjectedPlatformContext as k, useProtocolTemplates as l, useGroupAssignment as m, useJobsStatusTray as n, candidateMatchesSearch as nt, normalizeJobPercent as o, useSortedItems as ot, useReagentSeries as p, DEFAULT_COLORS as q, isActiveJobStatus as r, normalizeSearchQuery as rt, normalizeJobState as s, useAnalysisArtifacts as t, useToast as tt, DEFAULT_PRESETS as u, useBioTemplateWorkspace as v, useExperimentSave as w, useBioTemplateComponents as x, getBioTemplateComponentProps as y, useFileImport as z };
4740
4895
 
4741
- //# sourceMappingURL=useJobsStatusTray-CVecN6Ao.js.map
4896
+ //# sourceMappingURL=useAnalysisArtifacts-Ob8UtVwl.js.map