cozy-bar 1.17.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.eslintrc.json +7 -0
- package/.github/auto-merge.yml +7 -0
- package/.nvmrc +1 -0
- package/.transifexrc.tpl +4 -0
- package/.travis.yml +28 -0
- package/.tx/config +8 -0
- package/CHANGELOG.md +493 -0
- package/CODEOWNERS +2 -0
- package/CONTRIBUTING.md +135 -0
- package/LICENSE +21 -0
- package/README.md +172 -0
- package/babel.config.js +3 -0
- package/config/aliases/globalReact.js +1 -0
- package/config/aliases/globalReactDOM.js +1 -0
- package/config/webpack.config.analyzer.js +10 -0
- package/config/webpack.config.base.js +61 -0
- package/config/webpack.config.dev.js +16 -0
- package/config/webpack.config.extract.js +84 -0
- package/config/webpack.config.inline-styles.js +82 -0
- package/config/webpack.config.jsx.js +14 -0
- package/config/webpack.config.prod.js +18 -0
- package/config/webpack.js +31 -0
- package/config/webpack.vars.js +11 -0
- package/dist/cozy-bar.css +9445 -0
- package/dist/cozy-bar.css.map +1 -0
- package/dist/cozy-bar.js +122668 -0
- package/dist/cozy-bar.js.map +1 -0
- package/dist/cozy-bar.min.css +9 -0
- package/dist/cozy-bar.min.css.map +1 -0
- package/dist/cozy-bar.min.js +57 -0
- package/dist/cozy-bar.min.js.map +1 -0
- package/dist/cozy-bar.mobile.js +123719 -0
- package/dist/cozy-bar.mobile.js.map +1 -0
- package/dist/cozy-bar.mobile.min.js +57 -0
- package/dist/cozy-bar.mobile.min.js.map +1 -0
- package/docs/dev.md +20 -0
- package/examples/Procfile +3 -0
- package/examples/icon.png +0 -0
- package/examples/index.html +7 -0
- package/examples/index.jsx +122 -0
- package/examples/logs.js +3 -0
- package/package.json +163 -0
- package/postcss.config.js +23 -0
- package/public/fonts/Lato-Bold.woff2 +0 -0
- package/public/fonts/Lato-Regular.woff2 +0 -0
- package/public/fonts.css +13 -0
- package/public/icon-type-folder-32.png +0 -0
- package/public/index.html +63 -0
- package/renovate.json +5 -0
- package/src/assets/icons/16/icon-claudy.svg +5 -0
- package/src/assets/icons/16/icon-cozy-16.svg +1 -0
- package/src/assets/icons/16/icon-cube-16.svg +6 -0
- package/src/assets/icons/16/icon-logout-16.svg +3 -0
- package/src/assets/icons/16/icon-magnifier-16.svg +6 -0
- package/src/assets/icons/16/icon-people-16.svg +3 -0
- package/src/assets/icons/16/icon-phone-16.svg +3 -0
- package/src/assets/icons/16/icon-question-mark-16.svg +3 -0
- package/src/assets/icons/16/icon-storage-16.svg +3 -0
- package/src/assets/icons/24/icon-arrow-left.svg +3 -0
- package/src/assets/icons/32/icon-claudy.svg +1 -0
- package/src/assets/icons/apps/icon-collect.svg +25 -0
- package/src/assets/icons/apps/icon-drive.svg +17 -0
- package/src/assets/icons/apps/icon-market-soon.svg +25 -0
- package/src/assets/icons/apps/icon-photos.svg +19 -0
- package/src/assets/icons/apps/icon-soon.svg +21 -0
- package/src/assets/icons/apps/icon-store.svg +19 -0
- package/src/assets/icons/claudyActions/icon-bills.svg +6 -0
- package/src/assets/icons/claudyActions/icon-laptop.svg +7 -0
- package/src/assets/icons/claudyActions/icon-phone.svg +8 -0
- package/src/assets/icons/claudyActions/icon-question-mark.svg +6 -0
- package/src/assets/icons/comingsoon/icon-bank.svg +12 -0
- package/src/assets/icons/comingsoon/icon-sante.svg +12 -0
- package/src/assets/icons/comingsoon/icon-store.svg +6 -0
- package/src/assets/icons/icon-cozy.svg +3 -0
- package/src/assets/icons/icon-shield.svg +3 -0
- package/src/assets/icons/spinner.svg +4 -0
- package/src/assets/sprites/icon-apps.svg +1 -0
- package/src/assets/sprites/icon-cozy-home.svg +16 -0
- package/src/components/Apps/AppItem.jsx +117 -0
- package/src/components/Apps/AppItemPlaceholder.jsx +12 -0
- package/src/components/Apps/AppNavButtons.jsx +88 -0
- package/src/components/Apps/AppsContent.jsx +89 -0
- package/src/components/Apps/ButtonCozyHome.jsx +30 -0
- package/src/components/Apps/ButtonCozyHome.spec.jsx +53 -0
- package/src/components/Apps/IconCozyHome.jsx +24 -0
- package/src/components/Apps/index.jsx +81 -0
- package/src/components/Banner.jsx +41 -0
- package/src/components/Bar.jsx +293 -0
- package/src/components/Bar.spec.jsx +133 -0
- package/src/components/Claudy.jsx +81 -0
- package/src/components/Drawer.jsx +227 -0
- package/src/components/Drawer.spec.jsx +98 -0
- package/src/components/SearchBar.jsx +358 -0
- package/src/components/Settings/SettingsContent.jsx +145 -0
- package/src/components/Settings/StorageData.jsx +29 -0
- package/src/components/Settings/helper.js +8 -0
- package/src/components/Settings/index.jsx +218 -0
- package/src/components/SupportModal.jsx +59 -0
- package/src/components/__snapshots__/Bar.spec.jsx.snap +302 -0
- package/src/config/claudyActions.yaml +14 -0
- package/src/config/persistWhitelist.yaml +2 -0
- package/src/dom.js +80 -0
- package/src/index.jsx +235 -0
- package/src/index.spec.jsx +34 -0
- package/src/lib/api/helpers.js +13 -0
- package/src/lib/api/index.jsx +145 -0
- package/src/lib/exceptions.js +89 -0
- package/src/lib/expiringMemoize.js +13 -0
- package/src/lib/icon.js +77 -0
- package/src/lib/importIcons.js +14 -0
- package/src/lib/intents.js +16 -0
- package/src/lib/logger.js +6 -0
- package/src/lib/middlewares/appsI18n.js +57 -0
- package/src/lib/realtime.js +43 -0
- package/src/lib/reducers/apps.js +175 -0
- package/src/lib/reducers/apps.spec.js +59 -0
- package/src/lib/reducers/content.js +50 -0
- package/src/lib/reducers/context.js +83 -0
- package/src/lib/reducers/index.js +73 -0
- package/src/lib/reducers/locale.js +22 -0
- package/src/lib/reducers/settings.js +111 -0
- package/src/lib/reducers/theme.js +48 -0
- package/src/lib/reducers/unserializable.js +26 -0
- package/src/lib/stack-client.js +401 -0
- package/src/lib/stack.js +79 -0
- package/src/lib/store/index.js +54 -0
- package/src/locales/de.json +57 -0
- package/src/locales/en.json +57 -0
- package/src/locales/es.json +57 -0
- package/src/locales/fr.json +57 -0
- package/src/locales/it.json +57 -0
- package/src/locales/ja.json +57 -0
- package/src/locales/nl_NL.json +57 -0
- package/src/locales/pl.json +57 -0
- package/src/locales/ru.json +57 -0
- package/src/locales/sq.json +57 -0
- package/src/locales/zh_CN.json +57 -0
- package/src/proptypes/index.js +10 -0
- package/src/queries/index.js +16 -0
- package/src/styles/apps.css +248 -0
- package/src/styles/banner.css +64 -0
- package/src/styles/bar.css +106 -0
- package/src/styles/base.css +41 -0
- package/src/styles/claudy.css +99 -0
- package/src/styles/drawer.css +126 -0
- package/src/styles/index.styl +33 -0
- package/src/styles/indicators.css +58 -0
- package/src/styles/nav.css +81 -0
- package/src/styles/navigation_item.css +39 -0
- package/src/styles/searchbar.css +158 -0
- package/src/styles/settings.css +44 -0
- package/src/styles/storage.css +22 -0
- package/src/styles/supportModal.css +20 -0
- package/src/styles/theme.styl +25 -0
- package/test/__mocks__/fileMock.js +3 -0
- package/test/__snapshots__/index.spec.js.snap +41 -0
- package/test/components/AppItem.spec.jsx +113 -0
- package/test/components/AppsContent.spec.jsx +116 -0
- package/test/components/Settings/helper.spec.js +23 -0
- package/test/components/__snapshots__/AppsContent.spec.jsx.snap +90 -0
- package/test/index.spec.js +24 -0
- package/test/jestLib/I18n.js +15 -0
- package/test/jestLib/setup.js +14 -0
- package/test/lib/__snapshots__/api.spec.jsx.snap +67 -0
- package/test/lib/__snapshots__/stack.spec.js.snap +3 -0
- package/test/lib/api.spec.jsx +142 -0
- package/test/lib/mockStackClient.js +7 -0
- package/test/lib/stack-client/stack-client.appiconprops.spec.js +65 -0
- package/test/lib/stack-client/stack-client.compare.spec.js +20 -0
- package/test/lib/stack-client/stack-client.cozyfetchjson.spec.js +46 -0
- package/test/lib/stack-client/stack-client.cozyurl.spec.js +29 -0
- package/test/lib/stack-client/stack-client.getapp.spec.js +72 -0
- package/test/lib/stack-client/stack-client.getapps.spec.js +72 -0
- package/test/lib/stack-client/stack-client.getcontext.spec.js +96 -0
- package/test/lib/stack-client/stack-client.getstoragedata.spec.js +85 -0
- package/test/lib/stack-client/stack-client.init.spec.js +56 -0
- package/test/lib/stack-client/stack-client.intents.spec.js +27 -0
- package/test/lib/stack-client/stack-client.logout.spec.js +40 -0
- package/test/lib/stack.spec.js +60 -0
- package/test/store/__snapshots__/index.spec.js.snap +14 -0
- package/test/store/index.spec.js +41 -0
|
@@ -0,0 +1,401 @@
|
|
|
1
|
+
/* eslint-env browser */
|
|
2
|
+
import compare from 'semver-compare'
|
|
3
|
+
import { Intents } from 'cozy-interapp'
|
|
4
|
+
import getIcon from 'lib/icon'
|
|
5
|
+
import initializeRealtime from 'lib/realtime'
|
|
6
|
+
|
|
7
|
+
import {
|
|
8
|
+
ForbiddenException,
|
|
9
|
+
ServerErrorException,
|
|
10
|
+
NotFoundException,
|
|
11
|
+
MethodNotAllowedException,
|
|
12
|
+
UnavailableSettingsException,
|
|
13
|
+
UnavailableStackException,
|
|
14
|
+
UnauthorizedStackException
|
|
15
|
+
} from 'lib/exceptions'
|
|
16
|
+
import { isMobileApp } from 'cozy-device-helper'
|
|
17
|
+
|
|
18
|
+
const errorStatuses = {
|
|
19
|
+
'401': UnauthorizedStackException,
|
|
20
|
+
'403': ForbiddenException,
|
|
21
|
+
'404': NotFoundException,
|
|
22
|
+
'405': MethodNotAllowedException,
|
|
23
|
+
'500': ServerErrorException
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Cozy client instance
|
|
28
|
+
* @private
|
|
29
|
+
*/
|
|
30
|
+
let cozyClient
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Get the client instance
|
|
34
|
+
*
|
|
35
|
+
* @private
|
|
36
|
+
* @function
|
|
37
|
+
* @returns {Object} cozy-client instance
|
|
38
|
+
*/
|
|
39
|
+
const getIntents = function() {
|
|
40
|
+
return new Intents({ client: cozyClient })
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* Get the stackClient from the cozy-client instance
|
|
45
|
+
*
|
|
46
|
+
* @private
|
|
47
|
+
* @function
|
|
48
|
+
* @returns {Object} cozy-stack-client instance
|
|
49
|
+
*/
|
|
50
|
+
const getStackClient = function() {
|
|
51
|
+
return cozyClient.getStackClient()
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Logout and disconnect the user
|
|
56
|
+
* @function
|
|
57
|
+
* @TODO move this to cozy-stack-client
|
|
58
|
+
* @returns {Promise}
|
|
59
|
+
*/
|
|
60
|
+
const logout = function() {
|
|
61
|
+
return getStackClient()
|
|
62
|
+
.fetch('DELETE', '/auth/login')
|
|
63
|
+
.then(resp => {
|
|
64
|
+
if (resp.status === 401) {
|
|
65
|
+
throw new UnauthorizedStackException()
|
|
66
|
+
} else if (resp.status === 204) {
|
|
67
|
+
window.location.reload()
|
|
68
|
+
}
|
|
69
|
+
return true
|
|
70
|
+
})
|
|
71
|
+
.catch(() => {
|
|
72
|
+
throw new UnavailableStackException()
|
|
73
|
+
})
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* Get a cozy URL object
|
|
78
|
+
*
|
|
79
|
+
* @function
|
|
80
|
+
* @returns {URL}
|
|
81
|
+
*/
|
|
82
|
+
const getCozyURL = function() {
|
|
83
|
+
return new URL(getStackClient().uri)
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Get a the cozy origin as an URL string
|
|
88
|
+
*
|
|
89
|
+
* @function
|
|
90
|
+
* @returns {string}
|
|
91
|
+
*/
|
|
92
|
+
const getCozyURLOrigin = function() {
|
|
93
|
+
return getCozyURL().origin
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* @deprecated
|
|
98
|
+
* @private
|
|
99
|
+
*/
|
|
100
|
+
const updateAccessToken = function() {
|
|
101
|
+
throw new Error(
|
|
102
|
+
'updateAccessToken should not be used with a cozy-client instance initialization'
|
|
103
|
+
)
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Fetch a resource with cozy-client
|
|
108
|
+
*
|
|
109
|
+
* Utility to maintain the compatibility with the legacy
|
|
110
|
+
* standalone cozy-bar client
|
|
111
|
+
*
|
|
112
|
+
* @function
|
|
113
|
+
* @private
|
|
114
|
+
* @returns {Promise} the full raw JSON payload
|
|
115
|
+
*/
|
|
116
|
+
const fetchJSON = function(method, path, body, options = {}) {
|
|
117
|
+
// We mirror here a few lines from cozy-stack-client
|
|
118
|
+
// because we want a customized fetchJSON
|
|
119
|
+
const headers = (options.headers = options.headers || {})
|
|
120
|
+
headers['Accept'] = 'application/json'
|
|
121
|
+
if (method !== 'GET' && method !== 'HEAD' && body !== undefined) {
|
|
122
|
+
if (!headers['Content-Type']) {
|
|
123
|
+
headers['Content-Type'] = 'application/json'
|
|
124
|
+
body = JSON.stringify(body)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
return getStackClient()
|
|
129
|
+
.fetch(method, path, body, options)
|
|
130
|
+
.then(resp => {
|
|
131
|
+
if (typeof errorStatuses[resp.status] === 'function') {
|
|
132
|
+
throw new errorStatuses[resp.status]()
|
|
133
|
+
}
|
|
134
|
+
const contentType = resp.headers.get('content-type')
|
|
135
|
+
const isJson = contentType.includes('json')
|
|
136
|
+
if (!isJson) {
|
|
137
|
+
throw new Error('Server response not in JSON')
|
|
138
|
+
}
|
|
139
|
+
return resp.json()
|
|
140
|
+
})
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Test if an error is from an HTTP 404
|
|
145
|
+
*
|
|
146
|
+
* @function
|
|
147
|
+
* @private
|
|
148
|
+
* @param {Function} error - received from a fetch
|
|
149
|
+
* @returns {boolean}
|
|
150
|
+
*/
|
|
151
|
+
const is404 = function(error) {
|
|
152
|
+
return (
|
|
153
|
+
['NotFoundException', 'NotFound', 'FetchError'].includes(error.name) &&
|
|
154
|
+
error.status &&
|
|
155
|
+
error.status === 404
|
|
156
|
+
)
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
/**
|
|
160
|
+
* Memoize the result of a function which does an HTTP fetch
|
|
161
|
+
*
|
|
162
|
+
* If a call throws an error because the
|
|
163
|
+
* underlying HTTP request returned a 404
|
|
164
|
+
* then this function returns a default value
|
|
165
|
+
*
|
|
166
|
+
* In the absence of any other error, the result is
|
|
167
|
+
* cached and reused in the next call to the function.
|
|
168
|
+
*
|
|
169
|
+
*
|
|
170
|
+
* @function
|
|
171
|
+
* @param {Function} fn - the function to memoize. It will be
|
|
172
|
+
* called without any parameter
|
|
173
|
+
* @param {Object} defaultValue - returned in case of 404
|
|
174
|
+
* @returns {Function} async function
|
|
175
|
+
*/
|
|
176
|
+
|
|
177
|
+
const withCache = function(fn, defaultValue) {
|
|
178
|
+
let cache = undefined
|
|
179
|
+
return async function() {
|
|
180
|
+
if (cache === undefined) {
|
|
181
|
+
try {
|
|
182
|
+
cache = await fn()
|
|
183
|
+
} catch (error) {
|
|
184
|
+
cache = is404(error) ? defaultValue : undefined
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return cache
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* List all installed applications
|
|
193
|
+
*
|
|
194
|
+
* Returns only the `data` key of the
|
|
195
|
+
* whole JSON payload from the server
|
|
196
|
+
*
|
|
197
|
+
* @function
|
|
198
|
+
* @returns {Promise}
|
|
199
|
+
*/
|
|
200
|
+
const getApps = function() {
|
|
201
|
+
return fetchJSON('GET', '/apps/').then(json => {
|
|
202
|
+
if (json.error) {
|
|
203
|
+
throw new Error(json.error)
|
|
204
|
+
}
|
|
205
|
+
return json.data
|
|
206
|
+
})
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Detail of an installed application by its slug
|
|
211
|
+
*
|
|
212
|
+
* Returns only the `data` key of the
|
|
213
|
+
* whole JSON payload from the server
|
|
214
|
+
*
|
|
215
|
+
* @function
|
|
216
|
+
* @param {string} slug
|
|
217
|
+
* @returns {Promise}
|
|
218
|
+
*/
|
|
219
|
+
const getApp = function(slug) {
|
|
220
|
+
if (!slug) {
|
|
221
|
+
throw new Error('Missing slug')
|
|
222
|
+
}
|
|
223
|
+
return fetchJSON('GET', `/apps/${slug}`).then(json => {
|
|
224
|
+
if (json.error) {
|
|
225
|
+
throw new Error(json.error)
|
|
226
|
+
}
|
|
227
|
+
return json.data
|
|
228
|
+
})
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* default value when no quota is provided
|
|
233
|
+
* @private
|
|
234
|
+
*/
|
|
235
|
+
const defaultQuota = 10 ** 12 // 1 Tera
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Get storage and quota usage
|
|
239
|
+
*
|
|
240
|
+
* When no quota is returned by the server
|
|
241
|
+
* the quota used is the larger between
|
|
242
|
+
* `defaultQuota` and 10 * usage
|
|
243
|
+
*
|
|
244
|
+
* @function
|
|
245
|
+
* @returns {Object} {usage, quota, isLimited}
|
|
246
|
+
*/
|
|
247
|
+
const getStorageData = function() {
|
|
248
|
+
return fetchJSON('GET', '/settings/disk-usage')
|
|
249
|
+
.then(json => {
|
|
250
|
+
// parseInt because responses from the server are in text
|
|
251
|
+
const usage = parseInt(json.data.attributes.used, 10)
|
|
252
|
+
const realQuota = parseInt(json.data.attributes.quota, 10)
|
|
253
|
+
// @TODO this is a workaround, we should certainly do smarter
|
|
254
|
+
// and either not requiring this attribute
|
|
255
|
+
// or set it to something more real
|
|
256
|
+
const quota = realQuota || Math.max(defaultQuota, 10 * usage)
|
|
257
|
+
const isLimited = json.data.attributes.is_limited
|
|
258
|
+
return { usage, quota, isLimited }
|
|
259
|
+
})
|
|
260
|
+
.catch(() => {
|
|
261
|
+
throw new UnavailableStackException()
|
|
262
|
+
})
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
/**
|
|
266
|
+
* Fetch an icon data from its path
|
|
267
|
+
*
|
|
268
|
+
* The purpose of this function is to be sent
|
|
269
|
+
* to AppIcon components for mobile devices.
|
|
270
|
+
*
|
|
271
|
+
* @private
|
|
272
|
+
* @function
|
|
273
|
+
* @param {string} iconPath - path of the icon in the stack
|
|
274
|
+
* @returns {Blob}
|
|
275
|
+
*/
|
|
276
|
+
const iconFetcher = function(iconPath) {
|
|
277
|
+
return getStackClient().fetch('GET', iconPath)
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Get a props object that can be sent to an AppIcon component
|
|
282
|
+
*
|
|
283
|
+
* Mobile devices and web browsers need different props
|
|
284
|
+
*
|
|
285
|
+
* @function
|
|
286
|
+
* @returns {Object}
|
|
287
|
+
*/
|
|
288
|
+
const getAppIconProps = function() {
|
|
289
|
+
const mobileAppIconProps = {
|
|
290
|
+
fetchIcon: app => getIcon(iconFetcher, app, true)
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const browserAppIconProps = {
|
|
294
|
+
// we mustn't give the protocol here
|
|
295
|
+
domain: getCozyURL().host,
|
|
296
|
+
secure: getCozyURL().protocol === 'https:'
|
|
297
|
+
}
|
|
298
|
+
return isMobileApp() ? mobileAppIconProps : browserAppIconProps
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
/**
|
|
302
|
+
* Get settings context
|
|
303
|
+
*
|
|
304
|
+
* @function
|
|
305
|
+
* @return {Promise}
|
|
306
|
+
* @see https://docs.cozy.io/en/cozy-stack/settings/#get-settingscontext
|
|
307
|
+
*/
|
|
308
|
+
const getContext = function() {
|
|
309
|
+
return fetchJSON('GET', '/settings/context')
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
/**
|
|
313
|
+
* Fetch a resource on the cozy stack
|
|
314
|
+
* with a prototype compatible with the legacy cozy-client-js
|
|
315
|
+
*
|
|
316
|
+
* @function
|
|
317
|
+
* @param {object} cozy - cozy-client-js
|
|
318
|
+
* @param {string} method - HTTP method
|
|
319
|
+
* @param {string} path
|
|
320
|
+
* @param {object} body
|
|
321
|
+
* @returns {Promise}
|
|
322
|
+
*/
|
|
323
|
+
const cozyFetchJSON = function(cozy, method, path, body) {
|
|
324
|
+
return fetchJSON(method, path, body).then(json => {
|
|
325
|
+
const responseData = Object.assign({}, json.data)
|
|
326
|
+
if (responseData.id) {
|
|
327
|
+
responseData._id = responseData.id
|
|
328
|
+
}
|
|
329
|
+
return responseData
|
|
330
|
+
})
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
const getSettingsAppURL = function() {
|
|
334
|
+
return getApp('settings').then(settings => {
|
|
335
|
+
if (!settings) {
|
|
336
|
+
throw new UnavailableSettingsException()
|
|
337
|
+
}
|
|
338
|
+
return settings.links.related
|
|
339
|
+
})
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/**
|
|
343
|
+
*
|
|
344
|
+
* @param {cozyClient} forcedCozyClient only used to test purpose
|
|
345
|
+
*
|
|
346
|
+
* We can not read `version` from `import CozyClient from cozy-client`
|
|
347
|
+
* since in that case, we'll read version from the cozy-bar node modules
|
|
348
|
+
* and not from the app one.
|
|
349
|
+
*
|
|
350
|
+
* In order to avoid this issue, we get the instance passed by the app to the bar),
|
|
351
|
+
* then read the constructor and then read the version from it
|
|
352
|
+
*/
|
|
353
|
+
const compareClientVersion = function(targetVersion, forcedCozyClient = null) {
|
|
354
|
+
const usedClient = cozyClient ? cozyClient.constructor : {}
|
|
355
|
+
const cozyClientToUse =
|
|
356
|
+
forcedCozyClient !== null ? forcedCozyClient : usedClient
|
|
357
|
+
|
|
358
|
+
if (!cozyClientToUse.version) return false
|
|
359
|
+
const result = compare(cozyClientToUse.version, targetVersion)
|
|
360
|
+
return result >= 0
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
/**
|
|
364
|
+
* Initializes the functions to call the cozy stack
|
|
365
|
+
*
|
|
366
|
+
* @function
|
|
367
|
+
* @param {Object} arg
|
|
368
|
+
* @param {Object} arg.cozyClient - a cozy client instance
|
|
369
|
+
* @param {Function} arg.onCreate
|
|
370
|
+
* @param {Function} arg.onDelete
|
|
371
|
+
* @returns {Promise}
|
|
372
|
+
*/
|
|
373
|
+
const init = function({ cozyClient: client, onCreate, onDelete }) {
|
|
374
|
+
cozyClient = client
|
|
375
|
+
if (!cozyClient.isLogged) return
|
|
376
|
+
initializeRealtime({
|
|
377
|
+
getApp,
|
|
378
|
+
onCreate,
|
|
379
|
+
onDelete,
|
|
380
|
+
cozyClient
|
|
381
|
+
})
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
export { compareClientVersion }
|
|
385
|
+
|
|
386
|
+
export default {
|
|
387
|
+
get: {
|
|
388
|
+
app: getApp,
|
|
389
|
+
apps: getApps,
|
|
390
|
+
context: withCache(getContext, {}),
|
|
391
|
+
storageData: getStorageData,
|
|
392
|
+
iconProps: getAppIconProps,
|
|
393
|
+
cozyURL: getCozyURLOrigin,
|
|
394
|
+
intents: getIntents,
|
|
395
|
+
settingsAppURL: getSettingsAppURL
|
|
396
|
+
},
|
|
397
|
+
updateAccessToken,
|
|
398
|
+
cozyFetchJSON,
|
|
399
|
+
logout,
|
|
400
|
+
init
|
|
401
|
+
}
|
package/src/lib/stack.js
ADDED
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* This file served as a proxy between the old internal stack client from the
|
|
3
|
+
* bar and the new stack-client included in cozy-client. It is no longer
|
|
4
|
+
* necessary as there is no more internal-client. It is there only temporarily
|
|
5
|
+
* and should be removed as soon as possible.
|
|
6
|
+
*
|
|
7
|
+
* @TODO remove this and update the tests.
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import client from 'lib/stack-client'
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Reference to the current client depending
|
|
14
|
+
* on which one has been initialized
|
|
15
|
+
*
|
|
16
|
+
* @private
|
|
17
|
+
*/
|
|
18
|
+
let stack
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Get the current stack client (legacy or cozy-client based)
|
|
22
|
+
* based on which one has been initialized
|
|
23
|
+
*
|
|
24
|
+
* @returns {Object} functions to call the stack
|
|
25
|
+
*/
|
|
26
|
+
const current = function() {
|
|
27
|
+
if (!stack) {
|
|
28
|
+
throw new Error('client not initialized in cozy-bar')
|
|
29
|
+
}
|
|
30
|
+
return stack
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Initializes the functions to call the cozy stack
|
|
35
|
+
*
|
|
36
|
+
* It can be initialized either with a cozy-client instance
|
|
37
|
+
* or a { cozyURL, ssl, token } tupple.
|
|
38
|
+
*
|
|
39
|
+
* @function
|
|
40
|
+
* @param {Object} arg
|
|
41
|
+
* @param {Object} arg.cozyClient - a cozy client instance
|
|
42
|
+
* @param {string} arg.cozyURL - URL or domain of the stack
|
|
43
|
+
* @param {boolean} arg.ssl - Tells if we should use a secure protocol
|
|
44
|
+
* required if cozyURL does not have a protocol
|
|
45
|
+
* @param {string} arg.token - Access token for the stack
|
|
46
|
+
* @param {Function} arg.onCreateApp
|
|
47
|
+
* @param {Function} arg.onDeleteApp
|
|
48
|
+
* @param {Boolean} arg.isPublic
|
|
49
|
+
* @returns {Promise}
|
|
50
|
+
*/
|
|
51
|
+
const init = function(options) {
|
|
52
|
+
stack = client
|
|
53
|
+
return stack.init(options)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const get = {
|
|
57
|
+
app: (...args) => current().get.app(...args),
|
|
58
|
+
apps: (...args) => current().get.apps(...args),
|
|
59
|
+
context: (...args) => current().get.context(...args),
|
|
60
|
+
storageData: (...args) => current().get.storageData(...args),
|
|
61
|
+
iconProps: (...args) => current().get.iconProps(...args),
|
|
62
|
+
cozyURL: (...args) => current().get.cozyURL(...args),
|
|
63
|
+
settingsAppURL: (...args) => current().get.settingsAppURL(...args)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const stackProxy = {
|
|
67
|
+
init,
|
|
68
|
+
get,
|
|
69
|
+
updateAccessToken: (...args) => current().updateAccessToken(...args),
|
|
70
|
+
logout: (...args) => current().logout(...args),
|
|
71
|
+
cozyFetchJSON: (...args) => current().cozyFetchJSON(...args),
|
|
72
|
+
// useful to connect some getters outside of this file without exposing
|
|
73
|
+
// directly the private stack variable
|
|
74
|
+
getStack: current,
|
|
75
|
+
getIntents: () => current().get.intents()
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export default stackProxy
|
|
79
|
+
export const { cozyFetchJSON, getIntents } = stackProxy
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/* global __DEVELOPMENT__ */
|
|
2
|
+
|
|
3
|
+
import { createStore as createReduxStore, applyMiddleware } from 'redux'
|
|
4
|
+
import appsI18nMiddleware from 'lib/middlewares/appsI18n'
|
|
5
|
+
import thunkMiddleware from 'redux-thunk'
|
|
6
|
+
import { persistStore, persistCombineReducers } from 'redux-persist'
|
|
7
|
+
import { reducers } from 'lib/reducers'
|
|
8
|
+
import { createLogger } from 'redux-logger'
|
|
9
|
+
import storage from 'redux-persist/lib/storage'
|
|
10
|
+
import persistWhitelist from 'config/persistWhitelist'
|
|
11
|
+
import logger from '../logger'
|
|
12
|
+
|
|
13
|
+
const config = {
|
|
14
|
+
storage,
|
|
15
|
+
key: 'cozy-bar',
|
|
16
|
+
whitelist: persistWhitelist
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
// copied and changed from https://github.com/LogRocket/redux-logger/blob/3ca9f2c1ecf17a7acf18c6fa0bbf4b6b239738f1/src/core.js#L25
|
|
20
|
+
function barTitleFormatter(action, time) {
|
|
21
|
+
const parts = ['[COZY-BAR]']
|
|
22
|
+
|
|
23
|
+
parts.push(`${String(action.type)}`)
|
|
24
|
+
if (time) parts.push(`@ ${time}`)
|
|
25
|
+
|
|
26
|
+
return parts.join(' ')
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const loggerMiddleware = createLogger({
|
|
30
|
+
titleFormatter: barTitleFormatter,
|
|
31
|
+
logger
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
const reducer = persistCombineReducers(config, { ...reducers })
|
|
35
|
+
|
|
36
|
+
const middlewares = [appsI18nMiddleware, thunkMiddleware]
|
|
37
|
+
|
|
38
|
+
if (__DEVELOPMENT__) middlewares.push(loggerMiddleware)
|
|
39
|
+
|
|
40
|
+
export const createStore = () => {
|
|
41
|
+
store = createReduxStore(reducer, applyMiddleware.apply(null, middlewares))
|
|
42
|
+
persistStore(store)
|
|
43
|
+
return store
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let store
|
|
47
|
+
const getOrCreateStore = () => {
|
|
48
|
+
if (!store) {
|
|
49
|
+
store = createStore()
|
|
50
|
+
}
|
|
51
|
+
return store
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export default getOrCreateStore
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"drawer": "Menü anzeigen",
|
|
3
|
+
"profile": "Profile",
|
|
4
|
+
"connectedDevices": "Verbundene Geräte",
|
|
5
|
+
"storage": "Speicher",
|
|
6
|
+
"storage_phrase": "%{diskUsage} GB von %{diskQuota} GB benutzt",
|
|
7
|
+
"view_offers": "View offers",
|
|
8
|
+
"view_my_offer": "My offer",
|
|
9
|
+
"help": "Hilfe",
|
|
10
|
+
"logout": "Ausloggen",
|
|
11
|
+
"soon": "Später",
|
|
12
|
+
"error_UnavailableStack": "Der Stapel ist nicht erreichbar (Verbindung Zeitüberschreitung).",
|
|
13
|
+
"error_UnauthorizedStack": "Einige Berechtigungen fehlen, die Anwendung kann nicht auf die angeforderte Ressource auf dem Stapel zugreifen.",
|
|
14
|
+
"no_apps": "Keine Anwendungen für Cozy gefunden.",
|
|
15
|
+
|
|
16
|
+
"menu": {
|
|
17
|
+
"apps": "Anwendungen",
|
|
18
|
+
"settings": "Einstellungen",
|
|
19
|
+
"home_mobile": "Back to home...",
|
|
20
|
+
"home": "Back to home",
|
|
21
|
+
"home_title": "Home"
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
"Categories": {
|
|
25
|
+
"cozy": "Cozy Anwendungen",
|
|
26
|
+
"partners": "Partner Anwendungen",
|
|
27
|
+
"ptnb": "expPTNB",
|
|
28
|
+
"others": "Andere Anwendungen"
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
"claudy": {
|
|
32
|
+
"title": "Wie willst du dein Cozy steuern?"
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
"searchbar": {
|
|
36
|
+
"placeholder": "Alle Dateien durchsuchen",
|
|
37
|
+
"empty": "Es wurde kein Ergebnis für die Suche \"%{query}\" gefunden"
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
"permsModal": {
|
|
41
|
+
"title": "Greife von deiner Anwendung aus auf dein komplettes Cozy zu",
|
|
42
|
+
"description": "Erlaube %{app} den Zugriff auf deine Cozy Anwendungen auf diesem Gerät",
|
|
43
|
+
"button": "Erlaube Zugriff"
|
|
44
|
+
},
|
|
45
|
+
"comingSoon": {
|
|
46
|
+
"store": {
|
|
47
|
+
"title": "Die Store Anwendung wird in deinem Cozy bald verfügbar sein.",
|
|
48
|
+
"description": "Dank Cozy Store wird es bald möglich sein gewünschte Anwendungen in dein Cozy zu installieren."
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"banner": {
|
|
52
|
+
"tos-updated": {
|
|
53
|
+
"description": "To comply with the GDPR, Cozy Cloud has updated its Terms of Services that have taken effect on May 25, 2018",
|
|
54
|
+
"CTA": "Jetzt lesen"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"drawer": "Show menu drawer",
|
|
3
|
+
"profile": "Profile",
|
|
4
|
+
"connectedDevices": "Connected devices",
|
|
5
|
+
"storage": "Storage",
|
|
6
|
+
"storage_phrase": "%{diskUsage} GB of %{diskQuota} GB used",
|
|
7
|
+
"view_offers": "View offers",
|
|
8
|
+
"view_my_offer": "My offer",
|
|
9
|
+
"help": "Help",
|
|
10
|
+
"logout": "Sign out",
|
|
11
|
+
"soon": "soon",
|
|
12
|
+
"error_UnavailableStack": "The stack is unreachable (connection timed-out).",
|
|
13
|
+
"error_UnauthorizedStack": "Some permissions are missing, the application can't access the requested resource on the stack.",
|
|
14
|
+
"no_apps": "No applications found on the Cozy.",
|
|
15
|
+
|
|
16
|
+
"menu": {
|
|
17
|
+
"apps": "Apps",
|
|
18
|
+
"settings": "Settings",
|
|
19
|
+
"home_mobile": "Back to home...",
|
|
20
|
+
"home": "Back to home",
|
|
21
|
+
"home_title": "Home"
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
"Categories": {
|
|
25
|
+
"cozy": "Cozy apps",
|
|
26
|
+
"partners": "Partners apps",
|
|
27
|
+
"ptnb": "expPTNB",
|
|
28
|
+
"others": "Other apps"
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
"claudy": {
|
|
32
|
+
"title": "How to drive your Cozy?"
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
"searchbar": {
|
|
36
|
+
"placeholder": "Search anything",
|
|
37
|
+
"empty": "No result has been found for the query “%{query}”"
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
"permsModal": {
|
|
41
|
+
"title": "Access your whole Cozy from your application",
|
|
42
|
+
"description": "Authorize %{app} to display your Cozy applications on this device",
|
|
43
|
+
"button": "Authorize access"
|
|
44
|
+
},
|
|
45
|
+
"comingSoon": {
|
|
46
|
+
"store": {
|
|
47
|
+
"title": "The Store application will be available soon in your Cozy.",
|
|
48
|
+
"description": "Thanks to Cozy Store you will be able to install the applications that you want in your Cozy."
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"banner": {
|
|
52
|
+
"tos-updated": {
|
|
53
|
+
"description": "To comply with the GDPR, Cozy Cloud has updated its Terms of Services that have taken effect on May 25, 2018",
|
|
54
|
+
"CTA": "Read now"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
{
|
|
2
|
+
"drawer": "Mostrar el menu lateral",
|
|
3
|
+
"profile": "Perfil",
|
|
4
|
+
"connectedDevices": "Aparatos conectados",
|
|
5
|
+
"storage": "Espacio en el disco",
|
|
6
|
+
"storage_phrase": "%{diskUsage} Go de %{diskQuota} Go",
|
|
7
|
+
"view_offers": "Ver ofertas",
|
|
8
|
+
"view_my_offer": "Mi oferta",
|
|
9
|
+
"help": "Ayuda",
|
|
10
|
+
"logout": "Desconectar",
|
|
11
|
+
"soon": "pronto",
|
|
12
|
+
"error_UnavailableStack": "Conexión a la stack imposible ( se agotó el tiempo para la conexión ).",
|
|
13
|
+
"error_UnauthorizedStack": "Faltan algunos permisos, la aplicación no puede acceder a los recursos solicitados.",
|
|
14
|
+
"no_apps": "No se han encontrado aplicaciones en su Cozy.",
|
|
15
|
+
|
|
16
|
+
"menu": {
|
|
17
|
+
"apps": "Aplicaciones",
|
|
18
|
+
"settings": "Parámetros",
|
|
19
|
+
"home_mobile": "Regresar a Inicio...",
|
|
20
|
+
"home": "Regresar a Inicio",
|
|
21
|
+
"home_title": "Inicio"
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
"Categories": {
|
|
25
|
+
"cozy": "Aplicaciones Cozy",
|
|
26
|
+
"partners": "Aplicaciones de asociados",
|
|
27
|
+
"ptnb": "expPTNB",
|
|
28
|
+
"others": "Otras aplicaciones"
|
|
29
|
+
},
|
|
30
|
+
|
|
31
|
+
"claudy": {
|
|
32
|
+
"title": "¿Cómo utilizar su Cozy?"
|
|
33
|
+
},
|
|
34
|
+
|
|
35
|
+
"searchbar": {
|
|
36
|
+
"placeholder": "Buscar",
|
|
37
|
+
"empty": "No se ha encontrado ningún resultado para su consulta “%{query}”"
|
|
38
|
+
},
|
|
39
|
+
|
|
40
|
+
"permsModal": {
|
|
41
|
+
"title": "Acceder a su Cozy desde su aplicación",
|
|
42
|
+
"description": "Autorizar a %{app} para mostrar sus aplicaciones Cozy en este aparato",
|
|
43
|
+
"button": "Autorizar el acceso"
|
|
44
|
+
},
|
|
45
|
+
"comingSoon": {
|
|
46
|
+
"store": {
|
|
47
|
+
"title": "En breve, la aplicación Store estará disponible en su Cozy",
|
|
48
|
+
"description": "Gracias a Cozy Store usted podrá instalar en su Cozy las aplicaciones que desee."
|
|
49
|
+
}
|
|
50
|
+
},
|
|
51
|
+
"banner": {
|
|
52
|
+
"tos-updated": {
|
|
53
|
+
"description": "Para cumplir con el RGPD, Cozy Cloud ha actualizado sus Condiciones de utilización que entraron en vigor desde el 25 de mayo de 2018.",
|
|
54
|
+
"CTA": "Leerlo ahora"
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|