lhcb-ntuple-wizard-test 1.3.3 → 2.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -2
- package/dist/App.d.ts +12 -0
- package/dist/App.js +22 -0
- package/dist/components/ConfigFilesUploadingAlert.d.ts +1 -0
- package/dist/components/ConfigFilesUploadingAlert.js +5 -0
- package/dist/components/DatasetEventTypeBadge.d.ts +5 -0
- package/dist/components/DatasetEventTypeBadge.js +23 -0
- package/dist/components/DatasetInfo.d.ts +5 -0
- package/dist/components/DatasetInfo.js +21 -0
- package/dist/components/DecayLatex.d.ts +7 -0
- package/dist/components/DecayLatex.js +103 -0
- package/dist/components/DecayList.d.ts +8 -0
- package/dist/components/DecayList.js +37 -0
- package/dist/components/DecayListItem.d.ts +11 -0
- package/dist/components/DecayListItem.js +23 -0
- package/dist/components/DecayTagBadge.d.ts +5 -0
- package/dist/components/DecayTagBadge.js +21 -0
- package/dist/components/DecayTreeCard.d.ts +7 -0
- package/dist/components/DecayTreeCard.js +43 -0
- package/dist/components/DecayTreeCardHeader.d.ts +7 -0
- package/dist/components/DecayTreeCardHeader.js +5 -0
- package/dist/components/DecayTreeGraph.d.ts +9 -0
- package/dist/components/DecayTreeGraph.js +89 -0
- package/dist/components/DeleteButton.d.ts +9 -0
- package/dist/components/DeleteButton.js +16 -53
- package/dist/components/DttNameInput.d.ts +9 -0
- package/dist/components/DttNameInput.js +73 -0
- package/dist/components/LineTableRow.d.ts +9 -0
- package/dist/components/LineTableRow.js +123 -0
- package/dist/components/LoadingIndicator.d.ts +6 -0
- package/dist/components/LoadingIndicator.js +5 -0
- package/dist/components/NtupleWizard.d.ts +26 -0
- package/dist/components/NtupleWizard.js +28 -137
- package/dist/components/NumStrippingLinesBadge.d.ts +8 -0
- package/dist/components/NumStrippingLinesBadge.js +10 -0
- package/dist/components/ParticleDropdown.d.ts +8 -0
- package/dist/components/ParticleDropdown.js +33 -0
- package/dist/components/ParticleTagBadge.d.ts +9 -0
- package/dist/components/ParticleTagBadge.js +22 -0
- package/dist/components/ParticleTagFilters.d.ts +6 -0
- package/dist/components/ParticleTagFilters.js +51 -0
- package/dist/components/PolarityBadge.d.ts +5 -0
- package/dist/components/PolarityBadge.js +13 -33
- package/dist/components/StrippingLineBadge.d.ts +7 -0
- package/dist/components/StrippingLineBadge.js +29 -0
- package/dist/components/StrippingLineInfo.d.ts +8 -0
- package/dist/components/StrippingLineInfo.js +17 -0
- package/dist/components/SubmitRequestButton.d.ts +11 -0
- package/dist/components/SubmitRequestButton.js +39 -0
- package/dist/components/TagDropdown.d.ts +12 -0
- package/dist/components/TagDropdown.js +31 -0
- package/dist/components/TupleToolDocsAccordion.d.ts +5 -0
- package/dist/components/TupleToolDocsAccordion.js +14 -0
- package/dist/components/TupleToolDropdown.d.ts +21 -0
- package/dist/components/TupleToolDropdown.js +29 -0
- package/dist/components/TupleToolGroup.d.ts +6 -0
- package/dist/components/TupleToolGroup.js +22 -0
- package/dist/components/TupleToolLabel.d.ts +6 -0
- package/dist/components/TupleToolLabel.js +20 -0
- package/dist/components/TupleToolList.d.ts +7 -0
- package/dist/components/TupleToolList.js +38 -0
- package/dist/components/YearBadge.d.ts +5 -0
- package/dist/components/YearBadge.js +13 -33
- package/dist/components/modals/AddTupleToolModal.d.ts +7 -0
- package/dist/components/modals/AddTupleToolModal.js +32 -0
- package/dist/components/modals/ConfigureTupleToolModal.d.ts +8 -0
- package/dist/components/modals/ConfigureTupleToolModal.js +43 -0
- package/dist/components/modals/ReasonForRequestModal.d.ts +8 -0
- package/dist/components/modals/ReasonForRequestModal.js +49 -0
- package/dist/components/modals/UploadDttConfigModal.d.ts +7 -0
- package/dist/components/modals/UploadDttConfigModal.js +35 -0
- package/dist/components/modals/UploadProdConfigModal.d.ts +5 -0
- package/dist/components/modals/UploadProdConfigModal.js +27 -0
- package/dist/components/tupleToolParams/BoolParamInput.d.ts +16 -0
- package/dist/components/tupleToolParams/BoolParamInput.js +15 -0
- package/dist/components/tupleToolParams/DictParamInput.d.ts +14 -0
- package/dist/components/tupleToolParams/DictParamInput.js +31 -0
- package/dist/components/tupleToolParams/ListParamInput.d.ts +14 -0
- package/dist/components/tupleToolParams/ListParamInput.js +46 -0
- package/dist/components/tupleToolParams/NumParamInput.d.ts +18 -0
- package/dist/components/tupleToolParams/NumParamInput.js +25 -0
- package/dist/components/tupleToolParams/StrParamInput.d.ts +19 -0
- package/dist/components/tupleToolParams/StrParamInput.js +22 -0
- package/dist/config.d.ts +78 -0
- package/dist/config.js +72 -0
- package/dist/{style/DecaysList.css → index.d.ts} +2 -6
- package/dist/index.js +2 -11
- package/dist/models/bkPath.d.ts +11 -0
- package/dist/models/bkPath.js +40 -0
- package/dist/models/blobFile.d.ts +12 -0
- package/dist/models/blobFile.js +1 -0
- package/dist/models/decayData.d.ts +15 -0
- package/dist/models/decayData.js +1 -0
- package/dist/models/dropdownOption.d.ts +5 -0
- package/dist/models/dropdownOption.js +1 -0
- package/dist/models/dtt.d.ts +108 -0
- package/dist/models/dtt.js +149 -0
- package/dist/models/jobConfig.d.ts +7 -0
- package/dist/models/jobConfig.js +1 -0
- package/dist/models/particle.d.ts +12 -0
- package/dist/models/particle.js +1 -0
- package/dist/models/particleTag.d.ts +4 -0
- package/dist/models/particleTag.js +1 -0
- package/dist/models/rowData.d.ts +15 -0
- package/dist/models/rowData.js +1 -0
- package/dist/models/strippingLine.d.ts +5 -0
- package/dist/models/strippingLine.js +1 -0
- package/dist/models/strippingLineOption.d.ts +6 -0
- package/dist/models/strippingLineOption.js +1 -0
- package/dist/models/tupleTool.d.ts +8 -0
- package/dist/models/tupleTool.js +18 -0
- package/dist/models/tupleTreeGraphData.d.ts +20 -0
- package/dist/models/tupleTreeGraphData.js +1 -0
- package/dist/models/yamlFile.d.ts +11 -0
- package/dist/models/yamlFile.js +78 -0
- package/dist/pages/DecaySearchPage.d.ts +5 -0
- package/dist/pages/DecaySearchPage.js +197 -0
- package/dist/pages/DecayTreeConfigPage.d.ts +5 -0
- package/dist/pages/DecayTreeConfigPage.js +63 -0
- package/dist/pages/LinesTablePage.d.ts +14 -0
- package/dist/pages/LinesTablePage.js +120 -0
- package/dist/providers/DttProvider.d.ts +24 -0
- package/dist/providers/DttProvider.js +77 -0
- package/dist/providers/MetadataProvider.d.ts +87 -0
- package/dist/providers/MetadataProvider.js +50 -0
- package/dist/providers/ProductionConfigProvider.d.ts +14 -0
- package/dist/providers/ProductionConfigProvider.js +76 -0
- package/dist/providers/RequestProvider.d.ts +15 -0
- package/dist/providers/RequestProvider.js +35 -0
- package/dist/providers/RowsProvider.d.ts +14 -0
- package/dist/providers/RowsProvider.js +31 -0
- package/dist/utils/mathjaxUtils.d.ts +12 -0
- package/dist/utils/mathjaxUtils.js +24 -0
- package/dist/utils/utils.d.ts +31 -0
- package/dist/utils/utils.js +80 -0
- package/package.json +43 -21
- package/dist/components/App.js +0 -99
- package/dist/components/ConfigDict.js +0 -103
- package/dist/components/ConfigList.js +0 -94
- package/dist/components/ConfigNode.js +0 -320
- package/dist/components/ConfigValue.js +0 -86
- package/dist/components/Dataset.js +0 -67
- package/dist/components/Decay.js +0 -50
- package/dist/components/DecayItem.js +0 -101
- package/dist/components/DecayTag.js +0 -52
- package/dist/components/DecayTree.js +0 -451
- package/dist/components/DecaysList.js +0 -107
- package/dist/components/DescriptorsSearch.js +0 -352
- package/dist/components/EventTypeBadge.js +0 -45
- package/dist/components/ItemSearch.js +0 -120
- package/dist/components/LinesTable.js +0 -1105
- package/dist/components/ParticleTag.js +0 -54
- package/dist/components/SearchItem.js +0 -99
- package/dist/components/SelectParticle.js +0 -61
- package/dist/components/SelectTag.js +0 -66
- package/dist/components/SelectTool.js +0 -59
- package/dist/components/SelectVariables.js +0 -106
- package/dist/components/StrippingBadge.js +0 -64
- package/dist/components/StrippingLine.js +0 -50
- package/dist/components/TupleTool.js +0 -46
- package/dist/components/VariablesSearch.js +0 -128
- package/dist/config.json +0 -72
- package/dist/contexts/MetadataContext.js +0 -135
- package/dist/lib/BKPath.js +0 -58
- package/dist/lib/DTTConfig.js +0 -178
- package/dist/lib/mathjax.js +0 -35
- package/dist/lib/utils.js +0 -191
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
import { BlobFile } from "../models/blobFile";
|
|
3
|
+
import { RowData } from "../models/rowData";
|
|
4
|
+
import { MetadataContext } from "./MetadataProvider";
|
|
5
|
+
export interface ProductionConfigApi {
|
|
6
|
+
parseProductionFiles(this: void, files: (BlobFile | File)[], metadata: MetadataContext): Promise<{
|
|
7
|
+
rows: RowData[];
|
|
8
|
+
emails: string[];
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
export declare function ProductionConfigProvider({ children }: {
|
|
12
|
+
children: ReactNode;
|
|
13
|
+
}): import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare function useProductionConfig(): ProductionConfigApi;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useCallback, useContext, useMemo } from "react";
|
|
3
|
+
import yaml from "js-yaml";
|
|
4
|
+
import Dtt from "../models/dtt";
|
|
5
|
+
const ProductionConfigContext = createContext(null);
|
|
6
|
+
export function ProductionConfigProvider({ children }) {
|
|
7
|
+
const parseInput = useCallback((decay) => (input) => {
|
|
8
|
+
const [, , stream, , lineName] = input.split("/");
|
|
9
|
+
const line = `Stripping${lineName}`;
|
|
10
|
+
return {
|
|
11
|
+
stream,
|
|
12
|
+
line,
|
|
13
|
+
versions: decay.lines[`${stream}/${line}`],
|
|
14
|
+
};
|
|
15
|
+
}, []);
|
|
16
|
+
const applyInfoYaml = useCallback((config, rows, emails) => {
|
|
17
|
+
const defaults = config.defaults;
|
|
18
|
+
if (defaults?.inform?.[0]) {
|
|
19
|
+
emails.push(defaults.inform[0]);
|
|
20
|
+
}
|
|
21
|
+
rows.forEach((row) => {
|
|
22
|
+
if (!row.dtt?.config.name)
|
|
23
|
+
return;
|
|
24
|
+
const dttName = row.dtt.config.name.split("/")[1];
|
|
25
|
+
Object.entries(config).forEach(([key, jobConfig]) => {
|
|
26
|
+
if (key === "defaults")
|
|
27
|
+
return;
|
|
28
|
+
const job = jobConfig;
|
|
29
|
+
if (!job.options)
|
|
30
|
+
return;
|
|
31
|
+
if (job.options.some((opt) => opt.split(".")[0] === dttName)) {
|
|
32
|
+
row.paths.push(job.input.bk_query);
|
|
33
|
+
}
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
}, []);
|
|
37
|
+
const parseProductionFiles = useCallback(async (files, metadata) => {
|
|
38
|
+
const rows = [];
|
|
39
|
+
const emails = [];
|
|
40
|
+
const sorted = [...files].sort((a, b) => (a.name === "info.yaml" ? 1 : b.name === "info.yaml" ? -1 : 0));
|
|
41
|
+
for (let i = 0; i < sorted.length; i++) {
|
|
42
|
+
const file = sorted[i];
|
|
43
|
+
const blob = file.blob ?? file;
|
|
44
|
+
const text = await blob.text();
|
|
45
|
+
if (file.name === "info.yaml") {
|
|
46
|
+
const config = yaml.load(text);
|
|
47
|
+
applyInfoYaml(config, rows, emails);
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
const config = yaml.load(text);
|
|
51
|
+
const decay = Object.values(metadata.decays).find((d) => d.descriptors.template === config.descriptorTemplate);
|
|
52
|
+
if (!decay || !config.inputs)
|
|
53
|
+
continue;
|
|
54
|
+
rows.push({
|
|
55
|
+
id: i,
|
|
56
|
+
decay,
|
|
57
|
+
lines: config.inputs.map(parseInput(decay)),
|
|
58
|
+
paths: [],
|
|
59
|
+
pathOptions: [],
|
|
60
|
+
dtt: new Dtt(config, {}),
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
return { rows, emails };
|
|
64
|
+
}, [applyInfoYaml, parseInput]);
|
|
65
|
+
const api = useMemo(() => ({
|
|
66
|
+
parseProductionFiles,
|
|
67
|
+
}), [parseProductionFiles]);
|
|
68
|
+
return _jsx(ProductionConfigContext.Provider, { value: api, children: children });
|
|
69
|
+
}
|
|
70
|
+
export function useProductionConfig() {
|
|
71
|
+
const ctx = useContext(ProductionConfigContext);
|
|
72
|
+
if (!ctx) {
|
|
73
|
+
throw new Error("useProductionConfig must be used within ProductionConfigProvider");
|
|
74
|
+
}
|
|
75
|
+
return ctx;
|
|
76
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { ReactNode } from "react";
|
|
2
|
+
interface RequestContextType {
|
|
3
|
+
productionName: string;
|
|
4
|
+
setProductionName: (name: string) => void;
|
|
5
|
+
contactEmails: string[];
|
|
6
|
+
setContactEmails: (emails: string[]) => void;
|
|
7
|
+
reasonForRequest: string;
|
|
8
|
+
setReasonForRequest: (reason: string) => void;
|
|
9
|
+
}
|
|
10
|
+
interface RequestProviderProps {
|
|
11
|
+
children: ReactNode;
|
|
12
|
+
}
|
|
13
|
+
export declare const RequestProvider: ({ children }: RequestProviderProps) => import("react/jsx-runtime").JSX.Element;
|
|
14
|
+
export declare const useRequest: () => RequestContextType;
|
|
15
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useState } from "react";
|
|
3
|
+
const RequestContext = createContext(null);
|
|
4
|
+
export const RequestProvider = ({ children }) => {
|
|
5
|
+
const [productionName, setProductionName] = useState(localStorage.getItem("name") || "");
|
|
6
|
+
const [contactEmails, setContactEmails] = useState((localStorage.getItem("email") || "").split(/,/).filter((s) => s));
|
|
7
|
+
const [reasonForRequest, setReasonForRequest] = useState(localStorage.getItem("reasonForRequest") || "");
|
|
8
|
+
const updateProductionName = (newProductionName) => {
|
|
9
|
+
setProductionName(newProductionName);
|
|
10
|
+
localStorage.setItem("name", newProductionName);
|
|
11
|
+
};
|
|
12
|
+
const updateContactEmails = (newContactEmails) => {
|
|
13
|
+
setContactEmails(newContactEmails);
|
|
14
|
+
localStorage.setItem("email", newContactEmails.join(","));
|
|
15
|
+
};
|
|
16
|
+
const updateReasonForRequest = (newReasonForRequest) => {
|
|
17
|
+
setReasonForRequest(newReasonForRequest);
|
|
18
|
+
localStorage.setItem("reasonForRequest", newReasonForRequest);
|
|
19
|
+
};
|
|
20
|
+
return (_jsx(RequestContext.Provider, { value: {
|
|
21
|
+
productionName,
|
|
22
|
+
setProductionName: updateProductionName,
|
|
23
|
+
contactEmails,
|
|
24
|
+
setContactEmails: updateContactEmails,
|
|
25
|
+
reasonForRequest,
|
|
26
|
+
setReasonForRequest: updateReasonForRequest,
|
|
27
|
+
}, children: children }));
|
|
28
|
+
};
|
|
29
|
+
export const useRequest = () => {
|
|
30
|
+
const ctx = useContext(RequestContext);
|
|
31
|
+
if (!ctx) {
|
|
32
|
+
throw new Error("useRequest must be used within a RequestProvider");
|
|
33
|
+
}
|
|
34
|
+
return ctx;
|
|
35
|
+
};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { Dispatch, ReactNode, SetStateAction } from "react";
|
|
2
|
+
import { RowData } from "../models/rowData.js";
|
|
3
|
+
import { YamlFile } from "../models/yamlFile";
|
|
4
|
+
interface RowsContextType {
|
|
5
|
+
rows: RowData[];
|
|
6
|
+
setRows: Dispatch<SetStateAction<RowData[]>>;
|
|
7
|
+
generateAllFiles: () => YamlFile[];
|
|
8
|
+
}
|
|
9
|
+
interface Props {
|
|
10
|
+
children: ReactNode;
|
|
11
|
+
}
|
|
12
|
+
export declare const RowsProvider: ({ children }: Props) => import("react/jsx-runtime").JSX.Element;
|
|
13
|
+
export declare const useRows: () => RowsContextType;
|
|
14
|
+
export {};
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { createContext, useContext, useEffect, useState } from "react";
|
|
3
|
+
import Dtt from "../models/dtt";
|
|
4
|
+
import { useMetadata } from "./MetadataProvider";
|
|
5
|
+
import { YamlFile } from "../models/yamlFile";
|
|
6
|
+
const RowsContext = createContext(undefined);
|
|
7
|
+
export const RowsProvider = ({ children }) => {
|
|
8
|
+
const metadata = useMetadata();
|
|
9
|
+
const storedRows = JSON.parse(localStorage.getItem("rows") || "[]");
|
|
10
|
+
const [rows, setRows] = useState(storedRows.map((row) => ({ ...row, dtt: row.dtt?.config ? new Dtt(row.dtt.config, {}) : null })));
|
|
11
|
+
useEffect(() => {
|
|
12
|
+
localStorage.setItem("rows", JSON.stringify(rows));
|
|
13
|
+
}, [rows]);
|
|
14
|
+
const generateAllFiles = () => {
|
|
15
|
+
if (!metadata) {
|
|
16
|
+
return [];
|
|
17
|
+
}
|
|
18
|
+
return [
|
|
19
|
+
...rows.filter((row) => row.dtt).map((row) => YamlFile.fromDtt(row.dtt)),
|
|
20
|
+
YamlFile.createInfoYaml(rows, metadata),
|
|
21
|
+
];
|
|
22
|
+
};
|
|
23
|
+
return _jsx(RowsContext.Provider, { value: { rows, setRows, generateAllFiles }, children: children });
|
|
24
|
+
};
|
|
25
|
+
export const useRows = () => {
|
|
26
|
+
const context = useContext(RowsContext);
|
|
27
|
+
if (!context) {
|
|
28
|
+
throw new Error("useRows must be used within a RowsProvider");
|
|
29
|
+
}
|
|
30
|
+
return context;
|
|
31
|
+
};
|
|
@@ -0,0 +1,12 @@
|
|
|
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
|
+
import "@mathjax/src/cjs/input/tex/ams/AmsConfiguration.js";
|
|
12
|
+
export declare function tex2svg(inputTeX: string): SVGElement;
|
|
@@ -0,0 +1,24 @@
|
|
|
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
|
+
import { mathjax } from "@mathjax/src/cjs/mathjax.js";
|
|
12
|
+
import { TeX } from "@mathjax/src/cjs/input/tex.js";
|
|
13
|
+
import { SVG } from "@mathjax/src/cjs/output/svg.js";
|
|
14
|
+
import { browserAdaptor } from "@mathjax/src/cjs/adaptors/browserAdaptor.js";
|
|
15
|
+
import { RegisterHTMLHandler } from "@mathjax/src/cjs/handlers/html.js";
|
|
16
|
+
import "@mathjax/src/cjs/input/tex/ams/AmsConfiguration.js";
|
|
17
|
+
RegisterHTMLHandler(browserAdaptor());
|
|
18
|
+
const mathDoc = mathjax.document("", {
|
|
19
|
+
InputJax: new TeX({ packages: ["base", "ams"] }),
|
|
20
|
+
OutputJax: new SVG({ fontCache: "none" }),
|
|
21
|
+
});
|
|
22
|
+
export function tex2svg(inputTeX) {
|
|
23
|
+
return mathDoc.convert(inputTeX);
|
|
24
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { YamlFile } from "../models/yamlFile";
|
|
2
|
+
/**
|
|
3
|
+
* Sanitizes a user-provided filename to prevent path traversal (Zip Slip)
|
|
4
|
+
* and unsafe filesystem characters.
|
|
5
|
+
*
|
|
6
|
+
* Guarantees the result is a single filename, not a path.
|
|
7
|
+
*
|
|
8
|
+
* - Strips directory separators (/ and \)
|
|
9
|
+
* - Removes path traversal sequences (..)
|
|
10
|
+
* - Removes leading dots
|
|
11
|
+
* - Allowlists safe characters
|
|
12
|
+
*
|
|
13
|
+
* @param input - Potentially unsafe filename
|
|
14
|
+
* @param fallback - Filename to use if sanitization results in an empty string
|
|
15
|
+
* @returns A safe filename
|
|
16
|
+
*/
|
|
17
|
+
export declare function sanitizeFilename(input: string, fallback?: string): string;
|
|
18
|
+
/**
|
|
19
|
+
* Downloads a text string with the given filename.
|
|
20
|
+
*
|
|
21
|
+
* @param yamlFile - The YamlFile object to download
|
|
22
|
+
* @param type - The MIME type of the file (default: text/plain)
|
|
23
|
+
*/
|
|
24
|
+
export declare function downloadText(yamlFile: YamlFile, type?: string): void;
|
|
25
|
+
/**
|
|
26
|
+
* Downloads a ZIP archive containing multiple text files.
|
|
27
|
+
*
|
|
28
|
+
* @param files - An array of [filename, content] pairs
|
|
29
|
+
* @param name - The desired archive filename
|
|
30
|
+
*/
|
|
31
|
+
export declare function downloadZip(files: YamlFile[], name?: string): Promise<void>;
|
|
@@ -0,0 +1,80 @@
|
|
|
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
|
+
import JsZip from "jszip";
|
|
12
|
+
/**
|
|
13
|
+
* Sanitizes a user-provided filename to prevent path traversal (Zip Slip)
|
|
14
|
+
* and unsafe filesystem characters.
|
|
15
|
+
*
|
|
16
|
+
* Guarantees the result is a single filename, not a path.
|
|
17
|
+
*
|
|
18
|
+
* - Strips directory separators (/ and \)
|
|
19
|
+
* - Removes path traversal sequences (..)
|
|
20
|
+
* - Removes leading dots
|
|
21
|
+
* - Allowlists safe characters
|
|
22
|
+
*
|
|
23
|
+
* @param input - Potentially unsafe filename
|
|
24
|
+
* @param fallback - Filename to use if sanitization results in an empty string
|
|
25
|
+
* @returns A safe filename
|
|
26
|
+
*/
|
|
27
|
+
export function sanitizeFilename(input, fallback = "file") {
|
|
28
|
+
// Get the last path segment
|
|
29
|
+
const basename = input.split(/[/\\]/).pop() ?? "";
|
|
30
|
+
const noTraversal = basename.replace(/\.\./g, "");
|
|
31
|
+
const noLeadingDots = noTraversal.replace(/^\.+/, "");
|
|
32
|
+
const sanitized = noLeadingDots.replace(/[^a-zA-Z0-9._-]/g, "");
|
|
33
|
+
return sanitized.length > 0 ? sanitized : fallback;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Downloads a Blob object with the given filename.
|
|
37
|
+
*
|
|
38
|
+
* @param blob - The Blob object to download
|
|
39
|
+
* @param name - The desired filename
|
|
40
|
+
*/
|
|
41
|
+
function downloadBlob(blob, name) {
|
|
42
|
+
const safeName = sanitizeFilename(name);
|
|
43
|
+
const blobUrl = URL.createObjectURL(blob);
|
|
44
|
+
const link = document.createElement("a");
|
|
45
|
+
link.href = blobUrl;
|
|
46
|
+
link.download = safeName;
|
|
47
|
+
document.body.appendChild(link);
|
|
48
|
+
link.dispatchEvent(new MouseEvent("click", {
|
|
49
|
+
bubbles: true,
|
|
50
|
+
cancelable: true,
|
|
51
|
+
view: window,
|
|
52
|
+
}));
|
|
53
|
+
document.body.removeChild(link);
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Downloads a text string with the given filename.
|
|
57
|
+
*
|
|
58
|
+
* @param yamlFile - The YamlFile object to download
|
|
59
|
+
* @param type - The MIME type of the file (default: text/plain)
|
|
60
|
+
*/
|
|
61
|
+
export function downloadText(yamlFile, type = "text/plain") {
|
|
62
|
+
const blob = new Blob([yamlFile.content], { type: type });
|
|
63
|
+
downloadBlob(blob, yamlFile.name);
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Downloads a ZIP archive containing multiple text files.
|
|
67
|
+
*
|
|
68
|
+
* @param files - An array of [filename, content] pairs
|
|
69
|
+
* @param name - The desired archive filename
|
|
70
|
+
*/
|
|
71
|
+
export async function downloadZip(files, name = "archive.zip") {
|
|
72
|
+
const zip = JsZip();
|
|
73
|
+
const safeZipName = sanitizeFilename(name, "archive.zip");
|
|
74
|
+
for (const file of files) {
|
|
75
|
+
const blob = new Blob([file.content], { type: "text/plain" });
|
|
76
|
+
zip.file(file.name, blob);
|
|
77
|
+
}
|
|
78
|
+
const blob = await zip.generateAsync({ type: "blob" });
|
|
79
|
+
downloadBlob(blob, safeZipName);
|
|
80
|
+
}
|
package/package.json
CHANGED
|
@@ -1,50 +1,50 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lhcb-ntuple-wizard-test",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.0.1",
|
|
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,
|
|
7
7
|
"main": "dist/index.js",
|
|
8
8
|
"module": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"type": "module",
|
|
9
11
|
"files": [
|
|
10
12
|
"dist",
|
|
11
13
|
"README.md"
|
|
12
14
|
],
|
|
15
|
+
"exports": {
|
|
16
|
+
".": "./dist/index.js"
|
|
17
|
+
},
|
|
13
18
|
"dependencies": {
|
|
14
|
-
"@
|
|
19
|
+
"@mathjax/src": "4.1.0",
|
|
20
|
+
"better-react-mathjax": "2.3.0",
|
|
15
21
|
"bootstrap": "5.3.8",
|
|
22
|
+
"dompurify": "^3.3.1",
|
|
16
23
|
"email-validator": "2.0.4",
|
|
17
24
|
"js-yaml": "4.1.1",
|
|
18
25
|
"jszip": "3.10.1",
|
|
19
|
-
"lodash": "4.17.
|
|
26
|
+
"lodash": "^4.17.23",
|
|
20
27
|
"lodash.memoize": "4.1.2",
|
|
21
|
-
"mathjax-
|
|
28
|
+
"mathjax-full": "3.2.2",
|
|
22
29
|
"pako": "2.1.0",
|
|
23
|
-
"react": "18.3.1",
|
|
24
30
|
"react-bootstrap": "2.10.10",
|
|
25
31
|
"react-bootstrap-icons": "1.11.6",
|
|
26
|
-
"react-dom": "18.3.1",
|
|
27
32
|
"react-graph-vis": "1.0.7",
|
|
28
|
-
"react-infinite-scroll-component": "6.1.
|
|
29
|
-
"react-
|
|
30
|
-
|
|
31
|
-
|
|
33
|
+
"react-infinite-scroll-component": "^6.1.1",
|
|
34
|
+
"react-select": "5.10.2"
|
|
35
|
+
},
|
|
36
|
+
"peerDependencies": {
|
|
37
|
+
"react": ">=19",
|
|
38
|
+
"react-dom": ">=19",
|
|
39
|
+
"react-router-dom": ">=7.12.0"
|
|
32
40
|
},
|
|
33
41
|
"overrides": {
|
|
34
42
|
"autoprefixer": "10.4.5"
|
|
35
43
|
},
|
|
36
44
|
"scripts": {
|
|
37
45
|
"start": "vite --open",
|
|
38
|
-
"build": "
|
|
39
|
-
"
|
|
40
|
-
"transpile": "babel src -d dist --copy-files",
|
|
41
|
-
"prepublishOnly": "npm run transpile"
|
|
42
|
-
},
|
|
43
|
-
"eslintConfig": {
|
|
44
|
-
"extends": [
|
|
45
|
-
"react-app",
|
|
46
|
-
"react-app/jest"
|
|
47
|
-
]
|
|
46
|
+
"build": "tsc",
|
|
47
|
+
"prepublishOnly": "npm run build"
|
|
48
48
|
},
|
|
49
49
|
"browserslist": {
|
|
50
50
|
"production": [
|
|
@@ -64,6 +64,28 @@
|
|
|
64
64
|
"devDependencies": {
|
|
65
65
|
"@babel/cli": "7.28.3",
|
|
66
66
|
"@babel/preset-env": "7.28.3",
|
|
67
|
-
"@babel/preset-react": "7.27.1"
|
|
67
|
+
"@babel/preset-react": "7.27.1",
|
|
68
|
+
"@eslint/js": "^9.17.0",
|
|
69
|
+
"@types/jest": "^30.0.0",
|
|
70
|
+
"@types/js-yaml": "^4.0.9",
|
|
71
|
+
"@types/lodash": "^4.17.21",
|
|
72
|
+
"@types/lodash.memoize": "^4.1.9",
|
|
73
|
+
"@types/pako": "^2.0.4",
|
|
74
|
+
"@types/react": "^19.2.7",
|
|
75
|
+
"@types/react-dom": "^19.2.3",
|
|
76
|
+
"@types/react-router-dom": "^5.3.3",
|
|
77
|
+
"@types/vis": "^4.21.27",
|
|
78
|
+
"@typescript-eslint/eslint-plugin": "^8.51.0",
|
|
79
|
+
"@typescript-eslint/parser": "^8.51.0",
|
|
80
|
+
"@vitejs/plugin-react": "5.1.2",
|
|
81
|
+
"eslint": "^9.17.0",
|
|
82
|
+
"eslint-plugin-react": "^7.37.5",
|
|
83
|
+
"globals": "^16.0.0",
|
|
84
|
+
"react": "^19.2.3",
|
|
85
|
+
"react-dom": "^19.2.3",
|
|
86
|
+
"react-router-dom": "^7.12.0",
|
|
87
|
+
"typescript": "^5.9.3",
|
|
88
|
+
"vite": "7.3.0",
|
|
89
|
+
"vite-tsconfig-paths": "^6.0.3"
|
|
68
90
|
}
|
|
69
91
|
}
|
package/dist/components/App.js
DELETED
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
require("bootstrap/dist/css/bootstrap.css");
|
|
8
|
-
var _react = _interopRequireDefault(require("react"));
|
|
9
|
-
var _reactBootstrap = require("react-bootstrap");
|
|
10
|
-
var _reactBootstrapIcons = require("react-bootstrap-icons");
|
|
11
|
-
var _config = _interopRequireDefault(require("../config"));
|
|
12
|
-
var _NtupleWizard = _interopRequireDefault(require("./NtupleWizard"));
|
|
13
|
-
var _jsxRuntime = require("react/jsx-runtime");
|
|
14
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
15
|
-
/*****************************************************************************\
|
|
16
|
-
* (c) Copyright 2021 CERN for the benefit of the LHCb Collaboration *
|
|
17
|
-
* *
|
|
18
|
-
* This software is distributed under the terms of the GNU General Public *
|
|
19
|
-
* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". *
|
|
20
|
-
* *
|
|
21
|
-
* In applying this licence, CERN does not waive the privileges and immunities *
|
|
22
|
-
* granted to it by virtue of its status as an Intergovernmental Organization *
|
|
23
|
-
* or submit itself to any jurisdiction. *
|
|
24
|
-
\*****************************************************************************/
|
|
25
|
-
|
|
26
|
-
class App extends _react.default.Component {
|
|
27
|
-
render() {
|
|
28
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_jsxRuntime.Fragment, {
|
|
29
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Navbar, {
|
|
30
|
-
collapseOnSelect: true,
|
|
31
|
-
expand: "lg",
|
|
32
|
-
bg: "dark",
|
|
33
|
-
variant: "dark",
|
|
34
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.Container, {
|
|
35
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.Navbar.Brand, {
|
|
36
|
-
href: "/",
|
|
37
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("img", {
|
|
38
|
-
src: "/logo.svg",
|
|
39
|
-
height: "30",
|
|
40
|
-
className: "d-inline-block align-top",
|
|
41
|
-
alt: "LHCb logo"
|
|
42
|
-
}), " ", "LHCb NTuple Wizard"]
|
|
43
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Navbar.Toggle, {
|
|
44
|
-
"aria-controls": "responsive-navbar-nav"
|
|
45
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Navbar.Collapse, {
|
|
46
|
-
className: "justify-content-end",
|
|
47
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.Nav, {
|
|
48
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.NavDropdown, {
|
|
49
|
-
title: "About",
|
|
50
|
-
id: "about-dropdown",
|
|
51
|
-
menuVariant: "dark",
|
|
52
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.NavDropdown.Item, {
|
|
53
|
-
href: "https://lhcb-dpa.web.cern.ch/lhcb-dpa/wp6/ntupling-wizard.html",
|
|
54
|
-
target: "_blank",
|
|
55
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrapIcons.House, {}), " Project home"]
|
|
56
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.NavDropdown.Item, {
|
|
57
|
-
href: "https://gitlab.cern.ch/lhcb-dpa/wp6-analysis-preservation-and-open-data/lhcb-ntuple-wizard-frontend",
|
|
58
|
-
target: "_blank",
|
|
59
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrapIcons.CodeSlash, {}), " Source code"]
|
|
60
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.NavDropdown.Item, {
|
|
61
|
-
href: _config.default.metadata_baseurl,
|
|
62
|
-
target: "_blank",
|
|
63
|
-
children: [/*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrapIcons.Archive, {}), " Metadata files"]
|
|
64
|
-
})]
|
|
65
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Nav.Link, {
|
|
66
|
-
href: "https://opendata.cern.ch/",
|
|
67
|
-
target: "_blank",
|
|
68
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)("img", {
|
|
69
|
-
src: "/open_data_portal.png",
|
|
70
|
-
height: "30",
|
|
71
|
-
alt: "CERN Open Data Portal"
|
|
72
|
-
})
|
|
73
|
-
})]
|
|
74
|
-
})
|
|
75
|
-
})]
|
|
76
|
-
})
|
|
77
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Container, {
|
|
78
|
-
className: "mt-4",
|
|
79
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_NtupleWizard.default, {
|
|
80
|
-
basePath: "/",
|
|
81
|
-
decaysPath: "/decays",
|
|
82
|
-
variablesPath: "/variables",
|
|
83
|
-
submitLocation: "" // Leave empty to hide the submit button -> overrides hideDownloadButtons to false
|
|
84
|
-
,
|
|
85
|
-
contactEmail: "" // Leave empty to let the user fill in their email address
|
|
86
|
-
,
|
|
87
|
-
hideDownloadButtons: false // Can be overridden by submitLocation
|
|
88
|
-
,
|
|
89
|
-
hideUploadButtons: false,
|
|
90
|
-
requestReasonMessage: "Please provide a reason for your request.",
|
|
91
|
-
requestSubmittedMessage: /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {
|
|
92
|
-
children: "Your request has been submitted."
|
|
93
|
-
})
|
|
94
|
-
})
|
|
95
|
-
})]
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
var _default = exports.default = App;
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
var _react = _interopRequireDefault(require("react"));
|
|
8
|
-
var _propTypes = _interopRequireDefault(require("prop-types"));
|
|
9
|
-
var _reactBootstrap = require("react-bootstrap");
|
|
10
|
-
var _jsxRuntime = require("react/jsx-runtime");
|
|
11
|
-
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
12
|
-
function _defineProperty(e, r, t) { return (r = _toPropertyKey(r)) in e ? Object.defineProperty(e, r, { value: t, enumerable: !0, configurable: !0, writable: !0 }) : e[r] = t, e; }
|
|
13
|
-
function _toPropertyKey(t) { var i = _toPrimitive(t, "string"); return "symbol" == typeof i ? i : i + ""; }
|
|
14
|
-
function _toPrimitive(t, r) { if ("object" != typeof t || !t) return t; var e = t[Symbol.toPrimitive]; if (void 0 !== e) { var i = e.call(t, r || "default"); if ("object" != typeof i) return i; throw new TypeError("@@toPrimitive must return a primitive value."); } return ("string" === r ? String : Number)(t); } /*****************************************************************************\
|
|
15
|
-
* (c) Copyright 2021 CERN for the benefit of the LHCb Collaboration *
|
|
16
|
-
* *
|
|
17
|
-
* This software is distributed under the terms of the GNU General Public *
|
|
18
|
-
* Licence version 3 (GPL Version 3), copied verbatim in the file "COPYING". *
|
|
19
|
-
* *
|
|
20
|
-
* In applying this licence, CERN does not waive the privileges and immunities *
|
|
21
|
-
* granted to it by virtue of its status as an Intergovernmental Organization *
|
|
22
|
-
* or submit itself to any jurisdiction. *
|
|
23
|
-
\*****************************************************************************/ //import ConfigValue from "./ConfigValue";
|
|
24
|
-
/*
|
|
25
|
-
* {str:str} -> <ConfigDict /> multiple rows of <input type="text" /> <input type="text" />
|
|
26
|
-
* {str:text} -> <ConfigDict /> multiple rows of <input type="text" /> <textarea />
|
|
27
|
-
*/ /*
|
|
28
|
-
* Keys have to be unique and not empty...
|
|
29
|
-
* this may cause problems if the callback is executed on every keystroke
|
|
30
|
-
*/
|
|
31
|
-
class ConfigDict extends _react.default.Component {
|
|
32
|
-
constructor() {
|
|
33
|
-
super(...arguments);
|
|
34
|
-
_defineProperty(this, "state", {
|
|
35
|
-
value: JSON.stringify(this.props.value, null, 2),
|
|
36
|
-
// Object.keys(this.props.value).map((key) => [key, this.props.value[key].valueOf()]),
|
|
37
|
-
edit: false,
|
|
38
|
-
error: ""
|
|
39
|
-
});
|
|
40
|
-
_defineProperty(this, "toggleEdit", () => {
|
|
41
|
-
this.setState({
|
|
42
|
-
edit: !this.state.edit
|
|
43
|
-
});
|
|
44
|
-
});
|
|
45
|
-
_defineProperty(this, "handleSave", () => {
|
|
46
|
-
try {
|
|
47
|
-
const value = JSON.parse(this.state.value);
|
|
48
|
-
this.props.callback(value);
|
|
49
|
-
this.setState({
|
|
50
|
-
error: ""
|
|
51
|
-
});
|
|
52
|
-
this.setState({
|
|
53
|
-
edit: false
|
|
54
|
-
});
|
|
55
|
-
} catch (e) {
|
|
56
|
-
this.setState({
|
|
57
|
-
error: "".concat(e)
|
|
58
|
-
});
|
|
59
|
-
}
|
|
60
|
-
});
|
|
61
|
-
_defineProperty(this, "handleUpdate", event => {
|
|
62
|
-
const {
|
|
63
|
-
value
|
|
64
|
-
} = event.target;
|
|
65
|
-
this.setState({
|
|
66
|
-
value: value
|
|
67
|
-
});
|
|
68
|
-
});
|
|
69
|
-
}
|
|
70
|
-
render() {
|
|
71
|
-
const errorMessage = this.state.error ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Alert, {
|
|
72
|
-
variant: "danger",
|
|
73
|
-
children: this.state.error
|
|
74
|
-
}) : /*#__PURE__*/(0, _jsxRuntime.jsx)(_jsxRuntime.Fragment, {});
|
|
75
|
-
const buttonLabel = this.state.edit ? "Cancel" : "Edit";
|
|
76
|
-
const saveButton = this.state.edit ? /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Button, {
|
|
77
|
-
variant: "primary",
|
|
78
|
-
onClick: this.handleSave,
|
|
79
|
-
children: "Save"
|
|
80
|
-
}) : "";
|
|
81
|
-
return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Card, {
|
|
82
|
-
children: /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.Card.Body, {
|
|
83
|
-
children: [errorMessage, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.FormControl, {
|
|
84
|
-
as: "textarea",
|
|
85
|
-
value: this.state.value,
|
|
86
|
-
onChange: this.handleUpdate,
|
|
87
|
-
disabled: !this.state.edit
|
|
88
|
-
}), /*#__PURE__*/(0, _jsxRuntime.jsxs)(_reactBootstrap.ButtonGroup, {
|
|
89
|
-
children: [saveButton, /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactBootstrap.Button, {
|
|
90
|
-
variant: "outline-secondary",
|
|
91
|
-
onClick: this.toggleEdit,
|
|
92
|
-
children: buttonLabel
|
|
93
|
-
})]
|
|
94
|
-
})]
|
|
95
|
-
})
|
|
96
|
-
});
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
ConfigDict.propTypes = {
|
|
100
|
-
value: _propTypes.default.oneOfType([_propTypes.default.objectOf(_propTypes.default.string), _propTypes.default.objectOf(_propTypes.default.arrayOf(_propTypes.default.string))]),
|
|
101
|
-
callback: _propTypes.default.func
|
|
102
|
-
};
|
|
103
|
-
var _default = exports.default = ConfigDict;
|