diff options
author | Muhamed <unknown> | 2022-11-24 02:56:10 +0530 |
---|---|---|
committer | Vijay Aravamudhan <vraravam@users.noreply.github.com> | 2022-11-25 05:04:25 +0530 |
commit | f92933c396db9e94ffd297c41add86de88dfc6c6 (patch) | |
tree | 57789f7f64c618086c3792833d076244d879aa75 /src/features/workspaces/store.ts | |
parent | fix: use 'Route' from 'react-router-dom' package (diff) | |
download | ferdium-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.ts | 371 |
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 @@ | |||
1 | import { computed, observable, action, makeObservable } from 'mobx'; | ||
2 | import localStorage from 'mobx-localstorage'; | ||
3 | import matchRoute from '../../helpers/routing-helpers'; | ||
4 | import workspaceActions from './actions'; | ||
5 | import FeatureStore from '../utils/FeatureStore'; | ||
6 | import { | ||
7 | createWorkspaceRequest, | ||
8 | deleteWorkspaceRequest, | ||
9 | getUserWorkspacesRequest, | ||
10 | updateWorkspaceRequest, | ||
11 | } from './api'; | ||
12 | import { WORKSPACES_ROUTES } from './constants'; | ||
13 | import { createReactions } from '../../stores/lib/Reaction'; | ||
14 | import { createActionBindings } from '../utils/ActionBinding'; | ||
15 | |||
16 | import { KEEP_WS_LOADED_USID } from '../../config'; | ||
17 | import Workspace from './models/Workspace'; | ||
18 | import { Actions } from '../../actions/lib/actions'; | ||
19 | |||
20 | const debug = require('../../preload-safe-debug')( | ||
21 | 'Ferdium:feature:workspaces:store', | ||
22 | ); | ||
23 | |||
24 | export 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 | } | ||