@byline/host-tanstack-start 3.21.0 → 4.1.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.
- package/dist/admin-shell/admin-activity/list.js +15 -5
- package/dist/admin-shell/admin-roles/delete.js +2 -1
- package/dist/admin-shell/admin-roles/list.js +2 -1
- package/dist/admin-shell/admin-users/delete.js +2 -1
- package/dist/admin-shell/admin-users/list.js +4 -7
- package/dist/admin-shell/chrome/admin-app-bar.js +2 -1
- package/dist/admin-shell/chrome/admin-menu-drawer.js +9 -8
- package/dist/admin-shell/chrome/admin-menu-provider.js +2 -1
- package/dist/admin-shell/chrome/dashboard.js +4 -3
- package/dist/admin-shell/chrome/sign-in-page.d.ts +2 -2
- package/dist/admin-shell/chrome/sign-in-page.js +2 -2
- package/dist/admin-shell/collections/create.js +4 -3
- package/dist/admin-shell/collections/document-history.js +6 -1
- package/dist/admin-shell/collections/edit.js +18 -14
- package/dist/admin-shell/collections/history.js +5 -4
- package/dist/admin-shell/collections/list.js +8 -7
- package/dist/admin-shell/collections/restore-version-modal.js +2 -1
- package/dist/admin-shell/collections/tree-list.js +53 -17
- package/dist/admin-shell/collections/view-menu.js +9 -8
- package/dist/i18n/resolve-locale.js +1 -1
- package/dist/index.d.ts +5 -6
- package/dist/integrations/abilities.js +8 -7
- package/dist/integrations/host-bridge.d.ts +13 -0
- package/dist/integrations/host-bridge.js +22 -0
- package/dist/integrations/serve-uploads.d.ts +1 -0
- package/dist/integrations/serve-uploads.js +1 -0
- package/dist/integrations/start-errors.js +2 -1
- package/dist/routes/admin-path.d.ts +22 -0
- package/dist/routes/admin-path.js +35 -0
- package/dist/routes/create-admin-account-route.js +3 -2
- package/dist/routes/create-admin-activity-route.js +3 -2
- package/dist/routes/create-admin-dashboard-route.js +2 -1
- package/dist/routes/create-admin-layout-route.d.ts +1 -1
- package/dist/routes/create-admin-layout-route.js +3 -1
- package/dist/routes/create-admin-permissions-route.js +3 -2
- package/dist/routes/create-admin-role-edit-route.js +4 -3
- package/dist/routes/create-admin-roles-list-route.js +3 -2
- package/dist/routes/create-admin-user-edit-route.js +4 -3
- package/dist/routes/create-admin-users-list-route.js +3 -2
- package/dist/routes/create-collection-api-route.js +5 -4
- package/dist/routes/create-collection-create-route.js +4 -3
- package/dist/routes/create-collection-edit-route.js +4 -3
- package/dist/routes/create-collection-history-route.js +5 -4
- package/dist/routes/create-collection-list-route.js +3 -2
- package/dist/routes/create-sign-in-route.js +3 -2
- package/dist/routes/index.d.ts +3 -0
- package/dist/routes/index.js +2 -0
- package/dist/routes/sign-in-path.d.ts +13 -0
- package/dist/routes/sign-in-path.js +19 -0
- package/dist/server-fns/admin-account/change-password.js +1 -1
- package/dist/server-fns/admin-account/get.js +1 -1
- package/dist/server-fns/admin-account/update.js +1 -1
- package/dist/server-fns/admin-activity/get.js +1 -1
- package/dist/server-fns/admin-permissions/get-role-abilities.js +1 -1
- package/dist/server-fns/admin-permissions/list-registered.js +1 -1
- package/dist/server-fns/admin-permissions/set-role-abilities.js +1 -1
- package/dist/server-fns/admin-permissions/who-has.js +1 -1
- package/dist/server-fns/admin-roles/create.js +1 -1
- package/dist/server-fns/admin-roles/delete.js +1 -1
- package/dist/server-fns/admin-roles/get.js +1 -1
- package/dist/server-fns/admin-roles/list.js +1 -1
- package/dist/server-fns/admin-roles/reorder.js +1 -1
- package/dist/server-fns/admin-roles/update.js +1 -1
- package/dist/server-fns/admin-users/create.js +1 -1
- package/dist/server-fns/admin-users/delete.js +1 -1
- package/dist/server-fns/admin-users/disable.js +1 -1
- package/dist/server-fns/admin-users/enable.js +1 -1
- package/dist/server-fns/admin-users/get-user-roles.js +1 -1
- package/dist/server-fns/admin-users/get.js +1 -1
- package/dist/server-fns/admin-users/list.js +1 -1
- package/dist/server-fns/admin-users/set-password.js +1 -1
- package/dist/server-fns/admin-users/set-user-roles.js +1 -1
- package/dist/server-fns/admin-users/update.js +1 -1
- package/dist/server-fns/ai/execute.js +1 -1
- package/dist/server-fns/auth/current-user.js +1 -1
- package/dist/server-fns/auth/sign-in.js +1 -1
- package/dist/server-fns/auth/sign-out.js +1 -2
- package/dist/server-fns/collections/audit.js +1 -1
- package/dist/server-fns/collections/copy-to-locale.js +1 -1
- package/dist/server-fns/collections/create.js +1 -1
- package/dist/server-fns/collections/delete-locale.js +1 -1
- package/dist/server-fns/collections/delete-outcome.d.ts +30 -0
- package/dist/server-fns/collections/delete-outcome.js +34 -0
- package/dist/server-fns/collections/delete.d.ts +1 -4
- package/dist/server-fns/collections/delete.js +3 -5
- package/dist/server-fns/collections/duplicate.js +1 -1
- package/dist/server-fns/collections/get.js +1 -1
- package/dist/server-fns/collections/history.js +1 -1
- package/dist/server-fns/collections/index.d.ts +1 -0
- package/dist/server-fns/collections/index.js +1 -0
- package/dist/server-fns/collections/list.js +1 -1
- package/dist/server-fns/collections/reindex.js +1 -1
- package/dist/server-fns/collections/reorder.js +1 -1
- package/dist/server-fns/collections/restore-version.js +1 -1
- package/dist/server-fns/collections/stats.js +1 -1
- package/dist/server-fns/collections/status.js +1 -1
- package/dist/server-fns/collections/tree-mutation.d.ts +46 -0
- package/dist/server-fns/collections/tree-mutation.js +109 -0
- package/dist/server-fns/collections/tree-read.d.ts +6 -0
- package/dist/server-fns/collections/tree-read.js +15 -0
- package/dist/server-fns/collections/tree.d.ts +5 -4
- package/dist/server-fns/collections/tree.js +16 -13
- package/dist/server-fns/collections/update.js +3 -2
- package/dist/server-fns/collections/upload.js +1 -1
- package/dist/server-fns/i18n/set-locale.js +1 -1
- package/dist/server-fns/preview/disable.js +1 -1
- package/dist/server-fns/preview/enable.js +1 -2
- package/dist/server-fns/preview/state.js +1 -1
- package/dist/vite/client-hook-boundary.d.ts +19 -0
- package/dist/vite/client-hook-boundary.js +20 -0
- package/dist/{integrations/byline-public-client.d.ts → vite/index.d.ts} +1 -2
- package/dist/vite/index.js +1 -0
- package/package.json +15 -14
- package/src/admin-shell/admin-activity/list.tsx +13 -3
- package/src/admin-shell/admin-roles/delete.tsx +2 -1
- package/src/admin-shell/admin-roles/list.tsx +2 -1
- package/src/admin-shell/admin-users/delete.tsx +3 -2
- package/src/admin-shell/admin-users/list.tsx +9 -8
- package/src/admin-shell/chrome/admin-app-bar.tsx +2 -1
- package/src/admin-shell/chrome/admin-menu-drawer.tsx +13 -8
- package/src/admin-shell/chrome/admin-menu-provider.tsx +2 -1
- package/src/admin-shell/chrome/dashboard.tsx +4 -3
- package/src/admin-shell/chrome/sign-in-page.tsx +3 -3
- package/src/admin-shell/collections/create.tsx +4 -3
- package/src/admin-shell/collections/document-history.tsx +5 -0
- package/src/admin-shell/collections/edit.tsx +20 -13
- package/src/admin-shell/collections/history.tsx +6 -5
- package/src/admin-shell/collections/list.tsx +8 -7
- package/src/admin-shell/collections/restore-version-modal.tsx +2 -1
- package/src/admin-shell/collections/tree-list.tsx +78 -22
- package/src/admin-shell/collections/view-menu.tsx +9 -8
- package/src/i18n/resolve-locale.ts +1 -1
- package/src/index.ts +5 -6
- package/src/integrations/abilities.tsx +14 -4
- package/src/integrations/host-bridge.ts +56 -0
- package/src/integrations/serve-uploads.ts +6 -0
- package/src/integrations/start-errors.test.node.ts +22 -0
- package/src/integrations/start-errors.ts +1 -0
- package/src/routes/admin-path.test.node.ts +129 -0
- package/src/routes/admin-path.ts +66 -0
- package/src/routes/auth-routes.test.node.ts +39 -0
- package/src/routes/create-admin-account-route.tsx +3 -2
- package/src/routes/create-admin-activity-route.tsx +3 -2
- package/src/routes/create-admin-dashboard-route.tsx +2 -1
- package/src/routes/create-admin-layout-route.tsx +4 -4
- package/src/routes/create-admin-permissions-route.tsx +3 -2
- package/src/routes/create-admin-role-edit-route.tsx +7 -3
- package/src/routes/create-admin-roles-list-route.tsx +3 -2
- package/src/routes/create-admin-user-edit-route.tsx +7 -3
- package/src/routes/create-admin-users-list-route.tsx +3 -2
- package/src/routes/create-collection-api-route.tsx +8 -4
- package/src/routes/create-collection-create-route.tsx +7 -3
- package/src/routes/create-collection-edit-route.tsx +7 -3
- package/src/routes/create-collection-history-route.tsx +8 -4
- package/src/routes/create-collection-list-route.tsx +3 -2
- package/src/routes/create-sign-in-route.tsx +9 -3
- package/src/routes/index.ts +11 -0
- package/src/routes/sign-in-path.test.node.ts +79 -0
- package/src/routes/sign-in-path.ts +36 -0
- package/src/server-fns/admin-account/change-password.ts +1 -1
- package/src/server-fns/admin-account/get.ts +1 -1
- package/src/server-fns/admin-account/update.ts +1 -1
- package/src/server-fns/admin-activity/get.ts +1 -1
- package/src/server-fns/admin-permissions/get-role-abilities.ts +1 -1
- package/src/server-fns/admin-permissions/list-registered.ts +1 -1
- package/src/server-fns/admin-permissions/set-role-abilities.ts +1 -1
- package/src/server-fns/admin-permissions/who-has.ts +1 -1
- package/src/server-fns/admin-roles/create.ts +1 -1
- package/src/server-fns/admin-roles/delete.ts +1 -1
- package/src/server-fns/admin-roles/get.ts +1 -1
- package/src/server-fns/admin-roles/list.ts +1 -1
- package/src/server-fns/admin-roles/reorder.ts +1 -1
- package/src/server-fns/admin-roles/update.ts +1 -1
- package/src/server-fns/admin-users/create.ts +1 -1
- package/src/server-fns/admin-users/delete.ts +1 -1
- package/src/server-fns/admin-users/disable.ts +1 -1
- package/src/server-fns/admin-users/enable.ts +1 -1
- package/src/server-fns/admin-users/get-user-roles.ts +1 -1
- package/src/server-fns/admin-users/get.ts +1 -1
- package/src/server-fns/admin-users/list.ts +1 -1
- package/src/server-fns/admin-users/set-password.ts +1 -1
- package/src/server-fns/admin-users/set-user-roles.ts +1 -1
- package/src/server-fns/admin-users/update.ts +1 -1
- package/src/server-fns/ai/execute.ts +1 -2
- package/src/server-fns/auth/current-user.ts +1 -1
- package/src/server-fns/auth/sign-in.ts +1 -1
- package/src/server-fns/auth/sign-out.ts +5 -3
- package/src/server-fns/collections/audit.ts +1 -1
- package/src/server-fns/collections/copy-to-locale.ts +1 -1
- package/src/server-fns/collections/create.ts +1 -1
- package/src/server-fns/collections/delete-locale.ts +1 -1
- package/src/server-fns/collections/delete-outcome.test.node.ts +72 -0
- package/src/server-fns/collections/delete-outcome.ts +80 -0
- package/src/server-fns/collections/delete.ts +3 -2
- package/src/server-fns/collections/duplicate.ts +1 -1
- package/src/server-fns/collections/get.ts +3 -1
- package/src/server-fns/collections/history.ts +1 -1
- package/src/server-fns/collections/index.ts +1 -0
- package/src/server-fns/collections/list.ts +1 -1
- package/src/server-fns/collections/reindex.ts +1 -1
- package/src/server-fns/collections/reorder.ts +1 -1
- package/src/server-fns/collections/restore-version.ts +1 -1
- package/src/server-fns/collections/stats.ts +2 -1
- package/src/server-fns/collections/status.ts +1 -1
- package/src/server-fns/collections/tree-mutation.test.node.ts +225 -0
- package/src/server-fns/collections/tree-mutation.ts +165 -0
- package/src/server-fns/collections/tree-read.test.node.ts +46 -0
- package/src/server-fns/collections/tree-read.ts +26 -0
- package/src/server-fns/collections/tree.ts +27 -11
- package/src/server-fns/collections/update.ts +4 -1
- package/src/server-fns/collections/upload.ts +1 -1
- package/src/server-fns/i18n/set-locale.ts +1 -1
- package/src/server-fns/preview/disable.ts +1 -1
- package/src/server-fns/preview/enable.ts +1 -2
- package/src/server-fns/preview/state.ts +1 -1
- package/src/vite/client-hook-boundary.test.node.ts +50 -0
- package/src/vite/client-hook-boundary.ts +45 -0
- package/src/vite/index.ts +9 -0
- package/dist/auth/auth-context.d.ts +0 -37
- package/dist/auth/auth-context.js +0 -57
- package/dist/auth/auth-cookies.d.ts +0 -34
- package/dist/auth/auth-cookies.js +0 -46
- package/dist/auth/preview-cookies.d.ts +0 -19
- package/dist/auth/preview-cookies.js +0 -26
- package/dist/integrations/byline-client.d.ts +0 -24
- package/dist/integrations/byline-client.js +0 -25
- package/dist/integrations/byline-public-client.js +0 -15
- package/dist/integrations/byline-viewer-client.d.ts +0 -20
- package/dist/integrations/byline-viewer-client.js +0 -39
- package/src/auth/auth-context.test.node.ts +0 -215
- package/src/auth/auth-context.ts +0 -124
- package/src/auth/auth-cookies.ts +0 -113
- package/src/auth/preview-cookies.ts +0 -73
- package/src/integrations/byline-client.ts +0 -66
- package/src/integrations/byline-public-client.ts +0 -53
- package/src/integrations/byline-viewer-client.ts +0 -99
|
@@ -26,6 +26,7 @@ import {
|
|
|
26
26
|
} from '@byline/ui/react'
|
|
27
27
|
import cx from 'classnames'
|
|
28
28
|
|
|
29
|
+
import { getAdminRouteId, getAdminRoutePath } from '../../routes/admin-path.js'
|
|
29
30
|
import { Link, useNavigate } from '../chrome/loose-router.js'
|
|
30
31
|
import { RouterPager } from '../chrome/router-pager.js'
|
|
31
32
|
import { TableHeadingCellSortable } from '../chrome/th-sortable.js'
|
|
@@ -139,8 +140,8 @@ export const HistoryView = ({
|
|
|
139
140
|
defaultContentLocale: string
|
|
140
141
|
}) => {
|
|
141
142
|
const { id, collection } = useParams({
|
|
142
|
-
from: '
|
|
143
|
-
})
|
|
143
|
+
from: getAdminRouteId('collections', '$collection', '$id', 'history') as never,
|
|
144
|
+
}) as { id: string; collection: string }
|
|
144
145
|
const navigate = useNavigate()
|
|
145
146
|
const { getCollectionDocumentVersion } = useBylineAdminServices()
|
|
146
147
|
const { t } = useTranslation('byline-admin')
|
|
@@ -181,7 +182,7 @@ export const HistoryView = ({
|
|
|
181
182
|
delete params.tab
|
|
182
183
|
}
|
|
183
184
|
navigate({
|
|
184
|
-
to: '
|
|
185
|
+
to: getAdminRoutePath('collections', '$collection', '$id', 'history'),
|
|
185
186
|
params: { collection, id } as never,
|
|
186
187
|
search: params,
|
|
187
188
|
})
|
|
@@ -193,7 +194,7 @@ export const HistoryView = ({
|
|
|
193
194
|
delete params.page
|
|
194
195
|
params.page_size = Number.parseInt(value, 10)
|
|
195
196
|
navigate({
|
|
196
|
-
to: '
|
|
197
|
+
to: getAdminRoutePath('collections', '$collection', '$id', 'history'),
|
|
197
198
|
params: { collection, id } as never,
|
|
198
199
|
search: params,
|
|
199
200
|
})
|
|
@@ -382,7 +383,7 @@ export const HistoryView = ({
|
|
|
382
383
|
</button>
|
|
383
384
|
) : (
|
|
384
385
|
<Link
|
|
385
|
-
to={'
|
|
386
|
+
to={getAdminRoutePath('collections', '$collection', '$id')}
|
|
386
387
|
params={{
|
|
387
388
|
collection,
|
|
388
389
|
id: document.id,
|
|
@@ -43,6 +43,7 @@ import {
|
|
|
43
43
|
} from '@dnd-kit/sortable'
|
|
44
44
|
import cx from 'classnames'
|
|
45
45
|
|
|
46
|
+
import { getAdminRoutePath } from '../../routes/admin-path.js'
|
|
46
47
|
import { Link, useNavigate } from '../chrome/loose-router.js'
|
|
47
48
|
import { RouterPager } from '../chrome/router-pager.js'
|
|
48
49
|
import { SortAscendingIcon } from '../chrome/sort-icons.js'
|
|
@@ -274,7 +275,7 @@ export const ListView = ({
|
|
|
274
275
|
delete params.page
|
|
275
276
|
params.query = query
|
|
276
277
|
navigate({
|
|
277
|
-
to: '
|
|
278
|
+
to: getAdminRoutePath('collections', '$collection'),
|
|
278
279
|
params: { collection: data.included.collection.path },
|
|
279
280
|
search: params,
|
|
280
281
|
})
|
|
@@ -286,7 +287,7 @@ export const ListView = ({
|
|
|
286
287
|
delete params.page
|
|
287
288
|
delete params.query
|
|
288
289
|
navigate({
|
|
289
|
-
to: '
|
|
290
|
+
to: getAdminRoutePath('collections', '$collection'),
|
|
290
291
|
params: { collection: data.included.collection.path },
|
|
291
292
|
search: params,
|
|
292
293
|
})
|
|
@@ -302,7 +303,7 @@ export const ListView = ({
|
|
|
302
303
|
params.status = value
|
|
303
304
|
}
|
|
304
305
|
navigate({
|
|
305
|
-
to: '
|
|
306
|
+
to: getAdminRoutePath('collections', '$collection'),
|
|
306
307
|
params: { collection: data.included.collection.path },
|
|
307
308
|
search: params,
|
|
308
309
|
})
|
|
@@ -314,7 +315,7 @@ export const ListView = ({
|
|
|
314
315
|
delete params.page
|
|
315
316
|
params.page_size = Number.parseInt(value, 10)
|
|
316
317
|
navigate({
|
|
317
|
-
to: '
|
|
318
|
+
to: getAdminRoutePath('collections', '$collection'),
|
|
318
319
|
params: { collection: data.included.collection.path },
|
|
319
320
|
search: params,
|
|
320
321
|
})
|
|
@@ -336,7 +337,7 @@ export const ListView = ({
|
|
|
336
337
|
aria-label={t('collections.list.createAriaLabel')}
|
|
337
338
|
render={
|
|
338
339
|
<Link
|
|
339
|
-
to={'
|
|
340
|
+
to={getAdminRoutePath('collections', '$collection', 'create')}
|
|
340
341
|
params={{ collection: data.included.collection.path }}
|
|
341
342
|
/>
|
|
342
343
|
}
|
|
@@ -454,7 +455,7 @@ export const ListView = ({
|
|
|
454
455
|
>
|
|
455
456
|
{useAsTitle && column.fieldName === useAsTitle ? (
|
|
456
457
|
<Link
|
|
457
|
-
to={'
|
|
458
|
+
to={getAdminRoutePath('collections', '$collection', '$id')}
|
|
458
459
|
params={{
|
|
459
460
|
collection: data.included.collection.path,
|
|
460
461
|
id: document.id,
|
|
@@ -530,7 +531,7 @@ export const ListView = ({
|
|
|
530
531
|
>
|
|
531
532
|
{useAsTitle && column.fieldName === useAsTitle ? (
|
|
532
533
|
<Link
|
|
533
|
-
to={'
|
|
534
|
+
to={getAdminRoutePath('collections', '$collection', '$id')}
|
|
534
535
|
params={{
|
|
535
536
|
collection: data.included.collection.path,
|
|
536
537
|
id: document.id,
|
|
@@ -24,6 +24,7 @@ import { useTranslation } from '@byline/i18n/react'
|
|
|
24
24
|
import { Alert, Button, LoaderEllipsis, Modal } from '@byline/ui/react'
|
|
25
25
|
import cx from 'classnames'
|
|
26
26
|
|
|
27
|
+
import { getAdminRoutePath } from '../../routes/admin-path.js'
|
|
27
28
|
import { restoreDocumentVersion } from '../../server-fns/collections/index.js'
|
|
28
29
|
import { useNavigate } from '../chrome/loose-router.js'
|
|
29
30
|
import styles from './restore-version-modal.module.css'
|
|
@@ -62,7 +63,7 @@ export function RestoreVersionModal({
|
|
|
62
63
|
onClose()
|
|
63
64
|
await router.invalidate()
|
|
64
65
|
navigate({
|
|
65
|
-
to: '
|
|
66
|
+
to: getAdminRoutePath('collections', '$collection', '$id'),
|
|
66
67
|
params: { collection, id: documentId },
|
|
67
68
|
})
|
|
68
69
|
} catch (err) {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
|
|
9
9
|
import type React from 'react'
|
|
10
|
-
import { useEffect, useMemo, useState } from 'react'
|
|
10
|
+
import { useEffect, useMemo, useRef, useState } from 'react'
|
|
11
11
|
import { useRouter } from '@tanstack/react-router'
|
|
12
12
|
|
|
13
13
|
import { renderFormatted, StatusBadge } from '@byline/admin/react'
|
|
@@ -41,6 +41,12 @@ import {
|
|
|
41
41
|
} from '@dnd-kit/sortable'
|
|
42
42
|
import cx from 'classnames'
|
|
43
43
|
|
|
44
|
+
import { getAdminRoutePath } from '../../routes/admin-path.js'
|
|
45
|
+
import {
|
|
46
|
+
createAdminTreeMoveController,
|
|
47
|
+
getAdminTreeMoveUiEffects,
|
|
48
|
+
shouldSyncAdminTreeRows,
|
|
49
|
+
} from '../../server-fns/collections/tree-mutation.js'
|
|
44
50
|
import { Link } from '../chrome/loose-router.js'
|
|
45
51
|
import { TableHeadingCellSortable } from '../chrome/th-sortable.js'
|
|
46
52
|
import { formatNumber } from '../chrome/utils.js'
|
|
@@ -59,7 +65,6 @@ export type TreeMoveFn = (params: {
|
|
|
59
65
|
afterDocumentId: string | null
|
|
60
66
|
}) => Promise<unknown>
|
|
61
67
|
|
|
62
|
-
// biome-ignore lint/suspicious/noExplicitAny: tree rows carry heterogeneous fields
|
|
63
68
|
function getColumnValue(row: CollectionTreeRow, fieldName: string): any {
|
|
64
69
|
if (row.fields && fieldName in row.fields) return row.fields[fieldName]
|
|
65
70
|
return (row as Record<string, any>)[fieldName]
|
|
@@ -73,19 +78,20 @@ function getColumnValue(row: CollectionTreeRow, fieldName: string): any {
|
|
|
73
78
|
*/
|
|
74
79
|
function SortableTreeRow({
|
|
75
80
|
id,
|
|
76
|
-
depth,
|
|
77
81
|
dragging,
|
|
82
|
+
disabled,
|
|
78
83
|
dragHandleLabel,
|
|
79
84
|
children,
|
|
80
85
|
}: {
|
|
81
86
|
id: string
|
|
82
|
-
depth: number
|
|
83
87
|
dragging: boolean
|
|
88
|
+
disabled: boolean
|
|
84
89
|
dragHandleLabel: string
|
|
85
90
|
children: React.ReactNode
|
|
86
91
|
}) {
|
|
87
92
|
const { setNodeRef, attributes, listeners, transform, transition, isDragging } = useSortable({
|
|
88
93
|
id,
|
|
94
|
+
disabled,
|
|
89
95
|
})
|
|
90
96
|
const style: React.CSSProperties = {
|
|
91
97
|
transform: transform ? `translate3d(0, ${transform.y}px, 0)` : undefined,
|
|
@@ -103,6 +109,7 @@ function SortableTreeRow({
|
|
|
103
109
|
<td className={cx('byline-tree-list-drag-cell', styles.dragCell)}>
|
|
104
110
|
<button
|
|
105
111
|
type="button"
|
|
112
|
+
disabled={disabled}
|
|
106
113
|
className={cx('byline-tree-list-drag-handle', styles.dragHandle)}
|
|
107
114
|
aria-label={dragHandleLabel}
|
|
108
115
|
{...attributes}
|
|
@@ -149,8 +156,12 @@ export const TreeListView = ({
|
|
|
149
156
|
// back). Mirrors the flat-list reorder pattern.
|
|
150
157
|
const [localPlaced, setLocalPlaced] = useState(() => rows.filter((r) => !r.unplaced))
|
|
151
158
|
const [isMoving, setIsMoving] = useState(false)
|
|
159
|
+
const [moveController] = useState(() => createAdminTreeMoveController())
|
|
160
|
+
const preserveOptimisticForRows = useRef<CollectionTreeRow[] | null>(null)
|
|
152
161
|
useEffect(() => {
|
|
153
|
-
if (!
|
|
162
|
+
if (!shouldSyncAdminTreeRows(rows, preserveOptimisticForRows.current, isMoving)) return
|
|
163
|
+
preserveOptimisticForRows.current = null
|
|
164
|
+
setLocalPlaced(rows.filter((r) => !r.unplaced))
|
|
154
165
|
}, [rows, isMoving])
|
|
155
166
|
|
|
156
167
|
const [activeId, setActiveId] = useState<string | null>(null)
|
|
@@ -174,11 +185,17 @@ export const TreeListView = ({
|
|
|
174
185
|
setOffsetLeft(0)
|
|
175
186
|
}
|
|
176
187
|
|
|
177
|
-
const handleDragStart = ({ active }: DragStartEvent) =>
|
|
188
|
+
const handleDragStart = ({ active }: DragStartEvent) => {
|
|
189
|
+
if (!moveController.isMoving()) setActiveId(String(active.id))
|
|
190
|
+
}
|
|
178
191
|
const handleDragMove = ({ delta }: DragMoveEvent) => setOffsetLeft(delta.x)
|
|
179
192
|
const handleDragOver = ({ over }: DragOverEvent) => setOverId(over ? String(over.id) : null)
|
|
180
193
|
|
|
181
194
|
const handleDragEnd = async ({ active, over }: DragEndEvent) => {
|
|
195
|
+
if (moveController.isMoving()) {
|
|
196
|
+
resetDnd()
|
|
197
|
+
return
|
|
198
|
+
}
|
|
182
199
|
const proj =
|
|
183
200
|
over != null
|
|
184
201
|
? getTreeProjection(localPlaced, String(active.id), String(over.id), offsetLeft, INDENT)
|
|
@@ -197,24 +214,60 @@ export const TreeListView = ({
|
|
|
197
214
|
|
|
198
215
|
setLocalPlaced(next)
|
|
199
216
|
setIsMoving(true)
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
217
|
+
const outcome = await moveController.execute(
|
|
218
|
+
() =>
|
|
219
|
+
onMove({
|
|
220
|
+
documentId,
|
|
221
|
+
parentDocumentId: proj.parentId,
|
|
222
|
+
beforeDocumentId: proj.beforeId,
|
|
223
|
+
afterDocumentId: proj.afterId,
|
|
224
|
+
}),
|
|
225
|
+
() => router.invalidate()
|
|
226
|
+
)
|
|
227
|
+
|
|
228
|
+
if (outcome.status === 'suppressed') {
|
|
209
229
|
setLocalPlaced(current)
|
|
230
|
+
setIsMoving(moveController.isMoving())
|
|
231
|
+
return
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const effects = getAdminTreeMoveUiEffects(outcome)
|
|
235
|
+
if (effects.rollback) setLocalPlaced(current)
|
|
236
|
+
|
|
237
|
+
if (effects.structuralFailure != null) {
|
|
238
|
+
const conflict = effects.structuralFailure === 'conflict'
|
|
210
239
|
toastManager.add({
|
|
211
|
-
title: t(
|
|
212
|
-
|
|
240
|
+
title: t(
|
|
241
|
+
conflict ? 'collections.list.treeConflictToast' : 'collections.list.reorderFailedToast'
|
|
242
|
+
),
|
|
243
|
+
description: t(
|
|
244
|
+
conflict
|
|
245
|
+
? 'collections.list.treeConflictDescription'
|
|
246
|
+
: 'collections.list.reorderFailedDescription'
|
|
247
|
+
),
|
|
213
248
|
data: { intent: 'danger', iconType: 'danger', icon: true, close: true },
|
|
214
249
|
})
|
|
215
|
-
} finally {
|
|
216
|
-
setIsMoving(false)
|
|
217
250
|
}
|
|
251
|
+
|
|
252
|
+
if (effects.committedHookWarning) {
|
|
253
|
+
toastManager.add({
|
|
254
|
+
title: t('collections.list.treeHookFailedToast'),
|
|
255
|
+
description: t('collections.list.treeHookFailedDescription'),
|
|
256
|
+
data: { intent: 'warning', iconType: 'warning', icon: true, close: true },
|
|
257
|
+
})
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
if (effects.refreshWarning) {
|
|
261
|
+
toastManager.add({
|
|
262
|
+
title: t('collections.list.treeRefreshFailedToast'),
|
|
263
|
+
description: t('collections.list.treeRefreshFailedDescription'),
|
|
264
|
+
data: { intent: 'warning', iconType: 'warning', icon: true, close: true },
|
|
265
|
+
})
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
if (effects.preserveOptimistic) preserveOptimisticForRows.current = rows
|
|
269
|
+
|
|
270
|
+
setIsMoving(false)
|
|
218
271
|
}
|
|
219
272
|
|
|
220
273
|
const renderCells = (row: CollectionTreeRow, depth: number) =>
|
|
@@ -240,7 +293,7 @@ export const TreeListView = ({
|
|
|
240
293
|
</span>
|
|
241
294
|
)}
|
|
242
295
|
<Link
|
|
243
|
-
to={'
|
|
296
|
+
to={getAdminRoutePath('collections', '$collection', '$id')}
|
|
244
297
|
params={{ collection, id: row.id }}
|
|
245
298
|
>
|
|
246
299
|
{column.formatter
|
|
@@ -277,7 +330,10 @@ export const TreeListView = ({
|
|
|
277
330
|
<IconButton
|
|
278
331
|
aria-label={t('collections.list.createAriaLabel')}
|
|
279
332
|
render={
|
|
280
|
-
<Link
|
|
333
|
+
<Link
|
|
334
|
+
to={getAdminRoutePath('collections', '$collection', 'create')}
|
|
335
|
+
params={{ collection }}
|
|
336
|
+
/>
|
|
281
337
|
}
|
|
282
338
|
>
|
|
283
339
|
<PlusIcon height="18px" width="18px" svgClassName="stroke-white" />
|
|
@@ -323,8 +379,8 @@ export const TreeListView = ({
|
|
|
323
379
|
<SortableTreeRow
|
|
324
380
|
key={row.id}
|
|
325
381
|
id={row.id}
|
|
326
|
-
depth={depth}
|
|
327
382
|
dragging={row.id === activeId}
|
|
383
|
+
disabled={isMoving}
|
|
328
384
|
dragHandleLabel={t('collections.list.dragHandleAriaLabel')}
|
|
329
385
|
>
|
|
330
386
|
{renderCells(row, depth)}
|
|
@@ -13,6 +13,7 @@ import { useTranslation } from '@byline/i18n/react'
|
|
|
13
13
|
import { Button, HistoryIcon, IconButton, Label, Select } from '@byline/ui/react'
|
|
14
14
|
import cx from 'classnames'
|
|
15
15
|
|
|
16
|
+
import { getAdminRoutePath } from '../../routes/admin-path.js'
|
|
16
17
|
import { useNavigate } from '../chrome/loose-router.js'
|
|
17
18
|
import { PreviewLink } from './preview-link.js'
|
|
18
19
|
import styles from './view-menu.module.css'
|
|
@@ -86,7 +87,7 @@ export const ViewMenu = ({
|
|
|
86
87
|
useEffect(() => {
|
|
87
88
|
if (activeView === 'edit' && locale === 'all') {
|
|
88
89
|
navigate({
|
|
89
|
-
to: '
|
|
90
|
+
to: getAdminRoutePath('collections', '$collection', '$id'),
|
|
90
91
|
params: { collection, id: documentId },
|
|
91
92
|
search: (prev: Record<string, unknown>) => ({
|
|
92
93
|
...prev,
|
|
@@ -103,19 +104,19 @@ export const ViewMenu = ({
|
|
|
103
104
|
const search = (prev: Record<string, unknown>) => ({ ...prev, locale: value })
|
|
104
105
|
if (activeView === 'api') {
|
|
105
106
|
navigate({
|
|
106
|
-
to: '
|
|
107
|
+
to: getAdminRoutePath('collections', '$collection', '$id', 'api'),
|
|
107
108
|
params: { collection, id: documentId },
|
|
108
109
|
search: search as never,
|
|
109
110
|
})
|
|
110
111
|
} else if (activeView === 'history') {
|
|
111
112
|
navigate({
|
|
112
|
-
to: '
|
|
113
|
+
to: getAdminRoutePath('collections', '$collection', '$id', 'history'),
|
|
113
114
|
params: { collection, id: documentId },
|
|
114
115
|
search: search as never,
|
|
115
116
|
})
|
|
116
117
|
} else {
|
|
117
118
|
navigate({
|
|
118
|
-
to: '
|
|
119
|
+
to: getAdminRoutePath('collections', '$collection', '$id'),
|
|
119
120
|
params: { collection, id: documentId },
|
|
120
121
|
search: search as never,
|
|
121
122
|
})
|
|
@@ -127,7 +128,7 @@ export const ViewMenu = ({
|
|
|
127
128
|
const n = Number.parseInt(value, 10)
|
|
128
129
|
const nextDepth = Number.isFinite(n) ? Math.max(0, Math.min(3, n)) : 0
|
|
129
130
|
navigate({
|
|
130
|
-
to: '
|
|
131
|
+
to: getAdminRoutePath('collections', '$collection', '$id', 'api'),
|
|
131
132
|
params: { collection, id: documentId },
|
|
132
133
|
// Store 0 as undefined so the URL stays clean when the user picks
|
|
133
134
|
// "no populate" — avoids `?depth=0` in bookmarks / share links.
|
|
@@ -201,7 +202,7 @@ export const ViewMenu = ({
|
|
|
201
202
|
variant={activeView === 'history' ? 'filled' : 'text'}
|
|
202
203
|
onClick={() =>
|
|
203
204
|
navigate({
|
|
204
|
-
to: '
|
|
205
|
+
to: getAdminRoutePath('collections', '$collection', '$id', 'history'),
|
|
205
206
|
params: { collection, id: documentId },
|
|
206
207
|
search: locale ? { locale } : {},
|
|
207
208
|
})
|
|
@@ -215,7 +216,7 @@ export const ViewMenu = ({
|
|
|
215
216
|
className={cx('byline-view-menu-button', styles.button)}
|
|
216
217
|
onClick={() =>
|
|
217
218
|
navigate({
|
|
218
|
-
to: '
|
|
219
|
+
to: getAdminRoutePath('collections', '$collection', '$id'),
|
|
219
220
|
params: { collection, id: documentId },
|
|
220
221
|
search: locale ? { locale } : {},
|
|
221
222
|
})
|
|
@@ -229,7 +230,7 @@ export const ViewMenu = ({
|
|
|
229
230
|
className={cx('byline-view-menu-button', styles.button)}
|
|
230
231
|
onClick={() =>
|
|
231
232
|
navigate({
|
|
232
|
-
to: '
|
|
233
|
+
to: getAdminRoutePath('collections', '$collection', '$id', 'api'),
|
|
233
234
|
params: { collection, id: documentId },
|
|
234
235
|
search: locale ? { locale } : {},
|
|
235
236
|
})
|
|
@@ -23,10 +23,10 @@
|
|
|
23
23
|
import { getRequestHeader } from '@tanstack/react-start/server'
|
|
24
24
|
|
|
25
25
|
import { AuthError, AuthErrorCodes } from '@byline/auth'
|
|
26
|
+
import { getAdminRequestContext } from '@byline/client/server'
|
|
26
27
|
import type { LocaleCode } from '@byline/i18n'
|
|
27
28
|
import { resolveInterfaceLocale } from '@byline/i18n'
|
|
28
29
|
|
|
29
|
-
import { getAdminRequestContext } from '../auth/auth-context.js'
|
|
30
30
|
import { bylineCore } from '../integrations/byline-core.js'
|
|
31
31
|
import { readAdminLocaleCookie } from './locale-cookie.js'
|
|
32
32
|
|
package/src/index.ts
CHANGED
|
@@ -19,14 +19,13 @@
|
|
|
19
19
|
* - `@byline/host-tanstack-start/server-fns/<module>` — TanStack Start
|
|
20
20
|
* server functions for each admin module (admin-account, admin-roles,
|
|
21
21
|
* admin-users, admin-permissions, auth, collections).
|
|
22
|
-
* - `@byline/host-tanstack-start/auth/auth-context` — request-scoped
|
|
23
|
-
* `RequestContext` resolution that reads session cookies, refreshes
|
|
24
|
-
* transparently, and surfaces `ERR_UNAUTHENTICATED` to callers.
|
|
25
22
|
* - `@byline/host-tanstack-start/integrations/*` — host-side adapters
|
|
26
23
|
* binding TanStack Start primitives to the framework-neutral
|
|
27
|
-
* contracts in `@byline/ui
|
|
28
|
-
* (`bylineFieldServices`, `bylineAdminServices`,
|
|
29
|
-
* `
|
|
24
|
+
* contracts in `@byline/ui`, `@byline/core`, and `@byline/client`
|
|
25
|
+
* (`bylineFieldServices`, `bylineAdminServices`, and `host-bridge` —
|
|
26
|
+
* the `HostRequestBridge` implementation behind the
|
|
27
|
+
* `@byline/client/server` getters; request-context resolution and the
|
|
28
|
+
* client singletons themselves live in `@byline/client/server`).
|
|
30
29
|
* - `@byline/host-tanstack-start/admin-shell/{chrome,collections,...}` —
|
|
31
30
|
* router-coupled admin UI: shared shell chrome (menu drawer, app bar,
|
|
32
31
|
* route-error, breadcrumbs, etc.) plus per-area page containers.
|
|
@@ -38,15 +38,25 @@
|
|
|
38
38
|
import type React from 'react'
|
|
39
39
|
import { useRouteContext } from '@tanstack/react-router'
|
|
40
40
|
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
import { getAdminRouteId } from '../routes/admin-path.js'
|
|
42
|
+
|
|
43
|
+
interface AbilityRouteContext {
|
|
44
|
+
user: {
|
|
45
|
+
is_super_admin: boolean
|
|
46
|
+
abilities: string[]
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function useAbilityRouteContext(): AbilityRouteContext {
|
|
51
|
+
return useRouteContext({ from: getAdminRouteId() as never }) as AbilityRouteContext
|
|
52
|
+
}
|
|
43
53
|
|
|
44
54
|
/**
|
|
45
55
|
* `true` when the current admin holds the given ability (or is a
|
|
46
56
|
* super-admin). Cosmetic — see file-level docstring.
|
|
47
57
|
*/
|
|
48
58
|
export function useAbility(ability: string): boolean {
|
|
49
|
-
const { user } =
|
|
59
|
+
const { user } = useAbilityRouteContext()
|
|
50
60
|
if (user.is_super_admin) return true
|
|
51
61
|
return user.abilities.includes(ability)
|
|
52
62
|
}
|
|
@@ -62,7 +72,7 @@ export function useAbilities(): {
|
|
|
62
72
|
hasAny: (abilities: readonly string[]) => boolean
|
|
63
73
|
isSuperAdmin: boolean
|
|
64
74
|
} {
|
|
65
|
-
const { user } =
|
|
75
|
+
const { user } = useAbilityRouteContext()
|
|
66
76
|
const has = (ability: string): boolean => user.is_super_admin || user.abilities.includes(ability)
|
|
67
77
|
const hasAny = (abilities: readonly string[]): boolean =>
|
|
68
78
|
user.is_super_admin || abilities.some((key) => user.abilities.includes(key))
|
|
@@ -0,0 +1,56 @@
|
|
|
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
|
+
|
|
9
|
+
/**
|
|
10
|
+
* The TanStack Start implementation of `HostRequestBridge` — the three
|
|
11
|
+
* request primitives (`getRequest` identity, cookie read, cookie write)
|
|
12
|
+
* that `@byline/client/server` is written against.
|
|
13
|
+
*
|
|
14
|
+
* Registered as a module side effect: every module in this package that
|
|
15
|
+
* fronts the server-side client stack imports this file first, so any
|
|
16
|
+
* code path that can reach a getter has already registered the bridge.
|
|
17
|
+
* Registration is idempotent (last-write-wins on a `globalThis` symbol
|
|
18
|
+
* slot), so repeated evaluation across Vite SSR module graphs is
|
|
19
|
+
* harmless.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { getCookie, getRequest, setCookie } from '@tanstack/react-start/server'
|
|
23
|
+
|
|
24
|
+
import {
|
|
25
|
+
type HostCookieSetOptions,
|
|
26
|
+
type HostRequestBridge,
|
|
27
|
+
registerHostRequestBridge,
|
|
28
|
+
} from '@byline/core'
|
|
29
|
+
|
|
30
|
+
const tanstackStartRequestBridge: HostRequestBridge = {
|
|
31
|
+
getRequest(): object | undefined {
|
|
32
|
+
try {
|
|
33
|
+
return getRequest()
|
|
34
|
+
} catch {
|
|
35
|
+
// No StartEvent in AsyncLocalStorage — running outside a request.
|
|
36
|
+
return undefined
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
getCookie(name: string): string | undefined {
|
|
40
|
+
return getCookie(name)
|
|
41
|
+
},
|
|
42
|
+
setCookie(name: string, value: string, options?: HostCookieSetOptions): void {
|
|
43
|
+
setCookie(name, value, options)
|
|
44
|
+
},
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Register the TanStack Start bridge. Safe to call any number of times;
|
|
49
|
+
* exported for hosts that want registration to be explicit in their
|
|
50
|
+
* server config rather than relying on a side-effect import.
|
|
51
|
+
*/
|
|
52
|
+
export function registerTanstackStartHostBridge(): void {
|
|
53
|
+
registerHostRequestBridge(tanstackStartRequestBridge)
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
registerTanstackStartHostBridge()
|
|
@@ -46,6 +46,12 @@ import type { Stats } from 'node:fs'
|
|
|
46
46
|
import { readFile, stat } from 'node:fs/promises'
|
|
47
47
|
import { resolve as resolvePath } from 'node:path'
|
|
48
48
|
|
|
49
|
+
// Belt-and-braces bridge registration: `serveUploads` is imported by every
|
|
50
|
+
// scaffolded app's `src/server.ts` at boot, so pulling in the host bridge
|
|
51
|
+
// here guarantees `@byline/client/server` getters can resolve cookies even
|
|
52
|
+
// if a server config forgets the explicit `registerTanstackStartHostBridge()`.
|
|
53
|
+
import './host-bridge.js'
|
|
54
|
+
|
|
49
55
|
export interface UploadsHandlerOptions {
|
|
50
56
|
/**
|
|
51
57
|
* URL prefix to match. Trailing slash required. Default `'/uploads/'`.
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ERR_CONFLICT, ERR_TREE_HOOK_COMMITTED } from '@byline/core'
|
|
2
|
+
import { describe, expect, it } from 'vitest'
|
|
3
|
+
|
|
4
|
+
import { bylineCodedErrorAdapter } from './start-errors.js'
|
|
5
|
+
|
|
6
|
+
describe('Byline coded error serialization', () => {
|
|
7
|
+
it.each([
|
|
8
|
+
ERR_CONFLICT({ message: 'stale tree' }),
|
|
9
|
+
ERR_TREE_HOOK_COMMITTED({ message: 'tree committed; hook failed' }),
|
|
10
|
+
])('preserves core BylineError code $code', (error) => {
|
|
11
|
+
expect(bylineCodedErrorAdapter.test(error)).toBe(true)
|
|
12
|
+
|
|
13
|
+
const payload = bylineCodedErrorAdapter.toSerializable(error)
|
|
14
|
+
const restored = bylineCodedErrorAdapter.fromSerializable(payload)
|
|
15
|
+
|
|
16
|
+
expect(restored).toMatchObject({
|
|
17
|
+
name: 'BylineError',
|
|
18
|
+
code: error.code,
|
|
19
|
+
message: error.message,
|
|
20
|
+
})
|
|
21
|
+
})
|
|
22
|
+
})
|