lhcb-ntuple-wizard-test 2.1.0 → 2.2.0
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/components/AddTupleToolButton.d.ts +1 -0
- package/dist/components/AddTupleToolButton.js +16 -0
- package/dist/components/BookkeepingPathDropdown.d.ts +1 -1
- package/dist/components/BookkeepingPathDropdown.js +1 -4
- package/dist/components/DatasetEventTypeBadge.js +1 -1
- package/dist/components/DatasetInfo.js +3 -3
- package/dist/components/DecayCard.d.ts +1 -1
- package/dist/components/DecayCard.js +12 -40
- package/dist/components/DecayLatex.d.ts +1 -1
- package/dist/components/DecayLatex.js +4 -87
- package/dist/components/DecayListItem.js +2 -2
- package/dist/components/DecayTagBadge.d.ts +1 -1
- package/dist/components/DecayTagBadge.js +0 -3
- package/dist/components/DecayTreeCard.d.ts +1 -7
- package/dist/components/DecayTreeCard.js +13 -18
- package/dist/components/DecayTreeCardHeader.d.ts +2 -3
- package/dist/components/DecayTreeCardHeader.js +2 -2
- package/dist/components/DecayTreeGraph.d.ts +1 -4
- package/dist/components/DecayTreeGraph.js +66 -41
- package/dist/components/DeleteButton.d.ts +2 -1
- package/dist/components/DeleteButton.js +2 -2
- package/dist/components/DttNameInput.d.ts +9 -0
- package/dist/components/DttNameInput.js +43 -0
- package/dist/components/GuideLinkButton.d.ts +15 -0
- package/dist/components/GuideLinkButton.js +16 -0
- package/dist/components/NtupleWizard.js +1 -7
- package/dist/components/ParticleDropdown.d.ts +11 -1
- package/dist/components/ParticleDropdown.js +3 -6
- package/dist/components/ParticleLatex.d.ts +6 -0
- package/dist/components/ParticleLatex.js +13 -0
- package/dist/components/ParticleTagBadge.d.ts +2 -1
- package/dist/components/ParticleTagBadge.js +5 -7
- package/dist/components/ParticleTagFilters.d.ts +1 -6
- package/dist/components/ParticleTagFilters.js +16 -17
- package/dist/components/RequestButtonGroup.d.ts +1 -1
- package/dist/components/RequestButtonGroup.js +0 -3
- package/dist/components/RequestRow.d.ts +1 -1
- package/dist/components/RequestRow.js +4 -9
- package/dist/components/StrippingLineDropdown.js +14 -16
- package/dist/components/StrippingLineInfo.d.ts +5 -5
- package/dist/components/StrippingLineInfo.js +14 -4
- package/dist/components/StrippingLineInfoButton.d.ts +6 -0
- package/dist/components/StrippingLineInfoButton.js +7 -0
- package/dist/components/StrippingLineVersionBadge.d.ts +7 -0
- package/dist/components/{StrippingLineBadge.js → StrippingLineVersionBadge.js} +5 -5
- package/dist/components/StrippingLinesCountBadge.d.ts +8 -0
- package/dist/components/StrippingLinesCountBadge.js +11 -0
- package/dist/components/TagDropdown.d.ts +3 -3
- package/dist/components/TagDropdown.js +2 -2
- package/dist/components/TupleToolClassDropdown.js +11 -14
- package/dist/components/TupleToolDocsAccordion.d.ts +1 -1
- package/dist/components/TupleToolDocsAccordion.js +4 -8
- package/dist/components/TupleToolGroupsAccordion.d.ts +5 -0
- package/dist/components/TupleToolGroupsAccordion.js +31 -0
- package/dist/components/TupleToolLabel.d.ts +1 -1
- package/dist/components/TupleToolLabel.js +2 -5
- package/dist/components/TupleToolsAccordion.d.ts +1 -0
- package/dist/components/TupleToolsAccordion.js +22 -0
- package/dist/components/modals/AddTupleToolModal.js +3 -2
- package/dist/components/modals/ConfigureTupleToolModal.js +1 -1
- package/dist/components/modals/UploadDttConfigModal.d.ts +1 -1
- package/dist/components/modals/UploadDttConfigModal.js +1 -4
- package/dist/config.d.ts +1 -0
- package/dist/config.js +3 -2
- package/dist/models/bkPath.js +1 -1
- package/dist/models/dtt.d.ts +5 -2
- package/dist/models/dtt.js +37 -18
- package/dist/models/rowData.d.ts +1 -1
- package/dist/models/yamlFile.js +1 -1
- package/dist/pages/DecaySearchPage.js +4 -9
- package/dist/pages/DecayTreeConfigPage.js +4 -38
- package/dist/pages/RequestPage.js +2 -4
- package/dist/providers/DttProvider.d.ts +3 -3
- package/dist/providers/DttProvider.js +30 -55
- package/dist/providers/MetadataProvider.d.ts +1 -1
- package/dist/providers/MetadataProvider.js +11 -5
- package/dist/providers/RequestProvider.js +2 -2
- package/dist/providers/RowProvider.d.ts +2 -2
- package/dist/providers/RowProvider.js +10 -9
- package/dist/providers/RowsProvider.js +0 -3
- package/dist/tests/components/BookkeepingPathDropdown.test.d.ts +1 -0
- package/dist/tests/components/BookkeepingPathDropdown.test.js +118 -0
- package/dist/tests/components/DatasetInfo.test.d.ts +1 -0
- package/dist/tests/components/DatasetInfo.test.js +38 -0
- package/dist/tests/components/DecayCard.test.d.ts +1 -0
- package/dist/tests/components/DecayCard.test.js +115 -0
- package/dist/tests/components/DecayLatex.test.d.ts +1 -0
- package/dist/tests/components/DecayLatex.test.js +31 -0
- package/dist/tests/components/DecayList.test.d.ts +1 -0
- package/dist/tests/components/DecayList.test.js +76 -0
- package/dist/tests/components/DecayListItem.test.d.ts +1 -0
- package/dist/tests/components/DecayListItem.test.js +51 -0
- package/dist/tests/components/DecayTreeCard.test.d.ts +1 -0
- package/dist/tests/components/DecayTreeCard.test.js +119 -0
- package/dist/tests/components/DecayTreeGraph.test.d.ts +1 -0
- package/dist/tests/components/DecayTreeGraph.test.js +125 -0
- package/dist/tests/components/DeleteButton.test.d.ts +1 -0
- package/dist/tests/components/DeleteButton.test.js +45 -0
- package/dist/tests/components/DttNameInput.test.d.ts +1 -0
- package/dist/tests/components/DttNameInput.test.js +75 -0
- package/dist/tests/components/NtupleWizard.test.d.ts +1 -0
- package/dist/tests/components/NtupleWizard.test.js +57 -0
- package/dist/tests/components/ParticleDropdown.test.d.ts +1 -0
- package/dist/tests/components/ParticleDropdown.test.js +23 -0
- package/dist/tests/components/ParticleTagFilters.test.d.ts +1 -0
- package/dist/tests/components/ParticleTagFilters.test.js +87 -0
- package/dist/tests/components/RequestButtonGroup.test.d.ts +1 -0
- package/dist/tests/components/RequestButtonGroup.test.js +132 -0
- package/dist/tests/components/RequestRow.test.d.ts +1 -0
- package/dist/tests/components/RequestRow.test.js +58 -0
- package/dist/tests/components/StrippingLineDropdown.test.d.ts +1 -0
- package/dist/tests/components/StrippingLineDropdown.test.js +88 -0
- package/dist/tests/components/badges.test.d.ts +1 -0
- package/dist/tests/components/badges.test.js +120 -0
- package/dist/tests/components/dropdowns.test.d.ts +1 -0
- package/dist/tests/components/dropdowns.test.js +110 -0
- package/dist/tests/components/dttComponents.test.d.ts +1 -0
- package/dist/tests/components/dttComponents.test.js +287 -0
- package/dist/tests/components/formInputs.test.d.ts +1 -0
- package/dist/tests/components/formInputs.test.js +96 -0
- package/dist/tests/components/metadataComponents.test.d.ts +1 -0
- package/dist/tests/components/metadataComponents.test.js +137 -0
- package/dist/tests/components/miscComponents.test.d.ts +1 -0
- package/dist/tests/components/miscComponents.test.js +134 -0
- package/dist/tests/components/modals.test.d.ts +1 -0
- package/dist/tests/components/modals.test.js +554 -0
- package/dist/tests/components/tupleToolParams.test.d.ts +1 -0
- package/dist/tests/components/tupleToolParams.test.js +213 -0
- package/dist/tests/config.test.d.ts +1 -0
- package/dist/tests/config.test.js +31 -0
- package/dist/tests/mockSetup.d.ts +1 -0
- package/dist/tests/mockSetup.js +30 -0
- package/dist/tests/models/BkPath.test.d.ts +1 -0
- package/dist/tests/models/BkPath.test.js +87 -0
- package/dist/tests/models/Dtt.test.d.ts +1 -0
- package/dist/tests/models/Dtt.test.js +376 -0
- package/dist/tests/models/TupleTool.test.d.ts +1 -0
- package/dist/tests/models/TupleTool.test.js +80 -0
- package/dist/tests/models/YamlFile.test.d.ts +1 -0
- package/dist/tests/models/YamlFile.test.js +123 -0
- package/dist/tests/pages/DecaySearchPage.test.d.ts +1 -0
- package/dist/tests/pages/DecaySearchPage.test.js +228 -0
- package/dist/tests/pages/DecayTreeConfigPage.test.d.ts +1 -0
- package/dist/tests/pages/DecayTreeConfigPage.test.js +105 -0
- package/dist/tests/pages/RequestPage.test.d.ts +1 -0
- package/dist/tests/pages/RequestPage.test.js +439 -0
- package/dist/tests/providers/DttProvider.test.d.ts +1 -0
- package/dist/tests/providers/DttProvider.test.js +105 -0
- package/dist/tests/providers/MetadataProvider.test.d.ts +1 -0
- package/dist/tests/providers/MetadataProvider.test.js +129 -0
- package/dist/tests/providers/RequestProvider.test.d.ts +1 -0
- package/dist/tests/providers/RequestProvider.test.js +306 -0
- package/dist/tests/providers/RowProvider.test.d.ts +1 -0
- package/dist/tests/providers/RowProvider.test.js +110 -0
- package/dist/tests/providers/RowsProvider.test.d.ts +1 -0
- package/dist/tests/providers/RowsProvider.test.js +84 -0
- package/dist/tests/providers/WizardConfigProvider.test.d.ts +1 -0
- package/dist/tests/providers/WizardConfigProvider.test.js +36 -0
- package/dist/tests/setupTests.d.ts +1 -0
- package/dist/tests/setupTests.js +15 -0
- package/dist/tests/testUtils.d.ts +33 -0
- package/dist/tests/testUtils.js +196 -0
- package/dist/tests/utils/latexUtils.test.d.ts +1 -0
- package/dist/tests/utils/latexUtils.test.js +62 -0
- package/dist/tests/utils/utils.test.d.ts +1 -0
- package/dist/tests/utils/utils.test.js +394 -0
- package/dist/utils/latexUtils.d.ts +13 -0
- package/dist/utils/latexUtils.js +86 -0
- package/dist/utils/utils.d.ts +1 -0
- package/dist/utils/utils.js +4 -1
- package/package.json +16 -7
- package/dist/components/NumStrippingLinesBadge.d.ts +0 -8
- package/dist/components/NumStrippingLinesBadge.js +0 -10
- package/dist/components/StrippingLineBadge.d.ts +0 -7
- package/dist/components/TupleToolGroup.d.ts +0 -5
- package/dist/components/TupleToolGroup.js +0 -22
- package/dist/components/TupleToolList.d.ts +0 -6
- package/dist/components/TupleToolList.js +0 -42
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function AddTupleToolButton(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { PlusLg } from "react-bootstrap-icons";
|
|
3
|
+
import { Button } from "react-bootstrap";
|
|
4
|
+
import { AddTupleToolModal } from "./modals/AddTupleToolModal";
|
|
5
|
+
import { useState } from "react";
|
|
6
|
+
import { ConfigureTupleToolModal } from "./modals/ConfigureTupleToolModal";
|
|
7
|
+
export function AddTupleToolButton() {
|
|
8
|
+
const [showAddModal, setShowAddModal] = useState(false);
|
|
9
|
+
const [showConfigModal, setShowConfigModal] = useState(null);
|
|
10
|
+
return (_jsxs(_Fragment, { children: [showAddModal && (_jsx(AddTupleToolModal, { onClose: (tool) => {
|
|
11
|
+
setShowAddModal(false);
|
|
12
|
+
if (tool?.class === "LoKi__Hybrid__TupleTool") {
|
|
13
|
+
setShowConfigModal({ tool });
|
|
14
|
+
}
|
|
15
|
+
} })), showConfigModal && (_jsx(ConfigureTupleToolModal, { tool: showConfigModal.tool, deleteIfCancelled: true, onClose: () => setShowConfigModal(null) })), _jsxs(Button, { variant: "success", size: "sm", className: "d-flex align-items-center gap-1 mt-1 w-100 justify-content-center", onClick: () => setShowAddModal(true), children: [_jsx(PlusLg, {}), "Add tool"] })] }));
|
|
16
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function BookkeepingPathDropdown(): import("react/jsx-runtime").JSX.Element
|
|
1
|
+
export declare function BookkeepingPathDropdown(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -9,9 +9,6 @@ export function BookkeepingPathDropdown() {
|
|
|
9
9
|
const metadata = useMetadata();
|
|
10
10
|
const { row, validateBkPath, updateBkPaths } = useRow();
|
|
11
11
|
const { updateRow } = useRows();
|
|
12
|
-
if (!metadata) {
|
|
13
|
-
return null;
|
|
14
|
-
}
|
|
15
12
|
const getOptionFromPath = useCallback((path) => ({
|
|
16
13
|
value: path,
|
|
17
14
|
label: _jsx(DatasetInfo, { pathString: path }),
|
|
@@ -31,5 +28,5 @@ export function BookkeepingPathDropdown() {
|
|
|
31
28
|
pathOptions: [...r.pathOptions, path],
|
|
32
29
|
}));
|
|
33
30
|
}, [row.id, validateBkPath, updateRow]);
|
|
34
|
-
return (_jsx(Creatable, { isMulti: true, options: defaultPaths, value: row.paths.map(getOptionFromPath), isDisabled: !row.
|
|
31
|
+
return (_jsx(Creatable, { isMulti: true, options: defaultPaths, value: row.paths.map(getOptionFromPath), isDisabled: !row.line, placeholder: "Choose dataset", onChange: (v) => updateBkPaths(v.map((i) => i.value)), onCreateOption: handleCreatePath, closeMenuOnSelect: false }));
|
|
35
32
|
}
|
|
@@ -11,7 +11,7 @@ import { jsx as _jsx } from "react/jsx-runtime";
|
|
|
11
11
|
\*****************************************************************************/
|
|
12
12
|
import { Badge } from "react-bootstrap";
|
|
13
13
|
export function DatasetEventTypeBadge({ eventType }) {
|
|
14
|
-
const content =
|
|
14
|
+
const content = eventType === "90000000" ? "Data" : eventType;
|
|
15
15
|
const linkProps = content === "Data"
|
|
16
16
|
? {}
|
|
17
17
|
: {
|
|
@@ -12,16 +12,16 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
12
12
|
import { Stack } from "react-bootstrap";
|
|
13
13
|
import { YearBadge } from "./YearBadge.js";
|
|
14
14
|
import { PolarityBadge } from "./PolarityBadge.js";
|
|
15
|
-
import {
|
|
15
|
+
import { StrippingLineVersionBadge } from "./StrippingLineVersionBadge";
|
|
16
16
|
import { DatasetEventTypeBadge } from "./DatasetEventTypeBadge";
|
|
17
17
|
import { BkPath } from "../models/bkPath.js";
|
|
18
18
|
export function DatasetInfo({ pathString }) {
|
|
19
19
|
try {
|
|
20
20
|
const path = new BkPath(pathString);
|
|
21
|
-
return (_jsxs("span", { children: [path.fileName, _jsx("br", {}), _jsxs(Stack, { direction: "horizontal", style: { flexWrap: "wrap" }, gap: 1, children: [_jsx(DatasetEventTypeBadge, { eventType: path.eventType }), _jsx(YearBadge, { year: path.year }), _jsx(PolarityBadge, { polarity: path.polarity || "?" }), _jsx(
|
|
21
|
+
return (_jsxs("span", { children: [path.fileName, _jsx("br", {}), _jsxs(Stack, { direction: "horizontal", style: { flexWrap: "wrap" }, gap: 1, children: [_jsx(DatasetEventTypeBadge, { eventType: path.eventType }), _jsx(YearBadge, { year: path.year }), _jsx(PolarityBadge, { polarity: path.polarity || "?" }), _jsx(StrippingLineVersionBadge, { version: path.strippingVersion })] })] }));
|
|
22
22
|
}
|
|
23
23
|
catch (e) {
|
|
24
|
-
console.error("Error parsing
|
|
24
|
+
console.error("Error parsing dataset:", e);
|
|
25
25
|
return null;
|
|
26
26
|
}
|
|
27
27
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare function DecayCard(): import("react/jsx-runtime").JSX.Element
|
|
1
|
+
export declare function DecayCard(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
2
|
-
import { Button, ButtonGroup, Card,
|
|
1
|
+
import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Button, ButtonGroup, Card, OverlayTrigger, Tooltip } from "react-bootstrap";
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { Download, ExclamationCircle, GearWideConnected, PlusLg, Upload } from "react-bootstrap-icons";
|
|
5
5
|
import { DeleteButton } from "./DeleteButton";
|
|
@@ -14,40 +14,25 @@ import { UploadDttConfigModal } from "./modals/UploadDttConfigModal";
|
|
|
14
14
|
import { VARIABLES_PATH } from "../constants";
|
|
15
15
|
import { useRow } from "../providers/RowProvider";
|
|
16
16
|
import { useWizardConfig } from "../providers/WizardConfigProvider";
|
|
17
|
+
import { DttNameInput } from "./DttNameInput";
|
|
18
|
+
import { GuideLinkButton } from "./GuideLinkButton";
|
|
17
19
|
export function DecayCard() {
|
|
18
20
|
const { row } = useRow();
|
|
19
|
-
const {
|
|
21
|
+
const { setRows, updateRow } = useRows();
|
|
20
22
|
const navigate = useNavigate();
|
|
21
23
|
const metadata = useMetadata();
|
|
22
24
|
const { basePath, variant } = useWizardConfig();
|
|
23
25
|
const [showUploadModal, setShowUploadModal] = useState(false);
|
|
24
|
-
const [dttName, setDttName] = useState(row.dtt?.getName() || "");
|
|
25
26
|
const [dttNameValid, setDttNameValid] = useState(true);
|
|
26
|
-
const [
|
|
27
|
-
if (!metadata) {
|
|
28
|
-
return null;
|
|
29
|
-
}
|
|
30
|
-
function allNameCharsValid(name) {
|
|
31
|
-
const pattern = /^[a-zA-Z0-9_:-]+$/;
|
|
32
|
-
return pattern.test(name);
|
|
33
|
-
}
|
|
34
|
-
function validateName() {
|
|
35
|
-
const trimmedName = dttName.trim();
|
|
36
|
-
const isNameEmpty = trimmedName === "";
|
|
37
|
-
const areCharsValid = allNameCharsValid(trimmedName);
|
|
38
|
-
const otherRowNames = rows.filter((r) => r.id !== row.id).map((row) => row.dtt?.getName() || "");
|
|
39
|
-
const isNameDuplicate = otherRowNames.includes(trimmedName);
|
|
40
|
-
const valid = !isNameEmpty && areCharsValid && !isNameDuplicate;
|
|
41
|
-
setDttNameValid(valid);
|
|
42
|
-
return valid;
|
|
43
|
-
}
|
|
27
|
+
const [autoFocusRow, setAutoFocusRow] = useState(null);
|
|
44
28
|
const handleCreateDTT = () => {
|
|
45
|
-
const dtt = Dtt.create(row.decay.descriptors.template, row.decay.descriptors.mapped_list.flatMap((item) => (Array.isArray(item) ? item : [item])), [],
|
|
29
|
+
const dtt = Dtt.create(row.decay.descriptors.template, row.decay.descriptors.mapped_list.flatMap((item) => (Array.isArray(item) ? item : [item])), [], `MyDecayTree${row.id}`, metadata.tupleTools.tupleTools);
|
|
30
|
+
// Only focus the name input if the DTT was just created
|
|
31
|
+
setAutoFocusRow(row.id);
|
|
46
32
|
updateRow(row.id, (r) => ({
|
|
47
33
|
...r,
|
|
48
|
-
dtt: dtt.
|
|
34
|
+
dtt: row.line ? dtt.withInputFromLine(row.line) : dtt,
|
|
49
35
|
}));
|
|
50
|
-
setAutoFocus(true);
|
|
51
36
|
};
|
|
52
37
|
const handleConfigureDtt = () => {
|
|
53
38
|
setRows((rows) => rows.map((r) => (r.id === row.id ? { ...r, editTree: true } : { ...r, editTree: false })));
|
|
@@ -55,21 +40,8 @@ export function DecayCard() {
|
|
|
55
40
|
};
|
|
56
41
|
const handleDeleteDtt = () => {
|
|
57
42
|
updateRow(row.id, (r) => ({ ...r, dtt: null }));
|
|
58
|
-
setDttName("");
|
|
59
43
|
};
|
|
60
|
-
return (_jsxs(Card, { children: [_jsxs(Card.Header, { className: "d-flex justify-content-between align-items-start gap-2", children: [row.dtt && (
|
|
61
|
-
if (!validateName()) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
updateRow(row.id, (r) => ({ ...r, dtt: r.dtt.withName(dttName) }));
|
|
65
|
-
}, onChange: (event) => {
|
|
66
|
-
setDttName(event.target.value);
|
|
67
|
-
setDttNameValid(true);
|
|
68
|
-
}, isInvalid: !dttNameValid }), _jsx(FormControl.Feedback, { type: "invalid", children: dttName.trim() === ""
|
|
69
|
-
? "Name cannot be empty"
|
|
70
|
-
: !allNameCharsValid(dttName.trim())
|
|
71
|
-
? "Name contains invalid characters"
|
|
72
|
-
: "Name is already taken" })] })), _jsx(ButtonGroup, { children: row.dtt ? (_jsxs(_Fragment, { children: [_jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: "Configure this DecayTreeTuple" }), children: _jsx(Button, { type: "submit", variant: "secondary", onClick: handleConfigureDtt, disabled: !dttNameValid, className: "align-items-center d-flex", children: _jsx(GearWideConnected, {}) }) }), variant === "standalone" && (_jsx(_Fragment, { children: _jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: "Download DecayTreeTuple YAML configuration file" }), children: _jsx(Button, { className: "align-items-center d-flex ms-auto", type: "button", onClick: () => {
|
|
44
|
+
return (_jsxs(Card, { children: [_jsxs(Card.Header, { className: "d-flex justify-content-between align-items-start gap-2", children: [row.dtt && (_jsx(DttNameInput, { dtt: row.dtt, rowId: row.id, autoFocus: autoFocusRow === row.id, onNameValidated: (valid) => setDttNameValid(valid) })), _jsx(ButtonGroup, { children: row.dtt ? (_jsxs(_Fragment, { children: [_jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: "Configure this DecayTreeTuple" }), children: _jsx(Button, { type: "submit", variant: "secondary", onClick: handleConfigureDtt, disabled: !dttNameValid, className: "align-items-center d-flex", children: _jsx(GearWideConnected, {}) }) }), variant === "standalone" && (_jsx(_Fragment, { children: _jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: "Download DecayTreeTuple YAML configuration file" }), children: _jsx(Button, { className: "align-items-center d-flex ms-auto", type: "button", onClick: () => {
|
|
73
45
|
downloadText(YamlFile.fromDtt(row.dtt));
|
|
74
|
-
}, disabled: !dttNameValid, children: _jsx(Download, {}) }) }) })), _jsx(DeleteButton, { action: handleDeleteDtt, popupMessage: "Delete DecayTreeTuple" })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "d-flex align-items-center gap-2", children: [_jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: "Please add a DecayTreeTuple in order to complete the production configuration" }), children: _jsx(ExclamationCircle, { width: 20, height: 20, className: "text-danger me-2" }) }), _jsxs(ButtonGroup, { children: [_jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: "Add a DecayTreeTuple" }), children: _jsx(Button, { type: "submit", variant: "success", onClick: handleCreateDTT,
|
|
46
|
+
}, disabled: !dttNameValid, children: _jsx(Download, {}) }) }) })), _jsx(DeleteButton, { action: handleDeleteDtt, popupMessage: "Delete DecayTreeTuple" })] })) : (_jsxs(_Fragment, { children: [_jsxs("div", { className: "d-flex align-items-center gap-2", children: [_jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: "Please add a DecayTreeTuple in order to complete the production configuration" }), children: _jsx(ExclamationCircle, { width: 20, height: 20, className: "text-danger me-2" }) }), _jsx(GuideLinkButton, { page: "ntupleCreation", topic: "Creating an ntuple" }), _jsxs(ButtonGroup, { className: "mx-2", children: [_jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: "Add a DecayTreeTuple" }), children: _jsx(Button, { type: "submit", variant: "success", onClick: handleCreateDTT, children: _jsx(PlusLg, {}) }) }), variant === "standalone" && (_jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: "Upload DecayTreeTuple configuration file" }), children: _jsx(Button, { className: "ms-auto", type: "button", onClick: () => setShowUploadModal(true), children: _jsx(Upload, {}) }) }))] })] }), showUploadModal && (_jsx(UploadDttConfigModal, { currentRow: row, onClose: () => setShowUploadModal(false) }))] })) })] }), _jsx(Card.Body, { style: { overflowX: "auto" }, children: _jsx(DecayLatex, { decay: row.decay }) })] }));
|
|
75
47
|
}
|
|
@@ -3,5 +3,5 @@ interface Props {
|
|
|
3
3
|
decay: DecayData;
|
|
4
4
|
selection?: string[];
|
|
5
5
|
}
|
|
6
|
-
export declare function DecayLatex({ decay, selection }: Props): import("react/jsx-runtime").JSX.Element
|
|
6
|
+
export declare function DecayLatex({ decay, selection }: Props): import("react/jsx-runtime").JSX.Element;
|
|
7
7
|
export {};
|
|
@@ -9,95 +9,12 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
9
9
|
* granted to it by virtue of its status as an Intergovernmental Organization *
|
|
10
10
|
* or submit itself to any jurisdiction. *
|
|
11
11
|
\*****************************************************************************/
|
|
12
|
-
import { MathJax } from "better-react-mathjax";
|
|
13
12
|
import { OverlayTrigger, Popover } from "react-bootstrap";
|
|
14
13
|
import { useMetadata } from "../providers/MetadataProvider";
|
|
14
|
+
import { selectionDescriptorToLatex } from "../utils/latexUtils";
|
|
15
|
+
import { InlineMath } from "react-katex";
|
|
15
16
|
export function DecayLatex({ decay, selection }) {
|
|
16
17
|
const metadata = useMetadata();
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
}
|
|
20
|
-
const LOKI_MARKERS = {
|
|
21
|
-
SELECTION_PREFIX: "^",
|
|
22
|
-
ARROW: "->",
|
|
23
|
-
};
|
|
24
|
-
const LATEX_COMMANDS = {
|
|
25
|
-
ARROW: "\\to",
|
|
26
|
-
TEXT: (content) => `\\text{${content}}`,
|
|
27
|
-
COLOR: (color, content) => `\\textcolor{${color}}{${content}}`,
|
|
28
|
-
};
|
|
29
|
-
/**
|
|
30
|
-
* Removes leading and trailing braces from LoKi selector string
|
|
31
|
-
*/
|
|
32
|
-
const cleanLoKiSelector = (selector) => {
|
|
33
|
-
return selector.replace(/^\[/, "").replace(/^\^\[/, "^").replace(/\]CC$/, "");
|
|
34
|
-
};
|
|
35
|
-
/**
|
|
36
|
-
* Counts occurrences of a pattern in a string
|
|
37
|
-
*/
|
|
38
|
-
const countMatches = (text, pattern) => {
|
|
39
|
-
return (text.match(pattern) || []).length;
|
|
40
|
-
};
|
|
41
|
-
/**
|
|
42
|
-
* Extracts and processes braces from particle names for sub-decay handling
|
|
43
|
-
*/
|
|
44
|
-
const extractBraces = (name) => {
|
|
45
|
-
const openCount = countMatches(name, /\(/g);
|
|
46
|
-
const closeCount = countMatches(name, /\)/g);
|
|
47
|
-
if (name.startsWith("(")) {
|
|
48
|
-
return {
|
|
49
|
-
cleanName: name.replace(/^\(/, ""),
|
|
50
|
-
openBrace: "(",
|
|
51
|
-
closeBrace: "",
|
|
52
|
-
};
|
|
53
|
-
}
|
|
54
|
-
if (name.endsWith(")") && closeCount > openCount) {
|
|
55
|
-
const extraClosingBraces = closeCount - openCount;
|
|
56
|
-
return {
|
|
57
|
-
cleanName: name.replace(/\)+$/, ""),
|
|
58
|
-
openBrace: "",
|
|
59
|
-
closeBrace: ")".repeat(extraClosingBraces),
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
return { cleanName: name, openBrace: "", closeBrace: "" };
|
|
63
|
-
};
|
|
64
|
-
/**
|
|
65
|
-
* Converts a LoKi decay selector string to LaTeX representation
|
|
66
|
-
*/
|
|
67
|
-
const displaySelectionDescriptor = (selection) => {
|
|
68
|
-
// Generate LoKi selector by marking selected particles with '^'
|
|
69
|
-
const decaySelector = decay.descriptors.template.replace(/\${(\w+)}/g, (_, variableName) => {
|
|
70
|
-
return selection.includes(variableName) ? LOKI_MARKERS.SELECTION_PREFIX : "";
|
|
71
|
-
});
|
|
72
|
-
const cleanedSelector = cleanLoKiSelector(decaySelector);
|
|
73
|
-
const particles = cleanedSelector.split(" ");
|
|
74
|
-
const latexTokens = particles.map((particle) => convertParticleToLatex(particle));
|
|
75
|
-
return latexTokens.join(" ");
|
|
76
|
-
};
|
|
77
|
-
/**
|
|
78
|
-
* Converts a single particle token to LaTeX representation
|
|
79
|
-
*/
|
|
80
|
-
const convertParticleToLatex = (particle) => {
|
|
81
|
-
// Handle arrow tokens
|
|
82
|
-
if (particle === LOKI_MARKERS.ARROW) {
|
|
83
|
-
return LATEX_COMMANDS.ARROW;
|
|
84
|
-
}
|
|
85
|
-
const isMarked = particle.startsWith(LOKI_MARKERS.SELECTION_PREFIX);
|
|
86
|
-
const particleName = particle.replace(/^\^/, "");
|
|
87
|
-
// Handle sub-decay braces
|
|
88
|
-
const { cleanName, openBrace, closeBrace } = extractBraces(particleName);
|
|
89
|
-
// Validate particle exists in metadata
|
|
90
|
-
if (!metadata.particleProperties[cleanName]) {
|
|
91
|
-
console.error(`${cleanName} not found in particle property metadata!`);
|
|
92
|
-
return LATEX_COMMANDS.TEXT(particle);
|
|
93
|
-
}
|
|
94
|
-
// Get base LaTeX representation
|
|
95
|
-
let latex = metadata.particleProperties[cleanName].latex;
|
|
96
|
-
// Underline marked particles
|
|
97
|
-
if (isMarked) {
|
|
98
|
-
latex = LATEX_COMMANDS.COLOR("#4169E1", latex);
|
|
99
|
-
}
|
|
100
|
-
return `${openBrace}${latex}${closeBrace}`;
|
|
101
|
-
};
|
|
102
|
-
return (_jsx(OverlayTrigger, { overlay: _jsxs(Popover, { children: [_jsx(Popover.Header, { children: "LoKi descriptor" }), _jsx(Popover.Body, { children: _jsx("code", { children: decay.descriptors.plain }) })] }), children: _jsx("span", { children: _jsx(MathJax, { inline: true, children: `\\(${selection && selection.length > 0 ? displaySelectionDescriptor(selection) : decay.descriptors.latex}\\)` }) }) }));
|
|
18
|
+
const math = selection?.length ? selectionDescriptorToLatex(metadata, decay, selection) : decay.descriptors.latex;
|
|
19
|
+
return (_jsx(OverlayTrigger, { overlay: _jsxs(Popover, { children: [_jsx(Popover.Header, { children: "LoKi descriptor" }), _jsx(Popover.Body, { children: _jsx("code", { children: decay.descriptors.plain }) })] }), children: _jsx("span", { children: _jsx(InlineMath, { math: math }) }) }));
|
|
103
20
|
}
|
|
@@ -13,11 +13,11 @@ import { useState } from "react";
|
|
|
13
13
|
import { InputGroup, ListGroup } from "react-bootstrap";
|
|
14
14
|
import { DecayLatex } from "./DecayLatex";
|
|
15
15
|
import { DecayTagBadge } from "./DecayTagBadge.js";
|
|
16
|
-
import {
|
|
16
|
+
import { StrippingLinesCountBadge } from "./StrippingLinesCountBadge";
|
|
17
17
|
export function DecayListItem({ decay, initiallySelected = false, onItemSelected }) {
|
|
18
18
|
const [selected, setSelected] = useState(initiallySelected);
|
|
19
19
|
return (_jsx(ListGroup.Item, { as: "li", style: { cursor: "pointer" }, onClick: () => {
|
|
20
20
|
setSelected(!selected);
|
|
21
21
|
onItemSelected({ selected, decay: decay });
|
|
22
|
-
}, children: _jsxs(InputGroup, { children: [_jsx(InputGroup.Checkbox, { checked: selected, readOnly: true }), _jsxs("div", { className: `react-select form-control p-2 d-flex flex-column align-items-start gap-1 ${selected ? "list-group-item-primary" : "list-group-item-light"}`, children: [_jsx(DecayLatex, { decay: decay }), _jsxs("div", { className: "d-flex flex-row flex-wrap gap-1", children: [_jsx(
|
|
22
|
+
}, children: _jsxs(InputGroup, { children: [_jsx(InputGroup.Checkbox, { checked: selected, readOnly: true }), _jsxs("div", { className: `react-select form-control p-2 d-flex flex-column align-items-start gap-1 ${selected ? "list-group-item-primary" : "list-group-item-light"}`, children: [_jsx(DecayLatex, { decay: decay }), _jsxs("div", { className: "d-flex flex-row flex-wrap gap-1", children: [_jsx(StrippingLinesCountBadge, { strippingLineVersions: decay.lines, selected: selected }), decay.tags.map((tag) => (_jsx(DecayTagBadge, { tag: tag }, tag)))] })] })] }) }));
|
|
23
23
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
interface Props {
|
|
2
2
|
tag: string;
|
|
3
3
|
}
|
|
4
|
-
export declare function DecayTagBadge({ tag, ...props }: Props): import("react/jsx-runtime").JSX.Element
|
|
4
|
+
export declare function DecayTagBadge({ tag, ...props }: Props): import("react/jsx-runtime").JSX.Element;
|
|
5
5
|
export {};
|
|
@@ -13,9 +13,6 @@ import { Badge, OverlayTrigger, Tooltip } from "react-bootstrap";
|
|
|
13
13
|
import { useMetadata } from "../providers/MetadataProvider.js";
|
|
14
14
|
export function DecayTagBadge({ tag, ...props }) {
|
|
15
15
|
const metadata = useMetadata();
|
|
16
|
-
if (!metadata) {
|
|
17
|
-
return null;
|
|
18
|
-
}
|
|
19
16
|
const tagInfo = metadata.userHints.decayTags[tag];
|
|
20
17
|
return (_jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: tagInfo.description }), children: _jsx(Badge, { pill: true, bg: tagInfo.warn ? "danger" : "warning", text: tagInfo.warn ? "light" : "dark", ...props, children: tag }) }));
|
|
21
18
|
}
|
|
@@ -1,7 +1 @@
|
|
|
1
|
-
|
|
2
|
-
interface Props {
|
|
3
|
-
onConfigSaved: (config: DttConfig) => void;
|
|
4
|
-
onDirtyUpdated: (dttId: string, dirty: boolean) => void;
|
|
5
|
-
}
|
|
6
|
-
export declare function DecayTreeCard({ onConfigSaved, onDirtyUpdated }: Props): import("react/jsx-runtime").JSX.Element | null;
|
|
7
|
-
export {};
|
|
1
|
+
export declare function DecayTreeCard(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -11,30 +11,25 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
*****************************************************************************/
|
|
12
12
|
import { DecayTagBadge } from "./DecayTagBadge.js";
|
|
13
13
|
import { DecayLatex } from "./DecayLatex";
|
|
14
|
-
import { TupleToolList } from "./TupleToolList";
|
|
15
14
|
import { useMetadata } from "../providers/MetadataProvider.js";
|
|
16
|
-
import { Card, OverlayTrigger, Stack, Tooltip } from "react-bootstrap";
|
|
15
|
+
import { Accordion, Button, Card, OverlayTrigger, Stack, Tooltip } from "react-bootstrap";
|
|
17
16
|
import { QuestionCircle } from "react-bootstrap-icons";
|
|
18
|
-
import { useEffect } from "react";
|
|
19
17
|
import { DecayTreeGraph } from "./DecayTreeGraph";
|
|
20
18
|
import { DecayTreeCardHeader } from "./DecayTreeCardHeader";
|
|
21
19
|
import { ParticleTagFilters } from "./ParticleTagFilters";
|
|
22
20
|
import { useDtt } from "../providers/DttProvider";
|
|
23
|
-
|
|
21
|
+
import { getControlKey } from "../utils/utils";
|
|
22
|
+
import { TupleToolsAccordion } from "./TupleToolsAccordion";
|
|
23
|
+
import { TupleToolGroupsAccordion } from "./TupleToolGroupsAccordion";
|
|
24
|
+
import { useState } from "react";
|
|
25
|
+
import { GuideLinkButton } from "./GuideLinkButton";
|
|
26
|
+
export function DecayTreeCard() {
|
|
24
27
|
const metadata = useMetadata();
|
|
25
|
-
const { dtt, decay,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}, [dtt, dirty]);
|
|
29
|
-
if (!metadata) {
|
|
30
|
-
return null;
|
|
31
|
-
}
|
|
32
|
-
return (_jsxs(Card, { children: [_jsx(DecayTreeCardHeader, { dttName: dtt.getName(), inputs: dtt.config.inputs }), _jsxs(Card.Body, { children: [_jsx(Card.Title, { className: "d-flex justify-content-between align-items-start", children: _jsxs("span", { children: [_jsx(OverlayTrigger, { placement: "bottom", overlay: _jsx(Tooltip, { children: "Click to select particles to configure. Hold ctrl to select multiple. Clear the selection to configure the entire decay." }), children: _jsx(QuestionCircle, {}) }), " ", "Configure ", _jsx(DecayLatex, { decay: decay })] }) }), _jsx(Stack, { direction: "horizontal", style: { flexWrap: "wrap", justifyContent: "center" }, gap: 2, children: decay.tags
|
|
28
|
+
const { dtt, decay, selectedBranch, setSelectedBranch, hoveredBranch } = useDtt();
|
|
29
|
+
const [activeKey, setActiveKey] = useState("0");
|
|
30
|
+
return (_jsxs(Card, { children: [_jsx(DecayTreeCardHeader, { dttName: dtt.getName(), input: dtt.config.input }), _jsxs(Card.Body, { children: [_jsxs(Card.Title, { className: "d-flex justify-content-between align-items-center", children: [_jsx(DecayLatex, { decay: decay, selection: selectedBranch.length === 0 ? hoveredBranch : selectedBranch }), _jsx(OverlayTrigger, { placement: "left", overlay: _jsxs(Tooltip, { children: ["Click on particles to configure. Hold ", _jsx("code", { children: getControlKey() }), " to select multiple. Clear the selection to configure the entire decay. Use", " ", _jsxs("code", { children: [getControlKey(), "+scroll"] }), " to zoom."] }), children: _jsx(QuestionCircle, {}) })] }), _jsx(Stack, { direction: "horizontal", style: { flexWrap: "wrap", justifyContent: "center" }, gap: 2, children: decay.tags
|
|
33
31
|
.filter((tag) => metadata.userHints.decayTags[tag].warn)
|
|
34
|
-
.map((tag) => (_jsx(DecayTagBadge, { tag: tag }, tag))) }),
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
const selection = group.split(",");
|
|
38
|
-
setSelectedBranch(selection);
|
|
39
|
-
}, onSave: () => onConfigSaved(dtt.config) })] })] }));
|
|
32
|
+
.map((tag) => (_jsx(DecayTagBadge, { tag: tag }, tag))) }), _jsxs("div", { className: "d-flex flex-row", children: [_jsxs("div", { style: { width: "100%" }, children: [_jsx(DecayTreeGraph, { onNodeSelectionChanged: (nodeIds) => {
|
|
33
|
+
setSelectedBranch([...nodeIds].sort());
|
|
34
|
+
} }), _jsx("div", { style: { paddingRight: 12 }, children: _jsx(ParticleTagFilters, {}) })] }), _jsxs("div", { className: "d-flex flex-column gap-2 mt-2", style: { minWidth: "350px" }, children: [_jsxs("div", { className: "d-flex justify-content-between align-items-center", children: [_jsxs("div", { className: "d-flex align-items-center gap-2", children: [selectedBranch.length, " particle", selectedBranch.length === 1 ? "" : "s", " selected", _jsx(GuideLinkButton, { page: "nodeTree", topic: "Configuring the node tree" })] }), _jsx(Button, { disabled: selectedBranch.length === 0, variant: "secondary", size: "sm", onClick: () => setSelectedBranch([]), children: "Deselect" })] }), _jsxs(Accordion, { defaultActiveKey: ["0"], activeKey: activeKey, onSelect: (key) => setActiveKey(key), children: [_jsx(TupleToolsAccordion, {}), _jsx(TupleToolGroupsAccordion, { setActiveKey: setActiveKey })] })] })] })] })] }));
|
|
40
35
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { DttConfig } from "../models/dtt.js";
|
|
2
1
|
interface Props {
|
|
3
2
|
dttName: string;
|
|
4
|
-
|
|
3
|
+
input?: string;
|
|
5
4
|
}
|
|
6
|
-
export declare function DecayTreeCardHeader({ dttName,
|
|
5
|
+
export declare function DecayTreeCardHeader({ dttName, input }: Props): import("react/jsx-runtime").JSX.Element;
|
|
7
6
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Accordion, Card, ListGroup, OverlayTrigger, Popover } from "react-bootstrap";
|
|
3
|
-
export function DecayTreeCardHeader({ dttName,
|
|
4
|
-
return (_jsxs(Card.Header, { className: "d-flex flex-column align-items-start", children: [_jsx(OverlayTrigger, { placement: "bottom", overlay: _jsx(Popover, { children: _jsxs(Popover.Body, { children: ["The ROOT TTree will be found under ", _jsx("code", { children: `DecayTreeTuple/${dttName}` }), "."] }) }), children: _jsxs(Card.Title, { children: ["Tree name: ", _jsx("code", { children: dttName })] }) }), _jsx(Accordion, { style: { width: "100%" }, children: _jsxs(Accordion.Item, { eventKey: "0", children: [
|
|
3
|
+
export function DecayTreeCardHeader({ dttName, input }) {
|
|
4
|
+
return (_jsxs(Card.Header, { className: "d-flex flex-column align-items-start", children: [_jsx(OverlayTrigger, { placement: "bottom", overlay: _jsx(Popover, { children: _jsxs(Popover.Body, { children: ["The ROOT TTree will be found under ", _jsx("code", { children: `DecayTreeTuple/${dttName}` }), "."] }) }), children: _jsxs(Card.Title, { children: ["Tree name: ", _jsx("code", { children: dttName })] }) }), _jsx(Accordion, { style: { width: "100%" }, children: _jsxs(Accordion.Item, { eventKey: "0", children: [_jsx(Accordion.Header, { children: input ? "1 input location" : "No input location" }), _jsx(Accordion.Body, { children: _jsx(ListGroup, { variant: "flush", children: _jsx(ListGroup.Item, { children: input ? (_jsx("code", { children: input })) : ("Choose at least one Stripping line, otherwise no decay candidates will be selected") }) }) })] }) })] }));
|
|
5
5
|
}
|
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
import { DecayData } from "../models/decayData";
|
|
2
1
|
interface Props {
|
|
3
|
-
decay: DecayData;
|
|
4
|
-
selectedParticlesIds: string[];
|
|
5
2
|
onNodeSelectionChanged: (nodeIds: string[]) => void;
|
|
6
3
|
}
|
|
7
|
-
export declare function DecayTreeGraph({
|
|
4
|
+
export declare function DecayTreeGraph({ onNodeSelectionChanged }: Props): import("react/jsx-runtime").JSX.Element;
|
|
8
5
|
export {};
|
|
@@ -6,9 +6,12 @@ import { config } from "../config";
|
|
|
6
6
|
import { tex2svg } from "../utils/mathjaxUtils";
|
|
7
7
|
import { useMetadata } from "../providers/MetadataProvider";
|
|
8
8
|
import { useEffect, useRef } from "react";
|
|
9
|
+
import { useDtt } from "../providers/DttProvider";
|
|
10
|
+
import { LATEX_SELECTED_COLOR } from "../utils/latexUtils";
|
|
9
11
|
cytoscape.use(dagre);
|
|
10
|
-
export function DecayTreeGraph({
|
|
12
|
+
export function DecayTreeGraph({ onNodeSelectionChanged }) {
|
|
11
13
|
const metadata = useMetadata();
|
|
14
|
+
const { dtt, decay, selectedBranch, highlightedBranch } = useDtt();
|
|
12
15
|
const cyRef = useRef(null);
|
|
13
16
|
// Sync external selection state to cytoscape selection
|
|
14
17
|
useEffect(() => {
|
|
@@ -16,42 +19,39 @@ export function DecayTreeGraph({ decay, selectedParticlesIds, onNodeSelectionCha
|
|
|
16
19
|
if (!cy)
|
|
17
20
|
return;
|
|
18
21
|
cy.nodes().forEach((node) => {
|
|
19
|
-
if (
|
|
22
|
+
if (selectedBranch.includes(node.id())) {
|
|
20
23
|
node.select();
|
|
21
24
|
}
|
|
22
25
|
else {
|
|
23
26
|
node.unselect();
|
|
24
27
|
}
|
|
25
28
|
});
|
|
26
|
-
}, [
|
|
27
|
-
function makeSVG(text,
|
|
29
|
+
}, [selectedBranch]);
|
|
30
|
+
function makeSVG(text, color = "black") {
|
|
28
31
|
const pipes = "\\phantom{{}^{|-}_{|-}}";
|
|
29
|
-
const texSVG = tex2svg(`${pipes}${text}${pipes}`).innerHTML.replaceAll("currentColor",
|
|
32
|
+
const texSVG = tex2svg(`${pipes}${text}${pipes}`).innerHTML.replaceAll("currentColor", color);
|
|
30
33
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(texSVG)}`;
|
|
31
34
|
}
|
|
32
|
-
function getHtmlTitle(text) {
|
|
33
|
-
const container = document.createElement("span");
|
|
34
|
-
container.innerText = text;
|
|
35
|
-
return container;
|
|
36
|
-
}
|
|
37
35
|
function buildElements() {
|
|
38
36
|
const elements = [];
|
|
39
|
-
if (!metadata)
|
|
40
|
-
return elements;
|
|
41
37
|
const addNodeAndEdge = (item, parentId) => {
|
|
42
38
|
const { branch, particle } = item;
|
|
43
39
|
const particleProperties = metadata.particleProperties[particle];
|
|
40
|
+
const branchList = branch.split(",");
|
|
41
|
+
const tupleToolCount = dtt.getBranchTools(branchList).length + dtt.getGroupsThatIncludeBranch(branchList).length;
|
|
42
|
+
// Color the highlightedBranch (which is hoveredBranch when set, otherwise selectedBranch)
|
|
43
|
+
const imageSrc = highlightedBranch.includes(branch)
|
|
44
|
+
? makeSVG(particleProperties.latex, LATEX_SELECTED_COLOR)
|
|
45
|
+
: makeSVG(particleProperties.latex, "black");
|
|
44
46
|
elements.push({
|
|
45
47
|
data: {
|
|
46
48
|
id: branch,
|
|
47
49
|
label: branch,
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
// Tooltip text (accessible via tippy or title attr if needed)
|
|
52
|
-
title: getHtmlTitle(particleProperties.html).innerText,
|
|
50
|
+
imageSrc,
|
|
51
|
+
tupleToolCountLabel: `${tupleToolCount}`,
|
|
52
|
+
tupleToolStatusColor: tupleToolCount > 0 ? "#198754" : "#6c757d",
|
|
53
53
|
},
|
|
54
|
-
selected:
|
|
54
|
+
selected: selectedBranch.includes(branch),
|
|
55
55
|
});
|
|
56
56
|
if (parentId !== null) {
|
|
57
57
|
elements.push({
|
|
@@ -85,7 +85,7 @@ export function DecayTreeGraph({ decay, selectedParticlesIds, onNodeSelectionCha
|
|
|
85
85
|
return elements;
|
|
86
86
|
}
|
|
87
87
|
const stylesheet = [
|
|
88
|
-
// Disable the grey circle
|
|
88
|
+
// Disable the grey circle that shows when clicking
|
|
89
89
|
{
|
|
90
90
|
selector: "core",
|
|
91
91
|
style: {
|
|
@@ -102,7 +102,21 @@ export function DecayTreeGraph({ decay, selectedParticlesIds, onNodeSelectionCha
|
|
|
102
102
|
"background-opacity": 0,
|
|
103
103
|
width: config.dttGraphOptions.nodes.width,
|
|
104
104
|
height: config.dttGraphOptions.nodes.height,
|
|
105
|
-
label: "",
|
|
105
|
+
label: "data(tupleToolCountLabel)",
|
|
106
|
+
"font-size": 9,
|
|
107
|
+
"font-weight": 700,
|
|
108
|
+
color: "#fff",
|
|
109
|
+
"text-background-color": "data(tupleToolStatusColor)",
|
|
110
|
+
"text-background-opacity": 1,
|
|
111
|
+
"text-background-shape": "circle",
|
|
112
|
+
"text-background-padding": "4px",
|
|
113
|
+
"text-border-width": 1,
|
|
114
|
+
"text-border-color": "#fff",
|
|
115
|
+
"text-border-opacity": 1,
|
|
116
|
+
"text-valign": "bottom",
|
|
117
|
+
"text-halign": "center",
|
|
118
|
+
"text-margin-x": 10,
|
|
119
|
+
"text-margin-y": -2,
|
|
106
120
|
},
|
|
107
121
|
},
|
|
108
122
|
{
|
|
@@ -118,13 +132,6 @@ export function DecayTreeGraph({ decay, selectedParticlesIds, onNodeSelectionCha
|
|
|
118
132
|
"background-color": config.dttGraphOptions.nodes.hoverColor,
|
|
119
133
|
},
|
|
120
134
|
},
|
|
121
|
-
{
|
|
122
|
-
selector: "node:selected",
|
|
123
|
-
style: {
|
|
124
|
-
// Swap to the selected SVG when the node is selected
|
|
125
|
-
"background-image": "data(imageSelected)",
|
|
126
|
-
},
|
|
127
|
-
},
|
|
128
135
|
{
|
|
129
136
|
selector: "edge",
|
|
130
137
|
style: {
|
|
@@ -137,24 +144,42 @@ export function DecayTreeGraph({ decay, selectedParticlesIds, onNodeSelectionCha
|
|
|
137
144
|
},
|
|
138
145
|
},
|
|
139
146
|
];
|
|
147
|
+
const updateZoomBounds = (cy) => {
|
|
148
|
+
const bb = cy.elements().boundingBox();
|
|
149
|
+
const container = cy.container();
|
|
150
|
+
if (!container || bb.w === 0 || bb.h === 0) {
|
|
151
|
+
return;
|
|
152
|
+
}
|
|
153
|
+
const zoomX = container.clientWidth / bb.w;
|
|
154
|
+
const zoomY = container.clientHeight / bb.h;
|
|
155
|
+
const fitZoom = Math.min(zoomX, zoomY);
|
|
156
|
+
cy.minZoom(fitZoom * 0.5);
|
|
157
|
+
cy.maxZoom(fitZoom * 2);
|
|
158
|
+
};
|
|
140
159
|
return (_jsx(CytoscapeComponent, { elements: buildElements(), stylesheet: stylesheet, style: { width: "100%", height: config.dttGraphOptions.height }, autoungrabify: !config.dttGraphOptions.nodes.draggable, autounselectify: false, boxSelectionEnabled: true, cy: (cy) => {
|
|
160
|
+
if (cyRef.current === null) {
|
|
161
|
+
// Handle zoom events
|
|
162
|
+
cy.container()?.addEventListener("wheel", (e) => {
|
|
163
|
+
if (!(e.ctrlKey || e.metaKey))
|
|
164
|
+
return;
|
|
165
|
+
e.preventDefault();
|
|
166
|
+
const zoom = cy.zoom();
|
|
167
|
+
const factor = 1 + (e.deltaY < 0 ? config.dttGraphOptions.zoomStep : -config.dttGraphOptions.zoomStep);
|
|
168
|
+
cy.zoom({
|
|
169
|
+
level: zoom * factor,
|
|
170
|
+
renderedPosition: { x: e.offsetX, y: e.offsetY },
|
|
171
|
+
});
|
|
172
|
+
}, { passive: false });
|
|
173
|
+
}
|
|
141
174
|
cyRef.current = cy;
|
|
142
175
|
// Set up zoom
|
|
143
176
|
cy.userZoomingEnabled(false);
|
|
144
|
-
cy.
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
cy.
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
e.preventDefault();
|
|
151
|
-
const zoom = cy.zoom();
|
|
152
|
-
const factor = 1 + (e.deltaY < 0 ? config.dttGraphOptions.zoomStep : -config.dttGraphOptions.zoomStep);
|
|
153
|
-
cy.zoom({
|
|
154
|
-
level: zoom * factor,
|
|
155
|
-
renderedPosition: { x: e.offsetX, y: e.offsetY },
|
|
156
|
-
});
|
|
157
|
-
}, { passive: false });
|
|
177
|
+
cy.ready(() => {
|
|
178
|
+
updateZoomBounds(cy);
|
|
179
|
+
});
|
|
180
|
+
cy.on("layoutstop", () => {
|
|
181
|
+
updateZoomBounds(cy);
|
|
182
|
+
});
|
|
158
183
|
// Handle node selection events
|
|
159
184
|
cy.off("select unselect", "node");
|
|
160
185
|
cy.on("select unselect", "node", () => {
|
|
@@ -4,7 +4,8 @@ interface Props {
|
|
|
4
4
|
outline?: boolean;
|
|
5
5
|
disabled?: boolean;
|
|
6
6
|
popupMessage?: string;
|
|
7
|
+
placement?: "auto" | "top" | "bottom" | "left" | "right";
|
|
7
8
|
children?: ReactNode;
|
|
8
9
|
}
|
|
9
|
-
export declare function DeleteButton({ action, outline, disabled, popupMessage, children }: Props): import("react/jsx-runtime").JSX.Element | null;
|
|
10
|
+
export declare function DeleteButton({ action, outline, disabled, popupMessage, placement, children, }: Props): import("react/jsx-runtime").JSX.Element | null;
|
|
10
11
|
export {};
|
|
@@ -11,9 +11,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
11
11
|
\*****************************************************************************/
|
|
12
12
|
import { Button, OverlayTrigger, Popover } from "react-bootstrap";
|
|
13
13
|
import { Trash } from "react-bootstrap-icons";
|
|
14
|
-
export function DeleteButton({ action, outline, disabled, popupMessage = "Confirm", children }) {
|
|
14
|
+
export function DeleteButton({ action, outline, disabled, popupMessage = "Confirm", placement = "auto", children, }) {
|
|
15
15
|
if (disabled) {
|
|
16
16
|
return null;
|
|
17
17
|
}
|
|
18
|
-
return (_jsx(OverlayTrigger, { trigger: "click", placement:
|
|
18
|
+
return (_jsx(OverlayTrigger, { trigger: "click", placement: placement, rootClose: true, overlay: _jsx(Popover, { children: _jsx(Popover.Body, { children: _jsx(Button, { variant: "danger", onClick: action, children: popupMessage }) }) }), children: _jsxs(Button, { variant: outline ? "outline-danger" : "danger", disabled: disabled, children: [_jsx(Trash, {}), " ", children] }) }));
|
|
19
19
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import Dtt from "../models/dtt";
|
|
2
|
+
interface Props {
|
|
3
|
+
dtt: Dtt;
|
|
4
|
+
rowId: number;
|
|
5
|
+
autoFocus?: boolean;
|
|
6
|
+
onNameValidated?: (valid: boolean) => void;
|
|
7
|
+
}
|
|
8
|
+
export declare function DttNameInput({ dtt, rowId, autoFocus, onNameValidated }: Props): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export {};
|