aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--packages/ui/src/infobox/index.tsx7
-rw-r--r--src/components/ui/Infobox.js17
-rw-r--r--src/features/workspaces/components/WorkspacesDashboard.js89
-rw-r--r--src/features/workspaces/containers/WorkspacesScreen.js3
-rw-r--r--src/features/workspaces/store.js15
-rw-r--r--src/i18n/locales/defaultMessages.json29
-rw-r--r--src/i18n/locales/en-US.json3
-rw-r--r--src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json29
-rw-r--r--src/stores/lib/Request.js4
9 files changed, 129 insertions, 67 deletions
diff --git a/packages/ui/src/infobox/index.tsx b/packages/ui/src/infobox/index.tsx
index 1a442a733..9066a623e 100644
--- a/packages/ui/src/infobox/index.tsx
+++ b/packages/ui/src/infobox/index.tsx
@@ -11,6 +11,7 @@ interface IProps extends IWithStyle {
11 type?: string; 11 type?: string;
12 dismissable?: boolean; 12 dismissable?: boolean;
13 onDismiss?: () => void; 13 onDismiss?: () => void;
14 onUnmount?: () => void;
14 ctaOnClick?: () => void; 15 ctaOnClick?: () => void;
15 ctaLabel?: string; 16 ctaLabel?: string;
16 ctaLoading?: boolean; 17 ctaLoading?: boolean;
@@ -46,6 +47,7 @@ const styles = (theme: Theme) => ({
46 wrapper: { 47 wrapper: {
47 position: 'relative', 48 position: 'relative',
48 overflow: 'hidden', 49 overflow: 'hidden',
50 height: 'auto',
49 }, 51 },
50 infobox: { 52 infobox: {
51 alignItems: 'center', 53 alignItems: 'center',
@@ -129,6 +131,11 @@ class InfoboxComponent extends Component<IProps, IState> {
129 }, 3000); 131 }, 3000);
130 } 132 }
131 133
134 componentWillUnmount(): void {
135 const { onUnmount } = this.props;
136 if (onUnmount) onUnmount();
137 }
138
132 render() { 139 render() {
133 const { 140 const {
134 classes, 141 classes,
diff --git a/src/components/ui/Infobox.js b/src/components/ui/Infobox.js
index a33c6474a..0917ee9f0 100644
--- a/src/components/ui/Infobox.js
+++ b/src/components/ui/Infobox.js
@@ -13,6 +13,8 @@ export default @observer class Infobox extends Component {
13 ctaLabel: PropTypes.string, 13 ctaLabel: PropTypes.string,
14 ctaLoading: PropTypes.bool, 14 ctaLoading: PropTypes.bool,
15 dismissable: PropTypes.bool, 15 dismissable: PropTypes.bool,
16 onDismiss: PropTypes.func,
17 onSeen: PropTypes.func,
16 }; 18 };
17 19
18 static defaultProps = { 20 static defaultProps = {
@@ -22,12 +24,19 @@ export default @observer class Infobox extends Component {
22 ctaOnClick: () => null, 24 ctaOnClick: () => null,
23 ctaLabel: '', 25 ctaLabel: '',
24 ctaLoading: false, 26 ctaLoading: false,
27 onDismiss: () => null,
28 onSeen: () => null,
25 }; 29 };
26 30
27 state = { 31 state = {
28 dismissed: false, 32 dismissed: false,
29 }; 33 };
30 34
35 componentDidMount() {
36 const { onSeen } = this.props;
37 if (onSeen) onSeen();
38 }
39
31 render() { 40 render() {
32 const { 41 const {
33 children, 42 children,
@@ -37,6 +46,7 @@ export default @observer class Infobox extends Component {
37 ctaLoading, 46 ctaLoading,
38 ctaOnClick, 47 ctaOnClick,
39 dismissable, 48 dismissable,
49 onDismiss,
40 } = this.props; 50 } = this.props;
41 51
42 if (this.state.dismissed) { 52 if (this.state.dismissed) {
@@ -76,9 +86,10 @@ export default @observer class Infobox extends Component {
76 {dismissable && ( 86 {dismissable && (
77 <button 87 <button
78 type="button" 88 type="button"
79 onClick={() => this.setState({ 89 onClick={() => {
80 dismissed: true, 90 this.setState({ dismissed: true });
81 })} 91 if (onDismiss) onDismiss();
92 }}
82 className="infobox__delete mdi mdi-close" 93 className="infobox__delete mdi mdi-close"
83 /> 94 />
84 )} 95 )}
diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js
index 2ccea1d55..3db38aff4 100644
--- a/src/features/workspaces/components/WorkspacesDashboard.js
+++ b/src/features/workspaces/components/WorkspacesDashboard.js
@@ -3,12 +3,13 @@ import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer, PropTypes as MobxPropTypes } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
5import injectSheet from 'react-jss'; 5import injectSheet from 'react-jss';
6import { Infobox } from '@meetfranz/ui';
6 7
7import Loader from '../../../components/ui/Loader'; 8import Loader from '../../../components/ui/Loader';
8import WorkspaceItem from './WorkspaceItem'; 9import WorkspaceItem from './WorkspaceItem';
9import CreateWorkspaceForm from './CreateWorkspaceForm'; 10import CreateWorkspaceForm from './CreateWorkspaceForm';
10import Request from '../../../stores/lib/Request'; 11import Request from '../../../stores/lib/Request';
11import Infobox from '../../../components/ui/Infobox'; 12import Appear from '../../../components/ui/effects/Appear';
12 13
13const messages = defineMessages({ 14const messages = defineMessages({
14 headline: { 15 headline: {
@@ -27,6 +28,10 @@ const messages = defineMessages({
27 id: 'settings.workspaces.tryReloadWorkspaces', 28 id: 'settings.workspaces.tryReloadWorkspaces',
28 defaultMessage: '!!!Try again', 29 defaultMessage: '!!!Try again',
29 }, 30 },
31 updatedInfo: {
32 id: 'settings.workspaces.updatedInfo',
33 defaultMessage: '!!!Your changes have been saved',
34 },
30}); 35});
31 36
32const styles = () => ({ 37const styles = () => ({
@@ -34,6 +39,9 @@ const styles = () => ({
34 height: 'auto', 39 height: 'auto',
35 marginBottom: '20px', 40 marginBottom: '20px',
36 }, 41 },
42 appear: {
43 height: 'auto',
44 },
37}); 45});
38 46
39@injectSheet(styles) @observer 47@injectSheet(styles) @observer
@@ -41,6 +49,7 @@ class WorkspacesDashboard extends Component {
41 static propTypes = { 49 static propTypes = {
42 classes: PropTypes.object.isRequired, 50 classes: PropTypes.object.isRequired,
43 getUserWorkspacesRequest: PropTypes.instanceOf(Request).isRequired, 51 getUserWorkspacesRequest: PropTypes.instanceOf(Request).isRequired,
52 updateWorkspaceRequest: PropTypes.instanceOf(Request).isRequired,
44 onCreateWorkspaceSubmit: PropTypes.func.isRequired, 53 onCreateWorkspaceSubmit: PropTypes.func.isRequired,
45 onWorkspaceClick: PropTypes.func.isRequired, 54 onWorkspaceClick: PropTypes.func.isRequired,
46 workspaces: MobxPropTypes.arrayOrObservableArray.isRequired, 55 workspaces: MobxPropTypes.arrayOrObservableArray.isRequired,
@@ -54,6 +63,7 @@ class WorkspacesDashboard extends Component {
54 const { 63 const {
55 classes, 64 classes,
56 getUserWorkspacesRequest, 65 getUserWorkspacesRequest,
66 updateWorkspaceRequest,
57 onCreateWorkspaceSubmit, 67 onCreateWorkspaceSubmit,
58 onWorkspaceClick, 68 onWorkspaceClick,
59 workspaces, 69 workspaces,
@@ -65,40 +75,51 @@ class WorkspacesDashboard extends Component {
65 <h1>{intl.formatMessage(messages.headline)}</h1> 75 <h1>{intl.formatMessage(messages.headline)}</h1>
66 </div> 76 </div>
67 <div className="settings__body"> 77 <div className="settings__body">
68 <div className={classes.body}> 78 {updateWorkspaceRequest.wasExecuted && updateWorkspaceRequest.result && (
69 <div className={classes.createForm}> 79 <Appear className={classes.appear}>
70 <CreateWorkspaceForm onSubmit={onCreateWorkspaceSubmit} /> 80 <Infobox
71 </div> 81 type="success"
72 {getUserWorkspacesRequest.isExecuting ? ( 82 icon="checkbox-marked-circle-outline"
73 <Loader /> 83 dismissable
74 ) : ( 84 onDismiss={updateWorkspaceRequest.reset}
75 <Fragment> 85 onUnmount={updateWorkspaceRequest.reset}
76 {getUserWorkspacesRequest.error ? ( 86 >
77 <Infobox 87 {intl.formatMessage(messages.updatedInfo)}
78 icon="alert" 88 </Infobox>
79 type="danger" 89 </Appear>
80 ctaLabel={intl.formatMessage(messages.tryReloadWorkspaces)} 90 )}
81 ctaLoading={getUserWorkspacesRequest.isExecuting} 91 <div className={classes.createForm}>
82 ctaOnClick={getUserWorkspacesRequest.retry} 92 <CreateWorkspaceForm onSubmit={onCreateWorkspaceSubmit} />
83 >
84 {intl.formatMessage(messages.workspacesRequestFailed)}
85 </Infobox>
86 ) : (
87 <table className="workspace-table">
88 <tbody>
89 {workspaces.map(workspace => (
90 <WorkspaceItem
91 key={workspace.id}
92 workspace={workspace}
93 onItemClick={w => onWorkspaceClick(w)}
94 />
95 ))}
96 </tbody>
97 </table>
98 )}
99 </Fragment>
100 )}
101 </div> 93 </div>
94 {getUserWorkspacesRequest.isExecuting ? (
95 <Loader />
96 ) : (
97 <Fragment>
98 {getUserWorkspacesRequest.error ? (
99 <Infobox
100 icon="alert"
101 type="danger"
102 ctaLabel={intl.formatMessage(messages.tryReloadWorkspaces)}
103 ctaLoading={getUserWorkspacesRequest.isExecuting}
104 ctaOnClick={getUserWorkspacesRequest.retry}
105 >
106 {intl.formatMessage(messages.workspacesRequestFailed)}
107 </Infobox>
108 ) : (
109 <table className="workspace-table">
110 <tbody>
111 {workspaces.map(workspace => (
112 <WorkspaceItem
113 key={workspace.id}
114 workspace={workspace}
115 onItemClick={w => onWorkspaceClick(w)}
116 />
117 ))}
118 </tbody>
119 </table>
120 )}
121 </Fragment>
122 )}
102 </div> 123 </div>
103 </div> 124 </div>
104 ); 125 );
diff --git a/src/features/workspaces/containers/WorkspacesScreen.js b/src/features/workspaces/containers/WorkspacesScreen.js
index 89bd2a2ef..3f41de0c2 100644
--- a/src/features/workspaces/containers/WorkspacesScreen.js
+++ b/src/features/workspaces/containers/WorkspacesScreen.js
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
4import WorkspacesDashboard from '../components/WorkspacesDashboard'; 4import WorkspacesDashboard from '../components/WorkspacesDashboard';
5import ErrorBoundary from '../../../components/util/ErrorBoundary'; 5import ErrorBoundary from '../../../components/util/ErrorBoundary';
6import { workspaceStore } from '../index'; 6import { workspaceStore } from '../index';
7import { getUserWorkspacesRequest } from '../api'; 7import { getUserWorkspacesRequest, updateWorkspaceRequest } from '../api';
8 8
9@inject('actions') @observer 9@inject('actions') @observer
10class WorkspacesScreen extends Component { 10class WorkspacesScreen extends Component {
@@ -23,6 +23,7 @@ class WorkspacesScreen extends Component {
23 <WorkspacesDashboard 23 <WorkspacesDashboard
24 workspaces={workspaceStore.workspaces} 24 workspaces={workspaceStore.workspaces}
25 getUserWorkspacesRequest={getUserWorkspacesRequest} 25 getUserWorkspacesRequest={getUserWorkspacesRequest}
26 updateWorkspaceRequest={updateWorkspaceRequest}
26 onCreateWorkspaceSubmit={data => actions.workspaces.create(data)} 27 onCreateWorkspaceSubmit={data => actions.workspaces.create(data)}
27 onWorkspaceClick={w => actions.workspaces.edit({ workspace: w })} 28 onWorkspaceClick={w => actions.workspaces.edit({ workspace: w })}
28 /> 29 />
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js
index 3cec5f360..f7df7b29c 100644
--- a/src/features/workspaces/store.js
+++ b/src/features/workspaces/store.js
@@ -102,9 +102,7 @@ export default class WorkspacesStore {
102 @action _create = async ({ name }) => { 102 @action _create = async ({ name }) => {
103 try { 103 try {
104 const workspace = await createWorkspaceRequest.execute(name); 104 const workspace = await createWorkspaceRequest.execute(name);
105 await getUserWorkspacesRequest.patch((result) => { 105 await getUserWorkspacesRequest.result.push(workspace);
106 result.push(workspace);
107 });
108 this._edit({ workspace }); 106 this._edit({ workspace });
109 } catch (error) { 107 } catch (error) {
110 throw error; 108 throw error;
@@ -114,9 +112,7 @@ export default class WorkspacesStore {
114 @action _delete = async ({ workspace }) => { 112 @action _delete = async ({ workspace }) => {
115 try { 113 try {
116 await deleteWorkspaceRequest.execute(workspace); 114 await deleteWorkspaceRequest.execute(workspace);
117 await getUserWorkspacesRequest.patch((result) => { 115 await getUserWorkspacesRequest.result.remove(workspace);
118 result.remove(workspace);
119 });
120 this.stores.router.push('/settings/workspaces'); 116 this.stores.router.push('/settings/workspaces');
121 } catch (error) { 117 } catch (error) {
122 throw error; 118 throw error;
@@ -126,10 +122,9 @@ export default class WorkspacesStore {
126 @action _update = async ({ workspace }) => { 122 @action _update = async ({ workspace }) => {
127 try { 123 try {
128 await updateWorkspaceRequest.execute(workspace); 124 await updateWorkspaceRequest.execute(workspace);
129 await getUserWorkspacesRequest.patch((result) => { 125 // Path local result optimistically
130 const localWorkspace = result.find(ws => ws.id === workspace.id); 126 const localWorkspace = this._getWorkspaceById(workspace.id);
131 Object.assign(localWorkspace, workspace); 127 Object.assign(localWorkspace, workspace);
132 });
133 this.stores.router.push('/settings/workspaces'); 128 this.stores.router.push('/settings/workspaces');
134 } catch (error) { 129 } catch (error) {
135 throw error; 130 throw error;
diff --git a/src/i18n/locales/defaultMessages.json b/src/i18n/locales/defaultMessages.json
index afbacf28a..891ad38d4 100644
--- a/src/i18n/locales/defaultMessages.json
+++ b/src/i18n/locales/defaultMessages.json
@@ -3388,52 +3388,65 @@
3388 "defaultMessage": "!!!Your workspaces", 3388 "defaultMessage": "!!!Your workspaces",
3389 "end": { 3389 "end": {
3390 "column": 3, 3390 "column": 3,
3391 "line": 17 3391 "line": 18
3392 }, 3392 },
3393 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 3393 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
3394 "id": "settings.workspaces.headline", 3394 "id": "settings.workspaces.headline",
3395 "start": { 3395 "start": {
3396 "column": 12, 3396 "column": 12,
3397 "line": 14 3397 "line": 15
3398 } 3398 }
3399 }, 3399 },
3400 { 3400 {
3401 "defaultMessage": "!!!You haven't added any workspaces yet.", 3401 "defaultMessage": "!!!You haven't added any workspaces yet.",
3402 "end": { 3402 "end": {
3403 "column": 3, 3403 "column": 3,
3404 "line": 21 3404 "line": 22
3405 }, 3405 },
3406 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 3406 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
3407 "id": "settings.workspaces.noWorkspacesAdded", 3407 "id": "settings.workspaces.noWorkspacesAdded",
3408 "start": { 3408 "start": {
3409 "column": 19, 3409 "column": 19,
3410 "line": 18 3410 "line": 19
3411 } 3411 }
3412 }, 3412 },
3413 { 3413 {
3414 "defaultMessage": "!!!Could not load your workspaces", 3414 "defaultMessage": "!!!Could not load your workspaces",
3415 "end": { 3415 "end": {
3416 "column": 3, 3416 "column": 3,
3417 "line": 25 3417 "line": 26
3418 }, 3418 },
3419 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 3419 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
3420 "id": "settings.workspaces.workspacesRequestFailed", 3420 "id": "settings.workspaces.workspacesRequestFailed",
3421 "start": { 3421 "start": {
3422 "column": 27, 3422 "column": 27,
3423 "line": 22 3423 "line": 23
3424 } 3424 }
3425 }, 3425 },
3426 { 3426 {
3427 "defaultMessage": "!!!Try again", 3427 "defaultMessage": "!!!Try again",
3428 "end": { 3428 "end": {
3429 "column": 3, 3429 "column": 3,
3430 "line": 29 3430 "line": 30
3431 }, 3431 },
3432 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 3432 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
3433 "id": "settings.workspaces.tryReloadWorkspaces", 3433 "id": "settings.workspaces.tryReloadWorkspaces",
3434 "start": { 3434 "start": {
3435 "column": 23, 3435 "column": 23,
3436 "line": 26 3436 "line": 27
3437 }
3438 },
3439 {
3440 "defaultMessage": "!!!Your changes have been saved",
3441 "end": {
3442 "column": 3,
3443 "line": 34
3444 },
3445 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
3446 "id": "settings.workspaces.updatedInfo",
3447 "start": {
3448 "column": 15,
3449 "line": 31
3437 } 3450 }
3438 } 3451 }
3439 ], 3452 ],
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json
index 2b4e79621..ad179bc1d 100644
--- a/src/i18n/locales/en-US.json
+++ b/src/i18n/locales/en-US.json
@@ -252,6 +252,7 @@
252 "settings.workspaces.headline": "Your workspaces", 252 "settings.workspaces.headline": "Your workspaces",
253 "settings.workspaces.noWorkspacesAdded": "You haven't added any workspaces yet.", 253 "settings.workspaces.noWorkspacesAdded": "You haven't added any workspaces yet.",
254 "settings.workspaces.tryReloadWorkspaces": "Try again", 254 "settings.workspaces.tryReloadWorkspaces": "Try again",
255 "settings.workspaces.updatedInfo": "!!!Your changes have been saved",
255 "settings.workspaces.workspacesRequestFailed": "Could not load your workspaces", 256 "settings.workspaces.workspacesRequestFailed": "Could not load your workspaces",
256 "sidebar.addNewService": "Add new service", 257 "sidebar.addNewService": "Add new service",
257 "sidebar.closeWorkspaceDrawer": "Close workspace drawer", 258 "sidebar.closeWorkspaceDrawer": "Close workspace drawer",
@@ -307,4 +308,4 @@
307 "workspaceDrawer.headline": "Workspaces", 308 "workspaceDrawer.headline": "Workspaces",
308 "workspaceDrawer.item.noServicesAddedYet": "No services added yet", 309 "workspaceDrawer.item.noServicesAddedYet": "No services added yet",
309 "workspaces.switchingIndicator.switchingTo": "Switching to" 310 "workspaces.switchingIndicator.switchingTo": "Switching to"
310} 311} \ No newline at end of file
diff --git a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json
index f875ace8a..d68899d9b 100644
--- a/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json
+++ b/src/i18n/messages/src/features/workspaces/components/WorkspacesDashboard.json
@@ -4,11 +4,11 @@
4 "defaultMessage": "!!!Your workspaces", 4 "defaultMessage": "!!!Your workspaces",
5 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 5 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
6 "start": { 6 "start": {
7 "line": 14, 7 "line": 15,
8 "column": 12 8 "column": 12
9 }, 9 },
10 "end": { 10 "end": {
11 "line": 17, 11 "line": 18,
12 "column": 3 12 "column": 3
13 } 13 }
14 }, 14 },
@@ -17,11 +17,11 @@
17 "defaultMessage": "!!!You haven't added any workspaces yet.", 17 "defaultMessage": "!!!You haven't added any workspaces yet.",
18 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 18 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
19 "start": { 19 "start": {
20 "line": 18, 20 "line": 19,
21 "column": 19 21 "column": 19
22 }, 22 },
23 "end": { 23 "end": {
24 "line": 21, 24 "line": 22,
25 "column": 3 25 "column": 3
26 } 26 }
27 }, 27 },
@@ -30,11 +30,11 @@
30 "defaultMessage": "!!!Could not load your workspaces", 30 "defaultMessage": "!!!Could not load your workspaces",
31 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 31 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
32 "start": { 32 "start": {
33 "line": 22, 33 "line": 23,
34 "column": 27 34 "column": 27
35 }, 35 },
36 "end": { 36 "end": {
37 "line": 25, 37 "line": 26,
38 "column": 3 38 "column": 3
39 } 39 }
40 }, 40 },
@@ -43,11 +43,24 @@
43 "defaultMessage": "!!!Try again", 43 "defaultMessage": "!!!Try again",
44 "file": "src/features/workspaces/components/WorkspacesDashboard.js", 44 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
45 "start": { 45 "start": {
46 "line": 26, 46 "line": 27,
47 "column": 23 47 "column": 23
48 }, 48 },
49 "end": { 49 "end": {
50 "line": 29, 50 "line": 30,
51 "column": 3
52 }
53 },
54 {
55 "id": "settings.workspaces.updatedInfo",
56 "defaultMessage": "!!!Your changes have been saved",
57 "file": "src/features/workspaces/components/WorkspacesDashboard.js",
58 "start": {
59 "line": 31,
60 "column": 15
61 },
62 "end": {
63 "line": 34,
51 "column": 3 64 "column": 3
52 } 65 }
53 } 66 }
diff --git a/src/stores/lib/Request.js b/src/stores/lib/Request.js
index 1fb67cc15..486de8a49 100644
--- a/src/stores/lib/Request.js
+++ b/src/stores/lib/Request.js
@@ -109,7 +109,7 @@ export default class Request {
109 Request._hooks.forEach(hook => hook(this)); 109 Request._hooks.forEach(hook => hook(this));
110 } 110 }
111 111
112 reset() { 112 reset = () => {
113 this.result = null; 113 this.result = null;
114 this.isExecuting = false; 114 this.isExecuting = false;
115 this.isError = false; 115 this.isError = false;
@@ -118,5 +118,5 @@ export default class Request {
118 this._promise = Promise; 118 this._promise = Promise;
119 119
120 return this; 120 return this;
121 } 121 };
122} 122}