@morscherlab/mint-sdk 1.3.0-beta.9 → 1.3.1
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/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-GDDvof8D.js → components-bbanLd1u.js} +510 -287
- package/dist/components-bbanLd1u.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 +129 -96
- 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/AppTopBarPageSelector.test.ts +4 -4
- package/src/__tests__/components/AutoGroupModal.anatomy.test.ts +86 -0
- package/src/__tests__/components/AutoGroupModal.wiring.test.ts +53 -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/SmartGroup.types.ts +23 -0
- package/src/components/SmartGroupFieldRecipe.groups.ts +14 -2
- package/src/components/SmartGroupFieldRecipe.vue +289 -169
- package/src/components/internal/AppTopBarPageSelectorInternal.vue +3 -6
- 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/app-page-selector.css +58 -14
- package/src/styles/components/smart-group.css +71 -82
- package/src/types/auto-group.ts +1 -0
- package/dist/components-GDDvof8D.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";
|
|
@@ -2866,7 +2866,7 @@ var _hoisted_4$49 = {
|
|
|
2866
2866
|
};
|
|
2867
2867
|
var _hoisted_5$47 = {
|
|
2868
2868
|
key: 0,
|
|
2869
|
-
class: "mint-
|
|
2869
|
+
class: "mint-page-selector__menu",
|
|
2870
2870
|
role: "menu"
|
|
2871
2871
|
};
|
|
2872
2872
|
var _hoisted_6$42 = {
|
|
@@ -2937,40 +2937,27 @@ var AppTopBarPageSelectorInternal_default = /* @__PURE__ */ defineComponent({
|
|
|
2937
2937
|
"stroke-linecap": "round",
|
|
2938
2938
|
"stroke-linejoin": "round"
|
|
2939
2939
|
}, [..._cache[1] || (_cache[1] = [createElementVNode("path", { d: "m6 9 6 6 6-6" }, null, -1)])], 2))])
|
|
2940
|
-
], 10, _hoisted_1$66), unref(isOpen) ? (openBlock(), createElementBlock("div", _hoisted_5$47, [_cache[
|
|
2940
|
+
], 10, _hoisted_1$66), unref(isOpen) ? (openBlock(), createElementBlock("div", _hoisted_5$47, [_cache[2] || (_cache[2] = createElementVNode("div", { class: "mint-page-selector__menu-title" }, "Go to", -1)), (openBlock(true), createElementBlock(Fragment, null, renderList(normalizedPages.value, (page) => {
|
|
2941
2941
|
return openBlock(), createBlock(ActionItemInternal_default, {
|
|
2942
2942
|
key: page.id,
|
|
2943
2943
|
href: page.href,
|
|
2944
2944
|
to: page.to,
|
|
2945
2945
|
disabled: page.disabled,
|
|
2946
2946
|
class: normalizeClass([
|
|
2947
|
-
"mint-
|
|
2948
|
-
{ "mint-
|
|
2947
|
+
"mint-page-selector__item",
|
|
2948
|
+
{ "mint-page-selector__item--active": page.id === current.value?.id },
|
|
2949
2949
|
{ "mint-page-selector__item--disabled": page.disabled }
|
|
2950
2950
|
]),
|
|
2951
2951
|
role: "menuitem",
|
|
2952
2952
|
onClick: ($event) => handleSelect(page)
|
|
2953
2953
|
}, {
|
|
2954
|
-
default: withCtx(() => [
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
}, null, 8, ["icon"])) : (openBlock(), createElementBlock("span", _hoisted_6$42, toDisplayString(page.label.charAt(0)), 1))])], 2),
|
|
2962
|
-
createElementVNode("span", _hoisted_7$38, toDisplayString(page.label), 1),
|
|
2963
|
-
_cache[2] || (_cache[2] = createElementVNode("svg", {
|
|
2964
|
-
class: "mint-menu-item__check",
|
|
2965
|
-
viewBox: "0 0 16 16",
|
|
2966
|
-
fill: "none",
|
|
2967
|
-
stroke: "currentColor",
|
|
2968
|
-
"stroke-width": "2",
|
|
2969
|
-
"stroke-linecap": "round",
|
|
2970
|
-
"stroke-linejoin": "round",
|
|
2971
|
-
"aria-hidden": "true"
|
|
2972
|
-
}, [createElementVNode("path", { d: "M3.5 8.5l3 3 6-7" })], -1))
|
|
2973
|
-
]),
|
|
2954
|
+
default: withCtx(() => [createElementVNode("span", { class: normalizeClass(["mint-page-selector__item-icon", { "mint-page-selector__item-icon--metadata": unref(isPluginIconFormat)(page.icon) }]) }, [renderSlot(_ctx.$slots, "item-icon", { page }, () => [unref(isPluginIconFormat)(page.icon) ? (openBlock(), createBlock(PluginIcon_default, {
|
|
2955
|
+
key: 0,
|
|
2956
|
+
class: "mint-page-selector__metadata-icon",
|
|
2957
|
+
icon: page.icon,
|
|
2958
|
+
size: "sm",
|
|
2959
|
+
variant: "solid"
|
|
2960
|
+
}, null, 8, ["icon"])) : (openBlock(), createElementBlock("span", _hoisted_6$42, toDisplayString(page.label.charAt(0)), 1))])], 2), createElementVNode("span", _hoisted_7$38, toDisplayString(page.label), 1)]),
|
|
2974
2961
|
_: 2
|
|
2975
2962
|
}, 1032, [
|
|
2976
2963
|
"href",
|
|
@@ -10727,6 +10714,13 @@ function appendQcGroup(groups, route, qcColor, qcCount = 3) {
|
|
|
10727
10714
|
function sampleTotalFor(route, realCount = 9, qcCount = 3) {
|
|
10728
10715
|
return route === "Exclude" ? realCount : realCount + qcCount;
|
|
10729
10716
|
}
|
|
10717
|
+
/**
|
|
10718
|
+
* True when half or more of the groups have one sample: the design has no
|
|
10719
|
+
* replicate in the names, or a field that is on is not part of the condition.
|
|
10720
|
+
*/
|
|
10721
|
+
function mostlySingletons(groups) {
|
|
10722
|
+
return groups.length > 1 && groups.filter((group) => group.count === 1).length * 2 >= groups.length;
|
|
10723
|
+
}
|
|
10730
10724
|
/** Decide which inline summary callout the Field Recipe should show. */
|
|
10731
10725
|
function fieldRecipeSummary(input) {
|
|
10732
10726
|
const groupCount = input.baseGroups.length;
|
|
@@ -10738,6 +10732,10 @@ function fieldRecipeSummary(input) {
|
|
|
10738
10732
|
kind: "warn",
|
|
10739
10733
|
groupCount
|
|
10740
10734
|
};
|
|
10735
|
+
if (mostlySingletons(input.baseGroups)) return {
|
|
10736
|
+
kind: "singletons",
|
|
10737
|
+
groupCount
|
|
10738
|
+
};
|
|
10741
10739
|
return {
|
|
10742
10740
|
kind: "info",
|
|
10743
10741
|
groupCount
|
|
@@ -10745,97 +10743,110 @@ function fieldRecipeSummary(input) {
|
|
|
10745
10743
|
}
|
|
10746
10744
|
//#endregion
|
|
10747
10745
|
//#region src/components/SmartGroupFieldRecipe.vue?vue&type=script&setup=true&lang.ts
|
|
10748
|
-
var _hoisted_1$42 = { class: "sg-
|
|
10749
|
-
var _hoisted_2$38 = { class: "sg-
|
|
10750
|
-
var _hoisted_3$31 =
|
|
10751
|
-
|
|
10752
|
-
|
|
10753
|
-
|
|
10754
|
-
};
|
|
10755
|
-
var _hoisted_5$28 = ["aria-expanded"];
|
|
10756
|
-
var _hoisted_6$26 = {
|
|
10757
|
-
key: 0,
|
|
10758
|
-
class: "fr-csv-menu",
|
|
10759
|
-
role: "menu"
|
|
10760
|
-
};
|
|
10761
|
-
var _hoisted_7$24 = [
|
|
10762
|
-
"disabled",
|
|
10763
|
-
"aria-disabled",
|
|
10764
|
-
"title"
|
|
10765
|
-
];
|
|
10766
|
-
var _hoisted_8$22 = [
|
|
10767
|
-
"disabled",
|
|
10768
|
-
"aria-disabled",
|
|
10769
|
-
"title"
|
|
10746
|
+
var _hoisted_1$42 = { class: "sg-head" };
|
|
10747
|
+
var _hoisted_2$38 = { class: "sg-head__sub" };
|
|
10748
|
+
var _hoisted_3$31 = [
|
|
10749
|
+
"aria-expanded",
|
|
10750
|
+
"onClick",
|
|
10751
|
+
"onKeydown"
|
|
10770
10752
|
];
|
|
10771
|
-
var
|
|
10753
|
+
var _hoisted_4$30 = {
|
|
10772
10754
|
class: "sg-mode",
|
|
10773
10755
|
role: "tablist",
|
|
10774
10756
|
"aria-label": "Grouping mode"
|
|
10775
10757
|
};
|
|
10776
|
-
var
|
|
10777
|
-
var
|
|
10758
|
+
var _hoisted_5$28 = { class: "sg-body" };
|
|
10759
|
+
var _hoisted_6$26 = {
|
|
10778
10760
|
key: 0,
|
|
10779
10761
|
class: "fr-dropzone"
|
|
10780
10762
|
};
|
|
10781
|
-
var
|
|
10763
|
+
var _hoisted_7$24 = {
|
|
10782
10764
|
key: 1,
|
|
10783
10765
|
class: "fr-loading"
|
|
10784
10766
|
};
|
|
10767
|
+
var _hoisted_8$22 = {
|
|
10768
|
+
key: 2,
|
|
10769
|
+
class: "fr-blank",
|
|
10770
|
+
"data-test": "recipe-empty"
|
|
10771
|
+
};
|
|
10772
|
+
var _hoisted_9$20 = {
|
|
10773
|
+
key: 0,
|
|
10774
|
+
class: "fr-anatomy"
|
|
10775
|
+
};
|
|
10776
|
+
var _hoisted_10$19 = { class: "fr-anatomy__tokens" };
|
|
10777
|
+
var _hoisted_11$17 = { class: "fr-token__text" };
|
|
10778
|
+
var _hoisted_12$16 = { class: "fr-token__caption" };
|
|
10785
10779
|
var _hoisted_13$16 = { class: "sg-recipe" };
|
|
10786
|
-
var _hoisted_14$16 = {
|
|
10787
|
-
var _hoisted_15$16 = { class: "sg-field__name" };
|
|
10788
|
-
var _hoisted_16$13 = [
|
|
10789
|
-
"aria-checked",
|
|
10790
|
-
"aria-label",
|
|
10791
|
-
"onClick"
|
|
10792
|
-
];
|
|
10793
|
-
var _hoisted_17$13 = {
|
|
10780
|
+
var _hoisted_14$16 = {
|
|
10794
10781
|
key: 0,
|
|
10795
|
-
class: "
|
|
10782
|
+
class: "fr-empty"
|
|
10796
10783
|
};
|
|
10797
|
-
var
|
|
10798
|
-
|
|
10799
|
-
"
|
|
10800
|
-
"
|
|
10801
|
-
"
|
|
10784
|
+
var _hoisted_15$16 = [
|
|
10785
|
+
"data-field",
|
|
10786
|
+
"draggable",
|
|
10787
|
+
"onDragstart",
|
|
10788
|
+
"onDragover",
|
|
10789
|
+
"onDrop"
|
|
10802
10790
|
];
|
|
10803
|
-
var
|
|
10804
|
-
|
|
10791
|
+
var _hoisted_16$13 = ["aria-label", "onKeydown"];
|
|
10792
|
+
var _hoisted_17$13 = { class: "fr-row__layer" };
|
|
10793
|
+
var _hoisted_18$13 = [
|
|
10805
10794
|
"aria-label",
|
|
10806
|
-
"
|
|
10795
|
+
"aria-invalid",
|
|
10796
|
+
"onKeydown",
|
|
10797
|
+
"onBlur"
|
|
10807
10798
|
];
|
|
10808
|
-
var
|
|
10809
|
-
|
|
10799
|
+
var _hoisted_19$13 = {
|
|
10800
|
+
key: 1,
|
|
10801
|
+
class: "fr-row__error",
|
|
10802
|
+
role: "alert"
|
|
10803
|
+
};
|
|
10804
|
+
var _hoisted_20$12 = { class: "sg-field__name" };
|
|
10805
|
+
var _hoisted_21$9 = ["aria-label", "onClick"];
|
|
10806
|
+
var _hoisted_22$9 = { class: "sg-field__vals" };
|
|
10807
|
+
var _hoisted_23$7 = {
|
|
10808
|
+
key: 3,
|
|
10809
|
+
class: "fr-row__hint"
|
|
10810
|
+
};
|
|
10811
|
+
var _hoisted_24$7 = { class: "sg-recipe" };
|
|
10812
|
+
var _hoisted_25$7 = ["data-field"];
|
|
10813
|
+
var _hoisted_26$5 = { class: "sg-field__name" };
|
|
10814
|
+
var _hoisted_27$5 = { class: "sg-field__vals" };
|
|
10815
|
+
var _hoisted_28$4 = {
|
|
10810
10816
|
key: 2,
|
|
10811
10817
|
class: "sg-summary fr-summary--mute"
|
|
10812
10818
|
};
|
|
10813
|
-
var
|
|
10814
|
-
var
|
|
10819
|
+
var _hoisted_29$4 = { class: "sg-summary__icon" };
|
|
10820
|
+
var _hoisted_30$3 = {
|
|
10815
10821
|
key: 3,
|
|
10816
10822
|
class: "sg-summary sg-summary--warn"
|
|
10817
10823
|
};
|
|
10818
|
-
var
|
|
10819
|
-
var
|
|
10824
|
+
var _hoisted_31$3 = { class: "sg-summary__icon" };
|
|
10825
|
+
var _hoisted_32$3 = {
|
|
10820
10826
|
key: 4,
|
|
10827
|
+
class: "sg-summary sg-summary--warn"
|
|
10828
|
+
};
|
|
10829
|
+
var _hoisted_33$3 = { class: "sg-summary__icon" };
|
|
10830
|
+
var _hoisted_34$2 = {
|
|
10831
|
+
key: 5,
|
|
10821
10832
|
class: "sg-summary"
|
|
10822
10833
|
};
|
|
10823
|
-
var
|
|
10824
|
-
var
|
|
10825
|
-
var
|
|
10826
|
-
var
|
|
10827
|
-
var
|
|
10828
|
-
var
|
|
10834
|
+
var _hoisted_35$2 = { class: "sg-summary__icon" };
|
|
10835
|
+
var _hoisted_36$2 = { class: "sg-body__side" };
|
|
10836
|
+
var _hoisted_37$2 = { class: "sg-preview__head" };
|
|
10837
|
+
var _hoisted_38$2 = { class: "sg-preview__count" };
|
|
10838
|
+
var _hoisted_39$2 = { class: "sg-grouplist" };
|
|
10839
|
+
var _hoisted_40$2 = {
|
|
10829
10840
|
key: 0,
|
|
10830
10841
|
class: "fr-empty"
|
|
10831
10842
|
};
|
|
10832
|
-
var
|
|
10833
|
-
var
|
|
10834
|
-
var
|
|
10835
|
-
var
|
|
10836
|
-
var
|
|
10837
|
-
var
|
|
10838
|
-
var
|
|
10843
|
+
var _hoisted_41$2 = { class: "sg-group__name" };
|
|
10844
|
+
var _hoisted_42$1 = { class: "sg-group__count" };
|
|
10845
|
+
var _hoisted_43$1 = { class: "sg-qc" };
|
|
10846
|
+
var _hoisted_44$1 = { class: "sg-qc__head" };
|
|
10847
|
+
var _hoisted_45$1 = { class: "fr-qc__chips" };
|
|
10848
|
+
var _hoisted_46$1 = { class: "sg-foot" };
|
|
10849
|
+
var _hoisted_47$1 = { class: "sg-foot__hint" };
|
|
10839
10850
|
var DEFAULT_SAMPLES = [
|
|
10840
10851
|
{
|
|
10841
10852
|
Condition: "Control",
|
|
@@ -10904,7 +10915,15 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
10904
10915
|
loading: {
|
|
10905
10916
|
type: Boolean,
|
|
10906
10917
|
default: false
|
|
10907
|
-
}
|
|
10918
|
+
},
|
|
10919
|
+
anatomy: {},
|
|
10920
|
+
hints: {},
|
|
10921
|
+
qcChips: {},
|
|
10922
|
+
renamable: {
|
|
10923
|
+
type: Boolean,
|
|
10924
|
+
default: false
|
|
10925
|
+
},
|
|
10926
|
+
reservedNames: {}
|
|
10908
10927
|
},
|
|
10909
10928
|
emits: [
|
|
10910
10929
|
"apply",
|
|
@@ -10913,6 +10932,7 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
10913
10932
|
"close",
|
|
10914
10933
|
"toggle",
|
|
10915
10934
|
"move",
|
|
10935
|
+
"rename",
|
|
10916
10936
|
"update:route",
|
|
10917
10937
|
"csv-file",
|
|
10918
10938
|
"download-template",
|
|
@@ -10939,9 +10959,9 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
10939
10959
|
check: "M20 6L9 17l-5-5",
|
|
10940
10960
|
close: "M6 18L18 6M6 6l12 12",
|
|
10941
10961
|
upload: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M17 8l-5-5-5 5M12 3v12",
|
|
10942
|
-
download: "M21 15v4a2 2 0 01-2 2H5a2 2 0 01-2-2v-4M7 10l5 5 5-5M12 15V3",
|
|
10943
10962
|
chev: "M6 9l6 6 6-6",
|
|
10944
|
-
|
|
10963
|
+
grip: "M9 6h.01M9 12h.01M9 18h.01M15 6h.01M15 12h.01M15 18h.01",
|
|
10964
|
+
pencil: "M12 20h9M16.5 3.5a2.12 2.12 0 013 3L7 19l-4 1 1-4L16.5 3.5z"
|
|
10945
10965
|
};
|
|
10946
10966
|
const MAX_BAR = 44;
|
|
10947
10967
|
/** QC reads the same everywhere: neutral solid ring, never a group color (3a). */
|
|
@@ -10961,7 +10981,8 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
10961
10981
|
if (file) emit("csv-file", file);
|
|
10962
10982
|
input.value = "";
|
|
10963
10983
|
}
|
|
10964
|
-
function onDragEnter() {
|
|
10984
|
+
function onDragEnter(event) {
|
|
10985
|
+
if (!event.dataTransfer?.types.includes("Files")) return;
|
|
10965
10986
|
dragDepth += 1;
|
|
10966
10987
|
dragOver.value = true;
|
|
10967
10988
|
}
|
|
@@ -10975,25 +10996,43 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
10975
10996
|
const file = event.dataTransfer?.files?.[0];
|
|
10976
10997
|
if (file && isCsvLike(file)) emit("csv-file", file);
|
|
10977
10998
|
}
|
|
10978
|
-
const
|
|
10979
|
-
|
|
10980
|
-
|
|
10981
|
-
|
|
10982
|
-
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
|
|
10989
|
-
|
|
10990
|
-
|
|
10991
|
-
|
|
10992
|
-
|
|
10993
|
-
|
|
10994
|
-
|
|
10999
|
+
const csvMenuItems = computed(() => [
|
|
11000
|
+
{
|
|
11001
|
+
id: "upload",
|
|
11002
|
+
label: "Upload CSV"
|
|
11003
|
+
},
|
|
11004
|
+
{
|
|
11005
|
+
id: "template",
|
|
11006
|
+
label: "Download template",
|
|
11007
|
+
disabled: !props.canDownloadTemplate
|
|
11008
|
+
},
|
|
11009
|
+
{
|
|
11010
|
+
id: "prefilled",
|
|
11011
|
+
label: "Download pre-filled",
|
|
11012
|
+
disabled: !props.canDownloadTemplate
|
|
11013
|
+
}
|
|
11014
|
+
]);
|
|
11015
|
+
function onCsvMenuSelect(item) {
|
|
11016
|
+
if (item.id === "upload") pickCsv();
|
|
11017
|
+
else if (item.id === "template") emit("download-template");
|
|
11018
|
+
else emit("download-prefilled");
|
|
10995
11019
|
}
|
|
10996
|
-
const
|
|
11020
|
+
const QC_ROUTE_OPTIONS = [
|
|
11021
|
+
{
|
|
11022
|
+
value: "Overlay only",
|
|
11023
|
+
label: "Overlay"
|
|
11024
|
+
},
|
|
11025
|
+
{
|
|
11026
|
+
value: "Exclude",
|
|
11027
|
+
label: "Exclude"
|
|
11028
|
+
},
|
|
11029
|
+
{
|
|
11030
|
+
value: "Mix into groups",
|
|
11031
|
+
label: "Mix in"
|
|
11032
|
+
}
|
|
11033
|
+
];
|
|
11034
|
+
const startLayers = props.enabled === void 0 ? props.layers : void 0;
|
|
11035
|
+
const onInner = ref(props.initialOn ? [...props.initialOn] : startLayers?.map((layer) => layer !== null) ?? props.fields.map((field) => !field.rep));
|
|
10997
11036
|
const orderInner = ref(onInner.value.flatMap((isOn, i) => isOn ? [i] : []));
|
|
10998
11037
|
const routeInner = ref(props.initialRoute);
|
|
10999
11038
|
const controlledEnabled = computed(() => props.enabled !== void 0);
|
|
@@ -11001,7 +11040,11 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11001
11040
|
const on = computed(() => props.enabled ?? onInner.value);
|
|
11002
11041
|
const currentRoute = computed(() => props.route ?? routeInner.value);
|
|
11003
11042
|
const layers = computed(() => {
|
|
11004
|
-
if (props.layers !== void 0) return props.layers;
|
|
11043
|
+
if (props.layers !== void 0 && controlledEnabled.value) return props.layers;
|
|
11044
|
+
if (props.layers !== void 0) {
|
|
11045
|
+
let last = Math.max(0, ...props.layers.map((layer) => layer ?? 0));
|
|
11046
|
+
return props.layers.map((layer, i) => on.value[i] ? layer ?? ++last : null);
|
|
11047
|
+
}
|
|
11005
11048
|
if (controlledEnabled.value) {
|
|
11006
11049
|
let layer = 0;
|
|
11007
11050
|
return props.fields.map((_, i) => on.value[i] ? ++layer : null);
|
|
@@ -11015,19 +11058,22 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11015
11058
|
layer,
|
|
11016
11059
|
i
|
|
11017
11060
|
}]).sort((a, b) => a.layer - b.layer).map((entry) => entry.i));
|
|
11061
|
+
const onCards = computed(() => layerOrder.value.map((index) => ({
|
|
11062
|
+
index,
|
|
11063
|
+
field: props.fields[index]
|
|
11064
|
+
})));
|
|
11065
|
+
const offCards = computed(() => props.fields.flatMap((field, index) => layers.value[index] === null ? [{
|
|
11066
|
+
index,
|
|
11067
|
+
field
|
|
11068
|
+
}] : []));
|
|
11018
11069
|
const computedBase = computed(() => computeFieldGroups(props.samples, props.fields, on.value, props.palette, layerOrder.value));
|
|
11019
11070
|
const baseGroups = computed(() => props.groups ?? computedBase.value);
|
|
11020
11071
|
const groups = computed(() => props.groups ?? appendQcGroup(computedBase.value, currentRoute.value, props.qcColor));
|
|
11021
11072
|
const activeFactors = computed(() => layerOrder.value.map((i) => props.fields[i].key));
|
|
11022
11073
|
const counts = computed(() => baseGroups.value.map((group) => group.count));
|
|
11023
11074
|
const uniform = computed(() => counts.value.length > 0 && counts.value.every((count) => count === counts.value[0]));
|
|
11024
|
-
const
|
|
11025
|
-
const repOn = computed(() =>
|
|
11026
|
-
const repRange = computed(() => {
|
|
11027
|
-
const parts = (repField.value?.vals ?? "").split(",").map((part) => part.trim()).filter(Boolean);
|
|
11028
|
-
if (parts.length === 0) return "";
|
|
11029
|
-
return parts.length > 1 ? `${parts[0]}–${parts[parts.length - 1]}` : parts[0];
|
|
11030
|
-
});
|
|
11075
|
+
const repOnField = computed(() => props.fields.find((field, i) => field.rep && on.value[i]));
|
|
11076
|
+
const repOn = computed(() => repOnField.value !== void 0);
|
|
11031
11077
|
const summary = computed(() => fieldRecipeSummary({
|
|
11032
11078
|
activeFactors: activeFactors.value,
|
|
11033
11079
|
repOn: repOn.value,
|
|
@@ -11038,12 +11084,23 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11038
11084
|
const qcCount = computed(() => props.qcCount ?? Math.max(0, props.headerCount - props.samples.length));
|
|
11039
11085
|
const realCount = computed(() => Math.max(0, props.headerCount - qcCount.value));
|
|
11040
11086
|
const sampleTotal = computed(() => sampleTotalFor(currentRoute.value, realCount.value, qcCount.value));
|
|
11041
|
-
const
|
|
11042
|
-
|
|
11043
|
-
|
|
11044
|
-
|
|
11087
|
+
const qcChips = computed(() => {
|
|
11088
|
+
if (props.qcChips !== void 0) return props.qcChips;
|
|
11089
|
+
if (props.qcChip !== void 0) return props.qcChip ? [props.qcChip] : [];
|
|
11090
|
+
return currentRoute.value !== "Mix into groups" ? [{
|
|
11091
|
+
name: "QC_Pool",
|
|
11092
|
+
count: qcCount.value
|
|
11093
|
+
}] : [];
|
|
11094
|
+
});
|
|
11045
11095
|
const footHint = computed(() => currentRoute.value === "Exclude" ? ` · ${qcCount.value} QC excluded` : currentRoute.value === "Mix into groups" ? " · QC mixed in" : ` · ${qcCount.value} QC overlaid`);
|
|
11096
|
+
const root = ref(null);
|
|
11097
|
+
const controlOf = (index, selector) => root.value?.querySelector(`[data-field="${index}"] ${selector}`) ?? null;
|
|
11098
|
+
async function refocus(index, selector) {
|
|
11099
|
+
await nextTick();
|
|
11100
|
+
controlOf(index, selector)?.focus();
|
|
11101
|
+
}
|
|
11046
11102
|
function toggle(index) {
|
|
11103
|
+
refocus(index, "[role=\"switch\"]");
|
|
11047
11104
|
if (controlledEnabled.value) {
|
|
11048
11105
|
emit("toggle", index);
|
|
11049
11106
|
return;
|
|
@@ -11053,7 +11110,7 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11053
11110
|
orderInner.value = wasOn ? orderInner.value.filter((i) => i !== index) : [...orderInner.value, index];
|
|
11054
11111
|
}
|
|
11055
11112
|
function moveLayer(index, direction) {
|
|
11056
|
-
if (controlledEnabled.value) {
|
|
11113
|
+
if (controlledEnabled.value || props.layers !== void 0) {
|
|
11057
11114
|
emit("move", index, direction);
|
|
11058
11115
|
return;
|
|
11059
11116
|
}
|
|
@@ -11065,6 +11122,48 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11065
11122
|
[next[from], next[to]] = [next[to], next[from]];
|
|
11066
11123
|
orderInner.value = next;
|
|
11067
11124
|
}
|
|
11125
|
+
const reorder = useListReorder({
|
|
11126
|
+
items: () => onCards.value,
|
|
11127
|
+
getId: (card) => card.field.key,
|
|
11128
|
+
getLabel: (card) => card.field.key,
|
|
11129
|
+
itemNoun: "layer",
|
|
11130
|
+
getElement: (id) => {
|
|
11131
|
+
const card = onCards.value.find((candidate) => candidate.field.key === id);
|
|
11132
|
+
return card ? controlOf(card.index, ".fr-row__grip") : null;
|
|
11133
|
+
},
|
|
11134
|
+
onReorder: ({ fromIndex, toIndex }) => {
|
|
11135
|
+
const { index } = onCards.value[fromIndex];
|
|
11136
|
+
const direction = toIndex < fromIndex ? "up" : "down";
|
|
11137
|
+
for (let step = 0; step < Math.abs(toIndex - fromIndex); step++) moveLayer(index, direction);
|
|
11138
|
+
}
|
|
11139
|
+
});
|
|
11140
|
+
const renaming = ref(null);
|
|
11141
|
+
const draftName = ref("");
|
|
11142
|
+
const renameTaken = ref(false);
|
|
11143
|
+
const renameInput = ref([]);
|
|
11144
|
+
async function startRename(card) {
|
|
11145
|
+
renaming.value = card.index;
|
|
11146
|
+
renameTaken.value = false;
|
|
11147
|
+
draftName.value = card.field.key;
|
|
11148
|
+
await nextTick();
|
|
11149
|
+
renameInput.value[0]?.select();
|
|
11150
|
+
}
|
|
11151
|
+
function endRename(card, restoreFocus) {
|
|
11152
|
+
renaming.value = null;
|
|
11153
|
+
renameTaken.value = false;
|
|
11154
|
+
if (restoreFocus) refocus(card.index, ".fr-row__rename");
|
|
11155
|
+
}
|
|
11156
|
+
function commitRename(card, fromBlur = false) {
|
|
11157
|
+
if (renaming.value !== card.index) return;
|
|
11158
|
+
const name = draftName.value.trim();
|
|
11159
|
+
const taken = name !== card.field.key && (props.fields.some((field) => field.key === name) || (props.reservedNames?.includes(name) ?? false));
|
|
11160
|
+
if (taken && !fromBlur) {
|
|
11161
|
+
renameTaken.value = true;
|
|
11162
|
+
return;
|
|
11163
|
+
}
|
|
11164
|
+
endRename(card, !fromBlur);
|
|
11165
|
+
if (name && name !== card.field.key && !taken) emit("rename", card.index, name);
|
|
11166
|
+
}
|
|
11068
11167
|
function onRouteChange(value) {
|
|
11069
11168
|
if (controlledRoute.value) {
|
|
11070
11169
|
emit("update:route", value);
|
|
@@ -11082,79 +11181,53 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11082
11181
|
});
|
|
11083
11182
|
}
|
|
11084
11183
|
return (_ctx, _cache) => {
|
|
11085
|
-
return openBlock(), createElementBlock("div",
|
|
11086
|
-
|
|
11184
|
+
return openBlock(), createElementBlock("div", {
|
|
11185
|
+
ref_key: "root",
|
|
11186
|
+
ref: root,
|
|
11187
|
+
class: "sg-modal fr"
|
|
11188
|
+
}, [
|
|
11189
|
+
createElementVNode("div", _hoisted_1$42, [
|
|
11087
11190
|
createVNode(Icon, {
|
|
11088
11191
|
d: ICON.bolt,
|
|
11089
11192
|
size: 18
|
|
11090
11193
|
}, null, 8, ["d"]),
|
|
11091
11194
|
_cache[11] || (_cache[11] = createElementVNode("span", { class: "sg-head__title" }, "Group samples", -1)),
|
|
11092
|
-
createElementVNode("span",
|
|
11195
|
+
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)]),
|
|
11093
11196
|
_cache[12] || (_cache[12] = createElementVNode("div", { class: "sg-head__spacer" }, null, -1)),
|
|
11094
|
-
|
|
11095
|
-
|
|
11096
|
-
|
|
11197
|
+
createVNode(ActionMenu_default, {
|
|
11198
|
+
label: "CSV",
|
|
11199
|
+
items: csvMenuItems.value,
|
|
11200
|
+
onSelect: onCsvMenuSelect
|
|
11201
|
+
}, {
|
|
11202
|
+
trigger: withCtx(({ open, toggle: toggleMenu, keydown }) => [createElementVNode("button", {
|
|
11097
11203
|
type: "button",
|
|
11098
11204
|
class: "fr-upload",
|
|
11099
11205
|
"aria-haspopup": "menu",
|
|
11100
|
-
"aria-expanded":
|
|
11101
|
-
onClick:
|
|
11206
|
+
"aria-expanded": open,
|
|
11207
|
+
onClick: toggleMenu,
|
|
11208
|
+
onKeydown: keydown
|
|
11102
11209
|
}, [
|
|
11103
11210
|
createVNode(Icon, {
|
|
11104
11211
|
d: ICON.upload,
|
|
11105
11212
|
size: 14
|
|
11106
11213
|
}, null, 8, ["d"]),
|
|
11107
|
-
_cache[
|
|
11214
|
+
_cache[9] || (_cache[9] = createTextVNode(" CSV ", -1)),
|
|
11108
11215
|
createVNode(Icon, {
|
|
11109
11216
|
d: ICON.chev,
|
|
11110
11217
|
size: 13
|
|
11111
11218
|
}, null, 8, ["d"])
|
|
11112
|
-
],
|
|
11113
|
-
|
|
11114
|
-
|
|
11115
|
-
|
|
11116
|
-
|
|
11117
|
-
|
|
11118
|
-
|
|
11119
|
-
|
|
11120
|
-
|
|
11121
|
-
|
|
11122
|
-
|
|
11123
|
-
|
|
11124
|
-
type: "button",
|
|
11125
|
-
class: "fr-csv-item",
|
|
11126
|
-
role: "menuitem",
|
|
11127
|
-
disabled: !__props.canDownloadTemplate,
|
|
11128
|
-
"aria-disabled": !__props.canDownloadTemplate,
|
|
11129
|
-
title: __props.canDownloadTemplate ? void 0 : "Load samples first",
|
|
11130
|
-
onClick: chooseDownloadTemplate
|
|
11131
|
-
}, [createVNode(Icon, {
|
|
11132
|
-
d: ICON.download,
|
|
11133
|
-
size: 14
|
|
11134
|
-
}, null, 8, ["d"]), _cache[8] || (_cache[8] = createTextVNode(" Download template ", -1))], 8, _hoisted_7$24),
|
|
11135
|
-
createElementVNode("button", {
|
|
11136
|
-
type: "button",
|
|
11137
|
-
class: "fr-csv-item",
|
|
11138
|
-
role: "menuitem",
|
|
11139
|
-
disabled: !__props.canDownloadTemplate,
|
|
11140
|
-
"aria-disabled": !__props.canDownloadTemplate,
|
|
11141
|
-
title: __props.canDownloadTemplate ? void 0 : "Load samples first",
|
|
11142
|
-
onClick: chooseDownloadPrefilled
|
|
11143
|
-
}, [createVNode(Icon, {
|
|
11144
|
-
d: ICON.download,
|
|
11145
|
-
size: 14
|
|
11146
|
-
}, null, 8, ["d"]), _cache[9] || (_cache[9] = createTextVNode(" Download pre-filled ", -1))], 8, _hoisted_8$22)
|
|
11147
|
-
])) : createCommentVNode("", true),
|
|
11148
|
-
createElementVNode("input", {
|
|
11149
|
-
ref_key: "fileInput",
|
|
11150
|
-
ref: fileInput,
|
|
11151
|
-
type: "file",
|
|
11152
|
-
accept: ".csv,.tsv,text/csv,text/tab-separated-values",
|
|
11153
|
-
hidden: "",
|
|
11154
|
-
onChange: onFileChange
|
|
11155
|
-
}, null, 544)
|
|
11156
|
-
], 512),
|
|
11157
|
-
createElementVNode("div", _hoisted_9$20, [_cache[10] || (_cache[10] = createElementVNode("button", {
|
|
11219
|
+
], 40, _hoisted_3$31)]),
|
|
11220
|
+
_: 1
|
|
11221
|
+
}, 8, ["items"]),
|
|
11222
|
+
createElementVNode("input", {
|
|
11223
|
+
ref_key: "fileInput",
|
|
11224
|
+
ref: fileInput,
|
|
11225
|
+
type: "file",
|
|
11226
|
+
accept: ".csv,.tsv,text/csv,text/tab-separated-values",
|
|
11227
|
+
hidden: "",
|
|
11228
|
+
onChange: onFileChange
|
|
11229
|
+
}, null, 544),
|
|
11230
|
+
createElementVNode("div", _hoisted_4$30, [_cache[10] || (_cache[10] = createElementVNode("button", {
|
|
11158
11231
|
type: "button",
|
|
11159
11232
|
class: "sg-mode__btn sg-mode__btn--on",
|
|
11160
11233
|
role: "tab",
|
|
@@ -11164,104 +11237,166 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11164
11237
|
class: "sg-mode__btn",
|
|
11165
11238
|
role: "tab",
|
|
11166
11239
|
"aria-selected": false,
|
|
11167
|
-
onClick: _cache[
|
|
11240
|
+
onClick: _cache[0] || (_cache[0] = ($event) => emit("manual"))
|
|
11168
11241
|
}, "Manual")]),
|
|
11169
11242
|
createElementVNode("button", {
|
|
11170
11243
|
class: "sg-head__close",
|
|
11171
11244
|
"aria-label": "Close",
|
|
11172
|
-
onClick: _cache[
|
|
11245
|
+
onClick: _cache[1] || (_cache[1] = ($event) => emit("close"))
|
|
11173
11246
|
}, [createVNode(Icon, {
|
|
11174
11247
|
d: ICON.close,
|
|
11175
11248
|
size: 16
|
|
11176
11249
|
}, null, 8, ["d"])])
|
|
11177
11250
|
]),
|
|
11178
|
-
createElementVNode("div",
|
|
11251
|
+
createElementVNode("div", _hoisted_5$28, [createElementVNode("div", {
|
|
11179
11252
|
class: "sg-body__main",
|
|
11180
11253
|
onDragenter: withModifiers(onDragEnter, ["prevent"]),
|
|
11181
|
-
onDragover: _cache[
|
|
11254
|
+
onDragover: _cache[6] || (_cache[6] = withModifiers(() => {}, ["prevent"])),
|
|
11182
11255
|
onDragleave: withModifiers(onDragLeave, ["prevent"]),
|
|
11183
11256
|
onDrop: withModifiers(onDrop, ["prevent"])
|
|
11184
11257
|
}, [
|
|
11185
|
-
dragOver.value ? (openBlock(), createElementBlock("div",
|
|
11258
|
+
dragOver.value ? (openBlock(), createElementBlock("div", _hoisted_6$26, [createVNode(Icon, {
|
|
11186
11259
|
d: ICON.upload,
|
|
11187
11260
|
size: 22
|
|
11188
11261
|
}, null, 8, ["d"]), _cache[13] || (_cache[13] = createElementVNode("span", null, "Drop CSV to load samples", -1))])) : createCommentVNode("", true),
|
|
11189
|
-
__props.loading ? (openBlock(), createElementBlock("div",
|
|
11262
|
+
__props.loading ? (openBlock(), createElementBlock("div", _hoisted_7$24, [createVNode(LoadingSpinner_default, {
|
|
11190
11263
|
size: "md",
|
|
11191
11264
|
label: "Loading experiment metadata"
|
|
11192
11265
|
}), _cache[14] || (_cache[14] = createElementVNode("span", null, "Loading experiment metadata…", -1))])) : createCommentVNode("", true),
|
|
11193
|
-
|
|
11194
|
-
|
|
11195
|
-
|
|
11196
|
-
|
|
11197
|
-
|
|
11198
|
-
|
|
11199
|
-
|
|
11200
|
-
|
|
11201
|
-
|
|
11202
|
-
|
|
11203
|
-
|
|
11204
|
-
|
|
11205
|
-
|
|
11206
|
-
|
|
11207
|
-
|
|
11208
|
-
|
|
11209
|
-
|
|
11210
|
-
|
|
11211
|
-
|
|
11266
|
+
__props.fields.length === 0 && __props.headerCount === 0 && !__props.loading ? (openBlock(), createElementBlock("div", _hoisted_8$22, [
|
|
11267
|
+
_cache[16] || (_cache[16] = createElementVNode("span", { class: "sg-lead__q" }, "No samples to group", -1)),
|
|
11268
|
+
_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)),
|
|
11269
|
+
createVNode(BaseButton_default, {
|
|
11270
|
+
variant: "secondary",
|
|
11271
|
+
size: "sm",
|
|
11272
|
+
onClick: pickCsv
|
|
11273
|
+
}, {
|
|
11274
|
+
"icon-left": withCtx(() => [createVNode(Icon, {
|
|
11275
|
+
d: ICON.upload,
|
|
11276
|
+
size: 15
|
|
11277
|
+
}, null, 8, ["d"])]),
|
|
11278
|
+
default: withCtx(() => [_cache[15] || (_cache[15] = createTextVNode(" Upload CSV ", -1))]),
|
|
11279
|
+
_: 1
|
|
11280
|
+
})
|
|
11281
|
+
])) : (openBlock(), createElementBlock(Fragment, { key: 3 }, [
|
|
11282
|
+
__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) => {
|
|
11283
|
+
return openBlock(), createElementBlock("span", {
|
|
11284
|
+
key: t,
|
|
11285
|
+
class: normalizeClass(["fr-token", "fr-token--" + token.state])
|
|
11286
|
+
}, [createElementVNode("span", _hoisted_11$17, toDisplayString(token.text), 1), createElementVNode("span", _hoisted_12$16, toDisplayString(token.caption), 1)], 2);
|
|
11287
|
+
}), 128))])])) : createCommentVNode("", true),
|
|
11288
|
+
_cache[28] || (_cache[28] = createElementVNode("span", { class: "fr-label" }, "Group by", -1)),
|
|
11289
|
+
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) => {
|
|
11290
|
+
return openBlock(), createElementBlock("div", {
|
|
11291
|
+
key: card.field.key,
|
|
11292
|
+
class: normalizeClass(["sg-field sg-field--on fr-row", {
|
|
11293
|
+
"fr-field--warn": card.field.rep,
|
|
11294
|
+
"fr-row--dragging": unref(reorder).isDragging(card.field.key),
|
|
11295
|
+
"fr-row--over": unref(reorder).isDragOver(card.field.key)
|
|
11296
|
+
}]),
|
|
11297
|
+
"data-test": "field-on",
|
|
11298
|
+
"data-field": card.index,
|
|
11299
|
+
draggable: renaming.value !== card.index,
|
|
11300
|
+
onDragstart: ($event) => unref(reorder).onDragStart($event, card, position),
|
|
11301
|
+
onDragover: ($event) => unref(reorder).onDragOver($event, card, position),
|
|
11302
|
+
onDragleave: _cache[4] || (_cache[4] = (...args) => unref(reorder).onDragLeave && unref(reorder).onDragLeave(...args)),
|
|
11303
|
+
onDrop: ($event) => unref(reorder).onDrop($event, card, position),
|
|
11304
|
+
onDragend: _cache[5] || (_cache[5] = (...args) => unref(reorder).onDragEnd && unref(reorder).onDragEnd(...args))
|
|
11305
|
+
}, [
|
|
11212
11306
|
createElementVNode("button", {
|
|
11213
11307
|
type: "button",
|
|
11214
|
-
class: "
|
|
11215
|
-
|
|
11216
|
-
|
|
11217
|
-
title: "Move up a layer",
|
|
11218
|
-
onClick: withModifiers(($event) => moveLayer(i, "up"), ["stop"])
|
|
11308
|
+
class: "fr-row__grip",
|
|
11309
|
+
"aria-label": `Move ${card.field.key}, layer ${position + 1} of ${onCards.value.length}. Press Alt and an arrow key.`,
|
|
11310
|
+
onKeydown: ($event) => unref(reorder).onKeydown($event, card, position)
|
|
11219
11311
|
}, [createVNode(Icon, {
|
|
11220
|
-
d: ICON.
|
|
11221
|
-
size:
|
|
11222
|
-
}, null, 8, ["d"])],
|
|
11223
|
-
createElementVNode("
|
|
11312
|
+
d: ICON.grip,
|
|
11313
|
+
size: 14
|
|
11314
|
+
}, null, 8, ["d"])], 40, _hoisted_16$13),
|
|
11315
|
+
createElementVNode("span", _hoisted_17$13, toDisplayString(position + 1), 1),
|
|
11316
|
+
renaming.value === card.index ? withDirectives((openBlock(), createElementBlock("input", {
|
|
11317
|
+
key: 0,
|
|
11318
|
+
ref_for: true,
|
|
11319
|
+
ref_key: "renameInput",
|
|
11320
|
+
ref: renameInput,
|
|
11321
|
+
"onUpdate:modelValue": _cache[2] || (_cache[2] = ($event) => draftName.value = $event),
|
|
11322
|
+
class: "fr-row__name-input",
|
|
11323
|
+
"aria-label": "New name for " + card.field.key,
|
|
11324
|
+
"aria-invalid": renameTaken.value || void 0,
|
|
11325
|
+
onInput: _cache[3] || (_cache[3] = ($event) => renameTaken.value = false),
|
|
11326
|
+
onKeydown: [withKeys(withModifiers(($event) => commitRename(card), ["prevent"]), ["enter"]), withKeys(withModifiers(($event) => endRename(card, true), ["stop"]), ["esc"])],
|
|
11327
|
+
onBlur: ($event) => commitRename(card, true)
|
|
11328
|
+
}, null, 40, _hoisted_18$13)), [[vModelText, draftName.value]]) : createCommentVNode("", true),
|
|
11329
|
+
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", {
|
|
11330
|
+
key: 0,
|
|
11224
11331
|
type: "button",
|
|
11225
|
-
class: "
|
|
11226
|
-
|
|
11227
|
-
|
|
11228
|
-
title: "Move down a layer",
|
|
11229
|
-
onClick: withModifiers(($event) => moveLayer(i, "down"), ["stop"])
|
|
11332
|
+
class: "fr-row__rename",
|
|
11333
|
+
"aria-label": "Rename " + card.field.key,
|
|
11334
|
+
onClick: ($event) => startRename(card)
|
|
11230
11335
|
}, [createVNode(Icon, {
|
|
11231
|
-
d: ICON.
|
|
11336
|
+
d: ICON.pencil,
|
|
11232
11337
|
size: 12
|
|
11233
|
-
}, null, 8, ["d"])], 8,
|
|
11234
|
-
|
|
11235
|
-
|
|
11236
|
-
|
|
11237
|
-
|
|
11238
|
-
|
|
11239
|
-
|
|
11240
|
-
|
|
11241
|
-
|
|
11242
|
-
|
|
11243
|
-
|
|
11244
|
-
|
|
11245
|
-
|
|
11246
|
-
|
|
11247
|
-
|
|
11248
|
-
|
|
11249
|
-
|
|
11250
|
-
|
|
11251
|
-
|
|
11252
|
-
|
|
11253
|
-
|
|
11254
|
-
|
|
11255
|
-
|
|
11256
|
-
|
|
11257
|
-
|
|
11258
|
-
|
|
11259
|
-
|
|
11260
|
-
|
|
11261
|
-
|
|
11262
|
-
|
|
11263
|
-
|
|
11264
|
-
|
|
11338
|
+
}, null, 8, ["d"])], 8, _hoisted_21$9)) : createCommentVNode("", true)], 64)),
|
|
11339
|
+
createElementVNode("span", _hoisted_22$9, toDisplayString(card.field.vals), 1),
|
|
11340
|
+
__props.hints?.[card.index] ? (openBlock(), createElementBlock("span", _hoisted_23$7, toDisplayString(__props.hints[card.index]), 1)) : createCommentVNode("", true),
|
|
11341
|
+
createVNode(BaseToggle_default, {
|
|
11342
|
+
size: "sm",
|
|
11343
|
+
"model-value": true,
|
|
11344
|
+
"aria-label": "Group by " + card.field.key,
|
|
11345
|
+
"onUpdate:modelValue": ($event) => toggle(card.index)
|
|
11346
|
+
}, null, 8, ["aria-label", "onUpdate:modelValue"])
|
|
11347
|
+
], 42, _hoisted_15$16);
|
|
11348
|
+
}), 128))]),
|
|
11349
|
+
createElementVNode("span", {
|
|
11350
|
+
style: normalizeStyle(unref(reorder).announcerStyle),
|
|
11351
|
+
"aria-live": "polite"
|
|
11352
|
+
}, toDisplayString(unref(reorder).announcement.value), 5),
|
|
11353
|
+
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) => {
|
|
11354
|
+
return openBlock(), createElementBlock("div", {
|
|
11355
|
+
key: card.field.key,
|
|
11356
|
+
class: "sg-field fr-row",
|
|
11357
|
+
"data-test": "field-off",
|
|
11358
|
+
"data-field": card.index
|
|
11359
|
+
}, [
|
|
11360
|
+
createElementVNode("span", _hoisted_26$5, toDisplayString(card.field.key), 1),
|
|
11361
|
+
createElementVNode("span", { class: normalizeClass(["sg-field__role", { "sg-field__role--rep": card.field.rep }]) }, toDisplayString(card.field.role), 3),
|
|
11362
|
+
createElementVNode("span", _hoisted_27$5, toDisplayString(card.field.vals), 1),
|
|
11363
|
+
createVNode(BaseToggle_default, {
|
|
11364
|
+
size: "sm",
|
|
11365
|
+
"model-value": false,
|
|
11366
|
+
"aria-label": "Group by " + card.field.key,
|
|
11367
|
+
"onUpdate:modelValue": ($event) => toggle(card.index)
|
|
11368
|
+
}, null, 8, ["aria-label", "onUpdate:modelValue"])
|
|
11369
|
+
], 8, _hoisted_25$7);
|
|
11370
|
+
}), 128))])], 64)) : createCommentVNode("", true),
|
|
11371
|
+
summary.value.kind === "mute" ? (openBlock(), createElementBlock("div", _hoisted_28$4, [createElementVNode("span", _hoisted_29$4, [createVNode(Icon, {
|
|
11372
|
+
d: ICON.info,
|
|
11373
|
+
size: 16
|
|
11374
|
+
}, 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, {
|
|
11375
|
+
d: ICON.warn,
|
|
11376
|
+
size: 16
|
|
11377
|
+
}, null, 8, ["d"])]), createElementVNode("span", null, [
|
|
11378
|
+
_cache[21] || (_cache[21] = createTextVNode(" Including ", -1)),
|
|
11379
|
+
createElementVNode("b", null, toDisplayString(repOnField.value?.key), 1),
|
|
11380
|
+
_cache[22] || (_cache[22] = createTextVNode(" makes every sample unique — ", -1)),
|
|
11381
|
+
createElementVNode("b", null, toDisplayString(baseGroups.value.length) + " groups of 1", 1),
|
|
11382
|
+
_cache[23] || (_cache[23] = createTextVNode(". Switch it off to keep replicates together. ", -1))
|
|
11383
|
+
])])) : summary.value.kind === "singletons" ? (openBlock(), createElementBlock("div", _hoisted_32$3, [createElementVNode("span", _hoisted_33$3, [createVNode(Icon, {
|
|
11384
|
+
d: ICON.warn,
|
|
11385
|
+
size: 16
|
|
11386
|
+
}, 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, {
|
|
11387
|
+
d: ICON.info,
|
|
11388
|
+
size: 16
|
|
11389
|
+
}, null, 8, ["d"])]), createElementVNode("span", null, [
|
|
11390
|
+
_cache[25] || (_cache[25] = createTextVNode(" Grouping by ", -1)),
|
|
11391
|
+
createElementVNode("b", null, toDisplayString(activeFactors.value.join(" × ")), 1),
|
|
11392
|
+
_cache[26] || (_cache[26] = createTextVNode(" → ", -1)),
|
|
11393
|
+
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)]),
|
|
11394
|
+
_cache[27] || (_cache[27] = createTextVNode(". ", -1))
|
|
11395
|
+
])]))
|
|
11396
|
+
], 64))
|
|
11397
|
+
], 32), createElementVNode("div", _hoisted_36$2, [
|
|
11398
|
+
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)]),
|
|
11399
|
+
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) => {
|
|
11265
11400
|
return openBlock(), createElementBlock("div", {
|
|
11266
11401
|
key: group.name,
|
|
11267
11402
|
class: "sg-group"
|
|
@@ -11270,7 +11405,7 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11270
11405
|
class: "sg-dot",
|
|
11271
11406
|
style: normalizeStyle(group.name === unref("QC_Pool") ? unref(QC_DOT_STYLE) : { background: group.color })
|
|
11272
11407
|
}, null, 4),
|
|
11273
|
-
createElementVNode("span",
|
|
11408
|
+
createElementVNode("span", _hoisted_41$2, toDisplayString(group.name), 1),
|
|
11274
11409
|
createElementVNode("span", {
|
|
11275
11410
|
class: "sg-group__bar",
|
|
11276
11411
|
style: normalizeStyle({
|
|
@@ -11278,34 +11413,36 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11278
11413
|
"--g": group.color
|
|
11279
11414
|
})
|
|
11280
11415
|
}, null, 4),
|
|
11281
|
-
createElementVNode("span",
|
|
11416
|
+
createElementVNode("span", _hoisted_42$1, toDisplayString(group.count), 1)
|
|
11282
11417
|
]);
|
|
11283
11418
|
}), 128))]),
|
|
11284
|
-
createElementVNode("div",
|
|
11285
|
-
class: "
|
|
11286
|
-
|
|
11287
|
-
|
|
11288
|
-
|
|
11289
|
-
|
|
11290
|
-
|
|
11291
|
-
|
|
11292
|
-
|
|
11293
|
-
|
|
11294
|
-
|
|
11295
|
-
|
|
11296
|
-
|
|
11297
|
-
|
|
11298
|
-
|
|
11419
|
+
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, {
|
|
11420
|
+
class: "fr-qc__route",
|
|
11421
|
+
size: "sm",
|
|
11422
|
+
variant: "card",
|
|
11423
|
+
"aria-label": "Quality control routing",
|
|
11424
|
+
"model-value": currentRoute.value,
|
|
11425
|
+
options: QC_ROUTE_OPTIONS,
|
|
11426
|
+
"onUpdate:modelValue": _cache[7] || (_cache[7] = ($event) => onRouteChange($event))
|
|
11427
|
+
}, null, 8, ["model-value"])]), createElementVNode("div", _hoisted_45$1, [(openBlock(true), createElementBlock(Fragment, null, renderList(qcChips.value, (chip) => {
|
|
11428
|
+
return openBlock(), createElementBlock("span", {
|
|
11429
|
+
key: chip.name,
|
|
11430
|
+
class: normalizeClass(["sg-qc__chip", { "fr-qc__chip--off": currentRoute.value === "Exclude" }])
|
|
11431
|
+
}, [createElementVNode("span", {
|
|
11432
|
+
class: "sg-dot",
|
|
11433
|
+
style: normalizeStyle(unref(QC_DOT_STYLE))
|
|
11434
|
+
}, null, 4), createTextVNode(toDisplayString(chip.name) + " ×" + toDisplayString(chip.count), 1)], 2);
|
|
11435
|
+
}), 128))])])
|
|
11299
11436
|
])]),
|
|
11300
|
-
createElementVNode("div",
|
|
11301
|
-
createElementVNode("span",
|
|
11302
|
-
_cache[
|
|
11437
|
+
createElementVNode("div", _hoisted_46$1, [
|
|
11438
|
+
createElementVNode("span", _hoisted_47$1, "Applies to " + toDisplayString(sampleTotal.value) + " samples" + toDisplayString(footHint.value), 1),
|
|
11439
|
+
_cache[33] || (_cache[33] = createElementVNode("div", { class: "sg-foot__spacer" }, null, -1)),
|
|
11303
11440
|
createVNode(BaseButton_default, {
|
|
11304
11441
|
variant: "ghost",
|
|
11305
11442
|
size: "sm",
|
|
11306
|
-
onClick: _cache[
|
|
11443
|
+
onClick: _cache[8] || (_cache[8] = ($event) => emit("cancel"))
|
|
11307
11444
|
}, {
|
|
11308
|
-
default: withCtx(() => [..._cache[
|
|
11445
|
+
default: withCtx(() => [..._cache[31] || (_cache[31] = [createTextVNode("Cancel", -1)])]),
|
|
11309
11446
|
_: 1
|
|
11310
11447
|
}),
|
|
11311
11448
|
createVNode(BaseButton_default, {
|
|
@@ -11318,11 +11455,11 @@ var SmartGroupFieldRecipe_default = /* @__PURE__ */ defineComponent({
|
|
|
11318
11455
|
d: ICON.check,
|
|
11319
11456
|
size: 15
|
|
11320
11457
|
}, null, 8, ["d"])]),
|
|
11321
|
-
default: withCtx(() => [_cache[
|
|
11458
|
+
default: withCtx(() => [_cache[32] || (_cache[32] = createTextVNode(" Apply grouping ", -1))]),
|
|
11322
11459
|
_: 1
|
|
11323
11460
|
}, 8, ["disabled"])
|
|
11324
11461
|
])
|
|
11325
|
-
]);
|
|
11462
|
+
], 512);
|
|
11326
11463
|
};
|
|
11327
11464
|
}
|
|
11328
11465
|
});
|
|
@@ -11941,11 +12078,73 @@ function parseCSV(text) {
|
|
|
11941
12078
|
}
|
|
11942
12079
|
//#endregion
|
|
11943
12080
|
//#region src/components/AutoGroupModal.adapter.ts
|
|
12081
|
+
var PREVIEW_VALUES = 3;
|
|
12082
|
+
/** Value preview of a field card: the first three values, then the count of the rest. */
|
|
12083
|
+
function previewValues(values) {
|
|
12084
|
+
const shown = values.slice(0, PREVIEW_VALUES).join(", ");
|
|
12085
|
+
return values.length > PREVIEW_VALUES ? `${shown} … +${values.length - PREVIEW_VALUES}` : shown;
|
|
12086
|
+
}
|
|
12087
|
+
/** Experiment line of the modal header: `exp157 · 2025-10-13 · LT`. */
|
|
12088
|
+
function experimentLabel(header) {
|
|
12089
|
+
return [
|
|
12090
|
+
header.code,
|
|
12091
|
+
header.date,
|
|
12092
|
+
header.operator
|
|
12093
|
+
].filter(Boolean).join(" · ");
|
|
12094
|
+
}
|
|
12095
|
+
/**
|
|
12096
|
+
* Names of all columns of the experimental classes. A field cannot take one
|
|
12097
|
+
* of them: the engine merges fields by name.
|
|
12098
|
+
*/
|
|
12099
|
+
function engineColumnNames(schemas) {
|
|
12100
|
+
const names = Object.values(schemas).filter((schema) => isExperimentalKind(schema.classKind)).flatMap((schema) => schema.columns.map((column) => column.displayName ?? column.name));
|
|
12101
|
+
return [...new Set(names)];
|
|
12102
|
+
}
|
|
12103
|
+
/** One chip for each QC-type class, with its sample count. */
|
|
12104
|
+
function engineQcChips(classes) {
|
|
12105
|
+
return classes.filter((c) => !isExperimentalKind(c.kind)).map((c) => ({
|
|
12106
|
+
name: c.label,
|
|
12107
|
+
count: c.members.length
|
|
12108
|
+
}));
|
|
12109
|
+
}
|
|
12110
|
+
/**
|
|
12111
|
+
* The tokens of one study sample with the role the engine gave each of them,
|
|
12112
|
+
* so the user sees how the names were read. The sample is the first member of
|
|
12113
|
+
* the largest experimental class. `cards` supplies the on/off state and the
|
|
12114
|
+
* layer of the tokens that are grouping fields.
|
|
12115
|
+
*/
|
|
12116
|
+
function engineAnatomy(classes, schemas, tokenized, cards) {
|
|
12117
|
+
const cls = classes.filter((c) => isExperimentalKind(c.kind) && schemas[classKey(c)]).sort((a, b) => b.members.length - a.members.length)[0];
|
|
12118
|
+
if (!cls) return [];
|
|
12119
|
+
const tokens = tokenized[cls.members[0]] ?? [];
|
|
12120
|
+
return schemas[classKey(cls)].columns.flatMap((column) => {
|
|
12121
|
+
const text = column.sourceIndices.map((index) => tokens[index] ?? "").join("_");
|
|
12122
|
+
if (!text) return [];
|
|
12123
|
+
const name = column.displayName ?? column.name;
|
|
12124
|
+
const card = cards.fields.findIndex((field) => field.key === name);
|
|
12125
|
+
if (card === -1) return [{
|
|
12126
|
+
text,
|
|
12127
|
+
caption: /^(Field \d+|Username.*|.* \d+)$/.test(name) ? roleLabel(column.role).toLowerCase() : name,
|
|
12128
|
+
state: "fixed"
|
|
12129
|
+
}];
|
|
12130
|
+
const layer = cards.layers[card];
|
|
12131
|
+
return [layer === null ? {
|
|
12132
|
+
text,
|
|
12133
|
+
caption: name,
|
|
12134
|
+
state: "off"
|
|
12135
|
+
} : {
|
|
12136
|
+
text,
|
|
12137
|
+
caption: String(layer),
|
|
12138
|
+
state: "on"
|
|
12139
|
+
}];
|
|
12140
|
+
});
|
|
12141
|
+
}
|
|
11944
12142
|
var ROLE_LABELS = {
|
|
11945
12143
|
"constant": "Constant",
|
|
11946
12144
|
"factor": "Factor",
|
|
11947
12145
|
"replicate": "Replicate",
|
|
11948
12146
|
"run-order": "Run",
|
|
12147
|
+
"id": "Sample ID",
|
|
11949
12148
|
"numeric": "Numeric",
|
|
11950
12149
|
"class-tag": "Class tag",
|
|
11951
12150
|
"ignore": "Ignore"
|
|
@@ -11955,14 +12154,15 @@ function roleLabel(role) {
|
|
|
11955
12154
|
return role ? ROLE_LABELS[role] : "Factor";
|
|
11956
12155
|
}
|
|
11957
12156
|
/**
|
|
11958
|
-
* Columns worth offering as grouping toggles: factors
|
|
11959
|
-
*
|
|
12157
|
+
* Columns worth offering as grouping toggles: factors, numerics, replicates and
|
|
12158
|
+
* sample IDs (the last two are off by default), plus any column already enabled
|
|
12159
|
+
* in `groupBy` (so a manual group-by choice still shows).
|
|
11960
12160
|
* Preserves the engine's column order. `groupBy` is the schema's ORDERED layer
|
|
11961
12161
|
* list — entry N is hierarchy layer N of the composed group names.
|
|
11962
12162
|
*/
|
|
11963
12163
|
function candidateColumns(columns, groupBy) {
|
|
11964
12164
|
const enabled = new Set(groupBy);
|
|
11965
|
-
return columns.filter((c) =>
|
|
12165
|
+
return columns.filter((c) => GROUPING_FIELD_ROLES.has(c.role) || enabled.has(c.index));
|
|
11966
12166
|
}
|
|
11967
12167
|
/**
|
|
11968
12168
|
* Build the batch-wide field recipe from every class schema. The active schema
|
|
@@ -11978,6 +12178,7 @@ function engineSchemasToCards(schemas, activeClassKey) {
|
|
|
11978
12178
|
const enabledOrder = [];
|
|
11979
12179
|
const enabled = /* @__PURE__ */ new Set();
|
|
11980
12180
|
for (const [, schema] of ordered) {
|
|
12181
|
+
if (!isExperimentalKind(schema.classKind)) continue;
|
|
11981
12182
|
for (const index of schema.groupBy) {
|
|
11982
12183
|
const column = schema.columns.find((candidate) => candidate.index === index);
|
|
11983
12184
|
if (!column) continue;
|
|
@@ -11997,8 +12198,8 @@ function engineSchemasToCards(schemas, activeClassKey) {
|
|
|
11997
12198
|
fields: cards.map(([key, column]) => ({
|
|
11998
12199
|
key,
|
|
11999
12200
|
role: roleLabel(column.role),
|
|
12000
|
-
vals: column.uniqueValues
|
|
12001
|
-
rep: column.role === "replicate"
|
|
12201
|
+
vals: previewValues(column.uniqueValues),
|
|
12202
|
+
rep: column.role === "replicate" || column.role === "id"
|
|
12002
12203
|
})),
|
|
12003
12204
|
enabled: cards.map(([key]) => enabled.has(key)),
|
|
12004
12205
|
layers: cards.map(([key]) => {
|
|
@@ -12182,12 +12383,20 @@ var AutoGroupModal_default = /* @__PURE__ */ defineComponent({
|
|
|
12182
12383
|
const fieldCards = computed(() => engineSchemasToCards(autoGroup.schemas.value, autoGroup.activeClassKey.value));
|
|
12183
12384
|
const railGroups = computed(() => engineGroupsToRail(autoGroup.result.value.experimentalGroups ?? autoGroup.groups.value));
|
|
12184
12385
|
const qcSampleCount = computed(() => autoGroup.classes.value.filter((c) => c.kind !== "biological" && c.kind !== "unknown").reduce((acc, c) => acc + c.members.length, 0));
|
|
12185
|
-
const
|
|
12186
|
-
name: "QC_Pool",
|
|
12187
|
-
count: qcSampleCount.value
|
|
12188
|
-
} : null);
|
|
12386
|
+
const qcChips = computed(() => qcRouting.value === "mix" ? [] : engineQcChips(autoGroup.classes.value));
|
|
12189
12387
|
const fieldRecipeRoute = computed(() => engineToQcRoute(qcRouting.value));
|
|
12190
12388
|
const headerCount = computed(() => autoGroup.samples.value.length);
|
|
12389
|
+
const headerLabel = computed(() => experimentLabel(autoGroup.experiment.value));
|
|
12390
|
+
const reservedNames = computed(() => engineColumnNames(autoGroup.schemas.value));
|
|
12391
|
+
const anatomy = computed(() => autoGroup.inputMode.value === "paste" ? engineAnatomy(autoGroup.classes.value, autoGroup.schemas.value, autoGroup.tokenized.value, fieldCards.value) : []);
|
|
12392
|
+
const fieldHints = computed(() => {
|
|
12393
|
+
const needsHelp = mostlySingletons(railGroups.value);
|
|
12394
|
+
return fieldCards.value.fields.map((field, index) => {
|
|
12395
|
+
if (!needsHelp || !fieldCards.value.enabled[index]) return null;
|
|
12396
|
+
const remaining = autoGroup.groupCountWithout(field.key);
|
|
12397
|
+
return `off → ${remaining} ${remaining === 1 ? "group" : "groups"}`;
|
|
12398
|
+
});
|
|
12399
|
+
});
|
|
12191
12400
|
function onToggleField(cardIndex) {
|
|
12192
12401
|
const field = fieldCards.value.fields[cardIndex];
|
|
12193
12402
|
if (!field) return;
|
|
@@ -12198,6 +12407,11 @@ var AutoGroupModal_default = /* @__PURE__ */ defineComponent({
|
|
|
12198
12407
|
if (!field) return;
|
|
12199
12408
|
autoGroup.moveGroupByField(field.key, direction);
|
|
12200
12409
|
}
|
|
12410
|
+
function onRenameField(cardIndex, name) {
|
|
12411
|
+
const field = fieldCards.value.fields[cardIndex];
|
|
12412
|
+
if (!field) return;
|
|
12413
|
+
autoGroup.renameGroupByField(field.key, name);
|
|
12414
|
+
}
|
|
12201
12415
|
function onRouteChange(route) {
|
|
12202
12416
|
setQcRouting(qcRouteToEngine(route));
|
|
12203
12417
|
}
|
|
@@ -12306,15 +12520,20 @@ var AutoGroupModal_default = /* @__PURE__ */ defineComponent({
|
|
|
12306
12520
|
enabled: fieldCards.value.enabled,
|
|
12307
12521
|
layers: fieldCards.value.layers,
|
|
12308
12522
|
groups: railGroups.value,
|
|
12309
|
-
"qc-
|
|
12523
|
+
"qc-chips": qcChips.value,
|
|
12310
12524
|
route: fieldRecipeRoute.value,
|
|
12311
12525
|
"header-count": headerCount.value,
|
|
12312
12526
|
"qc-count": qcSampleCount.value,
|
|
12313
12527
|
"can-download-template": unref(autoGroup).canDownloadTemplate.value,
|
|
12314
12528
|
loading: experimentLoading.value,
|
|
12315
|
-
"experiment-label":
|
|
12529
|
+
"experiment-label": headerLabel.value,
|
|
12530
|
+
anatomy: anatomy.value,
|
|
12531
|
+
hints: fieldHints.value,
|
|
12532
|
+
"reserved-names": reservedNames.value,
|
|
12533
|
+
renamable: "",
|
|
12316
12534
|
onToggle: onToggleField,
|
|
12317
12535
|
onMove: onMoveField,
|
|
12536
|
+
onRename: onRenameField,
|
|
12318
12537
|
"onUpdate:route": onRouteChange,
|
|
12319
12538
|
onCsvFile,
|
|
12320
12539
|
onDownloadTemplate,
|
|
@@ -12328,12 +12547,16 @@ var AutoGroupModal_default = /* @__PURE__ */ defineComponent({
|
|
|
12328
12547
|
"enabled",
|
|
12329
12548
|
"layers",
|
|
12330
12549
|
"groups",
|
|
12331
|
-
"qc-
|
|
12550
|
+
"qc-chips",
|
|
12332
12551
|
"route",
|
|
12333
12552
|
"header-count",
|
|
12334
12553
|
"qc-count",
|
|
12335
12554
|
"can-download-template",
|
|
12336
|
-
"loading"
|
|
12555
|
+
"loading",
|
|
12556
|
+
"experiment-label",
|
|
12557
|
+
"anatomy",
|
|
12558
|
+
"hints",
|
|
12559
|
+
"reserved-names"
|
|
12337
12560
|
])) : (openBlock(), createBlock(SmartGroupManual_default, {
|
|
12338
12561
|
key: manualKey.value,
|
|
12339
12562
|
"sample-names": manualSampleNames.value,
|
|
@@ -22909,4 +23132,4 @@ var components_exports = /* @__PURE__ */ __exportAll({
|
|
|
22909
23132
|
//#endregion
|
|
22910
23133
|
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 };
|
|
22911
23134
|
|
|
22912
|
-
//# sourceMappingURL=components-
|
|
23135
|
+
//# sourceMappingURL=components-bbanLd1u.js.map
|