@morscherlab/mint-sdk 1.3.0 → 1.3.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/dist/__tests__/components/AutoGroupModal.anatomy.test.d.ts +1 -0
- package/dist/__tests__/components/AutoGroupModal.wiring.test.d.ts +1 -0
- package/dist/__tests__/composables/autoGroup/fieldEdits.test.d.ts +1 -0
- package/dist/__tests__/composables/autoGroup/golden.test.d.ts +1 -0
- package/dist/components/AutoGroupModal.adapter.d.ts +27 -4
- package/dist/components/PlateEditor.vue.d.ts +2 -0
- package/dist/components/SmartGroup.types.d.ts +22 -0
- package/dist/components/SmartGroupFieldRecipe.groups.d.ts +10 -2
- package/dist/components/SmartGroupFieldRecipe.vue.d.ts +3 -0
- package/dist/components/index.js +1 -1
- package/dist/{components-vHfxV2PB.js → components-CEePoD3W.js} +502 -264
- package/dist/components-CEePoD3W.js.map +1 -0
- package/dist/composables/autoGroup/classify.d.ts +7 -1
- package/dist/composables/autoGroup/columns.d.ts +16 -1
- package/dist/composables/autoGroup/index.d.ts +5 -7
- package/dist/composables/autoGroup/tokenize.d.ts +36 -1
- package/dist/composables/index.js +2 -2
- package/dist/composables/useAutoGroup.d.ts +13 -2
- package/dist/{composables-D6uqp0UF.js → composables-BbHozlA7.js} +2 -2
- package/dist/{composables-D6uqp0UF.js.map → composables-BbHozlA7.js.map} +1 -1
- package/dist/index.js +3 -3
- package/dist/install.js +1 -1
- package/dist/permissions.js +2 -2
- package/dist/permissions.js.map +1 -1
- package/dist/styles.css +71 -82
- package/dist/types/auto-group.d.ts +1 -1
- package/dist/{validation-Dmp9Q5W0.js → validation-CukfLjy-.js} +323 -187
- package/dist/validation-CukfLjy-.js.map +1 -0
- package/package.json +2 -2
- package/src/__tests__/components/AutoGroupModal.anatomy.test.ts +86 -0
- package/src/__tests__/components/AutoGroupModal.wiring.test.ts +53 -0
- package/src/__tests__/components/PlateEditor.test.ts +10 -0
- package/src/__tests__/components/SampleSelector.test.ts +14 -16
- package/src/__tests__/components/SmartGroupFieldRecipe.groups.test.ts +23 -0
- package/src/__tests__/components/SmartGroupFieldRecipe.test.ts +176 -0
- package/src/__tests__/composables/autoGroup/columns.test.ts +100 -11
- package/src/__tests__/composables/autoGroup/fieldEdits.test.ts +74 -0
- package/src/__tests__/composables/autoGroup/fingerprint.test.ts +9 -0
- package/src/__tests__/composables/autoGroup/golden.test.ts +187 -0
- package/src/__tests__/composables/autoGroup/groupByOrder.test.ts +7 -7
- package/src/__tests__/composables/autoGroup/tokenLength.test.ts +7 -0
- package/src/__tests__/composables/autoGroup/tokenize.test.ts +78 -1
- package/src/__tests__/composables/useAutoGroup.test.ts +2 -1
- package/src/__tests__/fixtures/auto-group/share-exp021.txt +103 -0
- package/src/__tests__/fixtures/auto-group/share-exp031.txt +39 -0
- package/src/__tests__/fixtures/auto-group/share-exp114.txt +123 -0
- package/src/__tests__/fixtures/auto-group/share-exp214.txt +63 -0
- package/src/__tests__/utils/permissions.test.ts +15 -0
- package/src/components/AutoGroupModal.adapter.ts +80 -9
- package/src/components/AutoGroupModal.vue +41 -8
- package/src/components/PlateEditor.vue +3 -0
- package/src/components/SmartGroup.types.ts +23 -0
- package/src/components/SmartGroupFieldRecipe.groups.ts +14 -2
- package/src/components/SmartGroupFieldRecipe.vue +289 -169
- package/src/composables/autoGroup/classify.ts +26 -7
- package/src/composables/autoGroup/columns.ts +144 -36
- package/src/composables/autoGroup/compose.ts +8 -10
- package/src/composables/autoGroup/fingerprint.ts +1 -1
- package/src/composables/autoGroup/index.ts +5 -12
- package/src/composables/autoGroup/tokenLength.ts +8 -0
- package/src/composables/autoGroup/tokenize.ts +148 -1
- package/src/composables/autoGroup/vocab.json +5 -11
- package/src/composables/useAutoGroup.ts +92 -79
- package/src/permissions.ts +3 -2
- package/src/styles/components/smart-group.css +71 -82
- package/src/types/auto-group.ts +1 -0
- package/dist/components-vHfxV2PB.js.map +0 -1
- package/dist/composables/autoGroup/replicatePreGroup.d.ts +0 -36
- package/dist/validation-Dmp9Q5W0.js.map +0 -1
- package/src/composables/autoGroup/replicatePreGroup.ts +0 -124
|
@@ -2,7 +2,7 @@ import { a as tryUseSettingsStore, c as mintApiErrorFromResponse, i as tableDens
|
|
|
2
2
|
import { a as SORT_OPTIONS, c as formatExperimentDate, f as BaseModal_default, h as BaseButton_default, l as formatExperimentStatus, m as useEventListener, p as useFocusTrap, r as EXPERIMENT_STATUS_OPTIONS, t as DATE_PRESET_OPTIONS, u as getExperimentStatusVariant } from "./experiment-utils-DTANyVKV.js";
|
|
3
3
|
import { a as normalizeOptionInput, i as BaseSelect_default, n as Skeleton_default, o as BaseInput_default, r as EmptyState_default, t as ResourcePickerListInternal_default } from "./ResourcePickerListInternal-CFAw4vTZ.js";
|
|
4
4
|
import { $n as FormulaInput_default, An as getControlDefaults, B as toBioTemplateComponentProps, Cn as SAMPLE_GROUP_TOKENS, Cr as FileUploader_default, F as getBioTemplateComponentProps, Fn as controlsToSettingsSchema, Gn as getFieldRegistryEntry, H as toBioTemplateComponentPropsById, Hr as durationMinutes, In as controlsToSidebarPanels, Jn as UnitInput_default, Kr as formatTime, L as toBioTemplateComponentBindings, Mn as controlsToFormSchema, Pn as controlsToSectionFormSchemas, R as toBioTemplateComponentBindingsById, Rr as TagsInput_default, Sn as SAMPLE_COLOR_SCALE, Sr as _plugin_vue_export_helper_default, Tr as SecretInput_default, V as toBioTemplateComponentPropsByComponent, Vr as compareTime, Xn as MoleculeInput_default, Yn as useConcentrationUnits, Zn as SequenceInput_default, _n as createPlateRowLabels, ai as useListSelection, ar as getInjectedPlatformContext, br as isRecord, ci as BaseRadioGroup_default, di as Tooltip_default, fi as BaseTextarea_default, fn as extractTemplateCollection, gn as createPlateColumnLabels, hn as WELL_PLATE_SIZE_CONFIGS, hr as normalizeJobPercent, ii as MultiSelect_default, li as BaseToggle_default, lr as createGeneratedAnalysisTransport, mn as PLATE_CONFIGS, mr as jobStatusLabel, ni as DatePicker_default, nr as GeneratedPathInput_default, qn as ConcentrationInput_default, ri as useDropdownState, rr as GENERATED_JOBS_API_KEY, si as BaseSlider_default, sr as resolveCurrentExperimentId, tr as useChemicalFormula, ui as BaseCheckbox_default, ur as useGeneratedAnalysis, vn as createWellGrid, wn as SLOT_ORDER, wr as NumberInput_default, xr as useMenuKeyboard, yn as getRectangleWellIds, yr as DateTimePicker_default, zr as TimePicker_default } from "./templates-BU1pet28.js";
|
|
5
|
-
import { B as
|
|
5
|
+
import { $ as downloadBlob, At as useAppExperiment, B as GROUPING_FIELD_ROLES, Bt as useTextSearch, C as useExperimentSamples, D as getSampleGroupMajorPrefix, E as useSampleGroups, F as useAutoGroup, Ft as usePlatformContext, G as reorderList, H as classKey, Ht as useSortedItems, It as useTheme, J as useDoseCalculator, K as useListReorder, Lt as useToast, Mt as useRuntimeAlignment, O as getSampleGroupParentPath, Ot as mergeControlWorkspaceOptions, Pt as usePresenceHeartbeat, S as useScheduleDrag, St as useControlWorkspace, T as useExpansionSet, U as useRackEditor, Ut as useRovingFocus, V as isExperimentalKind, Z as usePluginJobCenter, a as useExperimentSelector, c as DEFAULT_PRESETS, d as useReagentSeries, dt as usePluginWorkspace, f as useGroupAssignment, ft as DEFAULT_MOBILE_VIEWPORT_QUERY, i as useAnalysisArtifacts, j as readFileAsText, jt as getInjectedFrontendRevision, kt as APP_EXPERIMENT_KEY, l as DEFAULT_UNITS, m as useBioTemplatePackWorkspace, mt as useFormBuilder, n as pickerFormat, p as useBioTemplatePresetWorkspace, pt as useMobileSupportGate, q as useReorderAnnouncer, r as pickerReason, s as useProtocolTemplates, t as pickerExclusion, ut as useRequestSyncState, vt as defineDoseDesignControlModel, w as useExperimentData, wt as resolveControlModel, z as DEFAULT_COLORS } from "./validation-CukfLjy-.js";
|
|
6
6
|
import { canAccessByPolicy, hasAllPermissions } from "./permissions.js";
|
|
7
7
|
import { a as useApi, o as useAuthStore, t as useExperimentStore } from "./experiment-DgllIc3I.js";
|
|
8
8
|
import { t as ANALYSIS_FILE_ARTIFACT_SCHEMA } from "./analysisArtifactTypes-Cy3D0Ipg.js";
|
|
@@ -9445,7 +9445,8 @@ var PlateEditor_default = /* @__PURE__ */ defineComponent({
|
|
|
9445
9445
|
type: Boolean,
|
|
9446
9446
|
default: false
|
|
9447
9447
|
},
|
|
9448
|
-
size: { default: "xs" }
|
|
9448
|
+
size: { default: "xs" },
|
|
9449
|
+
hint: {}
|
|
9449
9450
|
},
|
|
9450
9451
|
emits: [
|
|
9451
9452
|
"update:activeRackId",
|
|
@@ -9718,6 +9719,7 @@ var PlateEditor_default = /* @__PURE__ */ defineComponent({
|
|
|
9718
9719
|
}
|
|
9719
9720
|
const hint = computed(() => {
|
|
9720
9721
|
if (dragMode.value) return "Drag a filled well onto another to move or swap it.";
|
|
9722
|
+
if (props.hint) return props.hint;
|
|
9721
9723
|
if (!props.groups) return "";
|
|
9722
9724
|
if (railOn.value) return inspectorOn.value ? "Click a well to edit it on the right. Drag across wells, Ctrl-click to add one or Shift-click for a range." : "Click or drag across wells to select them.";
|
|
9723
9725
|
return inspectorOn.value ? "Click a well to edit it. Ctrl- or Cmd-click to select several, Shift-click for a range." : "Click or drag across wells to select them.";
|
|
@@ -10714,6 +10716,13 @@ function appendQcGroup(groups, route, qcColor, qcCount = 3) {
|
|
|
10714
10716
|
function sampleTotalFor(route, realCount = 9, qcCount = 3) {
|
|
10715
10717
|
return route === "Exclude" ? realCount : realCount + qcCount;
|
|
10716
10718
|
}
|
|
10719
|
+
/**
|
|
10720
|
+
* True when half or more of the groups have one sample: the design has no
|
|
10721
|
+
* replicate in the names, or a field that is on is not part of the condition.
|
|
10722
|
+
*/
|
|
10723
|
+
function mostlySingletons(groups) {
|
|
10724
|
+
return groups.length > 1 && groups.filter((group) => group.count === 1).length * 2 >= groups.length;
|
|
10725
|
+
}
|
|
10717
10726
|
/** Decide which inline summary callout the Field Recipe should show. */
|
|
10718
10727
|
function fieldRecipeSummary(input) {
|
|
10719
10728
|
const groupCount = input.baseGroups.length;
|
|
@@ -10725,6 +10734,10 @@ function fieldRecipeSummary(input) {
|
|
|
10725
10734
|
kind: "warn",
|
|
10726
10735
|
groupCount
|
|
10727
10736
|
};
|
|
10737
|
+
if (mostlySingletons(input.baseGroups)) return {
|
|
10738
|
+
kind: "singletons",
|
|
10739
|
+
groupCount
|
|
10740
|
+
};
|
|
10728
10741
|
return {
|
|
10729
10742
|
kind: "info",
|
|
10730
10743
|
groupCount
|
|
@@ -10732,97 +10745,110 @@ function fieldRecipeSummary(input) {
|
|
|
10732
10745
|
}
|
|
10733
10746
|
//#endregion
|
|
10734
10747
|
//#region src/components/SmartGroupFieldRecipe.vue?vue&type=script&setup=true&lang.ts
|
|
10735
|
-
var _hoisted_1$42 = { class: "sg-
|
|
10736
|
-
var _hoisted_2$38 = { class: "sg-
|
|
10737
|
-
var _hoisted_3$31 =
|
|
10738
|
-
|
|
10739
|
-
|
|
10740
|
-
|
|
10741
|
-
};
|
|
10742
|
-
var _hoisted_5$28 = ["aria-expanded"];
|
|
10743
|
-
var _hoisted_6$26 = {
|
|
10744
|
-
key: 0,
|
|
10745
|
-
class: "fr-csv-menu",
|
|
10746
|
-
role: "menu"
|
|
10747
|
-
};
|
|
10748
|
-
var _hoisted_7$24 = [
|
|
10749
|
-
"disabled",
|
|
10750
|
-
"aria-disabled",
|
|
10751
|
-
"title"
|
|
10752
|
-
];
|
|
10753
|
-
var _hoisted_8$22 = [
|
|
10754
|
-
"disabled",
|
|
10755
|
-
"aria-disabled",
|
|
10756
|
-
"title"
|
|
10748
|
+
var _hoisted_1$42 = { class: "sg-head" };
|
|
10749
|
+
var _hoisted_2$38 = { class: "sg-head__sub" };
|
|
10750
|
+
var _hoisted_3$31 = [
|
|
10751
|
+
"aria-expanded",
|
|
10752
|
+
"onClick",
|
|
10753
|
+
"onKeydown"
|
|
10757
10754
|
];
|
|
10758
|
-
var
|
|
10755
|
+
var _hoisted_4$30 = {
|
|
10759
10756
|
class: "sg-mode",
|
|
10760
10757
|
role: "tablist",
|
|
10761
10758
|
"aria-label": "Grouping mode"
|
|
10762
10759
|
};
|
|
10763
|
-
var
|
|
10764
|
-
var
|
|
10760
|
+
var _hoisted_5$28 = { class: "sg-body" };
|
|
10761
|
+
var _hoisted_6$26 = {
|
|
10765
10762
|
key: 0,
|
|
10766
10763
|
class: "fr-dropzone"
|
|
10767
10764
|
};
|
|
10768
|
-
var
|
|
10765
|
+
var _hoisted_7$24 = {
|
|
10769
10766
|
key: 1,
|
|
10770
10767
|
class: "fr-loading"
|
|
10771
10768
|
};
|
|
10769
|
+
var _hoisted_8$22 = {
|
|
10770
|
+
key: 2,
|
|
10771
|
+
class: "fr-blank",
|
|
10772
|
+
"data-test": "recipe-empty"
|
|
10773
|
+
};
|
|
10774
|
+
var _hoisted_9$20 = {
|
|
10775
|
+
key: 0,
|
|
10776
|
+
class: "fr-anatomy"
|
|
10777
|
+
};
|
|
10778
|
+
var _hoisted_10$19 = { class: "fr-anatomy__tokens" };
|
|
10779
|
+
var _hoisted_11$17 = { class: "fr-token__text" };
|
|
10780
|
+
var _hoisted_12$16 = { class: "fr-token__caption" };
|
|
10772
10781
|
var _hoisted_13$16 = { class: "sg-recipe" };
|
|
10773
|
-
var _hoisted_14$16 = {
|
|
10774
|
-
var _hoisted_15$16 = { class: "sg-field__name" };
|
|
10775
|
-
var _hoisted_16$13 = [
|
|
10776
|
-
"aria-checked",
|
|
10777
|
-
"aria-label",
|
|
10778
|
-
"onClick"
|
|
10779
|
-
];
|
|
10780
|
-
var _hoisted_17$13 = {
|
|
10782
|
+
var _hoisted_14$16 = {
|
|
10781
10783
|
key: 0,
|
|
10782
|
-
class: "
|
|
10784
|
+
class: "fr-empty"
|
|
10783
10785
|
};
|
|
10784
|
-
var
|
|
10785
|
-
|
|
10786
|
-
"
|
|
10787
|
-
"
|
|
10788
|
-
"
|
|
10786
|
+
var _hoisted_15$16 = [
|
|
10787
|
+
"data-field",
|
|
10788
|
+
"draggable",
|
|
10789
|
+
"onDragstart",
|
|
10790
|
+
"onDragover",
|
|
10791
|
+
"onDrop"
|
|
10789
10792
|
];
|
|
10790
|
-
var
|
|
10791
|
-
|
|
10793
|
+
var _hoisted_16$13 = ["aria-label", "onKeydown"];
|
|
10794
|
+
var _hoisted_17$13 = { class: "fr-row__layer" };
|
|
10795
|
+
var _hoisted_18$13 = [
|
|
10792
10796
|
"aria-label",
|
|
10793
|
-
"
|
|
10797
|
+
"aria-invalid",
|
|
10798
|
+
"onKeydown",
|
|
10799
|
+
"onBlur"
|
|
10794
10800
|
];
|
|
10795
|
-
var
|
|
10796
|
-
|
|
10801
|
+
var _hoisted_19$13 = {
|
|
10802
|
+
key: 1,
|
|
10803
|
+
class: "fr-row__error",
|
|
10804
|
+
role: "alert"
|
|
10805
|
+
};
|
|
10806
|
+
var _hoisted_20$12 = { class: "sg-field__name" };
|
|
10807
|
+
var _hoisted_21$9 = ["aria-label", "onClick"];
|
|
10808
|
+
var _hoisted_22$9 = { class: "sg-field__vals" };
|
|
10809
|
+
var _hoisted_23$7 = {
|
|
10810
|
+
key: 3,
|
|
10811
|
+
class: "fr-row__hint"
|
|
10812
|
+
};
|
|
10813
|
+
var _hoisted_24$7 = { class: "sg-recipe" };
|
|
10814
|
+
var _hoisted_25$7 = ["data-field"];
|
|
10815
|
+
var _hoisted_26$5 = { class: "sg-field__name" };
|
|
10816
|
+
var _hoisted_27$5 = { class: "sg-field__vals" };
|
|
10817
|
+
var _hoisted_28$4 = {
|
|
10797
10818
|
key: 2,
|
|
10798
10819
|
class: "sg-summary fr-summary--mute"
|
|
10799
10820
|
};
|
|
10800
|
-
var
|
|
10801
|
-
var
|
|
10821
|
+
var _hoisted_29$4 = { class: "sg-summary__icon" };
|
|
10822
|
+
var _hoisted_30$3 = {
|
|
10802
10823
|
key: 3,
|
|
10803
10824
|
class: "sg-summary sg-summary--warn"
|
|
10804
10825
|
};
|
|
10805
|
-
var
|
|
10806
|
-
var
|
|
10826
|
+
var _hoisted_31$3 = { class: "sg-summary__icon" };
|
|
10827
|
+
var _hoisted_32$3 = {
|
|
10807
10828
|
key: 4,
|
|
10829
|
+
class: "sg-summary sg-summary--warn"
|
|
10830
|
+
};
|
|
10831
|
+
var _hoisted_33$3 = { class: "sg-summary__icon" };
|
|
10832
|
+
var _hoisted_34$2 = {
|
|
10833
|
+
key: 5,
|
|
10808
10834
|
class: "sg-summary"
|
|
10809
10835
|
};
|
|
10810
|
-
var
|
|
10811
|
-
var
|
|
10812
|
-
var
|
|
10813
|
-
var
|
|
10814
|
-
var
|
|
10815
|
-
var
|
|
10836
|
+
var _hoisted_35$2 = { class: "sg-summary__icon" };
|
|
10837
|
+
var _hoisted_36$2 = { class: "sg-body__side" };
|
|
10838
|
+
var _hoisted_37$2 = { class: "sg-preview__head" };
|
|
10839
|
+
var _hoisted_38$2 = { class: "sg-preview__count" };
|
|
10840
|
+
var _hoisted_39$2 = { class: "sg-grouplist" };
|
|
10841
|
+
var _hoisted_40$2 = {
|
|
10816
10842
|
key: 0,
|
|
10817
10843
|
class: "fr-empty"
|
|
10818
10844
|
};
|
|
10819
|
-
var
|
|
10820
|
-
var
|
|
10821
|
-
var
|
|
10822
|
-
var
|
|
10823
|
-
var
|
|
10824
|
-
var
|
|
10825
|
-
var
|
|
10845
|
+
var _hoisted_41$2 = { class: "sg-group__name" };
|
|
10846
|
+
var _hoisted_42$1 = { class: "sg-group__count" };
|
|
10847
|
+
var _hoisted_43$1 = { class: "sg-qc" };
|
|
10848
|
+
var _hoisted_44$1 = { class: "sg-qc__head" };
|
|
10849
|
+
var _hoisted_45$1 = { class: "fr-qc__chips" };
|
|
10850
|
+
var _hoisted_46$1 = { class: "sg-foot" };
|
|
10851
|
+
var _hoisted_47$1 = { class: "sg-foot__hint" };
|
|
10826
10852
|
var DEFAULT_SAMPLES = [
|
|
10827
10853
|
{
|
|
10828
10854
|
Condition: "Control",
|
|
@@ -10891,7 +10917,15 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
10891
10917
|
loading: {
|
|
10892
10918
|
type: Boolean,
|
|
10893
10919
|
default: false
|
|
10894
|
-
}
|
|
10920
|
+
},
|
|
10921
|
+
anatomy: {},
|
|
10922
|
+
hints: {},
|
|
10923
|
+
qcChips: {},
|
|
10924
|
+
renamable: {
|
|
10925
|
+
type: Boolean,
|
|
10926
|
+
default: false
|
|
10927
|
+
},
|
|
10928
|
+
reservedNames: {}
|
|
10895
10929
|
},
|
|
10896
10930
|
emits: [
|
|
10897
10931
|
"apply",
|
|
@@ -10900,6 +10934,7 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
10900
10934
|
"close",
|
|
10901
10935
|
"toggle",
|
|
10902
10936
|
"move",
|
|
10937
|
+
"rename",
|
|
10903
10938
|
"update:route",
|
|
10904
10939
|
"csv-file",
|
|
10905
10940
|
"download-template",
|
|
@@ -10926,9 +10961,9 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
10926
10961
|
check: "M20 6L9 17l-5-5",
|
|
10927
10962
|
close: "M6 18L18 6M6 6l12 12",
|
|
10928
10963
|
upload: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12",
|
|
10929
|
-
download: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3",
|
|
10930
10964
|
chev: "M6 9l6 6 6-6",
|
|
10931
|
-
|
|
10965
|
+
grip: "M9 6h.01M9 12h.01M9 18h.01M15 6h.01M15 12h.01M15 18h.01",
|
|
10966
|
+
pencil: "M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z"
|
|
10932
10967
|
};
|
|
10933
10968
|
const MAX_BAR = 44;
|
|
10934
10969
|
/** QC reads the same everywhere: neutral solid ring, never a group color (3a). */
|
|
@@ -10948,7 +10983,8 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
10948
10983
|
if (file) emit("csv-file", file);
|
|
10949
10984
|
input.value = "";
|
|
10950
10985
|
}
|
|
10951
|
-
function onDragEnter() {
|
|
10986
|
+
function onDragEnter(event) {
|
|
10987
|
+
if (!event.dataTransfer?.types.includes("Files")) return;
|
|
10952
10988
|
dragDepth += 1;
|
|
10953
10989
|
dragOver.value = true;
|
|
10954
10990
|
}
|
|
@@ -10962,25 +10998,43 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
10962
10998
|
const file = event.dataTransfer?.files?.[0];
|
|
10963
10999
|
if (file && isCsvLike(file)) emit("csv-file", file);
|
|
10964
11000
|
}
|
|
10965
|
-
const
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
|
|
10969
|
-
|
|
10970
|
-
|
|
10971
|
-
|
|
10972
|
-
|
|
10973
|
-
|
|
10974
|
-
|
|
10975
|
-
|
|
10976
|
-
|
|
10977
|
-
|
|
10978
|
-
|
|
10979
|
-
|
|
10980
|
-
|
|
10981
|
-
|
|
11001
|
+
const csvMenuItems = computed(() => [
|
|
11002
|
+
{
|
|
11003
|
+
id: "upload",
|
|
11004
|
+
label: "Upload CSV"
|
|
11005
|
+
},
|
|
11006
|
+
{
|
|
11007
|
+
id: "template",
|
|
11008
|
+
label: "Download template",
|
|
11009
|
+
disabled: !props.canDownloadTemplate
|
|
11010
|
+
},
|
|
11011
|
+
{
|
|
11012
|
+
id: "prefilled",
|
|
11013
|
+
label: "Download pre-filled",
|
|
11014
|
+
disabled: !props.canDownloadTemplate
|
|
11015
|
+
}
|
|
11016
|
+
]);
|
|
11017
|
+
function onCsvMenuSelect(item) {
|
|
11018
|
+
if (item.id === "upload") pickCsv();
|
|
11019
|
+
else if (item.id === "template") emit("download-template");
|
|
11020
|
+
else emit("download-prefilled");
|
|
10982
11021
|
}
|
|
10983
|
-
const
|
|
11022
|
+
const QC_ROUTE_OPTIONS = [
|
|
11023
|
+
{
|
|
11024
|
+
value: "Overlay only",
|
|
11025
|
+
label: "Overlay"
|
|
11026
|
+
},
|
|
11027
|
+
{
|
|
11028
|
+
value: "Exclude",
|
|
11029
|
+
label: "Exclude"
|
|
11030
|
+
},
|
|
11031
|
+
{
|
|
11032
|
+
value: "Mix into groups",
|
|
11033
|
+
label: "Mix in"
|
|
11034
|
+
}
|
|
11035
|
+
];
|
|
11036
|
+
const startLayers = props.enabled === void 0 ? props.layers : void 0;
|
|
11037
|
+
const onInner = ref(props.initialOn ? [...props.initialOn] : startLayers?.map((layer) => layer !== null) ?? props.fields.map((field) => !field.rep));
|
|
10984
11038
|
const orderInner = ref(onInner.value.flatMap((isOn, i) => isOn ? [i] : []));
|
|
10985
11039
|
const routeInner = ref(props.initialRoute);
|
|
10986
11040
|
const controlledEnabled = computed(() => props.enabled !== void 0);
|
|
@@ -10988,7 +11042,11 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
10988
11042
|
const on = computed(() => props.enabled ?? onInner.value);
|
|
10989
11043
|
const currentRoute = computed(() => props.route ?? routeInner.value);
|
|
10990
11044
|
const layers = computed(() => {
|
|
10991
|
-
if (props.layers !== void 0) return props.layers;
|
|
11045
|
+
if (props.layers !== void 0 && controlledEnabled.value) return props.layers;
|
|
11046
|
+
if (props.layers !== void 0) {
|
|
11047
|
+
let last = Math.max(0, ...props.layers.map((layer) => layer ?? 0));
|
|
11048
|
+
return props.layers.map((layer, i) => on.value[i] ? layer ?? ++last : null);
|
|
11049
|
+
}
|
|
10992
11050
|
if (controlledEnabled.value) {
|
|
10993
11051
|
let layer = 0;
|
|
10994
11052
|
return props.fields.map((_, i) => on.value[i] ? ++layer : null);
|
|
@@ -11002,19 +11060,22 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11002
11060
|
layer,
|
|
11003
11061
|
i
|
|
11004
11062
|
}]).sort((a, b) => a.layer - b.layer).map((entry) => entry.i));
|
|
11063
|
+
const onCards = computed(() => layerOrder.value.map((index) => ({
|
|
11064
|
+
index,
|
|
11065
|
+
field: props.fields[index]
|
|
11066
|
+
})));
|
|
11067
|
+
const offCards = computed(() => props.fields.flatMap((field, index) => layers.value[index] === null ? [{
|
|
11068
|
+
index,
|
|
11069
|
+
field
|
|
11070
|
+
}] : []));
|
|
11005
11071
|
const computedBase = computed(() => computeFieldGroups(props.samples, props.fields, on.value, props.palette, layerOrder.value));
|
|
11006
11072
|
const baseGroups = computed(() => props.groups ?? computedBase.value);
|
|
11007
11073
|
const groups = computed(() => props.groups ?? appendQcGroup(computedBase.value, currentRoute.value, props.qcColor));
|
|
11008
11074
|
const activeFactors = computed(() => layerOrder.value.map((i) => props.fields[i].key));
|
|
11009
11075
|
const counts = computed(() => baseGroups.value.map((group) => group.count));
|
|
11010
11076
|
const uniform = computed(() => counts.value.length > 0 && counts.value.every((count) => count === counts.value[0]));
|
|
11011
|
-
const
|
|
11012
|
-
const repOn = computed(() =>
|
|
11013
|
-
const repRange = computed(() => {
|
|
11014
|
-
const parts = (repField.value?.vals ?? "").split(",").map((part) => part.trim()).filter(Boolean);
|
|
11015
|
-
if (parts.length === 0) return "";
|
|
11016
|
-
return parts.length > 1 ? `${parts[0]}–${parts[parts.length - 1]}` : parts[0];
|
|
11017
|
-
});
|
|
11077
|
+
const repOnField = computed(() => props.fields.find((field, i) => field.rep && on.value[i]));
|
|
11078
|
+
const repOn = computed(() => repOnField.value !== void 0);
|
|
11018
11079
|
const summary = computed(() => fieldRecipeSummary({
|
|
11019
11080
|
activeFactors: activeFactors.value,
|
|
11020
11081
|
repOn: repOn.value,
|
|
@@ -11025,12 +11086,23 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11025
11086
|
const qcCount = computed(() => props.qcCount ?? Math.max(0, props.headerCount - props.samples.length));
|
|
11026
11087
|
const realCount = computed(() => Math.max(0, props.headerCount - qcCount.value));
|
|
11027
11088
|
const sampleTotal = computed(() => sampleTotalFor(currentRoute.value, realCount.value, qcCount.value));
|
|
11028
|
-
const
|
|
11029
|
-
|
|
11030
|
-
|
|
11031
|
-
|
|
11089
|
+
const qcChips = computed(() => {
|
|
11090
|
+
if (props.qcChips !== void 0) return props.qcChips;
|
|
11091
|
+
if (props.qcChip !== void 0) return props.qcChip ? [props.qcChip] : [];
|
|
11092
|
+
return currentRoute.value !== "Mix into groups" ? [{
|
|
11093
|
+
name: "QC_Pool",
|
|
11094
|
+
count: qcCount.value
|
|
11095
|
+
}] : [];
|
|
11096
|
+
});
|
|
11032
11097
|
const footHint = computed(() => currentRoute.value === "Exclude" ? ` · ${qcCount.value} QC excluded` : currentRoute.value === "Mix into groups" ? " · QC mixed in" : ` · ${qcCount.value} QC overlaid`);
|
|
11098
|
+
const root = ref(null);
|
|
11099
|
+
const controlOf = (index, selector) => root.value?.querySelector(`[data-field="${index}"] ${selector}`) ?? null;
|
|
11100
|
+
async function refocus(index, selector) {
|
|
11101
|
+
await nextTick();
|
|
11102
|
+
controlOf(index, selector)?.focus();
|
|
11103
|
+
}
|
|
11033
11104
|
function toggle(index) {
|
|
11105
|
+
refocus(index, "[role=\"switch\"]");
|
|
11034
11106
|
if (controlledEnabled.value) {
|
|
11035
11107
|
emit("toggle", index);
|
|
11036
11108
|
return;
|
|
@@ -11040,7 +11112,7 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11040
11112
|
orderInner.value = wasOn ? orderInner.value.filter((i) => i !== index) : [...orderInner.value, index];
|
|
11041
11113
|
}
|
|
11042
11114
|
function moveLayer(index, direction) {
|
|
11043
|
-
if (controlledEnabled.value) {
|
|
11115
|
+
if (controlledEnabled.value || props.layers !== void 0) {
|
|
11044
11116
|
emit("move", index, direction);
|
|
11045
11117
|
return;
|
|
11046
11118
|
}
|
|
@@ -11052,6 +11124,48 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11052
11124
|
[next[from], next[to]] = [next[to], next[from]];
|
|
11053
11125
|
orderInner.value = next;
|
|
11054
11126
|
}
|
|
11127
|
+
const reorder = useListReorder({
|
|
11128
|
+
items: () => onCards.value,
|
|
11129
|
+
getId: (card) => card.field.key,
|
|
11130
|
+
getLabel: (card) => card.field.key,
|
|
11131
|
+
itemNoun: "layer",
|
|
11132
|
+
getElement: (id) => {
|
|
11133
|
+
const card = onCards.value.find((candidate) => candidate.field.key === id);
|
|
11134
|
+
return card ? controlOf(card.index, ".fr-row__grip") : null;
|
|
11135
|
+
},
|
|
11136
|
+
onReorder: ({ fromIndex, toIndex }) => {
|
|
11137
|
+
const { index } = onCards.value[fromIndex];
|
|
11138
|
+
const direction = toIndex < fromIndex ? "up" : "down";
|
|
11139
|
+
for (let step = 0; step < Math.abs(toIndex - fromIndex); step++) moveLayer(index, direction);
|
|
11140
|
+
}
|
|
11141
|
+
});
|
|
11142
|
+
const renaming = ref(null);
|
|
11143
|
+
const draftName = ref("");
|
|
11144
|
+
const renameTaken = ref(false);
|
|
11145
|
+
const renameInput = ref([]);
|
|
11146
|
+
async function startRename(card) {
|
|
11147
|
+
renaming.value = card.index;
|
|
11148
|
+
renameTaken.value = false;
|
|
11149
|
+
draftName.value = card.field.key;
|
|
11150
|
+
await nextTick();
|
|
11151
|
+
renameInput.value[0]?.select();
|
|
11152
|
+
}
|
|
11153
|
+
function endRename(card, restoreFocus) {
|
|
11154
|
+
renaming.value = null;
|
|
11155
|
+
renameTaken.value = false;
|
|
11156
|
+
if (restoreFocus) refocus(card.index, ".fr-row__rename");
|
|
11157
|
+
}
|
|
11158
|
+
function commitRename(card, fromBlur = false) {
|
|
11159
|
+
if (renaming.value !== card.index) return;
|
|
11160
|
+
const name = draftName.value.trim();
|
|
11161
|
+
const taken = name !== card.field.key && (props.fields.some((field) => field.key === name) || (props.reservedNames?.includes(name) ?? false));
|
|
11162
|
+
if (taken && !fromBlur) {
|
|
11163
|
+
renameTaken.value = true;
|
|
11164
|
+
return;
|
|
11165
|
+
}
|
|
11166
|
+
endRename(card, !fromBlur);
|
|
11167
|
+
if (name && name !== card.field.key && !taken) emit("rename", card.index, name);
|
|
11168
|
+
}
|
|
11055
11169
|
function onRouteChange(value) {
|
|
11056
11170
|
if (controlledRoute.value) {
|
|
11057
11171
|
emit("update:route", value);
|
|
@@ -11069,79 +11183,53 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11069
11183
|
});
|
|
11070
11184
|
}
|
|
11071
11185
|
return (_ctx, _cache) => {
|
|
11072
|
-
return openBlock(), createElementBlock("div",
|
|
11073
|
-
|
|
11186
|
+
return openBlock(), createElementBlock("div", {
|
|
11187
|
+
ref_key: "root",
|
|
11188
|
+
ref: root,
|
|
11189
|
+
class: "sg-modal fr"
|
|
11190
|
+
}, [
|
|
11191
|
+
createElementVNode("div", _hoisted_1$42, [
|
|
11074
11192
|
createVNode(Icon, {
|
|
11075
11193
|
d: ICON.bolt,
|
|
11076
11194
|
size: 18
|
|
11077
11195
|
}, null, 8, ["d"]),
|
|
11078
11196
|
_cache[11] || (_cache[11] = createElementVNode("span", { class: "sg-head__title" }, "Group samples", -1)),
|
|
11079
|
-
createElementVNode("span",
|
|
11197
|
+
createElementVNode("span", _hoisted_2$38, [createTextVNode("· " + toDisplayString(__props.headerCount) + " samples", 1), __props.experimentLabel ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(" from " + toDisplayString(__props.experimentLabel), 1)], 64)) : createCommentVNode("", true)]),
|
|
11080
11198
|
_cache[12] || (_cache[12] = createElementVNode("div", { class: "sg-head__spacer" }, null, -1)),
|
|
11081
|
-
|
|
11082
|
-
|
|
11083
|
-
|
|
11199
|
+
createVNode(ActionMenu_default, {
|
|
11200
|
+
label: "CSV",
|
|
11201
|
+
items: csvMenuItems.value,
|
|
11202
|
+
onSelect: onCsvMenuSelect
|
|
11203
|
+
}, {
|
|
11204
|
+
trigger: withCtx(({ open, toggle: toggleMenu, keydown }) => [createElementVNode("button", {
|
|
11084
11205
|
type: "button",
|
|
11085
11206
|
class: "fr-upload",
|
|
11086
11207
|
"aria-haspopup": "menu",
|
|
11087
|
-
"aria-expanded":
|
|
11088
|
-
onClick:
|
|
11208
|
+
"aria-expanded": open,
|
|
11209
|
+
onClick: toggleMenu,
|
|
11210
|
+
onKeydown: keydown
|
|
11089
11211
|
}, [
|
|
11090
11212
|
createVNode(Icon, {
|
|
11091
11213
|
d: ICON.upload,
|
|
11092
11214
|
size: 14
|
|
11093
11215
|
}, null, 8, ["d"]),
|
|
11094
|
-
_cache[
|
|
11216
|
+
_cache[9] || (_cache[9] = createTextVNode(" CSV ", -1)),
|
|
11095
11217
|
createVNode(Icon, {
|
|
11096
11218
|
d: ICON.chev,
|
|
11097
11219
|
size: 13
|
|
11098
11220
|
}, null, 8, ["d"])
|
|
11099
|
-
],
|
|
11100
|
-
|
|
11101
|
-
|
|
11102
|
-
|
|
11103
|
-
|
|
11104
|
-
|
|
11105
|
-
|
|
11106
|
-
|
|
11107
|
-
|
|
11108
|
-
|
|
11109
|
-
|
|
11110
|
-
|
|
11111
|
-
type: "button",
|
|
11112
|
-
class: "fr-csv-item",
|
|
11113
|
-
role: "menuitem",
|
|
11114
|
-
disabled: !__props.canDownloadTemplate,
|
|
11115
|
-
"aria-disabled": !__props.canDownloadTemplate,
|
|
11116
|
-
title: __props.canDownloadTemplate ? void 0 : "Load samples first",
|
|
11117
|
-
onClick: chooseDownloadTemplate
|
|
11118
|
-
}, [createVNode(Icon, {
|
|
11119
|
-
d: ICON.download,
|
|
11120
|
-
size: 14
|
|
11121
|
-
}, null, 8, ["d"]), _cache[8] || (_cache[8] = createTextVNode(" Download template ", -1))], 8, _hoisted_7$24),
|
|
11122
|
-
createElementVNode("button", {
|
|
11123
|
-
type: "button",
|
|
11124
|
-
class: "fr-csv-item",
|
|
11125
|
-
role: "menuitem",
|
|
11126
|
-
disabled: !__props.canDownloadTemplate,
|
|
11127
|
-
"aria-disabled": !__props.canDownloadTemplate,
|
|
11128
|
-
title: __props.canDownloadTemplate ? void 0 : "Load samples first",
|
|
11129
|
-
onClick: chooseDownloadPrefilled
|
|
11130
|
-
}, [createVNode(Icon, {
|
|
11131
|
-
d: ICON.download,
|
|
11132
|
-
size: 14
|
|
11133
|
-
}, null, 8, ["d"]), _cache[9] || (_cache[9] = createTextVNode(" Download pre-filled ", -1))], 8, _hoisted_8$22)
|
|
11134
|
-
])) : createCommentVNode("", true),
|
|
11135
|
-
createElementVNode("input", {
|
|
11136
|
-
ref_key: "fileInput",
|
|
11137
|
-
ref: fileInput,
|
|
11138
|
-
type: "file",
|
|
11139
|
-
accept: ".csv,.tsv,text/csv,text/tab-separated-values",
|
|
11140
|
-
hidden: "",
|
|
11141
|
-
onChange: onFileChange
|
|
11142
|
-
}, null, 544)
|
|
11143
|
-
], 512),
|
|
11144
|
-
createElementVNode("div", _hoisted_9$20, [_cache[10] || (_cache[10] = createElementVNode("button", {
|
|
11221
|
+
], 40, _hoisted_3$31)]),
|
|
11222
|
+
_: 1
|
|
11223
|
+
}, 8, ["items"]),
|
|
11224
|
+
createElementVNode("input", {
|
|
11225
|
+
ref_key: "fileInput",
|
|
11226
|
+
ref: fileInput,
|
|
11227
|
+
type: "file",
|
|
11228
|
+
accept: ".csv,.tsv,text/csv,text/tab-separated-values",
|
|
11229
|
+
hidden: "",
|
|
11230
|
+
onChange: onFileChange
|
|
11231
|
+
}, null, 544),
|
|
11232
|
+
createElementVNode("div", _hoisted_4$30, [_cache[10] || (_cache[10] = createElementVNode("button", {
|
|
11145
11233
|
type: "button",
|
|
11146
11234
|
class: "sg-mode__btn sg-mode__btn--on",
|
|
11147
11235
|
role: "tab",
|
|
@@ -11151,104 +11239,166 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11151
11239
|
class: "sg-mode__btn",
|
|
11152
11240
|
role: "tab",
|
|
11153
11241
|
"aria-selected": false,
|
|
11154
|
-
onClick: _cache[
|
|
11242
|
+
onClick: _cache[0] || (_cache[0] = ($event) => emit("manual"))
|
|
11155
11243
|
}, "Manual")]),
|
|
11156
11244
|
createElementVNode("button", {
|
|
11157
11245
|
class: "sg-head__close",
|
|
11158
11246
|
"aria-label": "Close",
|
|
11159
|
-
onClick: _cache[
|
|
11247
|
+
onClick: _cache[1] || (_cache[1] = ($event) => emit("close"))
|
|
11160
11248
|
}, [createVNode(Icon, {
|
|
11161
11249
|
d: ICON.close,
|
|
11162
11250
|
size: 16
|
|
11163
11251
|
}, null, 8, ["d"])])
|
|
11164
11252
|
]),
|
|
11165
|
-
createElementVNode("div",
|
|
11253
|
+
createElementVNode("div", _hoisted_5$28, [createElementVNode("div", {
|
|
11166
11254
|
class: "sg-body__main",
|
|
11167
11255
|
onDragenter: withModifiers(onDragEnter, ["prevent"]),
|
|
11168
|
-
onDragover: _cache[
|
|
11256
|
+
onDragover: _cache[6] || (_cache[6] = withModifiers(() => {}, ["prevent"])),
|
|
11169
11257
|
onDragleave: withModifiers(onDragLeave, ["prevent"]),
|
|
11170
11258
|
onDrop: withModifiers(onDrop, ["prevent"])
|
|
11171
11259
|
}, [
|
|
11172
|
-
dragOver.value ? (openBlock(), createElementBlock("div",
|
|
11260
|
+
dragOver.value ? (openBlock(), createElementBlock("div", _hoisted_6$26, [createVNode(Icon, {
|
|
11173
11261
|
d: ICON.upload,
|
|
11174
11262
|
size: 22
|
|
11175
11263
|
}, null, 8, ["d"]), _cache[13] || (_cache[13] = createElementVNode("span", null, "Drop CSV to load samples", -1))])) : createCommentVNode("", true),
|
|
11176
|
-
__props.loading ? (openBlock(), createElementBlock("div",
|
|
11264
|
+
__props.loading ? (openBlock(), createElementBlock("div", _hoisted_7$24, [createVNode(LoadingSpinner_default, {
|
|
11177
11265
|
size: "md",
|
|
11178
11266
|
label: "Loading experiment metadata"
|
|
11179
11267
|
}), _cache[14] || (_cache[14] = createElementVNode("span", null, "Loading experiment metadata…", -1))])) : createCommentVNode("", true),
|
|
11180
|
-
|
|
11181
|
-
|
|
11182
|
-
|
|
11183
|
-
|
|
11184
|
-
|
|
11185
|
-
|
|
11186
|
-
|
|
11187
|
-
|
|
11188
|
-
|
|
11189
|
-
|
|
11190
|
-
|
|
11191
|
-
|
|
11192
|
-
|
|
11193
|
-
|
|
11194
|
-
|
|
11195
|
-
|
|
11196
|
-
|
|
11197
|
-
|
|
11198
|
-
|
|
11268
|
+
__props.fields.length === 0 && __props.headerCount === 0 && !__props.loading ? (openBlock(), createElementBlock("div", _hoisted_8$22, [
|
|
11269
|
+
_cache[16] || (_cache[16] = createElementVNode("span", { class: "sg-lead__q" }, "No samples to group", -1)),
|
|
11270
|
+
_cache[17] || (_cache[17] = createElementVNode("span", { class: "sg-lead__hint" }, " Upload a CSV with one sample column and one column for each field, or close this dialog and select samples first. ", -1)),
|
|
11271
|
+
createVNode(BaseButton_default, {
|
|
11272
|
+
variant: "secondary",
|
|
11273
|
+
size: "sm",
|
|
11274
|
+
onClick: pickCsv
|
|
11275
|
+
}, {
|
|
11276
|
+
"icon-left": withCtx(() => [createVNode(Icon, {
|
|
11277
|
+
d: ICON.upload,
|
|
11278
|
+
size: 15
|
|
11279
|
+
}, null, 8, ["d"])]),
|
|
11280
|
+
default: withCtx(() => [_cache[15] || (_cache[15] = createTextVNode(" Upload CSV ", -1))]),
|
|
11281
|
+
_: 1
|
|
11282
|
+
})
|
|
11283
|
+
])) : (openBlock(), createElementBlock(Fragment, { key: 3 }, [
|
|
11284
|
+
__props.anatomy && __props.anatomy.length > 0 ? (openBlock(), createElementBlock("div", _hoisted_9$20, [_cache[18] || (_cache[18] = createElementVNode("span", { class: "fr-label" }, "How MINT read your names", -1)), createElementVNode("div", _hoisted_10$19, [(openBlock(true), createElementBlock(Fragment, null, renderList(__props.anatomy, (token, t) => {
|
|
11285
|
+
return openBlock(), createElementBlock("span", {
|
|
11286
|
+
key: t,
|
|
11287
|
+
class: normalizeClass(["fr-token", "fr-token--" + token.state])
|
|
11288
|
+
}, [createElementVNode("span", _hoisted_11$17, toDisplayString(token.text), 1), createElementVNode("span", _hoisted_12$16, toDisplayString(token.caption), 1)], 2);
|
|
11289
|
+
}), 128))])])) : createCommentVNode("", true),
|
|
11290
|
+
_cache[28] || (_cache[28] = createElementVNode("span", { class: "fr-label" }, "Group by", -1)),
|
|
11291
|
+
createElementVNode("div", _hoisted_13$16, [onCards.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_14$16, toDisplayString(__props.fields.length === 0 ? "These sample names have no field to group by." : "No field is on. Switch on a field below."), 1)) : createCommentVNode("", true), (openBlock(true), createElementBlock(Fragment, null, renderList(onCards.value, (card, position) => {
|
|
11292
|
+
return openBlock(), createElementBlock("div", {
|
|
11293
|
+
key: card.field.key,
|
|
11294
|
+
class: normalizeClass(["sg-field sg-field--on fr-row", {
|
|
11295
|
+
"fr-field--warn": card.field.rep,
|
|
11296
|
+
"fr-row--dragging": unref(reorder).isDragging(card.field.key),
|
|
11297
|
+
"fr-row--over": unref(reorder).isDragOver(card.field.key)
|
|
11298
|
+
}]),
|
|
11299
|
+
"data-test": "field-on",
|
|
11300
|
+
"data-field": card.index,
|
|
11301
|
+
draggable: renaming.value !== card.index,
|
|
11302
|
+
onDragstart: ($event) => unref(reorder).onDragStart($event, card, position),
|
|
11303
|
+
onDragover: ($event) => unref(reorder).onDragOver($event, card, position),
|
|
11304
|
+
onDragleave: _cache[4] || (_cache[4] = (...args) => unref(reorder).onDragLeave && unref(reorder).onDragLeave(...args)),
|
|
11305
|
+
onDrop: ($event) => unref(reorder).onDrop($event, card, position),
|
|
11306
|
+
onDragend: _cache[5] || (_cache[5] = (...args) => unref(reorder).onDragEnd && unref(reorder).onDragEnd(...args))
|
|
11307
|
+
}, [
|
|
11199
11308
|
createElementVNode("button", {
|
|
11200
11309
|
type: "button",
|
|
11201
|
-
class: "
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
title: "Move up a layer",
|
|
11205
|
-
onClick: withModifiers(($event) => moveLayer(i, "up"), ["stop"])
|
|
11310
|
+
class: "fr-row__grip",
|
|
11311
|
+
"aria-label": `Move ${card.field.key}, layer ${position + 1} of ${onCards.value.length}. Press Alt and an arrow key.`,
|
|
11312
|
+
onKeydown: ($event) => unref(reorder).onKeydown($event, card, position)
|
|
11206
11313
|
}, [createVNode(Icon, {
|
|
11207
|
-
d: ICON.
|
|
11208
|
-
size:
|
|
11209
|
-
}, null, 8, ["d"])],
|
|
11210
|
-
createElementVNode("
|
|
11314
|
+
d: ICON.grip,
|
|
11315
|
+
size: 14
|
|
11316
|
+
}, null, 8, ["d"])], 40, _hoisted_16$13),
|
|
11317
|
+
createElementVNode("span", _hoisted_17$13, toDisplayString(position + 1), 1),
|
|
11318
|
+
renaming.value === card.index ? withDirectives((openBlock(), createElementBlock("input", {
|
|
11319
|
+
key: 0,
|
|
11320
|
+
ref_for: true,
|
|
11321
|
+
ref_key: "renameInput",
|
|
11322
|
+
ref: renameInput,
|
|
11323
|
+
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => draftName.value = $event),
|
|
11324
|
+
class: "fr-row__name-input",
|
|
11325
|
+
"aria-label": "New name for " + card.field.key,
|
|
11326
|
+
"aria-invalid": renameTaken.value || void 0,
|
|
11327
|
+
onInput: _cache[3] || (_cache[3] = ($event) => renameTaken.value = false),
|
|
11328
|
+
onKeydown: [withKeys(withModifiers(($event) => commitRename(card), ["prevent"]), ["enter"]), withKeys(withModifiers(($event) => endRename(card, true), ["stop"]), ["esc"])],
|
|
11329
|
+
onBlur: ($event) => commitRename(card, true)
|
|
11330
|
+
}, null, 40, _hoisted_18$13)), [[vModelText, draftName.value]]) : createCommentVNode("", true),
|
|
11331
|
+
renaming.value === card.index && renameTaken.value ? (openBlock(), createElementBlock("span", _hoisted_19$13, " Another field has this name ")) : (openBlock(), createElementBlock(Fragment, { key: 2 }, [createElementVNode("span", _hoisted_20$12, toDisplayString(card.field.key), 1), __props.renamable ? (openBlock(), createElementBlock("button", {
|
|
11332
|
+
key: 0,
|
|
11211
11333
|
type: "button",
|
|
11212
|
-
class: "
|
|
11213
|
-
|
|
11214
|
-
|
|
11215
|
-
title: "Move down a layer",
|
|
11216
|
-
onClick: withModifiers(($event) => moveLayer(i, "down"), ["stop"])
|
|
11334
|
+
class: "fr-row__rename",
|
|
11335
|
+
"aria-label": "Rename " + card.field.key,
|
|
11336
|
+
onClick: ($event) => startRename(card)
|
|
11217
11337
|
}, [createVNode(Icon, {
|
|
11218
|
-
d: ICON.
|
|
11338
|
+
d: ICON.pencil,
|
|
11219
11339
|
size: 12
|
|
11220
|
-
}, null, 8, ["d"])], 8,
|
|
11221
|
-
|
|
11222
|
-
|
|
11223
|
-
|
|
11224
|
-
|
|
11225
|
-
|
|
11226
|
-
|
|
11227
|
-
|
|
11228
|
-
|
|
11229
|
-
|
|
11230
|
-
|
|
11231
|
-
|
|
11232
|
-
|
|
11233
|
-
|
|
11234
|
-
|
|
11235
|
-
|
|
11236
|
-
|
|
11237
|
-
|
|
11238
|
-
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
|
|
11242
|
-
|
|
11243
|
-
|
|
11244
|
-
|
|
11245
|
-
|
|
11246
|
-
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
|
|
11340
|
+
}, null, 8, ["d"])], 8, _hoisted_21$9)) : createCommentVNode("", true)], 64)),
|
|
11341
|
+
createElementVNode("span", _hoisted_22$9, toDisplayString(card.field.vals), 1),
|
|
11342
|
+
__props.hints?.[card.index] ? (openBlock(), createElementBlock("span", _hoisted_23$7, toDisplayString(__props.hints[card.index]), 1)) : createCommentVNode("", true),
|
|
11343
|
+
createVNode(BaseToggle_default, {
|
|
11344
|
+
size: "sm",
|
|
11345
|
+
"model-value": true,
|
|
11346
|
+
"aria-label": "Group by " + card.field.key,
|
|
11347
|
+
"onUpdate:modelValue": ($event) => toggle(card.index)
|
|
11348
|
+
}, null, 8, ["aria-label", "onUpdate:modelValue"])
|
|
11349
|
+
], 42, _hoisted_15$16);
|
|
11350
|
+
}), 128))]),
|
|
11351
|
+
createElementVNode("span", {
|
|
11352
|
+
style: normalizeStyle(unref(reorder).announcerStyle),
|
|
11353
|
+
"aria-live": "polite"
|
|
11354
|
+
}, toDisplayString(unref(reorder).announcement.value), 5),
|
|
11355
|
+
offCards.value.length > 0 ? (openBlock(), createElementBlock(Fragment, { key: 1 }, [_cache[19] || (_cache[19] = createElementVNode("span", { class: "fr-label" }, "Left off", -1)), createElementVNode("div", _hoisted_24$7, [(openBlock(true), createElementBlock(Fragment, null, renderList(offCards.value, (card) => {
|
|
11356
|
+
return openBlock(), createElementBlock("div", {
|
|
11357
|
+
key: card.field.key,
|
|
11358
|
+
class: "sg-field fr-row",
|
|
11359
|
+
"data-test": "field-off",
|
|
11360
|
+
"data-field": card.index
|
|
11361
|
+
}, [
|
|
11362
|
+
createElementVNode("span", _hoisted_26$5, toDisplayString(card.field.key), 1),
|
|
11363
|
+
createElementVNode("span", { class: normalizeClass(["sg-field__role", { "sg-field__role--rep": card.field.rep }]) }, toDisplayString(card.field.role), 3),
|
|
11364
|
+
createElementVNode("span", _hoisted_27$5, toDisplayString(card.field.vals), 1),
|
|
11365
|
+
createVNode(BaseToggle_default, {
|
|
11366
|
+
size: "sm",
|
|
11367
|
+
"model-value": false,
|
|
11368
|
+
"aria-label": "Group by " + card.field.key,
|
|
11369
|
+
"onUpdate:modelValue": ($event) => toggle(card.index)
|
|
11370
|
+
}, null, 8, ["aria-label", "onUpdate:modelValue"])
|
|
11371
|
+
], 8, _hoisted_25$7);
|
|
11372
|
+
}), 128))])], 64)) : createCommentVNode("", true),
|
|
11373
|
+
summary.value.kind === "mute" ? (openBlock(), createElementBlock("div", _hoisted_28$4, [createElementVNode("span", _hoisted_29$4, [createVNode(Icon, {
|
|
11374
|
+
d: ICON.info,
|
|
11375
|
+
size: 16
|
|
11376
|
+
}, null, 8, ["d"])]), _cache[20] || (_cache[20] = createElementVNode("span", null, "Turn on at least one field to form groups.", -1))])) : summary.value.kind === "warn" ? (openBlock(), createElementBlock("div", _hoisted_30$3, [createElementVNode("span", _hoisted_31$3, [createVNode(Icon, {
|
|
11377
|
+
d: ICON.warn,
|
|
11378
|
+
size: 16
|
|
11379
|
+
}, null, 8, ["d"])]), createElementVNode("span", null, [
|
|
11380
|
+
_cache[21] || (_cache[21] = createTextVNode(" Including ", -1)),
|
|
11381
|
+
createElementVNode("b", null, toDisplayString(repOnField.value?.key), 1),
|
|
11382
|
+
_cache[22] || (_cache[22] = createTextVNode(" makes every sample unique — ", -1)),
|
|
11383
|
+
createElementVNode("b", null, toDisplayString(baseGroups.value.length) + " groups of 1", 1),
|
|
11384
|
+
_cache[23] || (_cache[23] = createTextVNode(". Switch it off to keep replicates together. ", -1))
|
|
11385
|
+
])])) : summary.value.kind === "singletons" ? (openBlock(), createElementBlock("div", _hoisted_32$3, [createElementVNode("span", _hoisted_33$3, [createVNode(Icon, {
|
|
11386
|
+
d: ICON.warn,
|
|
11387
|
+
size: 16
|
|
11388
|
+
}, null, 8, ["d"])]), createElementVNode("span", null, [createElementVNode("b", null, toDisplayString(counts.value.filter((count) => count === 1).length) + " of " + toDisplayString(baseGroups.value.length) + " groups", 1), _cache[24] || (_cache[24] = createTextVNode(" have one sample. Switch off a field to form larger groups. ", -1))])])) : (openBlock(), createElementBlock("div", _hoisted_34$2, [createElementVNode("span", _hoisted_35$2, [createVNode(Icon, {
|
|
11389
|
+
d: ICON.info,
|
|
11390
|
+
size: 16
|
|
11391
|
+
}, null, 8, ["d"])]), createElementVNode("span", null, [
|
|
11392
|
+
_cache[25] || (_cache[25] = createTextVNode(" Grouping by ", -1)),
|
|
11393
|
+
createElementVNode("b", null, toDisplayString(activeFactors.value.join(" × ")), 1),
|
|
11394
|
+
_cache[26] || (_cache[26] = createTextVNode(" → ", -1)),
|
|
11395
|
+
createElementVNode("b", null, [createTextVNode(toDisplayString(baseGroups.value.length) + " groups", 1), uniform.value ? (openBlock(), createElementBlock(Fragment, { key: 0 }, [createTextVNode(" of " + toDisplayString(counts.value[0]), 1)], 64)) : createCommentVNode("", true)]),
|
|
11396
|
+
_cache[27] || (_cache[27] = createTextVNode(". ", -1))
|
|
11397
|
+
])]))
|
|
11398
|
+
], 64))
|
|
11399
|
+
], 32), createElementVNode("div", _hoisted_36$2, [
|
|
11400
|
+
createElementVNode("div", _hoisted_37$2, [_cache[29] || (_cache[29] = createTextVNode(" Resulting groups ", -1)), createElementVNode("span", _hoisted_38$2, toDisplayString(groups.value.length) + " groups · " + toDisplayString(groupedSampleTotal.value) + " samples", 1)]),
|
|
11401
|
+
createElementVNode("div", _hoisted_39$2, [groups.value.length === 0 ? (openBlock(), createElementBlock("div", _hoisted_40$2, "No groups yet — pick a field to start.")) : (openBlock(true), createElementBlock(Fragment, { key: 1 }, renderList(groups.value, (group) => {
|
|
11252
11402
|
return openBlock(), createElementBlock("div", {
|
|
11253
11403
|
key: group.name,
|
|
11254
11404
|
class: "sg-group"
|
|
@@ -11257,7 +11407,7 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11257
11407
|
class: "sg-dot",
|
|
11258
11408
|
style: normalizeStyle(group.name === unref("QC_Pool") ? unref(QC_DOT_STYLE) : { background: group.color })
|
|
11259
11409
|
}, null, 4),
|
|
11260
|
-
createElementVNode("span",
|
|
11410
|
+
createElementVNode("span", _hoisted_41$2, toDisplayString(group.name), 1),
|
|
11261
11411
|
createElementVNode("span", {
|
|
11262
11412
|
class: "sg-group__bar",
|
|
11263
11413
|
style: normalizeStyle({
|
|
@@ -11265,34 +11415,36 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11265
11415
|
"--g": group.color
|
|
11266
11416
|
})
|
|
11267
11417
|
}, null, 4),
|
|
11268
|
-
createElementVNode("span",
|
|
11418
|
+
createElementVNode("span", _hoisted_42$1, toDisplayString(group.count), 1)
|
|
11269
11419
|
]);
|
|
11270
11420
|
}), 128))]),
|
|
11271
|
-
createElementVNode("div",
|
|
11272
|
-
class: "
|
|
11273
|
-
|
|
11274
|
-
|
|
11275
|
-
|
|
11276
|
-
|
|
11277
|
-
|
|
11278
|
-
|
|
11279
|
-
|
|
11280
|
-
|
|
11281
|
-
|
|
11282
|
-
|
|
11283
|
-
|
|
11284
|
-
|
|
11285
|
-
|
|
11421
|
+
createElementVNode("div", _hoisted_43$1, [createElementVNode("div", _hoisted_44$1, [_cache[30] || (_cache[30] = createElementVNode("span", { class: "sg-qc__title" }, "Quality control", -1)), createVNode(SegmentedControl_default, {
|
|
11422
|
+
class: "fr-qc__route",
|
|
11423
|
+
size: "sm",
|
|
11424
|
+
variant: "card",
|
|
11425
|
+
"aria-label": "Quality control routing",
|
|
11426
|
+
"model-value": currentRoute.value,
|
|
11427
|
+
options: QC_ROUTE_OPTIONS,
|
|
11428
|
+
"onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => onRouteChange($event))
|
|
11429
|
+
}, null, 8, ["model-value"])]), createElementVNode("div", _hoisted_45$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(qcChips.value, (chip) => {
|
|
11430
|
+
return openBlock(), createElementBlock("span", {
|
|
11431
|
+
key: chip.name,
|
|
11432
|
+
class: normalizeClass(["sg-qc__chip", { "fr-qc__chip--off": currentRoute.value === "Exclude" }])
|
|
11433
|
+
}, [createElementVNode("span", {
|
|
11434
|
+
class: "sg-dot",
|
|
11435
|
+
style: normalizeStyle(unref(QC_DOT_STYLE))
|
|
11436
|
+
}, null, 4), createTextVNode(toDisplayString(chip.name) + " ×" + toDisplayString(chip.count), 1)], 2);
|
|
11437
|
+
}), 128))])])
|
|
11286
11438
|
])]),
|
|
11287
|
-
createElementVNode("div",
|
|
11288
|
-
createElementVNode("span",
|
|
11289
|
-
_cache[
|
|
11439
|
+
createElementVNode("div", _hoisted_46$1, [
|
|
11440
|
+
createElementVNode("span", _hoisted_47$1, "Applies to " + toDisplayString(sampleTotal.value) + " samples" + toDisplayString(footHint.value), 1),
|
|
11441
|
+
_cache[33] || (_cache[33] = createElementVNode("div", { class: "sg-foot__spacer" }, null, -1)),
|
|
11290
11442
|
createVNode(BaseButton_default, {
|
|
11291
11443
|
variant: "ghost",
|
|
11292
11444
|
size: "sm",
|
|
11293
|
-
onClick: _cache[
|
|
11445
|
+
onClick: _cache[8] || (_cache[8] = ($event) => emit("cancel"))
|
|
11294
11446
|
}, {
|
|
11295
|
-
default: withCtx(() => [..._cache[
|
|
11447
|
+
default: withCtx(() => [..._cache[31] || (_cache[31] = [createTextVNode("Cancel", -1)])]),
|
|
11296
11448
|
_: 1
|
|
11297
11449
|
}),
|
|
11298
11450
|
createVNode(BaseButton_default, {
|
|
@@ -11305,11 +11457,11 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11305
11457
|
d: ICON.check,
|
|
11306
11458
|
size: 15
|
|
11307
11459
|
}, null, 8, ["d"])]),
|
|
11308
|
-
default: withCtx(() => [_cache[
|
|
11460
|
+
default: withCtx(() => [_cache[32] || (_cache[32] = createTextVNode(" Apply grouping ", -1))]),
|
|
11309
11461
|
_: 1
|
|
11310
11462
|
}, 8, ["disabled"])
|
|
11311
11463
|
])
|
|
11312
|
-
]);
|
|
11464
|
+
], 512);
|
|
11313
11465
|
};
|
|
11314
11466
|
}
|
|
11315
11467
|
});
|
|
@@ -11928,11 +12080,73 @@ function parseCSV(text) {
|
|
|
11928
12080
|
}
|
|
11929
12081
|
//#endregion
|
|
11930
12082
|
//#region src/components/AutoGroupModal.adapter.ts
|
|
12083
|
+
var PREVIEW_VALUES = 3;
|
|
12084
|
+
/** Value preview of a field card: the first three values, then the count of the rest. */
|
|
12085
|
+
function previewValues(values) {
|
|
12086
|
+
const shown = values.slice(0, PREVIEW_VALUES).join(", ");
|
|
12087
|
+
return values.length > PREVIEW_VALUES ? `${shown} … +${values.length - PREVIEW_VALUES}` : shown;
|
|
12088
|
+
}
|
|
12089
|
+
/** Experiment line of the modal header: `exp157 · 2025-10-13 · LT`. */
|
|
12090
|
+
function experimentLabel(header) {
|
|
12091
|
+
return [
|
|
12092
|
+
header.code,
|
|
12093
|
+
header.date,
|
|
12094
|
+
header.operator
|
|
12095
|
+
].filter(Boolean).join(" · ");
|
|
12096
|
+
}
|
|
12097
|
+
/**
|
|
12098
|
+
* Names of all columns of the experimental classes. A field cannot take one
|
|
12099
|
+
* of them: the engine merges fields by name.
|
|
12100
|
+
*/
|
|
12101
|
+
function engineColumnNames(schemas) {
|
|
12102
|
+
const names = Object.values(schemas).filter((schema) => isExperimentalKind(schema.classKind)).flatMap((schema) => schema.columns.map((column) => column.displayName ?? column.name));
|
|
12103
|
+
return [...new Set(names)];
|
|
12104
|
+
}
|
|
12105
|
+
/** One chip for each QC-type class, with its sample count. */
|
|
12106
|
+
function engineQcChips(classes) {
|
|
12107
|
+
return classes.filter((c) => !isExperimentalKind(c.kind)).map((c) => ({
|
|
12108
|
+
name: c.label,
|
|
12109
|
+
count: c.members.length
|
|
12110
|
+
}));
|
|
12111
|
+
}
|
|
12112
|
+
/**
|
|
12113
|
+
* The tokens of one study sample with the role the engine gave each of them,
|
|
12114
|
+
* so the user sees how the names were read. The sample is the first member of
|
|
12115
|
+
* the largest experimental class. `cards` supplies the on/off state and the
|
|
12116
|
+
* layer of the tokens that are grouping fields.
|
|
12117
|
+
*/
|
|
12118
|
+
function engineAnatomy(classes, schemas, tokenized, cards) {
|
|
12119
|
+
const cls = classes.filter((c) => isExperimentalKind(c.kind) && schemas[classKey(c)]).sort((a, b) => b.members.length - a.members.length)[0];
|
|
12120
|
+
if (!cls) return [];
|
|
12121
|
+
const tokens = tokenized[cls.members[0]] ?? [];
|
|
12122
|
+
return schemas[classKey(cls)].columns.flatMap((column) => {
|
|
12123
|
+
const text = column.sourceIndices.map((index) => tokens[index] ?? "").join("_");
|
|
12124
|
+
if (!text) return [];
|
|
12125
|
+
const name = column.displayName ?? column.name;
|
|
12126
|
+
const card = cards.fields.findIndex((field) => field.key === name);
|
|
12127
|
+
if (card === -1) return [{
|
|
12128
|
+
text,
|
|
12129
|
+
caption: /^(Field \d+|Username.*|.* \d+)$/.test(name) ? roleLabel(column.role).toLowerCase() : name,
|
|
12130
|
+
state: "fixed"
|
|
12131
|
+
}];
|
|
12132
|
+
const layer = cards.layers[card];
|
|
12133
|
+
return [layer === null ? {
|
|
12134
|
+
text,
|
|
12135
|
+
caption: name,
|
|
12136
|
+
state: "off"
|
|
12137
|
+
} : {
|
|
12138
|
+
text,
|
|
12139
|
+
caption: String(layer),
|
|
12140
|
+
state: "on"
|
|
12141
|
+
}];
|
|
12142
|
+
});
|
|
12143
|
+
}
|
|
11931
12144
|
var ROLE_LABELS = {
|
|
11932
12145
|
"constant": "Constant",
|
|
11933
12146
|
"factor": "Factor",
|
|
11934
12147
|
"replicate": "Replicate",
|
|
11935
12148
|
"run-order": "Run",
|
|
12149
|
+
"id": "Sample ID",
|
|
11936
12150
|
"numeric": "Numeric",
|
|
11937
12151
|
"class-tag": "Class tag",
|
|
11938
12152
|
"ignore": "Ignore"
|
|
@@ -11942,14 +12156,15 @@ function roleLabel(role) {
|
|
|
11942
12156
|
return role ? ROLE_LABELS[role] : "Factor";
|
|
11943
12157
|
}
|
|
11944
12158
|
/**
|
|
11945
|
-
* Columns worth offering as grouping toggles: factors
|
|
11946
|
-
*
|
|
12159
|
+
* Columns worth offering as grouping toggles: factors, numerics, replicates and
|
|
12160
|
+
* sample IDs (the last two are off by default), plus any column already enabled
|
|
12161
|
+
* in `groupBy` (so a manual group-by choice still shows).
|
|
11947
12162
|
* Preserves the engine's column order. `groupBy` is the schema's ORDERED layer
|
|
11948
12163
|
* list — entry N is hierarchy layer N of the composed group names.
|
|
11949
12164
|
*/
|
|
11950
12165
|
function candidateColumns(columns, groupBy) {
|
|
11951
12166
|
const enabled = new Set(groupBy);
|
|
11952
|
-
return columns.filter((c) =>
|
|
12167
|
+
return columns.filter((c) => GROUPING_FIELD_ROLES.has(c.role) || enabled.has(c.index));
|
|
11953
12168
|
}
|
|
11954
12169
|
/**
|
|
11955
12170
|
* Build the batch-wide field recipe from every class schema. The active schema
|
|
@@ -11965,6 +12180,7 @@ function engineSchemasToCards(schemas, activeClassKey) {
|
|
|
11965
12180
|
const enabledOrder = [];
|
|
11966
12181
|
const enabled = /* @__PURE__ */ new Set();
|
|
11967
12182
|
for (const [, schema] of ordered) {
|
|
12183
|
+
if (!isExperimentalKind(schema.classKind)) continue;
|
|
11968
12184
|
for (const index of schema.groupBy) {
|
|
11969
12185
|
const column = schema.columns.find((candidate) => candidate.index === index);
|
|
11970
12186
|
if (!column) continue;
|
|
@@ -11984,8 +12200,8 @@ function engineSchemasToCards(schemas, activeClassKey) {
|
|
|
11984
12200
|
fields: cards.map(([key, column]) => ({
|
|
11985
12201
|
key,
|
|
11986
12202
|
role: roleLabel(column.role),
|
|
11987
|
-
vals: column.uniqueValues
|
|
11988
|
-
rep: column.role === "replicate"
|
|
12203
|
+
vals: previewValues(column.uniqueValues),
|
|
12204
|
+
rep: column.role === "replicate" || column.role === "id"
|
|
11989
12205
|
})),
|
|
11990
12206
|
enabled: cards.map(([key]) => enabled.has(key)),
|
|
11991
12207
|
layers: cards.map(([key]) => {
|
|
@@ -12169,12 +12385,20 @@ var AutoGroupModal_default = /* @__PURE__ */ defineComponent({
|
|
|
12169
12385
|
const fieldCards = computed(() => engineSchemasToCards(autoGroup.schemas.value, autoGroup.activeClassKey.value));
|
|
12170
12386
|
const railGroups = computed(() => engineGroupsToRail(autoGroup.result.value.experimentalGroups ?? autoGroup.groups.value));
|
|
12171
12387
|
const qcSampleCount = computed(() => autoGroup.classes.value.filter((c) => c.kind !== "biological" && c.kind !== "unknown").reduce((acc, c) => acc + c.members.length, 0));
|
|
12172
|
-
const
|
|
12173
|
-
name: "QC_Pool",
|
|
12174
|
-
count: qcSampleCount.value
|
|
12175
|
-
} : null);
|
|
12388
|
+
const qcChips = computed(() => qcRouting.value === "mix" ? [] : engineQcChips(autoGroup.classes.value));
|
|
12176
12389
|
const fieldRecipeRoute = computed(() => engineToQcRoute(qcRouting.value));
|
|
12177
12390
|
const headerCount = computed(() => autoGroup.samples.value.length);
|
|
12391
|
+
const headerLabel = computed(() => experimentLabel(autoGroup.experiment.value));
|
|
12392
|
+
const reservedNames = computed(() => engineColumnNames(autoGroup.schemas.value));
|
|
12393
|
+
const anatomy = computed(() => autoGroup.inputMode.value === "paste" ? engineAnatomy(autoGroup.classes.value, autoGroup.schemas.value, autoGroup.tokenized.value, fieldCards.value) : []);
|
|
12394
|
+
const fieldHints = computed(() => {
|
|
12395
|
+
const needsHelp = mostlySingletons(railGroups.value);
|
|
12396
|
+
return fieldCards.value.fields.map((field, index) => {
|
|
12397
|
+
if (!needsHelp || !fieldCards.value.enabled[index]) return null;
|
|
12398
|
+
const remaining = autoGroup.groupCountWithout(field.key);
|
|
12399
|
+
return `off → ${remaining} ${remaining === 1 ? "group" : "groups"}`;
|
|
12400
|
+
});
|
|
12401
|
+
});
|
|
12178
12402
|
function onToggleField(cardIndex) {
|
|
12179
12403
|
const field = fieldCards.value.fields[cardIndex];
|
|
12180
12404
|
if (!field) return;
|
|
@@ -12185,6 +12409,11 @@ var AutoGroupModal_default = /* @__PURE__ */ defineComponent({
|
|
|
12185
12409
|
if (!field) return;
|
|
12186
12410
|
autoGroup.moveGroupByField(field.key, direction);
|
|
12187
12411
|
}
|
|
12412
|
+
function onRenameField(cardIndex, name) {
|
|
12413
|
+
const field = fieldCards.value.fields[cardIndex];
|
|
12414
|
+
if (!field) return;
|
|
12415
|
+
autoGroup.renameGroupByField(field.key, name);
|
|
12416
|
+
}
|
|
12188
12417
|
function onRouteChange(route) {
|
|
12189
12418
|
setQcRouting(qcRouteToEngine(route));
|
|
12190
12419
|
}
|
|
@@ -12293,15 +12522,20 @@ var AutoGroupModal_default = /* @__PURE__ */ defineComponent({
|
|
|
12293
12522
|
enabled: fieldCards.value.enabled,
|
|
12294
12523
|
layers: fieldCards.value.layers,
|
|
12295
12524
|
groups: railGroups.value,
|
|
12296
|
-
"qc-
|
|
12525
|
+
"qc-chips": qcChips.value,
|
|
12297
12526
|
route: fieldRecipeRoute.value,
|
|
12298
12527
|
"header-count": headerCount.value,
|
|
12299
12528
|
"qc-count": qcSampleCount.value,
|
|
12300
12529
|
"can-download-template": unref(autoGroup).canDownloadTemplate.value,
|
|
12301
12530
|
loading: experimentLoading.value,
|
|
12302
|
-
"experiment-label":
|
|
12531
|
+
"experiment-label": headerLabel.value,
|
|
12532
|
+
anatomy: anatomy.value,
|
|
12533
|
+
hints: fieldHints.value,
|
|
12534
|
+
"reserved-names": reservedNames.value,
|
|
12535
|
+
renamable: "",
|
|
12303
12536
|
onToggle: onToggleField,
|
|
12304
12537
|
onMove: onMoveField,
|
|
12538
|
+
onRename: onRenameField,
|
|
12305
12539
|
"onUpdate:route": onRouteChange,
|
|
12306
12540
|
onCsvFile,
|
|
12307
12541
|
onDownloadTemplate,
|
|
@@ -12315,12 +12549,16 @@ var AutoGroupModal_default = /* @__PURE__ */ defineComponent({
|
|
|
12315
12549
|
"enabled",
|
|
12316
12550
|
"layers",
|
|
12317
12551
|
"groups",
|
|
12318
|
-
"qc-
|
|
12552
|
+
"qc-chips",
|
|
12319
12553
|
"route",
|
|
12320
12554
|
"header-count",
|
|
12321
12555
|
"qc-count",
|
|
12322
12556
|
"can-download-template",
|
|
12323
|
-
"loading"
|
|
12557
|
+
"loading",
|
|
12558
|
+
"experiment-label",
|
|
12559
|
+
"anatomy",
|
|
12560
|
+
"hints",
|
|
12561
|
+
"reserved-names"
|
|
12324
12562
|
])) : (openBlock(), createBlock(SmartGroupManual_default, {
|
|
12325
12563
|
key: manualKey.value,
|
|
12326
12564
|
"sample-names": manualSampleNames.value,
|
|
@@ -22896,4 +23134,4 @@ var components_exports = /* @__PURE__ */ __exportAll({
|
|
|
22896
23134
|
//#endregion
|
|
22897
23135
|
export { PlateEditor_default as $, SampleLegend_default as A, AppToastContainer_default as At, StatusIndicator_default as B, ChemicalFormula_default as C, AppAvatarMenu_default as Ct, ReagentEditor_default as D, ActionMenu_default as Dt, SampleHierarchyTree_default as E, ThemeToggle_default as Et, SettingsModal_default as F, Calendar_default as Ft, ControlWorkspaceView_default as G, LayoutResizeHandle_default as H, AdductText_default as I, BasePill_default as It, SampleSelector_default as J, ComponentBindingRenderer_default as K, Breadcrumb_default as L, SegmentedControl_default as Lt, BioTemplatePackWorkspaceView_default as M, FormField_default as Mt, BioTemplateExperimentWorkspaceView_default as N, DataFrame_default as Nt, SmartGroupModal_default as O, IconButton_default as Ot, BioTemplateRenderer_default as P, LoadingSpinner_default as Pt, ReagentList_default as Q, Avatar_default as R, BaseTabs_default as Rt, sequenceSamplesRemaining as S, AppTopBar_default as St, ProtocolStepEditor_default as T, CollapsibleCard_default as Tt, AppContainer_default as U, Divider_default as V, DoseDesignWorkspaceView_default as W, SmartGroupManual_default as X, AutoGroupModal_default as Y, SmartGroupFieldRecipe_default as Z, estimateSequenceFinishDate as _, AppLayout_default as _t, ArtifactSaveDialog_default as a, GeneratedPluginView_default as at, formatSequenceRemaining as b, FormActions_default as bt, SectionCard_default as c, GeneratedPlotlyResult_default as ct, ExperimentCodeBadge_default as d, ChartContainer_default as dt, ConfirmDialog_default as et, ExperimentDataViewer_default as f, generatedJobDefaults as ft, SequenceProgressBar_default as g, MobileSupportGate_default as gt, InstrumentStateBadge_default as h, PluginWorkspaceView_default as ht, ExperimentPopover_default as i, DoseCalculator_default as it, BioTemplatePresetWorkspaceView_default as j, AlertBox_default as jt, GroupAssigner_default as k, RuntimeUpdateNotice_default as kt, ResourceCard_default as l, PlotlyChart_default as lt, AuditTrail_default as m, normalizeGeneratedJobInput as mt, FilePicker_default as n, sampleTypeMarker as nt, ArtifactSelectorModal_default as o, JobsStatusTray_default as ot, BatchProgressList_default as p, generatedJobFormSchema as pt, ScheduleCalendar_default as q, FitPanel_default as r, ExperimentTimeline_default as rt, ExperimentSelectorModal_default as s, GeneratedResultRenderer_default as st, components_exports as t, WellPlate_default as tt, TimeRangeInput_default as u, mintPlotlyTemplate as ut, estimateSequenceRemainingSeconds as v, AppSidebar_default as vt, ScientificNumber_default as w, PluginIcon_default as wt, sequenceProgressPercent as x, StepWizard_default as xt, formatSequenceEta as y, FormBuilder_default as yt, ProgressBar_default as z, SearchableSelect_default as zt };
|
|
22898
23136
|
|
|
22899
|
-
//# sourceMappingURL=components-
|
|
23137
|
+
//# sourceMappingURL=components-CEePoD3W.js.map
|