Skip to content

Commit

Permalink
fix: Top should allow uparrown/downarrow to cycle through namespaces
Browse files Browse the repository at this point in the history
also refactors top controller into its own subdir, and refactors it into smaller files in that dir
  • Loading branch information
starpit committed Apr 19, 2023
1 parent 736cf3b commit acd51c3
Show file tree
Hide file tree
Showing 10 changed files with 577 additions and 396 deletions.
86 changes: 74 additions & 12 deletions plugins/plugin-codeflare-dashboard/src/components/Top/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,14 @@ import { emitKeypressEvents } from "readline"
import { Box, Text, render } from "ink"

import type Group from "./Group.js"
import type { OnData, UpdatePayload, ResourceSpec } from "./types.js"
import type {
Context,
ChangeContextRequest,
ChangeContextRequestHandler,
WatcherInitializer,
UpdatePayload,
ResourceSpec,
} from "./types.js"

import JobBox from "./JobBox.js"
import defaultValueFor from "./defaults.js"
Expand All @@ -32,11 +39,19 @@ type UI = {
refreshCycle?: number
}

type Props = UI & {
initWatcher: (cb: OnData) => void
}
type Props = UI &
Context /* initial context */ & {
/** UI is ready to consume model updates */
initWatcher: WatcherInitializer

/** Ui wants to change context */
changeContext: ChangeContextRequestHandler
}

type State = UI & {
/** Current watcher */
watcher: { kill(): void }

/** Model from controller */
rawModel: UpdatePayload

Expand All @@ -63,8 +78,27 @@ class Top extends React.PureComponent<Props, State> {
return ((n % d) + d) % d
}

public componentDidMount() {
this.props.initWatcher(this.onData)
/** Do we have a selected group? */
private get hasSelection() {
return this.state?.selectedGroupIdx >= 0 && this.state?.selectedGroupIdx < this.state.groups.length
}

/** Current cluster context */
private get currentContext() {
return {
cluster: this.state?.rawModel?.cluster || this.props.cluster,
namespace: this.state?.rawModel?.namespace || this.props.namespace,
}
}

/** Updated cluster context */
private updatedContext({ which }: Pick<ChangeContextRequest, "which">, next: string) {
return Object.assign(this.currentContext, which === "namespace" ? { namespace: next } : { cluster: next })
}

public async componentDidMount() {
this.setState({ watcher: await this.props.initWatcher(this.currentContext, this.onData) })

this.initRefresher()
this.initKeyboardEvents()
}
Expand Down Expand Up @@ -117,8 +151,23 @@ class Top extends React.PureComponent<Props, State> {
case "escape":
this.setState({ selectedGroupIdx: -1 })
break
case "up":
case "down":
/** Change context selection */
if (this.state?.rawModel.namespace) {
this.props
.changeContext({ which: "namespace", from: this.state.rawModel.namespace, dir: key.name })
.then((next) => {
if (next) {
this.reinit(this.updatedContext({ which: "namespace" }, next))
}
})
}
break

case "left":
case "right":
/** Change job selection */
if (this.state.groups) {
const incr = key.name === "left" ? -1 : 1
this.setState((curState) => ({
Expand All @@ -145,15 +194,33 @@ class Top extends React.PureComponent<Props, State> {
})
}

private get emptyStats(): UpdatePayload["stats"] {
return { min: { cpu: 0, mem: 0, gpu: 0 }, tot: {} }
}

private reinit(context: Context) {
if (this.state?.watcher) {
this.state?.watcher.kill()
}
this.setState({ groups: [], rawModel: Object.assign({ hosts: [], stats: this.emptyStats }, context) })
this.props.initWatcher(context, this.onData)
}

/** We have received data from the controller */
private readonly onData = (rawModel: UpdatePayload) =>
private readonly onData = (rawModel: UpdatePayload) => {
if (rawModel.cluster !== this.currentContext.cluster || rawModel.namespace !== this.currentContext.namespace) {
// this is straggler data from the prior context
return
}

this.setState((curState) => {
if (JSON.stringify(curState?.rawModel) === JSON.stringify(rawModel)) {
return null
} else {
return { rawModel, groups: this.groupBy(rawModel) }
}
})
}

private groupBy(model: UpdatePayload): State["groups"] {
return Object.values(
Expand Down Expand Up @@ -192,11 +259,6 @@ class Top extends React.PureComponent<Props, State> {
)
}

/** Do we have a selected group? */
private get hasSelection() {
return this.state?.selectedGroupIdx >= 0 && this.state?.selectedGroupIdx < this.state.groups.length
}

private mostOf({ request, limit }: ResourceSpec, defaultValue: number) {
if (request === -1 && limit === -1) {
return defaultValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,3 +65,9 @@ export type Context = {
export type UpdatePayload = Context & JobsByHost

export type OnData = (payload: UpdatePayload) => void

export type WatcherInitializer = (context: Context, cb: OnData) => Promise<{ kill(): void }>

export type ChangeContextRequest = { which: "context" | "namespace"; from: string; dir: "down" | "up" }

export type ChangeContextRequestHandler = (req: ChangeContextRequest) => Promise<string | undefined>
Loading

0 comments on commit acd51c3

Please sign in to comment.