aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/actions/index.ts2
-rw-r--r--src/actions/news.ts7
-rw-r--r--src/api/NewsApi.ts18
-rw-r--r--src/api/index.ts2
-rw-r--r--src/api/server/ServerApi.js36
-rw-r--r--src/components/layout/AppLayout.js59
-rw-r--r--src/containers/layout/AppLayoutContainer.js13
-rw-r--r--src/environment.ts3
-rw-r--r--src/internal-server/start/routes.js1
-rw-r--r--src/models/News.ts33
-rw-r--r--src/stores.types.ts16
-rw-r--r--src/stores/AppStore.js3
-rw-r--r--src/stores/NewsStore.js55
-rw-r--r--src/stores/index.ts2
14 files changed, 22 insertions, 228 deletions
diff --git a/src/actions/index.ts b/src/actions/index.ts
index aecdac675..983afa64b 100644
--- a/src/actions/index.ts
+++ b/src/actions/index.ts
@@ -7,7 +7,6 @@ import recipePreview from './recipePreview';
7import ui from './ui'; 7import ui from './ui';
8import app from './app'; 8import app from './app';
9import user from './user'; 9import user from './user';
10import news from './news';
11import settings from './settings'; 10import settings from './settings';
12import requests from './requests'; 11import requests from './requests';
13import workspaces from '../features/workspaces/actions'; 12import workspaces from '../features/workspaces/actions';
@@ -20,7 +19,6 @@ const actions = {
20 ui, 19 ui,
21 app, 20 app,
22 user, 21 user,
23 news,
24 settings, 22 settings,
25 requests, 23 requests,
26}; 24};
diff --git a/src/actions/news.ts b/src/actions/news.ts
deleted file mode 100644
index db106e84f..000000000
--- a/src/actions/news.ts
+++ /dev/null
@@ -1,7 +0,0 @@
1import PropTypes from 'prop-types';
2
3export default {
4 hide: {
5 newsId: PropTypes.string.isRequired,
6 },
7};
diff --git a/src/api/NewsApi.ts b/src/api/NewsApi.ts
deleted file mode 100644
index 31d3d903b..000000000
--- a/src/api/NewsApi.ts
+++ /dev/null
@@ -1,18 +0,0 @@
1export default class NewsApi {
2 server: any;
3
4 local: any;
5
6 constructor(server: any, local: any) {
7 this.server = server;
8 this.local = local;
9 }
10
11 latest() {
12 return this.server.getLatestNews();
13 }
14
15 hide(id: any) {
16 return this.server.hideNews(id);
17 }
18}
diff --git a/src/api/index.ts b/src/api/index.ts
index 73f613da1..59fad194a 100644
--- a/src/api/index.ts
+++ b/src/api/index.ts
@@ -4,7 +4,6 @@ import RecipePreviewsApi from './RecipePreviewsApi';
4import RecipesApi from './RecipesApi'; 4import RecipesApi from './RecipesApi';
5import UserApi from './UserApi'; 5import UserApi from './UserApi';
6import LocalApi from './LocalApi'; 6import LocalApi from './LocalApi';
7import NewsApi from './NewsApi';
8import FeaturesApi from './FeaturesApi'; 7import FeaturesApi from './FeaturesApi';
9 8
10export default (server: any, local: any) => ({ 9export default (server: any, local: any) => ({
@@ -15,5 +14,4 @@ export default (server: any, local: any) => ({
15 features: new FeaturesApi(server), 14 features: new FeaturesApi(server),
16 user: new UserApi(server, local), 15 user: new UserApi(server, local),
17 local: new LocalApi(server, local), 16 local: new LocalApi(server, local),
18 news: new NewsApi(server, local),
19}); 17});
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js
index e321f9372..6bbf572fa 100644
--- a/src/api/server/ServerApi.js
+++ b/src/api/server/ServerApi.js
@@ -16,14 +16,12 @@ import fetch from 'electron-fetch';
16import ServiceModel from '../../models/Service'; 16import ServiceModel from '../../models/Service';
17import RecipePreviewModel from '../../models/RecipePreview'; 17import RecipePreviewModel from '../../models/RecipePreview';
18import RecipeModel from '../../models/Recipe'; 18import RecipeModel from '../../models/Recipe';
19import NewsModel from '../../models/News';
20import UserModel from '../../models/User'; 19import UserModel from '../../models/User';
21 20
22import { sleep } from '../../helpers/async-helpers'; 21import { sleep } from '../../helpers/async-helpers';
23 22
24import { SERVER_NOT_LOADED } from '../../config'; 23import { SERVER_NOT_LOADED } from '../../config';
25import { osArch, osPlatform } from '../../environment'; 24import { userDataRecipesPath, userDataPath } from '../../environment-remote';
26import { userDataRecipesPath, userDataPath, ferdiVersion } from '../../environment-remote';
27import { asarRecipesPath } from '../../helpers/asar-helpers'; 25import { asarRecipesPath } from '../../helpers/asar-helpers';
28import apiBase from '../apiBase'; 26import apiBase from '../apiBase';
29import { prepareAuthRequest, sendAuthRequest } from '../utils/auth'; 27import { prepareAuthRequest, sendAuthRequest } from '../utils/auth';
@@ -442,25 +440,6 @@ export default class ServerApi {
442 } 440 }
443 } 441 }
444 442
445 // News
446 async getLatestNews() {
447 const url = `${apiBase(
448 true,
449 )}/news?platform=${osPlatform}&arch=${osArch}&version=${ferdiVersion}`;
450 const request = await sendAuthRequest(url);
451 if (!request.ok) throw request;
452 const data = await request.json();
453 const news = this._mapNewsModels(data);
454 debug('ServerApi::getLatestNews resolves', news);
455 return news;
456 }
457
458 async hideNews(id) {
459 const request = await sendAuthRequest(`${apiBase()}/news/${id}/read`);
460 if (!request.ok) throw request;
461 debug('ServerApi::hideNews resolves', id);
462 }
463
464 // Health Check 443 // Health Check
465 async healthCheck() { 444 async healthCheck() {
466 if (apiBase() === SERVER_NOT_LOADED) { 445 if (apiBase() === SERVER_NOT_LOADED) {
@@ -587,19 +566,6 @@ export default class ServerApi {
587 .filter(recipe => recipe !== null); 566 .filter(recipe => recipe !== null);
588 } 567 }
589 568
590 _mapNewsModels(news) {
591 return news
592 .map(newsItem => {
593 try {
594 return new NewsModel(newsItem);
595 } catch (error) {
596 console.error(error);
597 return null;
598 }
599 })
600 .filter(newsItem => newsItem !== null);
601 }
602
603 _getDevRecipes() { 569 _getDevRecipes() {
604 const recipesDirectory = getDevRecipeDirectory(); 570 const recipesDirectory = getDevRecipeDirectory();
605 try { 571 try {
diff --git a/src/components/layout/AppLayout.js b/src/components/layout/AppLayout.js
index 9c1dbf139..4bacc547b 100644
--- a/src/components/layout/AppLayout.js
+++ b/src/components/layout/AppLayout.js
@@ -1,6 +1,6 @@
1import { Component } from 'react'; 1import { Component } from 'react';
2import PropTypes from 'prop-types'; 2import PropTypes from 'prop-types';
3import { observer, PropTypes as MobxPropTypes } from 'mobx-react'; 3import { observer } from 'mobx-react';
4import { defineMessages, injectIntl } from 'react-intl'; 4import { defineMessages, injectIntl } from 'react-intl';
5import { TitleBar } from 'electron-react-titlebar/renderer'; 5import { TitleBar } from 'electron-react-titlebar/renderer';
6import injectSheet from 'react-jss'; 6import injectSheet from 'react-jss';
@@ -20,10 +20,6 @@ import { workspaceStore } from '../../features/workspaces';
20import AppUpdateInfoBar from '../AppUpdateInfoBar'; 20import AppUpdateInfoBar from '../AppUpdateInfoBar';
21import Todos from '../../features/todos/containers/TodosScreen'; 21import Todos from '../../features/todos/containers/TodosScreen';
22 22
23function createMarkup(HTMLString) {
24 return { __html: HTMLString };
25}
26
27const messages = defineMessages({ 23const messages = defineMessages({
28 servicesUpdated: { 24 servicesUpdated: {
29 id: 'infobar.servicesUpdated', 25 id: 'infobar.servicesUpdated',
@@ -73,11 +69,9 @@ class AppLayout extends Component {
73 workspacesDrawer: PropTypes.element.isRequired, 69 workspacesDrawer: PropTypes.element.isRequired,
74 services: PropTypes.element.isRequired, 70 services: PropTypes.element.isRequired,
75 children: PropTypes.element, 71 children: PropTypes.element,
76 news: MobxPropTypes.arrayOrObservableArray.isRequired,
77 showServicesUpdatedInfoBar: PropTypes.bool.isRequired, 72 showServicesUpdatedInfoBar: PropTypes.bool.isRequired,
78 appUpdateIsDownloaded: PropTypes.bool.isRequired, 73 appUpdateIsDownloaded: PropTypes.bool.isRequired,
79 authRequestFailed: PropTypes.bool.isRequired, 74 authRequestFailed: PropTypes.bool.isRequired,
80 removeNewsItem: PropTypes.func.isRequired,
81 reloadServicesAfterUpdate: PropTypes.func.isRequired, 75 reloadServicesAfterUpdate: PropTypes.func.isRequired,
82 installAppUpdate: PropTypes.func.isRequired, 76 installAppUpdate: PropTypes.func.isRequired,
83 showRequiredRequestsError: PropTypes.bool.isRequired, 77 showRequiredRequestsError: PropTypes.bool.isRequired,
@@ -103,11 +97,9 @@ class AppLayout extends Component {
103 sidebar, 97 sidebar,
104 services, 98 services,
105 children, 99 children,
106 news,
107 showServicesUpdatedInfoBar, 100 showServicesUpdatedInfoBar,
108 appUpdateIsDownloaded, 101 appUpdateIsDownloaded,
109 authRequestFailed, 102 authRequestFailed,
110 removeNewsItem,
111 reloadServicesAfterUpdate, 103 reloadServicesAfterUpdate,
112 installAppUpdate, 104 installAppUpdate,
113 showRequiredRequestsError, 105 showRequiredRequestsError,
@@ -132,26 +124,6 @@ class AppLayout extends Component {
132 {sidebar} 124 {sidebar}
133 <div className="app__service"> 125 <div className="app__service">
134 <WorkspaceSwitchingIndicator /> 126 <WorkspaceSwitchingIndicator />
135 {news.length > 0 &&
136 news.map(item => (
137 <InfoBar
138 key={item.id}
139 position="top"
140 type={item.type}
141 sticky={item.sticky}
142 onHide={() => removeNewsItem({ newsId: item.id })}
143 >
144 <span
145 dangerouslySetInnerHTML={createMarkup(item.message)}
146 onClick={event => {
147 const { target } = event;
148 if (target && target.hasAttribute('data-is-news-cta')) {
149 removeNewsItem({ newsId: item.id });
150 }
151 }}
152 />
153 </InfoBar>
154 ))}
155 {!areRequiredRequestsSuccessful && showRequiredRequestsError && ( 127 {!areRequiredRequestsSuccessful && showRequiredRequestsError && (
156 <InfoBar 128 <InfoBar
157 type="danger" 129 type="danger"
@@ -176,19 +148,22 @@ class AppLayout extends Component {
176 {intl.formatMessage(messages.authRequestFailed)} 148 {intl.formatMessage(messages.authRequestFailed)}
177 </InfoBar> 149 </InfoBar>
178 )} 150 )}
179 {showServicesUpdatedInfoBar && this.state.shouldShowServicesUpdatedInfoBar && ( 151 {showServicesUpdatedInfoBar &&
180 <InfoBar 152 this.state.shouldShowServicesUpdatedInfoBar && (
181 type="primary" 153 <InfoBar
182 ctaLabel={intl.formatMessage(messages.buttonReloadServices)} 154 type="primary"
183 onClick={reloadServicesAfterUpdate} 155 ctaLabel={intl.formatMessage(messages.buttonReloadServices)}
184 onHide={() => { 156 onClick={reloadServicesAfterUpdate}
185 this.setState({ shouldShowServicesUpdatedInfoBar: false }); 157 onHide={() => {
186 }} 158 this.setState({
187 > 159 shouldShowServicesUpdatedInfoBar: false,
188 <span className="mdi mdi-power-plug" /> 160 });
189 {intl.formatMessage(messages.servicesUpdated)} 161 }}
190 </InfoBar> 162 >
191 )} 163 <span className="mdi mdi-power-plug" />
164 {intl.formatMessage(messages.servicesUpdated)}
165 </InfoBar>
166 )}
192 {appUpdateIsDownloaded && this.state.shouldShowAppUpdateInfoBar && ( 167 {appUpdateIsDownloaded && this.state.shouldShowAppUpdateInfoBar && (
193 <AppUpdateInfoBar 168 <AppUpdateInfoBar
194 onInstallUpdate={installAppUpdate} 169 onInstallUpdate={installAppUpdate}
diff --git a/src/containers/layout/AppLayoutContainer.js b/src/containers/layout/AppLayoutContainer.js
index ae4cc8b63..0d566525d 100644
--- a/src/containers/layout/AppLayoutContainer.js
+++ b/src/containers/layout/AppLayoutContainer.js
@@ -8,7 +8,6 @@ import RecipesStore from '../../stores/RecipesStore';
8import ServicesStore from '../../stores/ServicesStore'; 8import ServicesStore from '../../stores/ServicesStore';
9import FeaturesStore from '../../stores/FeaturesStore'; 9import FeaturesStore from '../../stores/FeaturesStore';
10import UIStore from '../../stores/UIStore'; 10import UIStore from '../../stores/UIStore';
11import NewsStore from '../../stores/NewsStore';
12import SettingsStore from '../../stores/SettingsStore'; 11import SettingsStore from '../../stores/SettingsStore';
13import UserStore from '../../stores/UserStore'; 12import UserStore from '../../stores/UserStore';
14import RequestStore from '../../stores/RequestStore'; 13import RequestStore from '../../stores/RequestStore';
@@ -38,7 +37,6 @@ class AppLayoutContainer extends Component {
38 features, 37 features,
39 services, 38 services,
40 ui, 39 ui,
41 news,
42 settings, 40 settings,
43 globalError, 41 globalError,
44 requests, 42 requests,
@@ -63,8 +61,6 @@ class AppLayoutContainer extends Component {
63 awake, 61 awake,
64 } = this.props.actions.service; 62 } = this.props.actions.service;
65 63
66 const { hide } = this.props.actions.news;
67
68 const { retryRequiredRequests } = this.props.actions.requests; 64 const { retryRequiredRequests } = this.props.actions.requests;
69 65
70 const { installUpdate, toggleMuteApp } = this.props.actions.app; 66 const { installUpdate, toggleMuteApp } = this.props.actions.app;
@@ -95,10 +91,11 @@ class AppLayoutContainer extends Component {
95 91
96 const workspacesDrawer = ( 92 const workspacesDrawer = (
97 <WorkspaceDrawer 93 <WorkspaceDrawer
94 // eslint-disable-next-line no-confusing-arrow
98 getServicesForWorkspace={workspace => 95 getServicesForWorkspace={workspace =>
99 (workspace 96 workspace
100 ? workspaceStore.getWorkspaceServices(workspace).map(s => s.name) 97 ? workspaceStore.getWorkspaceServices(workspace).map(s => s.name)
101 : services.all.map(s => s.name)) 98 : services.all.map(s => s.name)
102 } 99 }
103 /> 100 />
104 ); 101 );
@@ -158,8 +155,6 @@ class AppLayoutContainer extends Component {
158 sidebar={sidebar} 155 sidebar={sidebar}
159 workspacesDrawer={workspacesDrawer} 156 workspacesDrawer={workspacesDrawer}
160 services={servicesContainer} 157 services={servicesContainer}
161 news={news.latest}
162 removeNewsItem={hide}
163 reloadServicesAfterUpdate={() => window.location.reload()} 158 reloadServicesAfterUpdate={() => window.location.reload()}
164 installAppUpdate={installUpdate} 159 installAppUpdate={installUpdate}
165 globalError={globalError.error} 160 globalError={globalError.error}
@@ -182,7 +177,6 @@ AppLayoutContainer.wrappedComponent.propTypes = {
182 recipes: PropTypes.instanceOf(RecipesStore).isRequired, 177 recipes: PropTypes.instanceOf(RecipesStore).isRequired,
183 app: PropTypes.instanceOf(AppStore).isRequired, 178 app: PropTypes.instanceOf(AppStore).isRequired,
184 ui: PropTypes.instanceOf(UIStore).isRequired, 179 ui: PropTypes.instanceOf(UIStore).isRequired,
185 news: PropTypes.instanceOf(NewsStore).isRequired,
186 settings: PropTypes.instanceOf(SettingsStore).isRequired, 180 settings: PropTypes.instanceOf(SettingsStore).isRequired,
187 user: PropTypes.instanceOf(UserStore).isRequired, 181 user: PropTypes.instanceOf(UserStore).isRequired,
188 requests: PropTypes.instanceOf(RequestStore).isRequired, 182 requests: PropTypes.instanceOf(RequestStore).isRequired,
@@ -191,7 +185,6 @@ AppLayoutContainer.wrappedComponent.propTypes = {
191 }).isRequired, 185 }).isRequired,
192 actions: PropTypes.shape({ 186 actions: PropTypes.shape({
193 service: PropTypes.instanceOf(ServicesStore).isRequired, 187 service: PropTypes.instanceOf(ServicesStore).isRequired,
194 news: PropTypes.instanceOf(NewsStore).isRequired,
195 ui: PropTypes.instanceOf(UIStore).isRequired, 188 ui: PropTypes.instanceOf(UIStore).isRequired,
196 app: PropTypes.instanceOf(AppStore).isRequired, 189 app: PropTypes.instanceOf(AppStore).isRequired,
197 requests: PropTypes.instanceOf(RequestStore).isRequired, 190 requests: PropTypes.instanceOf(RequestStore).isRequired,
diff --git a/src/environment.ts b/src/environment.ts
index 6b68ef432..9b727a607 100644
--- a/src/environment.ts
+++ b/src/environment.ts
@@ -1,6 +1,6 @@
1// Note: This file has now become devoid of all references to values deduced from the remote process - all those now live in the `environment-remote.js` file 1// Note: This file has now become devoid of all references to values deduced from the remote process - all those now live in the `environment-remote.js` file
2 2
3import { platform, arch, release } from 'os'; 3import { arch, release } from 'os';
4 4
5export const isMac = process.platform === 'darwin'; 5export const isMac = process.platform === 'darwin';
6export const isWindows = process.platform === 'win32'; 6export const isWindows = process.platform === 'win32';
@@ -10,7 +10,6 @@ export const electronVersion = process.versions.electron;
10export const chromeVersion = process.versions.chrome; 10export const chromeVersion = process.versions.chrome;
11export const nodeVersion = process.versions.node; 11export const nodeVersion = process.versions.node;
12 12
13export const osPlatform = platform();
14export const osArch = arch(); 13export const osArch = arch();
15export const osRelease = release(); 14export const osRelease = release();
16export const is64Bit = osArch.match(/64/); 15export const is64Bit = osArch.match(/64/);
diff --git a/src/internal-server/start/routes.js b/src/internal-server/start/routes.js
index db74479c9..50b9448cf 100644
--- a/src/internal-server/start/routes.js
+++ b/src/internal-server/start/routes.js
@@ -66,7 +66,6 @@ Route.group(() => {
66 // Static responses 66 // Static responses
67 Route.get('features/:mode?', 'StaticController.features'); 67 Route.get('features/:mode?', 'StaticController.features');
68 Route.get('services', 'StaticController.emptyArray'); 68 Route.get('services', 'StaticController.emptyArray');
69 Route.get('news', 'StaticController.emptyArray');
70}) 69})
71 .prefix(API_VERSION) 70 .prefix(API_VERSION)
72 .middleware(OnlyAllowFerdi); 71 .middleware(OnlyAllowFerdi);
diff --git a/src/models/News.ts b/src/models/News.ts
deleted file mode 100644
index 4fc21f590..000000000
--- a/src/models/News.ts
+++ /dev/null
@@ -1,33 +0,0 @@
1import { ifUndefinedString, ifUndefinedBoolean } from '../jsUtils';
2
3interface INews {
4 id: string;
5 message: string;
6 type: string;
7 sticky: boolean | undefined;
8}
9
10export default class News {
11 id: string = '';
12
13 message: string = '';
14
15 type: string = 'primary';
16
17 sticky: boolean = false;
18
19 constructor(data: INews) {
20 if (!data) {
21 throw new Error('News config not valid');
22 }
23
24 if (!data.id) {
25 throw new Error('News requires Id');
26 }
27
28 this.id = data.id;
29 this.message = ifUndefinedString(data.message, this.message);
30 this.type = ifUndefinedString(data.type, this.type);
31 this.sticky = ifUndefinedBoolean(data.sticky, this.sticky);
32 }
33}
diff --git a/src/stores.types.ts b/src/stores.types.ts
index 66c8e9b85..dd879179d 100644
--- a/src/stores.types.ts
+++ b/src/stores.types.ts
@@ -3,7 +3,6 @@ export interface FerdiStores {
3 communityRecipes: CommunityRecipesStore; 3 communityRecipes: CommunityRecipesStore;
4 features: FeaturesStore; 4 features: FeaturesStore;
5 globalError: GlobalErrorStore; 5 globalError: GlobalErrorStore;
6 news: NewsStore;
7 recipePreviews: RecipePreviewsStore; 6 recipePreviews: RecipePreviewsStore;
8 recipes: RecipeStore; 7 recipes: RecipeStore;
9 requests: RequestsStore; 8 requests: RequestsStore;
@@ -21,7 +20,6 @@ interface Stores {
21 communityRecipes: CommunityRecipesStore; 20 communityRecipes: CommunityRecipesStore;
22 features: FeaturesStore; 21 features: FeaturesStore;
23 globalError: GlobalErrorStore; 22 globalError: GlobalErrorStore;
24 news: NewsStore;
25 recipePreviews: RecipePreviewsStore; 23 recipePreviews: RecipePreviewsStore;
26 recipes: RecipeStore; 24 recipes: RecipeStore;
27 requests: RequestsStore; 25 requests: RequestsStore;
@@ -36,7 +34,6 @@ interface Stores {
36 34
37interface Actions { 35interface Actions {
38 app: AppStore; 36 app: AppStore;
39 news: NewsStore;
40 recipePreviews: RecipePreviewsStore; 37 recipePreviews: RecipePreviewsStore;
41 recipes: RecipeStore; 38 recipes: RecipeStore;
42 requests: RequestsStore; 39 requests: RequestsStore;
@@ -52,7 +49,6 @@ interface Api {
52 app: AppStore; 49 app: AppStore;
53 features: FeaturesStore; 50 features: FeaturesStore;
54 local: {}; 51 local: {};
55 news: NewsStore;
56 recipePreviews: RecipePreviewsStore; 52 recipePreviews: RecipePreviewsStore;
57 recipes: RecipeStore; 53 recipes: RecipeStore;
58 services: ServicesStore; 54 services: ServicesStore;
@@ -130,18 +126,6 @@ interface GlobalErrorStore {
130 actionStatus: () => void; 126 actionStatus: () => void;
131} 127}
132 128
133interface NewsStore {
134 actions: Actions;
135 api: Api;
136 hideNewsRequest: () => void;
137 latestNewsRequest: () => void;
138 stores: Stores;
139 _reactions: [];
140 _status: () => void;
141 actionStatus: () => void;
142 latest: () => void;
143}
144
145interface RecipePreviewsStore { 129interface RecipePreviewsStore {
146 actions: Actions; 130 actions: Actions;
147 allRecipePreviewsRequest: () => void; 131 allRecipePreviewsRequest: () => void;
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js
index a86a54c6d..81cef3775 100644
--- a/src/stores/AppStore.js
+++ b/src/stores/AppStore.js
@@ -153,9 +153,6 @@ export default class AppStore extends Store {
153 this.stores.features.featuresRequest.invalidate({ 153 this.stores.features.featuresRequest.invalidate({
154 immediately: true, 154 immediately: true,
155 }); 155 });
156 this.stores.news.latestNewsRequest.invalidate({
157 immediately: true,
158 });
159 }, ms('60m')); 156 }, ms('60m'));
160 157
161 // Check for updates once every 4 hours 158 // Check for updates once every 4 hours
diff --git a/src/stores/NewsStore.js b/src/stores/NewsStore.js
deleted file mode 100644
index 66a17cb29..000000000
--- a/src/stores/NewsStore.js
+++ /dev/null
@@ -1,55 +0,0 @@
1import { computed, observable } from 'mobx';
2import { remove } from 'lodash';
3
4import Store from './lib/Store';
5import CachedRequest from './lib/CachedRequest';
6import Request from './lib/Request';
7import { CHECK_INTERVAL } from '../config';
8
9export default class NewsStore extends Store {
10 @observable latestNewsRequest = new CachedRequest(this.api.news, 'latest');
11
12 @observable hideNewsRequest = new Request(this.api.news, 'hide');
13
14 constructor(...args) {
15 super(...args);
16
17 // Register action handlers
18 this.actions.news.hide.listen(this._hide.bind(this));
19 this.actions.user.logout.listen(this._resetNewsRequest.bind(this));
20 }
21
22 setup() {
23 // Check for news updates every couple of hours
24 setInterval(() => {
25 if (this.latestNewsRequest.wasExecuted && this.stores.user.isLoggedIn) {
26 this.latestNewsRequest.invalidate({ immediately: true });
27 }
28 }, CHECK_INTERVAL);
29 }
30
31 @computed get latest() {
32 return this.latestNewsRequest.execute().result || [];
33 }
34
35 // Actions
36 _hide({ newsId }) {
37 this.hideNewsRequest.execute(newsId);
38
39 this.latestNewsRequest.invalidate().patch((result) => {
40 // TODO: check if we can use mobx.array remove
41 remove(result, (n) => n.id === newsId);
42 });
43 }
44
45 /**
46 * Reset the news request when current user logs out so that when another user
47 * logs in again without an app restart, the request will be fetched again and
48 * the news will be shown to the user.
49 *
50 * @private
51 */
52 _resetNewsRequest() {
53 this.latestNewsRequest.reset();
54 }
55}
diff --git a/src/stores/index.ts b/src/stores/index.ts
index 1760ddfa2..6ad898d85 100644
--- a/src/stores/index.ts
+++ b/src/stores/index.ts
@@ -6,7 +6,6 @@ import ServicesStore from './ServicesStore';
6import RecipesStore from './RecipesStore'; 6import RecipesStore from './RecipesStore';
7import RecipePreviewsStore from './RecipePreviewsStore'; 7import RecipePreviewsStore from './RecipePreviewsStore';
8import UIStore from './UIStore'; 8import UIStore from './UIStore';
9import NewsStore from './NewsStore';
10import RequestStore from './RequestStore'; 9import RequestStore from './RequestStore';
11import GlobalErrorStore from './GlobalErrorStore'; 10import GlobalErrorStore from './GlobalErrorStore';
12import { workspaceStore } from '../features/workspaces'; 11import { workspaceStore } from '../features/workspaces';
@@ -25,7 +24,6 @@ export default (api, actions, router) => {
25 recipes: new RecipesStore(stores, api, actions), 24 recipes: new RecipesStore(stores, api, actions),
26 recipePreviews: new RecipePreviewsStore(stores, api, actions), 25 recipePreviews: new RecipePreviewsStore(stores, api, actions),
27 ui: new UIStore(stores, api, actions), 26 ui: new UIStore(stores, api, actions),
28 news: new NewsStore(stores, api, actions),
29 requests: new RequestStore(stores, api, actions), 27 requests: new RequestStore(stores, api, actions),
30 globalError: new GlobalErrorStore(stores, api, actions), 28 globalError: new GlobalErrorStore(stores, api, actions),
31 workspaces: workspaceStore, 29 workspaces: workspaceStore,