Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,151 changes: 60 additions & 1,091 deletions Control/package-lock.json

Large diffs are not rendered by default.

7 changes: 1 addition & 6 deletions Control/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,12 @@
"protobuf/"
],
"dependencies": {
"@aliceo2/web-ui": "2.7.3",
"@aliceo2/web-ui": "file:../Framework",
"@grpc/grpc-js": "1.12.0",
"@grpc/proto-loader": "0.7.0",
"google-protobuf": "3.21.0",
"kafkajs": "2.2.4"
},
"bundledDependencies": [
"@aliceo2/web-ui",
"@grpc/grpc-js",
"@grpc/proto-loader"
],
"devDependencies": {
"eslint": "^8.56.0",
"jsonwebtoken": "^9.0.2",
Expand Down
40 changes: 40 additions & 0 deletions Control/public/common/buttons/DropdownCopyValue.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* @license
* Copyright 2019-2020 CERN and copyright holders of ALICE O2.
* See http://alice-o2.web.cern.ch/copyright for details of the copyright holders.
* All rights not expressly granted are reserved.
*
* This software is distributed under the terms of the GNU General Public
* License v3 (GPL Version 3), copied verbatim in the file "COPYING".
*
* In applying this license CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/

import {h,CopyToClipboardComponent,DropdownComponent } from '/js/src/index.js';
import { iconCaretBottom } from '/js/src/icons.js';
/**
* Build a component which a dropdown with values and provides a copy to clipboard actionable icon
* @param {String|vnode} text - text to be displayed
* @param {String} type - type of the text
* @param {Array} options - options for the dropdown
* @return {vnode}
*/
export const DropdownCopyValue = (text, type,options) =>
h('.flex-row.items-center.btn-group', [
h(`${type}`, text),
DropdownComponent(
h('.btn.btn-group-item.last-item', iconCaretBottom()),
h('.flex-column.p2.g3',
[
options.map((option) =>
h(CopyToClipboardComponent, { value: option.value, id: option.value }, option.label)
)
],
),
{
alignment: 'right',
}
),
]);
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@

import {h} from '/js/src/index.js';
import {ALIECS_STATE_COLOR} from '../../../common/constants/stateColors.js';
import {textWithCopyClipboard} from '../../../common/buttons/textWithCopyClipboard.js';
import {parseObject} from '../../../common/utils.js';
import {EnvironmentState} from '../../../common/enums/EnvironmentState.enum.js';
import {DropdownCopyValue} from '../../../common/buttons/DropdownCopyValue.js';
/**
* Build a component which represents a summary of the state of the environment with the environment id, state and creation time
* @param {EnvironmentInfo} environment - DTO representing an environment
Expand All @@ -32,11 +32,23 @@ export const environmentStateSummary = (environment) => {
transitionTime = parseObject(userVars['run_start_time_ms'], 'run_start_time_ms');
transitionLabel = 'Running since: ';
}

var commaSeparated = [currentRunNumber, id].join(',').toString();
var SlashSeparated = [currentRunNumber, id].join('/').toString();

var options = [
{label: 'Environment Id: ' + id, value:id},
];

state === EnvironmentState.RUNNING && options.push({label: 'Run Number: ' + currentRunNumber, value:currentRunNumber},
{label: 'RunNumber, environmentId ', value:commaSeparated},
{label: 'RunNumber / environmentId ', value:SlashSeparated},
);

return h(`.flex-row.g2.p2.white.bg-${ALIECS_STATE_COLOR[state]}`, [
textWithCopyClipboard(id, 'h3'),
DropdownCopyValue('Copy', 'p', options),
h('h3', title),
state === EnvironmentState.RUNNING && textWithCopyClipboard(currentRunNumber, 'h3'),
// state === EnvironmentState.RUNNING && textWithCopyClipboard(currentRunNumber, 'h3'),
h('.ph1.flex-grow.flex-column.flex-center.text-right', transitionLabel + transitionTime)
]);
};
7 changes: 7 additions & 0 deletions Framework/Frontend/css/src/bootstrap.css
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,9 @@
--space-m: 1rem;
--space-l: 2rem;
--space-xl: 4rem;

/* fixed size */
--ui-component-large: 850px;
}

/* reset what specific browsers do */
Expand Down Expand Up @@ -308,6 +311,10 @@ svg.icon { height: 1em; width: 1em; margin-bottom: -0.2em; }
.dropup-open>.dropup-menu { display: block; }
.dropup-menu { box-shadow: 0 8px 17px 2px rgba(0, 0, 0, 0.14), 0 3px 14px 2px rgba(0, 0, 0, 0.12), 0 5px 5px -3px rgba(0, 0, 0, 0.2); display: none; position: absolute; bottom: calc(100% + 0.1rem); left: 0.1rem; z-index: 1000; font-size: 1rem; background-color: #fff; border: 1px solid rgba(0, 0, 0, .15); border-radius: .25rem; }

/* popover */

.popover { flex-shrink: 0;flex-wrap: wrap;align-items: flex-start;position: absolute;top: 0;left: 0;z-index: 1002;max-width: var(--ui-component-large); }

/* tooltip */
.tooltip {position: relative; display: inline-block; border-bottom: 1px dotted black;}
.tooltip .tooltiptext {visibility: hidden; width: 118px; background-color: #555; color: #fff; text-align: center; padding: 3px; border-radius: 6px; position: absolute; z-index: 1;}
Expand Down
16 changes: 16 additions & 0 deletions Framework/Frontend/js/src/components/Component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
/**
* @license
* Copyright CERN and copyright holders of ALICE O2. This software is
* distributed under the terms of the GNU General Public License v3 (GPL
* Version 3), copied verbatim in the file "COPYING".
*
* See http://alice-o2.web.cern.ch/license for full licensing information.
*
* In applying this license CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/

/**
* @typedef {(vnode|string|number|Array<(vnode|string|number)>|null)} Component
*/
125 changes: 125 additions & 0 deletions Framework/Frontend/js/src/components/CopyToClipboardComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
/**
* @license
* Copyright CERN and copyright holders of ALICE O2. This software is
* distributed under the terms of the GNU General Public License v3 (GPL
* Version 3), copied verbatim in the file "COPYING".
*
* See http://alice-o2.web.cern.ch/license for full licensing information.
*
* In applying this license CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/

import { StatefulComponent } from './StatefulComponent.js';
import { iconCheck, iconLinkIntact } from '../icons.js';
import { h } from '../renderer.js';

/**
* Represents a component that allows copying text to the clipboard.
*/
export class CopyToClipboardComponent extends StatefulComponent {
/**
* Constructs a new CopyToClipboardComponent.
*/
constructor() {
super();
this._successStateTimeout = null;
}

/**
* Copies the specified text to the clipboard.
*
* @param {string} clipboardTargetValue The text to be copied to the clipboard.
* @returns {void}
*/
copyToClipboard(clipboardTargetValue) {
navigator.clipboard.writeText(clipboardTargetValue);
this._successStateTimeout = setTimeout(() => {
this._successStateTimeout = null;
this.notify();
}, 2000);
this.notify();
}

/**
* Checks the availability of the clipboard and provides a message if it is not accessible.
*
* @throws {Error} Throws an error with a descriptive message if the clipboard is not available.
* @returns {void}
*/
checkClipboardAvailability() {
if (!this.isContextSecure()) {
throw new Error('Clipboard not available in a non-secure context.');
}

if (!this.isClipboardSupported()) {
throw new Error('Clipboard API is not supported in this browser.');
}

if (this.isWindowEmbedded()) {
throw new Error('Clipboard access is restricted in iframes.');
}
}

/**
* Checks if context is secure (HTTPS)
*
* @returns {boolean} Returns `true` if context is secure
*/
isContextSecure() {
return window.isSecureContext;
}

/**
* Checks if the clipboard API is available in the user's browser.
*
* @returns {boolean} Returns `true` if it is available
*/
isClipboardSupported() {
return Boolean(navigator.clipboard);
}

/**
* Check if the window is embeded in a frame.
*
* @returns {boolean} Returns `true` if it is embeded
*/
isWindowEmbedded() {
return window !== window.parent;
}

/**
* Renders the button that allows copying text to the clipboard.
*
* @param {vnode} vnode The virtual DOM node containing the attrs and children.
* @returns {Component} The copyToClipboard button component
*/
view(vnode) {
const { attrs, children } = vnode;
const { value: clipboardTargetValue = '', id } = attrs;
let available = true;
let message = '';

try {
this.checkClipboardAvailability();
} catch ({ message: errorMessage }) {
available = false;
message = errorMessage;
}

const defaultContent = [iconLinkIntact(), children];
const successContent = [iconCheck(), h('', 'Copied!')];

return h(
'button.btn.btn-primary',
{
id: `copy-${id}`,
onclick: () => this.copyToClipboard(clipboardTargetValue),
disabled: !available,
title: message || null,
},
h('div.flex-row.g1', this._successStateTimeout ? successContent : defaultContent),
);
}
}
45 changes: 45 additions & 0 deletions Framework/Frontend/js/src/components/DropdownComponent.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/**
* @license
* Copyright CERN and copyright holders of ALICE O2. This software is
* distributed under the terms of the GNU General Public License v3 (GPL
* Version 3), copied verbatim in the file "COPYING".
*
* See http://alice-o2.web.cern.ch/license for full licensing information.
*
* In applying this license CERN does not waive the privileges and immunities
* granted to it by virtue of its status as an Intergovernmental Organization
* or submit itself to any jurisdiction.
*/

import {h} from '../renderer.js';
import {PopoverTriggerPreConfiguration} from './PopoverPreConfigurations.js';
import {PopoverAnchors} from './PopoverEngine.js';
import {popover} from './popover.js';

/**
* Renders a dropdown component
*
* @param {Component} trigger the component triggering the dropdown opening trigger
* @param {Component} content the content of the dropdown
* @param {Object} [configuration] dropdown configuration
* @param {'left'|'right'} [configuration.alignment='left'] defines the alignment of the dropdown
* @param {popoverVisibilityChangeCallback} [configuration.onVisibilityChange] function called when the visibility changes
* @return {Component} the dropdown component
*/
export const DropdownComponent = (
trigger,
content,
configuration,
) => {
configuration = configuration || {};
const {alignment = 'left'} = configuration;
return popover(
trigger,
h('.dropdown', content),
{
...PopoverTriggerPreConfiguration.click,
anchor: alignment === 'left' ? PopoverAnchors.BOTTOM_START : PopoverAnchors.BOTTOM_END,
onVisibilityChange: configuration.onVisibilityChange,
},
);
};
Loading