@kyro-cms/admin 0.10.14 → 0.10.19
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/index.cjs +16 -16
- package/dist/index.js +16 -16
- package/package.json +1 -1
- package/src/components/AutoForm.tsx +3 -1
- package/src/components/GraphQLPlayground.tsx +34 -6
- package/src/components/RestPlayground.tsx +19 -7
- package/src/components/autoform/AutoFormApiView.tsx +1 -1
- package/src/components/autoform/AutoFormVersionView.tsx +2 -2
- package/src/components/fields/extensions/blockComponents.tsx +34 -39
package/package.json
CHANGED
|
@@ -272,7 +272,9 @@ export function AutoForm({
|
|
|
272
272
|
|
|
273
273
|
const result = await resp.json();
|
|
274
274
|
if (result.data) {
|
|
275
|
-
|
|
275
|
+
// Omit historical timestamps so OCC doesn't panic on save
|
|
276
|
+
const { updatedAt, createdAt, ...historicalData } = result.data;
|
|
277
|
+
const restoredData = { ...formData, ...historicalData };
|
|
276
278
|
setFormData(restoredData);
|
|
277
279
|
useAutoFormStore.getState().loadDocument(restoredData, restoredData);
|
|
278
280
|
onActionSuccess?.("Version restored successfully");
|
|
@@ -393,11 +393,19 @@ export function GraphQLPlayground({
|
|
|
393
393
|
const [token, setToken] = useState<string>("");
|
|
394
394
|
const [showToken, setShowToken] = useState(false);
|
|
395
395
|
const [isConnected, setIsConnected] = useState(false);
|
|
396
|
-
const [tab, setTab] = useState<QueryTab>({
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
396
|
+
const [tab, setTab] = useState<QueryTab>(() => {
|
|
397
|
+
if (typeof window !== "undefined") {
|
|
398
|
+
try {
|
|
399
|
+
const saved = localStorage.getItem("kyro_graphql_tab");
|
|
400
|
+
if (saved) return JSON.parse(saved);
|
|
401
|
+
} catch {}
|
|
402
|
+
}
|
|
403
|
+
return {
|
|
404
|
+
id: "default",
|
|
405
|
+
query: initialQuery || DEFAULT_QUERY,
|
|
406
|
+
variables: initialVariables || "{}",
|
|
407
|
+
headers: "",
|
|
408
|
+
};
|
|
401
409
|
});
|
|
402
410
|
const [response, setResponse] = useState<string>("");
|
|
403
411
|
const [isLoading, setIsLoading] = useState(false);
|
|
@@ -411,7 +419,15 @@ export function GraphQLPlayground({
|
|
|
411
419
|
const [rightTab, setRightTab] = useState<"response" | "docs" | "history">(
|
|
412
420
|
initialShowDocs ? "docs" : "response",
|
|
413
421
|
);
|
|
414
|
-
const [history, setHistory] = useState<HistoryEntry[]>(
|
|
422
|
+
const [history, setHistory] = useState<HistoryEntry[]>(() => {
|
|
423
|
+
if (typeof window !== "undefined") {
|
|
424
|
+
try {
|
|
425
|
+
const saved = localStorage.getItem("kyro_graphql_history");
|
|
426
|
+
if (saved) return JSON.parse(saved);
|
|
427
|
+
} catch {}
|
|
428
|
+
}
|
|
429
|
+
return [];
|
|
430
|
+
});
|
|
415
431
|
const [lastDuration, setLastDuration] = useState<number>(0);
|
|
416
432
|
const [lastStatus, setLastStatus] = useState<number>(0);
|
|
417
433
|
const [copied, setCopied] = useState(false);
|
|
@@ -426,6 +442,18 @@ export function GraphQLPlayground({
|
|
|
426
442
|
setIsMounted(true);
|
|
427
443
|
}, []);
|
|
428
444
|
|
|
445
|
+
useEffect(() => {
|
|
446
|
+
if (isMounted) {
|
|
447
|
+
localStorage.setItem("kyro_graphql_tab", JSON.stringify(tab));
|
|
448
|
+
}
|
|
449
|
+
}, [tab, isMounted]);
|
|
450
|
+
|
|
451
|
+
useEffect(() => {
|
|
452
|
+
if (isMounted) {
|
|
453
|
+
localStorage.setItem("kyro_graphql_history", JSON.stringify(history));
|
|
454
|
+
}
|
|
455
|
+
}, [history, isMounted]);
|
|
456
|
+
|
|
429
457
|
useEffect(() => {
|
|
430
458
|
const check = () => setIsDesktop(window.innerWidth >= 768);
|
|
431
459
|
check();
|
|
@@ -83,13 +83,21 @@ export function RestPlayground({ collections = [] }: RestPlaygroundProps) {
|
|
|
83
83
|
const [history, setHistory] = useState<HistoryItem[]>([]);
|
|
84
84
|
const [envVars, setEnvVars] = useState<EnvVariable[]>([]);
|
|
85
85
|
const [selectedRequest, setSelectedRequest] = useState<SavedRequest | null>(null);
|
|
86
|
-
const [currentRequest, setCurrentRequest] = useState<SavedRequest>({
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
86
|
+
const [currentRequest, setCurrentRequest] = useState<SavedRequest>(() => {
|
|
87
|
+
if (typeof window !== "undefined") {
|
|
88
|
+
try {
|
|
89
|
+
const saved = localStorage.getItem("kyro_rest_current");
|
|
90
|
+
if (saved) return JSON.parse(saved);
|
|
91
|
+
} catch {}
|
|
92
|
+
}
|
|
93
|
+
return {
|
|
94
|
+
id: "new",
|
|
95
|
+
name: "Untitled Request",
|
|
96
|
+
method: "GET",
|
|
97
|
+
url: "",
|
|
98
|
+
headers: {},
|
|
99
|
+
body: "",
|
|
100
|
+
};
|
|
93
101
|
});
|
|
94
102
|
const [response, setResponse] = useState<{ status: number; duration: number; size: number; data: any } | null>(null);
|
|
95
103
|
const [loading, setLoading] = useState(false);
|
|
@@ -136,6 +144,10 @@ export function RestPlayground({ collections = [] }: RestPlaygroundProps) {
|
|
|
136
144
|
if (isMounted) localStorage.setItem(STORAGE_KEYS.env, JSON.stringify(envVars));
|
|
137
145
|
}, [envVars, isMounted]);
|
|
138
146
|
|
|
147
|
+
useEffect(() => {
|
|
148
|
+
if (isMounted) localStorage.setItem("kyro_rest_current", JSON.stringify(currentRequest));
|
|
149
|
+
}, [currentRequest, isMounted]);
|
|
150
|
+
|
|
139
151
|
const resolveUrl = (url: string) => {
|
|
140
152
|
let resolved = url;
|
|
141
153
|
envVars.forEach((v) => {
|
|
@@ -33,7 +33,7 @@ export function AutoFormApiView({
|
|
|
33
33
|
<label className="text-[10px] font-bold tracking-[0.1em] text-[var(--kyro-text-secondary)] opacity-50 block mb-2">
|
|
34
34
|
Reference Path
|
|
35
35
|
</label>
|
|
36
|
-
<div className="bg-[var(--kyro-bg-secondary)] px-4 py-3 rounded-
|
|
36
|
+
<div className="bg-[var(--kyro-bg-secondary)] px-4 py-3 rounded-md border border-[var(--kyro-border)] text-[11px] font-mono break-all selection:bg-[var(--kyro-primary)]/20 text-[var(--kyro-text-primary)]">
|
|
37
37
|
{globalSlug
|
|
38
38
|
? `kyro.globals('${globalSlug}').get()`
|
|
39
39
|
: formData.id
|
|
@@ -167,7 +167,7 @@ export function AutoFormVersionView({
|
|
|
167
167
|
)}
|
|
168
168
|
</div>
|
|
169
169
|
<div className="text-[11px] text-[var(--kyro-text-muted)]">
|
|
170
|
-
{new Date(v.createdAt as string).toLocaleString("en-US", {
|
|
170
|
+
{new Date((v.createdAt || (v as any).created_at) as string).toLocaleString("en-US", {
|
|
171
171
|
month: "short",
|
|
172
172
|
day: "numeric",
|
|
173
173
|
hour: "2-digit",
|
|
@@ -236,7 +236,7 @@ export function AutoFormVersionView({
|
|
|
236
236
|
</div>
|
|
237
237
|
<div className="flex items-center gap-2 mt-1 flex-wrap">
|
|
238
238
|
<span className="text-[11px] text-[var(--kyro-text-muted)]">
|
|
239
|
-
{new Date(v.createdAt as string).toLocaleString("en-US", {
|
|
239
|
+
{new Date((v.createdAt || (v as any).created_at) as string).toLocaleString("en-US", {
|
|
240
240
|
month: "short",
|
|
241
241
|
day: "numeric",
|
|
242
242
|
hour: "2-digit",
|
|
@@ -8,9 +8,7 @@ import { CodeBlock } from "../../blocks/CodeBlock";
|
|
|
8
8
|
import { FileBlock } from "../../blocks/FileBlock";
|
|
9
9
|
import { AccordionBlock } from "../../blocks/AccordionBlock";
|
|
10
10
|
import { RichTextBlock } from "../../blocks/RichTextBlock";
|
|
11
|
-
|
|
12
11
|
import { HeroBlock } from "../../blocks/HeroBlock";
|
|
13
|
-
import { HeadingSubheadingBlock } from "../../blocks/HeadingSubheadingBlock";
|
|
14
12
|
import { CardBlock } from "../../blocks/CardBlock";
|
|
15
13
|
import { ArrayBlock } from "../../blocks/ArrayBlock";
|
|
16
14
|
import { RelationshipBlock } from "../../blocks/RelationshipBlock";
|
|
@@ -53,7 +51,6 @@ export const BLOCK_COMPONENTS: Record<string, React.ComponentType<{ block: Recor
|
|
|
53
51
|
richtext: RichTextBlock,
|
|
54
52
|
|
|
55
53
|
hero: HeroBlock,
|
|
56
|
-
"heading-subheading": HeadingSubheadingBlock,
|
|
57
54
|
card: CardBlock,
|
|
58
55
|
array: ArrayBlock,
|
|
59
56
|
relationship: RelationshipBlock,
|
|
@@ -61,19 +58,19 @@ export const BLOCK_COMPONENTS: Record<string, React.ComponentType<{ block: Recor
|
|
|
61
58
|
|
|
62
59
|
// Block Theme mapping for consistent coloring across UI
|
|
63
60
|
export const blockTheme: Record<string, { text: string; border: string; borderLeft: string }> = {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
61
|
+
featureSplit: { text: "text-indigo-500", border: "border-indigo-500", borderLeft: "border-l-indigo-500" },
|
|
62
|
+
featureGrid: { text: "text-blue-500", border: "border-blue-500", borderLeft: "border-l-blue-500" },
|
|
63
|
+
ctaBanner: { text: "text-amber-500", border: "border-amber-500", borderLeft: "border-l-amber-500" },
|
|
67
64
|
testimonials: { text: "text-emerald-500", border: "border-emerald-500", borderLeft: "border-l-emerald-500" },
|
|
68
65
|
faq: { text: "text-orange-500", border: "border-orange-500", borderLeft: "border-l-orange-500" },
|
|
69
66
|
stats: { text: "text-rose-500", border: "border-rose-500", borderLeft: "border-l-rose-500" },
|
|
70
|
-
|
|
67
|
+
logoCloud: { text: "text-cyan-500", border: "border-cyan-500", borderLeft: "border-l-cyan-500" },
|
|
71
68
|
pricing: { text: "text-green-500", border: "border-green-500", borderLeft: "border-l-green-500" },
|
|
72
69
|
team: { text: "text-violet-500", border: "border-violet-500", borderLeft: "border-l-violet-500" },
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
70
|
+
recentFeed: { text: "text-sky-500", border: "border-sky-500", borderLeft: "border-l-sky-500" },
|
|
71
|
+
processSteps: { text: "text-fuchsia-500", border: "border-fuchsia-500", borderLeft: "border-l-fuchsia-500" },
|
|
72
|
+
formEmbed: { text: "text-pink-500", border: "border-pink-500", borderLeft: "border-l-pink-500" },
|
|
73
|
+
videoShowcase: { text: "text-red-500", border: "border-red-500", borderLeft: "border-l-red-500" },
|
|
77
74
|
hero: { text: "text-yellow-500", border: "border-yellow-500", borderLeft: "border-l-yellow-500" },
|
|
78
75
|
card: { text: "text-teal-500", border: "border-teal-500", borderLeft: "border-l-teal-500" },
|
|
79
76
|
default: { text: "text-zinc-400", border: "border-zinc-400", borderLeft: "border-l-zinc-400" },
|
|
@@ -92,25 +89,24 @@ export const blockIcons: Record<string, React.ReactNode> = {
|
|
|
92
89
|
richtext: <AlignLeft className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
93
90
|
|
|
94
91
|
hero: <Star className={`w-4 h-4 ${blockTheme.hero.text}`} />,
|
|
95
|
-
"heading-subheading": <Heading1 className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
96
92
|
card: <Box className={`w-4 h-4 ${blockTheme.card.text}`} />,
|
|
97
93
|
array: <ListOrdered className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
98
94
|
relationship: <Link2 className={`w-4 h-4 ${blockTheme.default.text}`} />,
|
|
99
95
|
|
|
100
96
|
// New Block Icons
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
97
|
+
featureSplit: <Columns3 className={`w-4 h-4 ${blockTheme.featureSplit.text}`} />,
|
|
98
|
+
featureGrid: <Blocks className={`w-4 h-4 ${blockTheme.featureGrid.text}`} />,
|
|
99
|
+
ctaBanner: <Sparkles className={`w-4 h-4 ${blockTheme.ctaBanner.text}`} />,
|
|
104
100
|
testimonials: <Users className={`w-4 h-4 ${blockTheme.testimonials.text}`} />,
|
|
105
101
|
faq: <HelpCircle className={`w-4 h-4 ${blockTheme.faq.text}`} />,
|
|
106
102
|
stats: <Activity className={`w-4 h-4 ${blockTheme.stats.text}`} />,
|
|
107
|
-
|
|
103
|
+
logoCloud: <Image className={`w-4 h-4 ${blockTheme.logoCloud.text}`} />,
|
|
108
104
|
pricing: <Tag className={`w-4 h-4 ${blockTheme.pricing.text}`} />,
|
|
109
105
|
team: <Users className={`w-4 h-4 ${blockTheme.team.text}`} />,
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
106
|
+
recentFeed: <Database className={`w-4 h-4 ${blockTheme.recentFeed.text}`} />,
|
|
107
|
+
processSteps: <Clock className={`w-4 h-4 ${blockTheme.processSteps.text}`} />,
|
|
108
|
+
formEmbed: <Mail className={`w-4 h-4 ${blockTheme.formEmbed.text}`} />,
|
|
109
|
+
videoShowcase: <Video className={`w-4 h-4 ${blockTheme.videoShowcase.text}`} />,
|
|
114
110
|
};
|
|
115
111
|
|
|
116
112
|
// Internal utility to check if block has a specific custom react component
|
|
@@ -121,9 +117,9 @@ export function getBlockComponent(type: string) {
|
|
|
121
117
|
// Determines if block is a native layout requiring generic rendering
|
|
122
118
|
export function isGenericSemanticBlock(type: string) {
|
|
123
119
|
return [
|
|
124
|
-
"
|
|
125
|
-
"testimonials", "faq", "stats", "
|
|
126
|
-
"pricing", "team", "
|
|
120
|
+
"featureSplit", "featureGrid", "ctaBanner",
|
|
121
|
+
"testimonials", "faq", "stats", "logoCloud",
|
|
122
|
+
"pricing", "team", "recentFeed", "processSteps", "formEmbed", "videoShowcase"
|
|
127
123
|
].includes(type);
|
|
128
124
|
}
|
|
129
125
|
|
|
@@ -145,32 +141,31 @@ export function getBlockLabel(type: string): string {
|
|
|
145
141
|
|
|
146
142
|
// Core Semantic Blocks
|
|
147
143
|
hero: "Hero Section",
|
|
148
|
-
"heading-subheading": "Heading + Subheading",
|
|
149
144
|
card: "Card Block",
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
145
|
+
featureSplit: "Feature Split",
|
|
146
|
+
featureGrid: "Feature Grid",
|
|
147
|
+
ctaBanner: "CTA Banner",
|
|
153
148
|
testimonials: "Testimonials Stack",
|
|
154
149
|
faq: "FAQ Section",
|
|
155
150
|
stats: "Stats & Metrics",
|
|
156
|
-
|
|
151
|
+
logoCloud: "Logo Cloud",
|
|
157
152
|
|
|
158
153
|
// Brand New Blocks
|
|
159
154
|
pricing: "Pricing Grid / Plan",
|
|
160
155
|
team: "Team Profiles Showcase",
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
156
|
+
recentFeed: "Dynamic Content Feed",
|
|
157
|
+
processSteps: "Process Timeline / Steps",
|
|
158
|
+
formEmbed: "Lead Intake Form",
|
|
159
|
+
videoShowcase: "Cinematic Video Showcase",
|
|
165
160
|
|
|
166
161
|
// Inline Content Elements
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
162
|
+
headingElement: "Heading",
|
|
163
|
+
textElement: "Text",
|
|
164
|
+
imageElement: "Image",
|
|
165
|
+
richtextElement: "Rich Text",
|
|
166
|
+
buttonElement: "Button",
|
|
167
|
+
videoElement: "Video",
|
|
168
|
+
listElement: "List",
|
|
174
169
|
};
|
|
175
170
|
return labelMap[type] || type;
|
|
176
171
|
}
|