Skip to content

fix: Load template page chunks without blocking #4689

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Oct 21, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
200 changes: 105 additions & 95 deletions site/src/components/TemplateLayout/TemplateLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ 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 { Loader } from "components/Loader/Loader"
import {
PageHeader,
PageHeaderSubtitle,
Expand Down Expand Up @@ -53,7 +52,7 @@ const useTemplateName = () => {

type TemplateLayoutContextValue = {
context: TemplateContext
permissions: Permissions
permissions?: Permissions
}

const TemplateLayoutContext = createContext<
Expand Down Expand Up @@ -97,23 +96,23 @@ export const TemplateLayout: FC<PropsWithChildren> = ({ children }) => {
!templateDAUs ||
!templatePermissions

if (isLoading) {
return <Loader />
}

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

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

const createWorkspaceButton = (className?: string) => (
<Link
underline="none"
component={RouterLink}
to={`/templates/${template.name}/workspace`}
to={`/templates/${templateName}/workspace`}
>
<Button className={className ?? ""} startIcon={<AddCircleOutline />}>
<Button
className={className ?? ""}
startIcon={<AddCircleOutline />}
disabled={isLoading}
>
{Language.createButton}
</Button>
</Link>
Expand All @@ -128,89 +127,98 @@ export const TemplateLayout: FC<PropsWithChildren> = ({ children }) => {
<Margins>
<PageHeader
actions={
<ChooseOne>
<Cond condition={templatePermissions.canUpdateTemplate}>
<Link
underline="none"
component={RouterLink}
to={`/templates/${template.name}/settings`}
>
<Button variant="outlined" startIcon={<SettingsOutlined />}>
{Language.settingsButton}
</Button>
</Link>
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>
<DropdownButton
primaryAction={createWorkspaceButton(styles.actionButton)}
secondaryActions={[
{
action: "delete",
button: (
<DeleteButton handleAction={handleDeleteTemplate} />
),
},
]}
canCancel={false}
/>
</Cond>

<Cond>{createWorkspaceButton()}</Cond>
</ChooseOne>
<Cond>{createWorkspaceButton()}</Cond>
</ChooseOne>
)
}
>
<Stack direction="row" spacing={3} className={styles.pageTitle}>
<div>
{hasIcon ? (
<div className={styles.iconWrapper}>
<img src={template.icon} alt="" />
</div>
) : (
<Avatar className={styles.avatar}>
{firstLetter(template.name)}
</Avatar>
)}
</div>
<div>
<PageHeaderTitle>{template.name}</PageHeaderTitle>
<PageHeaderSubtitle condensed>
{template.description === ""
? Language.noDescription
: template.description}
</PageHeaderSubtitle>
</div>
{!isLoading && (
<div>
{hasIcon ? (
<div className={styles.iconWrapper}>
<img src={template.icon} alt="" />
</div>
) : (
<Avatar className={styles.avatar}>
{firstLetter(templateName)}
</Avatar>
)}
</div>
)}

{!isLoading && (
<div>
<PageHeaderTitle>{templateName}</PageHeaderTitle>
<PageHeaderSubtitle condensed>
{template.description === ""
? Language.noDescription
: template.description}
</PageHeaderSubtitle>
</div>
)}
</Stack>
</PageHeader>
</Margins>

<div className={styles.tabs}>
<Margins>
<Stack direction="row" spacing={0.25}>
<NavLink
end
to={`/templates/${template.name}`}
className={({ isActive }) =>
combineClasses([
styles.tabItem,
isActive ? styles.tabItemActive : undefined,
])
}
>
Summary
</NavLink>
<NavLink
to={`/templates/${template.name}/permissions`}
className={({ isActive }) =>
combineClasses([
styles.tabItem,
isActive ? styles.tabItemActive : undefined,
])
}
>
Permissions
</NavLink>
</Stack>
</Margins>
</div>
{!isLoading && (
<div className={styles.tabs}>
<Margins>
<Stack direction="row" spacing={0.25}>
<NavLink
end
to={`/templates/${template.name}`}
className={({ isActive }) =>
combineClasses([
styles.tabItem,
isActive ? styles.tabItemActive : undefined,
])
}
>
Summary
</NavLink>
<NavLink
to={`/templates/${template.name}/permissions`}
className={({ isActive }) =>
combineClasses([
styles.tabItem,
isActive ? styles.tabItemActive : undefined,
])
}
>
Permissions
</NavLink>
</Stack>
</Margins>
</div>
)}

<Margins>
<TemplateLayoutContext.Provider
Expand All @@ -220,18 +228,20 @@ export const TemplateLayout: FC<PropsWithChildren> = ({ children }) => {
</TemplateLayoutContext.Provider>
</Margins>

<DeleteDialog
isOpen={templateState.matches("confirmingDelete")}
confirmLoading={templateState.matches("deleting")}
onConfirm={() => {
templateSend("CONFIRM_DELETE")
}}
onCancel={() => {
templateSend("CANCEL_DELETE")
}}
entity="template"
name={template.name}
/>
{!isLoading && (
<DeleteDialog
isOpen={templateState.matches("confirmingDelete")}
confirmLoading={templateState.matches("deleting")}
onConfirm={() => {
templateSend("CONFIRM_DELETE")
}}
onCancel={() => {
templateSend("CANCEL_DELETE")
}}
entity="template"
name={template.name}
/>
)}
</>
)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,23 +13,22 @@ import { Helmet } from "react-helmet-async"
import { pageTitle } from "util/page"
import { templateACLMachine } from "xServices/template/templateACLXService"
import { TemplatePermissionsPageView } from "./TemplatePermissionsPageView"
import { Loader } from "components/Loader/Loader"

export const TemplatePermissionsPage: FC<
React.PropsWithChildren<unknown>
> = () => {
const organizationId = useOrganizationId()
const { context } = useTemplateLayoutContext()
const { template, permissions } = context
if (!template || !permissions) {
throw new Error(
"This page should not be displayed until template or permissions being loaded.",
)
}
const { template_rbac: isTemplateRBACEnabled } = useFeatureVisibility()
const [state, send] = useMachine(templateACLMachine, {
context: { templateId: template.id },
context: { templateId: template?.id },
})
const { templateACL, userToBeUpdated, groupToBeUpdated } = state.context
if (!template || !permissions) {
return <Loader />
}

return (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { FC } from "react"
import { Helmet } from "react-helmet-async"
import { pageTitle } from "util/page"
import { TemplateSummaryPageView } from "./TemplateSummaryPageView"
import { Loader } from "components/Loader/Loader"

export const TemplateSummaryPage: FC = () => {
const { context } = useTemplateLayoutContext()
Expand All @@ -16,9 +17,7 @@ export const TemplateSummaryPage: FC = () => {
} = context

if (!template || !activeTemplateVersion || !templateResources) {
throw new Error(
"This page should not be displayed until template, activeTemplateVersion or templateResources being loaded.",
)
return <Loader />
}

return (
Expand Down