aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/workspaces/store.js
diff options
context:
space:
mode:
Diffstat (limited to 'src/features/workspaces/store.js')
-rw-r--r--src/features/workspaces/store.js276
1 files changed, 276 insertions, 0 deletions
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js
new file mode 100644
index 000000000..ea601700e
--- /dev/null
+++ b/src/features/workspaces/store.js
@@ -0,0 +1,276 @@
1import {
2 computed,
3 observable,
4 action,
5} from 'mobx';
6import localStorage from 'mobx-localstorage';
7import { matchRoute } from '../../helpers/routing-helpers';
8import { workspaceActions } from './actions';
9import { FeatureStore } from '../utils/FeatureStore';
10import {
11 createWorkspaceRequest,
12 deleteWorkspaceRequest,
13 getUserWorkspacesRequest,
14 updateWorkspaceRequest,
15} from './api';
16import { WORKSPACES_ROUTES } from './index';
17
18const debug = require('debug')('Franz:feature:workspaces:store');
19
20export default class WorkspacesStore extends FeatureStore {
21 @observable isFeatureEnabled = false;
22
23 @observable isFeatureActive = false;
24
25 @observable isPremiumFeature = true;
26
27 @observable isPremiumUpgradeRequired = true;
28
29 @observable activeWorkspace = null;
30
31 @observable nextWorkspace = null;
32
33 @observable workspaceBeingEdited = null;
34
35 @observable isSwitchingWorkspace = false;
36
37 @observable isWorkspaceDrawerOpen = false;
38
39 @observable isSettingsRouteActive = null;
40
41 @computed get workspaces() {
42 if (!this.isFeatureActive) return [];
43 return getUserWorkspacesRequest.result || [];
44 }
45
46 @computed get settings() {
47 return localStorage.getItem('workspaces') || {};
48 }
49
50 @computed get userHasWorkspaces() {
51 return getUserWorkspacesRequest.wasExecuted && this.workspaces.length > 0;
52 }
53
54 start(stores, actions) {
55 debug('WorkspacesStore::start');
56 this.stores = stores;
57 this.actions = actions;
58
59 this._listenToActions([
60 [workspaceActions.edit, this._edit],
61 [workspaceActions.create, this._create],
62 [workspaceActions.delete, this._delete],
63 [workspaceActions.update, this._update],
64 [workspaceActions.activate, this._setActiveWorkspace],
65 [workspaceActions.deactivate, this._deactivateActiveWorkspace],
66 [workspaceActions.toggleWorkspaceDrawer, this._toggleWorkspaceDrawer],
67 [workspaceActions.openWorkspaceSettings, this._openWorkspaceSettings],
68 ]);
69
70 this._startReactions([
71 this._setWorkspaceBeingEditedReaction,
72 this._setActiveServiceOnWorkspaceSwitchReaction,
73 this._setFeatureEnabledReaction,
74 this._setIsPremiumFeatureReaction,
75 this._activateLastUsedWorkspaceReaction,
76 this._openDrawerWithSettingsReaction,
77 this._cleanupInvalidServiceReferences,
78 ]);
79
80 getUserWorkspacesRequest.execute();
81 this.isFeatureActive = true;
82 }
83
84 stop() {
85 debug('WorkspacesStore::stop');
86 this.isFeatureActive = false;
87 this.activeWorkspace = null;
88 this.nextWorkspace = null;
89 this.workspaceBeingEdited = null;
90 this.isSwitchingWorkspace = false;
91 this.isWorkspaceDrawerOpen = false;
92 }
93
94 filterServicesByActiveWorkspace = (services) => {
95 const { activeWorkspace, isFeatureActive } = this;
96 if (isFeatureActive && activeWorkspace) {
97 return this.getWorkspaceServices(activeWorkspace);
98 }
99 return services;
100 };
101
102 getWorkspaceServices(workspace) {
103 const { services } = this.stores;
104 return workspace.services.map(id => services.one(id)).filter(s => !!s);
105 }
106
107 // ========== PRIVATE ========= //
108
109 _wasDrawerOpenBeforeSettingsRoute = null;
110
111 _getWorkspaceById = id => this.workspaces.find(w => w.id === id);
112
113 _updateSettings = (changes) => {
114 localStorage.setItem('workspaces', {
115 ...this.settings,
116 ...changes,
117 });
118 };
119
120 // Actions
121
122 @action _edit = ({ workspace }) => {
123 this.stores.router.push(`/settings/workspaces/edit/${workspace.id}`);
124 };
125
126 @action _create = async ({ name }) => {
127 try {
128 const workspace = await createWorkspaceRequest.execute(name);
129 await getUserWorkspacesRequest.result.push(workspace);
130 this._edit({ workspace });
131 } catch (error) {
132 throw error;
133 }
134 };
135
136 @action _delete = async ({ workspace }) => {
137 try {
138 await deleteWorkspaceRequest.execute(workspace);
139 await getUserWorkspacesRequest.result.remove(workspace);
140 this.stores.router.push('/settings/workspaces');
141 } catch (error) {
142 throw error;
143 }
144 };
145
146 @action _update = async ({ workspace }) => {
147 try {
148 await updateWorkspaceRequest.execute(workspace);
149 // Path local result optimistically
150 const localWorkspace = this._getWorkspaceById(workspace.id);
151 Object.assign(localWorkspace, workspace);
152 this.stores.router.push('/settings/workspaces');
153 } catch (error) {
154 throw error;
155 }
156 };
157
158 @action _setActiveWorkspace = ({ workspace }) => {
159 // Indicate that we are switching to another workspace
160 this.isSwitchingWorkspace = true;
161 this.nextWorkspace = workspace;
162 // Delay switching to next workspace so that the services loading does not drag down UI
163 setTimeout(() => {
164 this.activeWorkspace = workspace;
165 this._updateSettings({ lastActiveWorkspace: workspace.id });
166 }, 100);
167 // Indicate that we are done switching to the next workspace
168 setTimeout(() => {
169 this.isSwitchingWorkspace = false;
170 this.nextWorkspace = null;
171 }, 1000);
172 };
173
174 @action _deactivateActiveWorkspace = () => {
175 // Indicate that we are switching to default workspace
176 this.isSwitchingWorkspace = true;
177 this.nextWorkspace = null;
178 this._updateSettings({ lastActiveWorkspace: null });
179 // Delay switching to next workspace so that the services loading does not drag down UI
180 setTimeout(() => {
181 this.activeWorkspace = null;
182 }, 100);
183 // Indicate that we are done switching to the default workspace
184 setTimeout(() => { this.isSwitchingWorkspace = false; }, 1000);
185 };
186
187 @action _toggleWorkspaceDrawer = () => {
188 this.isWorkspaceDrawerOpen = !this.isWorkspaceDrawerOpen;
189 };
190
191 @action _openWorkspaceSettings = () => {
192 this.actions.ui.openSettings({ path: 'workspaces' });
193 };
194
195 // Reactions
196
197 _setFeatureEnabledReaction = () => {
198 const { isWorkspaceEnabled } = this.stores.features.features;
199 this.isFeatureEnabled = isWorkspaceEnabled;
200 };
201
202 _setIsPremiumFeatureReaction = () => {
203 const { features, user } = this.stores;
204 const { isPremium } = user.data;
205 const { isWorkspacePremiumFeature } = features.features;
206 this.isPremiumFeature = isWorkspacePremiumFeature;
207 this.isPremiumUpgradeRequired = isWorkspacePremiumFeature && !isPremium;
208 };
209
210 _setWorkspaceBeingEditedReaction = () => {
211 const { pathname } = this.stores.router.location;
212 const match = matchRoute('/settings/workspaces/edit/:id', pathname);
213 if (match) {
214 this.workspaceBeingEdited = this._getWorkspaceById(match.id);
215 }
216 };
217
218 _setActiveServiceOnWorkspaceSwitchReaction = () => {
219 if (!this.isFeatureActive) return;
220 if (this.activeWorkspace) {
221 const services = this.stores.services.allDisplayed;
222 const activeService = services.find(s => s.isActive);
223 const workspaceServices = this.getWorkspaceServices(this.activeWorkspace);
224 if (workspaceServices.length <= 0) return;
225 const isActiveServiceInWorkspace = workspaceServices.includes(activeService);
226 if (!isActiveServiceInWorkspace) {
227 this.actions.service.setActive({ serviceId: workspaceServices[0].id });
228 }
229 }
230 };
231
232 _activateLastUsedWorkspaceReaction = () => {
233 if (!this.activeWorkspace && this.userHasWorkspaces) {
234 const { lastActiveWorkspace } = this.settings;
235 if (lastActiveWorkspace) {
236 const workspace = this._getWorkspaceById(lastActiveWorkspace);
237 if (workspace) this._setActiveWorkspace({ workspace });
238 }
239 }
240 };
241
242 _openDrawerWithSettingsReaction = () => {
243 const { router } = this.stores;
244 const isWorkspaceSettingsRoute = router.location.pathname.includes(WORKSPACES_ROUTES.ROOT);
245 const isSwitchingToSettingsRoute = !this.isSettingsRouteActive && isWorkspaceSettingsRoute;
246 const isLeavingSettingsRoute = !isWorkspaceSettingsRoute && this.isSettingsRouteActive;
247
248 if (isSwitchingToSettingsRoute) {
249 this.isSettingsRouteActive = true;
250 this._wasDrawerOpenBeforeSettingsRoute = this.isWorkspaceDrawerOpen;
251 if (!this._wasDrawerOpenBeforeSettingsRoute) {
252 workspaceActions.toggleWorkspaceDrawer();
253 }
254 } else if (isLeavingSettingsRoute) {
255 this.isSettingsRouteActive = false;
256 if (!this._wasDrawerOpenBeforeSettingsRoute && this.isWorkspaceDrawerOpen) {
257 workspaceActions.toggleWorkspaceDrawer();
258 }
259 }
260 };
261
262 _cleanupInvalidServiceReferences = () => {
263 const { services } = this.stores;
264 let invalidServiceReferencesExist = false;
265 this.workspaces.forEach((workspace) => {
266 workspace.services.forEach((serviceId) => {
267 if (!services.one(serviceId)) {
268 invalidServiceReferencesExist = true;
269 }
270 });
271 });
272 if (invalidServiceReferencesExist) {
273 getUserWorkspacesRequest.execute();
274 }
275 };
276}