diff options
Diffstat (limited to 'opendc-web/opendc-web-ui/src/pages')
16 files changed, 377 insertions, 210 deletions
diff --git a/opendc-web/opendc-web-ui/src/pages/404.js b/opendc-web/opendc-web-ui/src/pages/404.js new file mode 100644 index 00000000..cc9281fc --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/404.js @@ -0,0 +1,19 @@ +import React from 'react' +import Head from 'next/head' +import TerminalWindow from '../components/not-found/TerminalWindow' +import style from './404.module.scss' + +const NotFound = () => { + return ( + <> + <Head> + <title>Page Not Found - OpenDC</title> + </Head> + <div className={style['not-found-backdrop']}> + <TerminalWindow /> + </div> + </> + ) +} + +export default NotFound diff --git a/opendc-web/opendc-web-ui/src/pages/404.module.scss b/opendc-web/opendc-web-ui/src/pages/404.module.scss new file mode 100644 index 00000000..e91c2780 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/404.module.scss @@ -0,0 +1,8 @@ +.not-found-backdrop { + display: flex; + + width: 100%; + height: 100%; + + background-image: linear-gradient(135deg, #00678a, #008fbf, #00a6d6); +} diff --git a/opendc-web/opendc-web-ui/src/pages/App.js b/opendc-web/opendc-web-ui/src/pages/App.js deleted file mode 100644 index ea62e8dc..00000000 --- a/opendc-web/opendc-web-ui/src/pages/App.js +++ /dev/null @@ -1,103 +0,0 @@ -import PropTypes from 'prop-types' -import React, { useEffect } from 'react' -import { HotKeys } from 'react-hotkeys' -import { useDispatch, useSelector } from 'react-redux' -import { openPortfolioSucceeded } from '../actions/portfolios' -import { openProjectSucceeded } from '../actions/projects' -import ToolPanelComponent from '../components/app/map/controls/ToolPanelComponent' -import LoadingScreen from '../components/app/map/LoadingScreen' -import ScaleIndicatorContainer from '../containers/app/map/controls/ScaleIndicatorContainer' -import MapStage from '../containers/app/map/MapStage' -import TopologySidebarContainer from '../containers/app/sidebars/topology/TopologySidebarContainer' -import DeleteMachineModal from '../containers/modals/DeleteMachineModal' -import DeleteRackModal from '../containers/modals/DeleteRackModal' -import DeleteRoomModal from '../containers/modals/DeleteRoomModal' -import EditRackNameModal from '../containers/modals/EditRackNameModal' -import EditRoomNameModal from '../containers/modals/EditRoomNameModal' -import NewTopologyModal from '../containers/modals/NewTopologyModal' -import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' -import ProjectSidebarContainer from '../containers/app/sidebars/project/ProjectSidebarContainer' -import { openScenarioSucceeded } from '../actions/scenarios' -import NewPortfolioModal from '../containers/modals/NewPortfolioModal' -import NewScenarioModal from '../containers/modals/NewScenarioModal' -import PortfolioResultsContainer from '../containers/app/results/PortfolioResultsContainer' -import KeymapConfiguration from '../shortcuts/keymap' -import { useDocumentTitle } from '../util/hooks' - -const App = ({ projectId, portfolioId, scenarioId }) => { - const projectName = useSelector( - (state) => - state.currentProjectId !== '-1' && - state.objects.project[state.currentProjectId] && - state.objects.project[state.currentProjectId].name - ) - const topologyIsLoading = useSelector((state) => state.currentTopologyId === '-1') - - const dispatch = useDispatch() - useEffect(() => { - if (scenarioId) { - dispatch(openScenarioSucceeded(projectId, portfolioId, scenarioId)) - } else if (portfolioId) { - dispatch(openPortfolioSucceeded(projectId, portfolioId)) - } else { - dispatch(openProjectSucceeded(projectId)) - } - }, [projectId, portfolioId, scenarioId, dispatch]) - - const constructionElements = topologyIsLoading ? ( - <div className="full-height d-flex align-items-center justify-content-center"> - <LoadingScreen /> - </div> - ) : ( - <div className="full-height"> - <MapStage /> - <ScaleIndicatorContainer /> - <ToolPanelComponent /> - <ProjectSidebarContainer /> - <TopologySidebarContainer /> - </div> - ) - - const portfolioElements = ( - <div className="full-height app-page-container"> - <ProjectSidebarContainer /> - <div className="container-fluid full-height"> - <PortfolioResultsContainer /> - </div> - </div> - ) - - const scenarioElements = ( - <div className="full-height app-page-container"> - <ProjectSidebarContainer /> - <div className="container-fluid full-height"> - <h2>Scenario loading</h2> - </div> - </div> - ) - - useDocumentTitle(projectName ? projectName + ' - OpenDC' : 'Simulation - OpenDC') - - return ( - <HotKeys keyMap={KeymapConfiguration} className="page-container full-height"> - <AppNavbarContainer fullWidth={true} /> - {scenarioId ? scenarioElements : portfolioId ? portfolioElements : constructionElements} - <NewTopologyModal /> - <NewPortfolioModal /> - <NewScenarioModal /> - <EditRoomNameModal /> - <DeleteRoomModal /> - <EditRackNameModal /> - <DeleteRackModal /> - <DeleteMachineModal /> - </HotKeys> - ) -} - -App.propTypes = { - projectId: PropTypes.string.isRequired, - portfolioId: PropTypes.string, - scenarioId: PropTypes.string, -} - -export default App diff --git a/opendc-web/opendc-web-ui/src/pages/Home.sass b/opendc-web/opendc-web-ui/src/pages/Home.sass deleted file mode 100644 index 79cb9698..00000000 --- a/opendc-web/opendc-web-ui/src/pages/Home.sass +++ /dev/null @@ -1,9 +0,0 @@ -.body-wrapper - position: relative - overflow-y: hidden - -.intro-section, .modeling-section, .technologies-section - background-color: #fff - -.stakeholder-section, .simulation-section, .team-section - background-color: #f2f2f2 diff --git a/opendc-web/opendc-web-ui/src/pages/NotFound.js b/opendc-web/opendc-web-ui/src/pages/NotFound.js deleted file mode 100644 index b933ffa5..00000000 --- a/opendc-web/opendc-web-ui/src/pages/NotFound.js +++ /dev/null @@ -1,15 +0,0 @@ -import React from 'react' -import TerminalWindow from '../components/not-found/TerminalWindow' -import './NotFound.sass' -import { useDocumentTitle } from '../util/hooks' - -const NotFound = () => { - useDocumentTitle('Page Not Found - OpenDC') - return ( - <div className="not-found-backdrop"> - <TerminalWindow /> - </div> - ) -} - -export default NotFound diff --git a/opendc-web/opendc-web-ui/src/pages/NotFound.sass b/opendc-web/opendc-web-ui/src/pages/NotFound.sass deleted file mode 100644 index 59231f7a..00000000 --- a/opendc-web/opendc-web-ui/src/pages/NotFound.sass +++ /dev/null @@ -1,11 +0,0 @@ -.not-found-backdrop - position: absolute - left: 0 - top: 0 - - margin: 0 - padding: 0 - width: 100% - height: 100% - - background-image: linear-gradient(135deg, #00678a, #008fbf, #00A6D6) diff --git a/opendc-web/opendc-web-ui/src/pages/Profile.js b/opendc-web/opendc-web-ui/src/pages/Profile.js deleted file mode 100644 index ea781686..00000000 --- a/opendc-web/opendc-web-ui/src/pages/Profile.js +++ /dev/null @@ -1,31 +0,0 @@ -import React from 'react' -import { useDispatch } from 'react-redux' -import { openDeleteProfileModal } from '../actions/modals/profile' -import DeleteProfileModal from '../containers/modals/DeleteProfileModal' -import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' -import { useDocumentTitle } from '../util/hooks' - -const Profile = () => { - const dispatch = useDispatch() - const onDelete = () => dispatch(openDeleteProfileModal()) - - useDocumentTitle('My Profile - OpenDC') - return ( - <div className="full-height"> - <AppNavbarContainer fullWidth={false} /> - <div className="container text-page-container full-height"> - <button className="btn btn-danger mb-2 ml-auto mr-auto" style={{ maxWidth: 300 }} onClick={onDelete}> - Delete my account on OpenDC - </button> - <p className="text-muted text-center"> - This does not delete your Google account, but simply disconnects it from the OpenDC platform and - deletes any project info that is associated with you (projects you own and any authorizations you - may have on other projects). - </p> - </div> - <DeleteProfileModal /> - </div> - ) -} - -export default Profile diff --git a/opendc-web/opendc-web-ui/src/pages/Projects.js b/opendc-web/opendc-web-ui/src/pages/Projects.js deleted file mode 100644 index 5e642a03..00000000 --- a/opendc-web/opendc-web-ui/src/pages/Projects.js +++ /dev/null @@ -1,30 +0,0 @@ -import React, { useEffect } from 'react' -import { useDispatch } from 'react-redux' -import { fetchAuthorizationsOfCurrentUser } from '../actions/users' -import ProjectFilterPanel from '../components/projects/FilterPanel' -import NewProjectModal from '../containers/modals/NewProjectModal' -import NewProjectButtonContainer from '../containers/projects/NewProjectButtonContainer' -import VisibleProjectList from '../containers/projects/VisibleProjectAuthList' -import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' -import { useDocumentTitle } from '../util/hooks' - -function Projects() { - const dispatch = useDispatch() - - useEffect(() => dispatch(fetchAuthorizationsOfCurrentUser())) - useDocumentTitle('My Projects - OpenDC') - - return ( - <div className="full-height"> - <AppNavbarContainer fullWidth={false} /> - <div className="container text-page-container full-height"> - <ProjectFilterPanel /> - <VisibleProjectList /> - <NewProjectButtonContainer /> - </div> - <NewProjectModal /> - </div> - ) -} - -export default Projects diff --git a/opendc-web/opendc-web-ui/src/pages/_app.js b/opendc-web/opendc-web-ui/src/pages/_app.js new file mode 100644 index 00000000..4ef4445c --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/_app.js @@ -0,0 +1,69 @@ +/* + * 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 Head from 'next/head' +import { Provider } from 'react-redux' +import { useStore } from '../redux' +import '../index.scss' +import { AuthProvider, useAuth } from '../auth' +import * as Sentry from '@sentry/react' +import { Integrations } from '@sentry/tracing' + +// This setup is necessary to forward the Auth0 context to the Redux context +const Inner = ({ Component, pageProps }) => { + const auth = useAuth() + const store = useStore(pageProps.initialReduxState, { auth }) + return ( + <Provider store={store}> + <Component {...pageProps} /> + </Provider> + ) +} + +const dsn = process.env.NEXT_PUBLIC_SENTRY_DSN +// Initialize Sentry if the user has configured a DSN +if (process.browser && dsn) { + if (dsn) { + Sentry.init({ + environment: process.env.NODE_ENV, + dsn: dsn, + integrations: [new Integrations.BrowserTracing()], + tracesSampleRate: 0.1, + }) + } +} + +export default function App(props) { + return ( + <> + <Head> + <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no" /> + <meta name="theme-color" content="#00A6D6" /> + </Head> + <Sentry.ErrorBoundary fallback={"An error has occurred"}> + <AuthProvider> + <Inner {...props} /> + </AuthProvider> + </Sentry.ErrorBoundary> + </> + ) +} diff --git a/opendc-web/opendc-web-ui/src/pages/_document.js b/opendc-web/opendc-web-ui/src/pages/_document.js new file mode 100644 index 00000000..8e4680c0 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/_document.js @@ -0,0 +1,95 @@ +/* + * 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 Document, { Html, Head, Main, NextScript } from 'next/document' + +class OpenDCDocument extends Document { + render() { + return ( + <Html> + <Head> + <meta charSet="utf-8" /> + <meta name="theme-color" content="#00A6D6" /> + <meta + name="description" + content="Collaborative Datacenter Simulation and Exploration for Everybody" + /> + <meta name="author" content="@Large Research" /> + <meta + name="keywords" + content="OpenDC, Datacenter, Simulation, Simulator, Collaborative, Distributed, Cluster" + /> + <link rel="manifest" href="/manifest.json" /> + <link rel="shortcut icon" href="/favicon.ico" /> + + {/* Twitter Card data */} + <meta name="twitter:card" content="summary" /> + <meta name="twitter:site" content="@LargeResearch" /> + <meta name="twitter:title" content="OpenDC" /> + <meta + name="twitter:description" + content="Collaborative Datacenter Simulation and Exploration for Everybody" + /> + <meta name="twitter:creator" content="@LargeResearch" /> + <meta name="twitter:image" content="http://opendc.org/img/logo.png" /> + + {/* OpenGraph meta tags */} + <meta property="og:title" content="OpenDC" /> + <meta property="og:site_name" content="OpenDC" /> + <meta property="og:type" content="website" /> + <meta property="og:image" content="http://opendc.org/img/logo.png" /> + <meta property="og:url" content="http://opendc.org/" /> + <meta + property="og:description" + content="OpenDC provides collaborative online datacenter modeling, diverse and effective datacenter simulation, and exploratory datacenter performance feedback." + /> + <meta property="og:locale" content="en_US" /> + + {/* CDN Dependencies */} + <link + href="https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&display=swap" + rel="stylesheet" + /> + + {/* Google Analytics */} + <script async src="https://www.googletagmanager.com/gtag/js?id=UA-84285092-3" /> + <script + dangerouslySetInnerHTML={{ + __html: ` + window.dataLayer = window.dataLayer || []; + function gtag(){dataLayer.push(arguments);} + gtag('js', new Date()); + gtag('config', 'UA-84285092-3'); + `, + }} + /> + </Head> + <body> + <Main /> + <NextScript /> + </body> + </Html> + ) + } +} + +export default OpenDCDocument diff --git a/opendc-web/opendc-web-ui/src/pages/Home.js b/opendc-web/opendc-web-ui/src/pages/index.js index fb383426..bb904eb6 100644 --- a/opendc-web/opendc-web-ui/src/pages/Home.js +++ b/opendc-web/opendc-web-ui/src/pages/index.js @@ -1,4 +1,5 @@ import React from 'react' +import Head from 'next/head' import ContactSection from '../components/home/ContactSection' import IntroSection from '../components/home/IntroSection' import JumbotronHeader from '../components/home/JumbotronHeader' @@ -8,25 +9,33 @@ import StakeholderSection from '../components/home/StakeholderSection' import TeamSection from '../components/home/TeamSection' import TechnologiesSection from '../components/home/TechnologiesSection' import HomeNavbar from '../components/navigation/HomeNavbar' -import './Home.sass' -import { useDocumentTitle } from '../util/hooks' +import { + introSection, + stakeholderSection, + modelingSection, + simulationSection, + technologiesSection, + teamSection, +} from './index.module.scss' function Home() { - useDocumentTitle('OpenDC') return ( - <div> + <> + <Head> + <title>OpenDC</title> + </Head> <HomeNavbar /> <div className="body-wrapper page-container"> <JumbotronHeader /> - <IntroSection /> - <StakeholderSection /> - <ModelingSection /> - <SimulationSection /> - <TechnologiesSection /> - <TeamSection /> + <IntroSection className={introSection} /> + <StakeholderSection className={stakeholderSection} /> + <ModelingSection className={modelingSection} /> + <SimulationSection className={simulationSection} /> + <TechnologiesSection className={technologiesSection} /> + <TeamSection className={teamSection} /> <ContactSection /> </div> - </div> + </> ) } diff --git a/opendc-web/opendc-web-ui/src/pages/index.module.scss b/opendc-web/opendc-web-ui/src/pages/index.module.scss new file mode 100644 index 00000000..aed1d88f --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/index.module.scss @@ -0,0 +1,16 @@ +.bodyWrapper { + position: relative; + overflow-y: hidden; +} + +.introSection, +.modelingSection, +.technologiesSection { + background-color: #fff; +} + +.stakeholderSection, +.simulationSection, +.teamSection { + background-color: #f2f2f2; +} diff --git a/opendc-web/opendc-web-ui/src/pages/logout.js b/opendc-web/opendc-web-ui/src/pages/logout.js new file mode 100644 index 00000000..e96e0605 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/logout.js @@ -0,0 +1,39 @@ +/* + * 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 React from 'react' +import Head from 'next/head' +import AppNavbarContainer from '../containers/navigation/AppNavbarContainer' + +function Logout() { + return ( + <> + <Head> + <title>Logged Out - OpenDC</title> + </Head> + <AppNavbarContainer fullWidth={false} /> + <span>Logged out successfully</span> + </> + ) +} + +export default Logout 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 new file mode 100644 index 00000000..72316bc9 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/projects/[project]/index.js @@ -0,0 +1,37 @@ +/* + * 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 App from '../../../containers/app/App' + +function Project() { + const router = useRouter() + const { project } = router.query + + if (project) { + return <App projectId={project} /> + } + + return <div /> +} + +export default Project 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 new file mode 100644 index 00000000..76a8d23b --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/projects/[project]/portfolios/[portfolio].js @@ -0,0 +1,37 @@ +/* + * 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 App from '../../../../containers/app/App' + +function Project() { + const router = useRouter() + const { project, portfolio } = router.query + + if (project && portfolio) { + return <App projectId={project} portfolioId={portfolio} /> + } + + return <div /> +} + +export default Project diff --git a/opendc-web/opendc-web-ui/src/pages/projects/index.js b/opendc-web/opendc-web-ui/src/pages/projects/index.js new file mode 100644 index 00000000..8603c228 --- /dev/null +++ b/opendc-web/opendc-web-ui/src/pages/projects/index.js @@ -0,0 +1,37 @@ +import React, { useEffect, useState } from 'react' +import Head from 'next/head' +import { useDispatch } from 'react-redux' +import ProjectFilterPanel from '../../components/projects/FilterPanel' +import NewProjectContainer from '../../containers/projects/NewProjectContainer' +import ProjectListContainer from '../../containers/projects/ProjectListContainer' +import AppNavbarContainer from '../../containers/navigation/AppNavbarContainer' +import { useRequireAuth } from '../../auth' +import { Container } from 'reactstrap' +import { fetchProjects } from '../../redux/actions/projects' + +function Projects() { + useRequireAuth() + + const dispatch = useDispatch() + const [filter, setFilter] = useState('SHOW_ALL') + + useEffect(() => dispatch(fetchProjects()), []) + + return ( + <> + <Head> + <title>My Projects - OpenDC</title> + </Head> + <div className="full-height"> + <AppNavbarContainer fullWidth={false} /> + <Container className="text-page-container"> + <ProjectFilterPanel onSelect={setFilter} activeFilter={filter} /> + <ProjectListContainer filter={filter} /> + <NewProjectContainer /> + </Container> + </div> + </> + ) +} + +export default Projects |
