Skip to content
Snippets Groups Projects
Commit 2155d2c3 authored by Matthias Feyll's avatar Matthias Feyll :cookie:
Browse files

(ui): add metadata information

parent c73d3566
No related branches found
No related tags found
2 merge requests!1196[renovate] Update module golang.org/x/net to v0.32.0,!1195UI: implement add device functionality
......@@ -55,3 +55,41 @@
text-decoration: underline;
}
}
.transitions {
$transition-duration-hover: 0.1s;
$transition-duration-change: 0.2s;
transition:
--startOpacity $transition-duration-hover ease-in-out,
--startPosition $transition-duration-hover ease-in-out;
}
@property --startOpacity {
syntax: "<number>";
initial-value: 0.35;
inherits: false;
}
@property --startPosition {
syntax: "<percentage>";
initial-value: 10%;
inherits: false;
}
.bg-gradient-fade {
$primary-color: map-get($theme-colors, "primary");
background: linear-gradient(
to bottom,
rgba($primary-color, var(--startOpacity)) var(--startPosition),
rgba($primary-color, 0.1) 100%
);
&:hover {
--startOpacity: 0.4;
--startPosition: 30%;
}
}
.disabled-hover:hover {
$primary-color: rgba(map-get($theme-colors, "dark"), 0.1);
background: linear-gradient(to bottom, rgb(223, 223, 223) 1%, white 100%);
}
......@@ -27,7 +27,7 @@ export const DeviceList = ({ searchRef }: { searchRef: RefObject<HTMLInputElemen
const { id } = device
setExpandedId(expandedId === id ? null : id);
}, [expandedId]);
1
const getDeviceList = useCallback(() => {
const search = searchRef?.current?.value;
let filtered = devices;
......@@ -53,12 +53,14 @@ export const DeviceList = ({ searchRef }: { searchRef: RefObject<HTMLInputElemen
return (
<div
key={deviceId}
className={`border-bottom border-primary p-2 transition-bg ${isSelected && 'bg-gradient-fade'} ${!isSelected && 'text-disabled'}`}
className={`border-bottom border-primary p-2 transitions ${isSelected && 'bg-gradient-fade py-2'} ${!isSelected && 'text-disabled disabled-hover'}`}
onClick={() => !isExpanded && handleItemClick(device)}
>
<div
aria-expanded={isExpanded}
className="d-flex justify-content-between py-4 clickable"
onClick={() => handleItemClick(device)}>
className="d-flex justify-content-between py-2 clickable"
onClick={() => isExpanded && handleItemClick(device)}
>
<FontAwesomeIcon icon={faChevronDown} rotation={isExpanded ? undefined : 270} />
<span dangerouslySetInnerHTML={{
__html: search ? insertMarkTags(devicename, search) : DOMPurify.sanitize(devicename)
......@@ -85,7 +87,7 @@ export const DeviceList = ({ searchRef }: { searchRef: RefObject<HTMLInputElemen
return (
<div className="rounded border border-primary mt-2">
<div className="border-bottom border-primary d-flex justify-content-between px-4 py-2 clickable" onClick={() => handleItemClick(device)}>
<div className="border-bottom border-primary d-flex justify-content-between px-4 py-2 clickable">
<FontAwesomeIcon icon={faChevronDown} className="opacity-0" />
<span className="font-medium">{t('device.table.header.name')}</span>
<span className="font-medium">{t('device.table.header.uuid')}</span>
......
......@@ -14,7 +14,7 @@ import { DeviceList } from './device.view.table';
const DeviceView = () => {
const { t } = useTranslation('common');
const searchRef = useRef<HTMLInputElement>(null);
const { jsonYang } = useDeviceViewModel();
const { jsonYang, selectedDevice } = useDeviceViewModel();
return (
<div className='m-4 pt-4'>
......@@ -28,8 +28,8 @@ const DeviceView = () => {
/>
<FontAwesomeIcon icon={faGripVertical} className="drag-handle" />
<Row>
<Col sm={12} className='mt-4'>
<h3 className='text-black-50'>{t('device.title')}</h3>
<Col sm={12}>
<h3 className='c-box-title'>{t('device.title')}</h3>
</Col>
</Row>
<Row>
......@@ -59,8 +59,8 @@ const DeviceView = () => {
/>
<FontAwesomeIcon icon={faGripVertical} className="drag-handle" />
<Row>
<Col xs={12} className='mt-4'>
{t('device.tabs.yang_model.title')}
<Col xs={12}>
<h3 className='c-box-title'>{t('device.tabs.yang_model.title')} <small>{selectedDevice?.device.name}</small></h3>
</Col>
</Row>
<Row className='align-items-start'>
......
......@@ -4,7 +4,7 @@ import { insertMarkTags } from "@helper/text";
import { useAppSelector } from "@hooks";
import { JsonViewer } from "@shared/components/json_viewer/view/json_viewer.view";
import DOMPurify from 'dompurify';
import { useCallback, useEffect, useState } from "react";
import { useState } from "react";
import { Collapse } from "react-bootstrap";
interface DeviceListCollapsableProps {
......@@ -13,60 +13,48 @@ interface DeviceListCollapsableProps {
search?: string,
}
export const DeviceListCollapsable = ({ deviceId, username, search }: DeviceListCollapsableProps) => {
const { selected } = useAppSelector(state => state.device);
const [metadata, setMetadata] = useState<boolean>(false)
useEffect(() => {
if (!selected?.json) return;
})
const [metadata, setMetadata] = useState<boolean>(true)
const content = useCallback(() => {
if (!selected?.json) return;
const json = selected?.json || {}
const key = Object.keys(selected.json).at(2) as keyof typeof selected.json
const metadataObject = selected.json[key] as JSON;
const key = Object.keys(json).at(2) as keyof typeof json
const metadataObject = json[key] as JSON || {};
return (
<div id={`collapse-${deviceId}`}>
<div className="pb-4 pt-1 d-flex flex-column gap-1" >
<div className="d-flex justify-content-between">
<div>
<FontAwesomeIcon className="me-2" icon={faHashtag} />
UUID:
</div>
<span dangerouslySetInnerHTML={{
__html: search ? insertMarkTags(deviceId, search) : DOMPurify.sanitize(deviceId)
}} />
return (
<div id={`collapse-${deviceId}`}>
<div className="pb-4 pt-1 d-flex flex-column gap-1" >
<div className="d-flex justify-content-between">
<div>
<FontAwesomeIcon className="me-2" icon={faHashtag} />
UUID:
</div>
<div className="d-flex justify-content-between">
<div>
<FontAwesomeIcon className="me-2" icon={faUser} />
User:
</div>
<span>{username}</span>
<span dangerouslySetInnerHTML={{
__html: search ? insertMarkTags(deviceId, search) : DOMPurify.sanitize(deviceId)
}} />
</div>
<div className="d-flex justify-content-between">
<div>
<FontAwesomeIcon className="me-2" icon={faUser} />
User:
</div>
<span>{username}</span>
</div>
<div className="d-flex justify-content-between clickable border-top border-dark mt-3 pt-2" aria-expanded={metadata} onClick={() => setMetadata(!metadata)}>
<div>
<FontAwesomeIcon icon={faChevronDown} rotation={metadata ? undefined : 270} />
Metadata:
</div>
<div className="d-flex justify-content-between clickable border-top border-dark mt-3 pt-1" aria-expanded={metadata} onClick={() => setMetadata(!metadata)}>
<div>
<FontAwesomeIcon icon={faChevronDown} rotation={metadata ? undefined : 270} />
Metadata
</div>
<Collapse in={metadata}>
<div id={`collapse-${deviceId}`}>
{JsonViewer({ json: metadataObject, options: { editable: false, searchEnabled: false } })}
</div>
</Collapse>
</div>
</div >
)
}, [metadata])
return content()
<Collapse in={metadata}>
<div id={`collapse-${deviceId}`}>
{JsonViewer({ json: metadataObject, options: { editable: false, searchEnabled: false } })}
</div>
</Collapse>
</div>
</div >
)
}
\ No newline at end of file
......@@ -22,6 +22,7 @@ export const useDeviceViewModel = () => {
const jsonYang = useMemo<JSON | null>(getYangModelJSON, [selectedDevice])
return {
jsonYang
jsonYang,
selectedDevice
}
}
......@@ -47,9 +47,6 @@
},
"add_device_button": "Add device",
"tabs": {
"metadata": {
"title": "Metadata"
},
"yang_model": {
"title": "YANG Model"
}
......
......@@ -23,18 +23,6 @@ export const JsonViewer = ({ json, options = { searchEnabled: true, editable: tr
const { getSubset, breadcrumbs, isCollapsed, collapseable, collapse, parameterizedJson, searchTerm } = useJsonViewer({ json, search, container: htmlContainer });
const breadcrumbHTML = useMemo(() => {
return (
<nav aria-label="breadcrumb">
<ol className="breadcrumb">
{breadcrumbs.map(breadcrumb => (
<li key={breadcrumb} className="breadcrumb-item"><a href="#">{breadcrumb}</a></li>
))}
</ol>
</nav>
)
}, [breadcrumbs])
const renderInner = (innerJson: JSON, nested: number = 0, parentKey: string = "", path: string = "/network-instance/0/"): JSX.Element => {
path += parentKey + (parentKey === "" ? "" : "/")
......@@ -129,7 +117,7 @@ export const JsonViewer = ({ json, options = { searchEnabled: true, editable: tr
const searchHTML = (): React.ReactElement => {
return (
<Form.Group controlId='json_viewer.search' className='p-0 mx-1 pt-2'>
<Form.Group controlId='json_viewer.search' className='p-0 '>
<Form.Control type="text" placeholder={t('device.search.placeholder')} ref={search} />
</Form.Group>
)
......@@ -138,7 +126,6 @@ export const JsonViewer = ({ json, options = { searchEnabled: true, editable: tr
return (
<div ref={htmlContainer}>
{options?.searchEnabled && searchHTML()}
{breadcrumbHTML}
{hierarchyHTML}
</div>
)
......
......@@ -132,7 +132,7 @@ export const useJsonViewer = ({ json, search, container }: JsonViewerViewModelTy
innerSearch(json, searchTerm);
return parameterizedJsonMap
}, [searchTerm])
}, [searchTerm, json])
useEffect(() => {
if (!container.current || !subscribe) {
......
@import "./colors.scss";
$box-padding: 1em;
$box-padding: 1.5em;
$border-radius: 0.25em;
$border-width: 2px;
$transition-duration: 0.3s;
.c-box {
padding: $box-padding !important;
padding: $box-padding / 2 $box-padding !important;
background-color: white;
position: relative;
transition: box-shadow $transition-duration ease-in-out;
......@@ -23,6 +23,24 @@ $transition-duration: 0.3s;
}
}
.c-box-title {
$text-color: black;
color: $text-color;
padding: 0.5em 0;
margin-top: 0.2em;
small {
font-size: 0.75em;
color: rgba($text-color, 0.65);
&::before {
content: "(";
}
&::after {
content: ")";
}
}
}
.rounded {
border-radius: $border-radius;
}
......@@ -64,33 +82,3 @@ $transition-duration: 0.3s;
transition: opacity $transition-duration ease-in-out;
}
}
@property --startOpacity {
syntax: "<number>";
initial-value: 0.35;
inherits: false;
}
@property --startPosition {
syntax: "<percentage>";
initial-value: 10%;
inherits: false;
}
.bg-gradient-fade {
$primary-color: map-get($theme-colors, "primary");
background: linear-gradient(
to bottom,
rgba($primary-color, var(--startOpacity)) var(--startPosition),
rgba($primary-color, 0.1) 100%
);
&:hover {
--startOpacity: 0.4;
--startPosition: 30%;
}
transition:
--startOpacity $transition-duration ease-in-out,
--startPosition $transition-duration ease-in-out;
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment