Skip to content

Commit aa8698e

Browse files
committed
create minimal ui for new status page
1 parent ba16a2e commit aa8698e

File tree

8 files changed

+373
-0
lines changed

8 files changed

+373
-0
lines changed

site/frontend/package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
"source": "src/pages/status.ts",
3939
"distDir": "dist/scripts"
4040
},
41+
"status_new": {
42+
"source": "src/pages/status_new.ts",
43+
"distDir": "dist/scripts"
44+
},
4145
"bootstrap": {
4246
"source": "src/pages/bootstrap.ts",
4347
"distDir": "dist/scripts"
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import Status from "./status_new/page.vue";
2+
import {createApp} from "vue";
3+
import WithSuspense from "../components/with-suspense.vue";
4+
5+
const app = createApp(WithSuspense, {
6+
component: Status,
7+
});
8+
app.mount("#app");
Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,130 @@
1+
import {getTypeString} from "../../utils/getType";
2+
3+
type CommitTypeMaster = {
4+
sha: string;
5+
parent_sha: string;
6+
pr: number;
7+
};
8+
9+
type CommitTypeRelease = {
10+
tag: string;
11+
};
12+
13+
type CommitTypeTry = {
14+
sha: string;
15+
parent_sha: string | null;
16+
pr: number;
17+
};
18+
19+
export type CommitType = CommitTypeRelease | CommitTypeMaster | CommitTypeTry;
20+
export type CommitTypeString = "Master" | "Try" | "Release";
21+
22+
export type BenchmarkRequestComplete = {
23+
commit_type: {
24+
[K in CommitTypeString]: CommitType;
25+
};
26+
commit_date: string | null;
27+
created_at: string | null;
28+
status: {
29+
Completed: {
30+
completed_at: string;
31+
duration_ms: number;
32+
};
33+
};
34+
backends: string;
35+
profile: string;
36+
};
37+
38+
export type BenchmarkRequestInProgress = {
39+
commit_type: {
40+
[K in CommitTypeString]: CommitType;
41+
};
42+
commit_date: string | null;
43+
created_at: string | null;
44+
status: "InProgress";
45+
backends: string;
46+
profiles: string;
47+
};
48+
49+
export function isMasterBenchmarkRequest(
50+
commitType: Object
51+
): commitType is {["Master"]: CommitTypeMaster} {
52+
return "Master" in commitType;
53+
}
54+
55+
export function isReleaseBenchmarkRequest(
56+
commitType: Object
57+
): commitType is {["Release"]: CommitTypeRelease} {
58+
return "Release" in commitType;
59+
}
60+
61+
export function isTryBenchmarkRequest(
62+
commitType: Object
63+
): commitType is {["Try"]: CommitTypeTry} {
64+
return "Try" in commitType;
65+
}
66+
67+
export type BenchmarkJobStatusInProgress = {
68+
started_at: string;
69+
collector_name: string;
70+
};
71+
72+
export type BenchmarkJobStatusCompleted = {
73+
started_at: string;
74+
completed_at: string;
75+
collector_name: string;
76+
success: boolean;
77+
};
78+
79+
export type BenchmarkJobStatusString = "InProgress" | "Completed";
80+
export type BenchmarkJobStatusQueued = "Queued";
81+
82+
export type BenchmarkJob = {
83+
id: number;
84+
target: string;
85+
backend: string;
86+
request_tag: string;
87+
benchmark_set: number;
88+
created_at: string;
89+
status:
90+
| BenchmarkJobStatusQueued
91+
| {
92+
[K in BenchmarkJobStatusQueued]:
93+
| BenchmarkJobStatusInProgress
94+
| BenchmarkJobStatusCompleted;
95+
};
96+
deque_counter: number;
97+
};
98+
99+
export function isQueuedBenchmarkJob(
100+
status: unknown
101+
): status is BenchmarkJobStatusQueued {
102+
return getTypeString(status) === "string";
103+
}
104+
105+
export function isInProgressBenchmarkJob(
106+
status: unknown
107+
): status is {["InProgress"]: BenchmarkJobStatusInProgress} {
108+
return getTypeString(status) === "object" && "InProgress" in status;
109+
}
110+
111+
export function isCompletedBenchmarkJob(
112+
status: unknown
113+
): status is {["Completed"]: BenchmarkJobStatusCompleted} {
114+
return getTypeString(status) === "object" && "Completed" in status;
115+
}
116+
117+
export type CollectorConfig = {
118+
name: string;
119+
target: string;
120+
benchmark_set: number;
121+
is_active: boolean;
122+
last_heartbeat_at: string;
123+
date_added: string;
124+
};
125+
126+
export type StatusResponse = {
127+
completed: [BenchmarkRequestComplete, string[]][];
128+
in_progress: [BenchmarkRequestInProgress, BenchmarkJob[]][];
129+
collector_configs: CollectorConfig[];
130+
};
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import {ref} from "vue";
2+
3+
export function useExpandedStore() {
4+
const expanded = ref(new Set());
5+
6+
function isExpanded(sha: string) {
7+
return expanded.value.has(sha);
8+
}
9+
10+
function toggleExpanded(sha: string) {
11+
if (isExpanded(sha)) {
12+
expanded.value.delete(sha);
13+
} else {
14+
expanded.value.add(sha);
15+
}
16+
}
17+
18+
return {toggleExpanded, isExpanded};
19+
}
Lines changed: 193 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,193 @@
1+
<script setup lang="ts">
2+
import {getJson} from "../../utils/requests";
3+
import {STATUS_DATA_NEW_URL} from "../../urls";
4+
import {withLoading} from "../../utils/loading";
5+
import {ref, Ref} from "vue";
6+
import {StatusResponseNew} from "./data";
7+
import {useExpandedStore} from "./expansion";
8+
9+
async function loadStatusNew(loading: Ref<boolean>) {
10+
dataNew.value = await withLoading(loading, () =>
11+
getJson<StatusResponse>(STATUS_DATA_NEW_URL)
12+
);
13+
}
14+
15+
const loading = ref(true);
16+
const dataNew: Ref<StatusResponse | null> = ref(null);
17+
18+
function statusLabel(c) {
19+
if (!c.is_active) return "Inactive";
20+
return this.isStale(c) ? "Stale" : "Active";
21+
}
22+
23+
function statusClass(c) {
24+
return c.is_active ? "active" : "inactive";
25+
}
26+
27+
loadStatusNew(loading);
28+
</script>
29+
30+
<template>
31+
<div v-if="dataNew !== null">
32+
<span>
33+
<h2>JSON from the database</h2>
34+
<code style="white-space: break-spaces">
35+
{{ JSON.stringify(dataNew, null, 2) }}
36+
</code>
37+
</span>
38+
<div id="app" class="container">
39+
<h1>Collectors</h1>
40+
41+
<div class="grid">
42+
<div
43+
v-for="c in dataNew.collector_configs"
44+
:key="c.name + c.target"
45+
class="card"
46+
>
47+
<div>
48+
<div class="header">
49+
<div class="name">{{ c.name }}:</div>
50+
<div class="status" :class="statusClass(c)">
51+
{{ c.is_active ? "Active" : "Inactive" }}
52+
</div>
53+
</div>
54+
<div class="meta">
55+
<div><strong>Target:</strong> {{ c.target }}</div>
56+
<div><strong>Benchmark Set:</strong> #{{ c.benchmark_set }}</div>
57+
<div>
58+
<strong>Last Heartbeat:</strong>
59+
{{ c.last_heartbeat_at }}
60+
</div>
61+
<div>
62+
<strong>Date Added:</strong>
63+
{{ c.date_added }}
64+
</div>
65+
</div>
66+
</div>
67+
</div>
68+
</div>
69+
</div>
70+
</div>
71+
</template>
72+
73+
<style scoped lang="scss">
74+
.timeline {
75+
max-width: 100%;
76+
width: fit-content;
77+
78+
table {
79+
border-collapse: collapse;
80+
font-size: 1.1em;
81+
82+
th,
83+
td {
84+
padding: 0.2em;
85+
}
86+
87+
th {
88+
text-align: center;
89+
}
90+
td {
91+
text-align: left;
92+
padding: 0 0.5em;
93+
94+
&.centered {
95+
text-align: center;
96+
}
97+
&.right-align {
98+
text-align: right;
99+
}
100+
}
101+
tr.active {
102+
font-weight: bold;
103+
}
104+
}
105+
106+
@media screen and (min-width: 1440px) {
107+
width: 100%;
108+
}
109+
}
110+
111+
.header {
112+
display: flex;
113+
align-items: center;
114+
}
115+
116+
.status {
117+
padding: 2px 8px;
118+
border-radius: 20px;
119+
font-size: 0.75rem;
120+
width: 50px;
121+
font-weight: bold;
122+
}
123+
124+
.status.active {
125+
color: green;
126+
}
127+
.status.inactive {
128+
color: red;
129+
}
130+
131+
.wrapper {
132+
display: grid;
133+
column-gap: 100px;
134+
grid-template-columns: 1fr;
135+
136+
@media screen and (min-width: 1440px) {
137+
grid-template-columns: 4fr 6fr;
138+
}
139+
}
140+
.current {
141+
max-width: 100%;
142+
width: fit-content;
143+
144+
.benchmark {
145+
margin-bottom: 10px;
146+
font-size: 1.2em;
147+
}
148+
}
149+
.column-centered {
150+
display: flex;
151+
flex-direction: column;
152+
align-items: center;
153+
}
154+
.current-table {
155+
border-collapse: collapse;
156+
font-size: 1.1em;
157+
158+
td,
159+
th {
160+
padding: 0 10px;
161+
}
162+
tbody > tr {
163+
td {
164+
padding-top: 5px;
165+
text-align: center;
166+
}
167+
}
168+
}
169+
.aligned {
170+
text-align: right;
171+
}
172+
.error {
173+
padding: 10px;
174+
background-color: #f7f7f7;
175+
max-width: 100%;
176+
white-space: pre-wrap;
177+
word-break: break-word;
178+
}
179+
.grid {
180+
display: grid;
181+
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
182+
gap: 20px;
183+
}
184+
.card {
185+
border-radius: 12px;
186+
padding: 16px;
187+
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.4);
188+
display: flex;
189+
flex-direction: column;
190+
justify-content: space-between;
191+
transition: transform 0.2s ease;
192+
}
193+
</style>

site/frontend/src/urls.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ export const INFO_URL = `${BASE_URL}/info`;
44

55
export const DASHBOARD_DATA_URL = `${BASE_URL}/dashboard`;
66
export const STATUS_DATA_URL = `${BASE_URL}/status_page`;
7+
export const STATUS_DATA_NEW_URL = `${BASE_URL}/status_page_new`;
78
export const BOOTSTRAP_DATA_URL = `${BASE_URL}/bootstrap`;
89
export const GRAPH_DATA_URL = `${BASE_URL}/graphs`;
910
export const COMPARE_DATA_URL = `${BASE_URL}/get`;

site/frontend/src/utils/getType.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
export function getTypeString(obj: any): string {
2+
return Object.prototype.toString
3+
.call(obj)
4+
.toLowerCase()
5+
.replace("[", "")
6+
.replace("]", "")
7+
.split(" ")[1];
8+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
{% extends "layout.html" %}
2+
{% block head %}
3+
<link rel="stylesheet" type="text/css" href="scripts/status_new.css">
4+
{% endblock %}
5+
{% block content %}
6+
<div id="app"></div>
7+
{% endblock %}
8+
{% block script %}
9+
<script src="scripts/status_new.js"></script>
10+
{% endblock %}

0 commit comments

Comments
 (0)