lhcb-ntuple-wizard-test 2.0.7 → 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/App.js +2 -1
- 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 -0
- package/dist/components/DecayCard.js +47 -0
- 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 +14 -22
- package/dist/components/DecayTreeCardHeader.d.ts +2 -3
- package/dist/components/DecayTreeCardHeader.js +2 -2
- package/dist/components/DecayTreeGraph.d.ts +1 -5
- package/dist/components/DecayTreeGraph.js +160 -49
- package/dist/components/DeleteButton.d.ts +3 -1
- package/dist/components/DeleteButton.js +2 -2
- package/dist/components/DttNameInput.d.ts +9 -1
- package/dist/components/DttNameInput.js +29 -61
- package/dist/components/GuideLinkButton.d.ts +15 -0
- package/dist/components/GuideLinkButton.js +16 -0
- package/dist/components/NtupleWizard.js +1 -2
- 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 +2 -5
- package/dist/components/RequestRow.d.ts +1 -1
- package/dist/components/RequestRow.js +8 -12
- 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/{TupleToolDropdown.d.ts → TupleToolClassDropdown.d.ts} +2 -5
- package/dist/components/{TupleToolDropdown.js → TupleToolClassDropdown.js} +16 -13
- 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/VerticalLine.d.ts +7 -0
- package/dist/components/VerticalLine.js +4 -0
- package/dist/components/modals/AddTupleToolModal.d.ts +3 -4
- package/dist/components/modals/AddTupleToolModal.js +13 -12
- package/dist/components/modals/ConfigureTupleToolModal.d.ts +2 -2
- package/dist/components/modals/ConfigureTupleToolModal.js +28 -11
- package/dist/components/modals/UploadDttConfigModal.d.ts +1 -1
- package/dist/components/modals/UploadDttConfigModal.js +1 -4
- package/dist/config.d.ts +19 -47
- package/dist/config.js +27 -39
- 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 +5 -39
- package/dist/pages/RequestPage.js +11 -16
- package/dist/providers/DttProvider.d.ts +5 -3
- package/dist/providers/DttProvider.js +33 -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 +40 -4
- package/package.json +24 -10
- 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 -6
- package/dist/components/TupleToolGroup.js +0 -22
- package/dist/components/TupleToolList.d.ts +0 -7
- package/dist/components/TupleToolList.js +0 -38
package/dist/App.js
CHANGED
|
@@ -15,6 +15,7 @@ import { Archive, CodeSlash, House } from "react-bootstrap-icons";
|
|
|
15
15
|
import { config } from "./config";
|
|
16
16
|
import { NtupleWizard } from "./components/NtupleWizard";
|
|
17
17
|
import { BrowserRouter } from "react-router-dom";
|
|
18
|
+
import { Slide, ToastContainer } from "react-toastify";
|
|
18
19
|
export function App() {
|
|
19
|
-
return (_jsxs(_Fragment, { children: [_jsx(Navbar, { collapseOnSelect: true, expand: "lg", bg: "dark", variant: "dark", children: _jsxs(Container, { children: [_jsxs(Navbar.Brand, { href: "/", children: [_jsx("img", { src: "/logo.svg", height: "30", className: "d-inline-block align-top", alt: "LHCb logo" }), " LHCb NTuple Wizard"] }), _jsx(Navbar.Toggle, { "aria-controls": "responsive-navbar-nav" }), _jsx(Navbar.Collapse, { className: "justify-content-end", children: _jsxs(Nav, { children: [_jsxs(NavDropdown, { title: "About", id: "about-dropdown", menuVariant: "dark", children: [_jsxs(NavDropdown.Item, { href: "https://lhcb-dpa.web.cern.ch/lhcb-dpa/wp6/ntupling-wizard.html", target: "_blank", children: [_jsx(House, {}), " Project home"] }), _jsxs(NavDropdown.Item, { href: "https://gitlab.cern.ch/lhcb-dpa/wp6-analysis-preservation-and-open-data/lhcb-ntuple-wizard-frontend", target: "_blank", children: [_jsx(CodeSlash, {}), " Source code"] }), _jsxs(NavDropdown.Item, { href: config.metadata_baseurl, target: "_blank", children: [_jsx(Archive, {}), " Metadata files"] })] }), _jsx(Nav.Link, { href: "https://opendata.cern.ch/", target: "_blank", children: _jsx("img", { src: "/open_data_portal.png", height: "30", alt: "CERN Open Data Portal" }) })] }) })] }) }), _jsx(Container, { className: "mt-4", children:
|
|
20
|
+
return (_jsxs(_Fragment, { children: [_jsx(Navbar, { collapseOnSelect: true, expand: "lg", bg: "dark", variant: "dark", children: _jsxs(Container, { children: [_jsxs(Navbar.Brand, { href: "/", children: [_jsx("img", { src: "/logo.svg", height: "30", className: "d-inline-block align-top", alt: "LHCb logo" }), " LHCb NTuple Wizard"] }), _jsx(Navbar.Toggle, { "aria-controls": "responsive-navbar-nav" }), _jsx(Navbar.Collapse, { className: "justify-content-end", children: _jsxs(Nav, { children: [_jsxs(NavDropdown, { title: "About", id: "about-dropdown", menuVariant: "dark", children: [_jsxs(NavDropdown.Item, { href: "https://lhcb-dpa.web.cern.ch/lhcb-dpa/wp6/ntupling-wizard.html", target: "_blank", children: [_jsx(House, {}), " Project home"] }), _jsxs(NavDropdown.Item, { href: "https://gitlab.cern.ch/lhcb-dpa/wp6-analysis-preservation-and-open-data/lhcb-ntuple-wizard-frontend", target: "_blank", children: [_jsx(CodeSlash, {}), " Source code"] }), _jsxs(NavDropdown.Item, { href: config.metadata_baseurl, target: "_blank", children: [_jsx(Archive, {}), " Metadata files"] })] }), _jsx(Nav.Link, { href: "https://opendata.cern.ch/", target: "_blank", children: _jsx("img", { src: "/open_data_portal.png", height: "30", alt: "CERN Open Data Portal" }) })] }) })] }) }), _jsx(Container, { className: "mt-4", children: _jsxs(BrowserRouter, { children: [_jsx(ToastContainer, { transition: Slide, hideProgressBar: true }), _jsx(NtupleWizard, {})] }) })] }));
|
|
20
21
|
}
|
|
@@ -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
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function DecayCard(): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,47 @@
|
|
|
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
|
+
import { useState } from "react";
|
|
4
|
+
import { Download, ExclamationCircle, GearWideConnected, PlusLg, Upload } from "react-bootstrap-icons";
|
|
5
|
+
import { DeleteButton } from "./DeleteButton";
|
|
6
|
+
import { DecayLatex } from "./DecayLatex";
|
|
7
|
+
import Dtt from "../models/dtt";
|
|
8
|
+
import { useRows } from "../providers/RowsProvider";
|
|
9
|
+
import { useNavigate } from "react-router-dom";
|
|
10
|
+
import { useMetadata } from "../providers/MetadataProvider";
|
|
11
|
+
import { downloadText } from "../utils/utils";
|
|
12
|
+
import { YamlFile } from "../models/yamlFile";
|
|
13
|
+
import { UploadDttConfigModal } from "./modals/UploadDttConfigModal";
|
|
14
|
+
import { VARIABLES_PATH } from "../constants";
|
|
15
|
+
import { useRow } from "../providers/RowProvider";
|
|
16
|
+
import { useWizardConfig } from "../providers/WizardConfigProvider";
|
|
17
|
+
import { DttNameInput } from "./DttNameInput";
|
|
18
|
+
import { GuideLinkButton } from "./GuideLinkButton";
|
|
19
|
+
export function DecayCard() {
|
|
20
|
+
const { row } = useRow();
|
|
21
|
+
const { setRows, updateRow } = useRows();
|
|
22
|
+
const navigate = useNavigate();
|
|
23
|
+
const metadata = useMetadata();
|
|
24
|
+
const { basePath, variant } = useWizardConfig();
|
|
25
|
+
const [showUploadModal, setShowUploadModal] = useState(false);
|
|
26
|
+
const [dttNameValid, setDttNameValid] = useState(true);
|
|
27
|
+
const [autoFocusRow, setAutoFocusRow] = useState(null);
|
|
28
|
+
const handleCreateDTT = () => {
|
|
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);
|
|
32
|
+
updateRow(row.id, (r) => ({
|
|
33
|
+
...r,
|
|
34
|
+
dtt: row.line ? dtt.withInputFromLine(row.line) : dtt,
|
|
35
|
+
}));
|
|
36
|
+
};
|
|
37
|
+
const handleConfigureDtt = () => {
|
|
38
|
+
setRows((rows) => rows.map((r) => (r.id === row.id ? { ...r, editTree: true } : { ...r, editTree: false })));
|
|
39
|
+
void navigate(`${basePath}${VARIABLES_PATH}`);
|
|
40
|
+
};
|
|
41
|
+
const handleDeleteDtt = () => {
|
|
42
|
+
updateRow(row.id, (r) => ({ ...r, dtt: null }));
|
|
43
|
+
};
|
|
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: () => {
|
|
45
|
+
downloadText(YamlFile.fromDtt(row.dtt));
|
|
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 }) })] }));
|
|
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("RoyalBlue", 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,33 +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 { Button, Card, OverlayTrigger, Stack, Tooltip } from "react-bootstrap";
|
|
17
|
-
import {
|
|
18
|
-
import { config } from "../config.js";
|
|
19
|
-
import { useEffect, useState } from "react";
|
|
15
|
+
import { Accordion, Button, Card, OverlayTrigger, Stack, Tooltip } from "react-bootstrap";
|
|
16
|
+
import { QuestionCircle } from "react-bootstrap-icons";
|
|
20
17
|
import { DecayTreeGraph } from "./DecayTreeGraph";
|
|
21
18
|
import { DecayTreeCardHeader } from "./DecayTreeCardHeader";
|
|
22
19
|
import { ParticleTagFilters } from "./ParticleTagFilters";
|
|
23
20
|
import { useDtt } from "../providers/DttProvider";
|
|
24
|
-
|
|
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() {
|
|
25
27
|
const metadata = useMetadata();
|
|
26
|
-
const { dtt, decay,
|
|
27
|
-
const [
|
|
28
|
-
|
|
29
|
-
useEffect(() => {
|
|
30
|
-
onDirtyUpdated(dtt.getName(), dirty);
|
|
31
|
-
}, [dtt, dirty]);
|
|
32
|
-
if (!metadata) {
|
|
33
|
-
return null;
|
|
34
|
-
}
|
|
35
|
-
return (_jsxs(Card, { children: [_jsx(DecayTreeCardHeader, { dttName: dtt.getName(), inputs: dtt.config.inputs }), _jsxs(Card.Body, { children: [_jsxs(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(OverlayTrigger, { placement: "bottom", overlay: _jsxs(Tooltip, { children: ["Click to ", lockGraphZoom ? "unlock" : "lock", " scroll-to-zoom."] }), children: _jsxs(Button, { onClick: () => setLockGraphZoom(!lockGraphZoom), variant: "secondary-outline", children: [lockGraphZoom ? _jsx(Lock, {}) : _jsx(Unlock, {}), _jsx(Search, {})] }) })] }), _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
|
|
36
31
|
.filter((tag) => metadata.userHints.decayTags[tag].warn)
|
|
37
|
-
.map((tag) => (_jsx(DecayTagBadge, { tag: tag }, tag))) }),
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
const selection = group.split(",");
|
|
41
|
-
setSelectedBranch(selection);
|
|
42
|
-
}, 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 })] })] })] })] })] }));
|
|
43
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,9 +1,5 @@
|
|
|
1
|
-
import { DecayData } from "../models/decayData";
|
|
2
1
|
interface Props {
|
|
3
|
-
decay: DecayData;
|
|
4
|
-
lockGraphZoom: boolean;
|
|
5
|
-
selectedParticlesIds: string[];
|
|
6
2
|
onNodeSelectionChanged: (nodeIds: string[]) => void;
|
|
7
3
|
}
|
|
8
|
-
export declare function DecayTreeGraph({
|
|
4
|
+
export declare function DecayTreeGraph({ onNodeSelectionChanged }: Props): import("react/jsx-runtime").JSX.Element;
|
|
9
5
|
export {};
|
|
@@ -1,52 +1,66 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
import
|
|
2
|
+
import CytoscapeComponent from "react-cytoscapejs";
|
|
3
|
+
import cytoscape from "cytoscape";
|
|
4
|
+
import dagre from "cytoscape-dagre";
|
|
4
5
|
import { config } from "../config";
|
|
5
6
|
import { tex2svg } from "../utils/mathjaxUtils";
|
|
6
7
|
import { useMetadata } from "../providers/MetadataProvider";
|
|
7
|
-
import { useEffect,
|
|
8
|
-
|
|
8
|
+
import { useEffect, useRef } from "react";
|
|
9
|
+
import { useDtt } from "../providers/DttProvider";
|
|
10
|
+
import { LATEX_SELECTED_COLOR } from "../utils/latexUtils";
|
|
11
|
+
cytoscape.use(dagre);
|
|
12
|
+
export function DecayTreeGraph({ onNodeSelectionChanged }) {
|
|
9
13
|
const metadata = useMetadata();
|
|
10
|
-
|
|
11
|
-
const
|
|
14
|
+
const { dtt, decay, selectedBranch, highlightedBranch } = useDtt();
|
|
15
|
+
const cyRef = useRef(null);
|
|
16
|
+
// Sync external selection state to cytoscape selection
|
|
12
17
|
useEffect(() => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
}
|
|
25
|
-
function makeSVG(text,
|
|
26
|
-
const pipes = "\\phantom{{}^{|-}_{|-}}";
|
|
27
|
-
const texSVG = tex2svg(`${pipes}${text}${pipes}`).innerHTML.replaceAll("currentColor",
|
|
18
|
+
const cy = cyRef.current;
|
|
19
|
+
if (!cy)
|
|
20
|
+
return;
|
|
21
|
+
cy.nodes().forEach((node) => {
|
|
22
|
+
if (selectedBranch.includes(node.id())) {
|
|
23
|
+
node.select();
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
node.unselect();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
}, [selectedBranch]);
|
|
30
|
+
function makeSVG(text, color = "black") {
|
|
31
|
+
const pipes = "\\phantom{{}^{|-}_{|-}}";
|
|
32
|
+
const texSVG = tex2svg(`${pipes}${text}${pipes}`).innerHTML.replaceAll("currentColor", color);
|
|
28
33
|
return `data:image/svg+xml;charset=utf-8,${encodeURIComponent(texSVG)}`;
|
|
29
34
|
}
|
|
30
|
-
function
|
|
31
|
-
const
|
|
32
|
-
if (!metadata) {
|
|
33
|
-
return graph;
|
|
34
|
-
}
|
|
35
|
+
function buildElements() {
|
|
36
|
+
const elements = [];
|
|
35
37
|
const addNodeAndEdge = (item, parentId) => {
|
|
36
38
|
const { branch, particle } = item;
|
|
37
39
|
const particleProperties = metadata.particleProperties[particle];
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
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");
|
|
46
|
+
elements.push({
|
|
47
|
+
data: {
|
|
48
|
+
id: branch,
|
|
49
|
+
label: branch,
|
|
50
|
+
imageSrc,
|
|
51
|
+
tupleToolCountLabel: `${tupleToolCount}`,
|
|
52
|
+
tupleToolStatusColor: tupleToolCount > 0 ? "#198754" : "#6c757d",
|
|
46
53
|
},
|
|
54
|
+
selected: selectedBranch.includes(branch),
|
|
47
55
|
});
|
|
48
56
|
if (parentId !== null) {
|
|
49
|
-
|
|
57
|
+
elements.push({
|
|
58
|
+
data: {
|
|
59
|
+
id: `${parentId}->${branch}`,
|
|
60
|
+
source: parentId,
|
|
61
|
+
target: branch,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
50
64
|
}
|
|
51
65
|
return branch;
|
|
52
66
|
};
|
|
@@ -68,22 +82,119 @@ export function DecayTreeGraph({ decay, lockGraphZoom, selectedParticlesIds, onN
|
|
|
68
82
|
}
|
|
69
83
|
};
|
|
70
84
|
walk(decay.descriptors.mapped_list, null);
|
|
71
|
-
return
|
|
85
|
+
return elements;
|
|
72
86
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
87
|
+
const stylesheet = [
|
|
88
|
+
// Disable the grey circle that shows when clicking
|
|
89
|
+
{
|
|
90
|
+
selector: "core",
|
|
91
|
+
style: {
|
|
92
|
+
"active-bg-size": 0,
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
{
|
|
96
|
+
selector: "node",
|
|
97
|
+
style: {
|
|
98
|
+
shape: "ellipse",
|
|
99
|
+
// Use the unselected SVG as the background image
|
|
100
|
+
"background-image": "data(imageSrc)",
|
|
101
|
+
"background-fit": "contain",
|
|
102
|
+
"background-opacity": 0,
|
|
103
|
+
width: config.dttGraphOptions.nodes.width,
|
|
104
|
+
height: config.dttGraphOptions.nodes.height,
|
|
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,
|
|
120
|
+
},
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
selector: "node:active",
|
|
124
|
+
style: {
|
|
125
|
+
"overlay-opacity": 0,
|
|
126
|
+
},
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
selector: "node.hover",
|
|
130
|
+
style: {
|
|
131
|
+
"background-opacity": 0.2,
|
|
132
|
+
"background-color": config.dttGraphOptions.nodes.hoverColor,
|
|
78
133
|
},
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
134
|
+
},
|
|
135
|
+
{
|
|
136
|
+
selector: "edge",
|
|
137
|
+
style: {
|
|
138
|
+
"curve-style": "bezier",
|
|
139
|
+
"target-arrow-shape": "triangle",
|
|
140
|
+
width: config.dttGraphOptions.edges.width,
|
|
141
|
+
"line-color": config.dttGraphOptions.edges.color,
|
|
142
|
+
"target-arrow-color": config.dttGraphOptions.edges.color,
|
|
143
|
+
events: "no",
|
|
83
144
|
},
|
|
84
|
-
},
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
145
|
+
},
|
|
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
|
+
};
|
|
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
|
+
}
|
|
174
|
+
cyRef.current = cy;
|
|
175
|
+
// Set up zoom
|
|
176
|
+
cy.userZoomingEnabled(false);
|
|
177
|
+
cy.ready(() => {
|
|
178
|
+
updateZoomBounds(cy);
|
|
179
|
+
});
|
|
180
|
+
cy.on("layoutstop", () => {
|
|
181
|
+
updateZoomBounds(cy);
|
|
182
|
+
});
|
|
183
|
+
// Handle node selection events
|
|
184
|
+
cy.off("select unselect", "node");
|
|
185
|
+
cy.on("select unselect", "node", () => {
|
|
186
|
+
const selected = cy.nodes(":selected").map((n) => n.id());
|
|
187
|
+
onNodeSelectionChanged(selected);
|
|
188
|
+
});
|
|
189
|
+
// Handle hover events
|
|
190
|
+
cy.on("mouseover", "node", (e) => {
|
|
191
|
+
e.target.addClass("hover");
|
|
192
|
+
});
|
|
193
|
+
cy.on("mouseout", "node", (e) => {
|
|
194
|
+
e.target.removeClass("hover");
|
|
195
|
+
});
|
|
196
|
+
}, layout: {
|
|
197
|
+
...config.dttGraphOptions.layout,
|
|
198
|
+
name: "dagre",
|
|
88
199
|
} }));
|
|
89
200
|
}
|