Skip to content

Commit

Permalink
Template delete button/kira pilot (#4992)
Browse files Browse the repository at this point in the history
* removed button

* ripped out delete dialog

* fixed tests

* added error message back

* redirecting after success
  • Loading branch information
Kira-Pilot committed Nov 10, 2022
1 parent 0eed533 commit 1c9677d
Show file tree
Hide file tree
Showing 11 changed files with 253 additions and 190 deletions.
132 changes: 49 additions & 83 deletions site/src/components/TemplateLayout/TemplateLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,6 @@ import { makeStyles } from "@material-ui/core/styles"
import AddCircleOutline from "@material-ui/icons/AddCircleOutline"
import SettingsOutlined from "@material-ui/icons/SettingsOutlined"
import { useMachine, useSelector } from "@xstate/react"
import { ChooseOne, Cond } from "components/Conditionals/ChooseOne"
import { DeleteDialog } from "components/Dialogs/DeleteDialog/DeleteDialog"
import { DeleteButton } from "components/DropdownButton/ActionCtas"
import { DropdownButton } from "components/DropdownButton/DropdownButton"
import {
PageHeader,
PageHeaderSubtitle,
Expand All @@ -22,12 +18,7 @@ import {
Suspense,
useContext,
} from "react"
import {
Link as RouterLink,
Navigate,
NavLink,
useParams,
} from "react-router-dom"
import { Link as RouterLink, NavLink, useParams } from "react-router-dom"
import { combineClasses } from "util/combineClasses"
import { firstLetter } from "util/firstLetter"
import { selectPermissions } from "xServices/auth/authSelectors"
Expand All @@ -36,8 +27,8 @@ import {
TemplateContext,
templateMachine,
} from "xServices/template/templateXService"
import { Margins } from "../../components/Margins/Margins"
import { Stack } from "../../components/Stack/Stack"
import { Margins } from "components/Margins/Margins"
import { Stack } from "components/Stack/Stack"
import { Permissions } from "xServices/auth/authXService"
import { Loader } from "components/Loader/Loader"

Expand Down Expand Up @@ -76,11 +67,40 @@ export const useTemplateLayoutContext = (): TemplateLayoutContextValue => {
return context
}

const TemplateSettingsButton: FC<{ templateName: string }> = ({
templateName,
}) => (
<Link
underline="none"
component={RouterLink}
to={`/templates/${templateName}/settings`}
>
<Button variant="outlined" startIcon={<SettingsOutlined />}>
{Language.settingsButton}
</Button>
</Link>
)

const CreateWorkspaceButton: FC<{
templateName: string
className?: string
}> = ({ templateName, className }) => (
<Link
underline="none"
component={RouterLink}
to={`/templates/${templateName}/workspace`}
>
<Button className={className ?? ""} startIcon={<AddCircleOutline />}>
{Language.createButton}
</Button>
</Link>
)

export const TemplateLayout: FC<PropsWithChildren> = ({ children }) => {
const styles = useStyles()
const organizationId = useOrganizationId()
const templateName = useTemplateName()
const [templateState, templateSend] = useMachine(templateMachine, {
const [templateState, _] = useMachine(templateMachine, {
context: {
templateName,
organizationId,
Expand All @@ -103,67 +123,32 @@ export const TemplateLayout: FC<PropsWithChildren> = ({ children }) => {
!templateDAUs ||
!templatePermissions

if (templateState.matches("deleted")) {
return <Navigate to="/templates" />
}

const hasIcon = template && template.icon && template.icon !== ""

const createWorkspaceButton = (className?: string) => (
<Link
underline="none"
component={RouterLink}
to={`/templates/${templateName}/workspace`}
>
<Button
className={className ?? ""}
startIcon={<AddCircleOutline />}
disabled={isLoading}
>
{Language.createButton}
</Button>
</Link>
)
const generatePageHeaderActions = (): JSX.Element[] => {
const pageActions: JSX.Element[] = []

if (!isLoading && templatePermissions.canUpdateTemplate) {
pageActions.push(<TemplateSettingsButton templateName={templateName} />)
}

const handleDeleteTemplate = () => {
templateSend("DELETE")
if (!isLoading) {
pageActions.push(<CreateWorkspaceButton templateName={templateName} />)
}

return pageActions
}

return (
<>
<Margins>
<PageHeader
actions={
isLoading ? undefined : (
<ChooseOne>
<Cond condition={templatePermissions.canUpdateTemplate}>
<Link
underline="none"
component={RouterLink}
to={`/templates/${template.name}/settings`}
>
<Button variant="outlined" startIcon={<SettingsOutlined />}>
{Language.settingsButton}
</Button>
</Link>

<DropdownButton
primaryAction={createWorkspaceButton(styles.actionButton)}
secondaryActions={[
{
action: "delete",
button: (
<DeleteButton handleAction={handleDeleteTemplate} />
),
},
]}
canCancel={false}
/>
</Cond>

<Cond>{createWorkspaceButton()}</Cond>
</ChooseOne>
)
<>
{generatePageHeaderActions().map((action, i) => (
<div key={i}>{action}</div>
))}
</>
}
>
<Stack direction="row" spacing={3} className={styles.pageTitle}>
Expand Down Expand Up @@ -234,31 +219,12 @@ export const TemplateLayout: FC<PropsWithChildren> = ({ children }) => {
<Suspense fallback={<Loader />}>{children}</Suspense>
</TemplateLayoutContext.Provider>
</Margins>

{!isLoading && (
<DeleteDialog
isOpen={templateState.matches("confirmingDelete")}
confirmLoading={templateState.matches("deleting")}
onConfirm={() => {
templateSend("CONFIRM_DELETE")
}}
onCancel={() => {
templateSend("CANCEL_DELETE")
}}
entity="template"
name={template.name}
/>
)}
</>
)
}

export const useStyles = makeStyles((theme) => {
return {
actionButton: {
border: "none",
borderRadius: `${theme.shape.borderRadius}px 0px 0px ${theme.shape.borderRadius}px`,
},
pageTitle: {
alignItems: "center",
},
Expand Down
11 changes: 10 additions & 1 deletion site/src/i18n/en/templatePage.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,13 @@
{
"deleteSuccess": "Template successfully deleted.",
"createdVersion": "created the version"
"createdVersion": "created the version",
"templateSettings": {
"title": "Template settings",
"dangerZone": {
"dangerZoneHeader": "Danger Zone",
"deleteTemplateHeader": "Delete this template",
"deleteTemplateCaption": "Once you delete a template, there is no going back. Please be certain.",
"deleteCta": "Delete Template"
}
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { fireEvent, screen } from "@testing-library/react"
import { screen } from "@testing-library/react"
import { TemplateLayout } from "components/TemplateLayout/TemplateLayout"
import { rest } from "msw"
import { ResizeObserver } from "resize-observer"
Expand Down Expand Up @@ -42,13 +42,6 @@ describe("TemplateSummaryPage", () => {
screen.getByText(MockWorkspaceResource.name)
screen.queryAllByText(`${MockTemplateVersion.name}`).length
})
it("allows an admin to delete a template", async () => {
renderPage()
const dropdownButton = await screen.findByLabelText("open-dropdown")
fireEvent.click(dropdownButton)
const deleteButton = await screen.findByText("Delete")
expect(deleteButton).toBeDefined()
})
it("does not allow a member to delete a template", () => {
// get member-level permissions
server.use(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ export const TemplateSummaryPage: FC = () => {
activeTemplateVersion,
templateResources,
templateVersions,
deleteTemplateError,
templateDAUs,
} = context

Expand All @@ -31,7 +30,6 @@ export const TemplateSummaryPage: FC = () => {
templateResources={templateResources}
templateVersions={templateVersions}
templateDAUs={templateDAUs}
deleteTemplateError={deleteTemplateError}
/>
</>
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import {
TemplateVersion,
WorkspaceResource,
} from "api/typesGenerated"
import { AlertBanner } from "components/AlertBanner/AlertBanner"
import { MemoizedMarkdown } from "components/Markdown/Markdown"
import { Stack } from "components/Stack/Stack"
import { TemplateResourcesTable } from "components/TemplateResourcesTable/TemplateResourcesTable"
Expand All @@ -21,7 +20,6 @@ export interface TemplateSummaryPageViewProps {
templateResources: WorkspaceResource[]
templateVersions?: TemplateVersion[]
templateDAUs?: TemplateDAUsResponse
deleteTemplateError: Error | unknown
}

export const TemplateSummaryPageView: FC<
Expand All @@ -32,15 +30,10 @@ export const TemplateSummaryPageView: FC<
templateResources,
templateVersions,
templateDAUs,
deleteTemplateError,
}) => {
const styles = useStyles()
const readme = frontMatter(activeTemplateVersion.readme)

const deleteError = deleteTemplateError ? (
<AlertBanner severity="error" error={deleteTemplateError} dismissible />
) : null

const getStartedResources = (resources: WorkspaceResource[]) => {
return resources.filter(
(resource) => resource.workspace_transition === "start",
Expand All @@ -49,7 +42,6 @@ export const TemplateSummaryPageView: FC<

return (
<Stack spacing={4}>
{deleteError}
<TemplateStats
template={template}
activeVersion={activeTemplateVersion}
Expand Down
5 changes: 1 addition & 4 deletions site/src/pages/TemplateSettingsPage/TemplateSettingsForm.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import InputAdornment from "@material-ui/core/InputAdornment"
import Popover from "@material-ui/core/Popover"
import { makeStyles } from "@material-ui/core/styles"
import TextField from "@material-ui/core/TextField"
import Typography from "@material-ui/core/Typography"
import { Template, UpdateTemplateMeta } from "api/typesGenerated"
import { OpenDropdown } from "components/DropdownArrows/DropdownArrows"
import { FormFooter } from "components/FormFooter/FormFooter"
Expand Down Expand Up @@ -188,9 +187,7 @@ export const TemplateSettingsForm: FC<TemplateSettingsForm> = ({
there are no validation errors for that field, display helper text.
We do not use the MUI helper-text prop because it overrides the validation error */}
{form.values.default_ttl_ms && !form.errors.default_ttl_ms && (
<Typography variant="subtitle2">
{Language.ttlHelperText(form.values.default_ttl_ms)}
</Typography>
<span>{Language.ttlHelperText(form.values.default_ttl_ms)}</span>
)}
</Stack>

Expand Down
18 changes: 16 additions & 2 deletions site/src/pages/TemplateSettingsPage/TemplateSettingsPage.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
validationSchema,
} from "./TemplateSettingsForm"
import { TemplateSettingsPage } from "./TemplateSettingsPage"
import { Language as ViewLanguage } from "./TemplateSettingsPageView"
import i18next from "i18next"

const renderTemplateSettingsPage = async () => {
const renderResult = renderWithAuth(<TemplateSettingsPage />, {
Expand Down Expand Up @@ -61,11 +61,25 @@ const fillAndSubmitForm = async ({

describe("TemplateSettingsPage", () => {
it("renders", async () => {
const { t } = i18next
const pageTitle = t("templateSettings.title", {
ns: "templatePage",
})
await renderTemplateSettingsPage()
const element = await screen.findByText(ViewLanguage.title)
const element = await screen.findByText(pageTitle)
expect(element).toBeDefined()
})

it("allows an admin to delete a template", async () => {
const { t } = i18next
await renderTemplateSettingsPage()
const deleteCta = t("templateSettings.dangerZone.deleteCta", {
ns: "templatePage",
})
const deleteButton = await screen.findByText(deleteCta)
expect(deleteButton).toBeDefined()
})

it("succeeds", async () => {
await renderTemplateSettingsPage()

Expand Down
10 changes: 10 additions & 0 deletions site/src/pages/TemplateSettingsPage/TemplateSettingsPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export const TemplateSettingsPage: FC = () => {
templateSettings: template,
saveTemplateSettingsError,
getTemplateError,
deleteTemplateError,
} = state.context

return (
Expand All @@ -41,13 +42,22 @@ export const TemplateSettingsPage: FC = () => {
errors={{
getTemplateError,
saveTemplateSettingsError,
deleteTemplateError,
}}
onCancel={() => {
navigate(`/templates/${templateName}`)
}}
onSubmit={(templateSettings) => {
send({ type: "SAVE", templateSettings })
}}
onDelete={() => {
send("DELETE")
}}
onConfirmDelete={() => send("CONFIRM_DELETE")}
onCancelDelete={() => send("CANCEL_DELETE")}
isConfirmingDelete={state.matches("confirmingDelete")}
isDeleting={state.matches("deleting")}
isDeleted={state.matches("deleted")}
/>
</>
)
Expand Down

0 comments on commit 1c9677d

Please sign in to comment.