From cd2c2525ebd1902c7fa9f62c88dae9c000a053bb Mon Sep 17 00:00:00 2001 From: Frank Sauerburger <frank@sauerburger.com> Date: Wed, 20 Jan 2021 21:29:46 +0100 Subject: [PATCH] Implement Fork feature --- uhepp-js/package-lock.json | 5 + uhepp-js/package.json | 1 + uhepp-js/src/components/UheppHistUI.jsx | 149 ++++++++++++++++-- .../templates/uhepp_vault/plot_detail.html | 6 +- 4 files changed, 145 insertions(+), 16 deletions(-) diff --git a/uhepp-js/package-lock.json b/uhepp-js/package-lock.json index a542993..916d665 100644 --- a/uhepp-js/package-lock.json +++ b/uhepp-js/package-lock.json @@ -5712,6 +5712,11 @@ "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", "dev": true }, + "js-cookie": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz", + "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==" + }, "js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", diff --git a/uhepp-js/package.json b/uhepp-js/package.json index 21a10c7..2d0add5 100644 --- a/uhepp-js/package.json +++ b/uhepp-js/package.json @@ -25,6 +25,7 @@ "core-js": "^3.6.5", "html-webpack-plugin": "^3.2.0", "jquery": "^3.4.1", + "js-cookie": "^2.2.1", "mathjax-react": "^1.0.6", "mocha": "^8.2.1", "popper.js": "^1.15.0", diff --git a/uhepp-js/src/components/UheppHistUI.jsx b/uhepp-js/src/components/UheppHistUI.jsx index 3082527..b9ca21d 100644 --- a/uhepp-js/src/components/UheppHistUI.jsx +++ b/uhepp-js/src/components/UheppHistUI.jsx @@ -1,6 +1,7 @@ -import React, { useState } from "react"; +import React, { useState, useEffect } from "react"; import UheppHist from "./UheppHist.jsx"; import { objfilter, objmap } from "../helpers/uhepp.js"; +import Cookies from 'js-cookie' const noVariationUsed = (uhepp) => { const main_names = uhepp.stacks.map(stack => stack.content.map(item => item.yields)).flat() @@ -62,6 +63,10 @@ const makeVariationRatio = (uhepp, stackId, variation, updown) => { ).flat() }] } +const useFetch = (url) => { + + return data; +}; const UheppHistUIWithSyst = ({ width, @@ -94,6 +99,7 @@ const UheppHistUIWithSyst = ({ variations, origStacks, origRatio, + origYields, envName, envId, }) => { @@ -101,6 +107,27 @@ const UheppHistUIWithSyst = ({ const [include_overflow, setOverflow] = useState(!!uhepp.bins.include_overflow) const [rebin, setRebin] = useState(uhepp.bins.rebin || uhepp.bins.edges) const [density_width, setDensity] = useState(uhepp.bins.density_width) + const [collections, setCollections] = useState(null); + const [destination, setDestination] = useState("") + const [saveStatus, setSaveStatus] = useState(null) + + const url = "/api/collections" + useEffect(() => { + async function fetchData() { + const response = await fetch(url); + const json = await response.json(); + setCollections(json) + if (json.length > 0) { + setDestination(json[0].url) + } + } + fetchData(); + }, [url]); + + const handleDestination = (e) => { + setDestination(e.target.value) + setSaveStatus(null) + } const reset = () => { setUnderflow(!!uhepp.bins.include_underflow) @@ -137,6 +164,39 @@ const UheppHistUIWithSyst = ({ density_width, })}) + const save = () => { + const csrftoken = Cookies.get('csrftoken'); + + async function asyncStringify(str) { + return JSON.stringify(str); + } + + const data = { + "collection": destination, + "uhepp": Object.assign({}, uhepp_derived, {yields: origYields}) + } + + async function fetchData() { + const response = await fetch("/api/plots/", { + method: "POST", + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + 'X-CSRFToken': csrftoken + }, + body: await asyncStringify(data) + }) + if (response.ok) { + const json = await response.json() + window.location = "/p/" + json.uuid + } else { + setSaveStatus('error') + } + } + setSaveStatus('loading') + fetchData() + } + return <> <div>{ Object.entries(uhepp.metadata.tags).map(([key, value], i) => value == null ? @@ -150,22 +210,46 @@ const UheppHistUIWithSyst = ({ <ul className="nav nav-tabs" id="view-options" role="tablist"> <li className="nav-item"> - <a className="nav-link active" id="info-tab" data-toggle="tab" href="#info" role="tab" aria-controls="info" aria-selected="true">Info</a> + <a className="nav-link active" id="info-tab" data-toggle="tab" href="#info" role="tab" aria-controls="info" aria-selected="true"> + <i className="fas fa-info-circle mr-1"></i> + Info + </a> </li> <li className="nav-item"> - <a className="nav-link" id="binning-tab" data-toggle="tab" href="#binning" role="tab" aria-controls="binning" aria-selected="true">Binning</a> + <a className="nav-link" id="binning-tab" data-toggle="tab" href="#binning" role="tab" aria-controls="binning" aria-selected="true"> + <i className="fas fa-chart-bar mr-1"></i> + Binning + </a> </li> <li className="nav-item"> - <a className="nav-link" id="stacks-tab" data-toggle="tab" href="#stacks" role="tab" aria-controls="stacks" aria-selected="false">Stacks</a> + <a className="nav-link" id="stacks-tab" data-toggle="tab" href="#stacks" role="tab" aria-controls="stacks" aria-selected="false"> + <i className="fas fa-layer-group mr-1"></i> + Stacks + </a> </li> <li className="nav-item"> - <a className="nav-link" id="ratio-tab" data-toggle="tab" href="#ratio" role="tab" aria-controls="ratio" aria-selected="false">Ratio</a> + <a className="nav-link" id="ratio-tab" data-toggle="tab" href="#ratio" role="tab" aria-controls="ratio" aria-selected="false"> + <i className="fas fa-percentage mr-1"></i> + Ratio + </a> </li> <li className="nav-item"> - <a className="nav-link" id="variations-tab" data-toggle="tab" href="#variations" role="tab" aria-controls="variations" aria-selected="false">Variations</a> + <a className="nav-link" id="variations-tab" data-toggle="tab" href="#variations" role="tab" aria-controls="variations" aria-selected="false"> + <i className="fas fa-envelope mr-1"></i> + Variations + </a> </li> <li className="nav-item"> - <a className="nav-link" id="reset-tab" data-toggle="tab" href="#reset" role="tab" aria-controls="reset" aria-selected="false">Reset</a> + <a className="nav-link" id="reset-tab" data-toggle="tab" href="#reset" role="tab" aria-controls="reset" aria-selected="false"> + <i className="fas fa-trash-restore mr-1"></i> + Restore + </a> + </li> + <li className="nav-item"> + <a className="nav-link" id="save-tab" data-toggle="tab" href="#save" role="tab" aria-controls="save" aria-selected="false"> + <i className="fas fa-code-branch mr-1"></i> + Fork/Save + </a> </li> </ul> @@ -419,7 +503,7 @@ const UheppHistUIWithSyst = ({ { isVariationReady && <form> <div className="form-group"> - <label htmlFor="envelop">Add envelop of </label> + <label htmlFor="envelop">Add envelope of </label> <select value={envName} className="form-control" id="envelop" onChange={(e) => onEnvChange(e)}> { [ <option value="NOMINAL" key={"nonminal"}>Nominal</option>, @@ -437,6 +521,7 @@ const UheppHistUIWithSyst = ({ </form> } </div> + <div className="tab-pane p-3" id="reset" role="tabpanel" aria-labelledby="reset-tab"> <p>Reset all view modifications. Pull the plot to make permanent changes.</p> @@ -444,6 +529,43 @@ const UheppHistUIWithSyst = ({ Reset view </button> </div> + + <div className="tab-pane p-3" id="save" role="tabpanel" aria-labelledby="save-tab"> + <form> + <p>Save the current view into another collection.</p> + <div className="form-group"> + <label htmlFor="env-stack">Destination collection</label> + { collections == null ? + <div className="d-flex justify-content-center"> + <div className="spinner-border text-primary" role="status"> + <span className="sr-only">Loading...</span> + </div> + </div> : + <select value={destination} className="form-control" onChange={(e) => handleDestination(e)}> + { collections.map((c, i) => <option value={c.url} key={i}>{c.title}</option>) } + </select> + } + </div> + + <p> + <button className="btn btn-secondary" type="button" onClick={() => save()} disabled={saveStatus == 'loading'}> + Save as new plot + { saveStatus == 'loading' && <> + <span className="ml-2 spinner-border spinner-border-sm" role="status"> </span> + <span className="sr-only">Loading...</span> + </>} + </button> + </p> + {saveStatus == 'loading' && + <p style={{fontSize: "smaller"}} className="text-muted">Depending on the size of the data, this might take some time.</p> + } + {saveStatus == 'error' && + <p className="alert alert-danger"> + Something went wrong. Please try again and make sure you have permission to write to that collection. + </p> } + </form> + </div> + </div> </> } @@ -567,7 +689,7 @@ const UheppHistUI = ({width, height, uhepp}) => { const handleDeleteRatioItem = (e, itemId) => { e.preventDefault() - setRatio(ratio.filter((_, i) => i != ratioId)) + setRatio(ratio.filter((_, i) => i != itemId)) } const handleAddRatioItem = (e) => { @@ -627,12 +749,13 @@ const UheppHistUI = ({width, height, uhepp}) => { const variations = variationList(mod_uhepp) const isVariationReady = noVariationUsed(mod_uhepp) && (variations.length > 0) - const main_names = mod_uhepp.stacks.map(stack => stack.content.map(item => item.yields)).flat() + const main_names = mod_uhepp.stacks.map(stack => stack.content.map(item => item.yield).flat()).flat() const num_names = mod_uhepp.ratio.map(item => item.numerator).flat() const den_names = mod_uhepp.ratio.map(item => item.denominator).flat() const all_names = [...main_names, ...num_names, ...den_names] + const used_var_names = all_names.filter(n => n).map(n => n.split("/")).filter(t => t.length == 3).map(t => t[1]) - const filter_var = (var_updown) => objfilter(var_updown, (value, key) => ((all_names.indexOf(key) != -1) || key.indexOf(envName) != -1)) + const filter_var = (var_updown) => objfilter(var_updown, (value, key) => ((used_var_names.indexOf(key) != -1) || key == envName)) const pruned = Object.assign({}, mod_uhepp, {"yields": objmap(uhepp.yields, y => Object.assign({}, y, { "var_up": filter_var(y.var_up || {}), @@ -642,9 +765,10 @@ const UheppHistUI = ({width, height, uhepp}) => { const pruned_env = envName == "NOMINAL" ? pruned : Object.assign({}, pruned, {stacks: [ - ...pruned.stacks, + ...pruned.stacks.filter((_, i) => i <= envId), ...makeVariationStacks(pruned, envId, envName, "up"), ...makeVariationStacks(pruned, envId, envName, "down"), + ...pruned.stacks.filter((_, i) => i > envId), ], ratio: [ ...makeVariationRatio(pruned, envId, envName, "up"), @@ -686,6 +810,7 @@ const UheppHistUI = ({width, height, uhepp}) => { envId={envId} origStacks={pruned.stacks} origRatio={pruned.ratio} + origYields={uhepp.yields} isVariationReady={isVariationReady} variations={variations} /> } diff --git a/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_detail.html b/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_detail.html index 9d8567f..3f7fdd6 100644 --- a/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_detail.html +++ b/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_detail.html @@ -26,7 +26,8 @@ </a> </span> {% endif %}</h1> -<div class="d-none d-lg-inline text-muted"><i class="fas fa-eye"></i> +<div class="d-none d-lg-inline text-muted"> + <i class="fas fa-eye"></i> {{ plot.view_count }} view{{ plot.view_count|pluralize }} </div> @@ -122,9 +123,6 @@ uhepp push {{ plot.collection.pk }} local_file.json</pre> </div> {{ plot.uhepp|json_script:"plot-data" }} - - - {% endblock %} {% block loadscript %} -- GitLab