@byline/host-tanstack-start 3.5.1 → 3.6.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.
@@ -17,7 +17,7 @@ const CreateView = ({ collectionDefinition, adminConfig, initialData })=>{
17
17
  const { labels, path, fields } = collectionDefinition;
18
18
  const handleSubmit = async ({ data, systemPath, systemAvailableLocales })=>{
19
19
  try {
20
- await createCollectionDocument({
20
+ const result = await createCollectionDocument({
21
21
  data: {
22
22
  collection: path,
23
23
  data,
@@ -29,7 +29,16 @@ const CreateView = ({ collectionDefinition, adminConfig, initialData })=>{
29
29
  } : {}
30
30
  }
31
31
  });
32
- navigate({
32
+ result?.documentId ? navigate({
33
+ to: '/admin/collections/$collection/$id',
34
+ params: {
35
+ collection: path,
36
+ id: result.documentId
37
+ },
38
+ search: {
39
+ action: 'created'
40
+ }
41
+ }) : navigate({
33
42
  to: '/admin/collections/$collection',
34
43
  params: {
35
44
  collection: path
@@ -1,13 +1,19 @@
1
1
  import { Fragment, jsx, jsxs } from "react/jsx-runtime";
2
+ import { useEffect, useRef } from "react";
2
3
  import { createFileRoute, notFound } from "@tanstack/react-router";
3
4
  import { getCollectionAdminConfig, getCollectionDefinition } from "@byline/core";
4
5
  import { useTranslation } from "@byline/i18n/react";
6
+ import { useToastManager } from "@byline/ui/react";
5
7
  import { z } from "zod";
6
8
  import { BreadcrumbsClient } from "../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js";
9
+ import { useNavigate } from "../admin-shell/chrome/loose-router.js";
7
10
  import { EditView } from "../admin-shell/collections/edit.js";
8
11
  import { getCollectionDocument } from "../server-fns/collections/index.js";
9
12
  const searchSchema = z.object({
10
- locale: z.string().optional()
13
+ locale: z.string().optional(),
14
+ action: z["enum"]([
15
+ 'created'
16
+ ]).optional()
11
17
  });
12
18
  function createCollectionEditRoute(path, opts) {
13
19
  const Route = createFileRoute(path)({
@@ -28,10 +34,50 @@ function createCollectionEditRoute(path, opts) {
28
34
  component: function() {
29
35
  const data = Route.useLoaderData();
30
36
  const { collection, id } = Route.useParams();
31
- const { locale } = Route.useSearch();
37
+ const search = Route.useSearch();
38
+ const { locale } = search;
32
39
  const collectionDef = getCollectionDefinition(collection);
33
40
  const adminConfig = getCollectionAdminConfig(collection);
34
41
  const { t } = useTranslation('byline-admin');
42
+ const toastManager = useToastManager();
43
+ const navigate = useNavigate();
44
+ const createdToastFiredRef = useRef(false);
45
+ useEffect(()=>{
46
+ if ('created' !== search.action) {
47
+ createdToastFiredRef.current = false;
48
+ return;
49
+ }
50
+ if (createdToastFiredRef.current) return;
51
+ createdToastFiredRef.current = true;
52
+ toastManager.add({
53
+ title: t('collections.list.createdToastTitle', {
54
+ label: collectionDef.labels.singular
55
+ }),
56
+ description: t("collections.list.createdToastDescription", {
57
+ label: collectionDef.labels.singular.toLowerCase()
58
+ }),
59
+ data: {
60
+ intent: 'success',
61
+ iconType: 'success',
62
+ icon: true,
63
+ close: true
64
+ }
65
+ });
66
+ navigate({
67
+ to: '.',
68
+ search: (prev)=>({
69
+ ...prev,
70
+ action: void 0
71
+ }),
72
+ replace: true
73
+ });
74
+ }, [
75
+ search.action,
76
+ navigate,
77
+ toastManager.add,
78
+ collectionDef.labels.singular,
79
+ t
80
+ ]);
35
81
  return /*#__PURE__*/ jsxs(Fragment, {
36
82
  children: [
37
83
  /*#__PURE__*/ jsx(BreadcrumbsClient, {
@@ -19,4 +19,6 @@ export declare const createCollectionDocument: import("@tanstack/react-start").R
19
19
  availableLocales?: string[];
20
20
  }, Promise<{
21
21
  status: "ok";
22
+ documentId: string;
23
+ documentVersionId: string;
22
24
  }>>;
@@ -27,7 +27,7 @@ const createCollectionDocument = createServerFn({
27
27
  slugifier: serverConfig.slugifier,
28
28
  requestContext: await getAdminRequestContext()
29
29
  };
30
- await createDocument(ctx, {
30
+ const result = await createDocument(ctx, {
31
31
  data: structuredClone(documentData),
32
32
  status: documentData.status,
33
33
  locale: locale ?? serverConfig.i18n.content.defaultLocale,
@@ -35,7 +35,9 @@ const createCollectionDocument = createServerFn({
35
35
  availableLocales
36
36
  });
37
37
  return {
38
- status: 'ok'
38
+ status: 'ok',
39
+ documentId: result.documentId,
40
+ documentVersionId: result.documentVersionId
39
41
  };
40
42
  });
41
43
  export { createCollectionDocument };
package/package.json CHANGED
@@ -3,7 +3,7 @@
3
3
  "private": false,
4
4
  "type": "module",
5
5
  "license": "MPL-2.0",
6
- "version": "3.5.1",
6
+ "version": "3.6.0",
7
7
  "engines": {
8
8
  "node": ">=20.9.0"
9
9
  },
@@ -115,13 +115,13 @@
115
115
  "react-swipeable": "^7.0.2",
116
116
  "uuid": "^14.0.0",
117
117
  "zod": "^4.4.3",
118
- "@byline/admin": "3.5.1",
119
- "@byline/i18n": "3.5.1",
120
- "@byline/ai": "3.5.1",
121
- "@byline/ui": "3.5.1",
122
- "@byline/core": "3.5.1",
123
- "@byline/auth": "3.5.1",
124
- "@byline/client": "3.5.1"
118
+ "@byline/admin": "3.6.0",
119
+ "@byline/client": "3.6.0",
120
+ "@byline/ai": "3.6.0",
121
+ "@byline/core": "3.6.0",
122
+ "@byline/ui": "3.6.0",
123
+ "@byline/i18n": "3.6.0",
124
+ "@byline/auth": "3.6.0"
125
125
  },
126
126
  "peerDependencies": {
127
127
  "@tanstack/react-router": "^1.167.0",
@@ -52,7 +52,7 @@ export const CreateView = ({
52
52
  systemAvailableLocales?: string[]
53
53
  }) => {
54
54
  try {
55
- await createCollectionDocument({
55
+ const result = await createCollectionDocument({
56
56
  data: {
57
57
  collection: path,
58
58
  data,
@@ -60,11 +60,23 @@ export const CreateView = ({
60
60
  ...(systemAvailableLocales ? { availableLocales: systemAvailableLocales } : {}),
61
61
  },
62
62
  })
63
- navigate({
64
- to: '/admin/collections/$collection' as never,
65
- params: { collection: path },
66
- search: { action: 'created' },
67
- })
63
+ // Create → edit: land the editor on the new document, where the rest
64
+ // of the work (content, status, relations) happens. The list-view
65
+ // fallback covers callers running against an older server fn that
66
+ // doesn't return the new document's id.
67
+ if (result?.documentId) {
68
+ navigate({
69
+ to: '/admin/collections/$collection/$id' as never,
70
+ params: { collection: path, id: result.documentId } as never,
71
+ search: { action: 'created' },
72
+ })
73
+ } else {
74
+ navigate({
75
+ to: '/admin/collections/$collection' as never,
76
+ params: { collection: path },
77
+ search: { action: 'created' },
78
+ })
79
+ }
68
80
  } catch (err) {
69
81
  console.error(err)
70
82
 
@@ -6,20 +6,25 @@
6
6
  * Copyright (c) Infonomic Company Limited
7
7
  */
8
8
 
9
+ import { useEffect, useRef } from 'react'
9
10
  import { createFileRoute, notFound } from '@tanstack/react-router'
10
11
 
11
12
  import type { CollectionDefinition } from '@byline/core'
12
13
  import { getCollectionAdminConfig, getCollectionDefinition } from '@byline/core'
13
14
  import { useTranslation } from '@byline/i18n/react'
15
+ import { useToastManager } from '@byline/ui/react'
14
16
  import { z } from 'zod'
15
17
 
16
18
  import { BreadcrumbsClient } from '../admin-shell/chrome/breadcrumbs/breadcrumbs-client.js'
19
+ import { useNavigate } from '../admin-shell/chrome/loose-router.js'
17
20
  import { EditView } from '../admin-shell/collections/edit.js'
18
21
  import { getCollectionDocument } from '../server-fns/collections/index.js'
19
22
  import type { ContentLocaleOption } from '../admin-shell/collections/view-menu.js'
20
23
 
21
24
  const searchSchema = z.object({
22
25
  locale: z.string().optional(),
26
+ /** Set by the create view's create → edit redirect; fires the created toast. */
27
+ action: z.enum(['created']).optional(),
23
28
  })
24
29
 
25
30
  interface CollectionEditOpts {
@@ -70,10 +75,46 @@ export function createCollectionEditRoute(path: string, opts: CollectionEditOpts
70
75
  component: function CollectionEditComponent() {
71
76
  const data = Route.useLoaderData()
72
77
  const { collection, id } = Route.useParams() as { collection: string; id: string }
73
- const { locale } = Route.useSearch() as z.infer<typeof searchSchema>
78
+ const search = Route.useSearch() as z.infer<typeof searchSchema>
79
+ const { locale } = search
74
80
  const collectionDef = getCollectionDefinition(collection) as CollectionDefinition
75
81
  const adminConfig = getCollectionAdminConfig(collection)
76
82
  const { t } = useTranslation('byline-admin')
83
+ const toastManager = useToastManager()
84
+ const navigate = useNavigate()
85
+
86
+ // Post-create toast for the create → edit redirect (?action=created).
87
+ // Ref-guarded for the same reason as the list route's created toast:
88
+ // `toastManager` changes identity on every add, so the effect depends
89
+ // on the stable `toastManager.add` and the ref protects against any
90
+ // re-fire that observes the search param before navigate clears it.
91
+ const createdToastFiredRef = useRef(false)
92
+ useEffect(() => {
93
+ if (search.action !== 'created') {
94
+ createdToastFiredRef.current = false
95
+ return
96
+ }
97
+ if (createdToastFiredRef.current) return
98
+ createdToastFiredRef.current = true
99
+
100
+ toastManager.add({
101
+ title: t('collections.list.createdToastTitle', { label: collectionDef.labels.singular }),
102
+ description: t('collections.list.createdToastDescription', {
103
+ label: collectionDef.labels.singular.toLowerCase(),
104
+ }),
105
+ data: {
106
+ intent: 'success',
107
+ iconType: 'success',
108
+ icon: true,
109
+ close: true,
110
+ },
111
+ })
112
+ navigate({
113
+ to: '.',
114
+ search: (prev: Record<string, unknown>) => ({ ...prev, action: undefined }),
115
+ replace: true,
116
+ })
117
+ }, [search.action, navigate, toastManager.add, collectionDef.labels.singular, t])
77
118
 
78
119
  return (
79
120
  <>
@@ -59,7 +59,7 @@ export const createCollectionDocument = createServerFn({ method: 'POST' })
59
59
  requestContext: await getAdminRequestContext(),
60
60
  }
61
61
 
62
- await createDocument(ctx, {
62
+ const result = await createDocument(ctx, {
63
63
  data: structuredClone(documentData),
64
64
  status: documentData.status,
65
65
  locale: locale ?? serverConfig.i18n.content.defaultLocale,
@@ -67,5 +67,11 @@ export const createCollectionDocument = createServerFn({ method: 'POST' })
67
67
  availableLocales,
68
68
  })
69
69
 
70
- return { status: 'ok' as const }
70
+ // The new document's id is returned so the create view can navigate
71
+ // straight to the edit view (create → edit).
72
+ return {
73
+ status: 'ok' as const,
74
+ documentId: result.documentId,
75
+ documentVersionId: result.documentVersionId,
76
+ }
71
77
  })