cozy-client 60.13.0 → 60.14.0

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.
@@ -3126,7 +3126,7 @@ var CozyClient = /*#__PURE__*/function () {
3126
3126
  CozyClient.hooks = CozyClient.hooks || {};
3127
3127
  CozyClient.fetchPolicies = _policies.default; //COZY_CLIENT_VERSION_PACKAGE in replaced by babel. See babel config
3128
3128
 
3129
- CozyClient.version = "60.13.0";
3129
+ CozyClient.version = "60.14.0";
3130
3130
 
3131
3131
  _microee.default.mixin(CozyClient);
3132
3132
 
@@ -5,10 +5,12 @@ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefau
5
5
  Object.defineProperty(exports, "__esModule", {
6
6
  value: true
7
7
  });
8
- exports.sortApplicationsList = exports.getAppDisplayName = exports.getUrl = exports.isInstalled = exports.getStoreInstallationURL = exports.getStoreURL = void 0;
8
+ exports.filterEntrypoints = exports.selectEntrypoints = exports.shouldDisplayEntrypoint = exports.checkEntrypointCondition = exports.sortApplicationsList = exports.getAppDisplayName = exports.getUrl = exports.isInstalled = exports.getStoreInstallationURL = exports.getStoreURL = void 0;
9
9
 
10
10
  var _toConsumableArray2 = _interopRequireDefault(require("@babel/runtime/helpers/toConsumableArray"));
11
11
 
12
+ var _cozyFlags = _interopRequireDefault(require("cozy-flags"));
13
+
12
14
  var _get = _interopRequireDefault(require("lodash/get"));
13
15
 
14
16
  var STORE_SLUG = 'store';
@@ -129,5 +131,93 @@ var sortApplicationsList = function sortApplicationsList(apps, slugsOrder) {
129
131
  return indexA - indexB;
130
132
  });
131
133
  };
134
+ /**
135
+ * @typedef {Object} EntrypointTitle
136
+ * @property {string} [en] - English title
137
+ * @property {string} [fr] - French title
138
+ * @property {string} [ru] - Russian title
139
+ * @property {string} [vi] - Vietnamese title
140
+ */
141
+
142
+ /**
143
+ * @typedef {Object} EntrypointCondition
144
+ * @property {'flag'} type - The type of condition (currently only 'flag' is supported)
145
+ * @property {string} name - The name of the flag
146
+ * @property {boolean} value - The expected value of the flag
147
+ */
148
+
149
+ /**
150
+ * @typedef {Object} Entrypoint
151
+ * @property {string} name - The unique name of the entrypoint
152
+ * @property {EntrypointTitle} title - Localized titles for the entrypoint
153
+ * @property {string} hash - The URL hash for navigation
154
+ * @property {string} icon - Base64 encoded SVG icon
155
+ * @property {EntrypointCondition[]} [conditions] - Conditions that must be met to display the entrypoint
156
+ */
157
+
158
+ /**
159
+ * Checks if an entrypoint condition is satisfied
160
+ *
161
+ * @param {EntrypointCondition} entrypointCondition - The condition to check
162
+ * @returns {boolean} True if the condition is satisfied
163
+ */
164
+
165
+
166
+ exports.sortApplicationsList = sortApplicationsList;
167
+
168
+ var checkEntrypointCondition = function checkEntrypointCondition(entrypointCondition) {
169
+ if (entrypointCondition.type === 'flag') {
170
+ return (0, _cozyFlags.default)(entrypointCondition.name) === entrypointCondition.value;
171
+ }
172
+
173
+ return false;
174
+ };
175
+ /**
176
+ * Checks if an entrypoint should be displayed based on its conditions
177
+ *
178
+ * @param {Entrypoint} entrypoint - The entrypoint to check
179
+ * @returns {boolean} True if all conditions are satisfied
180
+ */
181
+
182
+
183
+ exports.checkEntrypointCondition = checkEntrypointCondition;
184
+
185
+ var shouldDisplayEntrypoint = function shouldDisplayEntrypoint(entrypoint) {
186
+ var conditions = entrypoint.conditions || [];
187
+ return conditions.every(function (condition) {
188
+ return checkEntrypointCondition(condition);
189
+ });
190
+ };
191
+ /**
192
+ * Selects entrypoints by their names
193
+ *
194
+ * @param {Entrypoint[]} entrypoints - Array of entrypoints
195
+ * @param {string[]} names - Array of entrypoint names to select
196
+ * @returns {Entrypoint[]} Filtered array of entrypoints
197
+ */
198
+
199
+
200
+ exports.shouldDisplayEntrypoint = shouldDisplayEntrypoint;
201
+
202
+ var selectEntrypoints = function selectEntrypoints(entrypoints, names) {
203
+ return entrypoints.filter(function (entrypoint) {
204
+ return names.includes(entrypoint.name);
205
+ });
206
+ };
207
+ /**
208
+ * Filters entrypoints based on whether they should be displayed
209
+ *
210
+ * @param {Entrypoint[]} entrypoints - Array of entrypoints
211
+ * @returns {Entrypoint[]} Filtered array of entrypoints that should be displayed
212
+ */
213
+
214
+
215
+ exports.selectEntrypoints = selectEntrypoints;
216
+
217
+ var filterEntrypoints = function filterEntrypoints(entrypoints) {
218
+ return entrypoints.filter(function (entrypoint) {
219
+ return shouldDisplayEntrypoint(entrypoint);
220
+ });
221
+ };
132
222
 
133
- exports.sortApplicationsList = sortApplicationsList;
223
+ exports.filterEntrypoints = filterEntrypoints;
@@ -1,11 +1,18 @@
1
+ import flag from 'cozy-flags'
1
2
  import { applications } from './'
2
3
  const {
3
4
  getAppDisplayName,
4
5
  getStoreURL,
5
6
  getStoreInstallationURL,
6
- sortApplicationsList
7
+ sortApplicationsList,
8
+ checkEntrypointCondition,
9
+ shouldDisplayEntrypoint,
10
+ selectEntrypoints,
11
+ filterEntrypoints
7
12
  } = applications
8
13
 
14
+ jest.mock('cozy-flags')
15
+
9
16
  describe('applications model', () => {
10
17
  describe('application name', () => {
11
18
  it('should return names', () => {
@@ -224,4 +231,241 @@ describe('applications model', () => {
224
231
  expect(result).toEqual(expected)
225
232
  })
226
233
  })
234
+
235
+ describe('entrypoints', () => {
236
+ beforeEach(() => {
237
+ flag.mockReset()
238
+ })
239
+
240
+ describe('checkEntrypointCondition', () => {
241
+ it('should return true when flag condition is met', () => {
242
+ flag.mockReturnValue(true)
243
+ /** @type {import('./applications').EntrypointCondition} */
244
+ const condition = {
245
+ type: 'flag',
246
+ name: 'drive.office.enabled',
247
+ value: true
248
+ }
249
+ expect(checkEntrypointCondition(condition)).toBe(true)
250
+ })
251
+
252
+ it('should return false when flag condition is not met', () => {
253
+ flag.mockReturnValue(false)
254
+ /** @type {import('./applications').EntrypointCondition} */
255
+ const condition = {
256
+ type: 'flag',
257
+ name: 'drive.office.enabled',
258
+ value: true
259
+ }
260
+ expect(checkEntrypointCondition(condition)).toBe(false)
261
+ })
262
+
263
+ it('should return false for unknown condition types', () => {
264
+ const condition = {
265
+ type: 'unknown',
266
+ name: 'some.flag',
267
+ value: true
268
+ }
269
+ // @ts-expect-error Testing a bad format on purpose
270
+ expect(checkEntrypointCondition(condition)).toBe(false)
271
+ })
272
+ })
273
+
274
+ describe('shouldDisplayEntrypoint', () => {
275
+ it('should return true when entrypoint has no conditions', () => {
276
+ /** @type {import('./applications').Entrypoint} */
277
+ const entrypoint = {
278
+ name: 'test-entrypoint',
279
+ title: { en: 'Test' },
280
+ hash: '/test',
281
+ icon: 'test-icon'
282
+ }
283
+ expect(shouldDisplayEntrypoint(entrypoint)).toBe(true)
284
+ })
285
+
286
+ it('should return true when all conditions are met', () => {
287
+ flag.mockReturnValue(true)
288
+ /** @type {import('./applications').Entrypoint} */
289
+ const entrypoint = {
290
+ name: 'test-entrypoint',
291
+ title: { en: 'Test' },
292
+ hash: '/test',
293
+ icon: 'test-icon',
294
+ conditions: [
295
+ { type: 'flag', name: 'drive.office.enabled', value: true }
296
+ ]
297
+ }
298
+ expect(shouldDisplayEntrypoint(entrypoint)).toBe(true)
299
+ })
300
+
301
+ it('should return false when at least one condition is not met', () => {
302
+ flag.mockImplementation((/** @type {string} */ name) => {
303
+ if (name === 'drive.office.enabled') return true
304
+ if (name === 'other.flag') return false
305
+ return false
306
+ })
307
+ /** @type {import('./applications').Entrypoint} */
308
+ const entrypoint = {
309
+ name: 'test-entrypoint',
310
+ title: { en: 'Test' },
311
+ hash: '/test',
312
+ icon: 'test-icon',
313
+ conditions: [
314
+ { type: 'flag', name: 'drive.office.enabled', value: true },
315
+ { type: 'flag', name: 'other.flag', value: true }
316
+ ]
317
+ }
318
+ expect(shouldDisplayEntrypoint(entrypoint)).toBe(false)
319
+ })
320
+
321
+ it('should return true when conditions array is empty', () => {
322
+ /** @type {import('./applications').Entrypoint} */
323
+ const entrypoint = {
324
+ name: 'test-entrypoint',
325
+ title: { en: 'Test' },
326
+ hash: '/test',
327
+ icon: 'test-icon',
328
+ conditions: []
329
+ }
330
+ expect(shouldDisplayEntrypoint(entrypoint)).toBe(true)
331
+ })
332
+ })
333
+
334
+ describe('selectEntrypoints', () => {
335
+ const entrypoints = [
336
+ {
337
+ name: 'new-file-type-text',
338
+ title: { en: 'Doc' },
339
+ hash: '/onlyoffice/create/text',
340
+ icon: 'icon-text'
341
+ },
342
+ {
343
+ name: 'new-file-type-spreadsheet',
344
+ title: { en: 'Spreadsheet' },
345
+ hash: '/onlyoffice/create/spreadsheet',
346
+ icon: 'icon-spreadsheet'
347
+ },
348
+ {
349
+ name: 'new-file-type-presentation',
350
+ title: { en: 'Presentation' },
351
+ hash: '/onlyoffice/create/presentation',
352
+ icon: 'icon-presentation'
353
+ }
354
+ ]
355
+
356
+ it('should return entrypoints matching the given names', () => {
357
+ const names = ['new-file-type-text', 'new-file-type-presentation']
358
+ const result = selectEntrypoints(entrypoints, names)
359
+ expect(result).toHaveLength(2)
360
+ expect(result[0].name).toBe('new-file-type-text')
361
+ expect(result[1].name).toBe('new-file-type-presentation')
362
+ })
363
+
364
+ it('should return empty array when no names match', () => {
365
+ const names = ['non-existent']
366
+ const result = selectEntrypoints(entrypoints, names)
367
+ expect(result).toEqual([])
368
+ })
369
+
370
+ it('should return all entrypoints when all names are provided', () => {
371
+ const names = [
372
+ 'new-file-type-text',
373
+ 'new-file-type-spreadsheet',
374
+ 'new-file-type-presentation'
375
+ ]
376
+ const result = selectEntrypoints(entrypoints, names)
377
+ expect(result).toHaveLength(3)
378
+ })
379
+
380
+ it('should return empty array when names array is empty', () => {
381
+ const result = selectEntrypoints(entrypoints, [])
382
+ expect(result).toEqual([])
383
+ })
384
+ })
385
+
386
+ describe('filterEntrypoints', () => {
387
+ it('should return only entrypoints that should be displayed', () => {
388
+ flag.mockImplementation((/** @type {string} */ name) => {
389
+ if (name === 'feature.1') return true
390
+ if (name === 'feature.2') return false
391
+ return false
392
+ })
393
+
394
+ /** @type {import('./applications').Entrypoint[]} */
395
+ const entrypoints = [
396
+ {
397
+ name: 'always-visible',
398
+ title: { en: 'Always' },
399
+ hash: '/always',
400
+ icon: 'icon'
401
+ },
402
+ {
403
+ name: 'feature-1',
404
+ title: { en: 'Feature 1' },
405
+ hash: '/feature1',
406
+ icon: 'icon',
407
+ conditions: [{ type: 'flag', name: 'feature.1', value: true }]
408
+ },
409
+ {
410
+ name: 'feature-2',
411
+ title: { en: 'Feature 2' },
412
+ hash: '/feature2',
413
+ icon: 'icon',
414
+ conditions: [{ type: 'flag', name: 'feature.2', value: true }]
415
+ }
416
+ ]
417
+
418
+ const result = filterEntrypoints(entrypoints)
419
+ expect(result).toHaveLength(2)
420
+ expect(result[0].name).toBe('always-visible')
421
+ expect(result[1].name).toBe('feature-1')
422
+ })
423
+
424
+ it('should return all entrypoints when all conditions are met', () => {
425
+ flag.mockReturnValue(true)
426
+ /** @type {import('./applications').Entrypoint[]} */
427
+ const entrypoints = [
428
+ {
429
+ name: 'feature-1',
430
+ title: { en: 'Feature 1' },
431
+ hash: '/feature1',
432
+ icon: 'icon',
433
+ conditions: [{ type: 'flag', name: 'feature.1', value: true }]
434
+ },
435
+ {
436
+ name: 'feature-2',
437
+ title: { en: 'Feature 2' },
438
+ hash: '/feature2',
439
+ icon: 'icon',
440
+ conditions: [{ type: 'flag', name: 'feature.2', value: true }]
441
+ }
442
+ ]
443
+
444
+ const result = filterEntrypoints(entrypoints)
445
+ expect(result).toHaveLength(2)
446
+ })
447
+
448
+ it('should return empty array when no entrypoints should be displayed', () => {
449
+ flag.mockReturnValue(false)
450
+ /** @type {import('./applications').Entrypoint[]} */
451
+ const entrypoints = [
452
+ {
453
+ name: 'feature-1',
454
+ title: { en: 'Feature 1' },
455
+ hash: '/feature1',
456
+ icon: 'icon',
457
+ conditions: [{ type: 'flag', name: 'feature.1', value: true }]
458
+ }
459
+ ]
460
+
461
+ const result = filterEntrypoints(entrypoints)
462
+ expect(result).toEqual([])
463
+ })
464
+
465
+ it('should handle empty entrypoints array', () => {
466
+ const result = filterEntrypoints([])
467
+ expect(result).toEqual([])
468
+ })
469
+ })
470
+ })
227
471
  })
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-client",
3
- "version": "60.13.0",
3
+ "version": "60.14.0",
4
4
  "license": "MIT",
5
5
  "main": "dist/index.node.js",
6
6
  "browser": "dist/index.js",
@@ -74,5 +74,5 @@
74
74
  "react-native-ios11-devicecheck": "^0.0.3"
75
75
  },
76
76
  "sideEffects": false,
77
- "gitHead": "4f2002995a7e321591cbf56b4d4235cd062457ce"
77
+ "gitHead": "5147a1819dbf195aa920b5aea20265573e1b81bb"
78
78
  }
@@ -4,3 +4,61 @@ export function isInstalled(apps?: any[], wantedApp?: object): object;
4
4
  export function getUrl(app: object): string;
5
5
  export function getAppDisplayName(app: object, lang: string): string;
6
6
  export function sortApplicationsList(apps: object[], slugsOrder: string[]): object[];
7
+ export function checkEntrypointCondition(entrypointCondition: EntrypointCondition): boolean;
8
+ export function shouldDisplayEntrypoint(entrypoint: Entrypoint): boolean;
9
+ export function selectEntrypoints(entrypoints: Entrypoint[], names: string[]): Entrypoint[];
10
+ export function filterEntrypoints(entrypoints: Entrypoint[]): Entrypoint[];
11
+ export type EntrypointTitle = {
12
+ /**
13
+ * - English title
14
+ */
15
+ en?: string;
16
+ /**
17
+ * - French title
18
+ */
19
+ fr?: string;
20
+ /**
21
+ * - Russian title
22
+ */
23
+ ru?: string;
24
+ /**
25
+ * - Vietnamese title
26
+ */
27
+ vi?: string;
28
+ };
29
+ export type EntrypointCondition = {
30
+ /**
31
+ * - The type of condition (currently only 'flag' is supported)
32
+ */
33
+ type: 'flag';
34
+ /**
35
+ * - The name of the flag
36
+ */
37
+ name: string;
38
+ /**
39
+ * - The expected value of the flag
40
+ */
41
+ value: boolean;
42
+ };
43
+ export type Entrypoint = {
44
+ /**
45
+ * - The unique name of the entrypoint
46
+ */
47
+ name: string;
48
+ /**
49
+ * - Localized titles for the entrypoint
50
+ */
51
+ title: EntrypointTitle;
52
+ /**
53
+ * - The URL hash for navigation
54
+ */
55
+ hash: string;
56
+ /**
57
+ * - Base64 encoded SVG icon
58
+ */
59
+ icon: string;
60
+ /**
61
+ * - Conditions that must be met to display the entrypoint
62
+ */
63
+ conditions?: EntrypointCondition[];
64
+ };