@kyro-cms/admin 0.10.4 → 0.10.5

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kyro-cms/admin",
3
- "version": "0.10.4",
3
+ "version": "0.10.5",
4
4
  "engines": {
5
5
  "node": ">=22"
6
6
  },
@@ -18,7 +18,8 @@ import { MarkdownField } from "./fields/MarkdownField";
18
18
  import TextField from "./fields/TextField";
19
19
  import { globals, collections } from "../lib/config";
20
20
  import { slugifyText } from "../lib/slugify";
21
- import { resolveUrl, apiDelete, fetchWithAuth } from "../lib/api";
21
+ import { resolveUrl, apiGet, apiDelete, fetchWithAuth } from "../lib/api";
22
+ import { Shimmer } from "./ui/Shimmer";
22
23
  import { normalizeUploadFields } from "../lib/normalize-upload-fields";
23
24
  import { useAutoFormStore } from "../lib/autoform-store";
24
25
  import { useAutoFormState } from "../hooks/useAutoFormState";
@@ -47,6 +48,7 @@ interface AutoFormProps {
47
48
  disabled?: boolean;
48
49
  collectionSlug?: string;
49
50
  globalSlug?: string;
51
+ documentId?: string;
50
52
  documentName?: string;
51
53
  layout?: "split" | "single";
52
54
  onActionSuccess?: (message: string) => void;
@@ -63,6 +65,7 @@ export function AutoForm({
63
65
  disabled: propDisabled,
64
66
  collectionSlug,
65
67
  globalSlug,
68
+ documentId,
66
69
  documentName,
67
70
  layout = "split",
68
71
  onActionSuccess,
@@ -143,6 +146,30 @@ export function AutoForm({
143
146
  const [localSaveStatus, setLocalSaveStatus] = useState<"idle" | "saving" | "saved" | "error">("idle");
144
147
  const [now, setNow] = useState(Date.now());
145
148
  const disabled = propDisabled;
149
+ const [clientLoading, setClientLoading] = useState(false);
150
+
151
+ // Client-side fetch when SSR didn't provide data
152
+ useEffect(() => {
153
+ const shouldFetchCollection = collectionSlug && documentId && documentId !== "new";
154
+ const shouldFetchGlobal = globalSlug;
155
+ if (!shouldFetchCollection && !shouldFetchGlobal) return;
156
+ if (initialData && Object.keys(initialData).length > 0) return;
157
+
158
+ setClientLoading(true);
159
+ const url = globalSlug
160
+ ? `/api/globals/${globalSlug}`
161
+ : `/api/${collectionSlug}/${documentId}`;
162
+
163
+ apiGet<{ data?: Record<string, unknown> }>(url, { autoToast: false })
164
+ .then((result) => {
165
+ const docData = result.data || {};
166
+ setFormData(docData);
167
+ setClientLoading(false);
168
+ })
169
+ .catch(() => {
170
+ setClientLoading(false);
171
+ });
172
+ }, [collectionSlug, documentId, globalSlug, initialData]);
146
173
 
147
174
  // Tick every 10s so the "saved X ago" label stays fresh
148
175
  useEffect(() => {
@@ -1807,6 +1834,20 @@ export function AutoForm({
1807
1834
  </div>
1808
1835
  );
1809
1836
 
1837
+ if (clientLoading) {
1838
+ return (
1839
+ <div className="space-y-6 p-4">
1840
+ <div className="space-y-2">
1841
+ <Shimmer variant="text" className="w-1/3" />
1842
+ <Shimmer variant="text" className="w-2/3" />
1843
+ </div>
1844
+ <div className="space-y-4">
1845
+ <Shimmer variant="rect" count={4} />
1846
+ </div>
1847
+ </div>
1848
+ );
1849
+ }
1850
+
1810
1851
  return (
1811
1852
  <div className="flex flex-col h-full">
1812
1853
  {layout !== "single" && renderHeader()}
@@ -2,11 +2,10 @@
2
2
  import AdminLayout from "../../layouts/AdminLayout.astro";
3
3
  import { collections } from "../../lib/config";
4
4
  import { AutoForm } from "../../components/AutoForm";
5
+ import { adminPath } from "../../lib/paths";
5
6
 
6
7
  const { collection, id } = Astro.params;
7
8
 
8
- import { adminPath, apiPath } from "../../lib/paths";
9
-
10
9
  // Validate collection exists
11
10
  if (!collection || !collections[collection]) {
12
11
  return Astro.redirect(adminPath);
@@ -14,39 +13,10 @@ if (!collection || !collections[collection]) {
14
13
 
15
14
  const config = collections[collection];
16
15
 
17
- // Fetch document if editing
18
- let doc: any = null;
19
- let fetchError: string | null = null;
20
- if (id && id !== "new") {
21
- try {
22
- const response = await fetch(
23
- `${Astro.url.origin}${apiPath}/${collection}/${id}`,
24
- {
25
- headers: Astro.request.headers,
26
- credentials: "include",
27
- },
28
- );
29
- if (response.ok) {
30
- const result = await response.json();
31
- doc = result.data || null;
32
- } else {
33
- const errorData = await response.json().catch(() => ({}));
34
- fetchError = errorData.error || `Failed to load document (${response.status})`;
35
- }
36
- } catch (error) {
37
- fetchError = "Failed to fetch document. Check server connection.";
38
- console.error("Failed to fetch document:", error);
39
- }
40
- }
41
-
42
- const isNew = !doc;
43
- const docStatus = doc?.status || "draft";
16
+ const isNew = !id || id === "new";
44
17
  const title = isNew
45
18
  ? `Create ${config.singularLabel || config.label || collection}`
46
19
  : `Edit ${config.singularLabel || config.label || collection}`;
47
- const description =
48
- config.admin?.description ||
49
- `Manage ${(config.label || collection || "").toLowerCase()} documents`;
50
20
  ---
51
21
 
52
22
  <AdminLayout title={title}>
@@ -55,10 +25,8 @@ const description =
55
25
  <AutoForm
56
26
  client:load
57
27
  config={config}
58
- data={doc || {}}
59
28
  collectionSlug={collection}
60
29
  documentId={id || undefined}
61
- documentName={(typeof doc?.title === "object" ? "" : doc?.title) || (typeof doc?.name === "object" ? "" : doc?.name) || doc?.slug || "new-document"}
62
30
  />
63
31
  <input type="hidden" id="form-data" name="form-data" value="{}" />
64
32
  </form>
@@ -3,7 +3,7 @@ import AdminLayout from "../../layouts/AdminLayout.astro";
3
3
  import { globals } from "../../lib/config";
4
4
  import { SettingsPage } from "../../components/SettingsPage";
5
5
 
6
- import { adminPath, apiPath } from "../../lib/paths";
6
+ import { adminPath } from "../../lib/paths";
7
7
 
8
8
  const { slug } = Astro.params;
9
9
 
@@ -15,29 +15,6 @@ if (!slug || !globals[slug]) {
15
15
  const config = globals[slug];
16
16
  const hasVersioning = !!config.versions;
17
17
 
18
- // Fetch current settings data from API (authenticated)
19
- let data: any = {};
20
- try {
21
- const fetchUrl = new URL(`${apiPath}/globals/${slug}`, Astro.url.origin);
22
- if (hasVersioning) {
23
- fetchUrl.searchParams.set("draft", "true");
24
- }
25
-
26
- const response = await fetch(
27
- fetchUrl.toString(),
28
- {
29
- headers: Astro.request.headers,
30
- credentials: "include",
31
- },
32
- );
33
- if (response.ok) {
34
- const result = await response.json();
35
- data = result.data || {};
36
- }
37
- } catch (error) {
38
- console.error("Failed to fetch settings:", error);
39
- }
40
-
41
18
  const activeSlug = slug;
42
19
  const allGlobals = Object.values(globals);
43
20
 
@@ -116,7 +93,6 @@ const description =
116
93
  client:load
117
94
  config={config}
118
95
  globalSlug={slug}
119
- data={data}
120
96
  layout={hasVersioning ? "split" : "single"}
121
97
  />
122
98
  <input type="hidden" id="form-data" name="form-data" value="{}" />