Skip to content

Commit

Permalink
feat(manager): server metrics row (#2349)
Browse files Browse the repository at this point in the history
  • Loading branch information
daniellacosse authored Jan 30, 2025
1 parent 337aaa4 commit 96a01eb
Show file tree
Hide file tree
Showing 4 changed files with 424 additions and 0 deletions.
216 changes: 216 additions & 0 deletions server_manager/www/views/server_view/server_metrics_row/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,216 @@
/**
* Copyright 2025 The Outline Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {LitElement, html, css, nothing} from 'lit';
import {customElement, property} from 'lit/decorators.js';
import {unsafeHTML} from 'lit/directives/unsafe-html.js';

import '@material/mwc-icon';

import './server_metrics_row_subcard';
import type {ServerMetricsRowSubcard} from './server_metrics_row_subcard';

@customElement('server-metrics-row')
export class ServerMetricsRow extends LitElement {
@property({type: Array}) subcards?: Array<Partial<ServerMetricsRowSubcard>>;
@property({type: String}) subtitle?: string;
@property({type: String}) title: string;
@property({type: String}) titleIcon?: string;
@property({type: String}) tooltip?: string;
@property({type: String}) value: string;
@property({type: String}) valueLabel?: string;

static styles = css`
:host {
--server-metrics-row-background: hsl(200, 15%, 18%);
--server-metrics-row-font-family: 'Inter', system-ui;
--server-metrics-row-icon-size: 1.85rem;
--server-metrics-row-padding: 1.25rem 2rem;
--server-metrics-row-text-color: hsla(0, 0%, 100%, 0.8);
--server-metrics-row-title-color: hsla(0, 0%, 100%, 0.7);
--server-metrics-row-value-container-margin-top: 1rem;
--server-metrics-row-title-container-gap: 0.35rem;
--server-metrics-row-title-font-size: 1.3rem;
--server-metrics-row-value-font-size: 3rem;
--server-metrics-row-value-font-family: 'Roboto', system-ui;
--server-metrics-row-value-label-font-size: 1.1rem;
--server-metrics-row-value-label-margin-left: 0.25rem;
--server-metrics-row-tooltip-background: hsl(0, 0%, 94%);
--server-metrics-row-tooltip-border-radius: 0.3rem;
--server-metrics-row-tooltip-padding: 0.3rem;
--server-metrics-row-tooltip-text-color: hsl(0, 0%, 20%);
--server-metrics-row-tooltip-max-width: 320px;
--server-metrics-row-footer-top-border: 1px solid hsla(0, 0%, 100%, 0.35);
--server-metrics-row-subtitle-font-size: 1rem;
--server-metrics-row-subtitle-margin-bottom: 1rem;
--server-metrics-row-subcards-gap: 0.75rem;
--server-metrics-row-subcards-min-width: 320px;
}
section {
background-color: var(--server-metrics-row-background);
box-sizing: border-box;
color: var(--server-metrics-row-text-color);
display: block;
font-family: 'iRoboto', system-u;
width: 100%;
}
.title-and-value-container {
padding: var(--server-metrics-row-padding);
}
.title-container {
display: flex;
align-items: center;
gap: var(--server-metrics-row-title-container-gap);
}
.title {
all: initial;
display: inline-block;
font-family: var(--server-metrics-row-font-family);
font-weight: 400;
font-size: var(--server-metrics-row-title-font-size);
color: var(--server-metrics-row-title-color);
}
mwc-icon {
font-size: var(--server-metrics-row-icon-size);
}
.value-container {
margin-top: var(--server-metrics-row-value-container-margin-top);
}
.value {
font-family: var(--server-metrics-row-value-font-family);
font-size: var(--server-metrics-row-value-font-size);
}
.value-label {
color: var(--server-metrics-row-title-color);
font-family: var(--server-metrics-row-font-family);
font-size: var(--server-metrics-row-value-label-font-size);
margin-left: var(--server-metrics-row-value-label-margin-left);
}
.tooltip-container {
cursor: help;
position: relative;
display: inline-flex;
}
.tooltip {
background-color: var(--server-metrics-row-tooltip-background);
border-radius: var(--server-metrics-row-tooltip-border-radius);
color: var(--server-metrics-row-tooltip-text-color);
font-family: var(--server-metrics-row-font-family);
left: 50%;
max-width: var(--server-metrics-row-tooltip-max-width);
padding: var(--server-metrics-row-tooltip-padding);
position: absolute;
top: 150%;
transform: translateX(-50%);
visibility: hidden;
white-space: pre-line;
width: max-content;
word-wrap: break-word;
}
.tooltip-container:hover .tooltip {
visibility: visible;
opacity: 1;
}
aside {
border-top: var(--server-metrics-row-footer-top-border);
padding: var(--server-metrics-row-padding);
}
.subtitle {
all: initial;
color: var(--server-metrics-row-title-color);
display: inline-block;
font-family: var(--server-metrics-row-font-family);
font-size: var(--server-metrics-row-subtitle-font-size);
margin-bottom: var(--server-metrics-row-subtitle-margin-bottom);
}
.subcards-container {
display: grid;
gap: var(--server-metrics-row-subcards-gap);
grid-template-columns: repeat(
auto-fit,
minmax(var(--server-metrics-row-subcards-min-width), 1fr)
);
}
`;

render() {
return html`
<section>
<div class="title-and-value-container">
<div class="title-container">
${this.titleIcon
? html`<mwc-icon>${this.titleIcon}</mwc-icon>`
: nothing}
<h2 class="title">${unsafeHTML(this.title)}</h2>
${this.tooltip
? html`<div class="tooltip-container">
<mwc-icon>info</mwc-icon>
<span class="tooltip">${this.tooltip}</span>
</div>`
: nothing}
</div>
<div class="value-container">
<span class="value">${this.value}</span>
<span class="value-label">${this.valueLabel}</span>
</div>
</div>
${this.subcards && this.subcards.length
? html`
<aside>
${this.subtitle
? html`<h3 class="subtitle">${unsafeHTML(this.subtitle)}</h3>`
: nothing}
<div class="subcards-container">
${this.subcards.map(
({highlight, title, subtitle, icon}) => html`
<server-metrics-row-subcard
highlight="${highlight}"
title="${title}"
subtitle="${subtitle}"
icon="${icon}"
></server-metrics-row-subcard>
`
)}
</div>
</aside>
`
: nothing}
</section>
`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
/**
* Copyright 2025 The Outline Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import {LitElement, html, css, nothing} from 'lit';
import {customElement, property} from 'lit/decorators.js';

@customElement('server-metrics-row-subcard')
export class ServerMetricsRowSubcard extends LitElement {
@property({type: String}) highlight?: string;
@property({type: String}) title: string;
@property({type: String}) subtitle?: string;
@property({type: String}) icon?: string;

static styles = css`
:host {
--server-metrics-row-subcard-background: hsl(194, 10%, 26%);
--server-metrics-row-subcard-border-radius: 0.5rem;
--server-metrics-row-subcard-font-family: 'Inter', system-ui;
--server-metrics-row-subcard-padding: 1rem;
--server-metrics-row-subcard-text-color: hsla(0, 0, 100%, 0.87);
--server-metrics-row-subcard-highlight-border: 2px solid
hsl(167, 49%, 56%);
--server-metrics-row-subcard-highlight-color: hsl(172, 22%, 34%);
--server-metrics-row-subcard-highlight-margin-bottom: 1rem;
--server-metrics-row-subcard-highlight-padding: 0.25rem 0.5rem;
--server-metrics-row-subcard-title-font-size: 1rem;
--server-metrics-row-subcard-title-margin-bottom: 0.25rem;
--server-metrics-row-subcard-subtitle-font-size: 0.9rem;
background-color: var(--server-metrics-row-subcard-background);
border-radius: var(--server-metrics-row-subcard-border-radius);
box-sizing: border-box;
display: block;
padding: var(--server-metrics-row-subcard-padding);
width: 100%;
}
.highlight,
.title,
.subtitle {
all: initial;
color: var(--server-metrics-row-subcard-text-color);
font-family: var(--server-metrics-row-subcard-font-family);
word-wrap: break-word;
}
.highlight {
background-color: var(--server-metrics-row-subcard-highlight-color);
border-radius: var(--server-metrics-row-subcard-border-radius);
border: var(--server-metrics-row-subcard-highlight-border);
display: inline-block;
margin-bottom: var(--server-metrics-row-subcard-highlight-margin-bottom);
padding: var(--server-metrics-row-subcard-highlight-padding);
}
.title {
display: block;
font-size: var(--server-metrics-row-subcard-title-font-size);
margin-bottom: var(--server-metrics-row-subcard-title-margin-bottom);
}
.subtitle {
font-size: var(--server-metrics-row-subcard-subtitle-font-size);
font-weight: bold;
}
`;

render() {
return html`
<div>
${this.highlight
? html`<mark class="highlight">${this.highlight}</mark>`
: nothing}
<h4 class="title">${this.title}</h4>
${this.subtitle
? html`<p class="subtitle">
<span>${this.subtitle}</span>
${this.icon
? html`<span role="img" aria-label="Icon">${this.icon}</span>`
: nothing}
</p>`
: nothing}
</div>
`;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
/**
* Copyright 2025 The Outline Authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

import './index';

export default {
title: 'Manager/Server View/Server Metrics Row/Server Metrics Row Subcard',
component: 'server-metrics-row-subcard',
argTypes: {
highlight: {control: 'text'},
title: {control: 'text'},
subtitle: {control: 'text'},
icon: {control: 'text'},
},
};

export const Example = {
args: {
highlight: '14.1hrs',
title: 'Spectrum Online Systems Inc',
subtitle: 'ASN3149',
icon: '🇺🇸',
},
};
Loading

0 comments on commit 96a01eb

Please sign in to comment.