-
Notifications
You must be signed in to change notification settings - Fork 22
Expand file tree
/
Copy pathProjectLayoutBase.tsx
More file actions
126 lines (115 loc) · 4.31 KB
/
ProjectLayoutBase.tsx
File metadata and controls
126 lines (115 loc) · 4.31 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, you can obtain one at https://mozilla.org/MPL/2.0/.
*
* Copyright Oxide Computer Company
*/
import type { ReactElement } from 'react'
import { useLocation, type LoaderFunctionArgs } from 'react-router'
import { api, q, queryClient, usePrefetchedQuery } from '@oxide/api'
import {
Access16Icon,
Affinity16Icon,
Folder16Icon,
Images16Icon,
Instances16Icon,
IpGlobal16Icon,
Networking16Icon,
Snapshots16Icon,
Storage16Icon,
} from '@oxide/design-system/icons/react'
import { TopBar } from '~/components/TopBar'
import { makeCrumb } from '~/hooks/use-crumbs'
import { getProjectSelector, useProjectSelector } from '~/hooks/use-params'
import { useQuickActions } from '~/hooks/use-quick-actions'
import { Divider } from '~/ui/lib/Divider'
import { pb } from '~/util/path-builder'
import type * as PP from '~/util/path-params'
import { DocsLinkItem, NavLinkItem, Sidebar } from '../components/Sidebar'
import { ContentPane, PageContainer } from './helpers'
export const projectLayoutHandle = makeCrumb(
(p) => p.project!,
(p) => pb.project(getProjectSelector(p))
)
type ProjectLayoutProps = {
/** Sometimes we need a different layout for the content pane. Like
* `<ContentPane />`, the element passed here should contain an `<Outlet />`.
*/
overrideContentPane?: ReactElement
}
const projectView = ({ project }: PP.Project) => q(api.projectView, { path: { project } })
export async function projectLayoutLoader({ params }: LoaderFunctionArgs) {
const { project } = getProjectSelector(params)
await queryClient.prefetchQuery(projectView({ project }))
return null
}
export function ProjectLayoutBase({ overrideContentPane }: ProjectLayoutProps) {
// project will always be there, instance may not
const projectSelector = useProjectSelector()
const { data: project } = usePrefetchedQuery(projectView(projectSelector))
const { pathname } = useLocation()
useQuickActions(
() =>
[
{ value: 'Instances', path: pb.instances(projectSelector) },
{ value: 'Disks', path: pb.disks(projectSelector) },
{ value: 'Snapshots', path: pb.snapshots(projectSelector) },
{ value: 'Images', path: pb.projectImages(projectSelector) },
{ value: 'VPCs', path: pb.vpcs(projectSelector) },
{ value: 'Floating IPs', path: pb.floatingIps(projectSelector) },
{ value: 'Affinity Groups', path: pb.affinity(projectSelector) },
{ value: 'Project Access', path: pb.projectAccess(projectSelector) },
]
// filter out the entry for the path we're currently on
.filter((i) => i.path !== pathname)
.map((i) => ({
navGroup: `Project '${project.name}'`,
value: i.value,
action: i.path,
})),
[pathname, project.name, projectSelector]
)
return (
<PageContainer>
<TopBar systemOrSilo="silo" />
<Sidebar>
<Sidebar.Nav>
<NavLinkItem to={pb.projects()} end>
<Folder16Icon />
Projects
</NavLinkItem>
<DocsLinkItem />
</Sidebar.Nav>
<Divider />
<Sidebar.Nav heading={project.name}>
<NavLinkItem to={pb.instances(projectSelector)}>
<Instances16Icon /> Instances
</NavLinkItem>
<NavLinkItem to={pb.disks(projectSelector)}>
<Storage16Icon /> Disks
</NavLinkItem>
<NavLinkItem to={pb.snapshots(projectSelector)}>
<Snapshots16Icon /> Snapshots
</NavLinkItem>
<NavLinkItem to={pb.projectImages(projectSelector)}>
<Images16Icon /> Images
</NavLinkItem>
<NavLinkItem to={pb.vpcs(projectSelector)}>
<Networking16Icon /> VPCs
</NavLinkItem>
<NavLinkItem to={pb.floatingIps(projectSelector)}>
<IpGlobal16Icon /> Floating IPs
</NavLinkItem>
<NavLinkItem to={pb.affinity(projectSelector)}>
<Affinity16Icon /> Affinity Groups
</NavLinkItem>
<NavLinkItem to={pb.projectAccess(projectSelector)}>
<Access16Icon /> Project Access
</NavLinkItem>
</Sidebar.Nav>
</Sidebar>
{overrideContentPane || <ContentPane />}
</PageContainer>
)
}