summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFabian Mastenbroek <mail.fabianm@gmail.com>2021-08-17 11:30:29 +0200
committerGitHub <noreply@github.com>2021-08-17 11:30:29 +0200
commitf84dc9f8b8b4eaa7621f9ee4fc83ef38a85c431b (patch)
tree5bd9ed3f9c13cbcac510a59c61d1f574d4c99897
parentce2d730159ae24c7cebb22ec42d094fe5fdc888f (diff)
feat(ui): Add context selectors
This change adds context selectors for the OpenDC frontend where the user can select different projects, portfolios or topologies from the context selection bar.
-rw-r--r--opendc-web/opendc-web-ui/src/components/AppPage.js12
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.js34
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.module.scss28
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/ContextSelector.js75
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/ContextSelector.module.scss45
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/PortfolioSelector.js47
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/ProjectSelector.js48
-rw-r--r--opendc-web/opendc-web-ui/src/components/context/TopologySelector.js52
-rw-r--r--opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js10
-rw-r--r--opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js12
-rw-r--r--opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js12
11 files changed, 368 insertions, 7 deletions
diff --git a/opendc-web/opendc-web-ui/src/components/AppPage.js b/opendc-web/opendc-web-ui/src/components/AppPage.js
index 2e0ea4cc..25afaf9a 100644
--- a/opendc-web/opendc-web-ui/src/components/AppPage.js
+++ b/opendc-web/opendc-web-ui/src/components/AppPage.js
@@ -23,11 +23,15 @@
import PropTypes from 'prop-types'
import { AppHeader } from './AppHeader'
import React from 'react'
-import { Page } from '@patternfly/react-core'
+import { Page, PageGroup, PageBreadcrumb } from '@patternfly/react-core'
-export function AppPage({ children, breadcrumb, tertiaryNav }) {
+export function AppPage({ children, breadcrumb, contextSelectors }) {
return (
- <Page breadcrumb={breadcrumb} tertiaryNav={tertiaryNav} header={<AppHeader />}>
+ <Page header={<AppHeader />}>
+ <PageGroup>
+ {contextSelectors}
+ {breadcrumb && <PageBreadcrumb>{breadcrumb}</PageBreadcrumb>}
+ </PageGroup>
{children}
</Page>
)
@@ -35,6 +39,6 @@ export function AppPage({ children, breadcrumb, tertiaryNav }) {
AppPage.propTypes = {
breadcrumb: PropTypes.node,
- tertiaryNav: PropTypes.node,
+ contextSelectors: PropTypes.node,
children: PropTypes.node,
}
diff --git a/opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.js b/opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.js
new file mode 100644
index 00000000..5d3a6441
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.js
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import PropTypes from 'prop-types'
+import { contextSelectionSection } from './ContextSelectionSection.module.scss'
+
+function ContextSelectionSection({ children }) {
+ return <section className={contextSelectionSection}>{children}</section>
+}
+
+ContextSelectionSection.propTypes = {
+ children: PropTypes.node,
+}
+
+export default ContextSelectionSection
diff --git a/opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.module.scss b/opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.module.scss
new file mode 100644
index 00000000..0e902af0
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/context/ContextSelectionSection.module.scss
@@ -0,0 +1,28 @@
+/*!
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+.contextSelectionSection {
+ padding-left: var(--pf-c-page__main-breadcrumb--PaddingLeft);
+ flex-shrink: 0;
+ border-bottom: var(--pf-global--BorderWidth--sm) solid var(--pf-global--BorderColor--100);
+ background-color: var(--pf-c-page__main-breadcrumb--BackgroundColor);
+}
diff --git a/opendc-web/opendc-web-ui/src/components/context/ContextSelector.js b/opendc-web/opendc-web-ui/src/components/context/ContextSelector.js
new file mode 100644
index 00000000..3712cfa0
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/context/ContextSelector.js
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import PropTypes from 'prop-types'
+import { ContextSelector as PFContextSelector, ContextSelectorItem } from '@patternfly/react-core'
+import { useMemo, useState, useReducer } from 'react'
+import { contextSelector } from './ContextSelector.module.scss'
+
+function ContextSelector({ activeItem, items, onSelect, label }) {
+ const [isOpen, toggle] = useReducer((isOpen) => !isOpen, false)
+ const [searchValue, setSearchValue] = useState('')
+
+ const filteredItems = useMemo(
+ () => items.filter(({ name }) => name.toLowerCase().indexOf(searchValue.toLowerCase()) !== -1) || items,
+ [items, searchValue]
+ )
+
+ return (
+ <PFContextSelector
+ menuAppendTo={global.document?.body}
+ className={contextSelector}
+ toggleText={activeItem ? `${label}: ${activeItem.name}` : label}
+ onSearchInputChange={(value) => setSearchValue(value)}
+ searchInputValue={searchValue}
+ isOpen={isOpen}
+ onToggle={toggle}
+ onSelect={(event) => {
+ const targetId = event.target.value
+ const target = items.find((item) => item._id === targetId)
+
+ toggle()
+ onSelect(target)
+ }}
+ >
+ {filteredItems.map((item) => (
+ <ContextSelectorItem key={item._id} value={item._id}>
+ {item.name}
+ </ContextSelectorItem>
+ ))}
+ </PFContextSelector>
+ )
+}
+
+const Item = PropTypes.shape({
+ _id: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
+})
+
+ContextSelector.propTypes = {
+ activeItem: Item,
+ items: PropTypes.arrayOf(Item).isRequired,
+ onSelect: PropTypes.func.isRequired,
+ label: PropTypes.string,
+}
+
+export default ContextSelector
diff --git a/opendc-web/opendc-web-ui/src/components/context/ContextSelector.module.scss b/opendc-web/opendc-web-ui/src/components/context/ContextSelector.module.scss
new file mode 100644
index 00000000..fefba41f
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/context/ContextSelector.module.scss
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+.contextSelector {
+ width: auto;
+ margin-right: 20px;
+
+ --pf-c-context-selector__toggle--PaddingTop: var(--pf-global--spacer--sm);
+ --pf-c-context-selector__toggle--PaddingRight: 0;
+ --pf-c-context-selector__toggle--PaddingBottom: var(--pf-global--spacer--sm);
+ --pf-c-context-selector__toggle--PaddingLeft: 0;
+ --pf-c-context-selector__toggle--BorderWidth: 0;
+ --pf-c-context-selector__toggle-text--FontSize: var(--pf-global--FontSize--sm);
+
+ & :global(.pf-c-context-selector__toggle) {
+ &:active,
+ &:focus-within,
+ &:global(.pf-m-active) {
+ --pf-c-context-selector__toggle--after--BorderBottomWidth: 0;
+ }
+ }
+
+ &:global(.pf-m-expanded) > :global(.pf-c-context-selector__toggle) {
+ --pf-c-context-selector__toggle--after--BorderBottomWidth: 0;
+ }
+}
diff --git a/opendc-web/opendc-web-ui/src/components/context/PortfolioSelector.js b/opendc-web/opendc-web-ui/src/components/context/PortfolioSelector.js
new file mode 100644
index 00000000..694681ac
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/context/PortfolioSelector.js
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import { useRouter } from 'next/router'
+import { useMemo } from 'react'
+import { useProjectPortfolios } from '../../data/project'
+import ContextSelector from './ContextSelector'
+
+function PortfolioSelector() {
+ const router = useRouter()
+ const { project, portfolio: activePortfolioId } = router.query
+ const { data: portfolios = [] } = useProjectPortfolios(project)
+ const activePortfolio = useMemo(() => portfolios.find((portfolio) => portfolio._id === activePortfolioId), [
+ activePortfolioId,
+ portfolios,
+ ])
+
+ return (
+ <ContextSelector
+ label="Portfolio"
+ activeItem={activePortfolio}
+ items={portfolios}
+ onSelect={(portfolio) => router.push(`/projects/${portfolio.projectId}/portfolios/${portfolio._id}`)}
+ />
+ )
+}
+
+export default PortfolioSelector
diff --git a/opendc-web/opendc-web-ui/src/components/context/ProjectSelector.js b/opendc-web/opendc-web-ui/src/components/context/ProjectSelector.js
new file mode 100644
index 00000000..753632ab
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/context/ProjectSelector.js
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import PropTypes from 'prop-types'
+import { useRouter } from 'next/router'
+import { useMemo } from 'react'
+import { useProjects } from '../../data/project'
+import ContextSelector from './ContextSelector'
+
+function ProjectSelector({ projectId }) {
+ const router = useRouter()
+ const { data: projects = [] } = useProjects()
+ const activeProject = useMemo(() => projects.find((project) => project._id === projectId), [projectId, projects])
+
+ return (
+ <ContextSelector
+ label="Project"
+ activeItem={activeProject}
+ items={projects}
+ onSelect={(project) => router.push(`/projects/${project._id}`)}
+ />
+ )
+}
+
+ProjectSelector.propTypes = {
+ projectId: PropTypes.string,
+}
+
+export default ProjectSelector
diff --git a/opendc-web/opendc-web-ui/src/components/context/TopologySelector.js b/opendc-web/opendc-web-ui/src/components/context/TopologySelector.js
new file mode 100644
index 00000000..d5e51c6c
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/components/context/TopologySelector.js
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2021 AtLarge Research
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+import PropTypes from 'prop-types'
+import { useRouter } from 'next/router'
+import { useMemo } from 'react'
+import { useProjectTopologies } from '../../data/topology'
+import ContextSelector from './ContextSelector'
+
+function TopologySelector({ projectId, topologyId }) {
+ const router = useRouter()
+ const { data: topologies = [] } = useProjectTopologies(projectId)
+ const activeTopology = useMemo(() => topologies.find((topology) => topology._id === topologyId), [
+ topologyId,
+ topologies,
+ ])
+
+ return (
+ <ContextSelector
+ label="Topology"
+ activeItem={activeTopology}
+ items={topologies}
+ onSelect={(topology) => router.push(`/projects/${topology.projectId}/topologies/${topology._id}`)}
+ />
+ )
+}
+
+TopologySelector.propTypes = {
+ projectId: PropTypes.string,
+ topologyId: PropTypes.string,
+}
+
+export default TopologySelector
diff --git a/opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js b/opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js
index 5c17303f..c07a2c31 100644
--- a/opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js
+++ b/opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js
@@ -21,7 +21,9 @@
*/
import { useRouter } from 'next/router'
+import ContextSelectionSection from '../../../components/context/ContextSelectionSection'
import ProjectOverview from '../../../components/projects/ProjectOverview'
+import ProjectSelector from '../../../components/context/ProjectSelector'
import { useProject } from '../../../data/project'
import { AppPage } from '../../../components/AppPage'
import Head from 'next/head'
@@ -53,8 +55,14 @@ function Project() {
</Breadcrumb>
)
+ const contextSelectors = (
+ <ContextSelectionSection>
+ <ProjectSelector projectId={projectId} />
+ </ContextSelectionSection>
+ )
+
return (
- <AppPage breadcrumb={breadcrumb}>
+ <AppPage breadcrumb={breadcrumb} contextSelectors={contextSelectors}>
<Head>
<title>{project?.name ?? 'Project'} - OpenDC</title>
</Head>
diff --git a/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js b/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js
index 28b03c37..d1533d98 100644
--- a/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js
+++ b/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js
@@ -37,6 +37,9 @@ import {
TextContent,
} from '@patternfly/react-core'
import { AppPage } from '../../../../components/AppPage'
+import ContextSelectionSection from '../../../../components/context/ContextSelectionSection'
+import PortfolioSelector from '../../../../components/context/PortfolioSelector'
+import ProjectSelector from '../../../../components/context/ProjectSelector'
import BreadcrumbLink from '../../../../components/util/BreadcrumbLink'
import PortfolioOverview from '../../../../components/portfolios/PortfolioOverview'
import PortfolioResults from '../../../../components/portfolios/PortfolioResults'
@@ -65,8 +68,15 @@ function Portfolio() {
</Breadcrumb>
)
+ const contextSelectors = (
+ <ContextSelectionSection>
+ <ProjectSelector projectId={projectId} />
+ <PortfolioSelector projectId={projectId} portfolioId={portfolioId} />
+ </ContextSelectionSection>
+ )
+
return (
- <AppPage breadcrumb={breadcrumb}>
+ <AppPage breadcrumb={breadcrumb} contextSelectors={contextSelectors}>
<Head>
<title>Portfolio - OpenDC</title>
</Head>
diff --git a/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js b/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js
index ae26ae83..858f9b16 100644
--- a/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js
+++ b/opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js
@@ -21,6 +21,9 @@
*/
import { useRouter } from 'next/router'
+import ContextSelectionSection from '../../../../components/context/ContextSelectionSection'
+import ProjectSelector from '../../../../components/context/ProjectSelector'
+import TopologySelector from '../../../../components/context/TopologySelector'
import TopologyOverview from '../../../../components/topologies/TopologyOverview'
import { useProject } from '../../../../data/project'
import { useDispatch } from 'react-redux'
@@ -77,8 +80,15 @@ function Topology() {
</Breadcrumb>
)
+ const contextSelectors = (
+ <ContextSelectionSection>
+ <ProjectSelector projectId={projectId} />
+ <TopologySelector projectId={projectId} topologyId={topologyId} />
+ </ContextSelectionSection>
+ )
+
return (
- <AppPage breadcrumb={breadcrumb}>
+ <AppPage breadcrumb={breadcrumb} contextSelectors={contextSelectors}>
<Head>
<title>{project?.name ?? 'Topologies'} - OpenDC</title>
</Head>