2852fa3c5e
* api: fix types for config API * api: remove broken swagger UI * admin: re-fix system task enum * events: make event optional * events: fix Schema for notification transport test * flows: use APIView for Flow Executor * core: fix schema for Metrics APIs * web: rewrite to use generated API client * web: generate API Client in CI * admin: use x_cord and y_cord to prevent yaml issues * events: fix linting errors * web: don't lint generated code * core: fix fields not being required in TypeSerializer * flows: fix missing permission_classes * web: cleanup * web: fix rendering of graph on Overview page * web: cleanup imports * core: fix missing background image filter * flows: fix flows not advancing properly * stages/*: fix warnings during get_challenge * web: send Flow response as JSON instead of FormData * web: fix styles for horizontal tabs * web: add base chart class and custom chart for application view * root: generate ts client for e2e tests * web: don't attempt to connect to websocket in selenium tests * web: fix UserTokenList not being included in the build * web: fix styling for static token list * web: fix CSRF Token missing * stages/authenticator_static: fix error when disable static tokens * core: fix display issue when updating user info * web: fix Flow executor not showing spinner when redirecting
104 lines
3.1 KiB
TypeScript
104 lines
3.1 KiB
TypeScript
import { css, CSSResult, html, LitElement, TemplateResult } from "lit-element";
|
|
import Chart from "chart.js";
|
|
|
|
interface TickValue {
|
|
value: number;
|
|
major: boolean;
|
|
}
|
|
|
|
export abstract class AKChart<T> extends LitElement {
|
|
|
|
abstract apiRequest(): Promise<T>;
|
|
abstract getDatasets(data: T): Chart.ChartDataSets[];
|
|
|
|
chart?: Chart;
|
|
|
|
static get styles(): CSSResult[] {
|
|
return [css`
|
|
:host {
|
|
position: relative;
|
|
height: 100%;
|
|
width: 100%;
|
|
display: block;
|
|
min-height: 25rem;
|
|
}
|
|
canvas {
|
|
width: 100px;
|
|
height: 100px;
|
|
}
|
|
`];
|
|
}
|
|
|
|
constructor() {
|
|
super();
|
|
window.addEventListener("resize", () => {
|
|
if (this.chart) {
|
|
this.chart.resize();
|
|
}
|
|
});
|
|
}
|
|
|
|
configureChart(data: T, ctx: CanvasRenderingContext2D): Chart {
|
|
return new Chart(ctx, {
|
|
type: "bar",
|
|
data: {
|
|
datasets: this.getDatasets(data),
|
|
},
|
|
options: {
|
|
maintainAspectRatio: false,
|
|
spanGaps: true,
|
|
scales: {
|
|
xAxes: [
|
|
{
|
|
stacked: true,
|
|
gridLines: {
|
|
color: "rgba(0, 0, 0, 0)",
|
|
},
|
|
type: "time",
|
|
offset: true,
|
|
ticks: {
|
|
callback: function (value, index: number, values) {
|
|
const valueStamp = <TickValue>(<unknown>values[index]);
|
|
const delta = Date.now() - valueStamp.value;
|
|
const ago = Math.round(delta / 1000 / 3600);
|
|
return `${ago} Hours ago`;
|
|
},
|
|
autoSkip: true,
|
|
maxTicksLimit: 8,
|
|
},
|
|
},
|
|
],
|
|
yAxes: [
|
|
{
|
|
stacked: true,
|
|
gridLines: {
|
|
color: "rgba(0, 0, 0, 0)",
|
|
},
|
|
},
|
|
],
|
|
},
|
|
},
|
|
});
|
|
}
|
|
|
|
firstUpdated(): void {
|
|
this.apiRequest().then((r) => {
|
|
const canvas = <HTMLCanvasElement>this.shadowRoot?.querySelector("canvas");
|
|
if (!canvas) {
|
|
console.warn("Failed to get canvas element");
|
|
return false;
|
|
}
|
|
const ctx = canvas.getContext("2d");
|
|
if (!ctx) {
|
|
console.warn("failed to get 2d context");
|
|
return false;
|
|
}
|
|
this.chart = this.configureChart(r, ctx);
|
|
});
|
|
}
|
|
|
|
render(): TemplateResult {
|
|
return html`<canvas></canvas>`;
|
|
}
|
|
}
|