@byline/host-tanstack-start 6.7.2 → 6.9.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.
Files changed (74) hide show
  1. package/dist/admin-shell/admin-roles/container_module.css +1 -1
  2. package/dist/admin-shell/admin-roles/delete.js +1 -1
  3. package/dist/admin-shell/admin-users/container.js +181 -159
  4. package/dist/admin-shell/admin-users/container.module.js +2 -1
  5. package/dist/admin-shell/admin-users/container_module.css +5 -1
  6. package/dist/admin-shell/admin-users/delete.js +1 -1
  7. package/dist/admin-shell/chrome/admin-app-bar.d.ts +0 -7
  8. package/dist/admin-shell/collections/api.d.ts +6 -2
  9. package/dist/admin-shell/collections/api.js +109 -3
  10. package/dist/admin-shell/collections/api.test.d.ts +8 -0
  11. package/dist/admin-shell/collections/edit.js +2 -0
  12. package/dist/admin-shell/collections/preview-link.js +17 -13
  13. package/dist/admin-shell/collections/view-menu.d.ts +8 -1
  14. package/dist/admin-shell/collections/view-menu.js +124 -107
  15. package/dist/admin-shell/collections/view-menu.module.js +1 -0
  16. package/dist/admin-shell/collections/view-menu_module.css +15 -1
  17. package/dist/admin-shell/scheduled-publications/list.js +2 -2
  18. package/dist/admin-shell/singletons/preview-link.js +17 -13
  19. package/dist/admin-shell/singletons/view-menu.js +78 -63
  20. package/dist/admin-shell/singletons/view.js +2 -0
  21. package/dist/integrations/byline-admin-services.js +2 -0
  22. package/dist/integrations/passkey-admin-services.d.ts +9 -0
  23. package/dist/integrations/passkey-admin-services.js +53 -0
  24. package/dist/integrations/session-coordination.d.ts +3 -1
  25. package/dist/integrations/session-coordination.js +3 -1
  26. package/dist/integrations/session-middleware.d.ts +3 -1
  27. package/dist/integrations/session-middleware.js +87 -79
  28. package/dist/integrations/sign-in-body.d.ts +3 -0
  29. package/dist/integrations/sign-in-body.js +19 -4
  30. package/dist/integrations/sign-in-middleware.js +30 -5
  31. package/dist/server-fns/auth/passkey-admission.d.ts +24 -0
  32. package/dist/server-fns/auth/passkey-admission.js +88 -0
  33. package/dist/server-fns/auth/passkeys.d.ts +96 -0
  34. package/dist/server-fns/auth/passkeys.js +238 -0
  35. package/dist/server-fns/auth/reconcile-locale.d.ts +20 -0
  36. package/dist/server-fns/auth/reconcile-locale.js +16 -0
  37. package/dist/server-fns/auth/sign-in.js +1 -15
  38. package/dist/server-fns/collections/get.d.ts +1 -0
  39. package/dist/server-fns/collections/get.js +4 -0
  40. package/package.json +11 -11
  41. package/src/admin-shell/admin-roles/container.module.css +1 -1
  42. package/src/admin-shell/admin-roles/delete.tsx +1 -1
  43. package/src/admin-shell/admin-users/container.module.css +7 -1
  44. package/src/admin-shell/admin-users/container.tsx +22 -2
  45. package/src/admin-shell/admin-users/delete.tsx +1 -1
  46. package/src/admin-shell/chrome/admin-app-bar.tsx +2 -2
  47. package/src/admin-shell/chrome/dashboard.test.tsx +2 -2
  48. package/src/admin-shell/collections/api.test.tsx +223 -0
  49. package/src/admin-shell/collections/api.tsx +98 -3
  50. package/src/admin-shell/collections/edit.tsx +9 -1
  51. package/src/admin-shell/collections/preview-link.tsx +13 -12
  52. package/src/admin-shell/collections/view-menu.module.css +29 -3
  53. package/src/admin-shell/collections/view-menu.tsx +114 -96
  54. package/src/admin-shell/scheduled-publications/list.tsx +3 -4
  55. package/src/admin-shell/singletons/history.test.tsx +1 -1
  56. package/src/admin-shell/singletons/preview-link.tsx +13 -12
  57. package/src/admin-shell/singletons/view-menu.tsx +65 -59
  58. package/src/admin-shell/singletons/view.test.tsx +4 -4
  59. package/src/admin-shell/singletons/view.tsx +3 -1
  60. package/src/integrations/byline-admin-services.ts +3 -0
  61. package/src/integrations/passkey-admin-services.ts +85 -0
  62. package/src/integrations/session-client.test.node.ts +73 -0
  63. package/src/integrations/session-coordination.ts +3 -1
  64. package/src/integrations/session-middleware.ts +86 -72
  65. package/src/integrations/sign-in-body.test.node.ts +31 -1
  66. package/src/integrations/sign-in-body.ts +27 -3
  67. package/src/integrations/sign-in-middleware.ts +42 -9
  68. package/src/server-fns/auth/passkey-admission.test.node.ts +173 -0
  69. package/src/server-fns/auth/passkey-admission.ts +125 -0
  70. package/src/server-fns/auth/passkeys.test.node.ts +247 -0
  71. package/src/server-fns/auth/passkeys.ts +252 -0
  72. package/src/server-fns/auth/reconcile-locale.ts +40 -0
  73. package/src/server-fns/auth/sign-in.ts +1 -32
  74. package/src/server-fns/collections/get.ts +3 -0
@@ -1,7 +1,7 @@
1
1
  :is(.card-glD1iI, .byline-role-detail-card) {
2
2
  border: var(--border-width-thin) var(--border-style-solid) var(--gray-100);
3
+ border-radius: var(--border-radius-sm);
3
4
  background-color: var(--canvas-25);
4
- border-radius: .125rem;
5
5
  margin-bottom: 1.5rem;
6
6
  padding: 1rem;
7
7
  }
@@ -82,7 +82,7 @@ function DeleteRole({ role, onClose }) {
82
82
  children: [
83
83
  /*#__PURE__*/ jsx(Button, {
84
84
  type: "button",
85
- intent: "secondary",
85
+ intent: "noeffect",
86
86
  size: "sm",
87
87
  onClick: onClose,
88
88
  disabled: pending,
@@ -5,10 +5,13 @@ import { useRouter } from "@tanstack/react-router";
5
5
  import { UserRoles } from "@byline/admin/admin-users/components/roles";
6
6
  import { SetPassword } from "@byline/admin/admin-users/components/set-password";
7
7
  import { UpdateUser } from "@byline/admin/admin-users/components/update";
8
+ import { PasskeyManager } from "@byline/admin/auth/components/passkey-manager";
8
9
  import { LocalDateTime } from "@byline/admin/react";
9
10
  import { useTranslation } from "@byline/i18n/react";
10
11
  import { Button, CloseIcon, Drawer, EditIcon, IconButton, Modal, useToastManager } from "@byline/ui/react";
11
12
  import clsx from "clsx";
13
+ import { getAdminRoutePath } from "../../routes/admin-path.js";
14
+ import { Link } from "../chrome/loose-router.js";
12
15
  import container_module from "./container.module.js";
13
16
  import { DeleteUser } from "./delete.js";
14
17
  const panelMeta = {
@@ -125,167 +128,164 @@ function AccountContainer({ user, allRoles, initialUserRoles }) {
125
128
  /*#__PURE__*/ jsxs("div", {
126
129
  className: clsx('byline-admin-user-grid', container_module.grid),
127
130
  children: [
128
- /*#__PURE__*/ jsx("div", {
129
- className: clsx('byline-admin-user-column', container_module.column),
130
- children: /*#__PURE__*/ jsxs(ContainerSection, {
131
- title: t('adminUsers.detail.sections.account'),
132
- onEdit: openDrawer('update'),
133
- editAriaLabel: editAriaFor(t('adminUsers.detail.sections.account')),
134
- children: [
135
- /*#__PURE__*/ jsxs("p", {
136
- className: clsx('byline-admin-user-line', container_module.line),
137
- children: [
138
- /*#__PURE__*/ jsx("span", {
139
- className: "muted",
140
- children: t('account.profile.emailColon')
141
- }),
142
- " ",
143
- currentUser.email
144
- ]
145
- }),
146
- /*#__PURE__*/ jsxs("p", {
147
- className: clsx('byline-admin-user-line', container_module.line),
148
- children: [
149
- /*#__PURE__*/ jsx("span", {
150
- className: "muted",
151
- children: t('account.profile.givenName')
152
- }),
153
- ' ',
154
- currentUser.given_name ?? /*#__PURE__*/ jsx("span", {
155
- className: clsx('muted byline-admin-user-not-set', container_module.notSet),
156
- children: t('common.notSet')
157
- })
158
- ]
159
- }),
160
- /*#__PURE__*/ jsxs("p", {
161
- className: clsx('byline-admin-user-line', container_module.line),
162
- children: [
163
- /*#__PURE__*/ jsx("span", {
164
- className: "muted",
165
- children: t('account.profile.familyName')
166
- }),
167
- ' ',
168
- currentUser.family_name ?? /*#__PURE__*/ jsx("span", {
169
- className: clsx('muted byline-admin-user-not-set', container_module.notSet),
170
- children: t('common.notSet')
171
- })
172
- ]
173
- }),
174
- /*#__PURE__*/ jsxs("p", {
175
- className: clsx('byline-admin-user-line', container_module.line),
176
- children: [
177
- /*#__PURE__*/ jsx("span", {
178
- className: "muted",
179
- children: t('account.profile.username')
180
- }),
181
- ' ',
182
- currentUser.username ?? /*#__PURE__*/ jsx("span", {
183
- className: clsx('muted byline-admin-user-not-set', container_module.notSet),
184
- children: t('common.notSet')
185
- })
186
- ]
187
- }),
188
- /*#__PURE__*/ jsxs("p", {
189
- className: clsx('byline-admin-user-line', container_module.line),
190
- children: [
191
- /*#__PURE__*/ jsx("span", {
192
- className: "muted",
193
- children: t('account.status.superAdmin')
194
- }),
195
- ' ',
196
- currentUser.is_super_admin ? t('common.boolean.yes') : t('common.boolean.no')
197
- ]
198
- }),
199
- /*#__PURE__*/ jsxs("p", {
200
- className: clsx('byline-admin-user-line', container_module.line),
201
- children: [
202
- /*#__PURE__*/ jsx("span", {
203
- className: "muted",
204
- children: t('account.status.emailVerified')
205
- }),
206
- ' ',
207
- currentUser.is_email_verified ? t('common.boolean.yes') : t('common.boolean.no')
208
- ]
209
- }),
210
- /*#__PURE__*/ jsxs("p", {
211
- className: clsx('byline-admin-user-line-spaced', container_module.lineSpaced),
212
- children: [
213
- /*#__PURE__*/ jsx("span", {
214
- className: "muted",
215
- children: t('account.status.status')
216
- }),
217
- ' ',
218
- /*#__PURE__*/ jsx("span", {
219
- className: clsx({
220
- 'byline-admin-user-status-on': currentUser.is_enabled,
221
- [container_module.statusOn]: currentUser.is_enabled,
222
- 'byline-admin-user-status-off': !currentUser.is_enabled,
223
- [container_module.statusOff]: !currentUser.is_enabled
224
- }),
225
- children: currentUser.is_enabled ? t('account.status.enabled') : t('account.status.disabled')
226
- })
227
- ]
228
- }),
229
- /*#__PURE__*/ jsx(Button, {
230
- size: "sm",
231
- onClick: openDrawer('update'),
232
- children: t('adminUsers.detail.updateButton')
233
- }),
234
- /*#__PURE__*/ jsxs("div", {
235
- className: clsx('muted byline-admin-user-meta', container_module.meta),
236
- children: [
237
- /*#__PURE__*/ jsxs("p", {
238
- children: [
239
- /*#__PURE__*/ jsxs("span", {
240
- className: "font-bold",
241
- children: [
242
- t('account.profile.created'),
243
- "\xa0"
244
- ]
245
- }),
246
- /*#__PURE__*/ jsx(LocalDateTime, {
247
- value: currentUser.created_at
248
- })
249
- ]
250
- }),
251
- /*#__PURE__*/ jsxs("p", {
252
- children: [
253
- /*#__PURE__*/ jsxs("span", {
254
- className: "font-bold",
255
- children: [
256
- t('account.profile.updated'),
257
- "\xa0"
258
- ]
259
- }),
260
- /*#__PURE__*/ jsx(LocalDateTime, {
261
- value: currentUser.updated_at
262
- })
263
- ]
264
- }),
265
- /*#__PURE__*/ jsxs("p", {
266
- className: clsx('byline-admin-user-line', container_module.line),
267
- children: [
268
- /*#__PURE__*/ jsxs("span", {
269
- className: "font-bold",
270
- children: [
271
- t('account.profile.lastLogin'),
272
- "\xa0"
273
- ]
274
- }),
275
- /*#__PURE__*/ jsx(LocalDateTime, {
276
- value: currentUser.last_login,
277
- fallback: t('common.never')
278
- })
279
- ]
280
- })
281
- ]
282
- })
283
- ]
284
- })
285
- }),
286
131
  /*#__PURE__*/ jsxs("div", {
287
132
  className: clsx('byline-admin-user-column', container_module.column),
288
133
  children: [
134
+ /*#__PURE__*/ jsxs(ContainerSection, {
135
+ title: t('adminUsers.detail.sections.account'),
136
+ onEdit: openDrawer('update'),
137
+ editAriaLabel: editAriaFor(t('adminUsers.detail.sections.account')),
138
+ children: [
139
+ /*#__PURE__*/ jsxs("p", {
140
+ className: clsx('byline-admin-user-line', container_module.line),
141
+ children: [
142
+ /*#__PURE__*/ jsx("span", {
143
+ className: "muted",
144
+ children: t('account.profile.emailColon')
145
+ }),
146
+ " ",
147
+ currentUser.email
148
+ ]
149
+ }),
150
+ /*#__PURE__*/ jsxs("p", {
151
+ className: clsx('byline-admin-user-line', container_module.line),
152
+ children: [
153
+ /*#__PURE__*/ jsx("span", {
154
+ className: "muted",
155
+ children: t('account.profile.givenName')
156
+ }),
157
+ ' ',
158
+ currentUser.given_name ?? /*#__PURE__*/ jsx("span", {
159
+ className: clsx('muted byline-admin-user-not-set', container_module.notSet),
160
+ children: t('common.notSet')
161
+ })
162
+ ]
163
+ }),
164
+ /*#__PURE__*/ jsxs("p", {
165
+ className: clsx('byline-admin-user-line', container_module.line),
166
+ children: [
167
+ /*#__PURE__*/ jsx("span", {
168
+ className: "muted",
169
+ children: t('account.profile.familyName')
170
+ }),
171
+ ' ',
172
+ currentUser.family_name ?? /*#__PURE__*/ jsx("span", {
173
+ className: clsx('muted byline-admin-user-not-set', container_module.notSet),
174
+ children: t('common.notSet')
175
+ })
176
+ ]
177
+ }),
178
+ /*#__PURE__*/ jsxs("p", {
179
+ className: clsx('byline-admin-user-line', container_module.line),
180
+ children: [
181
+ /*#__PURE__*/ jsx("span", {
182
+ className: "muted",
183
+ children: t('account.profile.username')
184
+ }),
185
+ ' ',
186
+ currentUser.username ?? /*#__PURE__*/ jsx("span", {
187
+ className: clsx('muted byline-admin-user-not-set', container_module.notSet),
188
+ children: t('common.notSet')
189
+ })
190
+ ]
191
+ }),
192
+ /*#__PURE__*/ jsxs("p", {
193
+ className: clsx('byline-admin-user-line', container_module.line),
194
+ children: [
195
+ /*#__PURE__*/ jsx("span", {
196
+ className: "muted",
197
+ children: t('account.status.superAdmin')
198
+ }),
199
+ ' ',
200
+ currentUser.is_super_admin ? t('common.boolean.yes') : t('common.boolean.no')
201
+ ]
202
+ }),
203
+ /*#__PURE__*/ jsxs("p", {
204
+ className: clsx('byline-admin-user-line', container_module.line),
205
+ children: [
206
+ /*#__PURE__*/ jsx("span", {
207
+ className: "muted",
208
+ children: t('account.status.emailVerified')
209
+ }),
210
+ ' ',
211
+ currentUser.is_email_verified ? t('common.boolean.yes') : t('common.boolean.no')
212
+ ]
213
+ }),
214
+ /*#__PURE__*/ jsxs("p", {
215
+ className: clsx('byline-admin-user-line-spaced', container_module.lineSpaced),
216
+ children: [
217
+ /*#__PURE__*/ jsx("span", {
218
+ className: "muted",
219
+ children: t('account.status.status')
220
+ }),
221
+ ' ',
222
+ /*#__PURE__*/ jsx("span", {
223
+ className: clsx({
224
+ 'byline-admin-user-status-on': currentUser.is_enabled,
225
+ [container_module.statusOn]: currentUser.is_enabled,
226
+ 'byline-admin-user-status-off': !currentUser.is_enabled,
227
+ [container_module.statusOff]: !currentUser.is_enabled
228
+ }),
229
+ children: currentUser.is_enabled ? t('account.status.enabled') : t('account.status.disabled')
230
+ })
231
+ ]
232
+ }),
233
+ /*#__PURE__*/ jsx(Button, {
234
+ size: "sm",
235
+ onClick: openDrawer('update'),
236
+ children: t('adminUsers.detail.updateButton')
237
+ }),
238
+ /*#__PURE__*/ jsxs("div", {
239
+ className: clsx('muted byline-admin-user-meta', container_module.meta),
240
+ children: [
241
+ /*#__PURE__*/ jsxs("p", {
242
+ children: [
243
+ /*#__PURE__*/ jsxs("span", {
244
+ className: "font-bold",
245
+ children: [
246
+ t('account.profile.created'),
247
+ "\xa0"
248
+ ]
249
+ }),
250
+ /*#__PURE__*/ jsx(LocalDateTime, {
251
+ value: currentUser.created_at
252
+ })
253
+ ]
254
+ }),
255
+ /*#__PURE__*/ jsxs("p", {
256
+ children: [
257
+ /*#__PURE__*/ jsxs("span", {
258
+ className: "font-bold",
259
+ children: [
260
+ t('account.profile.updated'),
261
+ "\xa0"
262
+ ]
263
+ }),
264
+ /*#__PURE__*/ jsx(LocalDateTime, {
265
+ value: currentUser.updated_at
266
+ })
267
+ ]
268
+ }),
269
+ /*#__PURE__*/ jsxs("p", {
270
+ className: clsx('byline-admin-user-line', container_module.line),
271
+ children: [
272
+ /*#__PURE__*/ jsxs("span", {
273
+ className: "font-bold",
274
+ children: [
275
+ t('account.profile.lastLogin'),
276
+ "\xa0"
277
+ ]
278
+ }),
279
+ /*#__PURE__*/ jsx(LocalDateTime, {
280
+ value: currentUser.last_login,
281
+ fallback: t('common.never')
282
+ })
283
+ ]
284
+ })
285
+ ]
286
+ })
287
+ ]
288
+ }),
289
289
  /*#__PURE__*/ jsxs(ContainerSection, {
290
290
  title: t('adminUsers.detail.sections.roles'),
291
291
  onEdit: openDrawer('roles'),
@@ -306,7 +306,12 @@ function AccountContainer({ user, allRoles, initialUserRoles }) {
306
306
  children: t('adminUsers.detail.editRolesButton')
307
307
  })
308
308
  ]
309
- }),
309
+ })
310
+ ]
311
+ }),
312
+ /*#__PURE__*/ jsxs("div", {
313
+ className: clsx('byline-admin-user-column', container_module.column),
314
+ children: [
310
315
  /*#__PURE__*/ jsxs(ContainerSection, {
311
316
  title: t('adminUsers.detail.sections.password'),
312
317
  onEdit: openDrawer('set_password'),
@@ -323,6 +328,23 @@ function AccountContainer({ user, allRoles, initialUserRoles }) {
323
328
  })
324
329
  ]
325
330
  }),
331
+ /*#__PURE__*/ jsx(PasskeyManager, {
332
+ targetUserId: currentUser.id,
333
+ targetIsSuperAdmin: currentUser.is_super_admin,
334
+ section: ContainerSection,
335
+ ownAccountNotice: /*#__PURE__*/ jsxs("p", {
336
+ className: clsx('byline-admin-user-line-spaced', container_module.lineSpaced),
337
+ children: [
338
+ t('adminUsers.detail.passkeys.ownAccount'),
339
+ ' ',
340
+ /*#__PURE__*/ jsx(Link, {
341
+ to: getAdminRoutePath('account'),
342
+ className: clsx('byline-admin-user-account-link', container_module.accountLink),
343
+ children: t('adminUsers.detail.passkeys.openAccount')
344
+ })
345
+ ]
346
+ })
347
+ }),
326
348
  /*#__PURE__*/ jsxs(ContainerSection, {
327
349
  title: t('adminUsers.detail.sections.delete'),
328
350
  children: [
@@ -17,6 +17,7 @@ const container_module = {
17
17
  drawerLarge: "drawerLarge-TviQRx",
18
18
  drawerScroll: "drawerScroll-oMah5X",
19
19
  modal: "modal-bnEv25",
20
- modalHead: "modalHead-LNaBLq"
20
+ modalHead: "modalHead-LNaBLq",
21
+ accountLink: "accountLink-jqPC1J"
21
22
  };
22
23
  export default container_module;
@@ -22,7 +22,7 @@
22
22
  :is(.section-R34Khp, .byline-admin-user-section) {
23
23
  border: var(--border-width-thin) var(--border-style-solid) var(--gray-100);
24
24
  background-color: var(--canvas-25);
25
- border-radius: .125rem;
25
+ border-radius: var(--border-radius-sm);
26
26
  padding: 1rem;
27
27
  }
28
28
 
@@ -134,3 +134,7 @@
134
134
  display: flex;
135
135
  }
136
136
 
137
+ :is(.accountLink-jqPC1J, .byline-admin-user-account-link) {
138
+ text-decoration: underline;
139
+ }
140
+
@@ -90,7 +90,7 @@ function DeleteUser({ user, onClose }) {
90
90
  children: [
91
91
  /*#__PURE__*/ jsx(Button, {
92
92
  type: "button",
93
- intent: "secondary",
93
+ intent: "noeffect",
94
94
  size: "sm",
95
95
  onClick: onClose,
96
96
  disabled: pending,
@@ -1,10 +1,3 @@
1
- /**
2
- * This Source Code is subject to the terms of the Mozilla Public
3
- * License, v. 2.0. If a copy of the MPL was not distributed with this
4
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
- *
6
- * Copyright (c) Infonomic Company Limited
7
- */
8
1
  import { type CurrentAdminUser } from '../../server-fns/auth/index.js';
9
2
  interface AdminAppBarProps {
10
3
  user: CurrentAdminUser;
@@ -12,13 +12,17 @@ import 'react-json-view-lite/dist/index.css';
12
12
  /**
13
13
  * JSON inspector view for a collection document.
14
14
  *
15
+ * Copy JSON and Download JSON render in the view menu's data group, beside the
16
+ * locale and depth controls whose selection they export.
17
+ *
15
18
  * Stable override handles: `.byline-api-section`, `.byline-api-container`,
16
- * `.byline-api-head`, `.byline-api-title`, `.byline-api-viewer`.
19
+ * `.byline-api-head`, `.byline-api-title`, `.byline-api-action`,
20
+ * `.byline-api-viewer`.
17
21
  */
18
22
  export declare const ApiView: ({ collectionDefinition, initialData, locale, depth, contentLocales, defaultContentLocale, }: {
19
23
  collectionDefinition: MultiCollectionDefinition;
20
24
  initialData: AnyCollectionSchemaTypes['UpdateType'];
21
- /** Currently active locale from the route search param (undefined → all). */
25
+ /** Locale from the route search param (undefined → the default content locale). */
22
26
  locale?: string;
23
27
  /** Populate depth from the route search param (undefined → 0, no populate). */
24
28
  depth?: number;
@@ -1,6 +1,7 @@
1
- import { jsx, jsxs } from "react/jsx-runtime";
1
+ import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { useState } from "react";
2
3
  import { useTranslation } from "@byline/i18n/react";
3
- import { Container, Section } from "@byline/ui/react";
4
+ import { Container, CopyIcon, DownloadIcon, IconButton, Section, Tooltip, useToastManager } from "@byline/ui/react";
4
5
  import clsx from "clsx";
5
6
  import { JsonView, darkStyles } from "react-json-view-lite";
6
7
  import api_module from "./api.module.js";
@@ -10,6 +11,72 @@ const expandToFirstLevel = (level)=>level < 2;
10
11
  const ApiView = ({ collectionDefinition, initialData, locale, depth, contentLocales, defaultContentLocale })=>{
11
12
  const { labels, path } = collectionDefinition;
12
13
  const { t } = useTranslation('byline-admin');
14
+ const toastManager = useToastManager();
15
+ const [copyPending, setCopyPending] = useState(false);
16
+ const copyJson = async ()=>{
17
+ setCopyPending(true);
18
+ try {
19
+ await navigator.clipboard.writeText(JSON.stringify(initialData, null, 2));
20
+ toastManager.add({
21
+ title: t('collections.api.copied'),
22
+ data: {
23
+ intent: 'success',
24
+ iconType: 'success',
25
+ icon: true,
26
+ close: true
27
+ }
28
+ });
29
+ } catch {
30
+ toastManager.add({
31
+ title: t('collections.api.copyFailed'),
32
+ data: {
33
+ intent: 'danger',
34
+ iconType: 'danger',
35
+ icon: true,
36
+ close: true
37
+ }
38
+ });
39
+ } finally{
40
+ setCopyPending(false);
41
+ }
42
+ };
43
+ const downloadJson = ()=>{
44
+ try {
45
+ const blob = new Blob([
46
+ JSON.stringify(initialData, null, 2)
47
+ ], {
48
+ type: 'application/json;charset=utf-8'
49
+ });
50
+ const url = URL.createObjectURL(blob);
51
+ const link = document.createElement('a');
52
+ try {
53
+ link.href = url;
54
+ const selection = [
55
+ path,
56
+ String(initialData.id),
57
+ locale ?? defaultContentLocale
58
+ ];
59
+ if (null != depth && depth > 0) selection.push(`depth${depth}`);
60
+ const filename = selection.join('-').replace(/[^a-zA-Z0-9_-]/g, '-');
61
+ link.download = `${filename}.json`;
62
+ document.body.appendChild(link);
63
+ link.click();
64
+ } finally{
65
+ link.remove();
66
+ setTimeout(()=>URL.revokeObjectURL(url), 1000);
67
+ }
68
+ } catch {
69
+ toastManager.add({
70
+ title: t('collections.api.downloadFailed'),
71
+ data: {
72
+ intent: 'danger',
73
+ iconType: 'danger',
74
+ icon: true,
75
+ close: true
76
+ }
77
+ });
78
+ }
79
+ };
13
80
  return /*#__PURE__*/ jsx(Section, {
14
81
  className: clsx('byline-api-section', api_module.section),
15
82
  children: /*#__PURE__*/ jsxs(Container, {
@@ -31,7 +98,46 @@ const ApiView = ({ collectionDefinition, initialData, locale, depth, contentLoca
31
98
  locale: locale,
32
99
  depth: depth,
33
100
  contentLocales: contentLocales,
34
- defaultContentLocale: defaultContentLocale
101
+ defaultContentLocale: defaultContentLocale,
102
+ dataActions: /*#__PURE__*/ jsxs(Fragment, {
103
+ children: [
104
+ /*#__PURE__*/ jsx(Tooltip, {
105
+ text: t('collections.api.copyJson'),
106
+ side: "bottom",
107
+ delay: 0,
108
+ children: /*#__PURE__*/ jsx(IconButton, {
109
+ type: "button",
110
+ size: "xs",
111
+ variant: "text",
112
+ className: "byline-view-menu-icon-button byline-api-action",
113
+ "aria-label": t('collections.api.copyJson'),
114
+ disabled: copyPending,
115
+ onClick: copyJson,
116
+ children: /*#__PURE__*/ jsx(CopyIcon, {
117
+ width: "18px",
118
+ height: "18px"
119
+ })
120
+ })
121
+ }),
122
+ /*#__PURE__*/ jsx(Tooltip, {
123
+ text: t('collections.api.downloadJson'),
124
+ side: "bottom",
125
+ delay: 0,
126
+ children: /*#__PURE__*/ jsx(IconButton, {
127
+ type: "button",
128
+ size: "xs",
129
+ variant: "text",
130
+ className: "byline-view-menu-icon-button byline-api-action",
131
+ "aria-label": t('collections.api.downloadJson'),
132
+ onClick: downloadJson,
133
+ children: /*#__PURE__*/ jsx(DownloadIcon, {
134
+ width: "20px",
135
+ height: "20px"
136
+ })
137
+ })
138
+ })
139
+ ]
140
+ })
35
141
  })
36
142
  ]
37
143
  }),
@@ -0,0 +1,8 @@
1
+ /**
2
+ * This Source Code is subject to the terms of the Mozilla Public
3
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
4
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
5
+ *
6
+ * Copyright (c) Infonomic Company Limited
7
+ */
8
+ export {};
@@ -297,6 +297,7 @@ const EditView = ({ collectionDefinition, adminConfig, initialData: loadedData,
297
297
  }
298
298
  };
299
299
  const publishedVersion = initialData?._publishedVersion ?? null;
300
+ const unavailableBlocks = initialData?._unavailableBlocks;
300
301
  const restoreWarnings = initialData?._restoreWarnings;
301
302
  const handleUnpublish = async ()=>{
302
303
  try {
@@ -863,6 +864,7 @@ const EditView = ({ collectionDefinition, adminConfig, initialData: loadedData,
863
864
  contentLocales: contentLocales,
864
865
  publishedVersion: publishedVersion,
865
866
  restoreWarnings: restoreWarnings,
867
+ unavailableBlocks: unavailableBlocks,
866
868
  nextStatus: nextStatus,
867
869
  workflowStatuses: workflowStatuses,
868
870
  onCancel: ()=>{