diff options
| author | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2022-09-14 23:02:46 +0200 |
|---|---|---|
| committer | Fabian Mastenbroek <mail.fabianm@gmail.com> | 2022-09-20 16:07:05 +0200 |
| commit | 9dd75a9a40f7f2aebbc617980c99085f9dc688f8 (patch) | |
| tree | 12b9fc2ef1b864c5773b78fe102f789508af7716 | |
| parent | d2c0b9c038f5cbcb2b1528d4cb22b862309bd99a (diff) | |
refactor(web/ui): Move project selector into masthead
This change moves the project selector into the masthead since it
affects the whole application. This follows the PatternFly guidelines.
| -rw-r--r-- | opendc-web/opendc-web-ui/public/img/logo.svg | 191 | ||||
| -rw-r--r-- | opendc-web/opendc-web-ui/src/components/AppHeader.js | 46 | ||||
| -rw-r--r-- | opendc-web/opendc-web-ui/src/components/AppHeader.module.scss (renamed from opendc-web/opendc-web-ui/src/components/AppLogo.module.scss) | 6 | ||||
| -rw-r--r-- | opendc-web/opendc-web-ui/src/components/AppHeaderTools.js | 96 | ||||
| -rw-r--r-- | opendc-web/opendc-web-ui/src/components/AppHeaderUser.js | 81 | ||||
| -rw-r--r-- | opendc-web/opendc-web-ui/src/components/AppLogo.js | 46 | ||||
| -rw-r--r-- | opendc-web/opendc-web-ui/src/components/context/ContextSelector.js | 9 | ||||
| -rw-r--r-- | opendc-web/opendc-web-ui/src/components/context/ContextSelector.module.scss | 2 | ||||
| -rw-r--r-- | opendc-web/opendc-web-ui/src/components/context/ProjectSelector.js | 8 | ||||
| -rw-r--r-- | opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js | 10 | ||||
| -rw-r--r-- | opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js | 2 | ||||
| -rw-r--r-- | opendc-web/opendc-web-ui/src/pages/projects/[project]/topologies/[topology].js | 2 |
12 files changed, 348 insertions, 151 deletions
diff --git a/opendc-web/opendc-web-ui/public/img/logo.svg b/opendc-web/opendc-web-ui/public/img/logo.svg new file mode 100644 index 00000000..5283a034 --- /dev/null +++ b/opendc-web/opendc-web-ui/public/img/logo.svg @@ -0,0 +1,191 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + xmlns:dc="http://purl.org/dc/elements/1.1/" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns="http://www.w3.org/2000/svg" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + width="4.3656249mm" + height="5.4239674mm" + viewBox="0 0 4.3656249 5.4239674" + version="1.1" + id="svg4738" + inkscape:version="0.92.1 r15371" + sodipodi:docname="opendc.svg"> + <defs + id="defs4732" /> + <sodipodi:namedview + id="base" + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1.0" + inkscape:pageopacity="0.0" + inkscape:pageshadow="2" + inkscape:zoom="22.4" + inkscape:cx="-5.0874286" + inkscape:cy="6.401307" + inkscape:document-units="mm" + inkscape:current-layer="layer1" + showgrid="false" + inkscape:window-width="1920" + inkscape:window-height="1027" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" /> + <metadata + id="metadata4735"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <dc:title></dc:title> + </cc:Work> + </rdf:RDF> + </metadata> + <g + inkscape:label="Layer 1" + inkscape:groupmode="layer" + id="layer1" + transform="translate(-16.538532,-146.52225)"> + <g + transform="matrix(0.26458333,0,0,0.26458333,-15.13354,-112.7517)" + id="g4333" + inkscape:export-filename="h:\Desktop\logo.png" + inkscape:export-xdpi="561.54816" + inkscape:export-ydpi="561.54816"> + <path + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\stackv2.png" + style="fill:#48a1cd;fill-opacity:1;stroke:none" + d="m 119.95547,988.18306 8,4 v -4 l -8,-4 z" + id="path4052-1-2-8" + inkscape:connector-curvature="0" /> + <path + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\stackv2.png" + style="fill:#82d0e7;fill-opacity:1;stroke:none" + d="m 127.95547,988.18306 v 4 l 8.00001,-4 v -4 z" + id="path4054-4-9-2" + inkscape:connector-curvature="0" /> + <path + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\stackv2.png" + style="fill:#82d0e7;fill-opacity:1;stroke:none" + d="m 119.95547,984.18306 8,-4 8.00001,4 -8.00001,4 z" + id="path4056-2-1-5" + inkscape:connector-curvature="0" /> + <path + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\comparison.png" + inkscape:connector-curvature="0" + id="path4048-1-9" + d="m 119.95547,992.18306 8,4 v -4 l -8,-4 z" + style="fill:#d1af2e;fill-opacity:1;stroke:none" /> + <path + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\comparison.png" + inkscape:connector-curvature="0" + id="path4050-7-2" + d="m 127.95546,992.18306 v 4 l 8.00001,-4 v -4 z" + style="fill:#edd667;fill-opacity:1;stroke:none" /> + <path + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\comparison.png" + style="fill:#df6f20;fill-opacity:1;stroke:none" + d="m 119.95547,996.18306 8,4.00004 v -4.00004 l -8,-4 z" + id="path3883-9-9-8" + inkscape:connector-curvature="0" /> + <path + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\comparison.png" + style="fill:#ed9c67;fill-opacity:1;stroke:none" + d="m 127.95547,996.18306 v 4.00004 l 8,-4.00004 v -4 z" + id="path3885-8-9-1" + inkscape:connector-curvature="0" /> + <path + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\comparison.png" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" + d="m 119.95547,984.18306 8,-4 8,4 -8,4 z" + id="path3893-6-0-8" + inkscape:connector-curvature="0" /> + <path + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\comparison.png" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 119.95547,984.18306 v 4 l 8,4 8,-4 v -4" + id="path3895-2-6-1" + inkscape:connector-curvature="0" /> + <path + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\comparison.png" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 127.95547,988.18306 v 12.00004" + id="path3897-3-2-1" + inkscape:connector-curvature="0" + sodipodi:nodetypes="cc" /> + <path + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\comparison.png" + inkscape:connector-curvature="0" + id="path3899-8-1-7" + d="m 119.95547,988.18306 v 4 l 8,4 8,-4 v -4" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" /> + <path + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\comparison.png" + style="fill:none;stroke:#000000;stroke-width:0.5;stroke-linecap:butt;stroke-linejoin:round;stroke-opacity:1" + d="m 119.95547,992.18306 v 4 l 8,4.00004 8,-4.00004 v -4" + id="path3901-5-6-1" + inkscape:connector-curvature="0" /> + <circle + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\stackv2.png" + transform="matrix(1.0403949,-0.44307824,0.3060712,0.9369482,-235.62413,33.696703)" + id="path3906-6-2-4-1-2" + style="fill:#000000;fill-opacity:1;stroke:none" + cx="43.5" + cy="1044.8622" + r="0.5" /> + <circle + inkscape:export-ydpi="1307.2168" + inkscape:export-xdpi="1307.2168" + inkscape:export-filename="h:\Desktop\stackv2.png" + transform="matrix(1.0403949,-0.44307824,0.3060712,0.9369482,-235.62413,37.696663)" + id="path3910-3-0-1-9-1" + style="fill:#000000;fill-opacity:1;stroke:none" + cx="43.5" + cy="1044.8622" + r="0.5" /> + <circle + style="fill:#000000;fill-opacity:1;stroke:none" + id="path4108-7-3-6" + transform="matrix(1.0403949,-0.44307824,0.3060712,0.9369482,-235.62413,29.696659)" + inkscape:export-filename="h:\Desktop\stackv2.png" + inkscape:export-xdpi="1307.2168" + inkscape:export-ydpi="1307.2168" + cx="43.5" + cy="1044.8622" + r="0.5" /> + </g> + </g> +</svg> diff --git a/opendc-web/opendc-web-ui/src/components/AppHeader.js b/opendc-web/opendc-web-ui/src/components/AppHeader.js index fd54b3ad..54f3bbf3 100644 --- a/opendc-web/opendc-web-ui/src/components/AppHeader.js +++ b/opendc-web/opendc-web-ui/src/components/AppHeader.js @@ -20,24 +20,44 @@ * SOFTWARE. */ -import { PageHeader } from '@patternfly/react-core' import React from 'react' +import { + Masthead, + MastheadMain, + MastheadBrand, + MastheadContent, + Toolbar, + ToolbarContent, + ToolbarItem, +} from '@patternfly/react-core' +import Link from "next/link"; import AppHeaderTools from './AppHeaderTools' -import { AppNavigation } from './AppNavigation' -import AppLogo from './AppLogo' +import AppHeaderUser from './AppHeaderUser' +import ProjectSelector from './context/ProjectSelector' -export function AppHeader() { - // eslint-disable-next-line @next/next/no-img-element - const logo = <img src="/img/logo.png" width={30} height={30} alt="OpenDC" /> +import styles from './AppHeader.module.scss' +export function AppHeader() { return ( - <PageHeader - logo={logo} - logoProps={{ href: '/' }} - logoComponent={AppLogo} - headerTools={<AppHeaderTools />} - topNav={<AppNavigation />} - /> + <Masthead id="app-header"> + <MastheadMain> + <MastheadBrand className={styles.logo} component={props => <Link href="/projects"><a {...props} /></Link>}> + <img src="/img/logo.svg" alt="OpenDC logo" width={30} height={30} /> + <span>OpenDC</span> + </MastheadBrand> + </MastheadMain> + <MastheadContent> + <Toolbar id="toolbar" isFullHeight isStatic> + <ToolbarContent> + <ToolbarItem> + <ProjectSelector /> + </ToolbarItem> + <AppHeaderTools /> + <AppHeaderUser /> + </ToolbarContent> + </Toolbar> + </MastheadContent> + </Masthead> ) } diff --git a/opendc-web/opendc-web-ui/src/components/AppLogo.module.scss b/opendc-web/opendc-web-ui/src/components/AppHeader.module.scss index 3d228cb6..a7a6e325 100644 --- a/opendc-web/opendc-web-ui/src/components/AppLogo.module.scss +++ b/opendc-web/opendc-web-ui/src/components/AppHeader.module.scss @@ -20,10 +20,12 @@ * SOFTWARE. */ -.appLogo { +.logo { span { - margin-left: 4px; + margin-left: 8px; color: #fff; + align-self: center; + font-weight: 500; } &:hover, diff --git a/opendc-web/opendc-web-ui/src/components/AppHeaderTools.js b/opendc-web/opendc-web-ui/src/components/AppHeaderTools.js index 3e58b209..499bceef 100644 --- a/opendc-web/opendc-web-ui/src/components/AppHeaderTools.js +++ b/opendc-web/opendc-web-ui/src/components/AppHeaderTools.js @@ -21,29 +21,19 @@ */ import { - Avatar, Button, ButtonVariant, Dropdown, - DropdownGroup, DropdownItem, - DropdownToggle, KebabToggle, - PageHeaderTools, - PageHeaderToolsGroup, - PageHeaderToolsItem, - Skeleton, + ToolbarGroup, + ToolbarItem, } from '@patternfly/react-core' -import { useState } from 'react' -import { useAuth } from '../auth' +import { useReducer } from 'react' import { GithubIcon, HelpIcon } from '@patternfly/react-icons' function AppHeaderTools() { - const { logout, user, isAuthenticated, isLoading } = useAuth() - const username = isAuthenticated || isLoading ? user?.name : 'Anonymous' - const avatar = isAuthenticated || isLoading ? user?.picture : '/img/avatar.svg' - - const [isKebabDropdownOpen, setKebabDropdownOpen] = useState(false) + const [isKebabDropdownOpen, toggleKebabDropdown] = useReducer((t) => !t, false) const kebabDropdownItems = [ <DropdownItem key={0} @@ -55,23 +45,14 @@ function AppHeaderTools() { />, ] - const [isDropdownOpen, setDropdownOpen] = useState(false) - const userDropdownItems = [ - <DropdownGroup key="group 2"> - <DropdownItem - key="group 2 logout" - isDisabled={!isAuthenticated} - onClick={() => logout({ returnTo: window.location.origin })} - > - Logout - </DropdownItem> - </DropdownGroup>, - ] - return ( - <PageHeaderTools> - <PageHeaderToolsGroup visibility={{ default: 'hidden', lg: 'visible' }}> - <PageHeaderToolsItem> + <ToolbarGroup + variant="icon-button-group" + alignment={{ default: 'alignRight' }} + spacer={{ default: 'spacerNone', md: 'spacerMd' }} + > + <ToolbarGroup variant="icon-button-group" visibility={{ default: 'hidden', lg: 'visible' }}> + <ToolbarItem> <Button component="a" href="https://github.com/atlarge-research/opendc" @@ -81,8 +62,8 @@ function AppHeaderTools() { > <GithubIcon /> </Button> - </PageHeaderToolsItem> - <PageHeaderToolsItem> + </ToolbarItem> + <ToolbarItem> <Button component="a" href="https://opendc.org/" @@ -92,45 +73,18 @@ function AppHeaderTools() { > <HelpIcon /> </Button> - </PageHeaderToolsItem> - </PageHeaderToolsGroup> - <PageHeaderToolsGroup> - <PageHeaderToolsItem visibility={{ lg: 'hidden' }}> - <Dropdown - isPlain - position="right" - toggle={<KebabToggle onToggle={() => setKebabDropdownOpen(!isKebabDropdownOpen)} />} - isOpen={isKebabDropdownOpen} - dropdownItems={kebabDropdownItems} - /> - </PageHeaderToolsItem> - <PageHeaderToolsItem visibility={{ default: 'hidden', md: 'visible' }}> - <Dropdown - isPlain - position="right" - isOpen={isDropdownOpen} - toggle={ - <DropdownToggle onToggle={() => setDropdownOpen(!isDropdownOpen)}> - {username ?? ( - <Skeleton - fontSize="xs" - width="150px" - className="pf-u-display-inline-flex" - screenreaderText="Loading username" - /> - )} - </DropdownToggle> - } - dropdownItems={userDropdownItems} - /> - </PageHeaderToolsItem> - </PageHeaderToolsGroup> - {avatar ? ( - <Avatar src={avatar} alt="Avatar image" /> - ) : ( - <Skeleton className="pf-c-avatar" shape="circle" width="2.25rem" screenreaderText="Loading avatar" /> - )} - </PageHeaderTools> + </ToolbarItem> + </ToolbarGroup> + <ToolbarItem visibility={{ lg: 'hidden' }}> + <Dropdown + isPlain + position="right" + toggle={<KebabToggle onToggle={toggleKebabDropdown} />} + isOpen={isKebabDropdownOpen} + dropdownItems={kebabDropdownItems} + /> + </ToolbarItem> + </ToolbarGroup> ) } diff --git a/opendc-web/opendc-web-ui/src/components/AppHeaderUser.js b/opendc-web/opendc-web-ui/src/components/AppHeaderUser.js new file mode 100644 index 00000000..809f3ac3 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/components/AppHeaderUser.js @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2022 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 { + Dropdown, + DropdownToggle, + Skeleton, + ToolbarItem, + DropdownItem, + DropdownGroup, + Avatar, +} from '@patternfly/react-core' +import { useReducer } from 'react' +import { useAuth } from '../auth' + +export default function AppHeaderUser() { + const { logout, user, isAuthenticated, isLoading } = useAuth() + const username = isAuthenticated || isLoading ? user?.name : 'Anonymous' + const avatar = isAuthenticated || isLoading ? user?.picture : '/img/avatar.svg' + + const [isDropdownOpen, toggleDropdown] = useReducer((t) => !t, false) + const userDropdownItems = [ + <DropdownGroup key="group 2"> + <DropdownItem + key="group 2 logout" + isDisabled={!isAuthenticated} + onClick={() => logout({ returnTo: window.location.origin })} + > + Logout + </DropdownItem> + </DropdownGroup>, + ] + + const avatarComponent = avatar ? ( + <Avatar src={avatar} alt="Avatar image" /> + ) : ( + <Skeleton className="pf-c-avatar" shape="circle" width="2.25rem" screenreaderText="Loading avatar" /> + ) + + return ( + <ToolbarItem visibility={{ default: 'hidden', md: 'visible' }}> + <Dropdown + isFullHeight + position="right" + isOpen={isDropdownOpen} + toggle={ + <DropdownToggle onToggle={toggleDropdown} icon={avatarComponent}> + {username ?? ( + <Skeleton + fontSize="xs" + width="150px" + className="pf-u-display-inline-flex" + screenreaderText="Loading username" + /> + )} + </DropdownToggle> + } + dropdownItems={userDropdownItems} + /> + </ToolbarItem> + ) +} diff --git a/opendc-web/opendc-web-ui/src/components/AppLogo.js b/opendc-web/opendc-web-ui/src/components/AppLogo.js deleted file mode 100644 index 92663295..00000000 --- a/opendc-web/opendc-web-ui/src/components/AppLogo.js +++ /dev/null @@ -1,46 +0,0 @@ -/* - * 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 Link from 'next/link' -import { appLogo } from './AppLogo.module.scss' - -function AppLogo({ href, children, className, ...props }) { - return ( - <> - <Link href={href}> - <a {...props} className={`${className ?? ''} ${appLogo}`}> - {children} - <span>OpenDC</span> - </a> - </Link> - </> - ) -} - -AppLogo.propTypes = { - href: PropTypes.string.isRequired, - children: PropTypes.node, - className: PropTypes.string, -} - -export default AppLogo diff --git a/opendc-web/opendc-web-ui/src/components/context/ContextSelector.js b/opendc-web/opendc-web-ui/src/components/context/ContextSelector.js index a99b60c0..436c179b 100644 --- a/opendc-web/opendc-web-ui/src/components/context/ContextSelector.js +++ b/opendc-web/opendc-web-ui/src/components/context/ContextSelector.js @@ -23,9 +23,9 @@ import PropTypes from 'prop-types' import { ContextSelector as PFContextSelector, ContextSelectorItem } from '@patternfly/react-core' import { useMemo, useState } from 'react' -import { contextSelector } from './ContextSelector.module.scss' +import styles from './ContextSelector.module.scss' -function ContextSelector({ activeItem, items, onSelect, onToggle, isOpen, label }) { +function ContextSelector({ activeItem, items, onSelect, onToggle, isOpen, label, isFullHeight, type = 'page' }) { const [searchValue, setSearchValue] = useState('') const filteredItems = useMemo( () => items.filter(({ name }) => name.toLowerCase().indexOf(searchValue.toLowerCase()) !== -1) || items, @@ -34,7 +34,7 @@ function ContextSelector({ activeItem, items, onSelect, onToggle, isOpen, label return ( <PFContextSelector - className={contextSelector} + className={type === 'page' && styles.pageSelector} toggleText={activeItem ? `${label}: ${activeItem.name}` : label} onSearchInputChange={(value) => setSearchValue(value)} searchInputValue={searchValue} @@ -47,6 +47,7 @@ function ContextSelector({ activeItem, items, onSelect, onToggle, isOpen, label onSelect(target) onToggle(!isOpen) }} + isFullHeight={isFullHeight} > {filteredItems.map((item) => ( <ContextSelectorItem key={item.id} value={item.id}> @@ -69,6 +70,8 @@ ContextSelector.propTypes = { onToggle: PropTypes.func.isRequired, isOpen: PropTypes.bool, label: PropTypes.string, + isFullHeight: PropTypes.bool, + type: PropTypes.oneOf(['app', 'page']), } 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 index c4b89503..4f86ac64 100644 --- a/opendc-web/opendc-web-ui/src/components/context/ContextSelector.module.scss +++ b/opendc-web/opendc-web-ui/src/components/context/ContextSelector.module.scss @@ -20,7 +20,7 @@ * SOFTWARE. */ -.contextSelector.contextSelector { +.pageSelector.pageSelector { // Ensure this selector has precedence over the default one margin-right: 20px; diff --git a/opendc-web/opendc-web-ui/src/components/context/ProjectSelector.js b/opendc-web/opendc-web-ui/src/components/context/ProjectSelector.js index 7721e04c..5f47c798 100644 --- a/opendc-web/opendc-web-ui/src/components/context/ProjectSelector.js +++ b/opendc-web/opendc-web-ui/src/components/context/ProjectSelector.js @@ -22,14 +22,16 @@ import { useRouter } from 'next/router' import { useState } from 'react' -import { useProjects } from '../../data/project' +import { useProjects, useProject } from '../../data/project' import { Project } from '../../shapes' import ContextSelector from './ContextSelector' -function ProjectSelector({ activeProject }) { +function ProjectSelector() { const router = useRouter() + const projectId = +router.query['project'] const [isOpen, setOpen] = useState(false) + const { data: activeProject } = useProject(+projectId) const { data: projects = [] } = useProjects({ enabled: isOpen }) return ( @@ -40,6 +42,8 @@ function ProjectSelector({ activeProject }) { onSelect={(project) => router.push(`/projects/${project.id}`)} onToggle={setOpen} isOpen={isOpen} + isFullHeight + type="app" /> ) } 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 39fcb4f3..e4e2156b 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,9 +21,7 @@ */ 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' @@ -55,14 +53,8 @@ function Project() { </Breadcrumb> ) - const contextSelectors = ( - <ContextSelectionSection> - <ProjectSelector activeProject={project} /> - </ContextSelectionSection> - ) - return ( - <AppPage breadcrumb={breadcrumb} contextSelectors={contextSelectors}> + <AppPage breadcrumb={breadcrumb}> <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 4b9aa437..460785c1 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 @@ -40,7 +40,6 @@ import { 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 { usePortfolio } from '../../../../data/project' @@ -81,7 +80,6 @@ function Portfolio() { const contextSelectors = ( <ContextSelectionSection> - <ProjectSelector activeProject={project} /> <PortfolioSelector activePortfolio={portfolio} /> </ContextSelectionSection> ) 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 c331761b..d3892710 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 @@ -23,7 +23,6 @@ import dynamic from 'next/dynamic' 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 { useDispatch } from 'react-redux' @@ -90,7 +89,6 @@ function Topology() { const contextSelectors = ( <ContextSelectionSection> - <ProjectSelector activeProject={project} /> <TopologySelector activeTopology={topology} /> </ContextSelectionSection> ) |
