diff --git a/app/pages/OrgsPage.tsx b/app/pages/OrgsPage.tsx index d49c37becb..da8f7b65bf 100644 --- a/app/pages/OrgsPage.tsx +++ b/app/pages/OrgsPage.tsx @@ -2,12 +2,15 @@ import { useMemo } from 'react' import { Link, useLocation, useNavigate } from 'react-router-dom' import type { Organization } from '@oxide/api' +import { canWrite } from '@oxide/api' +import { useEffectiveSiloRole } from '@oxide/api' import { apiQueryClient } from '@oxide/api' import { useApiQueryClient } from '@oxide/api' import { useApiMutation, useApiQuery } from '@oxide/api' import type { MenuAction } from '@oxide/table' import { DateCell, linkCell, useQueryTable } from '@oxide/table' import { + Button, EmptyMessage, Folder24Icon, PageHeader, @@ -33,7 +36,10 @@ const EmptyState = () => ( ) OrgsPage.loader = async () => { - await apiQueryClient.prefetchQuery('organizationList', { query: { limit: 10 } }) + await Promise.all([ + apiQueryClient.prefetchQuery('organizationList', { query: { limit: 10 } }), + apiQueryClient.prefetchQuery('policyView', {}), + ]) } interface OrgsPageProps { @@ -47,6 +53,8 @@ export default function OrgsPage({ modal }: OrgsPageProps) { const { Table, Column } = useQueryTable('organizationList', {}) const queryClient = useApiQueryClient() + const siloRole = useEffectiveSiloRole() + const { data: orgs } = useApiQuery('organizationList', { query: { limit: 10 }, // to have same params as QueryTable }) @@ -92,9 +100,18 @@ export default function OrgsPage({ modal }: OrgsPageProps) { }>Organizations - - New Organization - + {canWrite(siloRole) ? ( + + New Organization + + ) : ( + + )} } makeActions={makeActions}> pb.projects({ orgName }))} /> diff --git a/libs/api/roles.ts b/libs/api/roles.ts index c56124f26f..e348bfbfb5 100644 --- a/libs/api/roles.ts +++ b/libs/api/roles.ts @@ -157,3 +157,21 @@ export function userRoleFromPolicies( .map((ra) => ra.roleName) return getEffectiveRole(myRoles) || null } + +// Not having pop-in when the requests resolve depends on the right prefetches +// having happened. This is probably too fragile. We need to explore this. +// https://tkdodo.eu/blog/react-query-meets-react-router#a-typescript-tip +export function useEffectiveSiloRole() { + const { data: me } = useApiQuery('sessionMe', {}) + const { data: myGroups } = useApiQuery('sessionMeGroups', {}) + const { data: siloPolicy } = useApiQuery('policyView', {}) + return me && myGroups && siloPolicy + ? userRoleFromPolicies(me, myGroups.items, [siloPolicy]) + : null +} + +const readRoles = new Set(['admin', 'collaborator', 'viewer']) +const writeRoles = new Set(['admin', 'collaborator']) + +export const canRead = (role: RoleKey | null) => (role ? readRoles.has(role) : false) +export const canWrite = (role: RoleKey | null) => (role ? writeRoles.has(role) : false)