@morscherlab/mint-sdk 1.2.0-beta.15 → 1.2.0-beta.16

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 (108) hide show
  1. package/README.md +30 -0
  2. package/dist/{ExperimentPopover-BIZKoRTT.js → ExperimentPopover-CJdNlCZb.js} +3 -3
  3. package/dist/{ExperimentPopover-BIZKoRTT.js.map → ExperimentPopover-CJdNlCZb.js.map} +1 -1
  4. package/dist/{ExperimentSelectorModal-BeEOomw_.js → ExperimentSelectorModal-CZ1f_K9I.js} +5 -5
  5. package/dist/{ExperimentSelectorModal-BeEOomw_.js.map → ExperimentSelectorModal-CZ1f_K9I.js.map} +1 -1
  6. package/dist/{SettingsModal-Dphh3RrI.js → SettingsModal-DQUcpT4T.js} +5 -5
  7. package/dist/{SettingsModal-Dphh3RrI.js.map → SettingsModal-DQUcpT4T.js.map} +1 -1
  8. package/dist/{Skeleton-DxtwJ5gt.js → Skeleton-JaDtC8-9.js} +3 -3
  9. package/dist/{Skeleton-DxtwJ5gt.js.map → Skeleton-JaDtC8-9.js.map} +1 -1
  10. package/dist/__tests__/apiErrors.test.d.ts +1 -0
  11. package/dist/__tests__/components/PlotlyChart.test.d.ts +1 -0
  12. package/dist/apiErrors.d.ts +26 -0
  13. package/dist/components/BaseInput.vue.d.ts +1 -1
  14. package/dist/components/BaseSelect.vue.d.ts +1 -1
  15. package/dist/components/BaseTextarea.vue.d.ts +1 -1
  16. package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +2 -2
  17. package/dist/components/BioTemplatePackWorkspaceView.vue.d.ts +2 -2
  18. package/dist/components/ConcentrationInput.vue.d.ts +1 -1
  19. package/dist/components/DatePicker.vue.d.ts +1 -1
  20. package/dist/components/DateTimePicker.vue.d.ts +1 -1
  21. package/dist/components/FileBrowserModal.vue.d.ts +1 -1
  22. package/dist/components/FilePicker.vue.d.ts +3 -3
  23. package/dist/components/FileUploader.vue.d.ts +5 -2
  24. package/dist/components/FormulaInput.vue.d.ts +1 -1
  25. package/dist/components/GeneratedPlotlyResult.vue.d.ts +1 -3
  26. package/dist/components/MobileSupportGate.vue.d.ts +1 -1
  27. package/dist/components/MoleculeInput.vue.d.ts +1 -1
  28. package/dist/components/NumberInput.vue.d.ts +1 -1
  29. package/dist/components/PlotlyChart.vue.d.ts +59 -0
  30. package/dist/components/ResourceCard.vue.d.ts +1 -1
  31. package/dist/components/SecretInput.vue.d.ts +1 -1
  32. package/dist/components/SequenceInput.vue.d.ts +1 -1
  33. package/dist/components/StatusIndicator.vue.d.ts +1 -1
  34. package/dist/components/TagsInput.vue.d.ts +1 -1
  35. package/dist/components/TimePicker.vue.d.ts +1 -1
  36. package/dist/components/TimeRangeInput.vue.d.ts +1 -1
  37. package/dist/components/UnitInput.vue.d.ts +1 -1
  38. package/dist/components/WellPlate.vue.d.ts +1 -1
  39. package/dist/components/index.d.ts +1 -0
  40. package/dist/components/index.js +8 -8
  41. package/dist/{components-6IIxCSI8.js → components-DT6ggNrt.js} +580 -366
  42. package/dist/components-DT6ggNrt.js.map +1 -0
  43. package/dist/composables/filePicker/localFiles.d.ts +1 -1
  44. package/dist/composables/filePicker/usePickerNavigation.d.ts +4 -3
  45. package/dist/composables/index.js +9 -9
  46. package/dist/composables/useApi.d.ts +2 -0
  47. package/dist/composables/useFilePicker.d.ts +5 -6
  48. package/dist/{composables-hY2Q2xPI.js → composables-DmF_8iyX.js} +13 -10
  49. package/dist/{composables-hY2Q2xPI.js.map → composables-DmF_8iyX.js.map} +1 -1
  50. package/dist/{errors-_W0-LbA6.js → errors-DZDb1cIb.js} +66 -5
  51. package/dist/errors-DZDb1cIb.js.map +1 -0
  52. package/dist/{experiment-Cwl9AYxw.js → experiment-CHm_TwJy.js} +2 -2
  53. package/dist/{experiment-Cwl9AYxw.js.map → experiment-CHm_TwJy.js.map} +1 -1
  54. package/dist/{experiment-utils-DV3DrvE_.js → experiment-utils-CV2Wza3z.js} +1 -1
  55. package/dist/{experiment-utils-DV3DrvE_.js.map → experiment-utils-CV2Wza3z.js.map} +1 -1
  56. package/dist/index.d.ts +1 -0
  57. package/dist/index.js +15 -15
  58. package/dist/install.js +2 -2
  59. package/dist/stores/index.js +2 -2
  60. package/dist/styles.css +29 -18
  61. package/dist/templates/index.js +2 -2
  62. package/dist/{templates-Qq113pyZ.js → templates-CXARYr6_.js} +2 -2
  63. package/dist/{templates-Qq113pyZ.js.map → templates-CXARYr6_.js.map} +1 -1
  64. package/dist/types/filePicker.d.ts +9 -1
  65. package/dist/{useControlSchema-aMZlb4Sc.js → useControlSchema-BAzmP1_y.js} +42 -37
  66. package/dist/useControlSchema-BAzmP1_y.js.map +1 -0
  67. package/dist/{useDropdownState-DitCtrTT.js → useDropdownState-C7hRiVQf.js} +2 -2
  68. package/dist/{useDropdownState-DitCtrTT.js.map → useDropdownState-C7hRiVQf.js.map} +1 -1
  69. package/dist/{useExperimentSelector-I8HC8hUu.js → useExperimentSelector-D_vobhnW.js} +4 -4
  70. package/dist/{useExperimentSelector-I8HC8hUu.js.map → useExperimentSelector-D_vobhnW.js.map} +1 -1
  71. package/dist/{useFormBuilder-TCxNnqeb.js → useFormBuilder-DEHejpiL.js} +2 -2
  72. package/dist/{useFormBuilder-TCxNnqeb.js.map → useFormBuilder-DEHejpiL.js.map} +1 -1
  73. package/dist/{validation-nBbSn1TI.js → validation-OuEr0iAS.js} +9 -8
  74. package/dist/{validation-nBbSn1TI.js.map → validation-OuEr0iAS.js.map} +1 -1
  75. package/package.json +1 -1
  76. package/src/__tests__/apiErrors.test.ts +81 -0
  77. package/src/__tests__/components/FilePicker.state.test.ts +128 -1
  78. package/src/__tests__/components/FilePicker.test.ts +146 -1
  79. package/src/__tests__/components/GeneratedPlotlyResult.test.ts +52 -5
  80. package/src/__tests__/components/PlotlyChart.test.ts +305 -0
  81. package/src/__tests__/components/SegmentedControl.test.ts +19 -0
  82. package/src/__tests__/composables/useApi.test.ts +82 -9
  83. package/src/__tests__/composables/useGeneratedAnalysis.test.ts +7 -2
  84. package/src/__tests__/composables/usePluginClient.test.ts +3 -0
  85. package/src/apiErrors.ts +85 -0
  86. package/src/components/FilePicker.story.vue +44 -0
  87. package/src/components/FilePicker.vue +23 -40
  88. package/src/components/FileUploader.vue +32 -14
  89. package/src/components/GeneratedPlotlyResult.vue +34 -69
  90. package/src/components/GeneratedResultRenderer.vue +0 -5
  91. package/src/components/PlotlyChart.story.vue +61 -0
  92. package/src/components/PlotlyChart.vue +233 -0
  93. package/src/components/SegmentedControl.vue +2 -2
  94. package/src/components/index.ts +1 -0
  95. package/src/composables/filePicker/localFiles.ts +6 -3
  96. package/src/composables/filePicker/usePickerNavigation.ts +29 -8
  97. package/src/composables/filePicker/usePickerSelection.ts +17 -4
  98. package/src/composables/filePicker/validation.ts +1 -0
  99. package/src/composables/useApi.ts +33 -4
  100. package/src/composables/useFilePicker.ts +41 -22
  101. package/src/composables/useGeneratedAnalysis.ts +10 -17
  102. package/src/composables/usePluginClient.ts +3 -0
  103. package/src/index.ts +3 -0
  104. package/src/styles/components/file-picker.css +6 -5
  105. package/src/types/filePicker.ts +9 -2
  106. package/dist/components-6IIxCSI8.js.map +0 -1
  107. package/dist/errors-_W0-LbA6.js.map +0 -1
  108. package/dist/useControlSchema-aMZlb4Sc.js.map +0 -1
@@ -14,6 +14,7 @@ import type {
14
14
  } from './useJobsStatusTray'
15
15
  import { useEventStream, type EventStreamMessage } from './useEventStream'
16
16
  import { isActiveJobStatus, normalizeJobState } from '../jobs'
17
+ import { MintApiError, mintApiErrorFromResponse } from '../apiErrors'
17
18
  import type {
18
19
  GeneratedAnalysisJob,
19
20
  GeneratedAnalysisJobInput,
@@ -129,16 +130,6 @@ type PluginJobStreamData = GeneratedAnalysisJobInput | {
129
130
  jobs: GeneratedAnalysisJobInput[]
130
131
  }
131
132
 
132
- class GeneratedAnalysisRequestError extends Error {
133
- constructor(
134
- readonly status: number,
135
- readonly detail: unknown,
136
- ) {
137
- super(typeof detail === 'string' ? detail : `Request failed (${status})`)
138
- this.name = 'GeneratedAnalysisRequestError'
139
- }
140
- }
141
-
142
133
  export function createGeneratedAnalysisTransport(
143
134
  options: GeneratedAnalysisTransportOptions = {},
144
135
  ): GeneratedAnalysisTransport {
@@ -838,7 +829,7 @@ function createPluginJobs(
838
829
  job: GeneratedAnalysisJob,
839
830
  cause: unknown,
840
831
  ): void {
841
- if (cause instanceof GeneratedAnalysisRequestError) {
832
+ if (cause instanceof MintApiError) {
842
833
  if (cause.status === 404 || cause.status === 410) {
843
834
  discardCachedResult(job.job_id)
844
835
  jobs.value = jobs.value.map(candidate => (
@@ -1037,8 +1028,10 @@ function createPluginJobs(
1037
1028
  },
1038
1029
  })
1039
1030
  if (!response.ok) {
1040
- const payload = await response.json().catch(() => null) as { detail?: unknown } | null
1041
- throw new GeneratedAnalysisRequestError(response.status, payload?.detail)
1031
+ const payload: unknown = await response.json().catch(() => null)
1032
+ throw mintApiErrorFromResponse(response.status, payload, {
1033
+ requestId: response.headers.get('X-Request-ID'),
1034
+ })
1042
1035
  }
1043
1036
  return await response.json() as T
1044
1037
  }
@@ -1177,20 +1170,20 @@ function createGeneratedSessionStorage(candidate?: Storage): GeneratedSessionSto
1177
1170
  }
1178
1171
 
1179
1172
  function isSessionNotFoundError(error: unknown): boolean {
1180
- return error instanceof GeneratedAnalysisRequestError
1173
+ return error instanceof MintApiError
1181
1174
  && error.status === 404
1182
- && error.detail === SESSION_NOT_FOUND_DETAIL
1175
+ && (error.detail === SESSION_NOT_FOUND_DETAIL || error.message === SESSION_NOT_FOUND_DETAIL)
1183
1176
  }
1184
1177
 
1185
1178
  function isRetryableResultError(error: unknown): boolean {
1186
- return !(error instanceof GeneratedAnalysisRequestError)
1179
+ return !(error instanceof MintApiError)
1187
1180
  || error.status === 409
1188
1181
  || error.status === 429
1189
1182
  || error.status >= 500
1190
1183
  }
1191
1184
 
1192
1185
  function isRetryableJobLookupError(error: unknown): boolean {
1193
- return !(error instanceof GeneratedAnalysisRequestError)
1186
+ return !(error instanceof MintApiError)
1194
1187
  || error.status === 408
1195
1188
  || error.status === 429
1196
1189
  || error.status >= 500
@@ -423,6 +423,7 @@ export function createPluginClient<TClient extends object = GeneratedPluginClien
423
423
  const api = useApi({
424
424
  baseUrl: parts.baseUrl,
425
425
  withAuth: endpoint.requiresAuth !== false,
426
+ typedErrors: true,
426
427
  })
427
428
  const config = endpointRequestConfig(endpoint, parts.query, callOptions)
428
429
 
@@ -469,6 +470,7 @@ export async function uploadPluginEndpoint<TResponse = unknown>(
469
470
  const api = useApi({
470
471
  baseUrl: parts.baseUrl,
471
472
  withAuth: endpoint.requiresAuth !== false,
473
+ typedErrors: true,
472
474
  })
473
475
  const body = endpoint.hasBody
474
476
  ? requestBodyFromPayload(payload, parts.requestPayload, endpoint)
@@ -507,6 +509,7 @@ export async function downloadPluginEndpoint(
507
509
  const api = useApi({
508
510
  baseUrl: parts.baseUrl,
509
511
  withAuth: endpoint.requiresAuth !== false,
512
+ typedErrors: true,
510
513
  })
511
514
  const config = {
512
515
  ...(endpointRequestConfig(endpoint, parts.query, { signal: options.signal }) ?? {}),
package/src/index.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  // Styles (import to ensure bundling)
2
2
  import './styles/index.css'
3
3
 
4
+ // Typed API errors
5
+ export * from './apiErrors'
6
+
4
7
  // Vue Plugin for global component registration
5
8
  export { MINTSdk, default } from './install'
6
9
 
@@ -386,17 +386,18 @@
386
386
  gap: 8px;
387
387
  flex-shrink: 0;
388
388
  }
389
- .mint-picker__local-actions {
389
+ .mint-picker__local-upload {
390
390
  display: flex;
391
- align-items: center;
391
+ flex-direction: column;
392
392
  gap: 8px;
393
- padding: 8px 14px;
393
+ padding: 12px 18px;
394
394
  flex-shrink: 0;
395
- }
396
- .mint-picker__local-actions > span {
397
395
  color: var(--text-muted);
398
396
  font-size: 11px;
399
397
  }
398
+ .mint-picker__local-title {
399
+ flex: 1;
400
+ }
400
401
  @media (max-width: 600px) {
401
402
  .mint-picker-dialog .mint-file-browser-dialog__header {
402
403
  padding: 10px;
@@ -27,6 +27,13 @@ export type PickerNode = PickerFolder | PickerFile
27
27
  export interface PickerRequest {
28
28
  signal?: AbortSignal
29
29
  source?: PickerSource
30
+ /**
31
+ * Set only when the user pressed Refresh. Adapters that cache listings (or
32
+ * ask a server to bypass its own cache) should re-read the location then and
33
+ * serve cached data otherwise; the picker keeps folder contents while it is
34
+ * open and re-reads the current location on each open.
35
+ */
36
+ refresh?: true
30
37
  }
31
38
  export interface PickerAdapter {
32
39
  listRoot(request?: PickerRequest): Promise<PickerNode[]>
@@ -46,7 +53,7 @@ export interface PickerCapability {
46
53
  }
47
54
  export type PickerCapabilities = Partial<Record<PickerSource, PickerCapability>>
48
55
  export type PickerExclusionReason =
49
- 'deselected' | 'unsupported' | 'tooLarge' | 'blank' | 'unreadable'
56
+ 'deselected' | 'unsupported' | 'tooLarge' | 'blank' | 'unreadable' | 'forbidden'
50
57
  export interface PickerExcluded {
51
58
  /** Opaque identity prevents collisions between equal filenames in different folders. */
52
59
  path: string
@@ -55,7 +62,7 @@ export interface PickerExcluded {
55
62
  }
56
63
  export type PickerSelection =
57
64
  | { source: 'server'; folders: string[]; files: PickerFile[]; excluded: PickerExcluded[] }
58
- | { source: 'localFile'; files: File[] }
65
+ | { source: 'localFile'; files: File[]; relativePaths?: string[] }
59
66
  export interface PickerTreeRow {
60
67
  node: PickerNode
61
68
  depth: number