cozy-bar 35.2.22 → 35.3.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.
@@ -25,6 +25,8 @@ var _Bar = _interopRequireDefault(require("./Bar"));
25
25
 
26
26
  var _BarProvider = require("./BarProvider");
27
27
 
28
+ var _PlatformBanners = require("./PlatformBanners");
29
+
28
30
  function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
29
31
 
30
32
  function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
@@ -136,7 +138,7 @@ var BarComponent = function BarComponent(_ref2) {
136
138
  }
137
139
  };
138
140
  var cozyThemeProps = (componentsProps === null || componentsProps === void 0 ? void 0 : componentsProps.CozyTheme) || {};
139
- return /*#__PURE__*/_react.default.createElement(ReactPortal, {
141
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(ReactPortal, {
140
142
  wrapperElement: wrapperElement,
141
143
  setWrapperElement: setWrapperElement
142
144
  }, /*#__PURE__*/_react.default.createElement(_CozyTheme.default, (0, _extends2.default)({}, cozyThemeProps, {
@@ -146,7 +148,7 @@ var BarComponent = function BarComponent(_ref2) {
146
148
  barLeft: barLeft,
147
149
  barCenter: barCenter,
148
150
  barRight: barRight
149
- }))));
151
+ })))), !options.isPublic && /*#__PURE__*/_react.default.createElement(_PlatformBanners.PlatformBanners, null));
150
152
  };
151
153
 
152
154
  exports.BarComponent = BarComponent;
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.PlatformBannersPortal = void 0;
9
+
10
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
11
+
12
+ var _react = require("react");
13
+
14
+ var _reactDom = require("react-dom");
15
+
16
+ var _dom = require("../../dom");
17
+
18
+ var CONTAINER_ID = 'cozy-platform-banners';
19
+ var ACTIVE_CLASS = 'has-platform-banners';
20
+ /**
21
+ * Renders into a container created as the first child of the application node,
22
+ * so the application reflows around the banners rather than the bar's chrome.
23
+ *
24
+ * @param {object} props - Props
25
+ * @param {import('react').ReactNode} props.children - What to render
26
+ * @returns {import('react').ReactPortal|null} The portal, once the container exists
27
+ */
28
+
29
+ var PlatformBannersPortal = function PlatformBannersPortal(_ref) {
30
+ var children = _ref.children;
31
+
32
+ var _useState = (0, _react.useState)(null),
33
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
34
+ container = _useState2[0],
35
+ setContainer = _useState2[1];
36
+
37
+ (0, _react.useLayoutEffect)(function () {
38
+ var appNode = document.querySelector(_dom.APP_SELECTOR);
39
+
40
+ if (!appNode) {
41
+ // eslint-disable-next-line no-console
42
+ console.warn("[cozy-bar] no ".concat(_dom.APP_SELECTOR, " node, platform banners are disabled"));
43
+ return;
44
+ } // Resolved from the DOM, not a ref: React clears its root container on
45
+ // mount, so anything captured earlier points at a detached node.
46
+
47
+
48
+ var node = appNode.querySelector("#".concat(CONTAINER_ID));
49
+
50
+ if (!node) {
51
+ node = document.createElement('div');
52
+ node.id = CONTAINER_ID;
53
+ appNode.insertBefore(node, appNode.firstChild);
54
+ } // eslint-disable-next-line react-hooks/set-state-in-effect
55
+
56
+
57
+ setContainer(node);
58
+ appNode.classList.add(ACTIVE_CLASS);
59
+ return function () {
60
+ return appNode.classList.remove(ACTIVE_CLASS);
61
+ };
62
+ }, []);
63
+ if (!container) return null;
64
+ return /*#__PURE__*/(0, _reactDom.createPortal)(children, container);
65
+ };
66
+
67
+ exports.PlatformBannersPortal = PlatformBannersPortal;
@@ -0,0 +1,171 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.PlatformBanners = void 0;
9
+
10
+ var _useI18n2 = _interopRequireDefault(require("../useI18n"));
11
+
12
+ var _react = _interopRequireDefault(require("react"));
13
+
14
+ var _twakeIcons = require("@linagora/twake-icons");
15
+
16
+ var _Alert = _interopRequireDefault(require("cozy-ui/transpiled/react/Alert"));
17
+
18
+ var _Buttons = _interopRequireDefault(require("cozy-ui/transpiled/react/Buttons"));
19
+
20
+ var _CozyDialogs = require("cozy-ui/transpiled/react/CozyDialogs");
21
+
22
+ var _IconButton = _interopRequireDefault(require("cozy-ui/transpiled/react/IconButton"));
23
+
24
+ var _Typography = _interopRequireDefault(require("cozy-ui/transpiled/react/Typography"));
25
+
26
+ var _Breakpoints = require("cozy-ui/transpiled/react/providers/Breakpoints");
27
+
28
+ var _PlatformBannersPortal = require("./PlatformBannersPortal");
29
+
30
+ var _useBanners2 = require("./useBanners");
31
+
32
+ /** Rendered directly: `Icon` paints one theme colour over the whole glyph. */
33
+ var RESTRICTED = /*#__PURE__*/_react.default.createElement(_twakeIcons.RestrictedWorkspace, {
34
+ width: 100,
35
+ height: 100,
36
+ className: "u-mb-1",
37
+ "aria-hidden": "true"
38
+ });
39
+ /**
40
+ * A banner in the application's own layout, above its content. Polite whatever
41
+ * the severity: the condition outlives the page, so an assertive region would
42
+ * re-interrupt on every navigation.
43
+ */
44
+
45
+
46
+ var PlatformBanner = function PlatformBanner(_ref) {
47
+ var banner = _ref.banner,
48
+ onDismiss = _ref.onDismiss;
49
+
50
+ var _useI18n = (0, _useI18n2.default)(),
51
+ t = _useI18n.t;
52
+
53
+ var action = banner.cta || banner.dismissible ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, banner.cta && /*#__PURE__*/_react.default.createElement(_Buttons.default, {
54
+ variant: "text",
55
+ size: "small",
56
+ label: banner.cta.label,
57
+ component: "a",
58
+ href: banner.cta.url
59
+ }), banner.dismissible && /*#__PURE__*/_react.default.createElement(_IconButton.default, {
60
+ size: "small",
61
+ "aria-label": t('platformBanners.dismiss'),
62
+ onClick: function onClick() {
63
+ return onDismiss(banner);
64
+ }
65
+ }, /*#__PURE__*/_react.default.createElement(_twakeIcons.Icon, {
66
+ icon: _twakeIcons.Cross
67
+ }))) : null;
68
+ return /*#__PURE__*/_react.default.createElement(_Alert.default, {
69
+ role: "status",
70
+ severity: banner.severity,
71
+ "data-banner-id": banner.bannerId,
72
+ action: action // The host application may cancel the context menu across its content.
73
+ ,
74
+ onContextMenu: function onContextMenu(event) {
75
+ return event.stopPropagation();
76
+ }
77
+ }, /*#__PURE__*/_react.default.createElement("span", {
78
+ lang: banner.lang,
79
+ className: "coz-platform-banner-text"
80
+ }, banner.text));
81
+ };
82
+ /**
83
+ * A banner that interrupts rather than informs.
84
+ *
85
+ * Always escapable: a dialog with no call to action and no dismiss control
86
+ * would cover the application for good. Wider than the Figma's 480 except on
87
+ * mobile, where that size goes full screen and clips the actions. Named from
88
+ * its text when there is no heading, since cozy-ui's `aria-labelledby` then
89
+ * points at an empty block.
90
+ */
91
+
92
+
93
+ var BlockingDialog = function BlockingDialog(_ref2) {
94
+ var banner = _ref2.banner,
95
+ onDismiss = _ref2.onDismiss;
96
+
97
+ var _useBreakpoints = (0, _Breakpoints.useBreakpoints)(),
98
+ isMobile = _useBreakpoints.isMobile;
99
+
100
+ var illustration = banner.category === 'billing' ? RESTRICTED : undefined;
101
+ var dismissible = banner.dismissible || !banner.cta;
102
+ var Dialog = illustration ? _CozyDialogs.IllustrationDialog : _CozyDialogs.ConfirmDialog; // A stray backdrop click is not the user asking, and a dismissal is recorded
103
+ // server side for every device.
104
+
105
+ var onClose = function onClose(event, reason) {
106
+ if (reason !== 'backdropClick') onDismiss(banner);
107
+ };
108
+
109
+ return /*#__PURE__*/_react.default.createElement(Dialog, {
110
+ open: true,
111
+ "data-banner-id": banner.bannerId,
112
+ size: isMobile ? 'small' : 'medium',
113
+ actionsLayout: isMobile ? 'column' : undefined,
114
+ disableEscapeKeyDown: !dismissible,
115
+ onClose: dismissible ? onClose : undefined,
116
+ PaperProps: banner.title ? undefined : {
117
+ 'aria-label': banner.text
118
+ },
119
+ title: banner.title || illustration ? /*#__PURE__*/_react.default.createElement("div", {
120
+ className: illustration ? 'u-flex u-flex-column u-flex-items-center u-ta-center' : undefined
121
+ }, illustration, /*#__PURE__*/_react.default.createElement("span", {
122
+ lang: banner.lang
123
+ }, banner.title)) : null,
124
+ content: /*#__PURE__*/_react.default.createElement(_Typography.default, {
125
+ lang: banner.lang,
126
+ className: "coz-platform-banner-text"
127
+ }, banner.text),
128
+ actions: banner.cta && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, banner.secondaryCta && /*#__PURE__*/_react.default.createElement(_Buttons.default, {
129
+ variant: "secondary",
130
+ label: banner.secondaryCta.label,
131
+ component: "a",
132
+ href: banner.secondaryCta.url
133
+ }), /*#__PURE__*/_react.default.createElement(_Buttons.default, {
134
+ label: banner.cta.label,
135
+ component: "a",
136
+ href: banner.cta.url
137
+ }))
138
+ });
139
+ };
140
+ /**
141
+ * Platform banners, rendered by the bar into the application. Only the inline
142
+ * ones reach the portal; MUI puts the dialog on the body.
143
+ *
144
+ * @returns {import('react').ReactNode} The banners and the blocking dialog
145
+ */
146
+
147
+
148
+ var PlatformBanners = function PlatformBanners() {
149
+ var _useBanners = (0, _useBanners2.useBanners)(),
150
+ banners = _useBanners.banners,
151
+ dismiss = _useBanners.dismiss;
152
+
153
+ var inline = banners.filter(function (banner) {
154
+ return banner.surface !== 'modal';
155
+ });
156
+ var blocking = banners.find(function (banner) {
157
+ return banner.surface === 'modal';
158
+ });
159
+ return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, inline.length > 0 && /*#__PURE__*/_react.default.createElement(_PlatformBannersPortal.PlatformBannersPortal, null, inline.map(function (banner) {
160
+ return /*#__PURE__*/_react.default.createElement(PlatformBanner, {
161
+ key: banner.bannerId,
162
+ banner: banner,
163
+ onDismiss: dismiss
164
+ });
165
+ })), blocking && /*#__PURE__*/_react.default.createElement(BlockingDialog, {
166
+ banner: blocking,
167
+ onDismiss: dismiss
168
+ }));
169
+ };
170
+
171
+ exports.PlatformBanners = PlatformBanners;
@@ -0,0 +1,139 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.useBanners = void 0;
9
+
10
+ var _regenerator = _interopRequireDefault(require("@babel/runtime/regenerator"));
11
+
12
+ var _asyncToGenerator2 = _interopRequireDefault(require("@babel/runtime/helpers/asyncToGenerator"));
13
+
14
+ var _slicedToArray2 = _interopRequireDefault(require("@babel/runtime/helpers/slicedToArray"));
15
+
16
+ var _react = require("react");
17
+
18
+ var _cozyClient = require("cozy-client");
19
+
20
+ var _banner = require("cozy-client/dist/models/banner");
21
+
22
+ var POLL_INTERVAL_MS = 5 * 60 * 1000;
23
+ /**
24
+ * The banners to display, kept up to date. cozy-client owns the reading rules;
25
+ * this only owns when to read and how to record a dismissal.
26
+ *
27
+ * @returns {{banners: object[], dismiss: Function}} The banners and a dismisser
28
+ */
29
+
30
+ var useBanners = function useBanners() {
31
+ var client = (0, _cozyClient.useClient)();
32
+
33
+ var _useState = (0, _react.useState)([]),
34
+ _useState2 = (0, _slicedToArray2.default)(_useState, 2),
35
+ banners = _useState2[0],
36
+ setBanners = _useState2[1];
37
+
38
+ var generation = (0, _react.useRef)(0);
39
+ var read = (0, _react.useCallback)( /*#__PURE__*/(0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee() {
40
+ var startedAt, next;
41
+ return _regenerator.default.wrap(function _callee$(_context) {
42
+ while (1) {
43
+ switch (_context.prev = _context.next) {
44
+ case 0:
45
+ if (client) {
46
+ _context.next = 2;
47
+ break;
48
+ }
49
+
50
+ return _context.abrupt("return");
51
+
52
+ case 2:
53
+ startedAt = generation.current;
54
+ _context.prev = 3;
55
+ _context.next = 6;
56
+ return (0, _banner.getActiveBanners)(client);
57
+
58
+ case 6:
59
+ next = _context.sent;
60
+ if (generation.current === startedAt) setBanners(next);
61
+ _context.next = 13;
62
+ break;
63
+
64
+ case 10:
65
+ _context.prev = 10;
66
+ _context.t0 = _context["catch"](3);
67
+ // eslint-disable-next-line no-console
68
+ console.warn('[cozy-bar] could not read the platform banners', _context.t0);
69
+
70
+ case 13:
71
+ case "end":
72
+ return _context.stop();
73
+ }
74
+ }
75
+ }, _callee, null, [[3, 10]]);
76
+ })), [client]);
77
+ (0, _react.useEffect)(function () {
78
+ var readIfVisible = function readIfVisible() {
79
+ if (document.visibilityState !== 'visible') return;
80
+ read();
81
+ }; // eslint-disable-next-line react-hooks/set-state-in-effect
82
+
83
+
84
+ read();
85
+ var id = setInterval(readIfVisible, POLL_INTERVAL_MS);
86
+ document.addEventListener('visibilitychange', readIfVisible);
87
+ return function () {
88
+ clearInterval(id);
89
+ document.removeEventListener('visibilitychange', readIfVisible);
90
+ };
91
+ }, [read]);
92
+ var dismiss = (0, _react.useCallback)( /*#__PURE__*/function () {
93
+ var _ref2 = (0, _asyncToGenerator2.default)( /*#__PURE__*/_regenerator.default.mark(function _callee2(banner) {
94
+ return _regenerator.default.wrap(function _callee2$(_context2) {
95
+ while (1) {
96
+ switch (_context2.prev = _context2.next) {
97
+ case 0:
98
+ // Hidden before the round trip; the bump stops an in-flight read
99
+ // restoring it.
100
+ generation.current += 1;
101
+ setBanners(function (current) {
102
+ return current.filter(function (b) {
103
+ return b.bannerId !== banner.bannerId;
104
+ });
105
+ });
106
+ _context2.prev = 2;
107
+ _context2.next = 5;
108
+ return (0, _banner.dismiss)(client, banner);
109
+
110
+ case 5:
111
+ _context2.next = 11;
112
+ break;
113
+
114
+ case 7:
115
+ _context2.prev = 7;
116
+ _context2.t0 = _context2["catch"](2);
117
+ // eslint-disable-next-line no-console
118
+ console.warn('[cozy-bar] could not record the dismissal', _context2.t0);
119
+ read();
120
+
121
+ case 11:
122
+ case "end":
123
+ return _context2.stop();
124
+ }
125
+ }
126
+ }, _callee2, null, [[2, 7]]);
127
+ }));
128
+
129
+ return function (_x) {
130
+ return _ref2.apply(this, arguments);
131
+ };
132
+ }(), [client, read]);
133
+ return {
134
+ banners: banners,
135
+ dismiss: dismiss
136
+ };
137
+ };
138
+
139
+ exports.useBanners = useBanners;
@@ -57,5 +57,8 @@
57
57
  "storageAvailable": "%{smart_count} GB available",
58
58
  "emailDomainNotActive": "Email not active",
59
59
  "logOut": "Log out"
60
+ },
61
+ "platformBanners": {
62
+ "dismiss": "Dismiss"
60
63
  }
61
64
  }
@@ -57,5 +57,8 @@
57
57
  "storageAvailable": "%{smart_count} Go disponible",
58
58
  "emailDomainNotActive": "E-mail inactif",
59
59
  "logOut": "Se déconnecter"
60
+ },
61
+ "platformBanners": {
62
+ "dismiss": "Masquer"
60
63
  }
61
64
  }
@@ -57,5 +57,8 @@
57
57
  "storageAvailable": "Доступно %{smart_count} ГБ",
58
58
  "emailDomainNotActive": "Электронная почта неактивна",
59
59
  "logOut": "Выйти"
60
+ },
61
+ "platformBanners": {
62
+ "dismiss": "Скрыть"
60
63
  }
61
64
  }
@@ -57,6 +57,9 @@
57
57
  "storageAvailable": "Còn trống %{smart_count} GB",
58
58
  "emailDomainNotActive": "Địa chỉ email chưa được kích hoạt",
59
59
  "logOut": "Đăng xuất"
60
+ },
61
+ "platformBanners": {
62
+ "dismiss": "Ẩn"
60
63
  }
61
64
  }
62
65
 
@@ -62,3 +62,44 @@
62
62
  flex-shrink: 0;
63
63
  max-width: 10rem;
64
64
  }
65
+
66
+ /* Platform banners (io.cozy.banners), injected into the application's layout. */
67
+
68
+ /* No height: the node is already sized by its parent, and 100% ignores the bar
69
+ above it, pushing the application below the fold. */
70
+ [role=application].has-platform-banners {
71
+ display: flex;
72
+ flex-direction: column;
73
+ }
74
+
75
+ /* Class specificity, so an application can still override it. The container is
76
+ exempted by the id rule below. */
77
+ [role=application].has-platform-banners > * {
78
+ flex: 1 1 auto;
79
+ min-height: 0;
80
+ }
81
+
82
+ /* Inset and stacked per the design. Fixed basis, or a tall application
83
+ squashes the stack into a sliver. */
84
+ #cozy-platform-banners {
85
+ flex: 0 0 auto;
86
+ min-height: auto;
87
+ display: flex;
88
+ flex-direction: column;
89
+ gap: 1rem;
90
+ padding: 1rem 1rem 0;
91
+ }
92
+
93
+ #cozy-platform-banners:empty {
94
+ display: none;
95
+ }
96
+
97
+ /* Or a long message squeezes the slot until the call to action wraps. */
98
+ #cozy-platform-banners .MuiAlert-action {
99
+ flex-shrink: 0;
100
+ }
101
+
102
+ /* A newline the stack wrote is a line break the reader is meant to see. */
103
+ .coz-platform-banner-text {
104
+ white-space: pre-line;
105
+ }
@@ -284,6 +284,47 @@
284
284
  max-width: 10rem;
285
285
  }
286
286
 
287
+ /* Platform banners (io.cozy.banners), injected into the application's layout. */
288
+
289
+ /* No height: the node is already sized by its parent, and 100% ignores the bar
290
+ above it, pushing the application below the fold. */
291
+ [role=application].has-platform-banners {
292
+ display: flex;
293
+ flex-direction: column;
294
+ }
295
+
296
+ /* Class specificity, so an application can still override it. The container is
297
+ exempted by the id rule below. */
298
+ [role=application].has-platform-banners > * {
299
+ flex: 1 1 auto;
300
+ min-height: 0;
301
+ }
302
+
303
+ /* Inset and stacked per the design. Fixed basis, or a tall application
304
+ squashes the stack into a sliver. */
305
+ #cozy-platform-banners {
306
+ flex: 0 0 auto;
307
+ min-height: auto;
308
+ display: flex;
309
+ flex-direction: column;
310
+ gap: 1rem;
311
+ padding: 1rem 1rem 0;
312
+ }
313
+
314
+ #cozy-platform-banners:empty {
315
+ display: none;
316
+ }
317
+
318
+ /* Or a long message squeezes the slot until the call to action wraps. */
319
+ #cozy-platform-banners .MuiAlert-action {
320
+ flex-shrink: 0;
321
+ }
322
+
323
+ /* A newline the stack wrote is a line break the reader is meant to see. */
324
+ .coz-platform-banner-text {
325
+ white-space: pre-line;
326
+ }
327
+
287
328
  [role=banner] .coz-nav {
288
329
  display: flex;
289
330
  margin: 0;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cozy-bar",
3
- "version": "35.2.22",
3
+ "version": "35.3.0",
4
4
  "description": "cozy-bar.js library, a small lib provided by cozy-stack to inject the Cozy-bar component into each app",
5
5
  "main": "dist/index.js",
6
6
  "author": "Cozy Cloud <contact@cozycloud.cc> (https://cozy.io/)",
@@ -31,11 +31,11 @@
31
31
  "@babel/cli": "7.16.8",
32
32
  "@babel/core": "7.16.12",
33
33
  "@cozy/minilog": "^1.0.0",
34
- "@linagora/twake-icons": "^2.6.6",
34
+ "@linagora/twake-icons": "^2.10.0",
35
35
  "@testing-library/jest-dom": "5.17.0",
36
36
  "@testing-library/react": "12.1.5",
37
37
  "babel-preset-cozy-app": "^2.8.4",
38
- "cozy-client": "^60.21.0",
38
+ "cozy-client": "^60.32.0",
39
39
  "cozy-dataproxy-lib": "^4.15.6",
40
40
  "cozy-device-helper": "2.6.0",
41
41
  "cozy-flags": "^4.6.1",
@@ -60,8 +60,8 @@
60
60
  },
61
61
  "peerDependencies": {
62
62
  "@cozy/minilog": ">=1.0.0",
63
- "@linagora/twake-icons": ">=2.6.6",
64
- "cozy-client": ">=60.21.0",
63
+ "@linagora/twake-icons": ">=2.10.0",
64
+ "cozy-client": ">=60.32.0",
65
65
  "cozy-dataproxy-lib": ">=4.1.0",
66
66
  "cozy-device-helper": ">=2.6.0",
67
67
  "cozy-flags": ">=4.6.1",
@@ -75,5 +75,5 @@
75
75
  "react-router-dom": ">=6.14.2",
76
76
  "twake-i18n": ">=0.3.0"
77
77
  },
78
- "gitHead": "319c4890af0fbee641e25a2cb7c1bd2501b57024"
78
+ "gitHead": "fd478feb7f75253be1cbc3bf79f15cfe7c132ab3"
79
79
  }