|
17 | 17 | import stripAnsi from "strip-ansi"
|
18 | 18 | import type { TextProps } from "ink"
|
19 | 19 |
|
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" |
24 | 22 |
|
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" |
63 | 24 |
|
64 | 25 | /**
|
65 | 26 | * Maintain a model of live data from a given set of file streams
|
66 | 27 | * (`tails`), and pump it into the given `cb` callback.
|
67 | 28 | *
|
68 | 29 | */
|
69 |
| -class Live { |
| 30 | +export default class Live { |
70 | 31 | /** Model of status per worker */
|
71 | 32 | private readonly workers: Record<string, Worker> = {}
|
72 | 33 |
|
@@ -210,77 +171,3 @@ class Live {
|
210 | 171 | )
|
211 | 172 | }
|
212 | 173 | }
|
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 |
| -} |
0 commit comments