aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/workspaces/store.js
diff options
context:
space:
mode:
authorLibravatar Dominik Guzei <dominik.guzei@gmail.com>2019-03-23 14:15:57 +0100
committerLibravatar Dominik Guzei <dominik.guzei@gmail.com>2019-03-23 14:15:57 +0100
commit0af622e6e81a5aee64f839eeadd23b4a62b3cf62 (patch)
tree0e2264b83c3f57f2850062f6b7293bf06416bb49 /src/features/workspaces/store.js
parentfix merge conflicts with latest develop (diff)
downloadferdium-app-0af622e6e81a5aee64f839eeadd23b4a62b3cf62.tar.gz
ferdium-app-0af622e6e81a5aee64f839eeadd23b4a62b3cf62.tar.zst
ferdium-app-0af622e6e81a5aee64f839eeadd23b4a62b3cf62.zip
refactor state management for workspace feature
Diffstat (limited to 'src/features/workspaces/store.js')
-rw-r--r--src/features/workspaces/store.js196
1 files changed, 121 insertions, 75 deletions
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js
index f6b9b2ff4..883f36ffb 100644
--- a/src/features/workspaces/store.js
+++ b/src/features/workspaces/store.js
@@ -1,54 +1,39 @@
1import { observable, reaction, action } from 'mobx'; 1import {
2import Store from '../../stores/lib/Store'; 2 computed,
3import CachedRequest from '../../stores/lib/CachedRequest'; 3 observable,
4import Workspace from './models/Workspace'; 4 action,
5} from 'mobx';
6import Reaction from '../../stores/lib/Reaction';
5import { matchRoute } from '../../helpers/routing-helpers'; 7import { matchRoute } from '../../helpers/routing-helpers';
6import { workspaceActions } from './actions'; 8import { workspaceActions } from './actions';
9import {
10 createWorkspaceRequest,
11 deleteWorkspaceRequest,
12 getUserWorkspacesRequest,
13 updateWorkspaceRequest,
14} from './api';
7 15
8const debug = require('debug')('Franz:feature:workspaces'); 16const debug = require('debug')('Franz:feature:workspaces:store');
9 17
10export default class WorkspacesStore extends Store { 18export default class WorkspacesStore {
11 @observable allWorkspacesRequest = new CachedRequest(this.api, 'getUserWorkspaces'); 19 @observable isFeatureActive = false;
12 20
13 constructor(stores, api, actions, state) { 21 @observable activeWorkspace = null;
14 super(stores, api, actions); 22
15 this.state = state; 23 @observable nextWorkspace = null;
16 } 24
25 @observable workspaceBeingEdited = null;
26
27 @observable isSwitchingWorkspace = false;
17 28
18 setup() { 29 @observable isWorkspaceDrawerOpen = false;
19 debug('fetching workspaces');
20 this.allWorkspacesRequest.execute();
21
22 /**
23 * Update the state workspaces array when workspaces request has results.
24 */
25 reaction(
26 () => this.allWorkspacesRequest.result,
27 workspaces => this._setWorkspaces(workspaces),
28 );
29 /**
30 * Update the loading state when workspace request is executing.
31 */
32 reaction(
33 () => this.allWorkspacesRequest.isExecuting,
34 isExecuting => this._setIsLoadingWorkspaces(isExecuting),
35 );
36 /**
37 * Update the state with the workspace to be edited when route matches.
38 */
39 reaction(
40 () => ({
41 pathname: this.stores.router.location.pathname,
42 workspaces: this.state.workspaces,
43 }),
44 ({ pathname }) => {
45 const match = matchRoute('/settings/workspaces/edit/:id', pathname);
46 if (match) {
47 this.state.workspaceBeingEdited = this._getWorkspaceById(match.id);
48 }
49 },
50 );
51 30
31 @computed get workspaces() {
32 return getUserWorkspacesRequest.execute().result || [];
33 }
34
35 constructor() {
36 // Wire-up action handlers
52 workspaceActions.edit.listen(this._edit); 37 workspaceActions.edit.listen(this._edit);
53 workspaceActions.create.listen(this._create); 38 workspaceActions.create.listen(this._create);
54 workspaceActions.delete.listen(this._delete); 39 workspaceActions.delete.listen(this._delete);
@@ -57,28 +42,62 @@ export default class WorkspacesStore extends Store {
57 workspaceActions.deactivate.listen(this._deactivateActiveWorkspace); 42 workspaceActions.deactivate.listen(this._deactivateActiveWorkspace);
58 workspaceActions.toggleWorkspaceDrawer.listen(this._toggleWorkspaceDrawer); 43 workspaceActions.toggleWorkspaceDrawer.listen(this._toggleWorkspaceDrawer);
59 workspaceActions.openWorkspaceSettings.listen(this._openWorkspaceSettings); 44 workspaceActions.openWorkspaceSettings.listen(this._openWorkspaceSettings);
45
46 // Register and start reactions
47 this._registerReactions([
48 this._updateWorkspaceBeingEdited,
49 this._updateActiveServiceOnWorkspaceSwitch,
50 ]);
60 } 51 }
61 52
62 _getWorkspaceById = id => this.state.workspaces.find(w => w.id === id); 53 start(stores, actions) {
54 debug('WorkspacesStore::start');
55 this.stores = stores;
56 this.actions = actions;
57 this._reactions.forEach(r => r.start());
58 this.isFeatureActive = true;
59 }
63 60
64 @action _setWorkspaces = (workspaces) => { 61 stop() {
65 debug('setting user workspaces', workspaces.slice()); 62 debug('WorkspacesStore::stop');
66 this.state.workspaces = workspaces.map(data => new Workspace(data)); 63 this._reactions.forEach(r => r.stop());
67 }; 64 this.isFeatureActive = false;
65 }
68 66
69 @action _setIsLoadingWorkspaces = (isLoading) => { 67 filterServicesByActiveWorkspace = (services) => {
70 this.state.isLoadingWorkspaces = isLoading; 68 const { activeWorkspace, isFeatureActive } = this;
69
70 if (!isFeatureActive) return services;
71 if (activeWorkspace) {
72 return services.filter(s => (
73 activeWorkspace.services.includes(s.id)
74 ));
75 }
76 return services;
71 }; 77 };
72 78
79 // ========== PRIVATE ========= //
80
81 _reactions = [];
82
83 _registerReactions(reactions) {
84 reactions.forEach(r => this._reactions.push(new Reaction(r)));
85 }
86
87 _getWorkspaceById = id => this.workspaces.find(w => w.id === id);
88
89 // Actions
90
73 @action _edit = ({ workspace }) => { 91 @action _edit = ({ workspace }) => {
74 this.stores.router.push(`/settings/workspaces/edit/${workspace.id}`); 92 this.stores.router.push(`/settings/workspaces/edit/${workspace.id}`);
75 }; 93 };
76 94
77 @action _create = async ({ name }) => { 95 @action _create = async ({ name }) => {
78 try { 96 try {
79 const result = await this.api.createWorkspace(name); 97 const workspace = await createWorkspaceRequest.execute(name);
80 const workspace = new Workspace(result); 98 await getUserWorkspacesRequest.patch((result) => {
81 this.state.workspaces.push(workspace); 99 result.push(workspace);
100 });
82 this._edit({ workspace }); 101 this._edit({ workspace });
83 } catch (error) { 102 } catch (error) {
84 throw error; 103 throw error;
@@ -87,8 +106,10 @@ export default class WorkspacesStore extends Store {
87 106
88 @action _delete = async ({ workspace }) => { 107 @action _delete = async ({ workspace }) => {
89 try { 108 try {
90 await this.api.deleteWorkspace(workspace); 109 await deleteWorkspaceRequest.execute(workspace);
91 this.state.workspaces.remove(workspace); 110 await getUserWorkspacesRequest.patch((result) => {
111 result.remove(workspace);
112 });
92 this.stores.router.push('/settings/workspaces'); 113 this.stores.router.push('/settings/workspaces');
93 } catch (error) { 114 } catch (error) {
94 throw error; 115 throw error;
@@ -97,9 +118,11 @@ export default class WorkspacesStore extends Store {
97 118
98 @action _update = async ({ workspace }) => { 119 @action _update = async ({ workspace }) => {
99 try { 120 try {
100 await this.api.updateWorkspace(workspace); 121 await updateWorkspaceRequest.execute(workspace);
101 const localWorkspace = this.state.workspaces.find(ws => ws.id === workspace.id); 122 await getUserWorkspacesRequest.patch((result) => {
102 Object.assign(localWorkspace, workspace); 123 const localWorkspace = result.find(ws => ws.id === workspace.id);
124 Object.assign(localWorkspace, workspace);
125 });
103 this.stores.router.push('/settings/workspaces'); 126 this.stores.router.push('/settings/workspaces');
104 } catch (error) { 127 } catch (error) {
105 throw error; 128 throw error;
@@ -107,33 +130,56 @@ export default class WorkspacesStore extends Store {
107 }; 130 };
108 131
109 @action _setActiveWorkspace = ({ workspace }) => { 132 @action _setActiveWorkspace = ({ workspace }) => {
110 Object.assign(this.state, { 133 // Indicate that we are switching to another workspace
111 isSwitchingWorkspace: true, 134 this.isSwitchingWorkspace = true;
112 nextWorkspace: workspace, 135 this.nextWorkspace = workspace;
113 }); 136 // Delay switching to next workspace so that the services loading does not drag down UI
114 setTimeout(() => { this.state.activeWorkspace = workspace; }, 100); 137 setTimeout(() => { this.activeWorkspace = workspace; }, 100);
138 // Indicate that we are done switching to the next workspace
115 setTimeout(() => { 139 setTimeout(() => {
116 Object.assign(this.state, { 140 this.isSwitchingWorkspace = false;
117 isSwitchingWorkspace: false, 141 this.nextWorkspace = null;
118 nextWorkspace: null,
119 });
120 }, 1000); 142 }, 1000);
121 }; 143 };
122 144
123 @action _deactivateActiveWorkspace = () => { 145 @action _deactivateActiveWorkspace = () => {
124 Object.assign(this.state, { 146 // Indicate that we are switching to default workspace
125 isSwitchingWorkspace: true, 147 this.isSwitchingWorkspace = true;
126 nextWorkspace: null, 148 this.nextWorkspace = null;
127 }); 149 // Delay switching to next workspace so that the services loading does not drag down UI
128 setTimeout(() => { this.state.activeWorkspace = null; }, 100); 150 setTimeout(() => { this.activeWorkspace = null; }, 100);
129 setTimeout(() => { this.state.isSwitchingWorkspace = false; }, 1000); 151 // Indicate that we are done switching to the default workspace
152 setTimeout(() => { this.isSwitchingWorkspace = false; }, 1000);
130 }; 153 };
131 154
132 @action _toggleWorkspaceDrawer = () => { 155 @action _toggleWorkspaceDrawer = () => {
133 this.state.isWorkspaceDrawerOpen = !this.state.isWorkspaceDrawerOpen; 156 this.isWorkspaceDrawerOpen = !this.isWorkspaceDrawerOpen;
134 }; 157 };
135 158
136 @action _openWorkspaceSettings = () => { 159 @action _openWorkspaceSettings = () => {
137 this.actions.ui.openSettings({ path: 'workspaces' }); 160 this.actions.ui.openSettings({ path: 'workspaces' });
138 }; 161 };
162
163 // Reactions
164
165 _updateWorkspaceBeingEdited = () => {
166 const { pathname } = this.stores.router.location;
167 const match = matchRoute('/settings/workspaces/edit/:id', pathname);
168 if (match) {
169 this.workspaceBeingEdited = this._getWorkspaceById(match.id);
170 }
171 };
172
173 _updateActiveServiceOnWorkspaceSwitch = () => {
174 if (!this.isFeatureActive) return;
175 if (this.activeWorkspace) {
176 const services = this.stores.services.allDisplayed;
177 const activeService = services.find(s => s.isActive);
178 const workspaceServices = this.filterServicesByActiveWorkspace(services);
179 const isActiveServiceInWorkspace = workspaceServices.includes(activeService);
180 if (!isActiveServiceInWorkspace) {
181 this.actions.service.setActive({ serviceId: workspaceServices[0].id });
182 }
183 }
184 };
139} 185}