Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 1c9677d

Browse files
authored
Template delete button/kira pilot (#4992)
* removed button * ripped out delete dialog * fixed tests * added error message back * redirecting after success
1 parent 0eed533 commit 1c9677d

File tree

11 files changed

+253
-190
lines changed

11 files changed

+253
-190
lines changed

site/src/components/TemplateLayout/TemplateLayout.tsx

Lines changed: 49 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,6 @@ import { makeStyles } from "@material-ui/core/styles"
55
import AddCircleOutline from "@material-ui/icons/AddCircleOutline"
66
import SettingsOutlined from "@material-ui/icons/SettingsOutlined"
77
import { useMachine, useSelector } from "@xstate/react"
8-
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne"
9-
import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog"
10-
import { DeleteButton } from "components/DropdownButton/ActionCtas"
11-
import { DropdownButton } from "components/DropdownButton/DropdownButton"
128
import {
139
PageHeader,
1410
PageHeaderSubtitle,
@@ -22,12 +18,7 @@ import {
2218
Suspense,
2319
useContext,
2420
} from "react"
25-
import {
26-
Link as RouterLink,
27-
Navigate,
28-
NavLink,
29-
useParams,
30-
} from "react-router-dom"
21+
import { Link as RouterLink, NavLink, useParams } from "react-router-dom"
3122
import { combineClasses } from "util/combineClasses"
3223
import { firstLetter } from "util/firstLetter"
3324
import { selectPermissions } from "xServices/auth/authSelectors"
@@ -36,8 +27,8 @@ import {
3627
TemplateContext,
3728
templateMachine,
3829
} from "xServices/template/templateXService"
39-
import { Margins } from "../../components/Margins/Margins"
40-
import { Stack } from "../../components/Stack/Stack"
30+
import { Margins } from "components/Margins/Margins"
31+
import { Stack } from "components/Stack/Stack"
4132
import { Permissions } from "xServices/auth/authXService"
4233
import { Loader } from "components/Loader/Loader"
4334

@@ -76,11 +67,40 @@ export const useTemplateLayoutContext = (): TemplateLayoutContextValue => {
7667
return context
7768
}
7869

70+
const TemplateSettingsButton: FC<{ templateName: string }> = ({
71+
templateName,
72+
}) => (
73+
<Link
74+
underline="none"
75+
component={RouterLink}
76+
to={`/templates/${templateName}/settings`}
77+
>
78+
<Button variant="outlined" startIcon={<SettingsOutlined />}>
79+
{Language.settingsButton}
80+
</Button>
81+
</Link>
82+
)
83+
84+
const CreateWorkspaceButton: FC<{
85+
templateName: string
86+
className?: string
87+
}> = ({ templateName, className }) => (
88+
<Link
89+
underline="none"
90+
component={RouterLink}
91+
to={`/templates/${templateName}/workspace`}
92+
>
93+
<Button className={className ?? ""} startIcon={<AddCircleOutline />}>
94+
{Language.createButton}
95+
</Button>
96+
</Link>
97+
)
98+
7999
export const TemplateLayout: FC<PropsWithChildren> = ({ children }) => {
80100
const styles = useStyles()
81101
const organizationId = useOrganizationId()
82102
const templateName = useTemplateName()
83-
const [templateState, templateSend] = useMachine(templateMachine, {
103+
const [templateState, _] = useMachine(templateMachine, {
84104
context: {
85105
templateName,
86106
organizationId,
@@ -103,67 +123,32 @@ export const TemplateLayout: FC<PropsWithChildren> = ({ children }) => {
103123
!templateDAUs ||
104124
!templatePermissions
105125

106-
if (templateState.matches("deleted")) {
107-
return <Navigate to="/templates" />
108-
}
109-
110126
const hasIcon = template && template.icon && template.icon !== ""
111127

112-
const createWorkspaceButton = (className?: string) => (
113-
<Link
114-
underline="none"
115-
component={RouterLink}
116-
to={`/templates/${templateName}/workspace`}
117-
>
118-
<Button
119-
className={className ?? ""}
120-
startIcon={<AddCircleOutline />}
121-
disabled={isLoading}
122-
>
123-
{Language.createButton}
124-
</Button>
125-
</Link>
126-
)
128+
const generatePageHeaderActions = (): JSX.Element[] => {
129+
const pageActions: JSX.Element[] = []
130+
131+
if (!isLoading && templatePermissions.canUpdateTemplate) {
132+
pageActions.push(<TemplateSettingsButton templateName={templateName} />)
133+
}
127134

128-
const handleDeleteTemplate = () => {
129-
templateSend("DELETE")
135+
if (!isLoading) {
136+
pageActions.push(<CreateWorkspaceButton templateName={templateName} />)
137+
}
138+
139+
return pageActions
130140
}
131141

132142
return (
133143
<>
134144
<Margins>
135145
<PageHeader
136146
actions={
137-
isLoading ? undefined : (
138-
<ChooseOne>
139-
<Cond condition={templatePermissions.canUpdateTemplate}>
140-
<Link
141-
underline="none"
142-
component={RouterLink}
143-
to={`/templates/${template.name}/settings`}
144-
>
145-
<Button variant="outlined" startIcon={<SettingsOutlined />}>
146-
{Language.settingsButton}
147-
</Button>
148-
</Link>
149-
150-
<DropdownButton
151-
primaryAction={createWorkspaceButton(styles.actionButton)}
152-
secondaryActions={[
153-
{
154-
action: "delete",
155-
button: (
156-
<DeleteButton handleAction={handleDeleteTemplate} />
157-
),
158-
},
159-
]}
160-
canCancel={false}
161-
/>
162-
</Cond>
163-
164-
<Cond>{createWorkspaceButton()}</Cond>
165-
</ChooseOne>
166-
)
147+
<>
148+
{generatePageHeaderActions().map((action, i) => (
149+
<div key={i}>{action}</div>
150+
))}
151+
</>
167152
}
168153
>
169154
<Stack direction="row" spacing={3} className={styles.pageTitle}>
@@ -234,31 +219,12 @@ export const TemplateLayout: FC<PropsWithChildren> = ({ children }) => {
234219
<Suspense fallback={<Loader />}>{children}</Suspense>
235220
</TemplateLayoutContext.Provider>
236221
</Margins>
237-
238-
{!isLoading && (
239-
<DeleteDialog
240-
isOpen={templateState.matches("confirmingDelete")}
241-
confirmLoading={templateState.matches("deleting")}
242-
onConfirm={() => {
243-
templateSend("CONFIRM_DELETE")
244-
}}
245-
onCancel={() => {
246-
templateSend("CANCEL_DELETE")
247-
}}
248-
entity="template"
249-
name={template.name}
250-
/>
251-
)}
252222
</>
253223
)
254224
}
255225

256226
export const useStyles = makeStyles((theme) => {
257227
return {
258-
actionButton: {
259-
border: "none",
260-
borderRadius: `${theme.shape.borderRadius}px 0px 0px ${theme.shape.borderRadius}px`,
261-
},
262228
pageTitle: {
263229
alignItems: "center",
264230
},

site/src/i18n/en/templatePage.json

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,13 @@
11
{
22
"deleteSuccess": "Template successfully deleted.",
3-
"createdVersion": "created the version"
3+
"createdVersion": "created the version",
4+
"templateSettings": {
5+
"title": "Template settings",
6+
"dangerZone": {
7+
"dangerZoneHeader": "Danger Zone",
8+
"deleteTemplateHeader": "Delete this template",
9+
"deleteTemplateCaption": "Once you delete a template, there is no going back. Please be certain.",
10+
"deleteCta": "Delete Template"
11+
}
12+
}
413
}

site/src/pages/TemplatePage/TemplateSummaryPage/TemplateSummaryPage.test.tsx

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { fireEvent, screen } from "@testing-library/react"
1+
import { screen } from "@testing-library/react"
22
import { TemplateLayout } from "components/TemplateLayout/TemplateLayout"
33
import { rest } from "msw"
44
import { ResizeObserver } from "resize-observer"
@@ -42,13 +42,6 @@ describe("TemplateSummaryPage", () => {
4242
screen.getByText(MockWorkspaceResource.name)
4343
screen.queryAllByText(`${MockTemplateVersion.name}`).length
4444
})
45-
it("allows an admin to delete a template", async () => {
46-
renderPage()
47-
const dropdownButton = await screen.findByLabelText("open-dropdown")
48-
fireEvent.click(dropdownButton)
49-
const deleteButton = await screen.findByText("Delete")
50-
expect(deleteButton).toBeDefined()
51-
})
5245
it("does not allow a member to delete a template", () => {
5346
// get member-level permissions
5447
server.use(

site/src/pages/TemplatePage/TemplateSummaryPage/TemplateSummaryPage.tsx

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ export const TemplateSummaryPage: FC = () => {
1212
activeTemplateVersion,
1313
templateResources,
1414
templateVersions,
15-
deleteTemplateError,
1615
templateDAUs,
1716
} = context
1817

@@ -31,7 +30,6 @@ export const TemplateSummaryPage: FC = () => {
3130
templateResources={templateResources}
3231
templateVersions={templateVersions}
3332
templateDAUs={templateDAUs}
34-
deleteTemplateError={deleteTemplateError}
3533
/>
3634
</>
3735
)

site/src/pages/TemplatePage/TemplateSummaryPage/TemplateSummaryPageView.tsx

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import {
55
TemplateVersion,
66
WorkspaceResource,
77
} from "api/typesGenerated"
8-
import { AlertBanner } from "components/AlertBanner/AlertBanner"
98
import { MemoizedMarkdown } from "components/Markdown/Markdown"
109
import { Stack } from "components/Stack/Stack"
1110
import { TemplateResourcesTable } from "components/TemplateResourcesTable/TemplateResourcesTable"
@@ -21,7 +20,6 @@ export interface TemplateSummaryPageViewProps {
2120
templateResources: WorkspaceResource[]
2221
templateVersions?: TemplateVersion[]
2322
templateDAUs?: TemplateDAUsResponse
24-
deleteTemplateError: Error | unknown
2523
}
2624

2725
export const TemplateSummaryPageView: FC<
@@ -32,15 +30,10 @@ export const TemplateSummaryPageView: FC<
3230
templateResources,
3331
templateVersions,
3432
templateDAUs,
35-
deleteTemplateError,
3633
}) => {
3734
const styles = useStyles()
3835
const readme = frontMatter(activeTemplateVersion.readme)
3936

40-
const deleteError = deleteTemplateError ? (
41-
<AlertBanner severity="error" error={deleteTemplateError} dismissible />
42-
) : null
43-
4437
const getStartedResources = (resources: WorkspaceResource[]) => {
4538
return resources.filter(
4639
(resource) => resource.workspace_transition === "start",
@@ -49,7 +42,6 @@ export const TemplateSummaryPageView: FC<
4942

5043
return (
5144
<Stack spacing={4}>
52-
{deleteError}
5345
<TemplateStats
5446
template={template}
5547
activeVersion={activeTemplateVersion}

site/src/pages/TemplateSettingsPage/TemplateSettingsForm.tsx

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import InputAdornment from "@material-ui/core/InputAdornment"
55
import Popover from "@material-ui/core/Popover"
66
import { makeStyles } from "@material-ui/core/styles"
77
import TextField from "@material-ui/core/TextField"
8-
import Typography from "@material-ui/core/Typography"
98
import { Template, UpdateTemplateMeta } from "api/typesGenerated"
109
import { OpenDropdown } from "components/DropdownArrows/DropdownArrows"
1110
import { FormFooter } from "components/FormFooter/FormFooter"
@@ -188,9 +187,7 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
188187
there are no validation errors for that field, display helper text.
189188
We do not use the MUI helper-text prop because it overrides the validation error */}
190189
{form.values.default_ttl_ms && !form.errors.default_ttl_ms && (
191-
<Typography variant="subtitle2">
192-
{Language.ttlHelperText(form.values.default_ttl_ms)}
193-
</Typography>
190+
<span>{Language.ttlHelperText(form.values.default_ttl_ms)}</span>
194191
)}
195192
</Stack>
196193

site/src/pages/TemplateSettingsPage/TemplateSettingsPage.test.tsx

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
validationSchema,
1111
} from "./TemplateSettingsForm"
1212
import { TemplateSettingsPage } from "./TemplateSettingsPage"
13-
import { Language as ViewLanguage } from "./TemplateSettingsPageView"
13+
import i18next from "i18next"
1414

1515
const renderTemplateSettingsPage = async () => {
1616
const renderResult = renderWithAuth(<TemplateSettingsPage />, {
@@ -61,11 +61,25 @@ const fillAndSubmitForm = async ({
6161

6262
describe("TemplateSettingsPage", () => {
6363
it("renders", async () => {
64+
const { t } = i18next
65+
const pageTitle = t("templateSettings.title", {
66+
ns: "templatePage",
67+
})
6468
await renderTemplateSettingsPage()
65-
const element = await screen.findByText(ViewLanguage.title)
69+
const element = await screen.findByText(pageTitle)
6670
expect(element).toBeDefined()
6771
})
6872

73+
it("allows an admin to delete a template", async () => {
74+
const { t } = i18next
75+
await renderTemplateSettingsPage()
76+
const deleteCta = t("templateSettings.dangerZone.deleteCta", {
77+
ns: "templatePage",
78+
})
79+
const deleteButton = await screen.findByText(deleteCta)
80+
expect(deleteButton).toBeDefined()
81+
})
82+
6983
it("succeeds", async () => {
7084
await renderTemplateSettingsPage()
7185

site/src/pages/TemplateSettingsPage/TemplateSettingsPage.tsx

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ export const TemplateSettingsPage: FC = () => {
2828
templateSettings: template,
2929
saveTemplateSettingsError,
3030
getTemplateError,
31+
deleteTemplateError,
3132
} = state.context
3233

3334
return (
@@ -41,13 +42,22 @@ export const TemplateSettingsPage: FC = () => {
4142
errors={{
4243
getTemplateError,
4344
saveTemplateSettingsError,
45+
deleteTemplateError,
4446
}}
4547
onCancel={() => {
4648
navigate(`/templates/${templateName}`)
4749
}}
4850
onSubmit={(templateSettings) => {
4951
send({ type: "SAVE", templateSettings })
5052
}}
53+
onDelete={() => {
54+
send("DELETE")
55+
}}
56+
onConfirmDelete={() => send("CONFIRM_DELETE")}
57+
onCancelDelete={() => send("CANCEL_DELETE")}
58+
isConfirmingDelete={state.matches("confirmingDelete")}
59+
isDeleting={state.matches("deleting")}
60+
isDeleted={state.matches("deleted")}
5161
/>
5262
</>
5363
)

0 commit comments

Comments
 (0)