lhcb-ntuple-wizard 2.0.3 → 2.1.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.
Files changed (45) hide show
  1. package/dist/App.js +2 -1
  2. package/dist/components/DecayCard.d.ts +1 -0
  3. package/dist/components/{DttNameInput.js → DecayCard.js} +9 -5
  4. package/dist/components/DecayLatex.js +1 -1
  5. package/dist/components/DecayTreeCard.js +7 -10
  6. package/dist/components/DecayTreeGraph.d.ts +1 -2
  7. package/dist/components/DecayTreeGraph.js +132 -46
  8. package/dist/components/DeleteButton.d.ts +2 -1
  9. package/dist/components/DeleteButton.js +2 -2
  10. package/dist/components/NtupleWizard.d.ts +2 -1
  11. package/dist/components/NtupleWizard.js +8 -2
  12. package/dist/components/RequestButtonGroup.d.ts +1 -7
  13. package/dist/components/RequestButtonGroup.js +5 -3
  14. package/dist/components/RequestRow.d.ts +1 -7
  15. package/dist/components/RequestRow.js +6 -5
  16. package/dist/components/StrippingLineBadge.js +1 -1
  17. package/dist/components/{TupleToolDropdown.d.ts → TupleToolClassDropdown.d.ts} +2 -5
  18. package/dist/components/{TupleToolDropdown.js → TupleToolClassDropdown.js} +10 -4
  19. package/dist/components/TupleToolGroup.d.ts +1 -2
  20. package/dist/components/TupleToolGroup.js +5 -5
  21. package/dist/components/TupleToolList.d.ts +1 -2
  22. package/dist/components/TupleToolList.js +11 -7
  23. package/dist/components/VerticalLine.d.ts +7 -0
  24. package/dist/components/VerticalLine.js +4 -0
  25. package/dist/components/modals/AddTupleToolModal.d.ts +3 -4
  26. package/dist/components/modals/AddTupleToolModal.js +12 -12
  27. package/dist/components/modals/ConfigureTupleToolModal.d.ts +2 -2
  28. package/dist/components/modals/ConfigureTupleToolModal.js +28 -11
  29. package/dist/components/modals/ReasonForRequestModal.d.ts +1 -3
  30. package/dist/components/modals/ReasonForRequestModal.js +6 -4
  31. package/dist/config.d.ts +18 -47
  32. package/dist/config.js +26 -39
  33. package/dist/pages/DecaySearchPage.d.ts +1 -5
  34. package/dist/pages/DecaySearchPage.js +3 -1
  35. package/dist/pages/DecayTreeConfigPage.d.ts +1 -5
  36. package/dist/pages/DecayTreeConfigPage.js +16 -14
  37. package/dist/pages/RequestPage.d.ts +1 -20
  38. package/dist/pages/RequestPage.js +15 -16
  39. package/dist/providers/DttProvider.d.ts +2 -0
  40. package/dist/providers/DttProvider.js +4 -1
  41. package/dist/providers/WizardConfigProvider.d.ts +21 -0
  42. package/dist/providers/WizardConfigProvider.js +21 -0
  43. package/dist/utils/utils.js +36 -3
  44. package/package.json +10 -5
  45. package/dist/components/DttNameInput.d.ts +0 -9
@@ -0,0 +1,4 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ export function VerticalLine({ width = "1px", height = "100%", color = "#bbb" }) {
3
+ return _jsx("div", { style: { borderLeft: `${width} solid ${color}`, height } });
4
+ }
@@ -1,7 +1,6 @@
1
+ import { TupleTool } from "../../models/tupleTool";
1
2
  interface Props {
2
- branch: string[];
3
- filterToolTags: string[];
4
- onClose: () => void;
3
+ onClose: (newTool: TupleTool | null) => void;
5
4
  }
6
- export declare function AddTupleToolModal({ branch, filterToolTags, onClose }: Props): import("react/jsx-runtime").JSX.Element;
5
+ export declare function AddTupleToolModal({ onClose }: Props): import("react/jsx-runtime").JSX.Element;
7
6
  export {};
@@ -1,18 +1,18 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { Button, FormControl, InputGroup, Modal } from "react-bootstrap";
3
- import { TupleToolDropdown } from "../TupleToolDropdown";
2
+ import { Button, ButtonGroup, FormControl, InputGroup, Modal } from "react-bootstrap";
3
+ import { TupleToolClassDropdown } from "../TupleToolClassDropdown";
4
4
  import { TupleToolDocsAccordion } from "../TupleToolDocsAccordion";
5
5
  import { useDtt } from "../../providers/DttProvider";
6
6
  import { TupleTool } from "../../models/tupleTool";
7
7
  import { useEffect, useRef, useState } from "react";
8
- export function AddTupleToolModal({ branch, filterToolTags, onClose }) {
9
- const { dtt, addTool } = useDtt();
8
+ export function AddTupleToolModal({ onClose }) {
9
+ const { dtt, addTool, selectedBranch } = useDtt();
10
10
  const nameInputRef = useRef(null);
11
11
  const [selectedTool, setSelectedTool] = useState(null);
12
12
  useEffect(() => {
13
13
  nameInputRef.current?.focus();
14
14
  }, [selectedTool]);
15
- return (_jsxs(Modal, { show: true, onHide: onClose, children: [_jsx(Modal.Header, { closeButton: true, children: "Add TupleTool" }), _jsxs(Modal.Body, { className: "gap-3 d-flex flex-column", children: [_jsxs(InputGroup, { hasValidation: true, children: [_jsx(TupleToolDropdown, { filterToolTags: filterToolTags, placeholder: "TupleTool class", onChange: (option) => {
15
+ return (_jsxs(Modal, { show: true, onHide: () => onClose(null), children: [_jsx(Modal.Header, { closeButton: true, children: "Add TupleTool" }), _jsxs(Modal.Body, { className: "gap-3 d-flex flex-column", children: [_jsxs(InputGroup, { hasValidation: true, children: [_jsx(TupleToolClassDropdown, { onChange: (option) => {
16
16
  if (option) {
17
17
  setSelectedTool((prev) => new TupleTool(option.value, prev?.name || ""));
18
18
  }
@@ -20,13 +20,13 @@ export function AddTupleToolModal({ branch, filterToolTags, onClose }) {
20
20
  // Remove all non-word characters
21
21
  const name = event.target.value.replaceAll(/[^\w]/g, "");
22
22
  setSelectedTool((prev) => new TupleTool(prev.class, name));
23
- }, value: selectedTool?.name || "", disabled: !selectedTool, isInvalid: !!selectedTool && dtt.toolExists(selectedTool, branch), onKeyDown: (event) => {
23
+ }, value: selectedTool?.name || "", disabled: !selectedTool, isInvalid: !!selectedTool && dtt.toolExists(selectedTool, selectedBranch), onKeyDown: (event) => {
24
24
  if (event.key === "Enter") {
25
- addTool(branch, selectedTool);
26
- onClose();
25
+ addTool(selectedBranch, selectedTool);
26
+ onClose(selectedTool);
27
27
  }
28
- } }), selectedTool && (_jsxs(FormControl.Feedback, { type: "invalid", children: ["A ", selectedTool.class, " with the name \"", selectedTool.name, "\" already exists"] }))] }), selectedTool && _jsx(TupleToolDocsAccordion, { toolClass: selectedTool.class }), _jsx(Button, { className: "align-self-end", variant: "success", disabled: !selectedTool || dtt.toolExists(selectedTool, branch), onClick: () => {
29
- addTool(branch, selectedTool);
30
- onClose();
31
- }, children: "Add tool" })] })] }));
28
+ } }), selectedTool && (_jsxs(FormControl.Feedback, { type: "invalid", children: ["A ", selectedTool.class, " with the name \"", selectedTool.name, "\" already exists"] }))] }), selectedTool && _jsx(TupleToolDocsAccordion, { toolClass: selectedTool.class }), _jsxs(ButtonGroup, { className: "align-self-end", children: [_jsx(Button, { variant: "outline-dark", onClick: () => onClose(null), children: "Cancel" }), _jsx(Button, { disabled: !selectedTool || dtt.toolExists(selectedTool, selectedBranch), onClick: () => {
29
+ addTool(selectedBranch, selectedTool);
30
+ onClose(selectedTool);
31
+ }, children: "Add tool" })] })] })] }));
32
32
  }
@@ -1,8 +1,8 @@
1
1
  import { TupleTool } from "../../models/tupleTool";
2
2
  interface Props {
3
- branch: string[];
4
3
  tool: TupleTool;
4
+ deleteIfCancelled: boolean;
5
5
  onClose: () => void;
6
6
  }
7
- export declare function ConfigureTupleToolModal({ branch, tool, onClose }: Props): import("react/jsx-runtime").JSX.Element;
7
+ export declare function ConfigureTupleToolModal({ tool, deleteIfCancelled, onClose }: Props): import("react/jsx-runtime").JSX.Element;
8
8
  export {};
@@ -1,5 +1,5 @@
1
1
  import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
2
- import { Button, Col, Form, Modal, OverlayTrigger, Row, Tooltip } from "react-bootstrap";
2
+ import { Button, ButtonGroup, Col, Form, Modal, OverlayTrigger, Row, Tooltip } from "react-bootstrap";
3
3
  import { StrParamInput } from "../tupleToolParams/StrParamInput";
4
4
  import { BoolParamInput } from "../tupleToolParams/BoolParamInput";
5
5
  import { NumParamInput } from "../tupleToolParams/NumParamInput";
@@ -8,36 +8,53 @@ import { DictParamInput } from "../tupleToolParams/DictParamInput";
8
8
  import { QuestionCircle } from "react-bootstrap-icons";
9
9
  import { TupleToolDocsAccordion } from "../TupleToolDocsAccordion";
10
10
  import { useDtt } from "../../providers/DttProvider";
11
- export function ConfigureTupleToolModal({ branch, tool, onClose }) {
12
- const { dtt, updateToolParam } = useDtt();
13
- return (_jsxs(Modal, { show: true, size: "xl", fullscreen: "lg-down", onHide: onClose, children: [_jsxs(Modal.Header, { closeButton: true, children: ["Configure ", tool.toString()] }), _jsxs(Modal.Body, { className: "gap-3 d-flex flex-column", children: [tool ? (_jsx(Form, { children: Object.entries(dtt.getToolConfig(branch, tool)).map(([paramName, param]) => {
11
+ import { config } from "../../config";
12
+ import { toast } from "react-toastify";
13
+ export function ConfigureTupleToolModal({ tool, deleteIfCancelled, onClose }) {
14
+ const { dtt, updateToolParam, removeTool, selectedBranch } = useDtt();
15
+ const toolConfig = dtt.getToolConfig(selectedBranch, tool);
16
+ return (_jsxs(Modal, { show: true, size: "xl", fullscreen: "lg-down", backdrop: "static", keyboard: false, children: [_jsxs(Modal.Header, { children: ["Configure ", tool.toString()] }), _jsxs(Modal.Body, { className: "gap-3 d-flex flex-column", children: [_jsx(Form, { children: Object.entries(toolConfig).map(([paramName, param]) => {
14
17
  const { description, type, default: defaultValue, value } = param;
15
18
  let inputComponent;
16
19
  switch (type) {
17
20
  case "str":
18
- inputComponent = (_jsx(StrParamInput, { value: value, defaultValue: defaultValue, onChange: (newValue) => updateToolParam(branch, tool, paramName, newValue), param: paramName }));
21
+ inputComponent = (_jsx(StrParamInput, { value: value, defaultValue: defaultValue, onChange: (newValue) => updateToolParam(selectedBranch, tool, paramName, newValue), param: paramName }));
19
22
  break;
20
23
  case "bool":
21
- inputComponent = (_jsx(BoolParamInput, { value: value, onChange: (newValue) => updateToolParam(branch, tool, paramName, newValue) }));
24
+ inputComponent = (_jsx(BoolParamInput, { value: value, onChange: (newValue) => updateToolParam(selectedBranch, tool, paramName, newValue) }));
22
25
  break;
23
26
  case "int":
24
27
  case "uint":
25
28
  case "float":
26
- inputComponent = (_jsx(NumParamInput, { type: type, value: value, defaultValue: defaultValue, onChange: (newValue) => updateToolParam(branch, tool, paramName, newValue) }));
29
+ inputComponent = (_jsx(NumParamInput, { type: type, value: value, defaultValue: defaultValue, onChange: (newValue) => updateToolParam(selectedBranch, tool, paramName, newValue) }));
27
30
  break;
28
31
  case "text":
29
- inputComponent = (_jsx(ListParamInput, { initialValues: value, defaultValues: defaultValue, newItemValue: "", onChange: (newValue) => updateToolParam(branch, tool, paramName, newValue), buildInnerInput: (props) => _jsx(StrParamInput, { ...props, param: paramName }) }));
32
+ inputComponent = (_jsx(ListParamInput, { initialValues: value, defaultValues: defaultValue, newItemValue: "", onChange: (newValue) => updateToolParam(selectedBranch, tool, paramName, newValue), buildInnerInput: (props) => _jsx(StrParamInput, { ...props, param: paramName }) }));
30
33
  break;
31
34
  case "[int]":
32
35
  case "[uint]":
33
36
  case "[float]":
34
- inputComponent = (_jsx(ListParamInput, { initialValues: value, defaultValues: defaultValue, newItemValue: 0, onChange: (newValue) => updateToolParam(branch, tool, paramName, newValue), buildInnerInput: (props) => (_jsx(NumParamInput, { type: type.slice(1, -1), ...props })) }));
37
+ inputComponent = (_jsx(ListParamInput, { initialValues: value, defaultValues: defaultValue, newItemValue: 0, onChange: (newValue) => updateToolParam(selectedBranch, tool, paramName, newValue), buildInnerInput: (props) => (_jsx(NumParamInput, { type: type.slice(1, -1), ...props })) }));
35
38
  break;
36
39
  case "{str:str}":
37
40
  case "{str:[str]}":
38
- inputComponent = (_jsx(DictParamInput, { value: value, onChange: (newValue) => updateToolParam(branch, tool, paramName, newValue) }));
41
+ inputComponent = (_jsx(DictParamInput, { value: value, onChange: (newValue) => updateToolParam(selectedBranch, tool, paramName, newValue) }));
39
42
  break;
40
43
  }
41
44
  return (_jsxs(Form.Group, { as: Row, className: "mb-2", children: [_jsxs(Form.Label, { column: true, sm: 3, children: [_jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: description }), children: _jsx(QuestionCircle, {}) }), _jsxs("code", { children: [" ", paramName, " "] })] }), _jsx(Form.Label, { column: true, sm: 2, children: _jsxs("code", { children: [" ", type, " "] }) }), _jsx(Col, { sm: 7, children: inputComponent })] }, paramName));
42
- }) })) : ("No tool selected"), _jsx(TupleToolDocsAccordion, { toolClass: tool.class }), _jsx(Button, { className: "align-self-end", onClick: onClose, children: "Save & close" })] })] }));
45
+ }) }), _jsx(TupleToolDocsAccordion, { toolClass: tool.class }), _jsxs(ButtonGroup, { className: "align-self-end", children: [_jsx(Button, { variant: deleteIfCancelled ? "outline-danger" : "outline-dark", onClick: () => {
46
+ if (deleteIfCancelled) {
47
+ removeTool(selectedBranch, tool);
48
+ }
49
+ onClose();
50
+ }, children: "Cancel" }), _jsx(Button, { onClick: () => {
51
+ if (Object.keys(config.tupleToolValidation).includes(tool.class)) {
52
+ const errorMsg = config.tupleToolValidation[tool.class].validate(toolConfig);
53
+ if (errorMsg) {
54
+ toast(errorMsg, { type: "error" });
55
+ return;
56
+ }
57
+ }
58
+ onClose();
59
+ }, children: "Save & close" })] })] })] }));
43
60
  }
@@ -1,7 +1,5 @@
1
1
  interface Props {
2
- submitLocation: string;
3
2
  onClose: (submitted: boolean) => void;
4
- requestReasonMessage: string;
5
3
  }
6
- export declare function ReasonForRequestModal({ submitLocation, onClose, requestReasonMessage }: Props): import("react/jsx-runtime").JSX.Element;
4
+ export declare function ReasonForRequestModal({ onClose }: Props): import("react/jsx-runtime").JSX.Element;
7
5
  export {};
@@ -3,12 +3,14 @@ import { Alert, Button, FormControl, InputGroup, Modal, OverlayTrigger, Spinner,
3
3
  import { useRequest } from "../../providers/RequestProvider";
4
4
  import { useState } from "react";
5
5
  import { useRows } from "../../providers/RowsProvider";
6
- export function ReasonForRequestModal({ submitLocation, onClose, requestReasonMessage }) {
6
+ import { useWizardConfig } from "../../providers/WizardConfigProvider";
7
+ export function ReasonForRequestModal({ onClose }) {
7
8
  const { generateAllFiles } = useRows();
8
9
  const { productionName, reasonForRequest, setReasonForRequest } = useRequest();
10
+ const { requestReasonMessage, submitLocation } = useWizardConfig();
9
11
  const [requestLoading, setRequestLoading] = useState(false);
10
12
  const [requestError, setRequestError] = useState(null);
11
- const submitRequest = (url) => {
13
+ const submitRequest = () => {
12
14
  setRequestLoading(true);
13
15
  setRequestError(null);
14
16
  const allFiles = generateAllFiles();
@@ -19,7 +21,7 @@ export function ReasonForRequestModal({ submitLocation, onClose, requestReasonMe
19
21
  formData.append("email", localStorage.getItem("email") || "");
20
22
  formData.append("name", productionName);
21
23
  formData.append("reasonForRequest", reasonForRequest);
22
- fetch(url, {
24
+ fetch(submitLocation, {
23
25
  method: "POST",
24
26
  body: formData,
25
27
  credentials: "include",
@@ -38,5 +40,5 @@ export function ReasonForRequestModal({ submitLocation, onClose, requestReasonMe
38
40
  setRequestLoading(false);
39
41
  });
40
42
  };
41
- return (_jsxs(Modal, { show: true, onHide: () => onClose(false), size: "lg", children: [_jsx(Modal.Header, { closeButton: true, children: _jsx(Modal.Title, { children: "Reason for request" }) }), _jsxs(Modal.Body, { children: [_jsx(Alert, { children: requestReasonMessage }), requestError && _jsx(Alert, { variant: "danger", children: requestError }), _jsxs(InputGroup, { hasValidation: true, children: [_jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: "Reason for requesting the chosen ntuples" }), children: _jsx(InputGroup.Text, { children: "Reason for request" }) }), _jsx(FormControl, { as: "textarea", rows: 3, value: reasonForRequest, onChange: (event) => setReasonForRequest(event.target.value), isValid: !!reasonForRequest, placeholder: "I need these ntuples for..." })] })] }), _jsx(Modal.Footer, { children: _jsx(Button, { variant: "primary", disabled: !reasonForRequest || requestLoading, onClick: () => submitRequest(submitLocation), children: requestLoading ? (_jsxs(_Fragment, { children: [_jsx(Spinner, { animation: "border", size: "sm" }), " Submitting..."] })) : ("Submit request") }) })] }));
43
+ return (_jsxs(Modal, { show: true, onHide: () => onClose(false), size: "lg", children: [_jsx(Modal.Header, { closeButton: true, children: _jsx(Modal.Title, { children: "Reason for request" }) }), _jsxs(Modal.Body, { children: [_jsx(Alert, { children: requestReasonMessage }), requestError && _jsx(Alert, { variant: "danger", children: requestError }), _jsxs(InputGroup, { hasValidation: true, children: [_jsx(OverlayTrigger, { overlay: _jsx(Tooltip, { children: "Reason for requesting the chosen ntuples" }), children: _jsx(InputGroup.Text, { children: "Reason for request" }) }), _jsx(FormControl, { as: "textarea", rows: 3, value: reasonForRequest, onChange: (event) => setReasonForRequest(event.target.value), isValid: !!reasonForRequest, placeholder: "I need these ntuples for..." })] })] }), _jsx(Modal.Footer, { children: _jsx(Button, { variant: "primary", disabled: !reasonForRequest || requestLoading, onClick: submitRequest, children: requestLoading ? (_jsxs(_Fragment, { children: [_jsx(Spinner, { animation: "border", size: "sm" }), " Submitting..."] })) : ("Submit request") }) })] }));
42
44
  }
package/dist/config.d.ts CHANGED
@@ -1,3 +1,5 @@
1
+ import { DagreLayoutOptions } from "cytoscape-dagre";
2
+ import { ToolConfig } from "./models/dtt";
1
3
  export declare const config: {
2
4
  metadata_baseurl: string;
3
5
  metadata_files: {
@@ -21,58 +23,27 @@ export declare const config: {
21
23
  lifetime: string;
22
24
  };
23
25
  dttGraphOptions: {
24
- layout: {
25
- hierarchical: {
26
- sortMethod: string;
27
- };
28
- };
26
+ height: string;
27
+ zoomMin: number;
28
+ zoomMax: number;
29
+ zoomStep: number;
30
+ layout: DagreLayoutOptions;
29
31
  nodes: {
30
- borderWidth: number;
31
- borderWidthSelected: number;
32
- imagePadding: number;
33
- font: {
34
- strokeWidth: number;
35
- background: string;
36
- };
37
- color: {
38
- background: string;
39
- highlight: {
40
- background: string;
41
- };
42
- hover: {
43
- background: string;
44
- };
45
- };
46
- scaling: {
47
- min: number;
48
- max: number;
49
- };
50
- value: number;
51
- shape: string;
52
- shapeProperties: {
53
- useBorderWithImage: boolean;
54
- useImageSize: boolean;
55
- };
32
+ draggable: boolean;
33
+ width: number;
34
+ height: number;
35
+ hoverColor: string;
56
36
  };
57
37
  edges: {
58
38
  color: string;
59
39
  width: number;
60
- selectionWidth: number;
61
- hoverWidth: number;
62
- };
63
- physics: {
64
- enabled: boolean;
65
40
  };
66
- interaction: {
67
- dragNodes: boolean;
68
- multiselect: boolean;
69
- selectConnectedEdges: boolean;
70
- hoverConnectedEdges: boolean;
71
- hover: boolean;
72
- zoomView: boolean;
73
- };
74
- height: string;
75
- autoResize: boolean;
76
- width: string;
77
41
  };
42
+ tupleToolValidation: TupleToolValidation;
78
43
  };
44
+ interface TupleToolValidation {
45
+ [toolClass: string]: {
46
+ validate: (config: ToolConfig) => string | null;
47
+ };
48
+ }
49
+ export {};
package/dist/config.js CHANGED
@@ -21,52 +21,39 @@ export const config = {
21
21
  lifetime: "secondary",
22
22
  },
23
23
  dttGraphOptions: {
24
+ height: "500px",
25
+ zoomMin: 0.2,
26
+ zoomMax: 3.0,
27
+ zoomStep: 0.018,
24
28
  layout: {
25
- hierarchical: { sortMethod: "directed" },
29
+ rankDir: "TB", // top -> bottom
30
+ nodeSep: 50,
31
+ rankSep: 80,
32
+ animate: false,
26
33
  },
27
34
  nodes: {
28
- borderWidth: 0,
29
- borderWidthSelected: 0,
30
- imagePadding: 10,
31
- font: {
32
- strokeWidth: 20,
33
- background: "white",
34
- },
35
- color: {
36
- background: "white",
37
- highlight: { background: "white" },
38
- hover: { background: "#eee" },
39
- },
40
- scaling: {
41
- min: 32,
42
- max: 32,
43
- },
44
- value: 1,
45
- shape: "image",
46
- shapeProperties: {
47
- useBorderWithImage: true,
48
- useImageSize: false,
49
- },
35
+ draggable: false,
36
+ width: 80,
37
+ height: 30,
38
+ hoverColor: "royalblue",
50
39
  },
51
40
  edges: {
52
- color: "black",
41
+ color: "#222",
53
42
  width: 1,
54
- selectionWidth: 0,
55
- hoverWidth: 0,
56
43
  },
57
- physics: {
58
- enabled: false,
59
- },
60
- interaction: {
61
- dragNodes: false,
62
- multiselect: true,
63
- selectConnectedEdges: false,
64
- hoverConnectedEdges: false,
65
- hover: true,
66
- zoomView: false,
44
+ },
45
+ tupleToolValidation: {
46
+ ["LoKi__Hybrid__TupleTool"]: {
47
+ validate: (config) => {
48
+ const hasVariables = Object.entries(config["Variables"].value).length > 0;
49
+ const hasBoolVariables = Object.entries(config["BoolVariables"].value).length > 0;
50
+ const hasFloatVariables = Object.entries(config["FloatVariables"].value).length > 0;
51
+ const hasIntVariables = Object.entries(config["IntVariables"].value).length > 0;
52
+ if (!hasVariables && !hasBoolVariables && !hasFloatVariables && !hasIntVariables) {
53
+ return "Please add at least one variable";
54
+ }
55
+ return null;
56
+ },
67
57
  },
68
- height: "500px",
69
- autoResize: true,
70
- width: "100%",
71
58
  },
72
59
  };
@@ -1,5 +1 @@
1
- interface Props {
2
- basePath: string;
3
- }
4
- export declare function DecaySearchPage({ basePath }: Props): import("react/jsx-runtime").JSX.Element;
5
- export {};
1
+ export declare function DecaySearchPage(): import("react/jsx-runtime").JSX.Element;
@@ -20,6 +20,7 @@ import { ParticleDropdown } from "../components/ParticleDropdown";
20
20
  import { getSelectTagOptions, TagDropdown } from "../components/TagDropdown";
21
21
  import { useRows } from "../providers/RowsProvider";
22
22
  import { LoadingIndicator } from "../components/LoadingIndicator";
23
+ import { useWizardConfig } from "../providers/WizardConfigProvider";
23
24
  var MatchType;
24
25
  (function (MatchType) {
25
26
  MatchType["any"] = "any";
@@ -31,9 +32,10 @@ var HeadMatchType;
31
32
  HeadMatchType["exactly"] = "exactly";
32
33
  HeadMatchType["category"] = "category";
33
34
  })(HeadMatchType || (HeadMatchType = {}));
34
- export function DecaySearchPage({ basePath }) {
35
+ export function DecaySearchPage() {
35
36
  const metadata = useMetadata();
36
37
  const { rows, setRows } = useRows();
38
+ const { basePath } = useWizardConfig();
37
39
  const [selectedContains, setSelectedContains] = useState([]);
38
40
  const [selectedHead, setSelectedHead] = useState(null);
39
41
  const [selectedHeadTags, setSelectedHeadTags] = useState([]);
@@ -1,5 +1 @@
1
- interface Props {
2
- basePath: string;
3
- }
4
- export declare function DecayTreeConfigPage({ basePath }: Props): import("react/jsx-runtime").JSX.Element;
5
- export {};
1
+ export declare function DecayTreeConfigPage(): import("react/jsx-runtime").JSX.Element;
@@ -9,7 +9,7 @@ import { jsx as _jsx, Fragment as _Fragment, jsxs as _jsxs } from "react/jsx-run
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 { Button, Col, OverlayTrigger, Row, Stack, Tooltip } from "react-bootstrap";
12
+ import { Button, OverlayTrigger, Stack, Tooltip } from "react-bootstrap";
13
13
  import { useNavigate } from "react-router-dom";
14
14
  import { useMetadata } from "../providers/MetadataProvider";
15
15
  import { DecayTreeCard } from "../components/DecayTreeCard";
@@ -18,10 +18,12 @@ import Dtt from "../models/dtt";
18
18
  import { DttProvider } from "../providers/DttProvider";
19
19
  import { LoadingIndicator } from "../components/LoadingIndicator";
20
20
  import { useEffect, useState } from "react";
21
- export function DecayTreeConfigPage({ basePath }) {
21
+ import { useWizardConfig } from "../providers/WizardConfigProvider";
22
+ export function DecayTreeConfigPage() {
22
23
  const navigate = useNavigate();
23
24
  const metadata = useMetadata();
24
25
  const { rows, updateRow } = useRows();
26
+ const { basePath } = useWizardConfig();
25
27
  const [dirtyDtts, setDirtyDtts] = useState(new Set());
26
28
  // Listen for when the user is about to leave the page and alert them if there are unsaved changes
27
29
  useEffect(() => {
@@ -39,18 +41,18 @@ export function DecayTreeConfigPage({ basePath }) {
39
41
  return _jsx(LoadingIndicator, { height: "70vh" });
40
42
  }
41
43
  const rowsToEdit = rows.filter((row) => !!row.editTree);
42
- return (_jsxs(_Fragment, { children: [_jsx("h3", { children: "DecayTreeTuple configuration" }), _jsx(Stack, { gap: 5, children: rowsToEdit.map((row) => (_jsx(Row, { className: "justify-content-lg-center", children: _jsx(Col, { lg: "auto", children: _jsx(DttProvider, { metadata: metadata, decay: row.decay, initialConfig: row.dtt.config, children: _jsx(DecayTreeCard, { onConfigSaved: (newConfig) => {
43
- updateRow(row.id, (r) => ({ ...r, dtt: new Dtt(newConfig, {}) }));
44
- }, onDirtyUpdated: (dttName, dirty) => setDirtyDtts((prev) => {
45
- if (dirty) {
46
- return new Set(prev.add(dttName));
47
- }
48
- else {
49
- const newSet = new Set(prev);
50
- newSet.delete(dttName);
51
- return newSet;
52
- }
53
- }) }) }) }, row.id) }, row.id))) }), _jsx(OverlayTrigger, { placement: "right", overlay: _jsx(Tooltip, { children: "Return to Stripping line and dataset selection" }), children: _jsx(Button, { className: "mt-2 mb-4", type: "submit", onClick: () => {
44
+ return (_jsxs(_Fragment, { children: [_jsx("h3", { className: "mb-4", children: "DecayTreeTuple configuration" }), _jsx(Stack, { gap: 5, children: rowsToEdit.map((row) => (_jsx(DttProvider, { metadata: metadata, decay: row.decay, initialConfig: row.dtt.config, children: _jsx(DecayTreeCard, { onConfigSaved: (newConfig) => {
45
+ updateRow(row.id, (r) => ({ ...r, dtt: new Dtt(newConfig, {}) }));
46
+ }, onDirtyUpdated: (dttName, dirty) => setDirtyDtts((prev) => {
47
+ if (dirty) {
48
+ return new Set(prev.add(dttName));
49
+ }
50
+ else {
51
+ const newSet = new Set(prev);
52
+ newSet.delete(dttName);
53
+ return newSet;
54
+ }
55
+ }) }) }, row.id))) }), _jsx(OverlayTrigger, { placement: "right", overlay: _jsx(Tooltip, { children: "Return to Stripping line and dataset selection" }), children: _jsx(Button, { className: "mt-2 mb-4", type: "submit", onClick: () => {
54
56
  if (dirtyDtts.size > 0) {
55
57
  if (!confirm("You have unsaved changes. Are you sure you want to discard them?")) {
56
58
  return;
@@ -1,20 +1 @@
1
- /*****************************************************************************\
2
- * (c) Copyright 2021-2024 CERN for the benefit of the LHCb Collaboration *
3
- * *
4
- * This software is distributed under the terms of the GNU General Public *
5
- * Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". *
6
- * *
7
- * In applying this licence, CERN does not waive the privileges and immunities *
8
- * granted to it by virtue of its status as an Intergovernmental Organization *
9
- * or submit itself to any jurisdiction. *
10
- \*****************************************************************************/
11
- import { ReactNode } from "react";
12
- export type NtupleWizardVariant = "standalone" | "embedded";
13
- interface Props {
14
- basePath: string;
15
- submitLocation?: string;
16
- requestReasonMessage?: string;
17
- requestSubmittedMessage?: ReactNode;
18
- }
19
- export declare function RequestPage({ basePath, submitLocation, requestReasonMessage, requestSubmittedMessage }: Props): import("react/jsx-runtime").JSX.Element;
20
- export {};
1
+ export declare function RequestPage(): import("react/jsx-runtime").JSX.Element;
@@ -12,7 +12,6 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
12
12
  import { useEffect, useState } from "react";
13
13
  import { Alert, Button, Col, Row, Stack } from "react-bootstrap";
14
14
  import { Download, Send } from "react-bootstrap-icons";
15
- import { useLocation } from "react-router-dom";
16
15
  import { downloadZip, processProductionFiles } from "../utils/utils";
17
16
  import { DeleteButton } from "../components/DeleteButton";
18
17
  import { useMetadata } from "../providers/MetadataProvider";
@@ -27,27 +26,25 @@ import { RowProvider } from "../providers/RowProvider";
27
26
  import { ProductionNameInput } from "../components/ProductionNameInput";
28
27
  import { RequestEmailInput } from "../components/RequestEmailInput";
29
28
  import { RequestButtonGroup } from "../components/RequestButtonGroup";
30
- export function RequestPage({ basePath, submitLocation, requestReasonMessage, requestSubmittedMessage }) {
31
- const location = useLocation();
29
+ import { useWizardConfig } from "../providers/WizardConfigProvider";
30
+ export function RequestPage() {
32
31
  const metadata = useMetadata();
33
32
  const { rows, setRows, generateAllFiles } = useRows();
34
33
  const { emailIsKnown, productionName, setProductionName, validation, showErrors, clearAll, trySubmit } = useRequest();
34
+ const { variant, requestSubmittedMessage, onRequestSubmitted } = useWizardConfig();
35
35
  const [showProdUploadModal, setShowProdUploadModal] = useState(false);
36
36
  const [prodUploadLoading, setProdUploadLoading] = useState(false);
37
37
  const [requestSubmitted, setRequestSubmitted] = useState(false);
38
38
  const [showReasonForRequestModal, setShowReasonForRequestModal] = useState(false);
39
- const variant = submitLocation ? "embedded" : "standalone";
39
+ const [checkedIfCloneNeeded, setCheckedIfCloneNeeded] = useState(false);
40
40
  useEffect(() => {
41
41
  if (!metadata) {
42
42
  return;
43
43
  }
44
- const urlParams = new URLSearchParams(location.search);
45
- if (urlParams.get("clone") === "1") {
46
- const infoYamlString = localStorage.getItem("infoYamlToClone");
47
- const dttConfigsString = localStorage.getItem("dttConfigsToClone");
48
- if (!dttConfigsString) {
49
- return;
50
- }
44
+ // If the localStorage has been set, we should clone the configuration
45
+ const infoYamlString = localStorage.getItem("infoYamlToClone");
46
+ const dttConfigsString = localStorage.getItem("dttConfigsToClone");
47
+ if (dttConfigsString) {
51
48
  setProdUploadLoading(true);
52
49
  setRows([]);
53
50
  try {
@@ -68,7 +65,8 @@ export function RequestPage({ basePath, submitLocation, requestReasonMessage, re
68
65
  localStorage.removeItem("dttConfigsToClone");
69
66
  }
70
67
  }
71
- }, [metadata, location.search]);
68
+ setCheckedIfCloneNeeded(true);
69
+ }, [metadata]);
72
70
  const handlePrimaryAction = async () => {
73
71
  if (trySubmit()) {
74
72
  if (variant === "standalone") {
@@ -80,22 +78,23 @@ export function RequestPage({ basePath, submitLocation, requestReasonMessage, re
80
78
  }
81
79
  }
82
80
  };
83
- if (!metadata) {
81
+ if (!metadata || !checkedIfCloneNeeded) {
84
82
  return _jsx(LoadingIndicator, { height: "70vh" });
85
83
  }
86
84
  if (requestSubmitted) {
87
85
  return (_jsx(Row, { className: "mt-3", children: _jsx(Col, { children: _jsxs(Alert, { variant: "success", dismissible: true, onClose: () => setRequestSubmitted(false), children: [_jsx(Alert.Heading, { children: "Request submitted!" }), requestSubmittedMessage] }) }) }));
88
86
  }
89
- return (_jsxs(_Fragment, { children: [showReasonForRequestModal && (_jsx(ReasonForRequestModal, { submitLocation: submitLocation, requestReasonMessage: requestReasonMessage, onClose: (submitted) => {
87
+ return (_jsxs(_Fragment, { children: [showReasonForRequestModal && (_jsx(ReasonForRequestModal, { onClose: (submitted) => {
90
88
  setShowReasonForRequestModal(false);
91
89
  if (submitted) {
92
90
  setRequestSubmitted(true);
91
+ onRequestSubmitted?.();
93
92
  }
94
- } })), showProdUploadModal && _jsx(UploadDttConfigModal, { onClose: () => setShowProdUploadModal(false) }), _jsxs("div", { className: "d-flex flex-column gap-3", children: [rows.map((row) => (_jsx(RowProvider, { row: row, children: _jsx(RequestRow, { hideDownloadButtons: variant === "standalone", hideUploadButtons: variant === "standalone", basePath: basePath }, row.id) }, row.id))), prodUploadLoading && _jsx(ConfigFilesUploadingAlert, {}), requestSubmitted && (_jsxs(Alert, { variant: "success", dismissible: true, onClose: () => setRequestSubmitted(false), children: [_jsx(Alert.Heading, { children: "Request submitted!" }), requestSubmittedMessage] })), showErrors &&
93
+ } })), showProdUploadModal && _jsx(UploadDttConfigModal, { onClose: () => setShowProdUploadModal(false) }), _jsxs("div", { className: "d-flex flex-column gap-4", children: [rows.map((row) => (_jsx(RowProvider, { row: row, children: _jsx(RequestRow, {}, row.id) }, row.id))), prodUploadLoading && _jsx(ConfigFilesUploadingAlert, {}), showErrors &&
95
94
  (rows.length === 0 ||
96
95
  !validation.allRowsHaveDtt ||
97
96
  !validation.allRowsHaveStrippingLine ||
98
97
  !validation.allRowsHavePaths) && (_jsx(Alert, { variant: "danger", className: "mb-0", children: rows.length === 0
99
98
  ? "Please select at least one decay"
100
- : "Please name all DecayTreeTuples and select at least one stripping line and bookkeeping path for each decay" })), _jsx(Row, { children: _jsx(Col, { xs: "auto", children: _jsx(RequestButtonGroup, { variant: variant, basePath: basePath }) }) }), _jsx(Row, { children: _jsxs(Col, { xs: 4, children: [_jsx(ProductionNameInput, {}), !emailIsKnown && _jsx(RequestEmailInput, {}), _jsxs(Stack, { direction: "horizontal", gap: 1, className: "mt-3 mb-3", children: [_jsxs(Button, { className: "align-items-center d-flex gap-1", onClick: () => void handlePrimaryAction(), children: [variant === "standalone" ? _jsx(Download, {}) : _jsx(Send, {}), variant === "standalone" ? "Download" : "Submit"] }), _jsx(DeleteButton, { action: clearAll, disabled: validation.isEmptySession, outline: undefined, children: "Clear all" })] })] }) })] })] }));
99
+ : "Please name all DecayTreeTuples and select at least one stripping line and bookkeeping path for each decay" })), _jsx(Row, { children: _jsx(Col, { xs: "auto", children: _jsx(RequestButtonGroup, {}) }) }), _jsx(Row, { children: _jsxs(Col, { xs: "auto", children: [_jsx(ProductionNameInput, {}), !emailIsKnown && _jsx(RequestEmailInput, {}), _jsxs(Stack, { direction: "horizontal", gap: 1, className: "mt-3 mb-3", children: [_jsxs(Button, { className: "align-items-center d-flex gap-1", onClick: () => void handlePrimaryAction(), children: [variant === "standalone" ? _jsx(Download, {}) : _jsx(Send, {}), variant === "standalone" ? "Download" : "Submit"] }), _jsx(DeleteButton, { action: clearAll, disabled: validation.isEmptySession, outline: undefined, children: "Clear all" })] })] }) })] })] }));
101
100
  }
@@ -12,6 +12,8 @@ interface DttContextType {
12
12
  dirty: boolean;
13
13
  save(this: void): void;
14
14
  revert(this: void): void;
15
+ selectedBranch: string[];
16
+ setSelectedBranch: (branch: string[]) => void;
15
17
  }
16
18
  interface DttProviderProps {
17
19
  initialConfig: DttConfig;
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
- import { createContext, useCallback, useContext, useReducer } from "react";
2
+ import { createContext, useCallback, useContext, useReducer, useState } from "react";
3
3
  import Dtt from "../models/dtt";
4
4
  const DttContext = createContext(null);
5
5
  function reducer(state, action) {
@@ -31,6 +31,7 @@ function reducer(state, action) {
31
31
  }
32
32
  }
33
33
  export function DttProvider({ initialConfig, decay, metadata, children }) {
34
+ const [selectedBranch, setSelectedBranch] = useState([]);
34
35
  const [state, dispatch] = useReducer(reducer, null, () => ({
35
36
  dtt: new Dtt(structuredClone(initialConfig), metadata.tupleTools.tupleTools),
36
37
  decay,
@@ -66,6 +67,8 @@ export function DttProvider({ initialConfig, decay, metadata, children }) {
66
67
  removeTool,
67
68
  save,
68
69
  revert,
70
+ selectedBranch,
71
+ setSelectedBranch,
69
72
  };
70
73
  return _jsx(DttContext.Provider, { value: value, children: children });
71
74
  }
@@ -0,0 +1,21 @@
1
+ import { ReactNode } from "react";
2
+ type NtupleWizardVariant = "standalone" | "embedded";
3
+ interface WizardConfigContextType {
4
+ variant: NtupleWizardVariant;
5
+ basePath: string;
6
+ submitLocation?: string;
7
+ requestReasonMessage?: string;
8
+ requestSubmittedMessage?: ReactNode;
9
+ onRequestSubmitted?: () => void;
10
+ }
11
+ interface WizardConfigProviderProps {
12
+ basePath: string;
13
+ submitLocation?: string;
14
+ requestReasonMessage?: string;
15
+ requestSubmittedMessage?: ReactNode;
16
+ onRequestSubmitted?: () => void;
17
+ children: ReactNode;
18
+ }
19
+ export declare const WizardConfigProvider: ({ basePath, submitLocation, requestReasonMessage, requestSubmittedMessage, onRequestSubmitted, children, }: WizardConfigProviderProps) => import("react/jsx-runtime").JSX.Element;
20
+ export declare const useWizardConfig: () => WizardConfigContextType;
21
+ export {};