Skip to content

Commit a259e97

Browse files
committed
feat: update profiles ui component to use profile watching logic
We already had this profile watching logic for the tray menu. This PR updates the profiles UI component to use the same.
1 parent bac2c29 commit a259e97

File tree

3 files changed

+88
-29
lines changed

3 files changed

+88
-29
lines changed

plugins/plugin-codeflare/src/controller/profile/get.tsx

Lines changed: 74 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,34 +17,87 @@
1717
import React from "react"
1818
import prettyMillis from "pretty-ms"
1919
import { Profiles } from "madwizard"
20+
import { Loading } from "@kui-shell/plugin-client-common"
2021
import { Grid, GridItem, Tile } from "@patternfly/react-core"
2122

23+
import ProfileWatcher from "../../tray/watchers/profile/list"
24+
2225
import PlusIcon from "@patternfly/react-icons/dist/esm/icons/user-plus-icon"
2326
import ProfileIcon from "@patternfly/react-icons/dist/esm/icons/user-icon"
2427

28+
type Props = Record<string, never>
29+
30+
type State = {
31+
watcher: ProfileWatcher
32+
profiles: Profiles.Profile[]
33+
catastrophicError?: unknown
34+
}
35+
36+
class ProfileExplorer extends React.PureComponent<Props, State> {
37+
public constructor(props: Props) {
38+
super(props)
39+
this.init()
40+
}
41+
42+
private readonly updateFn = () => {
43+
// slice to force a render; TODO we could do a comparison to avoid
44+
// false re-renders if we want to get fancy
45+
this.setState((curState) => ({
46+
profiles: curState.watcher.profiles.slice(),
47+
}))
48+
}
49+
50+
private async init() {
51+
try {
52+
const watcher = await new ProfileWatcher(this.updateFn, await Profiles.profilesPath({}, true)).init()
53+
this.setState({
54+
watcher,
55+
profiles: [],
56+
})
57+
} catch (err) {
58+
console.error(err)
59+
this.setState({ catastrophicError: err })
60+
}
61+
}
62+
63+
public componentWillUnmount() {
64+
if (this.state && this.state.watcher) {
65+
this.state.watcher.close()
66+
}
67+
}
68+
69+
public render() {
70+
if (this.state && this.state.catastrophicError) {
71+
return "Internal Error"
72+
} else if (!this.state || !this.state.profiles) {
73+
return <Loading />
74+
} else {
75+
return (
76+
<Grid className="codeflare--gallery-grid flex-fill sans-serif top-pad left-pad right-pad bottom-pad" hasGutter>
77+
{this.state.profiles.map((_) => (
78+
<GridItem key={_.name}>
79+
<Tile className="codeflare--tile" title={_.name} icon={<ProfileIcon />} isStacked>
80+
{`Last used ${prettyMillis(Date.now() - _.lastUsedTime, { compact: true })} ago`}
81+
</Tile>
82+
</GridItem>
83+
))}
84+
85+
{
86+
<GridItem>
87+
<Tile className="codeflare--tile codeflare--tile-new" title="New Profile" icon={<PlusIcon />} isStacked>
88+
Customize a profile
89+
</Tile>
90+
</GridItem>
91+
}
92+
</Grid>
93+
)
94+
}
95+
}
96+
}
97+
2598
// eslint-disable-next-line @typescript-eslint/no-unused-vars
2699
export default async function getProfiles() {
27-
const profiles = await Profiles.list({})
28-
29100
return {
30-
react: (
31-
<Grid className="codeflare--gallery-grid flex-fill sans-serif top-pad left-pad right-pad bottom-pad" hasGutter>
32-
{profiles.map((_) => (
33-
<GridItem key={_.profile.name}>
34-
<Tile className="codeflare--tile" title={_.profile.name} icon={<ProfileIcon />} isStacked>
35-
{`Last used ${prettyMillis(Date.now() - _.profile.lastUsedTime, { compact: true })} ago`}
36-
</Tile>
37-
</GridItem>
38-
))}
39-
40-
{
41-
<GridItem>
42-
<Tile className="codeflare--tile codeflare--tile-new" title="New Profile" icon={<PlusIcon />} isStacked>
43-
Customize a profile
44-
</Tile>
45-
</GridItem>
46-
}
47-
</Grid>
48-
),
101+
react: <ProfileExplorer />,
49102
}
50103
}

plugins/plugin-codeflare/src/tray/menus/profiles/index.ts

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,16 @@ export default async function profilesMenu(
5656
): Promise<MenuItemConstructorOptions[]> {
5757
if (!watcher) {
5858
watcher = new ProfileWatcher(updateFn, await Profiles.profilesPath({}, true))
59+
60+
// we need to close the chokidar watcher before exit, otherwise
61+
// electron-main dies with SIGABRT
62+
import("electron").then((_) =>
63+
_.app.on("will-quit", async () => {
64+
if (watcher) {
65+
await watcher.close()
66+
}
67+
})
68+
)
5969
}
6070

6171
// one-time initialization of the watcher, if needed; we need to do

plugins/plugin-codeflare/src/tray/watchers/profile/list.ts

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,14 +32,10 @@ export default class ProfileWatcher {
3232
private readonly updateFn: UpdateFunction,
3333
private readonly profilesPath: string,
3434
private readonly watcher = chokidar.watch(profilesPath, { depth: 1 })
35-
) {
36-
// we need to close the chokidar watcher before exit, otherwise
37-
// electron-main dies with SIGABRT
38-
import("electron").then((_) =>
39-
_.app.on("will-quit", async () => {
40-
await this.watcher.close()
41-
})
42-
)
35+
) {}
36+
37+
public async close() {
38+
await this.watcher.close()
4339
}
4440

4541
/** Initialize `this._profiles` model */

0 commit comments

Comments
 (0)