summaryrefslogtreecommitdiff
path: root/opendc-web
diff options
context:
space:
mode:
Diffstat (limited to 'opendc-web')
-rw-r--r--opendc-web/opendc-web-ui/src/actions/modals/projects.js14
-rw-r--r--opendc-web/opendc-web-ui/src/actions/projects.js8
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/FilterButton.js24
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/FilterPanel.js29
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/NewProjectButtonComponent.js17
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/ProjectActionButtons.js19
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/ProjectList.js (renamed from opendc-web/opendc-web-ui/src/components/projects/ProjectAuthList.js)10
-rw-r--r--opendc-web/opendc-web-ui/src/components/projects/ProjectRow.js (renamed from opendc-web/opendc-web-ui/src/components/projects/ProjectAuthRow.js)6
-rw-r--r--opendc-web/opendc-web-ui/src/containers/modals/NewProjectModal.js19
-rw-r--r--opendc-web/opendc-web-ui/src/containers/projects/FilterLink.js13
-rw-r--r--opendc-web/opendc-web-ui/src/containers/projects/NewProjectButtonContainer.js11
-rw-r--r--opendc-web/opendc-web-ui/src/containers/projects/NewProjectContainer.js33
-rw-r--r--opendc-web/opendc-web-ui/src/containers/projects/VisibleProjectAuthList.js13
-rw-r--r--opendc-web/opendc-web-ui/src/pages/projects/index.js23
-rw-r--r--opendc-web/opendc-web-ui/src/reducers/modals.js2
-rw-r--r--opendc-web/opendc-web-ui/src/reducers/project-list.js16
16 files changed, 98 insertions, 159 deletions
diff --git a/opendc-web/opendc-web-ui/src/actions/modals/projects.js b/opendc-web/opendc-web-ui/src/actions/modals/projects.js
deleted file mode 100644
index d1043cbb..00000000
--- a/opendc-web/opendc-web-ui/src/actions/modals/projects.js
+++ /dev/null
@@ -1,14 +0,0 @@
-export const OPEN_NEW_PROJECT_MODAL = 'OPEN_NEW_PROJECT_MODAL'
-export const CLOSE_NEW_PROJECT_MODAL = 'CLOSE_PROJECT_MODAL'
-
-export function openNewProjectModal() {
- return {
- type: OPEN_NEW_PROJECT_MODAL,
- }
-}
-
-export function closeNewProjectModal() {
- return {
- type: CLOSE_NEW_PROJECT_MODAL,
- }
-}
diff --git a/opendc-web/opendc-web-ui/src/actions/projects.js b/opendc-web/opendc-web-ui/src/actions/projects.js
index add0f242..15158164 100644
--- a/opendc-web/opendc-web-ui/src/actions/projects.js
+++ b/opendc-web/opendc-web-ui/src/actions/projects.js
@@ -1,17 +1,9 @@
-export const SET_AUTH_VISIBILITY_FILTER = 'SET_AUTH_VISIBILITY_FILTER'
export const ADD_PROJECT = 'ADD_PROJECT'
export const ADD_PROJECT_SUCCEEDED = 'ADD_PROJECT_SUCCEEDED'
export const DELETE_PROJECT = 'DELETE_PROJECT'
export const DELETE_PROJECT_SUCCEEDED = 'DELETE_PROJECT_SUCCEEDED'
export const OPEN_PROJECT_SUCCEEDED = 'OPEN_PROJECT_SUCCEEDED'
-export function setAuthVisibilityFilter(filter) {
- return {
- type: SET_AUTH_VISIBILITY_FILTER,
- filter,
- }
-}
-
export function addProject(name) {
return (dispatch, getState) => {
const { auth } = getState()
diff --git a/opendc-web/opendc-web-ui/src/components/projects/FilterButton.js b/opendc-web/opendc-web-ui/src/components/projects/FilterButton.js
deleted file mode 100644
index 664f9b46..00000000
--- a/opendc-web/opendc-web-ui/src/components/projects/FilterButton.js
+++ /dev/null
@@ -1,24 +0,0 @@
-import classNames from 'classnames'
-import PropTypes from 'prop-types'
-import React from 'react'
-
-const FilterButton = ({ active, children, onClick }) => (
- <button
- className={classNames('btn btn-secondary', { active: active })}
- onClick={() => {
- if (!active) {
- onClick()
- }
- }}
- >
- {children}
- </button>
-)
-
-FilterButton.propTypes = {
- active: PropTypes.bool.isRequired,
- children: PropTypes.node.isRequired,
- onClick: PropTypes.func.isRequired,
-}
-
-export default FilterButton
diff --git a/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.js b/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.js
index 89b483fb..5129c013 100644
--- a/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.js
+++ b/opendc-web/opendc-web-ui/src/components/projects/FilterPanel.js
@@ -1,13 +1,28 @@
import React from 'react'
-import FilterLink from '../../containers/projects/FilterLink'
+import PropTypes from 'prop-types'
+import { Button, ButtonGroup } from 'reactstrap'
import { filterPanel } from './FilterPanel.module.scss'
-const FilterPanel = () => (
- <div className={`btn-group ${filterPanel} mb-2`}>
- <FilterLink filter="SHOW_ALL">All Projects</FilterLink>
- <FilterLink filter="SHOW_OWN">My Projects</FilterLink>
- <FilterLink filter="SHOW_SHARED">Shared with me</FilterLink>
- </div>
+export const FILTERS = { SHOW_ALL: 'All Projects', SHOW_OWN: 'My Projects', SHOW_SHARED: 'Shared with me' }
+
+const FilterPanel = ({ onSelect, activeFilter = 'SHOW_ALL' }) => (
+ <ButtonGroup className={`${filterPanel} mb-2`}>
+ {Object.keys(FILTERS).map((filter) => (
+ <Button
+ color="secondary"
+ key={filter}
+ onClick={() => activeFilter === filter || onSelect(filter)}
+ active={activeFilter === filter}
+ >
+ {FILTERS[filter]}
+ </Button>
+ ))}
+ </ButtonGroup>
)
+FilterPanel.propTypes = {
+ onSelect: PropTypes.func.isRequired,
+ activeFilter: PropTypes.string,
+}
+
export default FilterPanel
diff --git a/opendc-web/opendc-web-ui/src/components/projects/NewProjectButtonComponent.js b/opendc-web/opendc-web-ui/src/components/projects/NewProjectButtonComponent.js
deleted file mode 100644
index 312671c6..00000000
--- a/opendc-web/opendc-web-ui/src/components/projects/NewProjectButtonComponent.js
+++ /dev/null
@@ -1,17 +0,0 @@
-import PropTypes from 'prop-types'
-import React from 'react'
-
-const NewProjectButtonComponent = ({ onClick }) => (
- <div className="bottom-btn-container">
- <div className="btn btn-primary float-right" onClick={onClick}>
- <span className="fa fa-plus mr-2" />
- New Project
- </div>
- </div>
-)
-
-NewProjectButtonComponent.propTypes = {
- onClick: PropTypes.func.isRequired,
-}
-
-export default NewProjectButtonComponent
diff --git a/opendc-web/opendc-web-ui/src/components/projects/ProjectActionButtons.js b/opendc-web/opendc-web-ui/src/components/projects/ProjectActionButtons.js
index 48cce019..96970fd9 100644
--- a/opendc-web/opendc-web-ui/src/components/projects/ProjectActionButtons.js
+++ b/opendc-web/opendc-web-ui/src/components/projects/ProjectActionButtons.js
@@ -1,24 +1,29 @@
import PropTypes from 'prop-types'
import React from 'react'
import Link from 'next/link'
+import { Button } from 'reactstrap'
const ProjectActionButtons = ({ projectId, onViewUsers, onDelete }) => (
<td className="text-right">
<Link href={`/projects/${projectId}`}>
- <a className="btn btn-outline-primary btn-sm mr-2" title="Open this project">
+ <Button color="primary" outline size="sm" className="mr-2" title="Open this project">
<span className="fa fa-play" />
- </a>
+ </Button>
</Link>
- <div
- className="btn btn-outline-success btn-sm disabled mr-2"
+ <Button
+ color="success"
+ outline
+ size="sm"
+ disabled
+ className="mr-2"
title="View and edit collaborators (not supported currently)"
onClick={() => onViewUsers(projectId)}
>
<span className="fa fa-users" />
- </div>
- <div className="btn btn-outline-danger btn-sm" title="Delete this project" onClick={() => onDelete(projectId)}>
+ </Button>
+ <Button color="danger" outline size="sm" title="Delete this project" onClick={() => onDelete(projectId)}>
<span className="fa fa-trash" />
- </div>
+ </Button>
</td>
)
diff --git a/opendc-web/opendc-web-ui/src/components/projects/ProjectAuthList.js b/opendc-web/opendc-web-ui/src/components/projects/ProjectList.js
index 15147e08..90d42326 100644
--- a/opendc-web/opendc-web-ui/src/components/projects/ProjectAuthList.js
+++ b/opendc-web/opendc-web-ui/src/components/projects/ProjectList.js
@@ -1,9 +1,9 @@
import PropTypes from 'prop-types'
import React from 'react'
import { Authorization } from '../../shapes'
-import ProjectAuthRow from './ProjectAuthRow'
+import ProjectRow from './ProjectRow'
-const ProjectAuthList = ({ authorizations }) => {
+const ProjectList = ({ authorizations }) => {
return (
<div className="vertically-expanding-container">
{authorizations.length === 0 ? (
@@ -23,7 +23,7 @@ const ProjectAuthList = ({ authorizations }) => {
</thead>
<tbody>
{authorizations.map((authorization) => (
- <ProjectAuthRow projectAuth={authorization} key={authorization.project._id} />
+ <ProjectRow projectAuth={authorization} key={authorization.project._id} />
))}
</tbody>
</table>
@@ -32,8 +32,8 @@ const ProjectAuthList = ({ authorizations }) => {
)
}
-ProjectAuthList.propTypes = {
+ProjectList.propTypes = {
authorizations: PropTypes.arrayOf(Authorization).isRequired,
}
-export default ProjectAuthList
+export default ProjectList
diff --git a/opendc-web/opendc-web-ui/src/components/projects/ProjectAuthRow.js b/opendc-web/opendc-web-ui/src/components/projects/ProjectRow.js
index 1c1d5cd8..bc63c805 100644
--- a/opendc-web/opendc-web-ui/src/components/projects/ProjectAuthRow.js
+++ b/opendc-web/opendc-web-ui/src/components/projects/ProjectRow.js
@@ -5,7 +5,7 @@ import { Authorization } from '../../shapes/index'
import { AUTH_DESCRIPTION_MAP, AUTH_ICON_MAP } from '../../util/authorizations'
import { parseAndFormatDateTime } from '../../util/date-time'
-const ProjectAuthRow = ({ projectAuth }) => (
+const ProjectRow = ({ projectAuth }) => (
<tr>
<td className="pt-3">{projectAuth.project.name}</td>
<td className="pt-3">{parseAndFormatDateTime(projectAuth.project.datetimeLastEdited)}</td>
@@ -17,8 +17,8 @@ const ProjectAuthRow = ({ projectAuth }) => (
</tr>
)
-ProjectAuthRow.propTypes = {
+ProjectRow.propTypes = {
projectAuth: Authorization.isRequired,
}
-export default ProjectAuthRow
+export default ProjectRow
diff --git a/opendc-web/opendc-web-ui/src/containers/modals/NewProjectModal.js b/opendc-web/opendc-web-ui/src/containers/modals/NewProjectModal.js
deleted file mode 100644
index e63ba76b..00000000
--- a/opendc-web/opendc-web-ui/src/containers/modals/NewProjectModal.js
+++ /dev/null
@@ -1,19 +0,0 @@
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import { closeNewProjectModal } from '../../actions/modals/projects'
-import { addProject } from '../../actions/projects'
-import TextInputModal from '../../components/modals/TextInputModal'
-
-const NewProjectModal = (props) => {
- const visible = useSelector((state) => state.modals.newProjectModalVisible)
- const dispatch = useDispatch()
- const callback = (text) => {
- if (text) {
- dispatch(addProject(text))
- }
- dispatch(closeNewProjectModal())
- }
- return <TextInputModal title="New Project" label="Project title" show={visible} callback={callback} {...props} />
-}
-
-export default NewProjectModal
diff --git a/opendc-web/opendc-web-ui/src/containers/projects/FilterLink.js b/opendc-web/opendc-web-ui/src/containers/projects/FilterLink.js
deleted file mode 100644
index 26f95c55..00000000
--- a/opendc-web/opendc-web-ui/src/containers/projects/FilterLink.js
+++ /dev/null
@@ -1,13 +0,0 @@
-import React from 'react'
-import { useDispatch, useSelector } from 'react-redux'
-import { setAuthVisibilityFilter } from '../../actions/projects'
-import FilterButton from '../../components/projects/FilterButton'
-
-const FilterLink = (props) => {
- const active = useSelector((state) => state.projectList.authVisibilityFilter === props.filter)
- const dispatch = useDispatch()
-
- return <FilterButton {...props} onClick={() => dispatch(setAuthVisibilityFilter(props.filter))} active={active} />
-}
-
-export default FilterLink
diff --git a/opendc-web/opendc-web-ui/src/containers/projects/NewProjectButtonContainer.js b/opendc-web/opendc-web-ui/src/containers/projects/NewProjectButtonContainer.js
deleted file mode 100644
index b8f6fef5..00000000
--- a/opendc-web/opendc-web-ui/src/containers/projects/NewProjectButtonContainer.js
+++ /dev/null
@@ -1,11 +0,0 @@
-import React from 'react'
-import { useDispatch } from 'react-redux'
-import { openNewProjectModal } from '../../actions/modals/projects'
-import NewProjectButtonComponent from '../../components/projects/NewProjectButtonComponent'
-
-const NewProjectButtonContainer = (props) => {
- const dispatch = useDispatch()
- return <NewProjectButtonComponent {...props} onClick={() => dispatch(openNewProjectModal())} />
-}
-
-export default NewProjectButtonContainer
diff --git a/opendc-web/opendc-web-ui/src/containers/projects/NewProjectContainer.js b/opendc-web/opendc-web-ui/src/containers/projects/NewProjectContainer.js
new file mode 100644
index 00000000..5a8a2dcf
--- /dev/null
+++ b/opendc-web/opendc-web-ui/src/containers/projects/NewProjectContainer.js
@@ -0,0 +1,33 @@
+import React, { useState } from 'react'
+import { useDispatch } from 'react-redux'
+import { addProject } from '../../actions/projects'
+import TextInputModal from '../../components/modals/TextInputModal'
+import { Button } from 'reactstrap'
+
+/**
+ * A container for creating a new project.
+ */
+const NewProjectContainer = () => {
+ const [isVisible, setVisible] = useState(false)
+ const dispatch = useDispatch()
+ const callback = (text) => {
+ if (text) {
+ dispatch(addProject(text))
+ }
+ setVisible(false)
+ }
+
+ return (
+ <>
+ <div className="bottom-btn-container">
+ <Button color="primary" className="float-right" onClick={() => setVisible(true)}>
+ <span className="fa fa-plus mr-2" />
+ New Project
+ </Button>
+ </div>
+ <TextInputModal title="New Project" label="Project title" show={isVisible} callback={callback} />
+ </>
+ )
+}
+
+export default NewProjectContainer
diff --git a/opendc-web/opendc-web-ui/src/containers/projects/VisibleProjectAuthList.js b/opendc-web/opendc-web-ui/src/containers/projects/VisibleProjectAuthList.js
index b869775c..8e1d063b 100644
--- a/opendc-web/opendc-web-ui/src/containers/projects/VisibleProjectAuthList.js
+++ b/opendc-web/opendc-web-ui/src/containers/projects/VisibleProjectAuthList.js
@@ -1,6 +1,7 @@
import React from 'react'
+import PropTypes from 'prop-types'
import { useSelector } from 'react-redux'
-import ProjectList from '../../components/projects/ProjectAuthList'
+import ProjectList from '../../components/projects/ProjectList'
const getVisibleProjectAuths = (projectAuths, filter) => {
switch (filter) {
@@ -15,7 +16,7 @@ const getVisibleProjectAuths = (projectAuths, filter) => {
}
}
-const VisibleProjectAuthList = (props) => {
+const VisibleProjectAuthList = ({ filter }) => {
const authorizations = useSelector((state) => {
const denormalizedAuthorizations = state.projectList.authorizationsOfCurrentUser.map((authorizationIds) => {
const authorization = state.objects.authorization[authorizationIds]
@@ -24,9 +25,13 @@ const VisibleProjectAuthList = (props) => {
return authorization
})
- return getVisibleProjectAuths(denormalizedAuthorizations, state.projectList.authVisibilityFilter)
+ return getVisibleProjectAuths(denormalizedAuthorizations, filter)
})
- return <ProjectList {...props} authorizations={authorizations} />
+ return <ProjectList authorizations={authorizations} />
+}
+
+VisibleProjectAuthList.propTypes = {
+ filter: PropTypes.string.isRequired,
}
export default VisibleProjectAuthList
diff --git a/opendc-web/opendc-web-ui/src/pages/projects/index.js b/opendc-web/opendc-web-ui/src/pages/projects/index.js
index bea9ad93..dd61751f 100644
--- a/opendc-web/opendc-web-ui/src/pages/projects/index.js
+++ b/opendc-web/opendc-web-ui/src/pages/projects/index.js
@@ -1,19 +1,21 @@
-import React, { useEffect } from 'react'
+import React, { useEffect, useState } from 'react'
import Head from 'next/head'
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 NewProjectContainer from '../../containers/projects/NewProjectContainer'
import VisibleProjectList from '../../containers/projects/VisibleProjectAuthList'
import AppNavbarContainer from '../../containers/navigation/AppNavbarContainer'
import { useRequireAuth } from '../../auth/hook'
+import { Container } from 'reactstrap'
function Projects() {
+ useRequireAuth()
+
const dispatch = useDispatch()
+ const [filter, setFilter] = useState('SHOW_ALL')
- useRequireAuth()
- useEffect(() => dispatch(fetchAuthorizationsOfCurrentUser()))
+ useEffect(() => dispatch(fetchAuthorizationsOfCurrentUser()), [])
return (
<>
@@ -22,12 +24,11 @@ function Projects() {
</Head>
<div className="full-height">
<AppNavbarContainer fullWidth={false} />
- <div className="container text-page-container full-height">
- <ProjectFilterPanel />
- <VisibleProjectList />
- <NewProjectButtonContainer />
- </div>
- <NewProjectModal />
+ <Container className="text-page-container">
+ <ProjectFilterPanel onSelect={setFilter} activeFilter={filter} />
+ <VisibleProjectList filter={filter} />
+ <NewProjectContainer />
+ </Container>
</div>
</>
)
diff --git a/opendc-web/opendc-web-ui/src/reducers/modals.js b/opendc-web/opendc-web-ui/src/reducers/modals.js
index e600d556..a58d8708 100644
--- a/opendc-web/opendc-web-ui/src/reducers/modals.js
+++ b/opendc-web/opendc-web-ui/src/reducers/modals.js
@@ -1,5 +1,4 @@
import { combineReducers } from 'redux'
-import { CLOSE_NEW_PROJECT_MODAL, OPEN_NEW_PROJECT_MODAL } from '../actions/modals/projects'
import {
CLOSE_NEW_TOPOLOGY_MODAL,
CLOSE_DELETE_MACHINE_MODAL,
@@ -31,7 +30,6 @@ function modal(openAction, closeAction) {
}
export const modals = combineReducers({
- newProjectModalVisible: modal(OPEN_NEW_PROJECT_MODAL, CLOSE_NEW_PROJECT_MODAL),
changeTopologyModalVisible: modal(OPEN_NEW_TOPOLOGY_MODAL, CLOSE_NEW_TOPOLOGY_MODAL),
editRoomNameModalVisible: modal(OPEN_EDIT_ROOM_NAME_MODAL, CLOSE_EDIT_ROOM_NAME_MODAL),
deleteRoomModalVisible: modal(OPEN_DELETE_ROOM_MODAL, CLOSE_DELETE_ROOM_MODAL),
diff --git a/opendc-web/opendc-web-ui/src/reducers/project-list.js b/opendc-web/opendc-web-ui/src/reducers/project-list.js
index 1f1aa8d0..ad803db0 100644
--- a/opendc-web/opendc-web-ui/src/reducers/project-list.js
+++ b/opendc-web/opendc-web-ui/src/reducers/project-list.js
@@ -1,5 +1,5 @@
import { combineReducers } from 'redux'
-import { ADD_PROJECT_SUCCEEDED, DELETE_PROJECT_SUCCEEDED, SET_AUTH_VISIBILITY_FILTER } from '../actions/projects'
+import { ADD_PROJECT_SUCCEEDED, DELETE_PROJECT_SUCCEEDED } from '../actions/projects'
import { FETCH_AUTHORIZATIONS_OF_CURRENT_USER_SUCCEEDED } from '../actions/users'
export function authorizationsOfCurrentUser(state = [], action) {
@@ -15,16 +15,4 @@ export function authorizationsOfCurrentUser(state = [], action) {
}
}
-export function authVisibilityFilter(state = 'SHOW_ALL', action) {
- switch (action.type) {
- case SET_AUTH_VISIBILITY_FILTER:
- return action.filter
- default:
- return state
- }
-}
-
-export const projectList = combineReducers({
- authorizationsOfCurrentUser,
- authVisibilityFilter,
-})
+export const projectList = combineReducers({ authorizationsOfCurrentUser })