Skip to content

Commit 185613a

Browse files
committed
chore: refactor dashboard controllers
1 parent cd881dc commit 185613a

File tree

12 files changed

+343
-218
lines changed

12 files changed

+343
-218
lines changed

plugins/plugin-codeflare-dashboard/src/controller/dashboard/grids.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@
1515
*/
1616

1717
import type Kind from "./kinds.js"
18-
import type { ValidTheme as ValidUtilizationTheme } from "./themes/utilization.js"
18+
import type { ValidTheme as ValidUtilizationTheme } from "./utilization/theme.js"
1919

2020
export type SupportedUtilizationGrid = "cpu%" | "mem%" | "gpu%" | "gpumem%"
2121

plugins/plugin-codeflare-dashboard/src/controller/dashboard/index.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ import type { Arguments } from "@kui-shell/core"
1818

1919
import tailf from "./tailf.js"
2020
import dashboardUI from "./db.js"
21-
import status from "./status.js"
22-
import utilization from "./utilization.js"
21+
import status from "./status/index.js"
22+
import utilization from "./utilization/index.js"
2323
import { SupportedGrid, isSupportedGrid } from "./grids.js"
2424
import { KindA, isValidKindA, validKinds } from "./kinds.js"
2525
import type { GridSpec } from "../../components/Dashboard/types.js"
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
/*
2+
* Copyright 2023 The Kubernetes Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import type { TextProps } from "ink"
18+
19+
import type { OnData } from "../../../components/Dashboard/types.js"
20+
21+
import { WorkerState, states } from "./states.js"
22+
23+
/** A blinking lights demo that pumps random data into the UI */
24+
export default class Demo {
25+
private readonly interval: ReturnType<typeof setInterval>
26+
27+
public constructor(cb: OnData, styleOf: Record<WorkerState, TextProps>) {
28+
const randoState = () => states[Math.round(Math.random() * states.length) % states.length]
29+
30+
// the model, filled initially with random data
31+
let workers = Array(50)
32+
.fill(1)
33+
.map((_, idx) => {
34+
const metric = randoState()
35+
return { name: String(idx), metric, firstUpdate: Date.now(), lastUpdate: Date.now(), style: styleOf[metric] }
36+
})
37+
38+
// initial callback to the UI
39+
cb({ workers })
40+
41+
// periodically, change a random number of worker states, randomly
42+
this.interval = setInterval(() => {
43+
const nChanged = Math.max(1, Math.min(Math.floor(Math.random() * 8), workers.length))
44+
for (let idx = 0; idx < nChanged; idx++) {
45+
const metric = randoState()
46+
const idx = Math.round(Math.random() * workers.length) % workers.length
47+
48+
workers = [
49+
...workers.slice(0, idx),
50+
Object.assign(workers[idx], { metric, lastUpdate: Date.now(), style: styleOf[metric] }),
51+
...workers.slice(idx + 1),
52+
]
53+
}
54+
55+
// periodic callback to the UI
56+
cb({ workers })
57+
}, 1000)
58+
}
59+
60+
public quit() {
61+
clearInterval(this.interval)
62+
}
63+
}

plugins/plugin-codeflare-dashboard/src/controller/dashboard/status.tsx renamed to plugins/plugin-codeflare-dashboard/src/controller/dashboard/status/Live.ts

+4-117
Original file line numberDiff line numberDiff line change
@@ -17,56 +17,17 @@
1717
import stripAnsi from "strip-ansi"
1818
import type { TextProps } from "ink"
1919

20-
import type { Tail } from "./tailf.js"
21-
import type Options from "./options.js"
22-
import type { OnData, Worker, GridSpec } from "../../components/Dashboard/types.js"
23-
import { isValidStatusTheme, statusThemes } from "./themes/status.js"
20+
import type { Tail } from "../tailf.js"
21+
import type { OnData, Worker } from "../../../components/Dashboard/types.js"
2422

25-
type WorkerState = "Queued" | "Provisioning" | "Initializing" | "Running" | "Success" | "Failed"
26-
27-
const states: WorkerState[] = ["Queued", "Provisioning", "Initializing", "Running", "Success", "Failed"]
28-
29-
const stateFor: Record<string, WorkerState> = {
30-
Pending: "Queued",
31-
Queued: "Queued",
32-
Job_Pending: "Initializing", // this comes after the job is submitted, but probably preparing deps
33-
34-
ContainerCreating: "Provisioning",
35-
SuccessfulCreate: "Provisioning",
36-
AddedInterface: "Provisioning",
37-
Created: "Provisioning",
38-
Scheduled: "Provisioning",
39-
40-
Unhealthy: "Provisioning", // service not yet ready... Initializing?
41-
42-
Initializing: "Initializing",
43-
Installing: "Initializing",
44-
Pulling: "Initializing",
45-
Pulled: "Initializing",
46-
47-
Started: "Initializing",
48-
Workers_Running: "Initializing",
49-
50-
Job_Running: "Running",
51-
52-
Success: "Success",
53-
Succeeded: "Success",
54-
55-
// ignore these
56-
// Workers_Terminating: "Success",
57-
// Workers_Killing: "Success",
58-
59-
Failed: "Failed",
60-
FailedScheduling: "Failed",
61-
Workers_Evicted: "Failed",
62-
}
23+
import { WorkerState, stateFor } from "./states.js"
6324

6425
/**
6526
* Maintain a model of live data from a given set of file streams
6627
* (`tails`), and pump it into the given `cb` callback.
6728
*
6829
*/
69-
class Live {
30+
export default class Live {
7031
/** Model of status per worker */
7132
private readonly workers: Record<string, Worker> = {}
7233

@@ -210,77 +171,3 @@ class Live {
210171
)
211172
}
212173
}
213-
214-
/** A blinking lights demo that pumps random data into the UI */
215-
class Demo {
216-
private readonly interval: ReturnType<typeof setInterval>
217-
218-
public constructor(cb: OnData, styleOf: Record<WorkerState, TextProps>) {
219-
const randoState = () => states[Math.round(Math.random() * states.length) % states.length]
220-
221-
// the model, filled initially with random data
222-
let workers = Array(50)
223-
.fill(1)
224-
.map((_, idx) => {
225-
const metric = randoState()
226-
return { name: String(idx), metric, firstUpdate: Date.now(), lastUpdate: Date.now(), style: styleOf[metric] }
227-
})
228-
229-
// initial callback to the UI
230-
cb({ workers })
231-
232-
// periodically, change a random number of worker states, randomly
233-
this.interval = setInterval(() => {
234-
const nChanged = Math.max(1, Math.min(Math.floor(Math.random() * 8), workers.length))
235-
for (let idx = 0; idx < nChanged; idx++) {
236-
const metric = randoState()
237-
const idx = Math.round(Math.random() * workers.length) % workers.length
238-
239-
workers = [
240-
...workers.slice(0, idx),
241-
Object.assign(workers[idx], { metric, lastUpdate: Date.now(), style: styleOf[metric] }),
242-
...workers.slice(idx + 1),
243-
]
244-
}
245-
246-
// periodic callback to the UI
247-
cb({ workers })
248-
}, 1000)
249-
}
250-
251-
public quit() {
252-
clearInterval(this.interval)
253-
}
254-
}
255-
256-
export default function statusDashboard(
257-
tails: Promise<Tail>[],
258-
opts: Pick<Options, "demo" | "theme" | "themeDefault">
259-
): GridSpec {
260-
const { theme: themeS = opts.themeDefault } = opts
261-
if (!isValidStatusTheme(themeS)) {
262-
throw new Error("Invalid theme: " + themeS)
263-
}
264-
265-
const theme = statusThemes[themeS]
266-
267-
const styleOf: Record<WorkerState, TextProps> = {
268-
Queued: theme[0],
269-
Provisioning: theme[1],
270-
Initializing: theme[2],
271-
Running: theme[3],
272-
Success: theme[4],
273-
Failed: theme[5],
274-
}
275-
276-
const initWatcher = (cb: OnData) => {
277-
if (opts.demo) {
278-
return new Demo(cb, styleOf)
279-
} else {
280-
return new Live(tails, cb, styleOf)
281-
}
282-
}
283-
284-
const styledStates = states.map((state) => ({ state, style: styleOf[state] }))
285-
return { title: "Worker Status", initWatcher, states: styledStates }
286-
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
/*
2+
* Copyright 2023 The Kubernetes Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
import type { TextProps } from "ink"
18+
19+
import type { Tail } from "../tailf.js"
20+
import type Options from "../options.js"
21+
import type { OnData, GridSpec } from "../../../components/Dashboard/types.js"
22+
23+
import Demo from "./Demo.js"
24+
import Live from "./Live.js"
25+
import { WorkerState, states } from "./states.js"
26+
import { isValidStatusTheme, statusThemes } from "./theme.js"
27+
28+
export default function statusDashboard(
29+
tails: Promise<Tail>[],
30+
opts: Pick<Options, "demo" | "theme" | "themeDefault">
31+
): GridSpec {
32+
const { theme: themeS = opts.themeDefault } = opts
33+
if (!isValidStatusTheme(themeS)) {
34+
throw new Error("Invalid theme: " + themeS)
35+
}
36+
37+
const theme = statusThemes[themeS]
38+
39+
const styleOf: Record<WorkerState, TextProps> = {
40+
Queued: theme[0],
41+
Provisioning: theme[1],
42+
Initializing: theme[2],
43+
Running: theme[3],
44+
Success: theme[4],
45+
Failed: theme[5],
46+
}
47+
48+
const initWatcher = (cb: OnData) => {
49+
if (opts.demo) {
50+
return new Demo(cb, styleOf)
51+
} else {
52+
return new Live(tails, cb, styleOf)
53+
}
54+
}
55+
56+
const styledStates = states.map((state) => ({ state, style: styleOf[state] }))
57+
return { title: "Worker Status", initWatcher, states: styledStates }
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
/*
2+
* Copyright 2023 The Kubernetes Authors
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
export const states = ["Queued", "Provisioning", "Initializing", "Running", "Success", "Failed"]
18+
19+
/** Type declaration for quantized utilization states */
20+
export type WorkerState = (typeof states)[number]
21+
22+
export const stateFor: Record<string, WorkerState> = {
23+
Pending: "Queued",
24+
Queued: "Queued",
25+
Job_Pending: "Initializing", // this comes after the job is submitted, but probably preparing deps
26+
27+
ContainerCreating: "Provisioning",
28+
SuccessfulCreate: "Provisioning",
29+
AddedInterface: "Provisioning",
30+
Created: "Provisioning",
31+
Scheduled: "Provisioning",
32+
33+
Unhealthy: "Provisioning", // service not yet ready... Initializing?
34+
35+
Initializing: "Initializing",
36+
Installing: "Initializing",
37+
Pulling: "Initializing",
38+
Pulled: "Initializing",
39+
40+
Started: "Initializing",
41+
Workers_Running: "Initializing",
42+
43+
Job_Running: "Running",
44+
45+
Success: "Success",
46+
Succeeded: "Success",
47+
48+
// ignore these
49+
// Workers_Terminating: "Success",
50+
// Workers_Killing: "Success",
51+
52+
Failed: "Failed",
53+
FailedScheduling: "Failed",
54+
Workers_Evicted: "Failed",
55+
}

0 commit comments

Comments
 (0)