lhcb-ntuple-wizard-test 2.2.3 → 2.3.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/DropdownOptionWithDesc.d.ts +7 -0
- package/dist/components/DropdownOptionWithDesc.js +15 -0
- package/dist/components/TupleToolClassDropdown.d.ts +2 -17
- package/dist/components/TupleToolClassDropdown.js +63 -12
- package/dist/components/modals/AddTupleToolModal.js +20 -15
- package/dist/components/modals/ConfigureTupleToolModal.js +11 -0
- package/dist/components/tupleToolParams/LokiVariableDictInput.d.ts +14 -0
- package/dist/components/tupleToolParams/LokiVariableDictInput.js +42 -0
- package/dist/config.js +7 -5
- package/dist/models/dtt.d.ts +1 -0
- package/dist/models/yamlFile.d.ts +2 -2
- package/dist/providers/DttProvider.d.ts +2 -2
- package/dist/providers/MetadataProvider.d.ts +57 -4
- package/dist/providers/MetadataProvider.js +19 -2
- package/dist/tests/components/modals.test.js +4 -3
- package/dist/tests/models/Dtt.test.js +10 -5
- package/dist/tests/testUtils.d.ts +2 -2
- package/dist/tests/testUtils.js +12 -7
- package/dist/utils/latexUtils.d.ts +3 -3
- package/dist/utils/utils.d.ts +3 -3
- package/package.json +2 -1
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { OptionProps } from "react-select";
|
|
2
|
+
export interface SelectOption {
|
|
3
|
+
value: string;
|
|
4
|
+
label: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare function DropdownOptionWithDesc({ data, innerRef, innerProps, isFocused, isSelected }: OptionProps<SelectOption>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
export function DropdownOptionWithDesc({ data, innerRef, innerProps, isFocused, isSelected }) {
|
|
3
|
+
return (_jsxs("div", { ref: innerRef, ...innerProps, style: {
|
|
4
|
+
backgroundColor: isSelected ? "#0d6efd" : isFocused ? "#e9ecef" : "white",
|
|
5
|
+
color: isSelected ? "white" : "inherit",
|
|
6
|
+
padding: "6px 12px",
|
|
7
|
+
cursor: "pointer",
|
|
8
|
+
}, children: [data.label, isFocused && data.description && (_jsx("div", { style: {
|
|
9
|
+
fontSize: "0.75em",
|
|
10
|
+
color: isSelected ? "rgba(255,255,255,0.75)" : "#6c757d",
|
|
11
|
+
marginTop: 2,
|
|
12
|
+
whiteSpace: "normal",
|
|
13
|
+
lineHeight: 1.3,
|
|
14
|
+
}, children: data.description }))] }));
|
|
15
|
+
}
|
|
@@ -1,18 +1,3 @@
|
|
|
1
|
-
/*****************************************************************************\
|
|
2
|
-
* (c) Copyright 2021 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
1
|
import { GroupBase, Props as SelectProps } from "react-select";
|
|
12
|
-
import {
|
|
13
|
-
|
|
14
|
-
value: string;
|
|
15
|
-
label: ReactNode;
|
|
16
|
-
};
|
|
17
|
-
export declare function TupleToolClassDropdown(props: SelectProps<ToolDropdownOption, false, GroupBase<ToolDropdownOption>>): import("react/jsx-runtime").JSX.Element;
|
|
18
|
-
export {};
|
|
2
|
+
import { SelectOption } from "./DropdownOptionWithDesc";
|
|
3
|
+
export declare function TupleToolClassDropdown(props: SelectProps<SelectOption, false, GroupBase<SelectOption>>): import("react/jsx-runtime").JSX.Element;
|
|
@@ -9,24 +9,75 @@ import { jsx as _jsx } 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 { useDeferredValue, useMemo, useState } from "react";
|
|
12
13
|
import Select from "react-select";
|
|
14
|
+
import Fuse from "fuse.js";
|
|
13
15
|
import { useMetadata } from "../providers/MetadataProvider.js";
|
|
14
16
|
import { TupleTool } from "../models/tupleTool";
|
|
15
17
|
import { useDtt } from "../providers/DttProvider";
|
|
16
18
|
import { config } from "../config";
|
|
19
|
+
import { DropdownOptionWithDesc } from "./DropdownOptionWithDesc";
|
|
20
|
+
function flattenVariableEntries(vars) {
|
|
21
|
+
const entries = [];
|
|
22
|
+
for (const [key, value] of Object.entries(vars)) {
|
|
23
|
+
if (typeof value === "string") {
|
|
24
|
+
entries.push(value ? `${key}: ${value}` : key);
|
|
25
|
+
}
|
|
26
|
+
else if (value !== null && typeof value === "object") {
|
|
27
|
+
entries.push(...flattenVariableEntries(value));
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return entries;
|
|
31
|
+
}
|
|
17
32
|
export function TupleToolClassDropdown(props) {
|
|
18
33
|
const metadata = useMetadata();
|
|
19
34
|
const { selectedBranch } = useDtt();
|
|
20
|
-
const
|
|
21
|
-
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
const [inputValue, setInputValue] = useState("");
|
|
36
|
+
const deferredInput = useDeferredValue(inputValue);
|
|
37
|
+
const allowedTags = useMemo(() => ["IParticleTupleTool", ...(selectedBranch.length === 0 ? ["IEventTupleTool"] : [])], [selectedBranch.length]);
|
|
38
|
+
const allTools = useMemo(() => Object.keys(metadata.tupleTools.tupleTools)
|
|
39
|
+
.sort()
|
|
40
|
+
.map(TupleTool.fromString)
|
|
41
|
+
.map((tool) => ({
|
|
42
|
+
value: tool.toString(),
|
|
43
|
+
label: tool.class,
|
|
44
|
+
description: metadata.tupleTools.tupleTools[tool.toString()].description,
|
|
45
|
+
variables: metadata.kgdoc[tool.class]
|
|
46
|
+
? flattenVariableEntries(metadata.kgdoc[tool.class].variables)
|
|
47
|
+
: [],
|
|
48
|
+
}))
|
|
49
|
+
.filter((tool) => metadata.tupleTools.tupleTools[tool.value].tags.some((tag) => allowedTags.includes(tag)) &&
|
|
50
|
+
!config.disabledTupleTools.includes(tool.value)), [metadata, allowedTags]);
|
|
51
|
+
const groupedOptions = useMemo(() => allowedTags.map((tag) => ({
|
|
52
|
+
label: tag,
|
|
53
|
+
options: allTools.filter((tool) => metadata.tupleTools.tupleTools[tool.value].tags.includes(tag)),
|
|
54
|
+
})), [allTools, allowedTags, metadata]);
|
|
55
|
+
const fuse = useMemo(() => new Fuse(allTools, {
|
|
56
|
+
keys: [
|
|
57
|
+
{ name: "label", weight: 2 },
|
|
58
|
+
{ name: "description", weight: 1 },
|
|
59
|
+
{ name: "variables", weight: 0.5 },
|
|
60
|
+
],
|
|
61
|
+
includeMatches: true,
|
|
62
|
+
threshold: 0.4,
|
|
63
|
+
minMatchCharLength: 2,
|
|
64
|
+
shouldSort: true,
|
|
65
|
+
}), [allTools]);
|
|
66
|
+
const displayOptions = useMemo(() => {
|
|
67
|
+
if (!deferredInput)
|
|
68
|
+
return groupedOptions;
|
|
69
|
+
return fuse.search(deferredInput, { limit: 50 }).map((r) => {
|
|
70
|
+
const matchedVars = (r.matches ?? [])
|
|
71
|
+
.filter((m) => m.key === "variables")
|
|
72
|
+
.map((m) => m.value)
|
|
73
|
+
.filter(Boolean)
|
|
74
|
+
.join(", ");
|
|
75
|
+
return matchedVars ? { ...r.item, description: matchedVars } : r.item;
|
|
76
|
+
});
|
|
77
|
+
}, [deferredInput, fuse, groupedOptions]);
|
|
78
|
+
return (_jsx("div", { className: "react-select form-control p-0", children: _jsx(Select, { placeholder: "Search by name, description, or variables...", styles: { control: (base) => ({ ...base, border: 0, boxShadow: "none" }) }, ...props, options: displayOptions, inputValue: inputValue, onInputChange: (val, { action }) => {
|
|
79
|
+
if (action !== "input-blur" && action !== "menu-close") {
|
|
80
|
+
setInputValue(val);
|
|
81
|
+
}
|
|
82
|
+
}, filterOption: () => true, components: { Option: DropdownOptionWithDesc } }) }));
|
|
32
83
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import { Button, ButtonGroup, FormControl, Modal } from "react-bootstrap";
|
|
2
|
+
import { Button, ButtonGroup, Form, FormControl, Modal } from "react-bootstrap";
|
|
3
3
|
import { TupleToolClassDropdown } from "../TupleToolClassDropdown";
|
|
4
4
|
import { TupleToolDocsAccordion } from "../TupleToolDocsAccordion";
|
|
5
5
|
import { useDtt } from "../../providers/DttProvider";
|
|
@@ -13,20 +13,25 @@ export function AddTupleToolModal({ onClose }) {
|
|
|
13
13
|
useEffect(() => {
|
|
14
14
|
nameInputRef.current?.focus();
|
|
15
15
|
}, [selectedTool]);
|
|
16
|
-
return (_jsxs(Modal, { show: true, onHide: () => onClose(null), size: "lg", children: [_jsx(Modal.Header, { closeButton: true, children: _jsx(Modal.Title, { children: "Add TupleTool" }) }), _jsxs(Modal.Body, { className: "gap-3 d-flex flex-column", children: [selectedBranch.length > 0 && (_jsxs("div", { className: "d-flex flex-row gap-2", children: [_jsx("h6", { className: "my-auto", children: "Target:" }), selectedBranch.map((pid, i) => (_jsx(ParticleLatex, { particleId: pid }, i)))] })), _jsxs("div", { className: "d-flex flex-row gap-2", children: [_jsx(TupleToolClassDropdown, { onChange: (option) => {
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
16
|
+
return (_jsxs(Modal, { show: true, onHide: () => onClose(null), size: "lg", children: [_jsx(Modal.Header, { closeButton: true, children: _jsx(Modal.Title, { children: "Add TupleTool" }) }), _jsxs(Modal.Body, { className: "gap-3 d-flex flex-column", children: [selectedBranch.length > 0 && (_jsxs("div", { className: "d-flex flex-row gap-2", children: [_jsx("h6", { className: "my-auto", children: "Target:" }), selectedBranch.map((pid, i) => (_jsx(ParticleLatex, { particleId: pid }, i)))] })), _jsxs("div", { className: "d-flex flex-column gap-1", children: [_jsxs("div", { className: "d-flex flex-row gap-2", children: [_jsxs(Form.Group, { className: "w-100", children: [_jsx(Form.Label, { className: "fw-bold", children: "Class" }), _jsx(TupleToolClassDropdown, { isClearable: true, onChange: (option) => {
|
|
17
|
+
if (option) {
|
|
18
|
+
setSelectedTool((prev) => new TupleTool(option.value, prev?.name || ""));
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
setSelectedTool(null);
|
|
22
|
+
}
|
|
23
|
+
}, value: selectedTool ? { value: selectedTool.class, label: selectedTool.class } : null })] }), _jsxs(Form.Group, { className: "w-100", children: [_jsx(Form.Label, { className: "fw-bold", children: "Name (optional)" }), _jsx(FormControl, { ref: nameInputRef, placeholder: "e.g. MyTool", onChange: (event) => {
|
|
24
|
+
// Remove all non-word characters
|
|
25
|
+
const name = event.target.value.replaceAll(/[^\w]/g, "");
|
|
26
|
+
setSelectedTool((prev) => new TupleTool(prev.class, name));
|
|
27
|
+
}, value: selectedTool?.name || "", disabled: !selectedTool, isInvalid: !!selectedTool &&
|
|
28
|
+
!!selectedTool.name &&
|
|
29
|
+
dtt.toolExists(selectedTool, selectedBranch), onKeyDown: (event) => {
|
|
30
|
+
if (event.key === "Enter") {
|
|
31
|
+
addTool(selectedBranch, selectedTool);
|
|
32
|
+
onClose(selectedTool);
|
|
33
|
+
}
|
|
34
|
+
} })] })] }), selectedTool && selectedTool.name && dtt.toolExists(selectedTool, selectedBranch) && (_jsxs(FormControl.Feedback, { type: "invalid", className: "d-block", 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: () => {
|
|
30
35
|
addTool(selectedBranch, selectedTool);
|
|
31
36
|
onClose(selectedTool);
|
|
32
37
|
}, children: "Add tool" })] })] })] }));
|
|
@@ -5,13 +5,17 @@ import { BoolParamInput } from "../tupleToolParams/BoolParamInput";
|
|
|
5
5
|
import { NumParamInput } from "../tupleToolParams/NumParamInput";
|
|
6
6
|
import { ListParamInput } from "../tupleToolParams/ListParamInput";
|
|
7
7
|
import { DictParamInput } from "../tupleToolParams/DictParamInput";
|
|
8
|
+
import { LokiVariableDictInput } from "../tupleToolParams/LokiVariableDictInput";
|
|
8
9
|
import { QuestionCircle } from "react-bootstrap-icons";
|
|
9
10
|
import { TupleToolDocsAccordion } from "../TupleToolDocsAccordion";
|
|
10
11
|
import { useDtt } from "../../providers/DttProvider";
|
|
12
|
+
import { useMetadata } from "../../providers/MetadataProvider";
|
|
11
13
|
import { config } from "../../config";
|
|
12
14
|
import { toast } from "react-toastify";
|
|
15
|
+
const LOKI_VARIABLE_PARAMS = new Set(["Variables", "BoolVariables", "FloatVariables", "IntVariables"]);
|
|
13
16
|
export function ConfigureTupleToolModal({ tool, deleteIfCancelled, onClose }) {
|
|
14
17
|
const { dtt, updateToolParam, removeTool, selectedBranch } = useDtt();
|
|
18
|
+
const { lokiVariables } = useMetadata();
|
|
15
19
|
const toolConfig = dtt.getToolConfig(selectedBranch, tool);
|
|
16
20
|
return (_jsxs(Modal, { show: true, size: "xl", fullscreen: "lg-down", backdrop: "static", keyboard: false, children: [_jsx(Modal.Header, { children: _jsxs(Modal.Title, { style: { textOverflow: "ellipsis", overflow: "hidden", whiteSpace: "nowrap" }, children: ["Configure ", tool.toString()] }) }), _jsxs(Modal.Body, { className: "gap-3 d-flex flex-column", children: [_jsx(Form, { children: Object.entries(toolConfig).map(([paramName, param]) => {
|
|
17
21
|
const { description, type, default: defaultValue, value } = param;
|
|
@@ -37,6 +41,13 @@ export function ConfigureTupleToolModal({ tool, deleteIfCancelled, onClose }) {
|
|
|
37
41
|
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 })) }));
|
|
38
42
|
break;
|
|
39
43
|
case "{str:str}":
|
|
44
|
+
if (tool.class === "LoKi__Hybrid__TupleTool" && LOKI_VARIABLE_PARAMS.has(paramName)) {
|
|
45
|
+
inputComponent = (_jsx(LokiVariableDictInput, { value: value, onChange: (newValue) => updateToolParam(selectedBranch, tool, paramName, newValue), lokiVariables: lokiVariables.lokiVariables }));
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
inputComponent = (_jsx(DictParamInput, { value: value, onChange: (newValue) => updateToolParam(selectedBranch, tool, paramName, newValue) }));
|
|
49
|
+
}
|
|
50
|
+
break;
|
|
40
51
|
case "{str:[str]}":
|
|
41
52
|
inputComponent = (_jsx(DictParamInput, { value: value, onChange: (newValue) => updateToolParam(selectedBranch, tool, paramName, newValue) }));
|
|
42
53
|
break;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { LokiVariable } from "../../providers/MetadataProvider";
|
|
2
|
+
interface Props {
|
|
3
|
+
value: {
|
|
4
|
+
[key: string]: string;
|
|
5
|
+
};
|
|
6
|
+
onChange: (value: {
|
|
7
|
+
[key: string]: string;
|
|
8
|
+
}) => void;
|
|
9
|
+
lokiVariables: {
|
|
10
|
+
[variableName: string]: LokiVariable;
|
|
11
|
+
};
|
|
12
|
+
}
|
|
13
|
+
export declare function LokiVariableDictInput({ value, onChange, lokiVariables }: Props): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import { useDeferredValue, useMemo, useState } from "react";
|
|
3
|
+
import { Button, CloseButton, Form, ListGroup } from "react-bootstrap";
|
|
4
|
+
import { PlusLg } from "react-bootstrap-icons";
|
|
5
|
+
import Select from "react-select";
|
|
6
|
+
import Fuse from "fuse.js";
|
|
7
|
+
import { DropdownOptionWithDesc } from "../DropdownOptionWithDesc";
|
|
8
|
+
function LokiValueSelect({ value, onChange, allOptions, fuse }) {
|
|
9
|
+
const [inputValue, setInputValue] = useState("");
|
|
10
|
+
const deferredInput = useDeferredValue(inputValue);
|
|
11
|
+
const filteredOptions = useMemo(() => (deferredInput ? fuse.search(deferredInput, { limit: 50 }).map((r) => r.item) : allOptions), [deferredInput, fuse, allOptions]);
|
|
12
|
+
return (_jsx(Select, { options: filteredOptions, value: allOptions.find((o) => o.value === value) ?? null, inputValue: inputValue, onInputChange: (val, { action }) => {
|
|
13
|
+
if (action !== "input-blur" && action !== "menu-close") {
|
|
14
|
+
setInputValue(val);
|
|
15
|
+
}
|
|
16
|
+
}, filterOption: () => true, onChange: (opt) => onChange(opt?.value ?? ""), placeholder: "LoKi variable...", isClearable: true, components: { Option: DropdownOptionWithDesc } }));
|
|
17
|
+
}
|
|
18
|
+
const entriesToDict = (entries) => Object.fromEntries(entries.map(({ key, value }) => [key, value]));
|
|
19
|
+
export function LokiVariableDictInput({ value, onChange, lokiVariables }) {
|
|
20
|
+
const [entries, setEntries] = useState(Object.entries(value).map(([k, v]) => ({ key: k, value: v })));
|
|
21
|
+
const allOptions = useMemo(() => Object.keys(lokiVariables)
|
|
22
|
+
.sort()
|
|
23
|
+
.map((name) => ({ value: name, label: name, description: lokiVariables[name].description })), [lokiVariables]);
|
|
24
|
+
const fuse = useMemo(() => new Fuse(allOptions, {
|
|
25
|
+
keys: [
|
|
26
|
+
{ name: "label", weight: 2 },
|
|
27
|
+
{ name: "description", weight: 1 },
|
|
28
|
+
],
|
|
29
|
+
threshold: 0.4,
|
|
30
|
+
minMatchCharLength: 2,
|
|
31
|
+
shouldSort: true,
|
|
32
|
+
}), [allOptions]);
|
|
33
|
+
const update = (newEntries) => {
|
|
34
|
+
setEntries(newEntries);
|
|
35
|
+
onChange(entriesToDict(newEntries));
|
|
36
|
+
};
|
|
37
|
+
const handleAdd = () => update([...entries, { key: "", value: "" }]);
|
|
38
|
+
const handleRemove = (index) => update(entries.filter((_, i) => i !== index));
|
|
39
|
+
const handleKeyChange = (index, key) => update(entries.map((entry, i) => (i === index ? { ...entry, key } : entry)));
|
|
40
|
+
const handleValueChange = (index, val) => update(entries.map((entry, i) => (i === index ? { ...entry, value: val } : entry)));
|
|
41
|
+
return (_jsxs(_Fragment, { children: [_jsx(ListGroup, { variant: "flush", children: entries.map(({ key, value: entryValue }, i) => (_jsx(ListGroup.Item, { className: "px-0", children: _jsxs("div", { className: "d-flex gap-2 align-items-center", children: [_jsx(Form.Control, { type: "text", value: key, placeholder: "Branch name", style: { flex: "0 0 35%" }, onChange: (e) => handleKeyChange(i, e.target.value) }), _jsx("div", { style: { flex: 1 }, children: _jsx(LokiValueSelect, { value: entryValue, onChange: (val) => handleValueChange(i, val), allOptions: allOptions, fuse: fuse }) }), _jsx(CloseButton, { onClick: () => handleRemove(i) })] }) }, i))) }), _jsx(Button, { variant: "success", size: "sm", onClick: handleAdd, className: "mt-1", children: _jsx(PlusLg, {}) })] }));
|
|
42
|
+
}
|
package/dist/config.js
CHANGED
|
@@ -46,11 +46,13 @@ export const config = {
|
|
|
46
46
|
tupleToolValidation: {
|
|
47
47
|
["LoKi__Hybrid__TupleTool"]: {
|
|
48
48
|
validate: (config) => {
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
49
|
+
const paramNames = ["Variables", "BoolVariables", "FloatVariables", "IntVariables"];
|
|
50
|
+
const allEntries = paramNames.flatMap((name) => Object.entries(config[name].value));
|
|
51
|
+
const hasIncomplete = allEntries.some(([key, value]) => !key || !value);
|
|
52
|
+
if (hasIncomplete) {
|
|
53
|
+
return "All variable entries must have both a branch name and a LoKi variable selected";
|
|
54
|
+
}
|
|
55
|
+
if (allEntries.length === 0) {
|
|
54
56
|
return "Please add at least one variable";
|
|
55
57
|
}
|
|
56
58
|
return null;
|
package/dist/models/dtt.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Dtt from "./dtt";
|
|
2
2
|
import { RowData } from "./rowData";
|
|
3
|
-
import {
|
|
3
|
+
import { Metadata } from "../providers/MetadataProvider";
|
|
4
4
|
import { JobConfig } from "./jobConfig";
|
|
5
5
|
interface InfoYamlDefaults {
|
|
6
6
|
application: string;
|
|
@@ -19,6 +19,6 @@ export declare class YamlFile {
|
|
|
19
19
|
content: string;
|
|
20
20
|
constructor(name: string, content: string);
|
|
21
21
|
static fromDtt(dtt: Dtt): YamlFile;
|
|
22
|
-
static createInfoYaml(rows: RowData[], metadata:
|
|
22
|
+
static createInfoYaml(rows: RowData[], metadata: Metadata): YamlFile;
|
|
23
23
|
}
|
|
24
24
|
export {};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { ReactNode } from "react";
|
|
2
2
|
import Dtt, { DttConfig, ToolParamTypeMap } from "../models/dtt";
|
|
3
|
-
import {
|
|
3
|
+
import { Metadata } from "./MetadataProvider";
|
|
4
4
|
import { DecayData } from "../models/decayData";
|
|
5
5
|
import { TupleTool } from "../models/tupleTool";
|
|
6
6
|
interface DttContextType {
|
|
@@ -18,7 +18,7 @@ interface DttContextType {
|
|
|
18
18
|
interface DttProviderProps {
|
|
19
19
|
initialConfig: DttConfig;
|
|
20
20
|
decay: DecayData;
|
|
21
|
-
metadata:
|
|
21
|
+
metadata: Metadata;
|
|
22
22
|
children: ReactNode;
|
|
23
23
|
}
|
|
24
24
|
export declare function DttProvider({ initialConfig, decay, metadata, children }: DttProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -37,7 +37,58 @@ interface StrippingInfo {
|
|
|
37
37
|
[key: string]: string;
|
|
38
38
|
};
|
|
39
39
|
}
|
|
40
|
-
export interface
|
|
40
|
+
export interface LokiVariable {
|
|
41
|
+
description: string;
|
|
42
|
+
documentation: string;
|
|
43
|
+
source: string;
|
|
44
|
+
}
|
|
45
|
+
interface KgDocItem {
|
|
46
|
+
variables: {
|
|
47
|
+
[key: string]: string | object;
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
export interface Metadata {
|
|
51
|
+
dataset: string[];
|
|
52
|
+
decays: {
|
|
53
|
+
[key: string]: DecayData;
|
|
54
|
+
};
|
|
55
|
+
kgdoc: {
|
|
56
|
+
[key: string]: KgDocItem;
|
|
57
|
+
};
|
|
58
|
+
lokiVariables: {
|
|
59
|
+
applicationInfo: ApplicationInfo;
|
|
60
|
+
lokiVariables: {
|
|
61
|
+
[key: string]: LokiVariable;
|
|
62
|
+
};
|
|
63
|
+
};
|
|
64
|
+
particleProperties: {
|
|
65
|
+
[key: string]: Particle;
|
|
66
|
+
};
|
|
67
|
+
stripping: {
|
|
68
|
+
[key: string]: {
|
|
69
|
+
[key: string]: StrippingInfo;
|
|
70
|
+
};
|
|
71
|
+
};
|
|
72
|
+
strippingHints: {
|
|
73
|
+
[key: string]: {
|
|
74
|
+
davinci: string;
|
|
75
|
+
description: string;
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
tupleTools: {
|
|
79
|
+
applicationInfo: ApplicationInfo;
|
|
80
|
+
tupleTools: ToolMetadata;
|
|
81
|
+
};
|
|
82
|
+
userHints: {
|
|
83
|
+
decayTags: {
|
|
84
|
+
[key: string]: DecayTagHint;
|
|
85
|
+
};
|
|
86
|
+
particleTags: {
|
|
87
|
+
[key: string]: ParticleTagHint;
|
|
88
|
+
};
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
export interface MetadataSchema {
|
|
41
92
|
dataset: string[];
|
|
42
93
|
decays: {
|
|
43
94
|
[key: string]: DecayData;
|
|
@@ -46,11 +97,13 @@ export interface MetadataContext {
|
|
|
46
97
|
[key: string]: string;
|
|
47
98
|
};
|
|
48
99
|
kgdoc: {
|
|
49
|
-
[key: string]:
|
|
100
|
+
[key: string]: KgDocItem;
|
|
50
101
|
};
|
|
51
102
|
lokiVariables: {
|
|
52
103
|
applicationInfo: ApplicationInfo;
|
|
53
|
-
lokiVariables:
|
|
104
|
+
lokiVariables: {
|
|
105
|
+
[key: string]: LokiVariable;
|
|
106
|
+
};
|
|
54
107
|
};
|
|
55
108
|
particleProperties: {
|
|
56
109
|
[key: string]: Particle;
|
|
@@ -83,5 +136,5 @@ interface Props {
|
|
|
83
136
|
children: ReactNode;
|
|
84
137
|
}
|
|
85
138
|
export declare function MetadataProvider({ children }: Props): import("react/jsx-runtime").JSX.Element;
|
|
86
|
-
export declare const useMetadata: () =>
|
|
139
|
+
export declare const useMetadata: () => Metadata;
|
|
87
140
|
export {};
|
|
@@ -32,10 +32,27 @@ export function MetadataProvider({ children }) {
|
|
|
32
32
|
const metadataContextKeys = Object.keys(config.metadata_files);
|
|
33
33
|
// Load all metadata files
|
|
34
34
|
const promises = metadataContextKeys.map(async (key) => [key, await loadDict(config.metadata_files[key])]);
|
|
35
|
-
// Build the
|
|
35
|
+
// Build the Metadata object
|
|
36
36
|
Promise.all(promises)
|
|
37
37
|
.then((entries) => {
|
|
38
|
-
|
|
38
|
+
const m = Object.fromEntries(entries);
|
|
39
|
+
setMetadata({
|
|
40
|
+
dataset: m.dataset,
|
|
41
|
+
decays: m.decays,
|
|
42
|
+
kgdoc: m.kgdoc,
|
|
43
|
+
lokiVariables: m.lokiVariables,
|
|
44
|
+
particleProperties: m.particleProperties,
|
|
45
|
+
stripping: m.stripping,
|
|
46
|
+
strippingHints: m.strippingHints,
|
|
47
|
+
tupleTools: {
|
|
48
|
+
applicationInfo: m.tupleTools?.applicationInfo ?? {},
|
|
49
|
+
tupleTools: Object.fromEntries(Object.entries(m.tupleTools?.tupleTools ?? {}).map(([key, tool]) => [
|
|
50
|
+
key,
|
|
51
|
+
{ ...tool, summary: m.embedding?.[key] ?? "" },
|
|
52
|
+
])),
|
|
53
|
+
},
|
|
54
|
+
userHints: m.userHints,
|
|
55
|
+
});
|
|
39
56
|
})
|
|
40
57
|
.catch(setError);
|
|
41
58
|
}, []);
|
|
@@ -63,7 +63,8 @@ const diverseToolMetadata = {
|
|
|
63
63
|
...mockToolMetadata,
|
|
64
64
|
DiverseTool: {
|
|
65
65
|
description: "Tool with diverse param types",
|
|
66
|
-
documentation: "",
|
|
66
|
+
documentation: "No documentation available.",
|
|
67
|
+
summary: "",
|
|
67
68
|
tags: [],
|
|
68
69
|
interface: [
|
|
69
70
|
{ name: "StrParam", type: "str", cpp_type: "string", default: "hello", description: "A string param" },
|
|
@@ -185,7 +186,7 @@ describe("AddTupleToolModal", () => {
|
|
|
185
186
|
it("sanitizes the tool name on input and reflects the value", () => {
|
|
186
187
|
render(_jsx(AddTupleToolModal, { onClose: vi.fn() }));
|
|
187
188
|
fireEvent.click(screen.getByTestId("tool-class-dropdown"));
|
|
188
|
-
const nameInput = screen.getByPlaceholderText("
|
|
189
|
+
const nameInput = screen.getByPlaceholderText("e.g. MyTool");
|
|
189
190
|
fireEvent.change(nameInput, { target: { value: "my tool!" } });
|
|
190
191
|
expect(nameInput).toHaveValue("mytool");
|
|
191
192
|
});
|
|
@@ -194,7 +195,7 @@ describe("AddTupleToolModal", () => {
|
|
|
194
195
|
const onClose = vi.fn();
|
|
195
196
|
render(_jsx(AddTupleToolModal, { onClose: onClose }));
|
|
196
197
|
fireEvent.click(screen.getByTestId("tool-class-dropdown"));
|
|
197
|
-
const nameInput = screen.getByPlaceholderText("
|
|
198
|
+
const nameInput = screen.getByPlaceholderText("e.g. MyTool");
|
|
198
199
|
fireEvent.keyDown(nameInput, { key: "Enter" });
|
|
199
200
|
expect(mockAddTool).toHaveBeenCalled();
|
|
200
201
|
expect(onClose).toHaveBeenCalledWith(expect.any(TupleTool));
|
|
@@ -385,7 +385,8 @@ const fixtureParsed = yaml.load(fixtureYaml);
|
|
|
385
385
|
const fixtureToolMetadata = {
|
|
386
386
|
TupleToolKinematic: {
|
|
387
387
|
description: "",
|
|
388
|
-
documentation: "",
|
|
388
|
+
documentation: "No documentation available.",
|
|
389
|
+
summary: "",
|
|
389
390
|
tags: [],
|
|
390
391
|
interface: [
|
|
391
392
|
{ name: "ExtraName", type: "str", cpp_type: "std::string", default: "", description: "" },
|
|
@@ -402,7 +403,8 @@ const fixtureToolMetadata = {
|
|
|
402
403
|
},
|
|
403
404
|
TupleToolPid: {
|
|
404
405
|
description: "",
|
|
405
|
-
documentation: "",
|
|
406
|
+
documentation: "No documentation available.",
|
|
407
|
+
summary: "",
|
|
406
408
|
tags: [],
|
|
407
409
|
interface: [
|
|
408
410
|
{ name: "ExtraName", type: "str", cpp_type: "std::string", default: "", description: "" },
|
|
@@ -412,7 +414,8 @@ const fixtureToolMetadata = {
|
|
|
412
414
|
},
|
|
413
415
|
TupleToolANNPID: {
|
|
414
416
|
description: "",
|
|
415
|
-
documentation: "",
|
|
417
|
+
documentation: "No documentation available.",
|
|
418
|
+
summary: "",
|
|
416
419
|
tags: [],
|
|
417
420
|
interface: [
|
|
418
421
|
{ name: "ExtraName", type: "str", cpp_type: "std::string", default: "", description: "" },
|
|
@@ -436,7 +439,8 @@ const fixtureToolMetadata = {
|
|
|
436
439
|
},
|
|
437
440
|
TupleToolAngles: {
|
|
438
441
|
description: "",
|
|
439
|
-
documentation: "",
|
|
442
|
+
documentation: "No documentation available.",
|
|
443
|
+
summary: "",
|
|
440
444
|
tags: [],
|
|
441
445
|
interface: [
|
|
442
446
|
{ name: "ExtraName", type: "str", cpp_type: "std::string", default: "", description: "" },
|
|
@@ -447,7 +451,8 @@ const fixtureToolMetadata = {
|
|
|
447
451
|
},
|
|
448
452
|
TupleToolCorrectedMass: {
|
|
449
453
|
description: "",
|
|
450
|
-
documentation: "",
|
|
454
|
+
documentation: "No documentation available.",
|
|
455
|
+
summary: "",
|
|
451
456
|
tags: [],
|
|
452
457
|
interface: [
|
|
453
458
|
{ name: "ExtraName", type: "str", cpp_type: "std::string", default: "", description: "" },
|
|
@@ -4,7 +4,7 @@ import Dtt from "../models/dtt";
|
|
|
4
4
|
import { DecayData } from "../models/decayData";
|
|
5
5
|
import { RowData } from "../models/rowData";
|
|
6
6
|
import { StrippingLine } from "../models/strippingLine";
|
|
7
|
-
import {
|
|
7
|
+
import { Metadata } from "../providers/MetadataProvider";
|
|
8
8
|
import { Particle } from "../models/particle";
|
|
9
9
|
export declare const mockToolMetadata: ToolMetadata;
|
|
10
10
|
export declare const mockBranchItems: BranchMapItem[];
|
|
@@ -16,7 +16,7 @@ export declare function createMockRow(overrides?: Partial<RowData>): RowData;
|
|
|
16
16
|
export declare const mockParticleProperties: {
|
|
17
17
|
[key: string]: Particle;
|
|
18
18
|
};
|
|
19
|
-
export declare const mockMetadata:
|
|
19
|
+
export declare const mockMetadata: Metadata;
|
|
20
20
|
export declare const mockInlineMath: ({ math }: {
|
|
21
21
|
math: string;
|
|
22
22
|
}) => import("react/jsx-runtime").JSX.Element;
|
package/dist/tests/testUtils.js
CHANGED
|
@@ -8,37 +8,43 @@ import Dtt from "../models/dtt";
|
|
|
8
8
|
export const mockToolMetadata = {
|
|
9
9
|
TupleToolKinematic: {
|
|
10
10
|
description: "Kinematic information",
|
|
11
|
-
documentation: "",
|
|
11
|
+
documentation: "No documentation available.",
|
|
12
|
+
summary: "TupleToolKinematic summary",
|
|
12
13
|
tags: [],
|
|
13
14
|
interface: [{ name: "Verbose", type: "bool", cpp_type: "bool", default: false, description: "Verbose output" }],
|
|
14
15
|
},
|
|
15
16
|
TupleToolPid: {
|
|
16
17
|
description: "PID information",
|
|
17
|
-
documentation: "",
|
|
18
|
+
documentation: "No documentation available.",
|
|
19
|
+
summary: "TupleToolPid summary",
|
|
18
20
|
tags: [],
|
|
19
21
|
interface: [{ name: "Verbose", type: "bool", cpp_type: "bool", default: false, description: "Verbose output" }],
|
|
20
22
|
},
|
|
21
23
|
TupleToolANNPID: {
|
|
22
24
|
description: "ANN PID",
|
|
23
|
-
documentation: "",
|
|
25
|
+
documentation: "No documentation available.",
|
|
26
|
+
summary: "TupleToolANNPID summary",
|
|
24
27
|
tags: [],
|
|
25
28
|
interface: [],
|
|
26
29
|
},
|
|
27
30
|
TupleToolGeometry: {
|
|
28
31
|
description: "Geometry",
|
|
29
|
-
documentation: "",
|
|
32
|
+
documentation: "No documentation available.",
|
|
33
|
+
summary: "TupleToolGeometry summary",
|
|
30
34
|
tags: [],
|
|
31
35
|
interface: [],
|
|
32
36
|
},
|
|
33
37
|
TupleToolEventInfo: {
|
|
34
38
|
description: "Event info",
|
|
35
|
-
documentation: "",
|
|
39
|
+
documentation: "No documentation available.",
|
|
40
|
+
summary: "TupleToolEventInfo summary",
|
|
36
41
|
tags: [],
|
|
37
42
|
interface: [],
|
|
38
43
|
},
|
|
39
44
|
TupleToolL0Data: {
|
|
40
45
|
description: "L0 trigger data",
|
|
41
|
-
documentation: "",
|
|
46
|
+
documentation: "No documentation available.",
|
|
47
|
+
summary: "TupleToolL0Data summary",
|
|
42
48
|
tags: [],
|
|
43
49
|
interface: [{ name: "Verbose", type: "bool", cpp_type: "bool", default: false, description: "Verbose output" }],
|
|
44
50
|
},
|
|
@@ -136,7 +142,6 @@ export const mockMetadata = {
|
|
|
136
142
|
decays: {
|
|
137
143
|
"[B+ -> K+ mu+ mu-]cc": mockDecay,
|
|
138
144
|
},
|
|
139
|
-
embedding: {},
|
|
140
145
|
kgdoc: {},
|
|
141
146
|
lokiVariables: {
|
|
142
147
|
applicationInfo: { Analysis: "v25r1", DaVinci: "v45r7", Phys: "v26r2" },
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import { DecayData } from "../models/decayData";
|
|
2
|
-
import {
|
|
2
|
+
import { Metadata } from "../providers/MetadataProvider";
|
|
3
3
|
export declare const LATEX_SELECTED_COLOR = "#0d6efd";
|
|
4
4
|
/**
|
|
5
5
|
* Converts a LoKi decay selector string to LaTeX representation
|
|
6
6
|
*/
|
|
7
|
-
export declare const selectionDescriptorToLatex: (metadata:
|
|
7
|
+
export declare const selectionDescriptorToLatex: (metadata: Metadata, decay: DecayData, selection: string[]) => string;
|
|
8
8
|
/**
|
|
9
9
|
* Converts a single particle token to LaTeX representation.
|
|
10
10
|
* Particle tokens may include a LoKi selection prefix ('^') and/or sub-decay parentheses.
|
|
11
11
|
* The `highlighted` param can be used instead of a '^' prefix when calling directly.
|
|
12
12
|
*/
|
|
13
|
-
export declare const convertParticleToLatex: (metadata:
|
|
13
|
+
export declare const convertParticleToLatex: (metadata: Metadata, particle: string, highlighted?: boolean) => string;
|
package/dist/utils/utils.d.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { InfoYaml, YamlFile } from "../models/yamlFile";
|
|
2
2
|
import { SavedDttConfig } from "../models/dtt";
|
|
3
3
|
import { RowData } from "../models/rowData";
|
|
4
|
-
import {
|
|
5
|
-
export declare function parseProductionFiles(files: File[], metadata:
|
|
4
|
+
import { Metadata } from "../providers/MetadataProvider";
|
|
5
|
+
export declare function parseProductionFiles(files: File[], metadata: Metadata): Promise<string | {
|
|
6
6
|
rows: RowData[];
|
|
7
7
|
emails: string[];
|
|
8
8
|
}>;
|
|
9
|
-
export declare function processProductionFiles(metadata:
|
|
9
|
+
export declare function processProductionFiles(metadata: Metadata, configs: SavedDttConfig[], infoYaml: InfoYaml | null): string | {
|
|
10
10
|
rows: RowData[];
|
|
11
11
|
emails: string[];
|
|
12
12
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lhcb-ntuple-wizard-test",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.3.0",
|
|
4
4
|
"description": "An application to access large-scale open data from LHCb",
|
|
5
5
|
"url": "https://gitlab.cern.ch/lhcb-dpa/wp6-analysis-preservation-and-open-data/lhcb-ntuple-wizard-frontend/issues",
|
|
6
6
|
"private": false,
|
|
@@ -21,6 +21,7 @@
|
|
|
21
21
|
"cytoscape": "3.33.1",
|
|
22
22
|
"cytoscape-dagre": "^2.5.0",
|
|
23
23
|
"email-validator": "2.0.4",
|
|
24
|
+
"fuse.js": "^7.3.0",
|
|
24
25
|
"js-yaml": "4.1.1",
|
|
25
26
|
"jszip": "3.10.1",
|
|
26
27
|
"katex": "^0.16.33",
|