8000 fix: fix loading states and permissions checks in organization settings by aslilac · Pull Request #16465 · coder/coder · GitHub
[go: up one dir, main page]

Skip to content

fix: fix loading states and permissions checks in organization settings #16465

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 25 commits into from
Feb 19, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
Prev Previous commit
Next Next commit
oh yeah
  • Loading branch information
aslilac committed Feb 7, 2025
commit 0a590893742171e847f461c4e52d0d0cc1466672
12 changes: 12 additions & 0 deletions site/src/api/queries/organizations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import {
organizationPermissionChecks,
type OrganizationPermissions,
type OrganizationPermissionName,
anyOrganizationPermissionChecks,
type AnyOrganizationPermissions,
} from "modules/management/organizationPermissions";

export const createOrganization = (queryClient: QueryClient) => {
Expand Down Expand Up @@ -251,6 +253,16 @@ export const organizationsPermissions = (
};
};

export const anyOrganizationPermissions = () => {
return {
queryKey: ["authorization", "anyOrganization"],
queryFn: () =>
API.checkAuthorization({
checks: anyOrganizationPermissionChecks,
}) as Promise<AnyOrganizationPermissions>,
};
};

export const getOrganizationIdpSyncClaimFieldValuesKey = (
organization: string,
field: string,
Expand Down
2 changes: 2 additions & 0 deletions site/src/contexts/auth/AuthProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,8 @@ export const AuthProvider: FC<PropsWithChildren> = ({ children }) => {
[updateProfileMutation],
);

console.log(permissionsQuery.data);

return (
<AuthContext.Provider
value={{
Expand Down
8 changes: 0 additions & 8 deletions site/src/contexts/auth/permissions.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ export const checks = {
readWorkspaceProxies: "readWorkspaceProxies",
editWorkspaceProxies: "editWorkspaceProxies",
createOrganization: "createOrganization",
editAnyOrganization: "editAnyOrganization",
viewAnyGroup: "viewAnyGroup",
createGroup: "createGroup",
viewAllLicenses: "viewAllLicenses",
Expand Down Expand Up @@ -122,13 +121,6 @@ export const permissionsToCheck = {
},
action: "create",
},
[checks.editAnyOrganization]: {
object: {
resource_type: "organization",
any_org: true,
},
action: "update",
},
[checks.viewAnyGroup]: {
object: {
resource_type: "group",
Expand Down
22 changes: 18 additions & 4 deletions site/src/modules/dashboard/DashboardProvider.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import { appearance } from "api/queries/appearance";
import { entitlements } from "api/queries/entitlements";
import { experiments } from "api/queries/experiments";
import { organizations } from "api/queries/organizations";
import {
anyOrganizationPermissions,
organizations,
} from "api/queries/organizations";
import type {
AppearanceConfig,
Entitlements,
Expand All @@ -14,13 +17,15 @@ import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata";
import { type FC, type PropsWithChildren, createContext } from "react";
import { useQuery } from "react-query";
import { selectFeatureVisibility } from "./entitlements";
import { canViewAnyOrganization } from "modules/management/organizationPermissions";

export interface DashboardValue {
entitlements: Entitlements;
experiments: Experiments;
appearance: AppearanceConfig;
organizations: readonly Organization[];
showOrganizations: boolean;
canViewOrganizationSettings: boolean;
}

export const DashboardContext = createContext<DashboardValue | undefined>(
Expand All @@ -33,12 +38,16 @@ export const DashboardProvider: FC<PropsWithChildren> = ({ children }) => {
const experimentsQuery = useQuery(experiments(metadata.experiments));
const appearanceQuery = useQuery(appearance(metadata.appearance));
const organizationsQuery = useQuery(organizations());
const anyOrganizationPermissionsQuery = useQuery(
anyOrganizationPermissions(),
);

const error =
entitlementsQuery.error ||
appearanceQuery.error ||
experimentsQuery.error ||
organizationsQuery.error;
organizationsQuery.error ||
anyOrganizationPermissionsQuery.error;

if (error) {
return <ErrorAlert error={error} />;
Expand All @@ -48,7 +57,8 @@ export const DashboardProvider: FC<PropsWithChildren> = ({ children }) => {
!entitlementsQuery.data ||
!appearanceQuery.data ||
!experimentsQuery.data ||
!organizationsQuery.data;
!organizationsQuery.data ||
!anyOrganizationPermissionsQuery.data;

if (isLoading) {
return <Loader fullscreen />;
Expand All @@ -58,6 +68,7 @@ export const DashboardProvider: FC<PropsWithChildren> = ({ children }) => {
const organizationsEnabled = selectFeatureVisibility(
entitlementsQuery.data,
).multiple_organizations;
const showOrganizations = hasMultipleOrganizations || organizationsEnabled;

return (
<DashboardContext.Provider
Expand All @@ -66,7 +77,10 @@ export const DashboardProvider: FC<PropsWithChildren> = ({ children }) => {
experiments: experimentsQuery.data,
appearance: appearanceQuery.data,
organizations: organizationsQuery.data,
showOrganizations: hasMultipleOrganizations || organizationsEnabled,
showOrganizations,
canViewOrganizationSettings:
showOrganizations &&
canViewAnyOrganization(anyOrganizationPermissionsQuery.data),
}}
>
{children}
Expand Down
6 changes: 2 additions & 4 deletions site/src/modules/dashboard/Navbar/Navbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,13 @@ export const Navbar: FC = () => {
const { metadata } = useEmbeddedMetadata();
const buildInfoQuery = useQuery(buildInfo(metadata["build-info"]));

const { appearance, showOrganizations } = useDashboard();
const { appearance, canViewOrganizationSettings } = useDashboard();
const { user: me, permissions, signOut } = useAuthenticated();
const featureVisibility = useFeatureVisibility();
const canViewAuditLog =
featureVisibility.audit_log && permissions.viewAnyAuditLog;
const canViewDeployment = permissions.viewDeploymentValues;
const canViewOrganizations =
(permissions.viewDeploymentValues || permissions.editAnyOrganization) &&
showOrganizations;
const canViewOrganizations = canViewOrganizationSettings;
const proxyContextValue = useProxy();
const canViewHealth = canViewDeployment;

Expand Down
28 changes: 5 additions & 23 deletions site/src/modules/management/OrganizationSettingsLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import NotFoundPage from "pages/404Page/404Page";
import { type FC, Suspense, createContext, useContext } from "react";
import { useQuery } from "react-query";
import { Outlet, useParams } from "react-router-dom";
import type { OrganizationPermissions } from "./organizationPermissions";
import {
canViewOrganization,
type OrganizationPermissions,
} from "./organizationPermissions";

export const OrganizationSettingsContext = createContext<
OrganizationSettingsValue | undefined
Expand All @@ -41,33 +44,12 @@ export const useOrganizationSettings = (): OrganizationSettingsValue => {
return context;
};

/**
* Checks if the user can view or edit members or groups for the organization
* that produced the given OrganizationPermissions.
*/
const canViewOrganization = (
permissions: OrganizationPermissions | undefined,
): permissions is OrganizationPermissions => {
return (
permissions !== undefined &&
(permissions.editOrganization ||
permissions.editMembers ||
permissions.viewMembers ||
permissions.editGroups ||
permissions.viewGroups)
);
};

const OrganizationSettingsLayout: FC = () => {
const { permissions } = useAuthenticated();
const { organizations } = useDashboard();
const { organizations, canViewOrganizationSettings } = useDashboard();
const { organization: orgName } = useParams() as {
organization?: string;
};

const canViewOrganizationSettings =
permissions.viewDeploymentValues || permissions.editAnyOrganization;

const organization = orgName
? organizations.find((org) => org.name === orgName)
: undefined;
Expand Down
Loading
0