Skip to content

Commit 5b110f8

Browse files
committed
feat: New and Delete buttons in ProfileExplorer
1 parent fb9face commit 5b110f8

File tree

4 files changed

+101
-36
lines changed

4 files changed

+101
-36
lines changed

Diff for: package-lock.json

+8-8
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Diff for: plugins/plugin-codeflare/src/components/ProfileExplorer.tsx

+64-22
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ import ProfileSelect from "./ProfileSelect"
4444
import ProfileWatcher from "../tray/watchers/profile/list"
4545
import ProfileStatusWatcher from "../tray/watchers/profile/status"
4646
import UpdateFunction from "../tray/update"
47-
import { handleReset } from "../controller/profile/actions"
47+
import { handleNew, handleDelete, handleReset } from "../controller/profile/actions"
4848

4949
import "../../web/scss/components/Dashboard/Description.scss"
5050
import "../../web/scss/components/ProfileExplorer/_index.scss"
@@ -91,16 +91,37 @@ export default class ProfileExplorer extends React.PureComponent<Props, State> {
9191
}))
9292
}
9393

94-
private readonly _handleProfileSelection = (selectedProfile: string) => {
95-
this.setState({ selectedProfile })
94+
/** If given `null`, then we will attempt to use the lastUsed profile */
95+
private readonly _handleProfileSelection = (selectedProfile: string | null) => {
96+
if (!selectedProfile && this.state.profiles) {
97+
// last used, excluding the currently selected profile
98+
const lastUsed = this.lastUsed(this.state.profiles.filter((_) => _.name !== this.state.selectedProfile))
99+
if (lastUsed) {
100+
selectedProfile = lastUsed.name
101+
}
102+
}
103+
104+
if (selectedProfile) {
105+
this.setState({ selectedProfile })
96106

97-
if (this.props.onSelectProfile) {
98-
this.props.onSelectProfile(selectedProfile)
107+
if (this.props.onSelectProfile) {
108+
this.props.onSelectProfile(selectedProfile)
109+
}
99110
}
100111
}
101112

102113
private updateDebouncer: null | ReturnType<typeof setTimeout> = null
103114

115+
private lastUsed(profiles: Profiles.Profile[]) {
116+
return profiles.slice(1).reduce((lastUsed, profile) => {
117+
if (lastUsed.lastUsedTime < profile.lastUsedTime) {
118+
return profile
119+
} else {
120+
return lastUsed
121+
}
122+
}, profiles[0])
123+
}
124+
104125
private readonly profileWatcherUpdateFn = () => {
105126
if (this.updateDebouncer) {
106127
clearTimeout(this.updateDebouncer)
@@ -122,13 +143,7 @@ export default class ProfileExplorer extends React.PureComponent<Props, State> {
122143
let selectedProfile = curState.selectedProfile
123144
if (!curState || !curState.profiles || curState.profiles.length === 0) {
124145
// use the last-used profile by default
125-
const newSelectedProfile = profiles.slice(1).reduce((lastUsed, profile) => {
126-
if (lastUsed.lastUsedTime < profile.lastUsedTime) {
127-
return profile
128-
} else {
129-
return lastUsed
130-
}
131-
}, profiles[0])
146+
const newSelectedProfile = this.lastUsed(profiles)
132147

133148
// also emit an initial profile selection event
134149
if (newSelectedProfile) {
@@ -223,17 +238,14 @@ type ProfileCardProps = Partial<Diff> &
223238
Pick<Props, "onSelectGuidebook"> & {
224239
profile: string
225240
profiles: Profiles.Profile[]
226-
onSelectProfile: (profile: string) => void
241+
onSelectProfile: (profile: string | null) => void
227242

228243
profileReadiness: string
229244
profileStatus: ProfileStatusWatcher
230245
}
231246

232247
type ProfileCardState = {
233248
isOpen: boolean
234-
235-
/** Clear any "just changed" indicators after a brief delay */
236-
// clearDiff?: ReturnType<typeof setTimeout>
237249
}
238250

239251
class ProfileCard extends React.PureComponent<ProfileCardProps, ProfileCardState> {
@@ -243,7 +255,24 @@ class ProfileCard extends React.PureComponent<ProfileCardProps, ProfileCardState
243255
isOpen: false,
244256
}
245257
}
246-
private readonly _handleReset = () => handleReset(this.props.profile)
258+
259+
/** Create new profile */
260+
private readonly _handleNew = async () => {
261+
if (this.props.profile) {
262+
const newProfile = await handleNew(this.props.profile, this.props.profiles)
263+
this.props.onSelectProfile(newProfile)
264+
}
265+
}
266+
267+
/** Delete selected profile */
268+
private readonly _handleDelete = async () => {
269+
if (this.props.profile) {
270+
await handleDelete(this.props.profile)
271+
this.props.onSelectProfile(null)
272+
}
273+
}
274+
275+
private readonly _handleReset = () => this.props.profile && handleReset(this.props.profile)
247276
// private readonly _handleBoot = () => handleBoot(this.props.profile)
248277
// private readonly _handleShutdown = () => handleShutdown(this.props.profile)
249278
private readonly _onToggle = () => this.setState({ isOpen: !this.state.isOpen })
@@ -454,7 +483,7 @@ class ProfileCard extends React.PureComponent<ProfileCardProps, ProfileCardState
454483
return <TreeView hasGuides defaultAllExpanded data={data} variant="compactNoBackground" />
455484
}
456485

457-
return "Internal Error"
486+
return <Loading />
458487
}
459488

460489
private sort(data: TreeViewDataItem[]) {
@@ -472,11 +501,24 @@ class ProfileCard extends React.PureComponent<ProfileCardProps, ProfileCardState
472501
private footer() {
473502
return (
474503
<Flex>
475-
<FlexItem flex={{ default: "flex_1" }}></FlexItem>
504+
<FlexItem flex={{ default: "flex_1" }}>
505+
<Tooltip content="Create a new profile">
506+
<Button variant="control" className="codeflare--profile-explorer--new-btn" onClick={this._handleNew}>
507+
<Icons icon="PlusSquare" />
508+
</Button>
509+
</Tooltip>
510+
</FlexItem>
476511
<FlexItem>
477-
<Button variant="link" isSmall className="codeflare--profile-explorer--reset-btn" onClick={this._handleReset}>
478-
Reset
479-
</Button>
512+
<Tooltip content="Reset the choices in this profile">
513+
<Button variant="link" className="codeflare--profile-explorer--reset-btn" onClick={this._handleReset}>
514+
Reset
515+
</Button>
516+
</Tooltip>
517+
<Tooltip content="Delete this profile">
518+
<Button variant="link" className="codeflare--profile-explorer--delete-btn" onClick={this._handleDelete}>
519+
<Icons icon="Trash" />
520+
</Button>
521+
</Tooltip>
480522
</FlexItem>
481523
{/*<FlexItem>
482524
<Button variant="link" isSmall className="codeflare--profile-explorer--boot-btn" onClick={this._handleBoot}>

Diff for: plugins/plugin-codeflare/src/controller/profile/actions.ts

+28-5
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,34 @@ export async function openWindow(title: string, initialTabTitle: string, argv: (
3232
)
3333
}
3434

35-
export async function handleReset(selectedProfile: string | undefined) {
36-
if (selectedProfile) {
37-
const { Profiles } = await import("madwizard")
38-
await Profiles.reset({}, selectedProfile)
39-
}
35+
/** Delete the given profile */
36+
export async function handleDelete(selectedProfile: string) {
37+
const { Profiles } = await import("madwizard")
38+
await Profiles.remove({}, selectedProfile)
39+
}
40+
41+
/** Create a new profile */
42+
export async function handleNew(selectedProfile: string, profiles: import("madwizard").Profiles.Profile[]) {
43+
const { Profiles } = await import("madwizard")
44+
45+
const defaults = profiles
46+
.map((_) => _.name.match(/default-?(\d+)?/))
47+
.filter(Boolean)
48+
.map((_) => (_ && _[1] ? parseInt(_[1], 10) : 0))
49+
defaults.sort((a, b) => b - a)
50+
51+
const name = defaults.length === 0 ? "default" : `default-${defaults[0] + 1}`
52+
await Profiles.clone({}, selectedProfile, name)
53+
await Profiles.reset({}, name)
54+
await Profiles.touch({}, name)
55+
56+
return name
57+
}
58+
59+
/** Reset the choices of the given profile */
60+
export async function handleReset(selectedProfile: string) {
61+
const { Profiles } = await import("madwizard")
62+
await Profiles.reset({}, selectedProfile)
4063
}
4164

4265
export function handleBoot(selectedProfile: string | undefined) {

Diff for: plugins/plugin-madwizard/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
"access": "public"
2424
},
2525
"dependencies": {
26-
"madwizard": "^1.2.0",
26+
"madwizard": "^1.3.1",
2727
"@guidebooks/store": "^0.14.3"
2828
}
2929
}

0 commit comments

Comments
 (0)