summaryrefslogtreecommitdiffstats
path: root/src/features/workspaces/store.ts
diff options
context:
space:
mode:
authorLibravatar Muhamed <unknown>2022-11-24 02:56:10 +0530
committerLibravatar Vijay Aravamudhan <vraravam@users.noreply.github.com>2022-11-25 05:04:25 +0530
commitf92933c396db9e94ffd297c41add86de88dfc6c6 (patch)
tree57789f7f64c618086c3792833d076244d879aa75 /src/features/workspaces/store.ts
parentfix: use 'Route' from 'react-router-dom' package (diff)
downloadferdium-app-f92933c396db9e94ffd297c41add86de88dfc6c6.tar.gz
ferdium-app-f92933c396db9e94ffd297c41add86de88dfc6c6.tar.zst
ferdium-app-f92933c396db9e94ffd297c41add86de88dfc6c6.zip
chore: transform workspace action store and todo store into ts
Diffstat (limited to 'src/features/workspaces/store.ts')
-rw-r--r--src/features/workspaces/store.ts371
1 files changed, 371 insertions, 0 deletions
diff --git a/src/features/workspaces/store.ts b/src/features/workspaces/store.ts
new file mode 100644
index 000000000..d63feb1f8
--- /dev/null
+++ b/src/features/workspaces/store.ts
@@ -0,0 +1,371 @@
1import { computed, observable, action, makeObservable } from 'mobx';
2import localStorage from 'mobx-localstorage';
3import matchRoute from '../../helpers/routing-helpers';
4import workspaceActions from './actions';
5import FeatureStore from '../utils/FeatureStore';
6import {
7 createWorkspaceRequest,
8 deleteWorkspaceRequest,
9 getUserWorkspacesRequest,
10 updateWorkspaceRequest,
11} from './api';
12import { WORKSPACES_ROUTES } from './constants';
13import { createReactions } from '../../stores/lib/Reaction';
14import { createActionBindings } from '../utils/ActionBinding';
15
16import { KEEP_WS_LOADED_USID } from '../../config';
17import Workspace from './models/Workspace';
18import { Actions } from '../../actions/lib/actions';
19
20const debug = require('../../preload-safe-debug')(
21 'Ferdium:feature:workspaces:store',
22);
23
24export default class WorkspacesStore extends FeatureStore {
25 @observable isFeatureActive = false;
26
27 @observable activeWorkspace: Workspace | undefined;
28
29 @observable nextWorkspace: Workspace | undefined;
30
31 @observable workspaceBeingEdited: any = null; // TODO - [TS DEBT] fix type later
32
33 @observable isSwitchingWorkspace = false;
34
35 @observable isWorkspaceDrawerOpen = false;
36
37 @observable isSettingsRouteActive = false;
38
39 stores: any; // TODO - [TS DEBT] fix type later
40
41 actions: Actions | undefined;
42
43 constructor() {
44 super();
45
46 makeObservable(this);
47 }
48
49 @computed get workspaces() {
50 if (!this.isFeatureActive) return [];
51 return getUserWorkspacesRequest.result || [];
52 }
53
54 @computed get isLoadingWorkspaces() {
55 if (!this.isFeatureActive) return false;
56 return getUserWorkspacesRequest.isExecutingFirstTime;
57 }
58
59 @computed get settings() {
60 return localStorage.getItem('workspaces') || {};
61 }
62
63 @computed get userHasWorkspaces() {
64 return getUserWorkspacesRequest.wasExecuted && this.workspaces.length > 0;
65 }
66
67 @computed get isUserAllowedToUseFeature() {
68 return true;
69 }
70
71 @computed get isAnyWorkspaceActive() {
72 return !!this.activeWorkspace;
73 }
74
75 // ========== PRIVATE PROPERTIES ========= //
76
77 _wasDrawerOpenBeforeSettingsRoute = false;
78
79 _allActions = [];
80
81 _allReactions = [];
82
83 // ========== PUBLIC API ========= //
84
85 @action start(stores, actions) {
86 debug('WorkspacesStore::start');
87 this.stores = stores;
88 this.actions = actions;
89
90 // ACTIONS
91
92 this._allActions = createActionBindings([
93 [workspaceActions.toggleWorkspaceDrawer, this._toggleWorkspaceDrawer],
94 [workspaceActions.openWorkspaceSettings, this._openWorkspaceSettings],
95 [workspaceActions.edit, this._edit],
96 [workspaceActions.create, this._create],
97 [workspaceActions.delete, this._delete],
98 [workspaceActions.update, this._update],
99 [workspaceActions.activate, this._setActivateWorkspace],
100 [workspaceActions.deactivate, this._deactivateActiveWorkspace],
101 [
102 workspaceActions.toggleKeepAllWorkspacesLoadedSetting,
103 this._toggleKeepAllWorkspacesLoadedSetting,
104 ],
105 ]);
106 this._registerActions(this._allActions);
107
108 // REACTIONS
109
110 this._allReactions = createReactions([
111 this._openDrawerWithSettingsReaction,
112 this._cleanupInvalidServiceReferences,
113 this._setActiveServiceOnWorkspaceSwitchReaction,
114 this._activateLastUsedWorkspaceReaction,
115 this._setWorkspaceBeingEditedReaction,
116 ]);
117 this._registerReactions(this._allReactions);
118
119 this.isFeatureActive = true;
120 }
121
122 @action reset() {
123 this._setActiveWorkspace(null);
124 this._setNextWorkspace(null);
125 this.workspaceBeingEdited = null;
126 this._setIsSwitchingWorkspace(false);
127 this.isWorkspaceDrawerOpen = false;
128 }
129
130 @action stop() {
131 super.stop();
132 debug('WorkspacesStore::stop');
133 this.reset();
134 this.isFeatureActive = false;
135 }
136
137 filterServicesByActiveWorkspace = services => {
138 const { activeWorkspace, isFeatureActive } = this;
139 if (isFeatureActive && activeWorkspace) {
140 return this.getWorkspaceServices(activeWorkspace);
141 }
142 return services;
143 };
144
145 getWorkspaceServices(workspace) {
146 const { services } = this.stores;
147 return workspace.services.map(id => services.one(id)).filter(s => !!s);
148 }
149
150 // ========== PRIVATE METHODS ========= //
151
152 _getWorkspaceById = id => this.workspaces.find(w => w.id === id);
153
154 _updateSettings = changes => {
155 localStorage.setItem('workspaces', {
156 ...this.settings,
157 ...changes,
158 });
159 };
160
161 // Actions
162
163 @action _edit = ({ workspace }) => {
164 this.stores.router.push(`/settings/workspaces/edit/${workspace.id}`);
165 };
166
167 @action _create = async ({ name }) => {
168 const workspace = await createWorkspaceRequest.execute(name).promise;
169 await getUserWorkspacesRequest.result.push(workspace);
170 this._edit({ workspace });
171 };
172
173 @action _delete = async ({ workspace }) => {
174 await deleteWorkspaceRequest.execute(workspace).promise;
175 await getUserWorkspacesRequest.result.remove(workspace);
176 this.stores.router.push('/settings/workspaces');
177 if (this.activeWorkspace === workspace) {
178 this._deactivateActiveWorkspace();
179 }
180 };
181
182 @action _update = async ({ workspace }) => {
183 await updateWorkspaceRequest.execute(workspace).promise;
184 // Path local result optimistically
185 const localWorkspace = this._getWorkspaceById(workspace.id);
186 Object.assign(localWorkspace, workspace);
187 this.stores.router.push('/settings/workspaces');
188 };
189
190 @action _setNextWorkspace(workspace) {
191 this.nextWorkspace = workspace;
192 }
193
194 @action _setIsSwitchingWorkspace(bool) {
195 this.isSwitchingWorkspace = bool;
196 }
197
198 @action _setActiveWorkspace(workspace) {
199 this.activeWorkspace = workspace;
200 }
201
202 @action _setActivateWorkspace = ({ workspace }) => {
203 // Indicate that we are switching to another workspace
204 this._setIsSwitchingWorkspace(true);
205 this._setNextWorkspace(workspace);
206 // Delay switching to next workspace so that the services loading does not drag down UI
207 setTimeout(() => {
208 this._setActiveWorkspace(workspace);
209 this._updateSettings({ lastActiveWorkspace: workspace.id });
210 }, 100);
211 // Indicate that we are done switching to the next workspace
212 setTimeout(() => {
213 this._setIsSwitchingWorkspace(false);
214 this._setNextWorkspace(null);
215 if (this.stores.settings.app.splitMode) {
216 const serviceNames = new Set(
217 this.getWorkspaceServices(workspace).map(service => service.name),
218 );
219 for (const wrapper of document.querySelectorAll<HTMLDivElement>(
220 '.services__webview-wrapper',
221 )) {
222 wrapper.style.display = serviceNames.has(wrapper.dataset.name)
223 ? ''
224 : 'none';
225 }
226 }
227 }, 500);
228 };
229
230 @action _deactivateActiveWorkspace = () => {
231 // Indicate that we are switching to default workspace
232 this._setIsSwitchingWorkspace(true);
233 this._setNextWorkspace(null);
234 this._updateSettings({ lastActiveWorkspace: null });
235 // Delay switching to next workspace so that the services loading does not drag down UI
236 setTimeout(() => {
237 this._setActiveWorkspace(null);
238 }, 100);
239 // Indicate that we are done switching to the default workspace
240 setTimeout(() => {
241 this._setIsSwitchingWorkspace(false);
242 if (this.stores.settings.app.splitMode) {
243 for (const wrapper of document.querySelectorAll<HTMLDivElement>(
244 '.services__webview-wrapper',
245 )) {
246 wrapper.style.display = '';
247 }
248 }
249 }, 500);
250 };
251
252 @action _toggleWorkspaceDrawer = () => {
253 this.isWorkspaceDrawerOpen = !this.isWorkspaceDrawerOpen;
254 };
255
256 @action _openWorkspaceSettings = () => {
257 if (!this.actions) {
258 return;
259 }
260 this.actions.ui.openSettings({ path: 'workspaces' });
261 };
262
263 @action reorderServicesOfActiveWorkspace = async ({ oldIndex, newIndex }) => {
264 if (!this.activeWorkspace) {
265 return;
266 }
267
268 const { services = [] } = this.activeWorkspace;
269 // Move services from the old to the new position
270 services.splice(newIndex, 0, services.splice(oldIndex, 1)[0]);
271 await updateWorkspaceRequest.execute(this.activeWorkspace).promise;
272 };
273
274 @action _setOpenDrawerWithSettings() {
275 const { router } = this.stores;
276 const isWorkspaceSettingsRoute = router.location.pathname.includes(
277 WORKSPACES_ROUTES.ROOT,
278 );
279 const isSwitchingToSettingsRoute =
280 !this.isSettingsRouteActive && isWorkspaceSettingsRoute;
281 const isLeavingSettingsRoute =
282 !isWorkspaceSettingsRoute && this.isSettingsRouteActive;
283
284 if (isSwitchingToSettingsRoute) {
285 this.isSettingsRouteActive = true;
286 this._wasDrawerOpenBeforeSettingsRoute = this.isWorkspaceDrawerOpen;
287 if (!this._wasDrawerOpenBeforeSettingsRoute) {
288 workspaceActions.toggleWorkspaceDrawer();
289 }
290 } else if (isLeavingSettingsRoute) {
291 this.isSettingsRouteActive = false;
292 if (
293 !this._wasDrawerOpenBeforeSettingsRoute &&
294 this.isWorkspaceDrawerOpen
295 ) {
296 workspaceActions.toggleWorkspaceDrawer();
297 }
298 }
299 }
300
301 @action _setWorkspaceBeingEdited(match) {
302 this.workspaceBeingEdited = this._getWorkspaceById(match.id);
303 }
304
305 _toggleKeepAllWorkspacesLoadedSetting = async () => {
306 this._updateSettings({
307 keepAllWorkspacesLoaded: !this.settings.keepAllWorkspacesLoaded,
308 });
309 };
310
311 // Reactions
312
313 _setWorkspaceBeingEditedReaction = () => {
314 const { pathname } = this.stores.router.location;
315 const match = matchRoute('/settings/workspaces/edit/:id', pathname);
316 if (match) {
317 this._setWorkspaceBeingEdited(match);
318 }
319 };
320
321 _setActiveServiceOnWorkspaceSwitchReaction = () => {
322 if (!this.isFeatureActive) return;
323 if (this.activeWorkspace) {
324 const activeService = this.stores.services.active;
325 const workspaceServices = this.getWorkspaceServices(this.activeWorkspace);
326 if (workspaceServices.length <= 0) return;
327 const isActiveServiceInWorkspace =
328 workspaceServices.includes(activeService);
329 if (!isActiveServiceInWorkspace && this.actions) {
330 this.actions.service.setActive({
331 serviceId: workspaceServices[0].id,
332 keepActiveRoute: true,
333 });
334 }
335 }
336 };
337
338 _activateLastUsedWorkspaceReaction = () => {
339 debug('_activateLastUsedWorkspaceReaction');
340 if (!this.activeWorkspace && this.userHasWorkspaces) {
341 const { lastActiveWorkspace } = this.settings;
342 if (lastActiveWorkspace) {
343 const workspace = this._getWorkspaceById(lastActiveWorkspace);
344 if (workspace) this._setActivateWorkspace({ workspace });
345 }
346 }
347 };
348
349 _openDrawerWithSettingsReaction = () => {
350 this._setOpenDrawerWithSettings();
351 };
352
353 _cleanupInvalidServiceReferences = () => {
354 const { services } = this.stores;
355 const { allServicesRequest } = services;
356 const servicesHaveBeenLoaded =
357 allServicesRequest.wasExecuted && !allServicesRequest.isError;
358 // Loop through all workspaces and remove invalid service ids (locally)
359 for (const workspace of this.workspaces) {
360 for (const serviceId of workspace.services) {
361 if (
362 servicesHaveBeenLoaded &&
363 !services.one(serviceId) &&
364 serviceId !== KEEP_WS_LOADED_USID
365 ) {
366 workspace.services.remove(serviceId);
367 }
368 }
369 }
370 };
371}