diff --git a/uhepp-js/src/common.scss b/uhepp-js/src/common.scss index 21bb873363368fe9bb4055d37f802c9aa0741c75..a5dd86711160c9c4002bc40834f5e61d73ef83a1 100644 --- a/uhepp-js/src/common.scss +++ b/uhepp-js/src/common.scss @@ -9,7 +9,6 @@ a:hover { text-decoration: none; } - @include media-breakpoint-up(md) { .uhepp-container { width: 750px; @@ -17,3 +16,38 @@ a:hover { margin-right: auto; } } + +.highlight pre { + margin-bottom: 0; +} + +.access-menu { + .dropdown-menu { + width: 399px; + } + .highlight pre { + overflow-x: auto; + } + input { + width: 100%; + } +} + +dd { + margin-left: 1rem; +} + +.badge-pair { + .badge, .badge-pill { + &:not(:first-child) { + border-top-left-radius: 0; + border-bottom-left-radius: 0; + padding-left: 0.3em; + } + &:not(:last-child) { + border-top-right-radius: 0; + border-bottom-right-radius: 0; + padding-right: 0.3em; + } + } +} diff --git a/uhepp-js/src/components/Uhepp.jsx b/uhepp-js/src/components/Uhepp.jsx index 87bb0eb831b2a431015e4e8248e45ae7b5190250..ea3ec3b4b344ccc170c33fb2d801a6c182e1e37a 100644 --- a/uhepp-js/src/components/Uhepp.jsx +++ b/uhepp-js/src/components/Uhepp.jsx @@ -12,22 +12,41 @@ const Error = (message) => ( </div>) -const Uhepp = ({width, height, uhepp}) => { - if (!uhepp) { - return Error("Invalid uhepp data") - } - if (!uhepp.version) { - return Error("Missing uhepp version") - } - if (uhepp.version != "0.1") { - return Error(`Unsupported uhepp version: ${uhepp.version}`) +class Uhepp extends React.Component { + constructor(props) { + super(props); + this.state = { error: null }; } - if (uhepp.type == "histogram") { - return <UheppHistUI width={width} height={height} uhepp={uhepp} /> - } else { - return Error(`Unknown or missing plot type: ${uhepp.type}`) - } + static getDerivedStateFromError(error) { + return {error: error.toString()} + } + + render() { + if (this.state.error) { + return Error(this.state.error) + } + const uhepp = this.props.uhepp; + + if (!uhepp) { + return Error("Invalid uhepp data") + } + if (!uhepp.version) { + return Error("Missing uhepp version") + } + if (uhepp.version != "0.1") { + return Error(`Unsupported uhepp version: ${uhepp.version}`) + } + + if (uhepp.type == "histogram") { + return <UheppHistUI + width={this.props.width} + height={this.props.height} + uhepp={uhepp} /> + } + + return Error(`Unknown or missing plot type: ${uhepp.type}`) + } } diff --git a/uhepp-js/src/components/UheppHist.jsx b/uhepp-js/src/components/UheppHist.jsx index 75632671bc5edec19e937a1851804180aeeb461b..1f2f6e1476c9a058fdc926f2b07fa565b4816cf2 100644 --- a/uhepp-js/src/components/UheppHist.jsx +++ b/uhepp-js/src/components/UheppHist.jsx @@ -15,18 +15,18 @@ import { preprocessData, sumBase, sumStat, histogramify } from "../helpers/uhepp const getMaxBin = (uhepp) => { let max = 0; - const edges = uhepp.bins.edges || uhepp.bins.rebin + const edges = uhepp.bins.rebin || uhepp.bins.edges const n_bins = edges.length - 1 for (let bin_i=0; bin_i < n_bins; bin_i++) { const density_scale = uhepp.bins.density_width ? uhepp.bins.density_width / (edges[bin_i + 1] - edges[bin_i]) : 1 uhepp.stacks.forEach((stack, stack_index) => { let bottom = 0 stack.content.forEach((stack_item, si_i) => { - const y_value = sumBase(uhepp.yields, stack_item["yield"], bin_i) * density_scale + const y_value = sumBase(uhepp.yields, stack_item["yield"], bin_i + 1) * density_scale if (y_value > 0) { bottom += y_value; } }) const whole_stack = stack.content.map(si => si["yield"]).flat() - const stat = sumStat(uhepp.yields, whole_stack, bin_i) * density_scale + const stat = sumStat(uhepp.yields, whole_stack, bin_i + 1) * density_scale if (stat > 0) { bottom += stat; } max = Math.max(max, bottom) }) @@ -323,8 +323,9 @@ const Histogram = ({ } } else if (stack.type == "step") { const bin_indices = Array(n_bins).fill(0).map((_, i) => i) - const density_scale = uhepp.bins.density_width ? uhepp.bins.density_width / (edges[bin_i + 1] - edges[bin_i]) : 1 - const y_values = bin_indices.map(i => sumBase(uhepp.yields, stack_item["yield"], i + 1)) * density_scale + const y_values = bin_indices.map(i => sumBase(uhepp.yields, stack_item["yield"], i + 1) * + (uhepp.bins.density_width ? uhepp.bins.density_width / (edges[i + 1] - edges[i]) : 1) + ) const [new_x, new_y] = histogramify(edges, y_values) diff --git a/uhepp-js/src/components/UheppHistUI.jsx b/uhepp-js/src/components/UheppHistUI.jsx index fa50c09f9e1479a69f3e7eaaea57fde795e37d6c..8048afc4854d90fb338bd81535f5092bb13e07fe 100644 --- a/uhepp-js/src/components/UheppHistUI.jsx +++ b/uhepp-js/src/components/UheppHistUI.jsx @@ -32,6 +32,14 @@ const UheppHistUI = ({width, height, uhepp}) => { let rebin = uhepp_data.bins.rebin || uhepp_data.bins.edges return <> + <div>{ Object.entries(uhepp.metadata.tags).map(([key, value]) => + value == null ? + <span className="badge badge-pill badge-primary mx-1">{key}</span> : + <span className="badge-pair mx-1"> + <span className="badge badge-pill badge-primary">{key}</span> + <span className="badge badge-pill badge-secondary">{value}</span> + </span> + ) }</div> <UheppHist width={width} height={height} uhepp={uhepp_data} /> <ul className="nav nav-tabs" id="view-options" role="tablist"> @@ -53,13 +61,30 @@ const UheppHistUI = ({width, height, uhepp}) => { <div className="tab-pane show active" id="info" role="tabpanel" aria-labelledby="binning-tab"> <dl> <dt>Author</dt> - <dd>{ uhepp.metadata.author }</dd> - <dt>Data</dt> - <dd>{ uhepp.metadata.data }</dd> + <dd>{ uhepp.metadata.author || <i>None</i>}</dd> + <dt>Date</dt> + <dd>{ uhepp.metadata.date ? (new Date(uhepp.metadata.date)).toString() : <i>None</i>}</dd> <dt>Producer</dt> <dd>{ uhepp.metadata.producer || <i>None</i>}</dd> <dt>Code revision</dt> <dd>{ uhepp.metadata.code_revision || <i>None</i>}</dd> + <dt>Event selection</dt> + <dd>{ uhepp.metadata.event_selection || <i>None</i>}</dd> + <dt>Total integrated luminosity</dt> + <dd>{ uhepp.metadata.lumi_ifb ? + <span>{ uhepp.metadata.lumi_ifb} fb<sup>-1</sup></span> : <i>None</i>}</dd> + <dt>Center-of-mass energy</dt> + <dd>{ uhepp.metadata.Ecm_TeV ? + uhepp.metadata.Ecm_TeV + " TeV" : <i>None</i>}</dd> + <dt>Tags</dt> + <dd>{ Object.entries(uhepp.metadata.tags).map(([key, value]) => + value == null ? + <span className="badge badge-pill badge-primary mx-1">{key}</span> : + <span className="badge-pair mx-1"> + <span className="badge badge-pill badge-primary">{key}</span> + <span className="badge badge-pill badge-secondary">{value}</span> + </span> + ) }</dd> </dl> </div> <div className="tab-pane" id="binning" role="tabpanel" aria-labelledby="binning-tab"> @@ -97,9 +122,11 @@ const UheppHistUI = ({width, height, uhepp}) => { <input type="number" className="form-control" id="densityWidth" onChange={e => handleDensityWidth(e)} value={uhepp_data.bins.density_width || "0"} /> - <div className="input-group-append"> - <span className="input-group-text">{uhepp_data.variable.unit}</span> - </div> + { uhepp.variable.unit && + <div className="input-group-append"> + <span className="input-group-text">{uhepp_data.variable.unit}</span> + </div> + } </div> </div> </form> diff --git a/uhepp_org/uhepp_org/settings.py b/uhepp_org/uhepp_org/settings.py index 8d6c20d3a9853b42565df3a5f97a5f2c6adce288..cbe31222fe0f7b4b0b301ecc910fe2db68cc07e9 100644 --- a/uhepp_org/uhepp_org/settings.py +++ b/uhepp_org/uhepp_org/settings.py @@ -112,7 +112,7 @@ INSTALLED_APPS = [ PYGMENTIFY = { 'style': 'default', - 'cssclass': 'highlight border rounded bg-light py-1 px-2 m-2' + 'cssclass': 'highlight border rounded bg-light px-2 m-2' } AUTHENTICATION_BACKENDS = [ diff --git a/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_detail.html b/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_detail.html index 90e0ca43387ccf50861daa7d927d0d3cc10518a6..12df3923187cfbd3ef697d54d5b7e427684d3bae 100644 --- a/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_detail.html +++ b/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_detail.html @@ -2,6 +2,14 @@ {% load pygmentify_tags %} {% block content %} +<nav aria-label="breadcrumb" class="d-none d-sm-block"> + <ol class="breadcrumb my-2"> + <li class="breadcrumb-item"><a href="/">Home</a></li> + <li class="breadcrumb-item"><a href="{% url 'uhepp_vault:user-detail' collection.owner.username %}">{{ collection.owner }}</a></li> + <li class="breadcrumb-item active"><a href="{% url 'uhepp_vault:collection-detail' collection.id %}">{{ collection.title }}</a></li> + </ol> +</nav> + <h1>{{ collection.title }}</h1> {% if collection.owner.pk == user.pk %} <p> @@ -12,34 +20,21 @@ delete </a> </p> - -{% endif %} -<p>Collection-ID: - {{ collection.id }} -</p> -<p>Owner: - <a href="{% url 'uhepp_vault:user-detail' collection.owner.username %}"> - {{ collection.owner.username }} - </a> -</p> - -<p>{{ collection.description }}</p> - -{% if collection.plots.all.count %} -<ul>{% for plot in collection.plots.all %} - <li> - <a href="{% url 'uhepp_vault:plot-detail' plot.uuid %}"> - {{ plot }} - </a> - </li> -{% endfor %}</ul> -{% else %} -<p>This collection is empty</p> {% endif %} -<h2>API access</h2> -<p>Make sure you've set up an API access token.</p> -<h3>Pull collection</h3> +<div class="d-flex"> +<span>Collection ID: {{ collection.id }}</span> +<div class="ml-auto btn-group btn-group-sm access-menu"> + <div class="btn-group btn-group-sm dropdown"> + <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown"> + API Access + </button> + <div class="dropdown-menu dropdown-menu-right p-4 shadow"> + <form> + <p class="alert alert-info m-2"> + Make sure you've set up an <a class="alert-link" href="{% url 'uhepp_vault:token-list' %}">API access token</a>. + </p> +<h5>Pull collection</h5> {% pygmentify %} <pre class="python"> import uhepp @@ -47,7 +42,7 @@ plots = uhepp.pull_collection({{ collection.pk }}) </pre> {% endpygmentify %} -<h3>Push new plot</h3> +<h5>Push new plot</h5> {% pygmentify %} <pre class="pyton"> import uhepp @@ -56,5 +51,48 @@ hist = uhepp.from_json("local_file.json") hist.push({{ collection.pk }}) </pre> {% endpygmentify %} + </form> + </div> + </div> + + <div class="btn-group btn-group-sm dropdown"> + <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown"> + CLI tool + </button> + <div class="dropdown-menu dropdown-menu-right p-4 shadow"> + <form> +<h5>Pull collection</h5> +{% pygmentify %} +<pre class="bash"> +uhepp cpull {{ colleciton.pk }} DESTINATION +</pre> +{% endpygmentify %} + +<h5>Push new plot</h5> +{% pygmentify %} +<pre class="bash"> +uhepp push {{ collection.pk }} local_file.json +</pre> +{% endpygmentify %} + </form> + </div> + </div> +</div> +</div> + +<p>{{ collection.description }}</p> + +{% if collection.plots.all.count %} +<ul>{% for plot in collection.plots.all %} + <li> + <a href="{% url 'uhepp_vault:plot-detail' plot.uuid %}"> + {{ plot }} + </a> + </li> +{% endfor %}</ul> +{% else %} +<p>This collection is empty</p> +{% endif %} + {% endblock %} diff --git a/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_list.html b/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_list.html index 1b33da77c6abf26e8c3337c683f17c4314c0c969..068e808f1ffb0219da467fc4635d2283b300fa3f 100644 --- a/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_list.html +++ b/uhepp_org/uhepp_vault/templates/uhepp_vault/collection_list.html @@ -2,22 +2,36 @@ {% block content %} <h1>Collections</h1> + + {% if collection_list %} -<ul> + <div class="list-group"> {% for collection in collection_list %} - <li> - <a href="{% url 'uhepp_vault:collection-detail' collection.pk %}"> - {{ collection.owner.username}} / - {{ collection.title }} - </a> - {% if collection.visibility >= 30 %}(public) - {% elif collection.visibility >= 20 %}(internal) - {% elif collection.visibility >= 10 %}(private) - {% endif %} - </li> + <a class="list-group-item" href="{% url 'uhepp_vault:collection-detail' collection.pk %}"> + <div class="d-flex justify-content-between align-items-center"> + <span> + {{ collection.title }} + <small class="text-muted">{% if collection.visibility >= 30 %}(public) + {% elif collection.visibility >= 20 %}(internal) + {% elif collection.visibility >= 10 %}(private) + {% endif %} + by <span class="text-body">{{ collection.owner.username}}</span> + </small> + + </span> + + {% if collection.plots.count %} + <span class="badge badge-primary badge-pill">{{ collection.plots.count }}</span> + {% endif %} + </div> + <small class="text-body"> + {{ collection.description }} + </small> + </a> {% endfor %} -</ul> + </div> {% else %} -<p>There are no collections visible to you.</p> +<p>{{ user.first_name }} has no collections shared with you</p> {% endif %} + {% endblock %} 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 ae87092175f7c8a96517a79fc9ce9e0fb017ac04..d5353f9f4282d653fdafb8b645ebe70356063d51 100644 --- a/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_detail.html +++ b/uhepp_org/uhepp_vault/templates/uhepp_vault/plot_detail.html @@ -2,36 +2,47 @@ {% load pygmentify_tags %} {% block content %} - <a href="{% url 'uhepp_vault:collection-detail' plot.collection.id %}"> - back to collection - </a> +<nav aria-label="breadcrumb" class="d-none d-lg-block"> + <ol class="breadcrumb my-2"> + <li class="breadcrumb-item"><a href="/">Home</a></li> + <li class="breadcrumb-item"><a href="{% url 'uhepp_vault:user-detail' plot.collection.owner.username %}">{{ plot.collection.owner }}</a></li> + <li class="breadcrumb-item"><a href="{% url 'uhepp_vault:collection-detail' plot.collection.id %}">{{ plot.collection.title }}</a></li> + <li class="breadcrumb-item active"><a href="{% url 'uhepp_vault:plot-detail' plot.uuid %}">{{ plot }}</a></li> + </ol> +</nav> + <h1>{{ plot }}</h1> <div class="d-flex"> -<p>UUID: {{ plot.uuid }}</p> -<div class="ml-auto btn-group btn-group-sm"> - <div class="btn-group btn-group-sm"> +<span class="d-none d-md-inline">UUID: {{ plot.uuid }}</span> +<div class="ml-auto btn-group btn-group-sm access-menu"> + <div class="btn-group btn-group-sm dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown"> Direct download </button> <div class="dropdown-menu dropdown-menu-right p-4 shadow"> - <p>Download the uhepp data directy as a JSON file.</p> + <form> + <p>Download the uhepp data directly as a JSON file.</p> <p> <a class="btn btn-primary" href="{% url 'uhepp_vault:plot-download' plot.uuid %}">Download JSON</a> </p> + <p>Copy the download URL</p> + <input type="text" value="{{ request.scheme }}://{{ request.get_host }}{% url 'uhepp_vault:plot-download' plot.uuid %}" /> + </form> </div> </div> - <div class="btn-group btn-group-sm"> + <div class="btn-group btn-group-sm dropdown"> <button class="btn btn-primary dropdown-toggle" type="button" data-toggle="dropdown"> API Access </button> <div class="dropdown-menu dropdown-menu-right p-4 shadow"> + <form> <p class="alert alert-info m-2"> - Make sure you've set up an <a href="{% url 'uhepp_vault:token-list' %}">API access token</a>. + Make sure you've set up an <a class="alert-link" href="{% url 'uhepp_vault:token-list' %}">API access token</a>. </p> - <h3>Pull plot</h3> + <h5>Pull plot</h5> {% pygmentify %} <pre class="python"> import uhepp @@ -41,7 +52,7 @@ plot = uhepp.pull("{{ plot.uuid }}") plot.show()</pre> {% endpygmentify %} - <h3>Push new plot to the same collection</h3> + <h5>Push new plot to the same collection</h5> {% pygmentify %} <pre class="python"> import uhepp @@ -49,34 +60,37 @@ import uhepp hist = uhepp.from_json("local_file.json") hist.push({{ plot.collection.pk }})</pre> {% endpygmentify %} + </form> </div> </div> - <div class="btn-group btn-group-sm"> + <div class="btn-group btn-group-sm dropdown"> <button class="btn btn-secondary dropdown-toggle" type="button" data-toggle="dropdown"> CLI tool </button> <div class="dropdown-menu dropdown-menu-right p-4 shadow"> + <form> <p class="alert alert-info m-2"> - Make sure you've set up an <a href="{% url 'uhepp_vault:token-list' %}">API access token</a>. + Make sure you've set up an <a class="alert-link" href="{% url 'uhepp_vault:token-list' %}">API access token</a>. </p> - <h3>Pull plot</h3> + <h5>Pull plot</h5> {% pygmentify %} - <pre class="console"> -$ uhepp pull {{ plot.uuid}}</pre> + <pre class="bash"> +uhepp pull {{ plot.uuid}}</pre> {% endpygmentify %} - <h3>Show plot</h3> + <h5>Show plot</h5> {% pygmentify %} - <pre class="console"> -$ uhepp show {{ plot.uuid}}</pre> + <pre class="bash"> +uhepp show {{ plot.uuid}}</pre> {% endpygmentify %} - <h3>Push new plot to the same collection</h3> + <h5>Push new plot to the same collection</h5> {% pygmentify %} - <pre class="console"> -$ uhepp push {{ plot.collection.pk }} local_file.json</pre> + <pre class="bash"> +uhepp push {{ plot.collection.pk }} local_file.json</pre> {% endpygmentify %} + </form> </div> </div> </div> diff --git a/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_detail.html b/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_detail.html index 28a48a96e9a94cf38684eb4ec0f72f4252eca594..366866e9cb0206204a67ffd5bf9f4732ba0fce87 100644 --- a/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_detail.html +++ b/uhepp_org/uhepp_vault/templates/uhepp_vault/profile_detail.html @@ -1,6 +1,12 @@ {% extends 'uhepp_vault/base.html' %} {% block content %} +<nav aria-label="breadcrumb"> + <ol class="breadcrumb my-2"> + <li class="breadcrumb-item"><a href="/">Home</a></li> + <li class="breadcrumb-item"><a class="active" href="{% url 'uhepp_vault:user-detail' user.username %}">{{ user.username }}</a></li> + </ol> +</nav> <h1>{{ user.first_name }} {{ user.last_name }}</h1> <p>Visibility: {% if user.profile.visibility >= 30 %} public @@ -19,16 +25,33 @@ <p><a href="{% url 'uhepp_vault:collection-create' %}">New collection</a></p> {% endif %} + + {% if user.collections %} - <ul> + <div class="list-group"> {% for collection in user.collections.all %} - <li> - <a href="{% url 'uhepp_vault:collection-detail' collection.pk %}"> + <a class="list-group-item" href="{% url 'uhepp_vault:collection-detail' collection.pk %}"> + <div class="d-flex justify-content-between align-items-center"> + <span> {{ collection.title }} - </a> - </li> + <small class="text-muted">{% if collection.visibility >= 30 %}(public) + {% elif collection.visibility >= 20 %}(internal) + {% elif collection.visibility >= 10 %}(private) + {% endif %} + </small> + + </span> + + {% if collection.plots.count %} + <span class="badge badge-primary badge-pill">{{ collection.plots.count }}</span> + {% endif %} + </div> + <small class="text-body"> + {{ collection.description }} + </small> + </a> {% endfor %} - </ul> + </div> {% else %} <p>{{ user.first_name }} has no collections shared with you</p> {% endif %}