aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/workspaces
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/workspaces')
-rw-r--r--src/features/workspaces/components/CreateWorkspaceForm.js4
-rw-r--r--src/features/workspaces/components/EditWorkspaceForm.js41
-rw-r--r--src/features/workspaces/components/WorkspacesDashboard.js38
-rw-r--r--src/features/workspaces/store.js89
4 files changed, 135 insertions, 37 deletions
diff --git a/src/features/workspaces/components/CreateWorkspaceForm.js b/src/features/workspaces/components/CreateWorkspaceForm.js
index 2c00ea63c..cddbb2b04 100644
--- a/src/features/workspaces/components/CreateWorkspaceForm.js
+++ b/src/features/workspaces/components/CreateWorkspaceForm.js
@@ -7,7 +7,7 @@ import injectSheet from 'react-jss';
7import Form from '../../../lib/Form'; 7import Form from '../../../lib/Form';
8import { required } from '../../../helpers/validation-helpers'; 8import { required } from '../../../helpers/validation-helpers';
9import { gaEvent } from '../../../lib/analytics'; 9import { gaEvent } from '../../../lib/analytics';
10import { GA_CATEGORY_WORKSPACES } from '../index'; 10import { GA_CATEGORY_WORKSPACES, workspaceStore } from '../index';
11 11
12const messages = defineMessages({ 12const messages = defineMessages({
13 submitButton: { 13 submitButton: {
@@ -82,7 +82,7 @@ class CreateWorkspaceForm extends Component {
82 {...form.$('name').bind()} 82 {...form.$('name').bind()}
83 showLabel={false} 83 showLabel={false}
84 onEnterKey={this.submitForm.bind(this, form)} 84 onEnterKey={this.submitForm.bind(this, form)}
85 focus 85 focus={workspaceStore.isUserAllowedToUseFeature}
86 /> 86 />
87 <Button 87 <Button
88 className={classes.submitButton} 88 className={classes.submitButton}
diff --git a/src/features/workspaces/components/EditWorkspaceForm.js b/src/features/workspaces/components/EditWorkspaceForm.js
index bba4485ff..e602ebd5a 100644
--- a/src/features/workspaces/components/EditWorkspaceForm.js
+++ b/src/features/workspaces/components/EditWorkspaceForm.js
@@ -1,4 +1,4 @@
1import React, { Component } from 'react'; 1import React, { Component, Fragment } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, intlShape } from 'react-intl'; 4import { defineMessages, intlShape } from 'react-intl';
@@ -36,6 +36,14 @@ const messages = defineMessages({
36 id: 'settings.workspace.form.servicesInWorkspaceHeadline', 36 id: 'settings.workspace.form.servicesInWorkspaceHeadline',
37 defaultMessage: '!!!Services in this Workspace', 37 defaultMessage: '!!!Services in this Workspace',
38 }, 38 },
39 noServicesAdded: {
40 id: 'settings.services.noServicesAdded',
41 defaultMessage: '!!!You haven\'t added any services yet.',
42 },
43 discoverServices: {
44 id: 'settings.services.discoverServices',
45 defaultMessage: '!!!Discover services',
46 },
39}); 47});
40 48
41const styles = () => ({ 49const styles = () => ({
@@ -150,14 +158,29 @@ class EditWorkspaceForm extends Component {
150 </div> 158 </div>
151 <h2>{intl.formatMessage(messages.servicesInWorkspaceHeadline)}</h2> 159 <h2>{intl.formatMessage(messages.servicesInWorkspaceHeadline)}</h2>
152 <div className={classes.serviceList}> 160 <div className={classes.serviceList}>
153 {services.map(s => ( 161 {services.length === 0 ? (
154 <WorkspaceServiceListItem 162 <div className="align-middle settings__empty-state">
155 key={s.id} 163 {/* ===== Empty state ===== */}
156 service={s} 164 <p className="settings__empty-text">
157 isInWorkspace={workspaceServices.includes(s.id)} 165 <span className="emoji">
158 onToggle={() => this.toggleService(s)} 166 <img src="./assets/images/emoji/sad.png" alt="" />
159 /> 167 </span>
160 ))} 168 {intl.formatMessage(messages.noServicesAdded)}
169 </p>
170 <Link to="/settings/recipes" className="button">{intl.formatMessage(messages.discoverServices)}</Link>
171 </div>
172 ) : (
173 <Fragment>
174 {services.map(s => (
175 <WorkspaceServiceListItem
176 key={s.id}
177 service={s}
178 isInWorkspace={workspaceServices.includes(s.id)}
179 onToggle={() => this.toggleService(s)}
180 />
181 ))}
182 </Fragment>
183 )}
161 </div> 184 </div>
162 </div> 185 </div>
163 <div className="settings__controls"> 186 <div className="settings__controls">
diff --git a/src/features/workspaces/components/WorkspacesDashboard.js b/src/features/workspaces/components/WorkspacesDashboard.js
index dd4381a15..09c98ab8c 100644
--- a/src/features/workspaces/components/WorkspacesDashboard.js
+++ b/src/features/workspaces/components/WorkspacesDashboard.js
@@ -170,18 +170,32 @@ class WorkspacesDashboard extends Component {
170 {intl.formatMessage(messages.workspacesRequestFailed)} 170 {intl.formatMessage(messages.workspacesRequestFailed)}
171 </Infobox> 171 </Infobox>
172 ) : ( 172 ) : (
173 <table className={classes.table}> 173 <Fragment>
174 {/* ===== Workspaces list ===== */} 174 {workspaces.length === 0 ? (
175 <tbody> 175 <div className="align-middle settings__empty-state">
176 {workspaces.map(workspace => ( 176 {/* ===== Workspaces empty state ===== */}
177 <WorkspaceItem 177 <p className="settings__empty-text">
178 key={workspace.id} 178 <span className="emoji">
179 workspace={workspace} 179 <img src="./assets/images/emoji/sad.png" alt="" />
180 onItemClick={w => onWorkspaceClick(w)} 180 </span>
181 /> 181 {intl.formatMessage(messages.noServicesAdded)}
182 ))} 182 </p>
183 </tbody> 183 </div>
184 </table> 184 ) : (
185 <table className={classes.table}>
186 {/* ===== Workspaces list ===== */}
187 <tbody>
188 {workspaces.map(workspace => (
189 <WorkspaceItem
190 key={workspace.id}
191 workspace={workspace}
192 onItemClick={w => onWorkspaceClick(w)}
193 />
194 ))}
195 </tbody>
196 </table>
197 )}
198 </Fragment>
185 )} 199 )}
186 </Fragment> 200 </Fragment>
187 )} 201 )}
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js
index ea601700e..51a7f3651 100644
--- a/src/features/workspaces/store.js
+++ b/src/features/workspaces/store.js
@@ -14,6 +14,8 @@ import {
14 updateWorkspaceRequest, 14 updateWorkspaceRequest,
15} from './api'; 15} from './api';
16import { WORKSPACES_ROUTES } from './index'; 16import { WORKSPACES_ROUTES } from './index';
17import { createReactions } from '../../stores/lib/Reaction';
18import { createActionBindings } from '../utils/ActionBinding';
17 19
18const debug = require('debug')('Franz:feature:workspaces:store'); 20const debug = require('debug')('Franz:feature:workspaces:store');
19 21
@@ -51,37 +53,78 @@ export default class WorkspacesStore extends FeatureStore {
51 return getUserWorkspacesRequest.wasExecuted && this.workspaces.length > 0; 53 return getUserWorkspacesRequest.wasExecuted && this.workspaces.length > 0;
52 } 54 }
53 55
56 @computed get isUserAllowedToUseFeature() {
57 return !this.isPremiumUpgradeRequired;
58 }
59
60 @computed get isAnyWorkspaceActive() {
61 return !!this.activeWorkspace;
62 }
63
64 // ========== PRIVATE PROPERTIES ========= //
65
66 _wasDrawerOpenBeforeSettingsRoute = null;
67
68 _freeUserActions = [];
69
70 _premiumUserActions = [];
71
72 _allActions = [];
73
74 _freeUserReactions = [];
75
76 _premiumUserReactions = [];
77
78 _allReactions = [];
79
80 // ========== PUBLIC API ========= //
81
54 start(stores, actions) { 82 start(stores, actions) {
55 debug('WorkspacesStore::start'); 83 debug('WorkspacesStore::start');
56 this.stores = stores; 84 this.stores = stores;
57 this.actions = actions; 85 this.actions = actions;
58 86
59 this._listenToActions([ 87 // ACTIONS
88
89 this._freeUserActions = createActionBindings([
90 [workspaceActions.toggleWorkspaceDrawer, this._toggleWorkspaceDrawer],
91 [workspaceActions.openWorkspaceSettings, this._openWorkspaceSettings],
92 ]);
93 this._premiumUserActions = createActionBindings([
60 [workspaceActions.edit, this._edit], 94 [workspaceActions.edit, this._edit],
61 [workspaceActions.create, this._create], 95 [workspaceActions.create, this._create],
62 [workspaceActions.delete, this._delete], 96 [workspaceActions.delete, this._delete],
63 [workspaceActions.update, this._update], 97 [workspaceActions.update, this._update],
64 [workspaceActions.activate, this._setActiveWorkspace], 98 [workspaceActions.activate, this._setActiveWorkspace],
65 [workspaceActions.deactivate, this._deactivateActiveWorkspace], 99 [workspaceActions.deactivate, this._deactivateActiveWorkspace],
66 [workspaceActions.toggleWorkspaceDrawer, this._toggleWorkspaceDrawer],
67 [workspaceActions.openWorkspaceSettings, this._openWorkspaceSettings],
68 ]); 100 ]);
101 this._allActions = this._freeUserActions.concat(this._premiumUserActions);
102 this._registerActions(this._allActions);
69 103
70 this._startReactions([ 104 // REACTIONS
71 this._setWorkspaceBeingEditedReaction, 105
72 this._setActiveServiceOnWorkspaceSwitchReaction, 106 this._freeUserReactions = createReactions([
107 this._stopPremiumActionsAndReactions,
108 this._openDrawerWithSettingsReaction,
73 this._setFeatureEnabledReaction, 109 this._setFeatureEnabledReaction,
74 this._setIsPremiumFeatureReaction, 110 this._setIsPremiumFeatureReaction,
75 this._activateLastUsedWorkspaceReaction,
76 this._openDrawerWithSettingsReaction,
77 this._cleanupInvalidServiceReferences, 111 this._cleanupInvalidServiceReferences,
78 ]); 112 ]);
113 this._premiumUserReactions = createReactions([
114 this._setActiveServiceOnWorkspaceSwitchReaction,
115 this._activateLastUsedWorkspaceReaction,
116 this._setWorkspaceBeingEditedReaction,
117 ]);
118 this._allReactions = this._freeUserReactions.concat(this._premiumUserReactions);
119
120 this._registerReactions(this._allReactions);
79 121
80 getUserWorkspacesRequest.execute(); 122 getUserWorkspacesRequest.execute();
81 this.isFeatureActive = true; 123 this.isFeatureActive = true;
82 } 124 }
83 125
84 stop() { 126 stop() {
127 super.stop();
85 debug('WorkspacesStore::stop'); 128 debug('WorkspacesStore::stop');
86 this.isFeatureActive = false; 129 this.isFeatureActive = false;
87 this.activeWorkspace = null; 130 this.activeWorkspace = null;
@@ -104,9 +147,7 @@ export default class WorkspacesStore extends FeatureStore {
104 return workspace.services.map(id => services.one(id)).filter(s => !!s); 147 return workspace.services.map(id => services.one(id)).filter(s => !!s);
105 } 148 }
106 149
107 // ========== PRIVATE ========= // 150 // ========== PRIVATE METHODS ========= //
108
109 _wasDrawerOpenBeforeSettingsRoute = null;
110 151
111 _getWorkspaceById = id => this.workspaces.find(w => w.id === id); 152 _getWorkspaceById = id => this.workspaces.find(w => w.id === id);
112 153
@@ -192,6 +233,14 @@ export default class WorkspacesStore extends FeatureStore {
192 this.actions.ui.openSettings({ path: 'workspaces' }); 233 this.actions.ui.openSettings({ path: 'workspaces' });
193 }; 234 };
194 235
236 @action reorderServicesOfActiveWorkspace = async ({ oldIndex, newIndex }) => {
237 const { activeWorkspace } = this;
238 const { services } = activeWorkspace;
239 // Move services from the old to the new position
240 services.splice(newIndex, 0, services.splice(oldIndex, 1)[0]);
241 await updateWorkspaceRequest.execute(activeWorkspace);
242 };
243
195 // Reactions 244 // Reactions
196 245
197 _setFeatureEnabledReaction = () => { 246 _setFeatureEnabledReaction = () => {
@@ -218,13 +267,15 @@ export default class WorkspacesStore extends FeatureStore {
218 _setActiveServiceOnWorkspaceSwitchReaction = () => { 267 _setActiveServiceOnWorkspaceSwitchReaction = () => {
219 if (!this.isFeatureActive) return; 268 if (!this.isFeatureActive) return;
220 if (this.activeWorkspace) { 269 if (this.activeWorkspace) {
221 const services = this.stores.services.allDisplayed; 270 const activeService = this.stores.services.active;
222 const activeService = services.find(s => s.isActive);
223 const workspaceServices = this.getWorkspaceServices(this.activeWorkspace); 271 const workspaceServices = this.getWorkspaceServices(this.activeWorkspace);
224 if (workspaceServices.length <= 0) return; 272 if (workspaceServices.length <= 0) return;
225 const isActiveServiceInWorkspace = workspaceServices.includes(activeService); 273 const isActiveServiceInWorkspace = workspaceServices.includes(activeService);
226 if (!isActiveServiceInWorkspace) { 274 if (!isActiveServiceInWorkspace) {
227 this.actions.service.setActive({ serviceId: workspaceServices[0].id }); 275 this.actions.service.setActive({
276 serviceId: workspaceServices[0].id,
277 keepActiveRoute: true,
278 });
228 } 279 }
229 } 280 }
230 }; 281 };
@@ -273,4 +324,14 @@ export default class WorkspacesStore extends FeatureStore {
273 getUserWorkspacesRequest.execute(); 324 getUserWorkspacesRequest.execute();
274 } 325 }
275 }; 326 };
327
328 _stopPremiumActionsAndReactions = () => {
329 if (!this.isUserAllowedToUseFeature) {
330 this._stopActions(this._premiumUserActions);
331 this._stopReactions(this._premiumUserReactions);
332 } else {
333 this._startActions(this._premiumUserActions);
334 this._startReactions(this._premiumUserReactions);
335 }
336 }
276} 337}