@morscherlab/mint-sdk 1.1.25 → 1.2.0-beta.2
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/README.md +9 -7
- package/dist/{ExperimentSelectorModal-B6P2msT4.js → ExperimentSelectorModal-DyPAUCLw.js} +3 -3
- package/dist/{ExperimentSelectorModal-B6P2msT4.js.map → ExperimentSelectorModal-DyPAUCLw.js.map} +1 -1
- package/dist/{SettingsModal-BW3Ar-uy.js → SettingsModal-BgKY93zh.js} +4 -4
- package/dist/{SettingsModal-BW3Ar-uy.js.map → SettingsModal-BgKY93zh.js.map} +1 -1
- package/dist/__tests__/composables/useEventStream.test.d.ts +1 -0
- package/dist/components/AutoGroupModal.vue.d.ts +1 -1
- package/dist/components/BioTemplateExperimentWorkspaceView.vue.d.ts +1 -1
- package/dist/components/JobsStatusTray.vue.d.ts +2 -9
- package/dist/components/SampleLegend.vue.d.ts +1 -1
- package/dist/components/SampleSelector.vue.d.ts +1 -1
- package/dist/components/SettingsModal.vue.d.ts +1 -1
- package/dist/components/SmartGroupFieldRecipe.vue.d.ts +1 -1
- package/dist/components/index.js +4 -4
- package/dist/{components-DQt0tcpY.js → components-DkHddRMl.js} +10 -16
- package/dist/components-DkHddRMl.js.map +1 -0
- package/dist/composables/index.d.ts +2 -3
- package/dist/composables/index.js +8 -8
- package/dist/composables/useEventStream.d.ts +43 -0
- package/dist/composables/useGeneratedAnalysis.d.ts +1 -3
- package/dist/composables/useJobsStatusTray.d.ts +1 -25
- package/dist/composables/usePluginClient.d.ts +3 -18
- package/dist/{composables-CkXDe7nm.js → composables-C_i90sGS.js} +32 -308
- package/dist/composables-C_i90sGS.js.map +1 -0
- package/dist/{experiment-Y9Iz7KYi.js → experiment-Cq145oEW.js} +2 -2
- package/dist/{experiment-Y9Iz7KYi.js.map → experiment-Cq145oEW.js.map} +1 -1
- package/dist/index.js +12 -12
- package/dist/install.js +4 -4
- package/dist/stores/auth.d.ts +0 -6
- package/dist/stores/index.js +2 -2
- package/dist/templates/index.js +2 -2
- package/dist/{templates-CovvRZ-9.js → templates-DsP51i-S.js} +2 -2
- package/dist/{templates-CovvRZ-9.js.map → templates-DsP51i-S.js.map} +1 -1
- package/dist/types/auth.d.ts +0 -1
- package/dist/{useApi-CDBq6z23.js → useApi-J6zFkHmn.js} +1 -2
- package/dist/useApi-J6zFkHmn.js.map +1 -0
- package/dist/{useControlSchema-BhoJzWzx.js → useControlSchema-BDx2Olha.js} +239 -103
- package/dist/useControlSchema-BDx2Olha.js.map +1 -0
- package/dist/{useExperimentSelector-D0pjj9WH.js → useExperimentSelector-CV4iNfMS.js} +2 -2
- package/dist/{useExperimentSelector-D0pjj9WH.js.map → useExperimentSelector-CV4iNfMS.js.map} +1 -1
- package/dist/{useFormBuilder-DiEcDis2.js → useFormBuilder-BLxG3BOX.js} +2 -2
- package/dist/{useFormBuilder-DiEcDis2.js.map → useFormBuilder-BLxG3BOX.js.map} +1 -1
- package/dist/{useProtocolTemplates-DHwSveE6.js → useProtocolTemplates-CS_SQl6U.js} +22 -113
- package/dist/useProtocolTemplates-CS_SQl6U.js.map +1 -0
- package/package.json +1 -1
- package/src/__tests__/components/GeneratedPluginView.test.ts +0 -5
- package/src/__tests__/components/JobsStatusTray.test.ts +20 -18
- package/src/__tests__/composables/useAuth.test.ts +23 -0
- package/src/__tests__/composables/useEventStream.test.ts +140 -0
- package/src/__tests__/composables/useGeneratedAnalysis.test.ts +103 -0
- package/src/__tests__/composables/useJobsStatusTray.test.ts +25 -161
- package/src/__tests__/composables/usePluginClient.test.ts +8 -13
- package/src/__tests__/docs/frontendDocsCatalog.test.ts +22 -1
- package/src/components/JobsStatusTray.story.vue +6 -10
- package/src/components/JobsStatusTray.vue +1 -16
- package/src/composables/index.ts +0 -7
- package/src/composables/useAuth.ts +0 -3
- package/src/composables/useEventStream.ts +314 -0
- package/src/composables/useGeneratedAnalysis.ts +40 -109
- package/src/composables/useJobsStatusTray.ts +17 -184
- package/src/composables/usePluginClient.ts +45 -249
- package/src/stores/auth.ts +0 -1
- package/src/types/auth.ts +0 -1
- package/dist/__tests__/composables/usePluginConfig.test.d.ts +0 -15
- package/dist/components-DQt0tcpY.js.map +0 -1
- package/dist/composables/usePluginConfig.d.ts +0 -25
- package/dist/composables-CkXDe7nm.js.map +0 -1
- package/dist/useApi-CDBq6z23.js.map +0 -1
- package/dist/useControlSchema-BhoJzWzx.js.map +0 -1
- package/dist/useProtocolTemplates-DHwSveE6.js.map +0 -1
- package/src/__tests__/composables/usePluginConfig.test.ts +0 -497
- package/src/composables/usePluginConfig.ts +0 -250
|
@@ -1,250 +0,0 @@
|
|
|
1
|
-
import { ref, computed, onMounted, type Ref, type ComputedRef } from 'vue'
|
|
2
|
-
import { useApi } from './useApi'
|
|
3
|
-
import { usePlatformContext } from './usePlatformContext'
|
|
4
|
-
import { getInjectedPlatformContext } from './platformContextHelpers'
|
|
5
|
-
import { useRequestSyncState } from './useRequestSyncState'
|
|
6
|
-
|
|
7
|
-
const PLATFORM_OWNED_SETTINGS_KEY = 'allowed_experiment_types'
|
|
8
|
-
|
|
9
|
-
function cloneConfig(config: Record<string, unknown>): Record<string, unknown> {
|
|
10
|
-
return JSON.parse(JSON.stringify(config)) as Record<string, unknown>
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
function hasOwnConfig(config: Record<string, unknown>, key: string): boolean {
|
|
14
|
-
return Object.prototype.hasOwnProperty.call(config, key)
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
function changedTopLevelKeys(
|
|
18
|
-
current: Record<string, unknown>,
|
|
19
|
-
saved: Record<string, unknown>,
|
|
20
|
-
): Set<string> {
|
|
21
|
-
return new Set(
|
|
22
|
-
[...new Set([...Object.keys(current), ...Object.keys(saved)])].filter(
|
|
23
|
-
key => JSON.stringify(current[key]) !== JSON.stringify(saved[key]),
|
|
24
|
-
),
|
|
25
|
-
)
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
function topLevelConfigPatch(
|
|
29
|
-
current: Record<string, unknown>,
|
|
30
|
-
keys: Iterable<string>,
|
|
31
|
-
): Record<string, unknown> {
|
|
32
|
-
return Object.fromEntries(
|
|
33
|
-
[...keys].map(key => [
|
|
34
|
-
key,
|
|
35
|
-
hasOwnConfig(current, key) ? current[key] : null,
|
|
36
|
-
]),
|
|
37
|
-
)
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function platformOwnedConfigPatch(config: Record<string, unknown>): Record<string, unknown> {
|
|
41
|
-
return {
|
|
42
|
-
[PLATFORM_OWNED_SETTINGS_KEY]: hasOwnConfig(config, PLATFORM_OWNED_SETTINGS_KEY)
|
|
43
|
-
? config[PLATFORM_OWNED_SETTINGS_KEY]
|
|
44
|
-
: null,
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
function responseConfigPayload(response: {
|
|
49
|
-
config?: Record<string, unknown>
|
|
50
|
-
settings?: Record<string, unknown>
|
|
51
|
-
}): Record<string, unknown> {
|
|
52
|
-
return response.config ?? response.settings ?? {}
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
export interface UsePluginConfigReturn {
|
|
56
|
-
/** Editable plugin configuration values. */
|
|
57
|
-
config: Ref<Record<string, unknown>>
|
|
58
|
-
/** Whether the config is currently loading. */
|
|
59
|
-
isLoading: Ref<boolean>
|
|
60
|
-
/** Whether the config is currently saving. */
|
|
61
|
-
isSaving: Ref<boolean>
|
|
62
|
-
/** Error message from the last failed operation, or null. */
|
|
63
|
-
error: Ref<string | null>
|
|
64
|
-
/** Timestamp of the last successful load, or null. */
|
|
65
|
-
lastLoadedAt: Ref<Date | null>
|
|
66
|
-
/** Timestamp of the last successful save, or null. */
|
|
67
|
-
lastSavedAt: Ref<Date | null>
|
|
68
|
-
/** Whether local config differs from the last loaded or saved snapshot. */
|
|
69
|
-
isDirty: ComputedRef<boolean>
|
|
70
|
-
/** Load plugin configuration from the platform. */
|
|
71
|
-
load: () => Promise<void>
|
|
72
|
-
/** Save plugin configuration to the platform. */
|
|
73
|
-
save: () => Promise<boolean>
|
|
74
|
-
/** Restore the last loaded or saved configuration snapshot. */
|
|
75
|
-
reset: () => void
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
/** Loads, saves, and tracks dirty state for a plugin's persistent configuration via the platform API. */
|
|
79
|
-
export function usePluginConfig(pluginName?: string): UsePluginConfigReturn {
|
|
80
|
-
const injectedContext = getInjectedPlatformContext()
|
|
81
|
-
const { plugin } = usePlatformContext()
|
|
82
|
-
const platformApi = useApi()
|
|
83
|
-
const pluginApi = useApi({
|
|
84
|
-
baseUrl: injectedContext?.plugin?.api_prefix ?? plugin.value?.api_prefix,
|
|
85
|
-
})
|
|
86
|
-
|
|
87
|
-
const resolvedName = computed(
|
|
88
|
-
() => pluginName ?? plugin.value?.name ?? injectedContext?.plugin?.name ?? '',
|
|
89
|
-
)
|
|
90
|
-
const usesPluginSettingsApi = computed(() => {
|
|
91
|
-
const currentPlugin = injectedContext?.plugin ?? plugin.value
|
|
92
|
-
return currentPlugin?.settings_api === 'plugin'
|
|
93
|
-
&& resolvedName.value === currentPlugin.name
|
|
94
|
-
})
|
|
95
|
-
|
|
96
|
-
const config = ref<Record<string, unknown>>({})
|
|
97
|
-
const savedConfig = ref<Record<string, unknown>>({})
|
|
98
|
-
const revision = ref<string | null>(null)
|
|
99
|
-
const request = useRequestSyncState('Plugin config request failed.')
|
|
100
|
-
const isLoading = ref(false)
|
|
101
|
-
const isSaving = ref(false)
|
|
102
|
-
const error = request.error
|
|
103
|
-
const lastLoadedAt = request.lastLoadedAt
|
|
104
|
-
const lastSavedAt = request.lastSavedAt
|
|
105
|
-
|
|
106
|
-
const isDirty = computed(() => {
|
|
107
|
-
return JSON.stringify(config.value) !== JSON.stringify(savedConfig.value)
|
|
108
|
-
})
|
|
109
|
-
|
|
110
|
-
async function load(): Promise<void> {
|
|
111
|
-
const name = resolvedName.value
|
|
112
|
-
if (!name) return
|
|
113
|
-
|
|
114
|
-
isLoading.value = true
|
|
115
|
-
try {
|
|
116
|
-
const response = usesPluginSettingsApi.value
|
|
117
|
-
? await request.run(
|
|
118
|
-
() => pluginApi.get<{
|
|
119
|
-
settings: Record<string, unknown>
|
|
120
|
-
mode?: string
|
|
121
|
-
revision?: string
|
|
122
|
-
}>('/settings'),
|
|
123
|
-
{ success: 'load', errorMessage: 'Failed to load plugin config' },
|
|
124
|
-
)
|
|
125
|
-
: await request.run(
|
|
126
|
-
() => platformApi.get<{
|
|
127
|
-
plugin_name: string
|
|
128
|
-
config: Record<string, unknown>
|
|
129
|
-
revision?: string
|
|
130
|
-
}>(
|
|
131
|
-
`/plugins/${encodeURIComponent(name)}/config`,
|
|
132
|
-
),
|
|
133
|
-
{ success: 'load', errorMessage: 'Failed to load plugin config' },
|
|
134
|
-
)
|
|
135
|
-
const responseConfig = responseConfigPayload(response)
|
|
136
|
-
config.value = cloneConfig(responseConfig)
|
|
137
|
-
savedConfig.value = cloneConfig(responseConfig)
|
|
138
|
-
revision.value = response.revision ?? null
|
|
139
|
-
} catch {
|
|
140
|
-
// Error state is handled by request.run().
|
|
141
|
-
} finally {
|
|
142
|
-
isLoading.value = false
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
async function save(): Promise<boolean> {
|
|
147
|
-
const name = resolvedName.value
|
|
148
|
-
if (!name) return false
|
|
149
|
-
|
|
150
|
-
isSaving.value = true
|
|
151
|
-
try {
|
|
152
|
-
const payload = cloneConfig(config.value)
|
|
153
|
-
let response: {
|
|
154
|
-
plugin_name?: string
|
|
155
|
-
config?: Record<string, unknown>
|
|
156
|
-
settings?: Record<string, unknown>
|
|
157
|
-
mode?: string
|
|
158
|
-
revision?: string
|
|
159
|
-
} | undefined
|
|
160
|
-
let nextRevision = revision.value
|
|
161
|
-
|
|
162
|
-
if (usesPluginSettingsApi.value) {
|
|
163
|
-
response = await request.run(
|
|
164
|
-
() => pluginApi.put<{
|
|
165
|
-
settings: Record<string, unknown>
|
|
166
|
-
mode?: string
|
|
167
|
-
revision?: string
|
|
168
|
-
}>(
|
|
169
|
-
'/settings',
|
|
170
|
-
payload,
|
|
171
|
-
revision.value
|
|
172
|
-
? { headers: { 'If-Match': `"${revision.value}"` } }
|
|
173
|
-
: undefined,
|
|
174
|
-
),
|
|
175
|
-
{ success: 'save', errorMessage: 'Failed to save plugin config' },
|
|
176
|
-
)
|
|
177
|
-
nextRevision = response.revision ?? nextRevision
|
|
178
|
-
} else {
|
|
179
|
-
const dirtyKeys = changedTopLevelKeys(payload, savedConfig.value)
|
|
180
|
-
const platformOwnedChanged = dirtyKeys.has(PLATFORM_OWNED_SETTINGS_KEY)
|
|
181
|
-
const typedKeys = [...dirtyKeys].filter(
|
|
182
|
-
key => key !== PLATFORM_OWNED_SETTINGS_KEY,
|
|
183
|
-
)
|
|
184
|
-
|
|
185
|
-
if (typedKeys.length) {
|
|
186
|
-
response = await request.run(
|
|
187
|
-
() => platformApi.patch<{
|
|
188
|
-
plugin_name: string
|
|
189
|
-
config: Record<string, unknown>
|
|
190
|
-
revision?: string
|
|
191
|
-
}>(
|
|
192
|
-
`/plugins/${encodeURIComponent(name)}/config`,
|
|
193
|
-
{ config: topLevelConfigPatch(payload, typedKeys) },
|
|
194
|
-
),
|
|
195
|
-
{ success: 'save', errorMessage: 'Failed to save plugin config' },
|
|
196
|
-
)
|
|
197
|
-
nextRevision = response.revision ?? nextRevision
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
if (platformOwnedChanged) {
|
|
201
|
-
response = await request.run(
|
|
202
|
-
() => platformApi.patch<{
|
|
203
|
-
plugin_name: string
|
|
204
|
-
config: Record<string, unknown>
|
|
205
|
-
revision?: string
|
|
206
|
-
}>(
|
|
207
|
-
`/plugins/${encodeURIComponent(name)}/config`,
|
|
208
|
-
{ config: platformOwnedConfigPatch(payload) },
|
|
209
|
-
),
|
|
210
|
-
{ success: 'save', errorMessage: 'Failed to save plugin config' },
|
|
211
|
-
)
|
|
212
|
-
nextRevision = response.revision ?? nextRevision
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (!response) return true
|
|
217
|
-
const responseConfig = responseConfigPayload(response)
|
|
218
|
-
config.value = cloneConfig(responseConfig)
|
|
219
|
-
savedConfig.value = cloneConfig(responseConfig)
|
|
220
|
-
revision.value = response.revision ?? nextRevision
|
|
221
|
-
return true
|
|
222
|
-
} catch {
|
|
223
|
-
return false
|
|
224
|
-
} finally {
|
|
225
|
-
isSaving.value = false
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
function reset(): void {
|
|
230
|
-
config.value = cloneConfig(savedConfig.value)
|
|
231
|
-
request.clearError()
|
|
232
|
-
}
|
|
233
|
-
|
|
234
|
-
onMounted(() => {
|
|
235
|
-
load()
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
return {
|
|
239
|
-
config,
|
|
240
|
-
isLoading,
|
|
241
|
-
isSaving,
|
|
242
|
-
error,
|
|
243
|
-
lastLoadedAt,
|
|
244
|
-
lastSavedAt,
|
|
245
|
-
isDirty,
|
|
246
|
-
load,
|
|
247
|
-
save,
|
|
248
|
-
reset,
|
|
249
|
-
}
|
|
250
|
-
}
|