@morscherlab/mint-sdk 1.0.0-alpha.8 → 1.0.0-alpha.9
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 +15 -15
- package/dist/{auth-BYmxZdJl.js → auth-DsI0rQ7_.js} +6 -6
- package/dist/auth-DsI0rQ7_.js.map +1 -0
- package/dist/components/index.js +2 -2
- package/dist/{components-CKf-UpGi.js → components-CzbQQPCb.js} +1429 -1429
- package/dist/components-CzbQQPCb.js.map +1 -0
- package/dist/composables/index.js +2 -2
- package/dist/composables/usePlatformContext.d.ts +3 -3
- package/dist/{composables-D0QfFzq1.js → composables-BXklV5ii.js} +3 -3
- package/dist/{composables-D0QfFzq1.js.map → composables-BXklV5ii.js.map} +1 -1
- package/dist/index.js +4 -4
- package/dist/install.d.ts +3 -3
- package/dist/install.js +5 -5
- package/dist/install.js.map +1 -1
- package/dist/stores/auth.d.ts +1 -1
- package/dist/stores/index.js +1 -1
- package/dist/stores/settings.d.ts +1 -1
- package/dist/styles.css +5388 -5388
- package/dist/types/platform.d.ts +1 -1
- package/dist/{useScheduleDrag-DAJueTbK.js → useScheduleDrag-CxBeqYcu.js} +331 -331
- package/dist/useScheduleDrag-CxBeqYcu.js.map +1 -0
- package/package.json +2 -2
- package/src/__tests__/components/AppLayout.test.ts +23 -23
- package/src/__tests__/components/AppSidebar.test.ts +29 -29
- package/src/__tests__/components/AppTopBar.test.ts +45 -45
- package/src/__tests__/components/BaseInput.test.ts +2 -2
- package/src/__tests__/components/BasePill.test.ts +37 -37
- package/src/__tests__/components/Calendar.test.ts +52 -52
- package/src/__tests__/components/CollapsibleCard.test.ts +81 -81
- package/src/__tests__/components/DataFrame.test.ts +80 -80
- package/src/__tests__/components/DropdownButton.test.ts +80 -80
- package/src/__tests__/composables/usePlatformContext.test.ts +1 -1
- package/src/components/AlertBox.story.vue +1 -1
- package/src/components/AlertBox.vue +14 -14
- package/src/components/AppAvatarMenu.vue +26 -26
- package/src/components/AppContainer.vue +3 -3
- package/src/components/AppLayout.vue +7 -7
- package/src/components/AppPageSelector.vue +30 -30
- package/src/components/AppPillNav.vue +10 -10
- package/src/components/AppPluginSwitcher.vue +31 -31
- package/src/components/AppSidebar.vue +8 -8
- package/src/components/AppTopBar.story.vue +7 -7
- package/src/components/AppTopBar.vue +102 -102
- package/src/components/AuditTrail.vue +19 -19
- package/src/components/AutoGroupModal.vue +76 -76
- package/src/components/Avatar.vue +6 -6
- package/src/components/BaseButton.vue +6 -6
- package/src/components/BaseCheckbox.vue +9 -9
- package/src/components/BaseInput.vue +4 -4
- package/src/components/BaseModal.story.vue +1 -1
- package/src/components/BaseModal.vue +14 -14
- package/src/components/BasePill.vue +9 -9
- package/src/components/BaseRadioGroup.vue +21 -21
- package/src/components/BaseSelect.vue +6 -6
- package/src/components/BaseSlider.vue +8 -8
- package/src/components/BaseTabs.vue +7 -7
- package/src/components/BaseTextarea.vue +5 -5
- package/src/components/BaseToggle.vue +10 -10
- package/src/components/BatchProgressList.vue +25 -25
- package/src/components/Breadcrumb.vue +8 -8
- package/src/components/Calendar.vue +19 -19
- package/src/components/ChartContainer.vue +9 -9
- package/src/components/ChemicalFormula.vue +7 -7
- package/src/components/CollapsibleCard.vue +20 -20
- package/src/components/ColorSlider.vue +6 -6
- package/src/components/ConcentrationInput.vue +12 -12
- package/src/components/ConfirmDialog.story.vue +1 -1
- package/src/components/ConfirmDialog.vue +7 -7
- package/src/components/DataFrame.vue +40 -40
- package/src/components/DatePicker.vue +29 -29
- package/src/components/DateTimePicker.vue +41 -41
- package/src/components/Divider.vue +9 -9
- package/src/components/DoseCalculator.vue +66 -66
- package/src/components/DropdownButton.vue +19 -19
- package/src/components/EmptyState.vue +9 -9
- package/src/components/ExperimentCodeBadge.vue +3 -3
- package/src/components/ExperimentDataViewer.vue +25 -25
- package/src/components/ExperimentPopover.vue +35 -35
- package/src/components/ExperimentSelectorModal.vue +40 -40
- package/src/components/ExperimentTimeline.vue +48 -48
- package/src/components/FileUploader.vue +31 -31
- package/src/components/FitPanel.vue +9 -9
- package/src/components/FormActions.vue +1 -1
- package/src/components/FormBuilder.vue +2 -2
- package/src/components/FormField.vue +7 -7
- package/src/components/FormSection.vue +7 -7
- package/src/components/FormulaInput.vue +10 -10
- package/src/components/GroupAssigner.vue +40 -40
- package/src/components/GroupingModal.vue +45 -45
- package/src/components/IconButton.vue +6 -6
- package/src/components/LoadingSpinner.vue +5 -5
- package/src/components/MoleculeInput.vue +21 -21
- package/src/components/MultiSelect.vue +13 -13
- package/src/components/NumberInput.vue +13 -13
- package/src/components/PlateMapEditor.vue +63 -63
- package/src/components/ProgressBar.vue +18 -18
- package/src/components/ProtocolStepEditor.vue +57 -57
- package/src/components/RackEditor.vue +28 -28
- package/src/components/ReagentEditor.vue +61 -61
- package/src/components/ReagentList.vue +49 -49
- package/src/components/ResourceCard.vue +28 -28
- package/src/components/SampleHierarchyTree.vue +13 -13
- package/src/components/SampleLegend.vue +12 -12
- package/src/components/SampleSelector.vue +104 -104
- package/src/components/ScheduleCalendar.vue +42 -42
- package/src/components/ScientificNumber.vue +11 -11
- package/src/components/SegmentedControl.vue +12 -12
- package/src/components/SequenceInput.vue +32 -32
- package/src/components/SettingsButton.vue +5 -5
- package/src/components/SettingsModal.vue +17 -17
- package/src/components/StatusIndicator.vue +5 -5
- package/src/components/StepWizard.vue +16 -16
- package/src/components/TagsInput.vue +20 -20
- package/src/components/ThemeToggle.vue +3 -3
- package/src/components/TimePicker.vue +21 -21
- package/src/components/TimeRangeInput.vue +5 -5
- package/src/components/ToastNotification.vue +8 -8
- package/src/components/Tooltip.vue +7 -7
- package/src/components/UnitInput.vue +12 -12
- package/src/components/WellEditPopup.vue +28 -28
- package/src/components/WellPlate.vue +37 -37
- package/src/composables/useAppExperiment.ts +1 -1
- package/src/composables/usePlatformContext.ts +16 -16
- package/src/composables/useProtocolTemplates.ts +1 -1
- package/src/install.ts +3 -3
- package/src/stores/auth.ts +3 -3
- package/src/stores/settings.ts +2 -2
- package/src/styles/components/alert-box.css +30 -30
- package/src/styles/components/app-avatar-menu.css +23 -23
- package/src/styles/components/app-container.css +6 -6
- package/src/styles/components/app-layout.css +15 -15
- package/src/styles/components/app-page-selector.css +26 -26
- package/src/styles/components/app-pill-nav.css +7 -7
- package/src/styles/components/app-plugin-switcher.css +27 -27
- package/src/styles/components/app-sidebar.css +24 -24
- package/src/styles/components/app-top-bar.css +65 -65
- package/src/styles/components/audit-trail.css +29 -29
- package/src/styles/components/auto-group-modal.css +91 -91
- package/src/styles/components/avatar.css +15 -15
- package/src/styles/components/batch-progress-list.css +40 -40
- package/src/styles/components/breadcrumb.css +8 -8
- package/src/styles/components/button.css +31 -31
- package/src/styles/components/calendar.css +27 -27
- package/src/styles/components/chart-container.css +9 -9
- package/src/styles/components/checkbox.css +20 -20
- package/src/styles/components/chemical-formula.css +8 -8
- package/src/styles/components/collapsible-card.css +35 -35
- package/src/styles/components/color-slider.css +8 -8
- package/src/styles/components/concentration-input.css +27 -27
- package/src/styles/components/confirm-dialog.css +32 -32
- package/src/styles/components/dataframe.css +66 -66
- package/src/styles/components/date-picker.css +40 -40
- package/src/styles/components/datetime-picker.css +37 -37
- package/src/styles/components/divider.css +13 -13
- package/src/styles/components/dose-calculator.css +43 -43
- package/src/styles/components/dropdown-button.css +46 -46
- package/src/styles/components/empty-state.css +44 -44
- package/src/styles/components/experiment-code-badge.css +8 -8
- package/src/styles/components/experiment-data-viewer.css +23 -23
- package/src/styles/components/experiment-popover.css +97 -97
- package/src/styles/components/experiment-selector-modal.css +39 -39
- package/src/styles/components/experiment-timeline.css +98 -98
- package/src/styles/components/file-uploader.css +44 -44
- package/src/styles/components/fit-panel.css +12 -12
- package/src/styles/components/form-builder.css +11 -11
- package/src/styles/components/form-field.css +7 -7
- package/src/styles/components/formula-input.css +17 -17
- package/src/styles/components/group-assigner.css +26 -26
- package/src/styles/components/grouping-modal.css +51 -51
- package/src/styles/components/icon-button.css +41 -41
- package/src/styles/components/input.css +13 -13
- package/src/styles/components/loading-spinner.css +12 -12
- package/src/styles/components/modal.css +69 -69
- package/src/styles/components/molecule-input.css +27 -27
- package/src/styles/components/multi-select.css +23 -23
- package/src/styles/components/number-input.css +32 -32
- package/src/styles/components/pill.css +37 -37
- package/src/styles/components/plate-map-editor.css +67 -67
- package/src/styles/components/progress-bar.css +41 -41
- package/src/styles/components/protocol-step-editor.css +63 -63
- package/src/styles/components/rack-editor.css +34 -34
- package/src/styles/components/radio-group.css +41 -41
- package/src/styles/components/reagent-editor.css +70 -70
- package/src/styles/components/reagent-list.css +65 -65
- package/src/styles/components/resource-card.css +52 -52
- package/src/styles/components/sample-hierarchy-tree.css +56 -56
- package/src/styles/components/sample-legend.css +37 -37
- package/src/styles/components/sample-selector.css +121 -121
- package/src/styles/components/schedule-calendar.css +67 -67
- package/src/styles/components/scientific-number.css +11 -11
- package/src/styles/components/segmented-control.css +33 -33
- package/src/styles/components/select.css +11 -11
- package/src/styles/components/sequence-input.css +29 -29
- package/src/styles/components/settings-button.css +16 -16
- package/src/styles/components/settings-modal.css +14 -14
- package/src/styles/components/skeleton.css +2 -2
- package/src/styles/components/slider.css +10 -10
- package/src/styles/components/status-indicator.css +12 -12
- package/src/styles/components/step-wizard.css +32 -32
- package/src/styles/components/tabs.css +16 -16
- package/src/styles/components/tags-input.css +46 -46
- package/src/styles/components/textarea.css +17 -17
- package/src/styles/components/theme-toggle.css +13 -13
- package/src/styles/components/time-picker.css +28 -28
- package/src/styles/components/time-range-input.css +8 -8
- package/src/styles/components/toast.css +18 -18
- package/src/styles/components/toggle.css +27 -27
- package/src/styles/components/tooltip.css +18 -18
- package/src/styles/components/unit-input.css +25 -25
- package/src/styles/components/well-edit-popup.css +32 -32
- package/src/styles/components/well-plate.css +49 -49
- package/src/styles/index.css +1 -1
- package/src/styles/variables.css +3 -3
- package/src/types/platform.ts +6 -6
- package/dist/auth-BYmxZdJl.js.map +0 -1
- package/dist/components-CKf-UpGi.js.map +0 -1
- package/dist/useScheduleDrag-DAJueTbK.js.map +0 -1
|
@@ -101,21 +101,21 @@ const sampleTypeButtons = [
|
|
|
101
101
|
<template>
|
|
102
102
|
<Teleport to="body">
|
|
103
103
|
<!-- Backdrop -->
|
|
104
|
-
<div class="
|
|
104
|
+
<div class="mint-well-edit-popup__backdrop" @click="close" />
|
|
105
105
|
|
|
106
106
|
<!-- Popup -->
|
|
107
107
|
<div
|
|
108
|
-
class="
|
|
108
|
+
class="mint-well-edit-popup"
|
|
109
109
|
:style="popupStyle"
|
|
110
110
|
@click.stop
|
|
111
111
|
>
|
|
112
112
|
<!-- Header -->
|
|
113
|
-
<div class="
|
|
114
|
-
<div class="
|
|
115
|
-
<span class="
|
|
116
|
-
<span class="
|
|
113
|
+
<div class="mint-well-edit-popup__header">
|
|
114
|
+
<div class="mint-well-edit-popup__header-left">
|
|
115
|
+
<span class="mint-well-edit-popup__well-id">{{ wellId }}</span>
|
|
116
|
+
<span class="mint-well-edit-popup__title">Edit Well</span>
|
|
117
117
|
</div>
|
|
118
|
-
<button class="
|
|
118
|
+
<button class="mint-well-edit-popup__close" @click="close">
|
|
119
119
|
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
|
|
120
120
|
<path d="M18 6 6 18" /><path d="m6 6 12 12" />
|
|
121
121
|
</svg>
|
|
@@ -123,32 +123,32 @@ const sampleTypeButtons = [
|
|
|
123
123
|
</div>
|
|
124
124
|
|
|
125
125
|
<!-- Body -->
|
|
126
|
-
<div class="
|
|
126
|
+
<div class="mint-well-edit-popup__body">
|
|
127
127
|
<!-- Sample Name -->
|
|
128
128
|
<div v-if="hasField('label')">
|
|
129
|
-
<label class="
|
|
129
|
+
<label class="mint-well-edit-popup__label">Sample Name</label>
|
|
130
130
|
<input
|
|
131
131
|
v-model="formData.label"
|
|
132
132
|
type="text"
|
|
133
133
|
placeholder="e.g., Sample_001"
|
|
134
|
-
class="
|
|
134
|
+
class="mint-well-edit-popup__input"
|
|
135
135
|
@keydown.enter="save"
|
|
136
136
|
autofocus
|
|
137
137
|
/>
|
|
138
138
|
</div>
|
|
139
139
|
|
|
140
140
|
<!-- Type + Volume row -->
|
|
141
|
-
<div class="
|
|
141
|
+
<div class="mint-well-edit-popup__row">
|
|
142
142
|
<div v-if="hasField('sampleType')">
|
|
143
|
-
<label class="
|
|
144
|
-
<div class="
|
|
143
|
+
<label class="mint-well-edit-popup__label">Type</label>
|
|
144
|
+
<div class="mint-well-edit-popup__type-grid">
|
|
145
145
|
<button
|
|
146
146
|
v-for="btn in sampleTypeButtons"
|
|
147
147
|
:key="btn.type"
|
|
148
148
|
:title="btn.tooltip"
|
|
149
|
-
class="
|
|
149
|
+
class="mint-well-edit-popup__type-btn"
|
|
150
150
|
:class="{
|
|
151
|
-
[`
|
|
151
|
+
[`mint-well-edit-popup__type-btn--${btn.type}`]: formData.sampleType === btn.type,
|
|
152
152
|
}"
|
|
153
153
|
@click="formData.sampleType = btn.type"
|
|
154
154
|
>
|
|
@@ -157,14 +157,14 @@ const sampleTypeButtons = [
|
|
|
157
157
|
</div>
|
|
158
158
|
</div>
|
|
159
159
|
<div v-if="hasField('injectionVolume')">
|
|
160
|
-
<label class="
|
|
160
|
+
<label class="mint-well-edit-popup__label">Volume (uL)</label>
|
|
161
161
|
<input
|
|
162
162
|
v-model.number="formData.injectionVolume"
|
|
163
163
|
type="number"
|
|
164
164
|
min="0.1"
|
|
165
165
|
max="100"
|
|
166
166
|
step="0.5"
|
|
167
|
-
class="
|
|
167
|
+
class="mint-well-edit-popup__input"
|
|
168
168
|
/>
|
|
169
169
|
</div>
|
|
170
170
|
</div>
|
|
@@ -172,7 +172,7 @@ const sampleTypeButtons = [
|
|
|
172
172
|
<!-- Advanced toggle -->
|
|
173
173
|
<label
|
|
174
174
|
v-if="hasField('injectionCount') || hasField('customMethod')"
|
|
175
|
-
class="
|
|
175
|
+
class="mint-well-edit-popup__advanced-toggle"
|
|
176
176
|
>
|
|
177
177
|
<input type="checkbox" v-model="showAdvanced" />
|
|
178
178
|
<span>Advanced options</span>
|
|
@@ -182,13 +182,13 @@ const sampleTypeButtons = [
|
|
|
182
182
|
<template v-if="showAdvanced">
|
|
183
183
|
<!-- Injection count -->
|
|
184
184
|
<div v-if="hasField('injectionCount')">
|
|
185
|
-
<label class="
|
|
186
|
-
<div class="
|
|
185
|
+
<label class="mint-well-edit-popup__label">Repeat Injections</label>
|
|
186
|
+
<div class="mint-well-edit-popup__count-grid">
|
|
187
187
|
<button
|
|
188
188
|
v-for="n in [1, 2, 3, 4, 5]"
|
|
189
189
|
:key="n"
|
|
190
|
-
class="
|
|
191
|
-
:class="{ '
|
|
190
|
+
class="mint-well-edit-popup__count-btn"
|
|
191
|
+
:class="{ 'mint-well-edit-popup__count-btn--active': formData.injectionCount === n }"
|
|
192
192
|
@click="formData.injectionCount = n"
|
|
193
193
|
>
|
|
194
194
|
{{ n }}×
|
|
@@ -198,30 +198,30 @@ const sampleTypeButtons = [
|
|
|
198
198
|
type="number"
|
|
199
199
|
min="1"
|
|
200
200
|
max="10"
|
|
201
|
-
class="
|
|
201
|
+
class="mint-well-edit-popup__count-input"
|
|
202
202
|
/>
|
|
203
203
|
</div>
|
|
204
204
|
</div>
|
|
205
205
|
|
|
206
206
|
<!-- Custom method -->
|
|
207
207
|
<div v-if="hasField('customMethod')">
|
|
208
|
-
<label class="
|
|
208
|
+
<label class="mint-well-edit-popup__label">Custom Method Path</label>
|
|
209
209
|
<input
|
|
210
210
|
v-model="formData.customMethod"
|
|
211
211
|
type="text"
|
|
212
212
|
placeholder="Leave empty for default"
|
|
213
|
-
class="
|
|
213
|
+
class="mint-well-edit-popup__input mint-well-edit-popup__input--mono"
|
|
214
214
|
/>
|
|
215
215
|
</div>
|
|
216
216
|
</template>
|
|
217
217
|
</div>
|
|
218
218
|
|
|
219
219
|
<!-- Footer -->
|
|
220
|
-
<div class="
|
|
221
|
-
<button class="
|
|
220
|
+
<div class="mint-well-edit-popup__footer">
|
|
221
|
+
<button class="mint-well-edit-popup__btn mint-well-edit-popup__btn--clear" @click="clear">
|
|
222
222
|
Clear Well
|
|
223
223
|
</button>
|
|
224
|
-
<button class="
|
|
224
|
+
<button class="mint-well-edit-popup__btn mint-well-edit-popup__btn--save" @click="save">
|
|
225
225
|
Save
|
|
226
226
|
</button>
|
|
227
227
|
</div>
|
|
@@ -316,22 +316,22 @@ function getWellClasses(well: Well): string[] {
|
|
|
316
316
|
const isDragTarget = dragTargetWell.value === well.id
|
|
317
317
|
|
|
318
318
|
const classes = [
|
|
319
|
-
'
|
|
320
|
-
props.wellShape === 'circle' ? '
|
|
319
|
+
'mint-well-plate__well',
|
|
320
|
+
props.wellShape === 'circle' ? 'mint-well-plate__well--circle' : 'mint-well-plate__well--rounded',
|
|
321
321
|
]
|
|
322
322
|
|
|
323
323
|
if (props.selectionMode === 'drag' && well.sampleType) {
|
|
324
|
-
classes.push('
|
|
324
|
+
classes.push('mint-well-plate__well--draggable')
|
|
325
325
|
}
|
|
326
326
|
|
|
327
|
-
if (isDragSource) classes.push('
|
|
328
|
-
else if (isDragTarget) classes.push('
|
|
329
|
-
else if (isWellSelected) classes.push('
|
|
330
|
-
else if (isDragOver) classes.push('
|
|
331
|
-
else if (isHovered && !props.readonly) classes.push('
|
|
327
|
+
if (isDragSource) classes.push('mint-well-plate__well--drag-source')
|
|
328
|
+
else if (isDragTarget) classes.push('mint-well-plate__well--drag-target')
|
|
329
|
+
else if (isWellSelected) classes.push('mint-well-plate__well--selected')
|
|
330
|
+
else if (isDragOver) classes.push('mint-well-plate__well--drag-over')
|
|
331
|
+
else if (isHovered && !props.readonly) classes.push('mint-well-plate__well--hovered')
|
|
332
332
|
|
|
333
|
-
if (isDisabled) classes.push('
|
|
334
|
-
if (well.state === 'filled') classes.push('
|
|
333
|
+
if (isDisabled) classes.push('mint-well-plate__well--disabled')
|
|
334
|
+
if (well.state === 'filled') classes.push('mint-well-plate__well--filled')
|
|
335
335
|
|
|
336
336
|
return classes
|
|
337
337
|
}
|
|
@@ -589,14 +589,14 @@ const tableStyle = computed(() => ({
|
|
|
589
589
|
<template>
|
|
590
590
|
<div
|
|
591
591
|
ref="plateRef"
|
|
592
|
-
:class="['
|
|
592
|
+
:class="['mint-well-plate', isFillMode ? 'mint-well-plate--fill' : 'mint-well-plate--inline']"
|
|
593
593
|
:style="containerStyle"
|
|
594
594
|
>
|
|
595
|
-
<div class="
|
|
596
|
-
<div class="
|
|
595
|
+
<div class="mint-well-plate__scroll">
|
|
596
|
+
<div class="mint-well-plate__content">
|
|
597
597
|
<table
|
|
598
598
|
ref="tableRef"
|
|
599
|
-
class="
|
|
599
|
+
class="mint-well-plate__table"
|
|
600
600
|
role="grid"
|
|
601
601
|
:aria-label="`${props.format}-well plate`"
|
|
602
602
|
:style="tableStyle"
|
|
@@ -612,7 +612,7 @@ const tableStyle = computed(() => ({
|
|
|
612
612
|
<th
|
|
613
613
|
v-if="'condition' in span"
|
|
614
614
|
:colspan="span.colspan"
|
|
615
|
-
class="
|
|
615
|
+
class="mint-well-plate__condition-label"
|
|
616
616
|
:style="{
|
|
617
617
|
height: sizeConfig.headerHeight,
|
|
618
618
|
fontSize: sizeConfig.fontSize,
|
|
@@ -634,13 +634,13 @@ const tableStyle = computed(() => ({
|
|
|
634
634
|
<th
|
|
635
635
|
v-for="col in colLabels"
|
|
636
636
|
:key="col"
|
|
637
|
-
class="
|
|
637
|
+
class="mint-well-plate__col-header"
|
|
638
638
|
:style="{ height: sizeConfig.headerHeight, fontSize: sizeConfig.fontSize }"
|
|
639
639
|
>
|
|
640
640
|
<template v-for="entry in [colConditionMap.get(col)]" :key="col">
|
|
641
641
|
<span
|
|
642
642
|
v-if="entry"
|
|
643
|
-
class="
|
|
643
|
+
class="mint-well-plate__condition-cell"
|
|
644
644
|
:style="conditionGradientStyle(
|
|
645
645
|
entry.condition.color,
|
|
646
646
|
entry.condition.concentrations[entry.indexInGroup],
|
|
@@ -663,8 +663,8 @@ const tableStyle = computed(() => ({
|
|
|
663
663
|
:key="rowIndex"
|
|
664
664
|
:rowspan="span.rowspan"
|
|
665
665
|
:class="[
|
|
666
|
-
'
|
|
667
|
-
'gap' in span ? '
|
|
666
|
+
'mint-well-plate__row-condition-label',
|
|
667
|
+
'gap' in span ? 'mint-well-plate__row-condition-label--empty' : '',
|
|
668
668
|
]"
|
|
669
669
|
:style="{
|
|
670
670
|
width: sizeConfig.headerWidth,
|
|
@@ -673,15 +673,15 @@ const tableStyle = computed(() => ({
|
|
|
673
673
|
...('condition' in span ? { color: span.condition.color } : {}),
|
|
674
674
|
}"
|
|
675
675
|
>
|
|
676
|
-
<div v-if="'condition' in span" class="
|
|
677
|
-
<span class="
|
|
676
|
+
<div v-if="'condition' in span" class="mint-well-plate__row-condition-wrap">
|
|
677
|
+
<span class="mint-well-plate__row-condition-text">{{ span.condition.label }}</span>
|
|
678
678
|
</div>
|
|
679
679
|
</td>
|
|
680
680
|
</template>
|
|
681
681
|
<!-- Row header (with concentration overlay when conditions present) -->
|
|
682
682
|
<td
|
|
683
683
|
v-if="props.showLabels"
|
|
684
|
-
class="
|
|
684
|
+
class="mint-well-plate__row-header"
|
|
685
685
|
:style="{
|
|
686
686
|
width: sizeConfig.headerWidth,
|
|
687
687
|
height: sizeConfig.cellHeight,
|
|
@@ -693,7 +693,7 @@ const tableStyle = computed(() => ({
|
|
|
693
693
|
<template v-for="entry in [rowConditionMap.get(rowLabels[rowIndex])]" :key="rowIndex">
|
|
694
694
|
<span
|
|
695
695
|
v-if="entry"
|
|
696
|
-
class="
|
|
696
|
+
class="mint-well-plate__condition-cell"
|
|
697
697
|
:style="conditionGradientStyle(
|
|
698
698
|
entry.condition.color,
|
|
699
699
|
entry.condition.concentrations[entry.indexInGroup],
|
|
@@ -707,7 +707,7 @@ const tableStyle = computed(() => ({
|
|
|
707
707
|
</td>
|
|
708
708
|
|
|
709
709
|
<!-- Wells -->
|
|
710
|
-
<td v-for="well in row" :key="well.id" class="
|
|
710
|
+
<td v-for="well in row" :key="well.id" class="mint-well-plate__cell">
|
|
711
711
|
<div
|
|
712
712
|
role="gridcell"
|
|
713
713
|
tabindex="0"
|
|
@@ -742,21 +742,21 @@ const tableStyle = computed(() => ({
|
|
|
742
742
|
<!-- Well label text (from metadata.label) -->
|
|
743
743
|
<span
|
|
744
744
|
v-if="getWellLabel(well)"
|
|
745
|
-
class="
|
|
745
|
+
class="mint-well-plate__label"
|
|
746
746
|
>
|
|
747
747
|
{{ getWellLabel(well) }}
|
|
748
748
|
</span>
|
|
749
749
|
<!-- Sample type indicator (S/B/Q/C) -->
|
|
750
750
|
<span
|
|
751
751
|
v-else-if="getSampleTypeIndicator(well)"
|
|
752
|
-
class="
|
|
752
|
+
class="mint-well-plate__indicator"
|
|
753
753
|
>
|
|
754
754
|
{{ getSampleTypeIndicator(well) }}
|
|
755
755
|
</span>
|
|
756
756
|
<!-- Well ID -->
|
|
757
757
|
<span
|
|
758
758
|
v-else-if="props.showWellIds"
|
|
759
|
-
class="
|
|
759
|
+
class="mint-well-plate__well-id"
|
|
760
760
|
>
|
|
761
761
|
{{ well.id }}
|
|
762
762
|
</span>
|
|
@@ -764,7 +764,7 @@ const tableStyle = computed(() => ({
|
|
|
764
764
|
<!-- Badge (injection count or custom method) -->
|
|
765
765
|
<span
|
|
766
766
|
v-if="getWellBadge(well)"
|
|
767
|
-
class="
|
|
767
|
+
class="mint-well-plate__badge"
|
|
768
768
|
:style="{ backgroundColor: getWellBadge(well)!.color }"
|
|
769
769
|
:title="getWellBadge(well)!.text === '+' ? 'Custom method' : `${getWellBadge(well)!.text}x injections`"
|
|
770
770
|
>
|
|
@@ -779,32 +779,32 @@ const tableStyle = computed(() => ({
|
|
|
779
779
|
<!-- Heatmap legend (inside content wrapper to match table width) -->
|
|
780
780
|
<div
|
|
781
781
|
v-if="props.heatmap?.enabled && props.heatmap.showLegend"
|
|
782
|
-
class="
|
|
782
|
+
class="mint-well-plate__legend"
|
|
783
783
|
>
|
|
784
|
-
<span class="
|
|
785
|
-
<div class="
|
|
784
|
+
<span class="mint-well-plate__legend-label">{{ props.heatmap.min ?? 0 }}</span>
|
|
785
|
+
<div class="mint-well-plate__legend-bar">
|
|
786
786
|
<div
|
|
787
787
|
v-for="(color, index) in (props.heatmap.colorScale === 'custom' && props.heatmap.customColors?.length ? props.heatmap.customColors : heatmapColors[props.heatmap.colorScale || 'viridis'])"
|
|
788
788
|
:key="index"
|
|
789
|
-
class="
|
|
789
|
+
class="mint-well-plate__legend-segment"
|
|
790
790
|
:style="{ backgroundColor: color }"
|
|
791
791
|
/>
|
|
792
792
|
</div>
|
|
793
|
-
<span class="
|
|
793
|
+
<span class="mint-well-plate__legend-label">{{ props.heatmap.max ?? 1 }}</span>
|
|
794
794
|
</div>
|
|
795
795
|
|
|
796
796
|
<!-- Sample type legend bar -->
|
|
797
|
-
<div v-if="props.showLegend" class="
|
|
797
|
+
<div v-if="props.showLegend" class="mint-well-plate__sample-legend">
|
|
798
798
|
<div
|
|
799
799
|
v-for="item in activeLegendItems"
|
|
800
800
|
:key="item.type"
|
|
801
|
-
class="
|
|
801
|
+
class="mint-well-plate__sample-legend-item"
|
|
802
802
|
>
|
|
803
803
|
<span
|
|
804
|
-
class="
|
|
804
|
+
class="mint-well-plate__sample-legend-dot"
|
|
805
805
|
:style="{ backgroundColor: `${item.color}26`, border: `1px solid ${item.color}66` }"
|
|
806
806
|
/>
|
|
807
|
-
<span class="
|
|
807
|
+
<span class="mint-well-plate__sample-legend-text">{{ item.label }}</span>
|
|
808
808
|
</div>
|
|
809
809
|
</div>
|
|
810
810
|
</div>
|
|
@@ -71,7 +71,7 @@ export function useAppExperiment(options: UseAppExperimentOptions = {}): UseAppE
|
|
|
71
71
|
// Fallback: if no explicit experiment_code, derive `EXP-${id}` so the
|
|
72
72
|
// topbar always has a compact identifier to show instead of the long
|
|
73
73
|
// name. Matches the `EXP-${id}` format used elsewhere (e.g., queue
|
|
74
|
-
// cards in
|
|
74
|
+
// cards in mint-ms-planner). Callers with the real code should pass it
|
|
75
75
|
// via `experiment_code` to keep the topbar chip in sync with the
|
|
76
76
|
// formal code shown in the popover panel.
|
|
77
77
|
experimentCode.value = experiment.experiment_code ?? (
|
|
@@ -73,7 +73,7 @@ function resetPlatformContextState(): void {
|
|
|
73
73
|
function isOriginAllowed(origin: string): boolean {
|
|
74
74
|
// Development mode: allow any origin (must be explicitly enabled)
|
|
75
75
|
if (allowAnyOrigin) {
|
|
76
|
-
console.warn('[
|
|
76
|
+
console.warn('[MINT SDK] postMessage origin validation disabled - only use in development')
|
|
77
77
|
return true
|
|
78
78
|
}
|
|
79
79
|
|
|
@@ -87,7 +87,7 @@ function isOriginAllowed(origin: string): boolean {
|
|
|
87
87
|
}
|
|
88
88
|
|
|
89
89
|
/**
|
|
90
|
-
* Platform context composable for plugin integration with
|
|
90
|
+
* Platform context composable for plugin integration with MINT Platform.
|
|
91
91
|
*
|
|
92
92
|
* Provides secure communication with the parent platform via postMessage.
|
|
93
93
|
*
|
|
@@ -102,7 +102,7 @@ function isOriginAllowed(origin: string): boolean {
|
|
|
102
102
|
*
|
|
103
103
|
* // With explicit allowed origins
|
|
104
104
|
* const { isIntegrated } = usePlatformContext({
|
|
105
|
-
* allowedOrigins: ['https://
|
|
105
|
+
* allowedOrigins: ['https://mint.example.com']
|
|
106
106
|
* })
|
|
107
107
|
*
|
|
108
108
|
* // Development mode (UNSAFE)
|
|
@@ -111,7 +111,7 @@ function isOriginAllowed(origin: string): boolean {
|
|
|
111
111
|
* })
|
|
112
112
|
* ```
|
|
113
113
|
*/
|
|
114
|
-
/** Connects a plugin to the
|
|
114
|
+
/** Connects a plugin to the MINT platform via postMessage, exposing user, theme, and experiment context. */
|
|
115
115
|
export function usePlatformContext(options: PlatformContextOptions = {}) {
|
|
116
116
|
const consumerId = ++nextConsumerId
|
|
117
117
|
const instanceOrigins = normalizeAllowedOrigins(options.allowedOrigins)
|
|
@@ -120,7 +120,7 @@ export function usePlatformContext(options: PlatformContextOptions = {}) {
|
|
|
120
120
|
function detectPlatform(): void {
|
|
121
121
|
const detectedOrigins = new Set<string>()
|
|
122
122
|
|
|
123
|
-
// Check if running under
|
|
123
|
+
// Check if running under MINT Platform by looking for platform-injected global
|
|
124
124
|
const platformData = (window as unknown as { __MINT_PLATFORM__?: PlatformContext }).__MINT_PLATFORM__
|
|
125
125
|
|
|
126
126
|
if (platformData) {
|
|
@@ -141,10 +141,10 @@ export function usePlatformContext(options: PlatformContextOptions = {}) {
|
|
|
141
141
|
} else {
|
|
142
142
|
// Check for platform indicator in URL or localStorage
|
|
143
143
|
const urlParams = new URLSearchParams(window.location.search)
|
|
144
|
-
const hasPluginParam = urlParams.has('
|
|
144
|
+
const hasPluginParam = urlParams.has('mint-plugin')
|
|
145
145
|
|
|
146
146
|
// Try to get platform origin from URL parameter
|
|
147
|
-
const platformOrigin = urlParams.get('
|
|
147
|
+
const platformOrigin = urlParams.get('mint-origin')
|
|
148
148
|
if (platformOrigin) {
|
|
149
149
|
const origin = getOriginFromUrl(platformOrigin)
|
|
150
150
|
if (origin) {
|
|
@@ -156,7 +156,7 @@ export function usePlatformContext(options: PlatformContextOptions = {}) {
|
|
|
156
156
|
isIntegrated: hasPluginParam,
|
|
157
157
|
theme: (() => {
|
|
158
158
|
try {
|
|
159
|
-
const s = localStorage.getItem('
|
|
159
|
+
const s = localStorage.getItem('mint-settings')
|
|
160
160
|
if (s) return (JSON.parse(s).theme as 'light' | 'dark' | 'system') || 'system'
|
|
161
161
|
} catch { /* ignore */ }
|
|
162
162
|
return 'system'
|
|
@@ -174,19 +174,19 @@ export function usePlatformContext(options: PlatformContextOptions = {}) {
|
|
|
174
174
|
|
|
175
175
|
// Validate origin for security
|
|
176
176
|
if (!isOriginAllowed(event.origin)) {
|
|
177
|
-
console.warn(`[
|
|
177
|
+
console.warn(`[MINT SDK] Rejected postMessage from untrusted origin: ${event.origin}`)
|
|
178
178
|
return
|
|
179
179
|
}
|
|
180
180
|
|
|
181
181
|
try {
|
|
182
182
|
const platformEvent = event.data as PlatformEvent
|
|
183
|
-
if (!platformEvent.type?.startsWith('
|
|
183
|
+
if (!platformEvent.type?.startsWith('mint:')) return
|
|
184
184
|
|
|
185
185
|
switch (platformEvent.type) {
|
|
186
|
-
case '
|
|
186
|
+
case 'mint:theme-changed':
|
|
187
187
|
platformContext.value.theme = platformEvent.payload as 'light' | 'dark' | 'system'
|
|
188
188
|
break
|
|
189
|
-
case '
|
|
189
|
+
case 'mint:user-changed':
|
|
190
190
|
platformContext.value.user = platformEvent.payload as PlatformContext['user']
|
|
191
191
|
break
|
|
192
192
|
}
|
|
@@ -216,10 +216,10 @@ export function usePlatformContext(options: PlatformContextOptions = {}) {
|
|
|
216
216
|
} else if (allowAnyOrigin) {
|
|
217
217
|
// Development mode fallback
|
|
218
218
|
targetOrigin = '*'
|
|
219
|
-
console.warn('[
|
|
219
|
+
console.warn('[MINT SDK] Using wildcard origin for postMessage - only use in development')
|
|
220
220
|
} else {
|
|
221
221
|
// Safety: if no origin is configured, log warning and don't send
|
|
222
|
-
console.warn('[
|
|
222
|
+
console.warn('[MINT SDK] Cannot send postMessage: no platform origin configured')
|
|
223
223
|
return
|
|
224
224
|
}
|
|
225
225
|
|
|
@@ -231,7 +231,7 @@ export function usePlatformContext(options: PlatformContextOptions = {}) {
|
|
|
231
231
|
*/
|
|
232
232
|
function navigate(path: string): void {
|
|
233
233
|
sendToPlatform({
|
|
234
|
-
type: '
|
|
234
|
+
type: 'mint:navigate',
|
|
235
235
|
payload: path,
|
|
236
236
|
})
|
|
237
237
|
}
|
|
@@ -241,7 +241,7 @@ export function usePlatformContext(options: PlatformContextOptions = {}) {
|
|
|
241
241
|
*/
|
|
242
242
|
function notify(message: string, type: 'success' | 'error' | 'warning' | 'info' = 'info'): void {
|
|
243
243
|
sendToPlatform({
|
|
244
|
-
type: '
|
|
244
|
+
type: 'mint:notification',
|
|
245
245
|
payload: { message, type },
|
|
246
246
|
})
|
|
247
247
|
}
|
|
@@ -346,7 +346,7 @@ const BUILT_IN_TEMPLATES: StepTemplate[] = [
|
|
|
346
346
|
]
|
|
347
347
|
|
|
348
348
|
// Storage key for custom templates
|
|
349
|
-
const STORAGE_KEY = '
|
|
349
|
+
const STORAGE_KEY = 'mint-custom-protocol-templates'
|
|
350
350
|
|
|
351
351
|
function loadCustomTemplates(): StepTemplate[] {
|
|
352
352
|
try {
|
package/src/install.ts
CHANGED
|
@@ -2,13 +2,13 @@ import type { App, Plugin } from 'vue'
|
|
|
2
2
|
import * as components from './components'
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
|
-
* Vue plugin that registers all
|
|
5
|
+
* Vue plugin that registers all MINT SDK components globally.
|
|
6
6
|
*
|
|
7
7
|
* @example
|
|
8
8
|
* ```typescript
|
|
9
9
|
* import { createApp } from 'vue'
|
|
10
|
-
* import { MINTSdk } from '@
|
|
11
|
-
* import '@
|
|
10
|
+
* import { MINTSdk } from '@morscherlab/mint-sdk'
|
|
11
|
+
* import '@morscherlab/mint-sdk/styles'
|
|
12
12
|
*
|
|
13
13
|
* const app = createApp(App)
|
|
14
14
|
* app.use(MINTSdk)
|
package/src/stores/auth.ts
CHANGED
|
@@ -2,12 +2,12 @@ import { defineStore } from 'pinia'
|
|
|
2
2
|
import { ref, computed } from 'vue'
|
|
3
3
|
import type { AuthConfig, UserInfo } from '../types'
|
|
4
4
|
|
|
5
|
-
const AUTH_TOKEN_KEY = '
|
|
6
|
-
const AUTH_EXPIRES_KEY = '
|
|
5
|
+
const AUTH_TOKEN_KEY = 'mint-auth-token'
|
|
6
|
+
const AUTH_EXPIRES_KEY = 'mint-auth-expires'
|
|
7
7
|
|
|
8
8
|
const hasLocalStorage = typeof localStorage !== 'undefined' && typeof localStorage.getItem === 'function'
|
|
9
9
|
|
|
10
|
-
export const useAuthStore = defineStore('
|
|
10
|
+
export const useAuthStore = defineStore('mint-auth', () => {
|
|
11
11
|
// State
|
|
12
12
|
const token = ref<string | null>(null)
|
|
13
13
|
const tokenExpires = ref<Date | null>(null)
|
package/src/stores/settings.ts
CHANGED
|
@@ -23,7 +23,7 @@ export interface SettingsState {
|
|
|
23
23
|
tableDensity: TableDensity
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
const STORAGE_KEY = '
|
|
26
|
+
const STORAGE_KEY = 'mint-settings'
|
|
27
27
|
|
|
28
28
|
function getDefaultServerHost(): string {
|
|
29
29
|
if (typeof window !== 'undefined' && window.location.hostname !== 'localhost') {
|
|
@@ -82,7 +82,7 @@ function saveSettings(settings: SettingsState): void {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
export const useSettingsStore = defineStore('
|
|
85
|
+
export const useSettingsStore = defineStore('mint-settings', () => {
|
|
86
86
|
// State
|
|
87
87
|
const serverHost = ref(defaultSettings.serverHost)
|
|
88
88
|
const serverPort = ref(defaultSettings.serverPort)
|