aboutsummaryrefslogtreecommitdiffstats
path: root/src/features
diff options
context:
space:
mode:
authorLibravatar Stefan Malzner <stefan@adlk.io>2019-06-13 13:22:27 +0200
committerLibravatar Stefan Malzner <stefan@adlk.io>2019-06-13 13:22:27 +0200
commitf65677735b02326870ada2100b55222fa69a401d (patch)
tree53adfc38c0a493e5e8fef3211d0e82b7d164d9ff /src/features
parentEnforce service limit (diff)
parentMerge branch 'release/5.2.0-beta.2' (diff)
downloadferdium-app-f65677735b02326870ada2100b55222fa69a401d.tar.gz
ferdium-app-f65677735b02326870ada2100b55222fa69a401d.tar.zst
ferdium-app-f65677735b02326870ada2100b55222fa69a401d.zip
Merge branch 'develop' into feature/service-limit
Diffstat (limited to 'src/features')
-rw-r--r--src/features/announcements/components/AnnouncementScreen.js2
-rw-r--r--src/features/announcements/index.js4
-rw-r--r--src/features/announcements/store.js61
-rw-r--r--src/features/workspaces/store.js31
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
8export const announcementsStore = new AnnouncementsStore(); 8export const announcementsStore = new AnnouncementsStore();
9 9
10export const ANNOUNCEMENTS_ROUTES = {
11 TARGET: '/announcements/:id',
12};
13
10export default function initAnnouncements(stores, actions) { 14export 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';
7import semver from 'semver'; 6import semver from 'semver';
8import localStorage from 'mobx-localstorage'; 7import localStorage from 'mobx-localstorage';
9 8
10import { FeatureStore } from '../utils/FeatureStore'; 9import { FeatureStore } from '../utils/FeatureStore';
11import { GA_CATEGORY_ANNOUNCEMENTS } from '.'; 10import { ANNOUNCEMENTS_ROUTES, GA_CATEGORY_ANNOUNCEMENTS } from '.';
12import { getAnnouncementRequest, getChangelogRequest, getCurrentVersionRequest } from './api'; 11import { getAnnouncementRequest, getChangelogRequest, getCurrentVersionRequest } from './api';
13import { announcementActions } from './actions'; 12import { announcementActions } from './actions';
14import { createActionBindings } from '../utils/ActionBinding'; 13import { createActionBindings } from '../utils/ActionBinding';
15import { createReactions } from '../../stores/lib/Reaction'; 14import { createReactions } from '../../stores/lib/Reaction';
16import { gaEvent } from '../../lib/analytics'; 15import { gaEvent } from '../../lib/analytics';
16import { matchRoute } from '../../helpers/routing-helpers';
17import { DEFAULT_APP_SETTINGS } from '../../config';
17 18
18const LOCAL_STORAGE_KEY = 'announcements'; 19const LOCAL_STORAGE_KEY = 'announcements';
19 20
@@ -22,8 +23,6 @@ const debug = require('debug')('Franz:feature:announcements:store');
22export class AnnouncementsStore extends FeatureStore { 23export 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 = () => {