Skip to content

Commit 8cc5b25

Browse files
authored
Use new fleet_viewer property on /v1/me (#2891)
use new fleet_viewer property on /v1/me
1 parent 33b2b55 commit 8cc5b25

File tree

11 files changed

+41
-91
lines changed

11 files changed

+41
-91
lines changed

OMICRON_VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
a9d9f1e1a17736aecc8d644c8d8c6174c1a5bc14
1+
c52ed36e07d70b6f968c177b27f606d9a91ca279

app/api/__generated__/Api.ts

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/api/__generated__/OMICRON_VERSION

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/api/__generated__/validate.ts

Lines changed: 9 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

app/api/hooks.ts

Lines changed: 0 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -305,40 +305,6 @@ export const wrapQueryClient = <A extends ApiClient>(api: A, queryClient: QueryC
305305
queryFn: () => api[method](params).then(handleResult(method)),
306306
...options,
307307
}),
308-
/**
309-
* Loader analog to `useApiQueryErrorsAllowed`. Prefetch a query that can
310-
* error, converting the error to a valid result so RQ will cache it.
311-
*/
312-
prefetchQueryErrorsAllowed: <M extends string & keyof A>(
313-
method: M,
314-
params: Params<A[M]>,
315-
options: FetchQueryOtherOptions<ErrorsAllowed<Result<A[M]>, ApiError>> & {
316-
/**
317-
* HTTP errors will show up unexplained in the browser console. It can be
318-
* helpful to reassure people they're normal.
319-
*/
320-
explanation: string
321-
expectedStatusCode: 403 | 404
322-
}
323-
) =>
324-
queryClient.prefetchQuery({
325-
queryKey: [method, params, ERRORS_ALLOWED],
326-
queryFn: () =>
327-
api[method](params)
328-
.then(handleResult(method))
329-
.then((data) => ({ type: 'success' as const, data }))
330-
.catch((data: ApiError) => {
331-
// if we get an unexpected error, we're still throwing
332-
if (data.statusCode !== options.expectedStatusCode) {
333-
// data is the result of handleResult, so it's ready to through
334-
// directly without further processing
335-
throw data
336-
}
337-
console.info(options.explanation)
338-
return { type: 'error' as const, data }
339-
}),
340-
...options,
341-
}),
342308
})
343309

344310
/*

app/components/TopBar.tsx

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { intersperse } from '~/util/array'
2727
import { pb } from '~/util/path-builder'
2828

2929
export function TopBar({ systemOrSilo }: { systemOrSilo: 'system' | 'silo' }) {
30-
const { isFleetViewer } = useCurrentUser()
30+
const { me } = useCurrentUser()
3131
// The height of this component is governed by the `PageContainer`
3232
// It's important that this component returns two distinct elements (wrapped in a fragment).
3333
// Each element will occupy one of the top column slots provided by `PageContainer`.
@@ -42,7 +42,7 @@ export function TopBar({ systemOrSilo }: { systemOrSilo: 'system' | 'silo' }) {
4242
<Breadcrumbs />
4343
</div>
4444
<div className="flex items-center gap-2">
45-
{isFleetViewer && <SiloSystemPicker level={systemOrSilo} />}
45+
{me.fleetViewer && <SiloSystemPicker level={systemOrSilo} />}
4646
<UserMenu />
4747
</div>
4848
</div>
@@ -155,8 +155,8 @@ function UserMenu() {
155155

156156
/**
157157
* Choose between System and Silo-scoped route trees, or if the user doesn't
158-
* have access to system routes (i.e., if systemPolicyView 403s) show the
159-
* current silo.
158+
* have access to system routes (i.e., if /v1/me has fleetViewer: false) show
159+
* the current silo.
160160
*/
161161
function SiloSystemPicker({ level }: { level: 'silo' | 'system' }) {
162162
return (

app/hooks/use-current-user.ts

Lines changed: 4 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,7 @@
66
* Copyright Oxide Computer Company
77
*/
88

9-
import { useQuery } from '@tanstack/react-query'
10-
11-
import { apiqErrorsAllowed, usePrefetchedApiQuery } from '~/api/client'
12-
import { invariant } from '~/util/invariant'
9+
import { apiq, usePrefetchedQuery } from '~/api/client'
1310

1411
/**
1512
* Access all the data fetched by the loader. Because of the `shouldRevalidate`
@@ -18,19 +15,7 @@ import { invariant } from '~/util/invariant'
1815
* loaders.
1916
*/
2017
export function useCurrentUser() {
21-
const { data: me } = usePrefetchedApiQuery('currentUserView', {})
22-
const { data: myGroups } = usePrefetchedApiQuery('currentUserGroups', {})
23-
24-
// User can only get to system routes if they have viewer perms (at least) on
25-
// the fleet. The natural place to find out whether they have such perms is
26-
// the fleet (system) policy, but if the user doesn't have fleet read, we'll
27-
// get a 403 from that endpoint. So we simply check whether that endpoint 200s
28-
// or not to determine whether the user is a fleet viewer.
29-
const { data: systemPolicy } = useQuery(apiqErrorsAllowed('systemPolicyView', {}))
30-
// don't use usePrefetchedApiQuery because it's not worth making an errors
31-
// allowed version of that
32-
invariant(systemPolicy, 'System policy must be prefetched')
33-
const isFleetViewer = systemPolicy.type === 'success'
34-
35-
return { me, myGroups, isFleetViewer }
18+
const { data: me } = usePrefetchedQuery(apiq('currentUserView', {}))
19+
const { data: myGroups } = usePrefetchedQuery(apiq('currentUserGroups', {}))
20+
return { me, myGroups }
3621
}

app/hooks/use-quick-actions.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ function closeQuickActions() {
5757
function useGlobalActions() {
5858
const location = useLocation()
5959
const navigate = useNavigate()
60-
const { isFleetViewer } = useCurrentUser()
60+
const { me } = useCurrentUser()
6161

6262
return useMemo(() => {
6363
const actions = []
@@ -69,15 +69,15 @@ function useGlobalActions() {
6969
onSelect: () => navigate(pb.profile()),
7070
})
7171
}
72-
if (isFleetViewer && !location.pathname.startsWith('/system/')) {
72+
if (me.fleetViewer && !location.pathname.startsWith('/system/')) {
7373
actions.push({
7474
navGroup: 'System',
7575
value: 'Manage system',
7676
onSelect: () => navigate(pb.silos()),
7777
})
7878
}
7979
return actions
80-
}, [location.pathname, navigate, isFleetViewer])
80+
}, [location.pathname, navigate, me.fleetViewer])
8181
}
8282

8383
/**

app/layouts/AuthenticatedLayout.tsx

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,18 +28,6 @@ export async function clientLoader() {
2828
await Promise.all([
2929
apiQueryClient.prefetchQuery('currentUserView', {}, { staleTime }),
3030
apiQueryClient.prefetchQuery('currentUserGroups', {}, { staleTime }),
31-
// Need to prefetch this because every layout hits it when deciding whether
32-
// to show the silo/system picker. It's also fetched by the SystemLayout
33-
// loader to figure out whether to 404, but RQ dedupes the request.
34-
apiQueryClient.prefetchQueryErrorsAllowed(
35-
'systemPolicyView',
36-
{},
37-
{
38-
explanation: '/v1/system/policy 403 is expected if user is not a fleet viewer.',
39-
expectedStatusCode: 403,
40-
staleTime,
41-
}
42-
),
4331
])
4432
return null
4533
}

app/layouts/SystemLayout.tsx

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -27,23 +27,13 @@ import { inventoryBase, pb } from '~/util/path-builder'
2727
import { ContentPane, PageContainer } from './helpers'
2828

2929
/**
30-
* If we can see the policy, we're a fleet viewer, and we need to be a fleet
31-
* viewer in order to see any of the routes under this layout. We need to
32-
* `fetchQuery` instead of `prefetchQuery` because the latter doesn't return the
33-
* result, and then we need to `.catch()` because `fetchQuery` throws on request
34-
* error. We're being a little cavalier here with the error. If it's something
35-
* other than a 403, that would be strange and we would want to know.
30+
* We need to be a fleet viewer in order to see any of the routes under this
31+
* layout. We need to `fetchQuery` instead of `prefetchQuery` because the latter
32+
* doesn't return the result.
3633
*/
3734
export async function clientLoader() {
38-
// we don't need to use the ErrorsAllowed version here because we're 404ing
39-
// immediately on error, so we don't need to pick the result up from the cache
40-
const isFleetViewer = await apiQueryClient
41-
.fetchQuery('systemPolicyView', {})
42-
.then(() => true)
43-
.catch(() => false)
44-
45-
if (!isFleetViewer) throw trigger404
46-
35+
const me = await apiQueryClient.fetchQuery('currentUserView', {})
36+
if (!me.fleetViewer) throw trigger404
4737
return null
4838
}
4939

0 commit comments

Comments
 (0)