cozy-sharing 30.2.0 → 30.2.2
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/CHANGELOG.md +10 -0
- package/dist/components/ShareByLink.js +33 -26
- package/dist/components/ShareRestrictionModal/ShareRestrictionModal.js +51 -64
- package/dist/components/ShareRestrictionModal/helpers.js +61 -12
- package/package.json +3 -3
- package/src/components/ShareByLink.jsx +21 -10
- package/src/components/ShareRestrictionModal/ShareRestrictionModal.jsx +42 -38
- package/src/components/ShareRestrictionModal/helpers.js +23 -4
package/CHANGELOG.md
CHANGED
|
@@ -3,6 +3,16 @@
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
5
|
|
|
6
|
+
## [30.2.2](https://github.com/cozy/cozy-libs/compare/cozy-sharing@30.2.1...cozy-sharing@30.2.2) (2026-04-22)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package cozy-sharing
|
|
9
|
+
|
|
10
|
+
## [30.2.1](https://github.com/cozy/cozy-libs/compare/cozy-sharing@30.2.0...cozy-sharing@30.2.1) (2026-04-20)
|
|
11
|
+
|
|
12
|
+
### Bug Fixes
|
|
13
|
+
|
|
14
|
+
- **cozy-sharing:** Preserve user gesture for Safari clipboard writes ([c3e9069](https://github.com/cozy/cozy-libs/commit/c3e9069e250880b9d6640c8ae7529b987af497dc))
|
|
15
|
+
|
|
6
16
|
# [30.2.0](https://github.com/cozy/cozy-libs/compare/cozy-sharing@30.1.1...cozy-sharing@30.2.0) (2026-04-20)
|
|
7
17
|
|
|
8
18
|
### Features
|
|
@@ -118,48 +118,55 @@ var ShareByLink = function ShareByLink(_ref) {
|
|
|
118
118
|
|
|
119
119
|
var generateLinkAndCopyLinkToClipboard = /*#__PURE__*/function () {
|
|
120
120
|
var _ref3 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
121
|
-
var
|
|
121
|
+
var generatedLink;
|
|
122
122
|
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
123
123
|
while (1) switch (_context2.prev = _context2.next) {
|
|
124
124
|
case 0:
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (linkToCopy) {
|
|
129
|
-
_context2.next = 6;
|
|
125
|
+
if (!link) {
|
|
126
|
+
_context2.next = 4;
|
|
130
127
|
break;
|
|
131
128
|
}
|
|
132
129
|
|
|
133
|
-
_context2.next =
|
|
134
|
-
return
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
130
|
+
_context2.next = 3;
|
|
131
|
+
return copyToClipboard(link, {
|
|
132
|
+
t: t,
|
|
133
|
+
showAlert: showAlert
|
|
134
|
+
});
|
|
138
135
|
|
|
139
|
-
case
|
|
140
|
-
|
|
141
|
-
_context2.next = 12;
|
|
142
|
-
break;
|
|
143
|
-
}
|
|
136
|
+
case 3:
|
|
137
|
+
return _context2.abrupt("return");
|
|
144
138
|
|
|
145
|
-
|
|
146
|
-
|
|
139
|
+
case 4:
|
|
140
|
+
// Safari: the clipboard API must be invoked synchronously within the
|
|
141
|
+
// click handler, so we pass the pending link to `copyToClipboard`.
|
|
142
|
+
// The resolved URL is captured here so we can branch on success after
|
|
143
|
+
// the copy has completed, without re-awaiting the promise.
|
|
144
|
+
generatedLink = null;
|
|
145
|
+
_context2.next = 7;
|
|
146
|
+
return copyToClipboard(handleGenerateLink().then(function (generated) {
|
|
147
|
+
generatedLink = generated;
|
|
148
|
+
if (!generated) throw new Error('link-generation-failed');
|
|
149
|
+
return generated;
|
|
150
|
+
}), {
|
|
147
151
|
t: t,
|
|
148
152
|
showAlert: showAlert
|
|
149
153
|
});
|
|
150
154
|
|
|
151
|
-
case
|
|
152
|
-
if (
|
|
153
|
-
|
|
155
|
+
case 7:
|
|
156
|
+
if (generatedLink) {
|
|
157
|
+
_context2.next = 10;
|
|
158
|
+
break;
|
|
154
159
|
}
|
|
155
160
|
|
|
156
|
-
_context2.next = 13;
|
|
157
|
-
break;
|
|
158
|
-
|
|
159
|
-
case 12:
|
|
160
161
|
showGenericError();
|
|
162
|
+
return _context2.abrupt("return");
|
|
161
163
|
|
|
162
|
-
case
|
|
164
|
+
case 10:
|
|
165
|
+
if (autoOpenShareRestriction) {
|
|
166
|
+
toggleEditDialogOpen();
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
case 11:
|
|
163
170
|
case "end":
|
|
164
171
|
return _context2.stop();
|
|
165
172
|
}
|
|
@@ -91,96 +91,83 @@ export var ShareRestrictionModal = function ShareRestrictionModal(_ref) {
|
|
|
91
91
|
|
|
92
92
|
var handleClick = /*#__PURE__*/function () {
|
|
93
93
|
var _ref2 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee() {
|
|
94
|
-
var
|
|
95
|
-
|
|
94
|
+
var permsPromise, urlPromise;
|
|
96
95
|
return _regeneratorRuntime.wrap(function _callee$(_context) {
|
|
97
96
|
while (1) switch (_context.prev = _context.next) {
|
|
98
97
|
case 0:
|
|
99
|
-
setLoading(true); //
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
_context.next = 13;
|
|
103
|
-
break;
|
|
104
|
-
}
|
|
98
|
+
setLoading(true); // The clipboard write must be initiated synchronously within the click
|
|
99
|
+
// handler for Safari to honor the user gesture; we pass a pending blob
|
|
100
|
+
// whose content resolves after the permission round-trip.
|
|
105
101
|
|
|
106
|
-
|
|
107
|
-
_context.next = 5;
|
|
108
|
-
return createPermissions({
|
|
102
|
+
permsPromise = hasSharingLink ? updatePermissions({
|
|
109
103
|
file: file,
|
|
110
104
|
t: t,
|
|
111
|
-
|
|
105
|
+
dateToggle: dateToggle,
|
|
106
|
+
selectedDate: selectedDate,
|
|
107
|
+
passwordToggle: passwordToggle,
|
|
112
108
|
password: password,
|
|
113
109
|
editingRights: editingRights,
|
|
114
110
|
documentType: documentType,
|
|
115
|
-
|
|
116
|
-
showAlert: showAlert
|
|
117
|
-
});
|
|
118
|
-
|
|
119
|
-
case 5:
|
|
120
|
-
_yield$createPermissi2 = _context.sent;
|
|
121
|
-
perms = _yield$createPermissi2.data;
|
|
122
|
-
url = generateWebLink({
|
|
123
|
-
cozyUrl: client.getStackClient().uri,
|
|
124
|
-
searchParams: [['sharecode', perms.attributes.shortcodes.code]],
|
|
125
|
-
pathname: '/public',
|
|
126
|
-
slug: getAppSlugFromDocumentType({
|
|
127
|
-
documentType: documentType
|
|
128
|
-
}),
|
|
129
|
-
subDomainType: client.capabilities.flat_subdomains ? 'flat' : 'nested'
|
|
130
|
-
});
|
|
131
|
-
_context.next = 10;
|
|
132
|
-
return copyToClipboard(url, {
|
|
133
|
-
t: t,
|
|
111
|
+
updateDocumentPermissions: updateDocumentPermissions,
|
|
134
112
|
showAlert: showAlert
|
|
135
|
-
})
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
onClose();
|
|
139
|
-
_context.next = 22;
|
|
140
|
-
break;
|
|
113
|
+
}).then(function (_ref3) {
|
|
114
|
+
var _ref4 = _slicedToArray(_ref3, 1),
|
|
115
|
+
perms = _ref4[0].data;
|
|
141
116
|
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
return updatePermissions({
|
|
117
|
+
return perms;
|
|
118
|
+
}) : createPermissions({
|
|
145
119
|
file: file,
|
|
146
120
|
t: t,
|
|
147
|
-
|
|
148
|
-
selectedDate: selectedDate,
|
|
149
|
-
passwordToggle: passwordToggle,
|
|
121
|
+
ttl: makeTTL(dateToggle && selectedDate),
|
|
150
122
|
password: password,
|
|
151
123
|
editingRights: editingRights,
|
|
152
124
|
documentType: documentType,
|
|
153
|
-
|
|
125
|
+
shareByLink: shareByLink,
|
|
154
126
|
showAlert: showAlert
|
|
127
|
+
}).then(function (_ref5) {
|
|
128
|
+
var perms = _ref5.data;
|
|
129
|
+
return perms;
|
|
155
130
|
});
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
documentType: documentType
|
|
167
|
-
}),
|
|
168
|
-
subDomainType: client.capabilities.flat_subdomains ? 'flat' : 'nested'
|
|
131
|
+
urlPromise = permsPromise.then(function (perms) {
|
|
132
|
+
return generateWebLink({
|
|
133
|
+
cozyUrl: client.getStackClient().uri,
|
|
134
|
+
searchParams: [['sharecode', perms.attributes.shortcodes.code]],
|
|
135
|
+
pathname: '/public',
|
|
136
|
+
slug: getAppSlugFromDocumentType({
|
|
137
|
+
documentType: documentType
|
|
138
|
+
}),
|
|
139
|
+
subDomainType: client.capabilities.flat_subdomains ? 'flat' : 'nested'
|
|
140
|
+
});
|
|
169
141
|
});
|
|
170
|
-
_context.next =
|
|
171
|
-
return copyToClipboard(
|
|
142
|
+
_context.next = 5;
|
|
143
|
+
return copyToClipboard(urlPromise, {
|
|
172
144
|
t: t,
|
|
173
145
|
showAlert: showAlert
|
|
174
146
|
});
|
|
175
147
|
|
|
176
|
-
case
|
|
148
|
+
case 5:
|
|
149
|
+
_context.prev = 5;
|
|
150
|
+
_context.next = 8;
|
|
151
|
+
return permsPromise;
|
|
152
|
+
|
|
153
|
+
case 8:
|
|
154
|
+
_context.next = 14;
|
|
155
|
+
break;
|
|
156
|
+
|
|
157
|
+
case 10:
|
|
158
|
+
_context.prev = 10;
|
|
159
|
+
_context.t0 = _context["catch"](5);
|
|
160
|
+
setLoading(false);
|
|
161
|
+
return _context.abrupt("return");
|
|
162
|
+
|
|
163
|
+
case 14:
|
|
177
164
|
onClose();
|
|
178
165
|
|
|
179
|
-
case
|
|
166
|
+
case 15:
|
|
180
167
|
case "end":
|
|
181
168
|
return _context.stop();
|
|
182
169
|
}
|
|
183
|
-
}, _callee);
|
|
170
|
+
}, _callee, null, [[5, 10]]);
|
|
184
171
|
}));
|
|
185
172
|
|
|
186
173
|
return function handleClick() {
|
|
@@ -189,7 +176,7 @@ export var ShareRestrictionModal = function ShareRestrictionModal(_ref) {
|
|
|
189
176
|
}();
|
|
190
177
|
|
|
191
178
|
var handleRevokeLink = /*#__PURE__*/function () {
|
|
192
|
-
var
|
|
179
|
+
var _ref6 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
|
|
193
180
|
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
194
181
|
while (1) switch (_context2.prev = _context2.next) {
|
|
195
182
|
case 0:
|
|
@@ -214,7 +201,7 @@ export var ShareRestrictionModal = function ShareRestrictionModal(_ref) {
|
|
|
214
201
|
}));
|
|
215
202
|
|
|
216
203
|
return function handleRevokeLink() {
|
|
217
|
-
return
|
|
204
|
+
return _ref6.apply(this, arguments);
|
|
218
205
|
};
|
|
219
206
|
}();
|
|
220
207
|
|
|
@@ -115,11 +115,19 @@ export var generateShareLinkFromFile = function generateShareLinkFromFile(_ref3)
|
|
|
115
115
|
});
|
|
116
116
|
};
|
|
117
117
|
/**
|
|
118
|
-
* Copy a
|
|
118
|
+
* Copy a value to the clipboard.
|
|
119
119
|
*
|
|
120
|
-
*
|
|
120
|
+
* Accepts a resolved string or a `Promise<string>`. The promise form is
|
|
121
|
+
* required when the value depends on a prior async step (e.g. creating a
|
|
122
|
+
* sharing link) from within a click handler: Safari drops the user-gesture
|
|
123
|
+
* context across any `await`, so `navigator.clipboard.writeText` called after
|
|
124
|
+
* an awaited call throws `NotAllowedError`. Passing a pending blob to
|
|
125
|
+
* `ClipboardItem` lets the clipboard API be invoked synchronously while the
|
|
126
|
+
* content is resolved later.
|
|
127
|
+
*
|
|
128
|
+
* @param {string | Promise<string>} value - Value to copy
|
|
121
129
|
* @param {object} [options]
|
|
122
|
-
* @param {
|
|
130
|
+
* @param {Function} options.t - Translation function
|
|
123
131
|
* @param {Function} options.showAlert - Function to display an alert
|
|
124
132
|
*/
|
|
125
133
|
|
|
@@ -128,6 +136,7 @@ export var copyToClipboard = /*#__PURE__*/function () {
|
|
|
128
136
|
var _ref5,
|
|
129
137
|
t,
|
|
130
138
|
showAlert,
|
|
139
|
+
blobPromise,
|
|
131
140
|
_args2 = arguments;
|
|
132
141
|
|
|
133
142
|
return _regeneratorRuntime.wrap(function _callee2$(_context2) {
|
|
@@ -144,33 +153,73 @@ export var copyToClipboard = /*#__PURE__*/function () {
|
|
|
144
153
|
|
|
145
154
|
case 3:
|
|
146
155
|
_context2.prev = 3;
|
|
147
|
-
|
|
156
|
+
|
|
157
|
+
if (!(typeof value === 'string')) {
|
|
158
|
+
_context2.next = 9;
|
|
159
|
+
break;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
_context2.next = 7;
|
|
148
163
|
return navigator.clipboard.writeText(value);
|
|
149
164
|
|
|
150
|
-
case
|
|
165
|
+
case 7:
|
|
166
|
+
_context2.next = 21;
|
|
167
|
+
break;
|
|
168
|
+
|
|
169
|
+
case 9:
|
|
170
|
+
if (!(typeof ClipboardItem !== 'undefined')) {
|
|
171
|
+
_context2.next = 15;
|
|
172
|
+
break;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
blobPromise = Promise.resolve(value).then(function (text) {
|
|
176
|
+
return new Blob([text], {
|
|
177
|
+
type: 'text/plain'
|
|
178
|
+
});
|
|
179
|
+
});
|
|
180
|
+
_context2.next = 13;
|
|
181
|
+
return navigator.clipboard.write([new ClipboardItem({
|
|
182
|
+
'text/plain': blobPromise
|
|
183
|
+
})]);
|
|
184
|
+
|
|
185
|
+
case 13:
|
|
186
|
+
_context2.next = 21;
|
|
187
|
+
break;
|
|
188
|
+
|
|
189
|
+
case 15:
|
|
190
|
+
_context2.t0 = navigator.clipboard;
|
|
191
|
+
_context2.next = 18;
|
|
192
|
+
return value;
|
|
193
|
+
|
|
194
|
+
case 18:
|
|
195
|
+
_context2.t1 = _context2.sent;
|
|
196
|
+
_context2.next = 21;
|
|
197
|
+
return _context2.t0.writeText.call(_context2.t0, _context2.t1);
|
|
198
|
+
|
|
199
|
+
case 21:
|
|
151
200
|
showAlert({
|
|
152
201
|
message: t('copyReminderContent.success'),
|
|
153
202
|
severity: 'success',
|
|
154
203
|
variant: 'filled'
|
|
155
204
|
});
|
|
156
|
-
_context2.next =
|
|
205
|
+
_context2.next = 28;
|
|
157
206
|
break;
|
|
158
207
|
|
|
159
|
-
case
|
|
160
|
-
_context2.prev =
|
|
161
|
-
_context2.
|
|
208
|
+
case 24:
|
|
209
|
+
_context2.prev = 24;
|
|
210
|
+
_context2.t2 = _context2["catch"](3);
|
|
162
211
|
showAlert({
|
|
163
212
|
message: t('copyReminderContent.error'),
|
|
164
213
|
severity: 'error',
|
|
165
214
|
variant: 'filled'
|
|
166
215
|
});
|
|
167
|
-
log.error("Error in 'copyToClipboard' function when trying to copy to clipboard", _context2.
|
|
216
|
+
log.error("Error in 'copyToClipboard' function when trying to copy to clipboard", _context2.t2);
|
|
168
217
|
|
|
169
|
-
case
|
|
218
|
+
case 28:
|
|
170
219
|
case "end":
|
|
171
220
|
return _context2.stop();
|
|
172
221
|
}
|
|
173
|
-
}, _callee2, null, [[3,
|
|
222
|
+
}, _callee2, null, [[3, 24]]);
|
|
174
223
|
}));
|
|
175
224
|
|
|
176
225
|
return function copyToClipboard(_x2) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cozy-sharing",
|
|
3
|
-
"version": "30.2.
|
|
3
|
+
"version": "30.2.2",
|
|
4
4
|
"description": "Provides sharing login for React applications.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"author": "Cozy",
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
"cozy-intent": "^2.31.1",
|
|
60
60
|
"cozy-minilog": "^3.10.1",
|
|
61
61
|
"cozy-ui": "^138.1.0",
|
|
62
|
-
"cozy-ui-plus": "^7.
|
|
62
|
+
"cozy-ui-plus": "^7.1.0",
|
|
63
63
|
"jest": "30.3.0",
|
|
64
64
|
"jest-environment-jsdom": "30.3.0",
|
|
65
65
|
"react": "16.12.0",
|
|
@@ -84,5 +84,5 @@
|
|
|
84
84
|
"sideEffects": [
|
|
85
85
|
"*.css"
|
|
86
86
|
],
|
|
87
|
-
"gitHead": "
|
|
87
|
+
"gitHead": "54d377d08003a9d2eb2bd96f9eeb87d27637d841"
|
|
88
88
|
}
|
|
@@ -75,18 +75,29 @@ const ShareByLink = ({
|
|
|
75
75
|
}
|
|
76
76
|
|
|
77
77
|
const generateLinkAndCopyLinkToClipboard = async () => {
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
linkToCopy = await handleGenerateLink()
|
|
78
|
+
if (link) {
|
|
79
|
+
await copyToClipboard(link, { t, showAlert })
|
|
80
|
+
return
|
|
82
81
|
}
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
82
|
+
// Safari: the clipboard API must be invoked synchronously within the
|
|
83
|
+
// click handler, so we pass the pending link to `copyToClipboard`.
|
|
84
|
+
// The resolved URL is captured here so we can branch on success after
|
|
85
|
+
// the copy has completed, without re-awaiting the promise.
|
|
86
|
+
let generatedLink = null
|
|
87
|
+
await copyToClipboard(
|
|
88
|
+
handleGenerateLink().then(generated => {
|
|
89
|
+
generatedLink = generated
|
|
90
|
+
if (!generated) throw new Error('link-generation-failed')
|
|
91
|
+
return generated
|
|
92
|
+
}),
|
|
93
|
+
{ t, showAlert }
|
|
94
|
+
)
|
|
95
|
+
if (!generatedLink) {
|
|
89
96
|
showGenericError()
|
|
97
|
+
return
|
|
98
|
+
}
|
|
99
|
+
if (autoOpenShareRestriction) {
|
|
100
|
+
toggleEditDialogOpen()
|
|
90
101
|
}
|
|
91
102
|
}
|
|
92
103
|
|
|
@@ -77,51 +77,55 @@ export const ShareRestrictionModal = ({ file, onClose }) => {
|
|
|
77
77
|
|
|
78
78
|
const handleClick = async () => {
|
|
79
79
|
setLoading(true)
|
|
80
|
-
//
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
password,
|
|
110
|
-
editingRights,
|
|
111
|
-
documentType,
|
|
112
|
-
updateDocumentPermissions,
|
|
113
|
-
showAlert
|
|
114
|
-
})
|
|
115
|
-
const url = generateWebLink({
|
|
80
|
+
// The clipboard write must be initiated synchronously within the click
|
|
81
|
+
// handler for Safari to honor the user gesture; we pass a pending blob
|
|
82
|
+
// whose content resolves after the permission round-trip.
|
|
83
|
+
const permsPromise = hasSharingLink
|
|
84
|
+
? updatePermissions({
|
|
85
|
+
file,
|
|
86
|
+
t,
|
|
87
|
+
dateToggle,
|
|
88
|
+
selectedDate,
|
|
89
|
+
passwordToggle,
|
|
90
|
+
password,
|
|
91
|
+
editingRights,
|
|
92
|
+
documentType,
|
|
93
|
+
updateDocumentPermissions,
|
|
94
|
+
showAlert
|
|
95
|
+
}).then(([{ data: perms }]) => perms)
|
|
96
|
+
: createPermissions({
|
|
97
|
+
file,
|
|
98
|
+
t,
|
|
99
|
+
ttl: makeTTL(dateToggle && selectedDate),
|
|
100
|
+
password,
|
|
101
|
+
editingRights,
|
|
102
|
+
documentType,
|
|
103
|
+
shareByLink,
|
|
104
|
+
showAlert
|
|
105
|
+
}).then(({ data: perms }) => perms)
|
|
106
|
+
|
|
107
|
+
const urlPromise = permsPromise.then(perms =>
|
|
108
|
+
generateWebLink({
|
|
116
109
|
cozyUrl: client.getStackClient().uri,
|
|
117
110
|
searchParams: [['sharecode', perms.attributes.shortcodes.code]],
|
|
118
111
|
pathname: '/public',
|
|
119
112
|
slug: getAppSlugFromDocumentType({ documentType }),
|
|
120
113
|
subDomainType: client.capabilities.flat_subdomains ? 'flat' : 'nested'
|
|
121
114
|
})
|
|
122
|
-
|
|
123
|
-
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
await copyToClipboard(urlPromise, { t, showAlert })
|
|
118
|
+
try {
|
|
119
|
+
// Observe the permission result so we can keep the modal open (and
|
|
120
|
+
// preserve the user's date / password / editing-rights inputs) if
|
|
121
|
+
// the permission round-trip failed. copyToClipboard swallows its
|
|
122
|
+
// own errors so the await above always resolves.
|
|
123
|
+
await permsPromise
|
|
124
|
+
} catch {
|
|
125
|
+
setLoading(false)
|
|
126
|
+
return
|
|
124
127
|
}
|
|
128
|
+
onClose()
|
|
125
129
|
}
|
|
126
130
|
|
|
127
131
|
const handleRevokeLink = async () => {
|
|
@@ -96,17 +96,36 @@ export const generateShareLinkFromFile = ({
|
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
/**
|
|
99
|
-
* Copy a
|
|
99
|
+
* Copy a value to the clipboard.
|
|
100
100
|
*
|
|
101
|
-
*
|
|
101
|
+
* Accepts a resolved string or a `Promise<string>`. The promise form is
|
|
102
|
+
* required when the value depends on a prior async step (e.g. creating a
|
|
103
|
+
* sharing link) from within a click handler: Safari drops the user-gesture
|
|
104
|
+
* context across any `await`, so `navigator.clipboard.writeText` called after
|
|
105
|
+
* an awaited call throws `NotAllowedError`. Passing a pending blob to
|
|
106
|
+
* `ClipboardItem` lets the clipboard API be invoked synchronously while the
|
|
107
|
+
* content is resolved later.
|
|
108
|
+
*
|
|
109
|
+
* @param {string | Promise<string>} value - Value to copy
|
|
102
110
|
* @param {object} [options]
|
|
103
|
-
* @param {
|
|
111
|
+
* @param {Function} options.t - Translation function
|
|
104
112
|
* @param {Function} options.showAlert - Function to display an alert
|
|
105
113
|
*/
|
|
106
114
|
export const copyToClipboard = async (value, { t, showAlert } = {}) => {
|
|
107
115
|
if (!value) return false
|
|
108
116
|
try {
|
|
109
|
-
|
|
117
|
+
if (typeof value === 'string') {
|
|
118
|
+
await navigator.clipboard.writeText(value)
|
|
119
|
+
} else if (typeof ClipboardItem !== 'undefined') {
|
|
120
|
+
const blobPromise = Promise.resolve(value).then(
|
|
121
|
+
text => new Blob([text], { type: 'text/plain' })
|
|
122
|
+
)
|
|
123
|
+
await navigator.clipboard.write([
|
|
124
|
+
new ClipboardItem({ 'text/plain': blobPromise })
|
|
125
|
+
])
|
|
126
|
+
} else {
|
|
127
|
+
await navigator.clipboard.writeText(await value)
|
|
128
|
+
}
|
|
110
129
|
showAlert({
|
|
111
130
|
message: t('copyReminderContent.success'),
|
|
112
131
|
severity: 'success',
|