Skip to content

Commit 6c2e5ca

Browse files
committed
fix: selected profiles in the ProfileExplorer are erratic
1 parent 2b6a3fd commit 6c2e5ca

File tree

4 files changed

+55
-56
lines changed

4 files changed

+55
-56
lines changed

plugins/plugin-codeflare/src/components/ProfileExplorer.tsx

Lines changed: 20 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616

1717
import React from "react"
18-
import { EventEmitter } from "events"
1918
import { Profiles } from "madwizard"
2019
import { Loading } from "@kui-shell/plugin-client-common"
2120
import {
@@ -44,22 +43,10 @@ import { handleBoot, handleShutdown } from "../controller/profile/actions"
4443
import "../../web/scss/components/Dashboard/Description.scss"
4544
import "../../web/scss/components/ProfileExplorer/_index.scss"
4645

47-
const events = new EventEmitter()
48-
49-
function emitSelectProfile(profile: string) {
50-
events.emit("/profile/select", profile)
51-
}
52-
53-
export function onSelectProfile(cb: (profile: string) => void) {
54-
events.on("/profile/select", cb)
55-
}
56-
57-
export function offSelectProfile(cb: (profile: string) => void) {
58-
events.off("/profile/select", cb)
46+
type Props = {
47+
onSelectProfile?(profile: string): void
5948
}
6049

61-
type Props = Record<string, never>
62-
6350
type State = {
6451
watcher: ProfileWatcher
6552
selectedProfile?: string
@@ -75,7 +62,10 @@ export default class ProfileExplorer extends React.PureComponent<Props, State> {
7562

7663
private readonly _handleProfileSelection = (selectedProfile: string) => {
7764
this.setState({ selectedProfile })
78-
emitSelectProfile(selectedProfile)
65+
66+
if (this.props.onSelectProfile) {
67+
this.props.onSelectProfile(selectedProfile)
68+
}
7969
}
8070

8171
private updateDebouncer: null | ReturnType<typeof setTimeout> = null
@@ -99,14 +89,22 @@ export default class ProfileExplorer extends React.PureComponent<Props, State> {
9989

10090
let selectedProfile = curState.selectedProfile
10191
if (!curState || !curState.profiles || curState.profiles.length === 0) {
102-
// sort the first time we get a list of profiles; TODO should
103-
// we re-sort if the list changes? what we want to avoid is
104-
// resorting simply because the selection changed
105-
profiles.sort((a, b) => b.lastUsedTime - a.lastUsedTime)
92+
// use the last-used profile by default
93+
const newSelectedProfile = profiles.slice(1).reduce((lastUsed, profile) => {
94+
if (lastUsed.lastUsedTime < profile.lastUsedTime) {
95+
return profile
96+
} else {
97+
return lastUsed
98+
}
99+
}, profiles[0])
106100

107101
// also emit an initial profile selection event
108-
selectedProfile = profiles[0].name
109-
emitSelectProfile(selectedProfile)
102+
if (newSelectedProfile) {
103+
selectedProfile = newSelectedProfile.name
104+
if (this.props.onSelectProfile) {
105+
this.props.onSelectProfile(newSelectedProfile.name)
106+
}
107+
}
110108
}
111109

112110
return {

plugins/plugin-codeflare/src/components/RestartableTerminal.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,8 +70,10 @@ export default class RestartableTerminal extends React.PureComponent<Props, Stat
7070
env: this.props.env,
7171
quiet: true, // strange i know, but this forces PTY execution
7272
onExit: () => {
73-
// restart
74-
this.initPty()
73+
if (this.mounted) {
74+
// restart, if still mounted
75+
this.initPty()
76+
}
7577
},
7678
onInit: () => (_) => {
7779
// hooks pty output to our passthrough stream

plugins/plugin-codeflare/src/components/SelectedProfileTerminal.tsx

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -15,47 +15,32 @@
1515
*/
1616

1717
import React from "react"
18-
import { Loading } from "@kui-shell/plugin-client-common"
1918

2019
import RestartableTerminal, { Props } from "./RestartableTerminal"
21-
import { onSelectProfile, offSelectProfile } from "./ProfileExplorer"
20+
21+
type MyProps = Props & {
22+
selectedProfile: string
23+
}
2224

2325
type State = {
24-
cmdline?: string
26+
cmdline: string
2527
}
2628

27-
export default class SelectedProfileTerminal extends React.PureComponent<Props, State> {
29+
export default class SelectedProfileTerminal extends React.PureComponent<MyProps, State> {
2830
public static readonly selectedProfilePattern = /\$\{SELECTED_PROFILE\}/g
2931

30-
public constructor(props: Props) {
32+
public constructor(props: MyProps) {
3133
super(props)
32-
onSelectProfile(this.onSelect)
33-
// this.init()
34-
}
35-
36-
public componentWillUnmount() {
37-
offSelectProfile(this.onSelect)
38-
}
39-
40-
private readonly onSelect = async (selectedProfile: string) => {
41-
const cmdline = await this.cmdline(selectedProfile)
42-
this.setState({ cmdline })
34+
this.state = {
35+
cmdline: this.cmdline(props.selectedProfile),
36+
}
4337
}
4438

45-
/* private async init() {
46-
const cmdline = await this.cmdline()
47-
this.setState({ cmdline })
48-
} */
49-
50-
private async cmdline(selectedProfile: string) {
39+
private cmdline(selectedProfile: string) {
5140
return this.props.cmdline.replace(SelectedProfileTerminal.selectedProfilePattern, selectedProfile)
5241
}
5342

5443
public render() {
55-
if (!this.state || !this.state.cmdline) {
56-
return <Loading />
57-
} else {
58-
return <RestartableTerminal key={this.state.cmdline} {...this.props} cmdline={this.state.cmdline} />
59-
}
44+
return <RestartableTerminal key={this.state.cmdline} {...this.props} cmdline={this.state.cmdline} />
6045
}
6146
}

plugins/plugin-codeflare/src/controller/terminal.tsx

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
import React from "react"
1818
import { Allotment } from "allotment"
19+
import { Loading } from "@kui-shell/plugin-client-common"
1920
import { Arguments, encodeComponent } from "@kui-shell/core"
2021

2122
import respawn from "./respawn"
@@ -42,8 +43,11 @@ export function shell(args: Arguments) {
4243
}
4344

4445
type Props = Pick<BaseProps, "tab" | "repl">
45-
type State = Pick<BaseProps, "cmdline" | "env"> & { error?: boolean }
46+
type State = Pick<BaseProps, "cmdline" | "env"> & { error?: boolean; selectedProfile?: string }
4647
class TaskTerminal extends React.PureComponent<Props, State> {
48+
/** Allotment initial split sizes */
49+
private readonly sizes = [35, 65]
50+
4751
private readonly tasks = [{ label: "Run a Job", argv: ["codeflare", "-p", "${SELECTED_PROFILE}"] }]
4852

4953
public constructor(props: Props) {
@@ -59,26 +63,36 @@ class TaskTerminal extends React.PureComponent<Props, State> {
5963
}
6064
}
6165

66+
private readonly onSelectProfile = (selectedProfile: string) => this.setState({ selectedProfile })
67+
6268
public static getDerivedStateFromError() {
6369
return { error: true }
6470
}
6571
public componentDidCatch(error: Error, errorInfo: React.ErrorInfo) {
6672
console.error("catastrophic error", error, errorInfo)
6773
}
6874

69-
private readonly sizes = [35, 65]
70-
7175
public render() {
7276
if (this.state.error) {
7377
return "Internal Error"
7478
}
7579
return (
7680
<Allotment defaultSizes={this.sizes} snap>
7781
<Allotment.Pane className="flex-fill flex-layout flex-align-stretch" minSize={400}>
78-
<ProfileExplorer />
82+
<ProfileExplorer onSelectProfile={this.onSelectProfile} />
7983
</Allotment.Pane>
8084
<Allotment.Pane className="flex-fill flex-layout flex-align-stretch">
81-
<SelectedProfileTerminal cmdline={this.state.cmdline} env={this.state.env} {...this.props} />
85+
{!this.state.selectedProfile ? (
86+
<Loading />
87+
) : (
88+
<SelectedProfileTerminal
89+
key={this.state.cmdline + "-" + this.state.selectedProfile}
90+
cmdline={this.state.cmdline}
91+
env={this.state.env}
92+
{...this.props}
93+
selectedProfile={this.state.selectedProfile}
94+
/>
95+
)}
8296
</Allotment.Pane>
8397
</Allotment>
8498
)

0 commit comments

Comments
 (0)