diff options
Diffstat (limited to 'src/features')
-rw-r--r-- | src/features/announcements/components/AnnouncementScreen.js | 2 | ||||
-rw-r--r-- | src/features/announcements/index.js | 4 | ||||
-rw-r--r-- | src/features/announcements/store.js | 61 | ||||
-rw-r--r-- | src/features/workspaces/store.js | 31 |
4 files changed, 58 insertions, 40 deletions
diff --git a/src/features/announcements/components/AnnouncementScreen.js b/src/features/announcements/components/AnnouncementScreen.js index dfce6cdd5..e7c5fe395 100644 --- a/src/features/announcements/components/AnnouncementScreen.js +++ b/src/features/announcements/components/AnnouncementScreen.js | |||
@@ -268,7 +268,7 @@ class AnnouncementScreen extends Component { | |||
268 | <div className={classes.changelog}> | 268 | <div className={classes.changelog}> |
269 | <h1 className={classes.headline}> | 269 | <h1 className={classes.headline}> |
270 | {intl.formatMessage(messages.headline, { | 270 | {intl.formatMessage(messages.headline, { |
271 | version: announcementsStore.currentVersion, | 271 | version: announcementsStore.targetVersion, |
272 | })} | 272 | })} |
273 | </h1> | 273 | </h1> |
274 | <div | 274 | <div |
diff --git a/src/features/announcements/index.js b/src/features/announcements/index.js index 4658b976f..f14e7c9a5 100644 --- a/src/features/announcements/index.js +++ b/src/features/announcements/index.js | |||
@@ -7,6 +7,10 @@ export const GA_CATEGORY_ANNOUNCEMENTS = 'Announcements'; | |||
7 | 7 | ||
8 | export const announcementsStore = new AnnouncementsStore(); | 8 | export const announcementsStore = new AnnouncementsStore(); |
9 | 9 | ||
10 | export const ANNOUNCEMENTS_ROUTES = { | ||
11 | TARGET: '/announcements/:id', | ||
12 | }; | ||
13 | |||
10 | export default function initAnnouncements(stores, actions) { | 14 | export default function initAnnouncements(stores, actions) { |
11 | // const { features } = stores; | 15 | // const { features } = stores; |
12 | 16 | ||
diff --git a/src/features/announcements/store.js b/src/features/announcements/store.js index 7ecc0e346..de7ed2596 100644 --- a/src/features/announcements/store.js +++ b/src/features/announcements/store.js | |||
@@ -2,18 +2,19 @@ import { | |||
2 | action, | 2 | action, |
3 | computed, | 3 | computed, |
4 | observable, | 4 | observable, |
5 | reaction, | ||
6 | } from 'mobx'; | 5 | } from 'mobx'; |
7 | import semver from 'semver'; | 6 | import semver from 'semver'; |
8 | import localStorage from 'mobx-localstorage'; | 7 | import localStorage from 'mobx-localstorage'; |
9 | 8 | ||
10 | import { FeatureStore } from '../utils/FeatureStore'; | 9 | import { FeatureStore } from '../utils/FeatureStore'; |
11 | import { GA_CATEGORY_ANNOUNCEMENTS } from '.'; | 10 | import { ANNOUNCEMENTS_ROUTES, GA_CATEGORY_ANNOUNCEMENTS } from '.'; |
12 | import { getAnnouncementRequest, getChangelogRequest, getCurrentVersionRequest } from './api'; | 11 | import { getAnnouncementRequest, getChangelogRequest, getCurrentVersionRequest } from './api'; |
13 | import { announcementActions } from './actions'; | 12 | import { announcementActions } from './actions'; |
14 | import { createActionBindings } from '../utils/ActionBinding'; | 13 | import { createActionBindings } from '../utils/ActionBinding'; |
15 | import { createReactions } from '../../stores/lib/Reaction'; | 14 | import { createReactions } from '../../stores/lib/Reaction'; |
16 | import { gaEvent } from '../../lib/analytics'; | 15 | import { gaEvent } from '../../lib/analytics'; |
16 | import { matchRoute } from '../../helpers/routing-helpers'; | ||
17 | import { DEFAULT_APP_SETTINGS } from '../../config'; | ||
17 | 18 | ||
18 | const LOCAL_STORAGE_KEY = 'announcements'; | 19 | const LOCAL_STORAGE_KEY = 'announcements'; |
19 | 20 | ||
@@ -22,8 +23,6 @@ const debug = require('debug')('Franz:feature:announcements:store'); | |||
22 | export class AnnouncementsStore extends FeatureStore { | 23 | export class AnnouncementsStore extends FeatureStore { |
23 | @observable targetVersion = null; | 24 | @observable targetVersion = null; |
24 | 25 | ||
25 | @observable isAnnouncementVisible = false; | ||
26 | |||
27 | @observable isFeatureActive = false; | 26 | @observable isFeatureActive = false; |
28 | 27 | ||
29 | @computed get changelog() { | 28 | @computed get changelog() { |
@@ -31,7 +30,15 @@ export class AnnouncementsStore extends FeatureStore { | |||
31 | } | 30 | } |
32 | 31 | ||
33 | @computed get announcement() { | 32 | @computed get announcement() { |
34 | return getAnnouncementRequest.result; | 33 | if (!this.stores || !getAnnouncementRequest.result) return null; |
34 | const { locale } = this.stores.app; | ||
35 | const announcement = getAnnouncementRequest.result; | ||
36 | // User locale | ||
37 | if (announcement[locale]) return announcement[locale]; | ||
38 | // Default locale | ||
39 | if (announcement[DEFAULT_APP_SETTINGS.fallbackLocale]) return announcement[DEFAULT_APP_SETTINGS.fallbackLocale]; | ||
40 | // No locales specified | ||
41 | return announcement; | ||
35 | } | 42 | } |
36 | 43 | ||
37 | @computed get areNewsAvailable() { | 44 | @computed get areNewsAvailable() { |
@@ -67,8 +74,9 @@ export class AnnouncementsStore extends FeatureStore { | |||
67 | ])); | 74 | ])); |
68 | 75 | ||
69 | this._reactions = createReactions([ | 76 | this._reactions = createReactions([ |
70 | this._fetchAnnouncements, | 77 | this._showAnnouncementOnRouteMatch, |
71 | this._showAnnouncementToUsersWhoUpdatedApp, | 78 | this._showAnnouncementToUsersWhoUpdatedApp, |
79 | this._fetchAnnouncements, | ||
72 | ]); | 80 | ]); |
73 | this._registerReactions(this._reactions); | 81 | this._registerReactions(this._reactions); |
74 | this.isFeatureActive = true; | 82 | this.isFeatureActive = true; |
@@ -78,7 +86,6 @@ export class AnnouncementsStore extends FeatureStore { | |||
78 | super.stop(); | 86 | super.stop(); |
79 | debug('AnnouncementsStore::stop'); | 87 | debug('AnnouncementsStore::stop'); |
80 | this.isFeatureActive = false; | 88 | this.isFeatureActive = false; |
81 | this.isAnnouncementVisible = false; | ||
82 | } | 89 | } |
83 | 90 | ||
84 | // ======= HELPERS ======= // | 91 | // ======= HELPERS ======= // |
@@ -93,39 +100,29 @@ export class AnnouncementsStore extends FeatureStore { | |||
93 | // ======= ACTIONS ======= // | 100 | // ======= ACTIONS ======= // |
94 | 101 | ||
95 | @action _showAnnouncement = ({ targetVersion } = {}) => { | 102 | @action _showAnnouncement = ({ targetVersion } = {}) => { |
96 | if (!this.areNewsAvailable) return; | 103 | const { router } = this.stores; |
97 | this.targetVersion = targetVersion || this.currentVersion; | 104 | this.targetVersion = targetVersion || this.currentVersion; |
98 | this.isAnnouncementVisible = true; | ||
99 | this.actions.service.blurActive(); | ||
100 | this._updateSettings({ | 105 | this._updateSettings({ |
101 | lastSeenAnnouncementVersion: this.currentVersion, | 106 | lastSeenAnnouncementVersion: this.currentVersion, |
102 | }); | 107 | }); |
103 | const dispose = reaction( | 108 | const targetRoute = `/announcements/${this.targetVersion}`; |
104 | () => this.stores.services.active, | 109 | if (router.location.pathname !== targetRoute) { |
105 | () => { | 110 | this.stores.router.push(targetRoute); |
106 | this._hideAnnouncement(); | 111 | } |
107 | dispose(); | ||
108 | }, | ||
109 | ); | ||
110 | |||
111 | gaEvent(GA_CATEGORY_ANNOUNCEMENTS, 'show'); | 112 | gaEvent(GA_CATEGORY_ANNOUNCEMENTS, 'show'); |
112 | }; | 113 | }; |
113 | 114 | ||
114 | @action _hideAnnouncement() { | ||
115 | this.isAnnouncementVisible = false; | ||
116 | } | ||
117 | |||
118 | // ======= REACTIONS ======== | 115 | // ======= REACTIONS ======== |
119 | 116 | ||
120 | _showAnnouncementToUsersWhoUpdatedApp = () => { | 117 | _showAnnouncementToUsersWhoUpdatedApp = () => { |
121 | const { announcement, isNewUser } = this; | 118 | const { announcement, isNewUser } = this; |
122 | // Check if there is an announcement and on't show announcements to new users | 119 | // Check if there is an announcement and don't show announcements to new users |
123 | if (!announcement || isNewUser) return; | 120 | if (!announcement || isNewUser) return; |
124 | 121 | ||
125 | // Check if the user has already used current version (= has seen the announcement) | 122 | // Check if the user has already used current version (= has seen the announcement) |
126 | const { currentVersion, lastSeenAnnouncementVersion } = this; | 123 | const { currentVersion, lastSeenAnnouncementVersion } = this; |
127 | if (semver.gt(currentVersion, lastSeenAnnouncementVersion || '0.0.0')) { | 124 | if (semver.gt(currentVersion, lastSeenAnnouncementVersion || '0.0.0')) { |
128 | debug(`${currentVersion} < ${lastSeenAnnouncementVersion}: announcement is shown`); | 125 | debug(`${currentVersion} > ${lastSeenAnnouncementVersion}: announcement is shown`); |
129 | this._showAnnouncement(); | 126 | this._showAnnouncement(); |
130 | } | 127 | } |
131 | }; | 128 | }; |
@@ -133,12 +130,16 @@ export class AnnouncementsStore extends FeatureStore { | |||
133 | _fetchAnnouncements = () => { | 130 | _fetchAnnouncements = () => { |
134 | const targetVersion = this.targetVersion || this.currentVersion; | 131 | const targetVersion = this.targetVersion || this.currentVersion; |
135 | if (!targetVersion) return; | 132 | if (!targetVersion) return; |
136 | getChangelogRequest.execute(targetVersion); | 133 | getChangelogRequest.reset().execute(targetVersion); |
137 | // We only fetch announcements for current / older versions | 134 | getAnnouncementRequest.reset().execute(targetVersion); |
138 | if (targetVersion <= this.currentVersion) { | 135 | }; |
139 | getAnnouncementRequest.execute(targetVersion); | 136 | |
140 | } else { | 137 | _showAnnouncementOnRouteMatch = () => { |
141 | getAnnouncementRequest.reset(); | 138 | const { router } = this.stores; |
139 | const match = matchRoute(ANNOUNCEMENTS_ROUTES.TARGET, router.location.pathname); | ||
140 | if (match) { | ||
141 | const targetVersion = match.id; | ||
142 | this._showAnnouncement({ targetVersion }); | ||
142 | } | 143 | } |
143 | } | 144 | } |
144 | } | 145 | } |
diff --git a/src/features/workspaces/store.js b/src/features/workspaces/store.js index e11513d1f..07b16ff23 100644 --- a/src/features/workspaces/store.js +++ b/src/features/workspaces/store.js | |||
@@ -57,6 +57,10 @@ export default class WorkspacesStore extends FeatureStore { | |||
57 | return !this.isPremiumUpgradeRequired; | 57 | return !this.isPremiumUpgradeRequired; |
58 | } | 58 | } |
59 | 59 | ||
60 | @computed get isAnyWorkspaceActive() { | ||
61 | return !!this.activeWorkspace; | ||
62 | } | ||
63 | |||
60 | // ========== PRIVATE PROPERTIES ========= // | 64 | // ========== PRIVATE PROPERTIES ========= // |
61 | 65 | ||
62 | _wasDrawerOpenBeforeSettingsRoute = null; | 66 | _wasDrawerOpenBeforeSettingsRoute = null; |
@@ -229,6 +233,14 @@ export default class WorkspacesStore extends FeatureStore { | |||
229 | this.actions.ui.openSettings({ path: 'workspaces' }); | 233 | this.actions.ui.openSettings({ path: 'workspaces' }); |
230 | }; | 234 | }; |
231 | 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 | |||
232 | // Reactions | 244 | // Reactions |
233 | 245 | ||
234 | _setFeatureEnabledReaction = () => { | 246 | _setFeatureEnabledReaction = () => { |
@@ -255,13 +267,15 @@ export default class WorkspacesStore extends FeatureStore { | |||
255 | _setActiveServiceOnWorkspaceSwitchReaction = () => { | 267 | _setActiveServiceOnWorkspaceSwitchReaction = () => { |
256 | if (!this.isFeatureActive) return; | 268 | if (!this.isFeatureActive) return; |
257 | if (this.activeWorkspace) { | 269 | if (this.activeWorkspace) { |
258 | const services = this.stores.services.allDisplayed; | 270 | const activeService = this.stores.services.active; |
259 | const activeService = services.find(s => s.isActive); | ||
260 | const workspaceServices = this.getWorkspaceServices(this.activeWorkspace); | 271 | const workspaceServices = this.getWorkspaceServices(this.activeWorkspace); |
261 | if (workspaceServices.length <= 0) return; | 272 | if (workspaceServices.length <= 0) return; |
262 | const isActiveServiceInWorkspace = workspaceServices.includes(activeService); | 273 | const isActiveServiceInWorkspace = workspaceServices.includes(activeService); |
263 | if (!isActiveServiceInWorkspace) { | 274 | if (!isActiveServiceInWorkspace) { |
264 | this.actions.service.setActive({ serviceId: workspaceServices[0].id }); | 275 | this.actions.service.setActive({ |
276 | serviceId: workspaceServices[0].id, | ||
277 | keepActiveRoute: true, | ||
278 | }); | ||
265 | } | 279 | } |
266 | } | 280 | } |
267 | }; | 281 | }; |
@@ -298,17 +312,16 @@ export default class WorkspacesStore extends FeatureStore { | |||
298 | 312 | ||
299 | _cleanupInvalidServiceReferences = () => { | 313 | _cleanupInvalidServiceReferences = () => { |
300 | const { services } = this.stores; | 314 | const { services } = this.stores; |
301 | let invalidServiceReferencesExist = false; | 315 | const { allServicesRequest } = services; |
316 | const servicesHaveBeenLoaded = allServicesRequest.wasExecuted && !allServicesRequest.isError; | ||
317 | // Loop through all workspaces and remove invalid service ids (locally) | ||
302 | this.workspaces.forEach((workspace) => { | 318 | this.workspaces.forEach((workspace) => { |
303 | workspace.services.forEach((serviceId) => { | 319 | workspace.services.forEach((serviceId) => { |
304 | if (!services.one(serviceId)) { | 320 | if (servicesHaveBeenLoaded && !services.one(serviceId)) { |
305 | invalidServiceReferencesExist = true; | 321 | workspace.services.remove(serviceId); |
306 | } | 322 | } |
307 | }); | 323 | }); |
308 | }); | 324 | }); |
309 | if (invalidServiceReferencesExist) { | ||
310 | getUserWorkspacesRequest.execute(); | ||
311 | } | ||
312 | }; | 325 | }; |
313 | 326 | ||
314 | _stopPremiumActionsAndReactions = () => { | 327 | _stopPremiumActionsAndReactions = () => { |