diff options
author | Dominik Guzei <dominik.guzei@gmail.com> | 2019-02-12 14:59:58 +0100 |
---|---|---|
committer | Dominik Guzei <dominik.guzei@gmail.com> | 2019-02-12 15:02:23 +0100 |
commit | 90399cc608b93cc185b0ee1c9b79e98cfafb8bc1 (patch) | |
tree | e8678c71c9ebf10bb0c3ac62291b396c32e686c9 /src/features/workspaces | |
parent | setup logic to display workspace edit page (diff) | |
download | ferdium-app-90399cc608b93cc185b0ee1c9b79e98cfafb8bc1.tar.gz ferdium-app-90399cc608b93cc185b0ee1c9b79e98cfafb8bc1.tar.zst ferdium-app-90399cc608b93cc185b0ee1c9b79e98cfafb8bc1.zip |
consolidate workspace feature for further development
Diffstat (limited to 'src/features/workspaces')
-rw-r--r-- | src/features/workspaces/actions.js | 8 | ||||
-rw-r--r-- | src/features/workspaces/components/WorkspaceItem.js | 42 | ||||
-rw-r--r-- | src/features/workspaces/components/WorkspacesDashboard.js | 63 | ||||
-rw-r--r-- | src/features/workspaces/containers/EditWorkspaceScreen.js | 75 | ||||
-rw-r--r-- | src/features/workspaces/containers/WorkspacesScreen.js | 37 | ||||
-rw-r--r-- | src/features/workspaces/models/Workspace.js | 25 | ||||
-rw-r--r-- | src/features/workspaces/store.js | 2 | ||||
-rw-r--r-- | src/features/workspaces/styles/workspaces-table.scss | 53 |
8 files changed, 304 insertions, 1 deletions
diff --git a/src/features/workspaces/actions.js b/src/features/workspaces/actions.js new file mode 100644 index 000000000..30866af96 --- /dev/null +++ b/src/features/workspaces/actions.js | |||
@@ -0,0 +1,8 @@ | |||
1 | import PropTypes from 'prop-types'; | ||
2 | import Workspace from './models/Workspace'; | ||
3 | |||
4 | export default { | ||
5 | edit: { | ||
6 | workspace: PropTypes.instanceOf(Workspace).isRequired, | ||
7 | }, | ||
8 | }; | ||
diff --git a/src/features/workspaces/components/WorkspaceItem.js b/src/features/workspaces/components/WorkspaceItem.js new file mode 100644 index 000000000..b2c2a4830 --- /dev/null +++ b/src/features/workspaces/components/WorkspaceItem.js | |||
@@ -0,0 +1,42 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { intlShape } from 'react-intl'; | ||
4 | import { observer } from 'mobx-react'; | ||
5 | import classnames from 'classnames'; | ||
6 | import Workspace from '../models/Workspace'; | ||
7 | |||
8 | // const messages = defineMessages({}); | ||
9 | |||
10 | @observer | ||
11 | class WorkspaceItem extends Component { | ||
12 | static propTypes = { | ||
13 | workspace: PropTypes.instanceOf(Workspace).isRequired, | ||
14 | onItemClick: PropTypes.func.isRequired, | ||
15 | }; | ||
16 | |||
17 | static contextTypes = { | ||
18 | intl: intlShape, | ||
19 | }; | ||
20 | |||
21 | render() { | ||
22 | const { workspace, onItemClick } = this.props; | ||
23 | // const { intl } = this.context; | ||
24 | |||
25 | return ( | ||
26 | <tr | ||
27 | className={classnames({ | ||
28 | 'workspace-table__row': true, | ||
29 | })} | ||
30 | > | ||
31 | <td | ||
32 | className="workspace-table__column-name" | ||
33 | onClick={() => onItemClick(workspace)} | ||
34 | > | ||
35 | {workspace.name} | ||
36 | </td> | ||
37 | </tr> | ||
38 | ); | ||
39 | } | ||
40 | } | ||
41 | |||
42 | export default WorkspaceItem; | ||
diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js new file mode 100644 index 000000000..2a8b3a5ee --- /dev/null +++ b/src/features/workspaces/components/WorkspacesDashboard.js | |||
@@ -0,0 +1,63 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import PropTypes from 'prop-types'; | ||
3 | import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; | ||
4 | import { defineMessages, intlShape } from 'react-intl'; | ||
5 | |||
6 | import Loader from '../../../components/ui/Loader'; | ||
7 | import WorkspaceItem from './WorkspaceItem'; | ||
8 | |||
9 | const messages = defineMessages({ | ||
10 | headline: { | ||
11 | id: 'settings.workspaces.headline', | ||
12 | defaultMessage: '!!!Your workspaces', | ||
13 | }, | ||
14 | noServicesAdded: { | ||
15 | id: 'settings.workspaces.noWorkspacesAdded', | ||
16 | defaultMessage: '!!!You haven\'t added any workspaces yet.', | ||
17 | }, | ||
18 | }); | ||
19 | |||
20 | @observer | ||
21 | class WorkspacesDashboard extends Component { | ||
22 | static propTypes = { | ||
23 | workspaces: MobxPropTypes.arrayOrObservableArray.isRequired, | ||
24 | isLoading: PropTypes.bool.isRequired, | ||
25 | onWorkspaceClick: PropTypes.func.isRequired, | ||
26 | }; | ||
27 | |||
28 | static contextTypes = { | ||
29 | intl: intlShape, | ||
30 | }; | ||
31 | |||
32 | render() { | ||
33 | const { workspaces, isLoading, onWorkspaceClick } = this.props; | ||
34 | const { intl } = this.context; | ||
35 | |||
36 | return ( | ||
37 | <div className="settings__main"> | ||
38 | <div className="settings__header"> | ||
39 | <h1>{intl.formatMessage(messages.headline)}</h1> | ||
40 | </div> | ||
41 | <div className="settings__body"> | ||
42 | {isLoading ? ( | ||
43 | <Loader /> | ||
44 | ) : ( | ||
45 | <table className="workspace-table"> | ||
46 | <tbody> | ||
47 | {workspaces.map(workspace => ( | ||
48 | <WorkspaceItem | ||
49 | key={workspace.id} | ||
50 | workspace={workspace} | ||
51 | onItemClick={w => onWorkspaceClick(w)} | ||
52 | /> | ||
53 | ))} | ||
54 | </tbody> | ||
55 | </table> | ||
56 | )} | ||
57 | </div> | ||
58 | </div> | ||
59 | ); | ||
60 | } | ||
61 | } | ||
62 | |||
63 | export default WorkspacesDashboard; | ||
diff --git a/src/features/workspaces/containers/EditWorkspaceScreen.js b/src/features/workspaces/containers/EditWorkspaceScreen.js new file mode 100644 index 000000000..d8c52f586 --- /dev/null +++ b/src/features/workspaces/containers/EditWorkspaceScreen.js | |||
@@ -0,0 +1,75 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import { inject, observer } from 'mobx-react'; | ||
3 | import { defineMessages, intlShape } from 'react-intl'; | ||
4 | import { Link } from 'react-router'; | ||
5 | import Form from '../../../lib/Form'; | ||
6 | import ErrorBoundary from '../../../components/util/ErrorBoundary'; | ||
7 | import { gaPage } from '../../../lib/analytics'; | ||
8 | import { state } from '../state'; | ||
9 | |||
10 | const messages = defineMessages({ | ||
11 | name: { | ||
12 | id: 'settings.workspace.form.name', | ||
13 | defaultMessage: '!!!Name', | ||
14 | }, | ||
15 | yourWorkspaces: { | ||
16 | id: 'settings.workspace.form.yourWorkspaces', | ||
17 | defaultMessage: '!!!Your workspaces', | ||
18 | }, | ||
19 | }); | ||
20 | |||
21 | @inject('stores', 'actions') @observer | ||
22 | class EditWorkspaceScreen extends Component { | ||
23 | static contextTypes = { | ||
24 | intl: intlShape, | ||
25 | }; | ||
26 | |||
27 | componentDidMount() { | ||
28 | gaPage('Settings/Workspace/Edit'); | ||
29 | } | ||
30 | |||
31 | prepareForm(workspace) { | ||
32 | const { intl } = this.context; | ||
33 | const config = { | ||
34 | fields: { | ||
35 | name: { | ||
36 | label: intl.formatMessage(messages.name), | ||
37 | placeholder: intl.formatMessage(messages.name), | ||
38 | value: workspace.name, | ||
39 | }, | ||
40 | }, | ||
41 | }; | ||
42 | return new Form(config); | ||
43 | } | ||
44 | |||
45 | render() { | ||
46 | const { intl } = this.context; | ||
47 | const { workspaceBeingEdited } = state; | ||
48 | if (!workspaceBeingEdited) return null; | ||
49 | |||
50 | // const form = this.prepareForm(workspaceBeingEdited); | ||
51 | |||
52 | return ( | ||
53 | <ErrorBoundary> | ||
54 | <div className="settings__main"> | ||
55 | <div className="settings__header"> | ||
56 | <span className="settings__header-item"> | ||
57 | <Link to="/settings/workspaces"> | ||
58 | {intl.formatMessage(messages.yourWorkspaces)} | ||
59 | </Link> | ||
60 | </span> | ||
61 | <span className="separator" /> | ||
62 | <span className="settings__header-item"> | ||
63 | {workspaceBeingEdited.name} | ||
64 | </span> | ||
65 | </div> | ||
66 | <div className="settings__body"> | ||
67 | test | ||
68 | </div> | ||
69 | </div> | ||
70 | </ErrorBoundary> | ||
71 | ); | ||
72 | } | ||
73 | } | ||
74 | |||
75 | export default EditWorkspaceScreen; | ||
diff --git a/src/features/workspaces/containers/WorkspacesScreen.js b/src/features/workspaces/containers/WorkspacesScreen.js new file mode 100644 index 000000000..f129edec5 --- /dev/null +++ b/src/features/workspaces/containers/WorkspacesScreen.js | |||
@@ -0,0 +1,37 @@ | |||
1 | import React, { Component } from 'react'; | ||
2 | import { inject, observer } from 'mobx-react'; | ||
3 | import PropTypes from 'prop-types'; | ||
4 | import { gaPage } from '../../../lib/analytics'; | ||
5 | import { state } from '../state'; | ||
6 | import WorkspacesDashboard from '../components/WorkspacesDashboard'; | ||
7 | import ErrorBoundary from '../../../components/util/ErrorBoundary'; | ||
8 | |||
9 | @inject('actions') @observer | ||
10 | class WorkspacesScreen extends Component { | ||
11 | static propTypes = { | ||
12 | actions: PropTypes.shape({ | ||
13 | workspace: PropTypes.shape({ | ||
14 | edit: PropTypes.func.isRequired, | ||
15 | }), | ||
16 | }).isRequired, | ||
17 | }; | ||
18 | |||
19 | componentDidMount() { | ||
20 | gaPage('Settings/Workspaces Dashboard'); | ||
21 | } | ||
22 | |||
23 | render() { | ||
24 | const { workspace } = this.props.actions; | ||
25 | return ( | ||
26 | <ErrorBoundary> | ||
27 | <WorkspacesDashboard | ||
28 | workspaces={state.workspaces} | ||
29 | isLoading={state.isLoading} | ||
30 | onWorkspaceClick={w => workspace.edit({ workspace: w })} | ||
31 | /> | ||
32 | </ErrorBoundary> | ||
33 | ); | ||
34 | } | ||
35 | } | ||
36 | |||
37 | export default WorkspacesScreen; | ||
diff --git a/src/features/workspaces/models/Workspace.js b/src/features/workspaces/models/Workspace.js new file mode 100644 index 000000000..ede2710dc --- /dev/null +++ b/src/features/workspaces/models/Workspace.js | |||
@@ -0,0 +1,25 @@ | |||
1 | import { observable } from 'mobx'; | ||
2 | |||
3 | export default class Workspace { | ||
4 | id = null; | ||
5 | |||
6 | @observable name = null; | ||
7 | |||
8 | @observable order = null; | ||
9 | |||
10 | @observable services = []; | ||
11 | |||
12 | @observable userId = null; | ||
13 | |||
14 | constructor(data) { | ||
15 | if (!data.id) { | ||
16 | throw Error('Workspace requires Id'); | ||
17 | } | ||
18 | |||
19 | this.id = data.id; | ||
20 | this.name = data.name; | ||
21 | this.order = data.order; | ||
22 | this.services = data.services; | ||
23 | this.userId = data.userId; | ||
24 | } | ||
25 | } | ||
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index aab66708b..ea61cec31 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js | |||
@@ -1,7 +1,7 @@ | |||
1 | import { observable, reaction } from 'mobx'; | 1 | import { observable, reaction } from 'mobx'; |
2 | import Store from '../../stores/lib/Store'; | 2 | import Store from '../../stores/lib/Store'; |
3 | import CachedRequest from '../../stores/lib/CachedRequest'; | 3 | import CachedRequest from '../../stores/lib/CachedRequest'; |
4 | import Workspace from '../../models/Workspace'; | 4 | import Workspace from './models/Workspace'; |
5 | import { matchRoute } from '../../helpers/routing-helpers'; | 5 | import { matchRoute } from '../../helpers/routing-helpers'; |
6 | 6 | ||
7 | const debug = require('debug')('Franz:feature:workspaces'); | 7 | const debug = require('debug')('Franz:feature:workspaces'); |
diff --git a/src/features/workspaces/styles/workspaces-table.scss b/src/features/workspaces/styles/workspaces-table.scss new file mode 100644 index 000000000..6d0e7b4f5 --- /dev/null +++ b/src/features/workspaces/styles/workspaces-table.scss | |||
@@ -0,0 +1,53 @@ | |||
1 | @import '../../../styles/config'; | ||
2 | |||
3 | .theme__dark .workspace-table { | ||
4 | .workspace-table__column-info .mdi { color: $dark-theme-gray-lightest; } | ||
5 | |||
6 | .workspace-table__row { | ||
7 | border-bottom: 1px solid $dark-theme-gray-darker; | ||
8 | |||
9 | &:hover { background: $dark-theme-gray-darker; } | ||
10 | &.workspace-table__row--disabled { color: $dark-theme-gray; } | ||
11 | } | ||
12 | } | ||
13 | |||
14 | .workspace-table { | ||
15 | width: 100%; | ||
16 | |||
17 | .workspace-table__toggle { | ||
18 | width: 60px; | ||
19 | |||
20 | .franz-form__field { | ||
21 | margin-bottom: 0; | ||
22 | } | ||
23 | } | ||
24 | |||
25 | .workspace-table__column-action { | ||
26 | width: 40px | ||
27 | } | ||
28 | |||
29 | .workspace-table__column-info { | ||
30 | width: 40px; | ||
31 | |||
32 | .mdi { | ||
33 | color: $theme-gray-light; | ||
34 | display: block; | ||
35 | font-size: 18px; | ||
36 | } | ||
37 | } | ||
38 | |||
39 | .workspace-table__row { | ||
40 | border-bottom: 1px solid $theme-gray-lightest; | ||
41 | |||
42 | &:hover { | ||
43 | cursor: initial; | ||
44 | background: $theme-gray-lightest; | ||
45 | } | ||
46 | |||
47 | &.workspace-table__row--disabled { | ||
48 | color: $theme-gray-light; | ||
49 | } | ||
50 | } | ||
51 | |||
52 | td { padding: 10px; } | ||
53 | } | ||