diff options
author | Stefan Malzner <stefan@adlk.io> | 2018-01-04 10:17:48 +0100 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-01-04 10:17:48 +0100 |
commit | d375d08684a457ec6a125f2a5d3a73562826ba05 (patch) | |
tree | 6322d2207545464064e24f6bdd2f9724d1e4b813 /src | |
parent | Merge pull request #533 from meetfranz/feature/ux-service-search (diff) | |
parent | Merge branch 'service-cache-cleanup' of https://github.com/dannyqiu/franz int... (diff) | |
download | ferdium-app-d375d08684a457ec6a125f2a5d3a73562826ba05.tar.gz ferdium-app-d375d08684a457ec6a125f2a5d3a73562826ba05.tar.zst ferdium-app-d375d08684a457ec6a125f2a5d3a73562826ba05.zip |
Merge pull request #517 from dannyqiu/service-cache-cleanup
Service cache cleanup
Diffstat (limited to 'src')
-rw-r--r-- | src/actions/app.js | 1 | ||||
-rw-r--r-- | src/actions/service.js | 3 | ||||
-rw-r--r-- | src/api/LocalApi.js | 8 | ||||
-rw-r--r-- | src/api/ServicesApi.js | 7 | ||||
-rw-r--r-- | src/api/server/LocalApi.js | 34 | ||||
-rw-r--r-- | src/api/server/ServerApi.js | 6 | ||||
-rw-r--r-- | src/components/settings/settings/EditSettingsForm.js | 38 | ||||
-rw-r--r-- | src/containers/settings/EditSettingsScreen.js | 17 | ||||
-rw-r--r-- | src/electron/ipc-api/autoUpdate.js | 3 | ||||
-rw-r--r-- | src/helpers/service-helpers.js | 20 | ||||
-rw-r--r-- | src/i18n/locales/en-US.json | 3 | ||||
-rw-r--r-- | src/index.js | 1 | ||||
-rw-r--r-- | src/stores/AppStore.js | 32 | ||||
-rw-r--r-- | src/stores/ServicesStore.js | 9 | ||||
-rw-r--r-- | src/styles/button.scss | 12 |
15 files changed, 189 insertions, 5 deletions
diff --git a/src/actions/app.js b/src/actions/app.js index e4f648fc9..e6f7f22ba 100644 --- a/src/actions/app.js +++ b/src/actions/app.js | |||
@@ -25,4 +25,5 @@ export default { | |||
25 | overrideSystemMute: PropTypes.bool, | 25 | overrideSystemMute: PropTypes.bool, |
26 | }, | 26 | }, |
27 | toggleMuteApp: {}, | 27 | toggleMuteApp: {}, |
28 | clearAllCache: {}, | ||
28 | }; | 29 | }; |
diff --git a/src/actions/service.js b/src/actions/service.js index e3100e986..5d483b12a 100644 --- a/src/actions/service.js +++ b/src/actions/service.js | |||
@@ -25,6 +25,9 @@ export default { | |||
25 | serviceId: PropTypes.string.isRequired, | 25 | serviceId: PropTypes.string.isRequired, |
26 | redirect: PropTypes.string, | 26 | redirect: PropTypes.string, |
27 | }, | 27 | }, |
28 | clearCache: { | ||
29 | serviceId: PropTypes.string.isRequired, | ||
30 | }, | ||
28 | setUnreadMessageCount: { | 31 | setUnreadMessageCount: { |
29 | serviceId: PropTypes.string.isRequired, | 32 | serviceId: PropTypes.string.isRequired, |
30 | count: PropTypes.object.isRequired, | 33 | count: PropTypes.object.isRequired, |
diff --git a/src/api/LocalApi.js b/src/api/LocalApi.js index 6f2b049d6..3f84f8a0b 100644 --- a/src/api/LocalApi.js +++ b/src/api/LocalApi.js | |||
@@ -15,4 +15,12 @@ export default class LocalApi { | |||
15 | removeKey(key) { | 15 | removeKey(key) { |
16 | return this.local.removeKey(key); | 16 | return this.local.removeKey(key); |
17 | } | 17 | } |
18 | |||
19 | getAppCacheSize() { | ||
20 | return this.local.getAppCacheSize(); | ||
21 | } | ||
22 | |||
23 | clearAppCache() { | ||
24 | return this.local.clearAppCache(); | ||
25 | } | ||
18 | } | 26 | } |
diff --git a/src/api/ServicesApi.js b/src/api/ServicesApi.js index 3cb40ba0d..36ed9482f 100644 --- a/src/api/ServicesApi.js +++ b/src/api/ServicesApi.js | |||
@@ -1,5 +1,6 @@ | |||
1 | export default class ServicesApi { | 1 | export default class ServicesApi { |
2 | constructor(server) { | 2 | constructor(server, local) { |
3 | this.local = local; | ||
3 | this.server = server; | 4 | this.server = server; |
4 | } | 5 | } |
5 | 6 | ||
@@ -30,4 +31,8 @@ export default class ServicesApi { | |||
30 | reorder(data) { | 31 | reorder(data) { |
31 | return this.server.reorderService(data); | 32 | return this.server.reorderService(data); |
32 | } | 33 | } |
34 | |||
35 | clearCache(serviceId) { | ||
36 | return this.local.clearCache(serviceId); | ||
37 | } | ||
33 | } | 38 | } |
diff --git a/src/api/server/LocalApi.js b/src/api/server/LocalApi.js index 79ac6e12f..e95d750ac 100644 --- a/src/api/server/LocalApi.js +++ b/src/api/server/LocalApi.js | |||
@@ -1,3 +1,10 @@ | |||
1 | import { remote } from 'electron'; | ||
2 | import du from 'du'; | ||
3 | |||
4 | import { getServicePartitionsDirectory } from '../../helpers/service-helpers.js'; | ||
5 | |||
6 | const { session } = remote; | ||
7 | |||
1 | export default class LocalApi { | 8 | export default class LocalApi { |
2 | // App | 9 | // App |
3 | async updateAppSettings(data) { | 10 | async updateAppSettings(data) { |
@@ -30,4 +37,31 @@ export default class LocalApi { | |||
30 | localStorage.setItem('app', JSON.stringify(settings)); | 37 | localStorage.setItem('app', JSON.stringify(settings)); |
31 | } | 38 | } |
32 | } | 39 | } |
40 | |||
41 | // Services | ||
42 | async getAppCacheSize() { | ||
43 | const partitionsDir = getServicePartitionsDirectory(); | ||
44 | return new Promise((resolve, reject) => { | ||
45 | du(partitionsDir, (err, size) => { | ||
46 | if (err) reject(err); | ||
47 | |||
48 | console.debug('LocalApi::getAppCacheSize resolves', size); | ||
49 | resolve(size); | ||
50 | }); | ||
51 | }); | ||
52 | } | ||
53 | |||
54 | async clearCache(serviceId) { | ||
55 | const s = session.fromPartition(`persist:service-${serviceId}`); | ||
56 | |||
57 | console.debug('LocalApi::clearCache resolves', serviceId); | ||
58 | return new Promise(resolve => s.clearCache(resolve)); | ||
59 | } | ||
60 | |||
61 | async clearAppCache() { | ||
62 | const s = session.defaultSession; | ||
63 | |||
64 | console.debug('LocalApi::clearCache clearAppCache'); | ||
65 | return new Promise(resolve => s.clearCache(resolve)); | ||
66 | } | ||
33 | } | 67 | } |
diff --git a/src/api/server/ServerApi.js b/src/api/server/ServerApi.js index 8b3136d27..d75d2e559 100644 --- a/src/api/server/ServerApi.js +++ b/src/api/server/ServerApi.js | |||
@@ -22,6 +22,10 @@ import { | |||
22 | loadRecipeConfig, | 22 | loadRecipeConfig, |
23 | } from '../../helpers/recipe-helpers'; | 23 | } from '../../helpers/recipe-helpers'; |
24 | 24 | ||
25 | import { | ||
26 | removeServicePartitionDirectory, | ||
27 | } from '../../helpers/service-helpers.js'; | ||
28 | |||
25 | module.paths.unshift( | 29 | module.paths.unshift( |
26 | getDevRecipeDirectory(), | 30 | getDevRecipeDirectory(), |
27 | getRecipeDirectory(), | 31 | getRecipeDirectory(), |
@@ -210,6 +214,8 @@ export default class ServerApi { | |||
210 | } | 214 | } |
211 | const data = await request.json(); | 215 | const data = await request.json(); |
212 | 216 | ||
217 | removeServicePartitionDirectory(id, true); | ||
218 | |||
213 | console.debug('ServerApi::deleteService resolves', data); | 219 | console.debug('ServerApi::deleteService resolves', data); |
214 | return data; | 220 | return data; |
215 | } | 221 | } |
diff --git a/src/components/settings/settings/EditSettingsForm.js b/src/components/settings/settings/EditSettingsForm.js index ff398aa33..72aa5a8af 100644 --- a/src/components/settings/settings/EditSettingsForm.js +++ b/src/components/settings/settings/EditSettingsForm.js | |||
@@ -40,6 +40,18 @@ const messages = defineMessages({ | |||
40 | id: 'settings.app.translationHelp', | 40 | id: 'settings.app.translationHelp', |
41 | defaultMessage: '!!!Help us to translate Franz into your language.', | 41 | defaultMessage: '!!!Help us to translate Franz into your language.', |
42 | }, | 42 | }, |
43 | subheadlineCache: { | ||
44 | id: 'settings.app.subheadlineCache', | ||
45 | defaultMessage: '!!!Cache', | ||
46 | }, | ||
47 | cacheInfo: { | ||
48 | id: 'settings.app.cacheInfo', | ||
49 | defaultMessage: '!!!Franz cache is currently using {size} of disk space.', | ||
50 | }, | ||
51 | buttonClearAllCache: { | ||
52 | id: 'settings.app.buttonClearAllCache', | ||
53 | defaultMessage: '!!!Clear cache', | ||
54 | }, | ||
43 | buttonSearchForUpdate: { | 55 | buttonSearchForUpdate: { |
44 | id: 'settings.app.buttonSearchForUpdate', | 56 | id: 'settings.app.buttonSearchForUpdate', |
45 | defaultMessage: '!!!Check for updates', | 57 | defaultMessage: '!!!Check for updates', |
@@ -77,6 +89,9 @@ export default class EditSettingsForm extends Component { | |||
77 | isUpdateAvailable: PropTypes.bool.isRequired, | 89 | isUpdateAvailable: PropTypes.bool.isRequired, |
78 | noUpdateAvailable: PropTypes.bool.isRequired, | 90 | noUpdateAvailable: PropTypes.bool.isRequired, |
79 | updateIsReadyToInstall: PropTypes.bool.isRequired, | 91 | updateIsReadyToInstall: PropTypes.bool.isRequired, |
92 | isClearingAllCache: PropTypes.bool.isRequired, | ||
93 | onClearAllCache: PropTypes.func.isRequired, | ||
94 | cacheSize: PropTypes.string.isRequired, | ||
80 | }; | 95 | }; |
81 | 96 | ||
82 | static contextTypes = { | 97 | static contextTypes = { |
@@ -103,6 +118,9 @@ export default class EditSettingsForm extends Component { | |||
103 | isUpdateAvailable, | 118 | isUpdateAvailable, |
104 | noUpdateAvailable, | 119 | noUpdateAvailable, |
105 | updateIsReadyToInstall, | 120 | updateIsReadyToInstall, |
121 | isClearingAllCache, | ||
122 | onClearAllCache, | ||
123 | cacheSize, | ||
106 | } = this.props; | 124 | } = this.props; |
107 | const { intl } = this.context; | 125 | const { intl } = this.context; |
108 | 126 | ||
@@ -155,6 +173,25 @@ export default class EditSettingsForm extends Component { | |||
155 | <h2 id="advanced">{intl.formatMessage(messages.headlineAdvanced)}</h2> | 173 | <h2 id="advanced">{intl.formatMessage(messages.headlineAdvanced)}</h2> |
156 | <Toggle field={form.$('enableSpellchecking')} /> | 174 | <Toggle field={form.$('enableSpellchecking')} /> |
157 | {/* <Select field={form.$('spellcheckingLanguage')} /> */} | 175 | {/* <Select field={form.$('spellcheckingLanguage')} /> */} |
176 | <div className="settings__settings-group"> | ||
177 | <h3> | ||
178 | {intl.formatMessage(messages.subheadlineCache)} | ||
179 | </h3> | ||
180 | <p> | ||
181 | {intl.formatMessage(messages.cacheInfo, { | ||
182 | size: cacheSize, | ||
183 | })} | ||
184 | </p> | ||
185 | <p> | ||
186 | <Button | ||
187 | buttonType="secondary" | ||
188 | label={intl.formatMessage(messages.buttonClearAllCache)} | ||
189 | onClick={onClearAllCache} | ||
190 | disabled={isClearingAllCache} | ||
191 | loaded={!isClearingAllCache} | ||
192 | /> | ||
193 | </p> | ||
194 | </div> | ||
158 | 195 | ||
159 | {/* Updates */} | 196 | {/* Updates */} |
160 | <h2 id="updates">{intl.formatMessage(messages.headlineUpdates)}</h2> | 197 | <h2 id="updates">{intl.formatMessage(messages.headlineUpdates)}</h2> |
@@ -165,6 +202,7 @@ export default class EditSettingsForm extends Component { | |||
165 | /> | 202 | /> |
166 | ) : ( | 203 | ) : ( |
167 | <Button | 204 | <Button |
205 | buttonType="secondary" | ||
168 | label={intl.formatMessage(updateButtonLabelMessage)} | 206 | label={intl.formatMessage(updateButtonLabelMessage)} |
169 | onClick={checkForUpdates} | 207 | onClick={checkForUpdates} |
170 | disabled={isCheckingForUpdates || isUpdateAvailable} | 208 | disabled={isCheckingForUpdates || isUpdateAvailable} |
diff --git a/src/containers/settings/EditSettingsScreen.js b/src/containers/settings/EditSettingsScreen.js index 45ded9e5c..9fa815a0a 100644 --- a/src/containers/settings/EditSettingsScreen.js +++ b/src/containers/settings/EditSettingsScreen.js | |||
@@ -193,8 +193,17 @@ export default class EditSettingsScreen extends Component { | |||
193 | } | 193 | } |
194 | 194 | ||
195 | render() { | 195 | render() { |
196 | const { updateStatus, updateStatusTypes } = this.props.stores.app; | 196 | const { |
197 | const { checkForUpdates, installUpdate } = this.props.actions.app; | 197 | updateStatus, |
198 | cacheSize, | ||
199 | updateStatusTypes, | ||
200 | isClearingAllCache, | ||
201 | } = this.props.stores.app; | ||
202 | const { | ||
203 | checkForUpdates, | ||
204 | installUpdate, | ||
205 | clearAllCache, | ||
206 | } = this.props.actions.app; | ||
198 | const form = this.prepareForm(); | 207 | const form = this.prepareForm(); |
199 | 208 | ||
200 | return ( | 209 | return ( |
@@ -207,6 +216,9 @@ export default class EditSettingsScreen extends Component { | |||
207 | noUpdateAvailable={updateStatus === updateStatusTypes.NOT_AVAILABLE} | 216 | noUpdateAvailable={updateStatus === updateStatusTypes.NOT_AVAILABLE} |
208 | updateIsReadyToInstall={updateStatus === updateStatusTypes.DOWNLOADED} | 217 | updateIsReadyToInstall={updateStatus === updateStatusTypes.DOWNLOADED} |
209 | onSubmit={d => this.onSubmit(d)} | 218 | onSubmit={d => this.onSubmit(d)} |
219 | cacheSize={cacheSize} | ||
220 | isClearingAllCache={isClearingAllCache} | ||
221 | onClearAllCache={clearAllCache} | ||
210 | /> | 222 | /> |
211 | ); | 223 | ); |
212 | } | 224 | } |
@@ -223,6 +235,7 @@ EditSettingsScreen.wrappedComponent.propTypes = { | |||
223 | launchOnStartup: PropTypes.func.isRequired, | 235 | launchOnStartup: PropTypes.func.isRequired, |
224 | checkForUpdates: PropTypes.func.isRequired, | 236 | checkForUpdates: PropTypes.func.isRequired, |
225 | installUpdate: PropTypes.func.isRequired, | 237 | installUpdate: PropTypes.func.isRequired, |
238 | clearAllCache: PropTypes.func.isRequired, | ||
226 | }).isRequired, | 239 | }).isRequired, |
227 | settings: PropTypes.shape({ | 240 | settings: PropTypes.shape({ |
228 | update: PropTypes.func.isRequired, | 241 | update: PropTypes.func.isRequired, |
diff --git a/src/electron/ipc-api/autoUpdate.js b/src/electron/ipc-api/autoUpdate.js index 7bc193e2d..ba49a2f97 100644 --- a/src/electron/ipc-api/autoUpdate.js +++ b/src/electron/ipc-api/autoUpdate.js | |||
@@ -1,8 +1,9 @@ | |||
1 | import { app, ipcMain } from 'electron'; | 1 | import { app, ipcMain } from 'electron'; |
2 | import { autoUpdater } from 'electron-updater'; | 2 | import { autoUpdater } from 'electron-updater'; |
3 | import { isDevMode } from '../../environment.js'; | ||
3 | 4 | ||
4 | export default (params) => { | 5 | export default (params) => { |
5 | if (process.platform === 'darwin' || process.platform === 'win32') { | 6 | if (!isDevMode && (process.platform === 'darwin' || process.platform === 'win32')) { |
6 | // autoUpdater.setFeedURL(updateUrl); | 7 | // autoUpdater.setFeedURL(updateUrl); |
7 | ipcMain.on('autoUpdate', (event, args) => { | 8 | ipcMain.on('autoUpdate', (event, args) => { |
8 | try { | 9 | try { |
diff --git a/src/helpers/service-helpers.js b/src/helpers/service-helpers.js new file mode 100644 index 000000000..5f63f6b7c --- /dev/null +++ b/src/helpers/service-helpers.js | |||
@@ -0,0 +1,20 @@ | |||
1 | import path from 'path'; | ||
2 | import { remote } from 'electron'; | ||
3 | import fs from 'fs-extra'; | ||
4 | |||
5 | const app = remote.app; | ||
6 | |||
7 | export function getServicePartitionsDirectory() { | ||
8 | return path.join(app.getPath('userData'), 'Partitions'); | ||
9 | } | ||
10 | |||
11 | export function removeServicePartitionDirectory(id = '', addServicePrefix = false) { | ||
12 | const servicePartition = path.join(getServicePartitionsDirectory(), `${addServicePrefix ? 'service-' : ''}${id}`); | ||
13 | |||
14 | return fs.remove(servicePartition); | ||
15 | } | ||
16 | |||
17 | export async function getServiceIdsFromPartitions() { | ||
18 | const files = await fs.readdir(getServicePartitionsDirectory()); | ||
19 | return files.filter(n => n !== '__chrome_extension'); | ||
20 | } | ||
diff --git a/src/i18n/locales/en-US.json b/src/i18n/locales/en-US.json index da5d4a143..2bfbf2455 100644 --- a/src/i18n/locales/en-US.json +++ b/src/i18n/locales/en-US.json | |||
@@ -150,6 +150,9 @@ | |||
150 | "settings.app.updateStatusSearching": "Is searching for update", | 150 | "settings.app.updateStatusSearching": "Is searching for update", |
151 | "settings.app.updateStatusAvailable": "Update available, downloading...", | 151 | "settings.app.updateStatusAvailable": "Update available, downloading...", |
152 | "settings.app.updateStatusUpToDate": "You are using the latest version of Franz", | 152 | "settings.app.updateStatusUpToDate": "You are using the latest version of Franz", |
153 | "settings.app.subheadlineCache": "Cache", | ||
154 | "settings.app.cacheInfo": "Franz cache is currently using {size} of disk space.", | ||
155 | "settings.app.buttonClearAllCache": "Clear cache", | ||
153 | "settings.app.form.autoLaunchOnStart": "Launch Franz on start", | 156 | "settings.app.form.autoLaunchOnStart": "Launch Franz on start", |
154 | "settings.app.form.autoLaunchInBackground": "Open in background", | 157 | "settings.app.form.autoLaunchInBackground": "Open in background", |
155 | "settings.app.form.enableSystemTray": "Show Franz in system tray", | 158 | "settings.app.form.enableSystemTray": "Show Franz in system tray", |
diff --git a/src/index.js b/src/index.js index a047e2bc1..f82bb3590 100644 --- a/src/index.js +++ b/src/index.js | |||
@@ -44,6 +44,7 @@ const isSecondInstance = app.makeSingleInstance((argv) => { | |||
44 | }); | 44 | }); |
45 | 45 | ||
46 | if (isSecondInstance) { | 46 | if (isSecondInstance) { |
47 | console.log('An instance of Franz is already running. Exiting...'); | ||
47 | app.exit(); | 48 | app.exit(); |
48 | } | 49 | } |
49 | 50 | ||
diff --git a/src/stores/AppStore.js b/src/stores/AppStore.js index aa6e801ff..e33f50f05 100644 --- a/src/stores/AppStore.js +++ b/src/stores/AppStore.js | |||
@@ -1,10 +1,11 @@ | |||
1 | import { remote, ipcRenderer, shell } from 'electron'; | 1 | import { remote, ipcRenderer, shell } from 'electron'; |
2 | import { action, observable } from 'mobx'; | 2 | import { action, computed, observable } from 'mobx'; |
3 | import moment from 'moment'; | 3 | import moment from 'moment'; |
4 | import key from 'keymaster'; | 4 | import key from 'keymaster'; |
5 | import { getDoNotDisturb } from '@meetfranz/electron-notification-state'; | 5 | import { getDoNotDisturb } from '@meetfranz/electron-notification-state'; |
6 | import idleTimer from '@paulcbetts/system-idle-time'; | 6 | import idleTimer from '@paulcbetts/system-idle-time'; |
7 | import AutoLaunch from 'auto-launch'; | 7 | import AutoLaunch from 'auto-launch'; |
8 | import prettyBytes from 'pretty-bytes'; | ||
8 | 9 | ||
9 | import Store from './lib/Store'; | 10 | import Store from './lib/Store'; |
10 | import Request from './lib/Request'; | 11 | import Request from './lib/Request'; |
@@ -14,7 +15,10 @@ import locales from '../i18n/translations'; | |||
14 | import { gaEvent } from '../lib/analytics'; | 15 | import { gaEvent } from '../lib/analytics'; |
15 | import Miner from '../lib/Miner'; | 16 | import Miner from '../lib/Miner'; |
16 | 17 | ||
18 | import { getServiceIdsFromPartitions, removeServicePartitionDirectory } from '../helpers/service-helpers.js'; | ||
19 | |||
17 | const { app } = remote; | 20 | const { app } = remote; |
21 | |||
18 | const defaultLocale = DEFAULT_APP_SETTINGS.locale; | 22 | const defaultLocale = DEFAULT_APP_SETTINGS.locale; |
19 | const autoLauncher = new AutoLaunch({ | 23 | const autoLauncher = new AutoLaunch({ |
20 | name: 'Franz', | 24 | name: 'Franz', |
@@ -30,6 +34,8 @@ export default class AppStore extends Store { | |||
30 | }; | 34 | }; |
31 | 35 | ||
32 | @observable healthCheckRequest = new Request(this.api.app, 'health'); | 36 | @observable healthCheckRequest = new Request(this.api.app, 'health'); |
37 | @observable getAppCacheSizeRequest = new Request(this.api.local, 'getAppCacheSize'); | ||
38 | @observable clearAppCacheRequest = new Request(this.api.local, 'clearAppCache'); | ||
33 | 39 | ||
34 | @observable autoLaunchOnStart = true; | 40 | @observable autoLaunchOnStart = true; |
35 | 41 | ||
@@ -47,6 +53,8 @@ export default class AppStore extends Store { | |||
47 | 53 | ||
48 | @observable isSystemMuteOverridden = false; | 54 | @observable isSystemMuteOverridden = false; |
49 | 55 | ||
56 | @observable isClearingAllCache = false; | ||
57 | |||
50 | constructor(...args) { | 58 | constructor(...args) { |
51 | super(...args); | 59 | super(...args); |
52 | 60 | ||
@@ -61,6 +69,7 @@ export default class AppStore extends Store { | |||
61 | this.actions.app.healthCheck.listen(this._healthCheck.bind(this)); | 69 | this.actions.app.healthCheck.listen(this._healthCheck.bind(this)); |
62 | this.actions.app.muteApp.listen(this._muteApp.bind(this)); | 70 | this.actions.app.muteApp.listen(this._muteApp.bind(this)); |
63 | this.actions.app.toggleMuteApp.listen(this._toggleMuteApp.bind(this)); | 71 | this.actions.app.toggleMuteApp.listen(this._toggleMuteApp.bind(this)); |
72 | this.actions.app.clearAllCache.listen(this._clearAllCache.bind(this)); | ||
64 | 73 | ||
65 | this.registerReactions([ | 74 | this.registerReactions([ |
66 | this._offlineCheck.bind(this), | 75 | this._offlineCheck.bind(this), |
@@ -165,6 +174,10 @@ export default class AppStore extends Store { | |||
165 | this._healthCheck(); | 174 | this._healthCheck(); |
166 | } | 175 | } |
167 | 176 | ||
177 | @computed get cacheSize() { | ||
178 | return prettyBytes(this.getAppCacheSizeRequest.execute().result || 0); | ||
179 | } | ||
180 | |||
168 | // Actions | 181 | // Actions |
169 | @action _notify({ title, options, notificationId, serviceId = null }) { | 182 | @action _notify({ title, options, notificationId, serviceId = null }) { |
170 | if (this.stores.settings.all.isAppMuted) return; | 183 | if (this.stores.settings.all.isAppMuted) return; |
@@ -255,6 +268,23 @@ export default class AppStore extends Store { | |||
255 | this._muteApp({ isMuted: !this.stores.settings.all.isAppMuted }); | 268 | this._muteApp({ isMuted: !this.stores.settings.all.isAppMuted }); |
256 | } | 269 | } |
257 | 270 | ||
271 | @action async _clearAllCache() { | ||
272 | this.isClearingAllCache = true; | ||
273 | const clearAppCache = this.clearAppCacheRequest.execute(); | ||
274 | const allServiceIds = await getServiceIdsFromPartitions(); | ||
275 | const allOrphanedServiceIds = allServiceIds.filter(id => !this.stores.services.all.find(s => id.replace('service-', '') === s.id)); | ||
276 | |||
277 | await Promise.all(allOrphanedServiceIds.map(id => removeServicePartitionDirectory(id))); | ||
278 | |||
279 | await Promise.all(this.stores.services.all.map(s => this.actions.service.clearCache({ serviceId: s.id }))); | ||
280 | |||
281 | await clearAppCache._promise; | ||
282 | |||
283 | this.getAppCacheSizeRequest.execute(); | ||
284 | |||
285 | this.isClearingAllCache = false; | ||
286 | } | ||
287 | |||
258 | // Reactions | 288 | // Reactions |
259 | _offlineCheck() { | 289 | _offlineCheck() { |
260 | if (!this.isOnline) { | 290 | if (!this.isOnline) { |
diff --git a/src/stores/ServicesStore.js b/src/stores/ServicesStore.js index 3abb57d1d..87ee57a0d 100644 --- a/src/stores/ServicesStore.js +++ b/src/stores/ServicesStore.js | |||
@@ -16,6 +16,7 @@ export default class ServicesStore extends Store { | |||
16 | @observable updateServiceRequest = new Request(this.api.services, 'update'); | 16 | @observable updateServiceRequest = new Request(this.api.services, 'update'); |
17 | @observable reorderServicesRequest = new Request(this.api.services, 'reorder'); | 17 | @observable reorderServicesRequest = new Request(this.api.services, 'reorder'); |
18 | @observable deleteServiceRequest = new Request(this.api.services, 'delete'); | 18 | @observable deleteServiceRequest = new Request(this.api.services, 'delete'); |
19 | @observable clearCacheRequest = new Request(this.api.services, 'clearCache'); | ||
19 | 20 | ||
20 | @observable filterNeedle = null; | 21 | @observable filterNeedle = null; |
21 | 22 | ||
@@ -31,6 +32,7 @@ export default class ServicesStore extends Store { | |||
31 | this.actions.service.createFromLegacyService.listen(this._createFromLegacyService.bind(this)); | 32 | this.actions.service.createFromLegacyService.listen(this._createFromLegacyService.bind(this)); |
32 | this.actions.service.updateService.listen(this._updateService.bind(this)); | 33 | this.actions.service.updateService.listen(this._updateService.bind(this)); |
33 | this.actions.service.deleteService.listen(this._deleteService.bind(this)); | 34 | this.actions.service.deleteService.listen(this._deleteService.bind(this)); |
35 | this.actions.service.clearCache.listen(this._clearCache.bind(this)); | ||
34 | this.actions.service.setWebviewReference.listen(this._setWebviewReference.bind(this)); | 36 | this.actions.service.setWebviewReference.listen(this._setWebviewReference.bind(this)); |
35 | this.actions.service.focusService.listen(this._focusService.bind(this)); | 37 | this.actions.service.focusService.listen(this._focusService.bind(this)); |
36 | this.actions.service.focusActiveService.listen(this._focusActiveService.bind(this)); | 38 | this.actions.service.focusActiveService.listen(this._focusActiveService.bind(this)); |
@@ -205,6 +207,13 @@ export default class ServicesStore extends Store { | |||
205 | gaEvent('Service', 'delete', service.recipe.id); | 207 | gaEvent('Service', 'delete', service.recipe.id); |
206 | } | 208 | } |
207 | 209 | ||
210 | @action async _clearCache({ serviceId }) { | ||
211 | this.clearCacheRequest.reset(); | ||
212 | const request = this.clearCacheRequest.execute(serviceId); | ||
213 | await request._promise; | ||
214 | gaEvent('Service', 'clear cache'); | ||
215 | } | ||
216 | |||
208 | @action _setActive({ serviceId }) { | 217 | @action _setActive({ serviceId }) { |
209 | const service = this.one(serviceId); | 218 | const service = this.one(serviceId); |
210 | 219 | ||
diff --git a/src/styles/button.scss b/src/styles/button.scss index 75d2cb1d4..8d2adbbcc 100644 --- a/src/styles/button.scss +++ b/src/styles/button.scss | |||
@@ -48,6 +48,18 @@ | |||
48 | } | 48 | } |
49 | } | 49 | } |
50 | 50 | ||
51 | &.franz-form__button--warning { | ||
52 | background: $theme-brand-warning; | ||
53 | |||
54 | &:hover { | ||
55 | background: darken($theme-brand-warning, 5%); | ||
56 | } | ||
57 | |||
58 | &:active { | ||
59 | background: lighten($theme-brand-warning, 5%); | ||
60 | } | ||
61 | } | ||
62 | |||
51 | &.franz-form__button--inverted { | 63 | &.franz-form__button--inverted { |
52 | background: none; | 64 | background: none; |
53 | padding: 10px 20px; | 65 | padding: 10px 20px; |