diff --git a/site/src/modules/provisioners/ProvisionerGroup.tsx b/site/src/modules/provisioners/ProvisionerGroup.tsx index 8dd5ca251094e..ee333c915a2fe 100644 --- a/site/src/modules/provisioners/ProvisionerGroup.tsx +++ b/site/src/modules/provisioners/ProvisionerGroup.tsx @@ -30,7 +30,7 @@ import { ProvisionerTag } from "./ProvisionerTag"; type ProvisionerGroupType = "builtin" | "psk" | "key"; interface ProvisionerGroupProps { - readonly buildInfo?: BuildInfoResponse; + readonly buildInfo: BuildInfoResponse; readonly keyName: string; readonly keyTags: Record; readonly type: ProvisionerGroupType; @@ -80,7 +80,7 @@ export const ProvisionerGroup: FC = ({ let warnings = 0; let provisionersWithWarnings = 0; const provisionersWithWarningInfo = provisioners.map((it) => { - const outOfDate = Boolean(buildInfo) && it.version !== buildInfo?.version; + const outOfDate = it.version !== buildInfo.version; const warningCount = outOfDate ? 1 : 0; warnings += warningCount; if (warnings > 0) { @@ -292,7 +292,7 @@ export const ProvisionerGroup: FC = ({ }; interface ProvisionerVersionPopoverProps { - buildInfo?: BuildInfoResponse; + buildInfo: BuildInfoResponse; provisioner: ProvisionerDaemon; } @@ -304,11 +304,9 @@ const ProvisionerVersionPopover: FC = ({ - {buildInfo - ? provisioner.version === buildInfo.version - ? "Up to date" - : "Out of date" - : provisioner.version} + {provisioner.version === buildInfo.version + ? "Up to date" + : "Out of date"} = ({

{provisioner.version}

Protocol version

{provisioner.api_version}

- {provisioner.api_version !== buildInfo?.provisioner_api_version && ( + {provisioner.api_version !== buildInfo.provisioner_api_version && (

This provisioner is out of date. You may experience issues when using a provisioner version that doesn’t match your Coder diff --git a/site/src/pages/ManagementSettingsPage/OrganizationProvisionersPage.tsx b/site/src/pages/ManagementSettingsPage/OrganizationProvisionersPage.tsx index e2e3fc75c3c2d..55dff198822a0 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationProvisionersPage.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationProvisionersPage.tsx @@ -3,15 +3,17 @@ import { organizationsPermissions, provisionerDaemonGroups, } from "api/queries/organizations"; -import type { Organization, ProvisionerDaemon } from "api/typesGenerated"; +import type { Organization } from "api/typesGenerated"; import { ErrorAlert } from "components/Alert/ErrorAlert"; import { EmptyState } from "components/EmptyState/EmptyState"; import { Loader } from "components/Loader/Loader"; +import { Paywall } from "components/Paywall/Paywall"; import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata"; -import NotFoundPage from "pages/404Page/404Page"; +import { useDashboard } from "modules/dashboard/useDashboard"; import type { FC } from "react"; import { useQuery } from "react-query"; import { useParams } from "react-router-dom"; +import { docs } from "utils/docs"; import { useOrganizationSettings } from "./ManagementSettingsLayout"; import { OrganizationProvisionersPageView } from "./OrganizationProvisionersPageView"; @@ -20,6 +22,7 @@ const OrganizationProvisionersPage: FC = () => { organization: string; }; const { organizations } = useOrganizationSettings(); + const { entitlements } = useDashboard(); const { metadata } = useEmbeddedMetadata(); const buildInfoQuery = useQuery(buildInfo(metadata["build-info"])); @@ -27,42 +30,18 @@ const OrganizationProvisionersPage: FC = () => { const organization = organizations ? getOrganizationByName(organizations, organizationName) : undefined; - const permissionsQuery = useQuery( - organizationsPermissions(organizations?.map((o) => o.id)), - ); const provisionersQuery = useQuery(provisionerDaemonGroups(organizationName)); if (!organization) { return ; } - if (permissionsQuery.isLoading || provisionersQuery.isLoading) { - return ; - } - - const permissions = permissionsQuery.data; - const provisioners = provisionersQuery.data; - const error = permissionsQuery.error || provisionersQuery.error; - if (error || !permissions || !provisioners) { - return ; - } - - // The user may not be able to edit this org but they can still see it because - // they can edit members, etc. In this case they will be shown a read-only - // summary page instead of the settings form. - // Similarly, if the feature is not entitled then the user will not be able to - // edit the organization. - if (!permissions[organization.id]?.viewProvisioners) { - // This probably doesn't work with the layout................fix this pls - // Kayla, hey, yes you, you gotta fix this. - // Don't scroll past this. It's important. Fix it!!! - return ; - } - return ( ); }; diff --git a/site/src/pages/ManagementSettingsPage/OrganizationProvisionersPageView.stories.tsx b/site/src/pages/ManagementSettingsPage/OrganizationProvisionersPageView.stories.tsx index 1a8b77479271d..dec8e40e28d59 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationProvisionersPageView.stories.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationProvisionersPageView.stories.tsx @@ -9,6 +9,7 @@ import { MockProvisionerPskKey, MockProvisionerWithTags, MockUserProvisioner, + mockApiError, } from "testHelpers/entities"; import { OrganizationProvisionersPageView } from "./OrganizationProvisionersPageView"; @@ -112,3 +113,18 @@ export const Empty: Story = { provisioners: [], }, }; + +export const WithError: Story = { + args: { + error: mockApiError({ + message: "Fern is mad", + detail: "Frieren slept in and didn't get groceries", + }), + }, +}; + +export const Paywall: Story = { + args: { + showPaywall: true, + }, +}; diff --git a/site/src/pages/ManagementSettingsPage/OrganizationProvisionersPageView.tsx b/site/src/pages/ManagementSettingsPage/OrganizationProvisionersPageView.tsx index aaee2c49c34b2..eac651f10219e 100644 --- a/site/src/pages/ManagementSettingsPage/OrganizationProvisionersPageView.tsx +++ b/site/src/pages/ManagementSettingsPage/OrganizationProvisionersPageView.tsx @@ -5,7 +5,10 @@ import type { ProvisionerKey, ProvisionerKeyDaemons, } from "api/typesGenerated"; +import { ErrorAlert } from "components/Alert/ErrorAlert"; import { EmptyState } from "components/EmptyState/EmptyState"; +import { Loader } from "components/Loader/Loader"; +import { Paywall } from "components/Paywall/Paywall"; import { SettingsHeader } from "components/SettingsHeader/SettingsHeader"; import { Stack } from "components/Stack/Stack"; import { ProvisionerGroup } from "modules/provisioners/ProvisionerGroup"; @@ -13,24 +16,22 @@ import type { FC } from "react"; import { docs } from "utils/docs"; interface OrganizationProvisionersPageViewProps { + /** Determines if the paywall will be shown or not */ + showPaywall?: boolean; + + /** An error to display instead of the page content */ + error?: unknown; + /** Info about the version of coderd */ buildInfo?: BuildInfoResponse; /** Groups of provisioners, along with their key information */ - provisioners: readonly ProvisionerKeyDaemons[]; + provisioners?: readonly ProvisionerKeyDaemons[]; } export const OrganizationProvisionersPageView: FC< OrganizationProvisionersPageViewProps -> = ({ buildInfo, provisioners }) => { - const isEmpty = provisioners.every((group) => group.daemons.length === 0); - - const provisionerGroupsCount = provisioners.length; - const provisionersCount = provisioners.reduce( - (a, group) => a + group.daemons.length, - 0, - ); - +> = ({ showPaywall, error, buildInfo, provisioners }) => { return (

- + {!showPaywall && ( + + )} + {showPaywall ? ( + + ) : error ? ( + + ) : !buildInfo || !provisioners ? ( + + ) : ( + + )} +
+ ); +}; + +type ViewContentProps = Required< + Pick +>; + +const ViewContent: FC = ({ buildInfo, provisioners }) => { + const isEmpty = provisioners.every((group) => group.daemons.length === 0); + + const provisionerGroupsCount = provisioners.length; + const provisionersCount = provisioners.reduce( + (a, group) => a + group.daemons.length, + 0, + ); + + return ( + <> {isEmpty ? ( - + ); };