@ai-stack/payloadcms 3.76.0-beta.0 → 3.76.0-beta.1
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/ai/core/media/image/handlers/multimodal.js +13 -33
- package/dist/ai/core/media/image/handlers/multimodal.js.map +1 -1
- package/dist/ai/core/media/image/handlers/standard.js +10 -7
- package/dist/ai/core/media/image/handlers/standard.js.map +1 -1
- package/dist/ai/core/media/speech/generateSpeech.js +8 -8
- package/dist/ai/core/media/speech/generateSpeech.js.map +1 -1
- package/dist/ai/core/media/types.d.ts +1 -1
- package/dist/ai/core/media/types.js.map +1 -1
- package/dist/ai/providers/blocks/google.js +1 -0
- package/dist/ai/providers/blocks/google.js.map +1 -1
- package/dist/ai/providers/registry.js +2 -2
- package/dist/ai/providers/registry.js.map +1 -1
- package/dist/collections/AIProviders.d.ts +2 -0
- package/dist/collections/{AISettings.js → AIProviders.js} +7 -6
- package/dist/collections/AIProviders.js.map +1 -0
- package/dist/collections/Instructions.js +8 -4
- package/dist/collections/Instructions.js.map +1 -1
- package/dist/defaults.js +1 -1
- package/dist/defaults.js.map +1 -1
- package/dist/endpoints/fetchFields.js +1 -1
- package/dist/endpoints/fetchFields.js.map +1 -1
- package/dist/endpoints/fetchVoices.js +1 -1
- package/dist/endpoints/fetchVoices.js.map +1 -1
- package/dist/endpoints/index.js +56 -21
- package/dist/endpoints/index.js.map +1 -1
- package/dist/exports/client.d.ts +1 -1
- package/dist/exports/client.js +1 -1
- package/dist/exports/client.js.map +1 -1
- package/dist/plugin.js +2 -2
- package/dist/plugin.js.map +1 -1
- package/dist/providers/InstructionsProvider/useInstructions.js +1 -1
- package/dist/providers/InstructionsProvider/useInstructions.js.map +1 -1
- package/dist/types.d.ts +4 -4
- package/dist/types.js.map +1 -1
- package/dist/ui/AIConfigDashboard/index.d.ts +1 -1
- package/dist/ui/AIConfigDashboard/index.js +16 -14
- package/dist/ui/AIConfigDashboard/index.js.map +1 -1
- package/dist/ui/AIConfigDashboard/index.jsx +18 -13
- package/dist/ui/Compose/hooks/menu/TranslateMenu.d.ts +5 -0
- package/dist/ui/Compose/hooks/menu/TranslateMenu.js +45 -4
- package/dist/ui/Compose/hooks/menu/TranslateMenu.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/TranslateMenu.jsx +41 -5
- package/dist/ui/Compose/hooks/menu/menu.module.scss +4 -1
- package/dist/ui/Compose/hooks/useActiveFieldTracking.js +34 -0
- package/dist/ui/Compose/hooks/useActiveFieldTracking.js.map +1 -1
- package/dist/ui/Compose/hooks/useGenerateUpload.js +8 -2
- package/dist/ui/Compose/hooks/useGenerateUpload.js.map +1 -1
- package/dist/ui/ConfigDashboard/index.d.ts +2 -0
- package/dist/ui/ConfigDashboard/index.js +224 -0
- package/dist/ui/ConfigDashboard/index.js.map +1 -0
- package/dist/ui/ConfigDashboard/index.jsx +175 -0
- package/dist/ui/DynamicModelSelect/index.js +1 -1
- package/dist/ui/DynamicModelSelect/index.js.map +1 -1
- package/dist/ui/DynamicModelSelect/index.jsx +1 -1
- package/dist/ui/DynamicProviderSelect/index.js +1 -1
- package/dist/ui/DynamicProviderSelect/index.js.map +1 -1
- package/dist/ui/DynamicProviderSelect/index.jsx +1 -1
- package/dist/ui/DynamicVoiceSelect/index.js +1 -1
- package/dist/ui/DynamicVoiceSelect/index.js.map +1 -1
- package/dist/ui/DynamicVoiceSelect/index.jsx +1 -1
- package/dist/ui/ProviderOptionsEditor/index.js +1 -1
- package/dist/ui/ProviderOptionsEditor/index.js.map +1 -1
- package/dist/ui/ProviderOptionsEditor/index.jsx +1 -1
- package/dist/utilities/updateFieldsConfig.js +1 -1
- package/dist/utilities/updateFieldsConfig.js.map +1 -1
- package/package.json +1 -1
- package/dist/collections/AISettings.d.ts +0 -2
- package/dist/collections/AISettings.js.map +0 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/ConfigDashboard/index.tsx"],"sourcesContent":["'use client'\n\nimport { Button, toast, useConfig } from '@payloadcms/ui'\n// @ts-expect-error - Next.js types are not resolving correctly with nodenext but runtime is fine\nimport { useRouter } from 'next/navigation'\nimport React, { use, useEffect, useState } from 'react'\n\nimport { excludeCollections } from '../../defaults.js'\nimport { InstructionsContext } from '../../providers/InstructionsProvider/context.js'\n\nexport const ConfigDashboard: React.FC = () => {\n const {\n config: {\n collections,\n routes: { admin: adminRoute, api: apiRoute },\n },\n } = useConfig()\n const router = useRouter()\n const { refresh, setEnabledCollections: setEnabledCollectionsInContext } =\n use(InstructionsContext)\n\n const [enabledCollections, setEnabledCollections] = useState<string[]>([])\n const [isLoading, setIsLoading] = useState(true)\n const [isSaving, setIsSaving] = useState(false)\n\n const availableCollections = collections.filter(\n (c) =>\n !excludeCollections.includes(c.slug) &&\n !(c.admin as unknown as { hidden?: ((args: any) => boolean) | boolean })?.hidden,\n )\n\n useEffect(() => {\n const fetchSettings = async () => {\n try {\n const response = await fetch(`${apiRoute}/globals/ai-providers`)\n if (response.ok) {\n const data = await response.json()\n // Handle both simple array and object wrapper if Payload wraps it\n const storedEnabled = data.enabledCollections || []\n setEnabledCollections(Array.isArray(storedEnabled) ? storedEnabled : [])\n }\n } catch (error) {\n console.error('Failed to fetch AI settings:', error)\n } finally {\n setIsLoading(false)\n }\n }\n\n fetchSettings().catch((e) => {\n console.log(e)\n })\n }, [apiRoute])\n\n const handleToggle = (slug: string) => {\n setEnabledCollections((prev) => {\n if (prev.includes(slug)) {\n return prev.filter((s) => s !== slug)\n }\n return [...prev, slug]\n })\n }\n\n const handleSave = async () => {\n setIsSaving(true)\n try {\n // First fetch current settings to get ID or just rely on global update behavior\n // We need to adhere to Payload's global update API\n const response = await fetch(`${apiRoute}/globals/ai-providers`, {\n body: JSON.stringify({\n enabledCollections,\n }),\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n\n if (response.ok) {\n toast.success('Settings saved successfully')\n if (setEnabledCollectionsInContext) {\n setEnabledCollectionsInContext(enabledCollections)\n }\n if (refresh) {\n await refresh()\n }\n router.refresh()\n } else {\n toast.error('Failed to save settings')\n }\n } catch (error) {\n console.error('Error saving settings:', error)\n toast.error('Error saving settings')\n } finally {\n setIsSaving(false)\n }\n }\n\n if (isLoading) {\n return <div style={{ padding: '20px', textAlign: 'center' }}>Loading configuration...</div>\n }\n\n return (\n <div\n style={{\n background: 'var(--theme-elevation-50)',\n // border: '1px solid var(--theme-elevation-150)',\n // borderRadius: '8px',\n // borderBottom: '1px solid var(--theme-elevation-150)',\n // borderTop: '1px solid var(--theme-elevation-150)',\n marginBottom: '20px',\n overflow: 'hidden',\n }}\n >\n <div\n style={{\n alignItems: 'center',\n borderBottom: '1px solid var(--theme-elevation-150)',\n display: 'flex',\n justifyContent: 'space-between',\n padding: '8px var(--gutter-h)',\n }}\n >\n <div>\n <h2 style={{ margin: '0 0 5px 0' }}>Let's configure your AI Plugin</h2>\n <p style={{ color: 'var(--theme-elevation-500)', fontSize: '14px', margin: '0' }}>\n Set up the provider → Choose the content → Refine the behavior.\n </p>\n </div>\n <div style={{ display: 'flex', gap: '10px' }}>\n <Button buttonStyle=\"secondary\" el=\"link\" to={`${adminRoute}/globals/ai-providers`}>\n Providers\n </Button>\n <Button disabled={isSaving} onClick={handleSave}>\n {isSaving ? 'Saving...' : 'Save Changes'}\n </Button>\n </div>\n </div>\n\n <div style={{ padding: '24px var(--gutter-h)' }}>\n <h5 style={{ marginBottom: '15px' }}>\n Select the collections where AI features should be available, toggle them on or off, and\n save your changes.\n </h5>\n <div\n style={{\n display: 'grid',\n gap: '15px',\n gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))',\n }}\n >\n {availableCollections.map((collection) => {\n const isEnabled = enabledCollections.includes(collection.slug)\n return (\n <button\n key={collection.slug}\n onClick={() => handleToggle(collection.slug)}\n style={{\n alignItems: 'center',\n background: isEnabled\n ? 'var(--theme-elevation-100)'\n : 'var(--theme-elevation-50)',\n border: `1px solid ${isEnabled ? 'var(--theme-text-success)' : 'var(--theme-elevation-200)'}`,\n borderRadius: '6px',\n cursor: 'pointer',\n display: 'flex',\n gap: '10px',\n padding: '10px 15px',\n textAlign: 'left',\n transition: 'all 0.2s ease',\n width: '100%',\n }}\n type=\"button\"\n >\n <div\n style={{\n alignItems: 'center',\n background: isEnabled\n ? 'var(--theme-text-success)'\n : 'var(--theme-elevation-200)',\n borderRadius: '12px',\n display: 'flex',\n height: '24px',\n justifyContent: isEnabled ? 'flex-end' : 'flex-start',\n padding: '2px',\n transition: 'all 0.2s ease',\n width: '44px',\n }}\n >\n <div\n style={{\n background: 'white',\n borderRadius: '50%',\n height: '20px',\n width: '20px',\n }}\n />\n </div>\n <span style={{ fontWeight: 500 }}>\n {typeof collection.labels?.singular === 'string'\n ? collection.labels.singular\n : collection.labels?.singular?.en || collection.slug}\n </span>\n </button>\n )\n })}\n </div>\n </div>\n </div>\n )\n}\n"],"names":["Button","toast","useConfig","useRouter","React","use","useEffect","useState","excludeCollections","InstructionsContext","ConfigDashboard","config","collections","routes","admin","adminRoute","api","apiRoute","router","refresh","setEnabledCollections","setEnabledCollectionsInContext","enabledCollections","isLoading","setIsLoading","isSaving","setIsSaving","availableCollections","filter","c","includes","slug","hidden","fetchSettings","response","fetch","ok","data","json","storedEnabled","Array","isArray","error","console","catch","e","log","handleToggle","prev","s","handleSave","body","JSON","stringify","headers","method","success","div","style","padding","textAlign","background","marginBottom","overflow","alignItems","borderBottom","display","justifyContent","h2","margin","p","color","fontSize","gap","buttonStyle","el","to","disabled","onClick","h5","gridTemplateColumns","map","collection","isEnabled","button","border","borderRadius","cursor","transition","width","type","height","span","fontWeight","labels","singular","en"],"mappings":"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"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { Button, toast, useConfig } from '@payloadcms/ui';
|
|
3
|
+
// @ts-expect-error - Next.js types are not resolving correctly with nodenext but runtime is fine
|
|
4
|
+
import { useRouter } from 'next/navigation';
|
|
5
|
+
import React, { use, useEffect, useState } from 'react';
|
|
6
|
+
import { excludeCollections } from '../../defaults.js';
|
|
7
|
+
import { InstructionsContext } from '../../providers/InstructionsProvider/context.js';
|
|
8
|
+
export const ConfigDashboard = () => {
|
|
9
|
+
const { config: { collections, routes: { admin: adminRoute, api: apiRoute }, }, } = useConfig();
|
|
10
|
+
const router = useRouter();
|
|
11
|
+
const { refresh, setEnabledCollections: setEnabledCollectionsInContext } = use(InstructionsContext);
|
|
12
|
+
const [enabledCollections, setEnabledCollections] = useState([]);
|
|
13
|
+
const [isLoading, setIsLoading] = useState(true);
|
|
14
|
+
const [isSaving, setIsSaving] = useState(false);
|
|
15
|
+
const availableCollections = collections.filter((c) => !excludeCollections.includes(c.slug) &&
|
|
16
|
+
!c.admin?.hidden);
|
|
17
|
+
useEffect(() => {
|
|
18
|
+
const fetchSettings = async () => {
|
|
19
|
+
try {
|
|
20
|
+
const response = await fetch(`${apiRoute}/globals/ai-providers`);
|
|
21
|
+
if (response.ok) {
|
|
22
|
+
const data = await response.json();
|
|
23
|
+
// Handle both simple array and object wrapper if Payload wraps it
|
|
24
|
+
const storedEnabled = data.enabledCollections || [];
|
|
25
|
+
setEnabledCollections(Array.isArray(storedEnabled) ? storedEnabled : []);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
console.error('Failed to fetch AI settings:', error);
|
|
30
|
+
}
|
|
31
|
+
finally {
|
|
32
|
+
setIsLoading(false);
|
|
33
|
+
}
|
|
34
|
+
};
|
|
35
|
+
fetchSettings().catch((e) => {
|
|
36
|
+
console.log(e);
|
|
37
|
+
});
|
|
38
|
+
}, [apiRoute]);
|
|
39
|
+
const handleToggle = (slug) => {
|
|
40
|
+
setEnabledCollections((prev) => {
|
|
41
|
+
if (prev.includes(slug)) {
|
|
42
|
+
return prev.filter((s) => s !== slug);
|
|
43
|
+
}
|
|
44
|
+
return [...prev, slug];
|
|
45
|
+
});
|
|
46
|
+
};
|
|
47
|
+
const handleSave = async () => {
|
|
48
|
+
setIsSaving(true);
|
|
49
|
+
try {
|
|
50
|
+
// First fetch current settings to get ID or just rely on global update behavior
|
|
51
|
+
// We need to adhere to Payload's global update API
|
|
52
|
+
const response = await fetch(`${apiRoute}/globals/ai-providers`, {
|
|
53
|
+
body: JSON.stringify({
|
|
54
|
+
enabledCollections,
|
|
55
|
+
}),
|
|
56
|
+
headers: {
|
|
57
|
+
'Content-Type': 'application/json',
|
|
58
|
+
},
|
|
59
|
+
method: 'POST',
|
|
60
|
+
});
|
|
61
|
+
if (response.ok) {
|
|
62
|
+
toast.success('Settings saved successfully');
|
|
63
|
+
if (setEnabledCollectionsInContext) {
|
|
64
|
+
setEnabledCollectionsInContext(enabledCollections);
|
|
65
|
+
}
|
|
66
|
+
if (refresh) {
|
|
67
|
+
await refresh();
|
|
68
|
+
}
|
|
69
|
+
router.refresh();
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
toast.error('Failed to save settings');
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
console.error('Error saving settings:', error);
|
|
77
|
+
toast.error('Error saving settings');
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
setIsSaving(false);
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
if (isLoading) {
|
|
84
|
+
return <div style={{ padding: '20px', textAlign: 'center' }}>Loading configuration...</div>;
|
|
85
|
+
}
|
|
86
|
+
return (<div style={{
|
|
87
|
+
background: 'var(--theme-elevation-50)',
|
|
88
|
+
// border: '1px solid var(--theme-elevation-150)',
|
|
89
|
+
// borderRadius: '8px',
|
|
90
|
+
// borderBottom: '1px solid var(--theme-elevation-150)',
|
|
91
|
+
// borderTop: '1px solid var(--theme-elevation-150)',
|
|
92
|
+
marginBottom: '20px',
|
|
93
|
+
overflow: 'hidden',
|
|
94
|
+
}}>
|
|
95
|
+
<div style={{
|
|
96
|
+
alignItems: 'center',
|
|
97
|
+
borderBottom: '1px solid var(--theme-elevation-150)',
|
|
98
|
+
display: 'flex',
|
|
99
|
+
justifyContent: 'space-between',
|
|
100
|
+
padding: '8px var(--gutter-h)',
|
|
101
|
+
}}>
|
|
102
|
+
<div>
|
|
103
|
+
<h2 style={{ margin: '0 0 5px 0' }}>Let's configure your AI Plugin</h2>
|
|
104
|
+
<p style={{ color: 'var(--theme-elevation-500)', fontSize: '14px', margin: '0' }}>
|
|
105
|
+
Set up the provider → Choose the content → Refine the behavior.
|
|
106
|
+
</p>
|
|
107
|
+
</div>
|
|
108
|
+
<div style={{ display: 'flex', gap: '10px' }}>
|
|
109
|
+
<Button buttonStyle="secondary" el="link" to={`${adminRoute}/globals/ai-providers`}>
|
|
110
|
+
Providers
|
|
111
|
+
</Button>
|
|
112
|
+
<Button disabled={isSaving} onClick={handleSave}>
|
|
113
|
+
{isSaving ? 'Saving...' : 'Save Changes'}
|
|
114
|
+
</Button>
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
|
|
118
|
+
<div style={{ padding: '24px var(--gutter-h)' }}>
|
|
119
|
+
<h5 style={{ marginBottom: '15px' }}>
|
|
120
|
+
Select the collections where AI features should be available, toggle them on or off, and
|
|
121
|
+
save your changes.
|
|
122
|
+
</h5>
|
|
123
|
+
<div style={{
|
|
124
|
+
display: 'grid',
|
|
125
|
+
gap: '15px',
|
|
126
|
+
gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))',
|
|
127
|
+
}}>
|
|
128
|
+
{availableCollections.map((collection) => {
|
|
129
|
+
const isEnabled = enabledCollections.includes(collection.slug);
|
|
130
|
+
return (<button key={collection.slug} onClick={() => handleToggle(collection.slug)} style={{
|
|
131
|
+
alignItems: 'center',
|
|
132
|
+
background: isEnabled
|
|
133
|
+
? 'var(--theme-elevation-100)'
|
|
134
|
+
: 'var(--theme-elevation-50)',
|
|
135
|
+
border: `1px solid ${isEnabled ? 'var(--theme-text-success)' : 'var(--theme-elevation-200)'}`,
|
|
136
|
+
borderRadius: '6px',
|
|
137
|
+
cursor: 'pointer',
|
|
138
|
+
display: 'flex',
|
|
139
|
+
gap: '10px',
|
|
140
|
+
padding: '10px 15px',
|
|
141
|
+
textAlign: 'left',
|
|
142
|
+
transition: 'all 0.2s ease',
|
|
143
|
+
width: '100%',
|
|
144
|
+
}} type="button">
|
|
145
|
+
<div style={{
|
|
146
|
+
alignItems: 'center',
|
|
147
|
+
background: isEnabled
|
|
148
|
+
? 'var(--theme-text-success)'
|
|
149
|
+
: 'var(--theme-elevation-200)',
|
|
150
|
+
borderRadius: '12px',
|
|
151
|
+
display: 'flex',
|
|
152
|
+
height: '24px',
|
|
153
|
+
justifyContent: isEnabled ? 'flex-end' : 'flex-start',
|
|
154
|
+
padding: '2px',
|
|
155
|
+
transition: 'all 0.2s ease',
|
|
156
|
+
width: '44px',
|
|
157
|
+
}}>
|
|
158
|
+
<div style={{
|
|
159
|
+
background: 'white',
|
|
160
|
+
borderRadius: '50%',
|
|
161
|
+
height: '20px',
|
|
162
|
+
width: '20px',
|
|
163
|
+
}}/>
|
|
164
|
+
</div>
|
|
165
|
+
<span style={{ fontWeight: 500 }}>
|
|
166
|
+
{typeof collection.labels?.singular === 'string'
|
|
167
|
+
? collection.labels.singular
|
|
168
|
+
: collection.labels?.singular?.en || collection.slug}
|
|
169
|
+
</span>
|
|
170
|
+
</button>);
|
|
171
|
+
})}
|
|
172
|
+
</div>
|
|
173
|
+
</div>
|
|
174
|
+
</div>);
|
|
175
|
+
};
|
|
@@ -94,7 +94,7 @@ export const DynamicModelSelect = (props)=>{
|
|
|
94
94
|
useEffect(()=>{
|
|
95
95
|
const fetchSettings = async ()=>{
|
|
96
96
|
try {
|
|
97
|
-
const response = await fetch('/api/globals/ai-
|
|
97
|
+
const response = await fetch('/api/globals/ai-providers?depth=1');
|
|
98
98
|
if (response.ok) {
|
|
99
99
|
const data = await response.json();
|
|
100
100
|
if (data && data.providers) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/DynamicModelSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField, useFormFields } from '@payloadcms/ui'\nimport React, { useEffect, useMemo, useState } from 'react'\n\nimport { allProviderBlocks } from '../../ai/providers/blocks/index.js'\n\ntype Props = {\n name: string\n path: string\n}\n\n/**\n * Find a field by name within a block's fields, searching through tabs\n */\nfunction findFieldInBlock(block: any, fieldName: string): any | undefined {\n const searchFields = (fields: any[]): any | undefined => {\n for (const field of fields) {\n if ('name' in field && field.name === fieldName) {\n return field\n }\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n const found = searchFields(tab.fields)\n if (found) {\n return found\n }\n }\n }\n if (field.type === 'group' && 'fields' in field) {\n const found = searchFields(field.fields)\n if (found) {\n return found\n }\n }\n }\n return undefined\n }\n \n return searchFields(block.fields)\n}\n\n/**\n * Infer use case from field path\n * Handles both:\n * - AISettings paths: 'defaults.text.model', 'defaults.image.model'\n * - Instructions paths: 'text-settings.model', 'image-settings.model'\n */\nfunction inferUseCase(path: string): string {\n const pathParts = path.split('.')\n const parentName = pathParts[pathParts.length - 2]\n \n // AISettings: 'defaults.text.model' -> parentName is 'text'\n // Direct use case names\n if (['image', 'text', 'tts', 'video'].includes(parentName)) {\n return parentName\n }\n \n // Instructions: 'text-settings.model' -> parentName is 'text-settings'\n if (parentName === 'image-settings') {\n return 'image'\n }\n if (parentName === 'tts-settings') {\n return 'tts'\n }\n if (parentName === 'text-settings' || parentName === 'richtext-settings') {\n return 'text'\n }\n if (parentName === 'video-settings') {\n return 'video'\n }\n \n // Default to text\n return 'text'\n}\n\nexport const DynamicModelSelect: React.FC<Props> = (props) => {\n const { name, path } = props\n\n // Getting the 'provider' sibling field value\n const parentPath = path.split('.').slice(0, -1).join('.')\n const providerPath = `${parentPath}.provider`\n\n const providerField = useFormFields(([fields]) => fields[providerPath])\n const providerValue = providerField?.value as string\n\n // Get all form fields to search for live provider configuration (for AISettings context)\n // We filter to only 'providers' fields to avoid unnecessary re-renders, \n // but note that the selector runs on every change.\n const formProviders = useFormFields(([fields]) => {\n const providers: Record<string, any> = {}\n if (fields && typeof fields === 'object') {\n Object.keys(fields).forEach((key) => {\n if (key.startsWith('providers.')) {\n providers[key] = fields[key]\n }\n })\n }\n return providers\n })\n\n const { setValue, value } = useField<string>({ path })\n\n // State to hold fetched providers data\n const [providersData, setProvidersData] = useState<any[]>([])\n\n // Fetch AI Settings global to get configured providers\n useEffect(() => {\n const fetchSettings = async () => {\n try {\n const response = await fetch('/api/globals/ai-settings?depth=1')\n if (response.ok) {\n const data = await response.json()\n if (data && data.providers) {\n setProvidersData(data.providers)\n }\n }\n } catch (error) {\n console.error('Error fetching AI settings:', error)\n }\n }\n\n fetchSettings().catch(console.error)\n }, [])\n\n const inferredUseCase = useMemo(() => inferUseCase(path), [path])\n\n const options = useMemo(() => {\n if (!providerValue) {\n return []\n }\n\n const optionsList: { label: string; value: string }[] = []\n\n // Strategy:\n // 1. Try to find provider in LIVE form state (if editing AISettings)\n // 2. If not found, try to find in FETCHED API data (if editing Instructions or saved AISettings)\n // 3. Fall back to static defaults from block definitions\n\n let foundInForm = false\n let foundInAPI = false\n\n // --- 1. Live Form Search ---\n // Iterate through form fields to find the matching provider block\n // We assume standard block structure: providers.0.blockType, etc.\n // We search up to 20 providers to be safe (unlikely to have more)\n for (let i = 0; i < 20; i++) {\n const typeKey = `providers.${i}.blockType`\n const typeField = formProviders[typeKey]\n \n if (!typeField) {break} // Stop if no more blocks (or gap)\n \n if (typeof typeField === 'object' && 'value' in typeField && typeField.value === providerValue) {\n foundInForm = true\n // Found the provider! Now iterate its models\n // Models path: providers.0.models.0.id\n for (let j = 0; j < 50; j++) {\n const idKey = `providers.${i}.models.${j}.id`\n const nameKey = `providers.${i}.models.${j}.name`\n const useCaseKey = `providers.${i}.models.${j}.useCase`\n const enabledKey = `providers.${i}.models.${j}.enabled`\n \n const idField = formProviders[idKey]\n if (!idField) {break} // Stop if no more models\n \n const modelId = (idField).value as string\n const modelName = (formProviders[nameKey])?.value as string\n const modelUseCase = (formProviders[useCaseKey])?.value as string\n const modelEnabled = (formProviders[enabledKey])?.value\n \n // Check use case and enabled status (default to enabled if undefined)\n if (modelUseCase === inferredUseCase && modelEnabled !== false) {\n optionsList.push({\n label: modelName || modelId,\n value: modelId,\n })\n }\n }\n break // Stop searching providers\n }\n }\n\n // --- 2. API Data Search (if not found in form) ---\n if (!foundInForm) {\n const userProviderBlock = providersData.find((p: any) => p.blockType === providerValue)\n\n if (userProviderBlock && userProviderBlock.models) {\n foundInAPI = true\n userProviderBlock.models.forEach((m: any) => {\n if (m.useCase === inferredUseCase && m.enabled !== false) {\n // Avoid duplicates\n if (!optionsList.some((opt) => opt.value === m.id)) {\n optionsList.push({\n label: m.name,\n value: m.id,\n })\n }\n }\n })\n }\n }\n\n // --- 3. Static Defaults (if not found in form OR API) ---\n // Note: We only fall back to static if we didn't find ANY configuration for this provider.\n // If we found the provider but it had no models for this use case, we show empty list (correct).\n if (!foundInForm && !foundInAPI) {\n const staticBlock = allProviderBlocks.find((b) => b.slug === providerValue)\n\n if (staticBlock) {\n // Search through tabs to find models field\n const modelsField = findFieldInBlock(staticBlock, 'models')\n const defaultModels =\n modelsField && 'defaultValue' in modelsField ? (modelsField.defaultValue as any[]) : []\n\n defaultModels.forEach((m) => {\n if (m.useCase === inferredUseCase && m.enabled !== false) {\n optionsList.push({\n label: m.name,\n value: m.id,\n })\n }\n })\n }\n }\n\n return optionsList\n }, [providerValue, providersData, inferredUseCase, formProviders])\n\n return (\n <div className=\"field-type select\">\n <label className=\"field-label\" htmlFor={path}>\n Model\n </label>\n <SelectInput\n name={name}\n onChange={(option) => {\n if (option && typeof option === 'object' && 'value' in option) {\n setValue(option.value as string)\n } else {\n setValue(option)\n }\n }}\n options={options as any}\n path={path}\n value={value}\n />\n </div>\n )\n}\n\n"],"names":["SelectInput","useField","useFormFields","React","useEffect","useMemo","useState","allProviderBlocks","findFieldInBlock","block","fieldName","searchFields","fields","field","name","type","tab","tabs","found","undefined","inferUseCase","path","pathParts","split","parentName","length","includes","DynamicModelSelect","props","parentPath","slice","join","providerPath","providerField","providerValue","value","formProviders","providers","Object","keys","forEach","key","startsWith","setValue","providersData","setProvidersData","fetchSettings","response","fetch","ok","data","json","error","console","catch","inferredUseCase","options","optionsList","foundInForm","foundInAPI","i","typeKey","typeField","j","idKey","nameKey","useCaseKey","enabledKey","idField","modelId","modelName","modelUseCase","modelEnabled","push","label","userProviderBlock","find","p","blockType","models","m","useCase","enabled","some","opt","id","staticBlock","b","slug","modelsField","defaultModels","defaultValue","div","className","htmlFor","onChange","option"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/DynamicModelSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField, useFormFields } from '@payloadcms/ui'\nimport React, { useEffect, useMemo, useState } from 'react'\n\nimport { allProviderBlocks } from '../../ai/providers/blocks/index.js'\n\ntype Props = {\n name: string\n path: string\n}\n\n/**\n * Find a field by name within a block's fields, searching through tabs\n */\nfunction findFieldInBlock(block: any, fieldName: string): any | undefined {\n const searchFields = (fields: any[]): any | undefined => {\n for (const field of fields) {\n if ('name' in field && field.name === fieldName) {\n return field\n }\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n const found = searchFields(tab.fields)\n if (found) {\n return found\n }\n }\n }\n if (field.type === 'group' && 'fields' in field) {\n const found = searchFields(field.fields)\n if (found) {\n return found\n }\n }\n }\n return undefined\n }\n \n return searchFields(block.fields)\n}\n\n/**\n * Infer use case from field path\n * Handles both:\n * - AISettings paths: 'defaults.text.model', 'defaults.image.model'\n * - Instructions paths: 'text-settings.model', 'image-settings.model'\n */\nfunction inferUseCase(path: string): string {\n const pathParts = path.split('.')\n const parentName = pathParts[pathParts.length - 2]\n \n // AISettings: 'defaults.text.model' -> parentName is 'text'\n // Direct use case names\n if (['image', 'text', 'tts', 'video'].includes(parentName)) {\n return parentName\n }\n \n // Instructions: 'text-settings.model' -> parentName is 'text-settings'\n if (parentName === 'image-settings') {\n return 'image'\n }\n if (parentName === 'tts-settings') {\n return 'tts'\n }\n if (parentName === 'text-settings' || parentName === 'richtext-settings') {\n return 'text'\n }\n if (parentName === 'video-settings') {\n return 'video'\n }\n \n // Default to text\n return 'text'\n}\n\nexport const DynamicModelSelect: React.FC<Props> = (props) => {\n const { name, path } = props\n\n // Getting the 'provider' sibling field value\n const parentPath = path.split('.').slice(0, -1).join('.')\n const providerPath = `${parentPath}.provider`\n\n const providerField = useFormFields(([fields]) => fields[providerPath])\n const providerValue = providerField?.value as string\n\n // Get all form fields to search for live provider configuration (for AISettings context)\n // We filter to only 'providers' fields to avoid unnecessary re-renders, \n // but note that the selector runs on every change.\n const formProviders = useFormFields(([fields]) => {\n const providers: Record<string, any> = {}\n if (fields && typeof fields === 'object') {\n Object.keys(fields).forEach((key) => {\n if (key.startsWith('providers.')) {\n providers[key] = fields[key]\n }\n })\n }\n return providers\n })\n\n const { setValue, value } = useField<string>({ path })\n\n // State to hold fetched providers data\n const [providersData, setProvidersData] = useState<any[]>([])\n\n // Fetch AI Settings global to get configured providers\n useEffect(() => {\n const fetchSettings = async () => {\n try {\n const response = await fetch('/api/globals/ai-providers?depth=1')\n if (response.ok) {\n const data = await response.json()\n if (data && data.providers) {\n setProvidersData(data.providers)\n }\n }\n } catch (error) {\n console.error('Error fetching AI settings:', error)\n }\n }\n\n fetchSettings().catch(console.error)\n }, [])\n\n const inferredUseCase = useMemo(() => inferUseCase(path), [path])\n\n const options = useMemo(() => {\n if (!providerValue) {\n return []\n }\n\n const optionsList: { label: string; value: string }[] = []\n\n // Strategy:\n // 1. Try to find provider in LIVE form state (if editing AISettings)\n // 2. If not found, try to find in FETCHED API data (if editing Instructions or saved AISettings)\n // 3. Fall back to static defaults from block definitions\n\n let foundInForm = false\n let foundInAPI = false\n\n // --- 1. Live Form Search ---\n // Iterate through form fields to find the matching provider block\n // We assume standard block structure: providers.0.blockType, etc.\n // We search up to 20 providers to be safe (unlikely to have more)\n for (let i = 0; i < 20; i++) {\n const typeKey = `providers.${i}.blockType`\n const typeField = formProviders[typeKey]\n \n if (!typeField) {break} // Stop if no more blocks (or gap)\n \n if (typeof typeField === 'object' && 'value' in typeField && typeField.value === providerValue) {\n foundInForm = true\n // Found the provider! Now iterate its models\n // Models path: providers.0.models.0.id\n for (let j = 0; j < 50; j++) {\n const idKey = `providers.${i}.models.${j}.id`\n const nameKey = `providers.${i}.models.${j}.name`\n const useCaseKey = `providers.${i}.models.${j}.useCase`\n const enabledKey = `providers.${i}.models.${j}.enabled`\n \n const idField = formProviders[idKey]\n if (!idField) {break} // Stop if no more models\n \n const modelId = (idField).value as string\n const modelName = (formProviders[nameKey])?.value as string\n const modelUseCase = (formProviders[useCaseKey])?.value as string\n const modelEnabled = (formProviders[enabledKey])?.value\n \n // Check use case and enabled status (default to enabled if undefined)\n if (modelUseCase === inferredUseCase && modelEnabled !== false) {\n optionsList.push({\n label: modelName || modelId,\n value: modelId,\n })\n }\n }\n break // Stop searching providers\n }\n }\n\n // --- 2. API Data Search (if not found in form) ---\n if (!foundInForm) {\n const userProviderBlock = providersData.find((p: any) => p.blockType === providerValue)\n\n if (userProviderBlock && userProviderBlock.models) {\n foundInAPI = true\n userProviderBlock.models.forEach((m: any) => {\n if (m.useCase === inferredUseCase && m.enabled !== false) {\n // Avoid duplicates\n if (!optionsList.some((opt) => opt.value === m.id)) {\n optionsList.push({\n label: m.name,\n value: m.id,\n })\n }\n }\n })\n }\n }\n\n // --- 3. Static Defaults (if not found in form OR API) ---\n // Note: We only fall back to static if we didn't find ANY configuration for this provider.\n // If we found the provider but it had no models for this use case, we show empty list (correct).\n if (!foundInForm && !foundInAPI) {\n const staticBlock = allProviderBlocks.find((b) => b.slug === providerValue)\n\n if (staticBlock) {\n // Search through tabs to find models field\n const modelsField = findFieldInBlock(staticBlock, 'models')\n const defaultModels =\n modelsField && 'defaultValue' in modelsField ? (modelsField.defaultValue as any[]) : []\n\n defaultModels.forEach((m) => {\n if (m.useCase === inferredUseCase && m.enabled !== false) {\n optionsList.push({\n label: m.name,\n value: m.id,\n })\n }\n })\n }\n }\n\n return optionsList\n }, [providerValue, providersData, inferredUseCase, formProviders])\n\n return (\n <div className=\"field-type select\">\n <label className=\"field-label\" htmlFor={path}>\n Model\n </label>\n <SelectInput\n name={name}\n onChange={(option) => {\n if (option && typeof option === 'object' && 'value' in option) {\n setValue(option.value as string)\n } else {\n setValue(option)\n }\n }}\n options={options as any}\n path={path}\n value={value}\n />\n </div>\n )\n}\n\n"],"names":["SelectInput","useField","useFormFields","React","useEffect","useMemo","useState","allProviderBlocks","findFieldInBlock","block","fieldName","searchFields","fields","field","name","type","tab","tabs","found","undefined","inferUseCase","path","pathParts","split","parentName","length","includes","DynamicModelSelect","props","parentPath","slice","join","providerPath","providerField","providerValue","value","formProviders","providers","Object","keys","forEach","key","startsWith","setValue","providersData","setProvidersData","fetchSettings","response","fetch","ok","data","json","error","console","catch","inferredUseCase","options","optionsList","foundInForm","foundInAPI","i","typeKey","typeField","j","idKey","nameKey","useCaseKey","enabledKey","idField","modelId","modelName","modelUseCase","modelEnabled","push","label","userProviderBlock","find","p","blockType","models","m","useCase","enabled","some","opt","id","staticBlock","b","slug","modelsField","defaultModels","defaultValue","div","className","htmlFor","onChange","option"],"mappings":"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"}
|
|
@@ -88,7 +88,7 @@ export const DynamicModelSelect = (props) => {
|
|
|
88
88
|
useEffect(() => {
|
|
89
89
|
const fetchSettings = async () => {
|
|
90
90
|
try {
|
|
91
|
-
const response = await fetch('/api/globals/ai-
|
|
91
|
+
const response = await fetch('/api/globals/ai-providers?depth=1');
|
|
92
92
|
if (response.ok) {
|
|
93
93
|
const data = await response.json();
|
|
94
94
|
if (data && data.providers) {
|
|
@@ -14,7 +14,7 @@ export const DynamicProviderSelect = (props)=>{
|
|
|
14
14
|
useEffect(()=>{
|
|
15
15
|
const fetchSettings = async ()=>{
|
|
16
16
|
try {
|
|
17
|
-
const response = await fetch('/api/globals/ai-
|
|
17
|
+
const response = await fetch('/api/globals/ai-providers?depth=1');
|
|
18
18
|
if (response.ok) {
|
|
19
19
|
const data = await response.json();
|
|
20
20
|
if (data && data.providers) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/DynamicProviderSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField } from '@payloadcms/ui'\nimport React, { useEffect, useMemo, useState } from 'react'\n\nimport { allProviderBlocks } from '../../ai/providers/blocks/index.js'\n\ntype Props = {\n name: string\n path: string\n}\n\nexport const DynamicProviderSelect: React.FC<Props> = (props) => {\n const { name, path } = props\n\n const { setValue, value } = useField<string>({ path })\n\n // State to hold fetched providers data\n const [providersData, setProvidersData] = useState<any[]>([])\n\n // Fetch AI Settings global to get configured providers\n useEffect(() => {\n const fetchSettings = async () => {\n try {\n const response = await fetch('/api/globals/ai-
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/DynamicProviderSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField } from '@payloadcms/ui'\nimport React, { useEffect, useMemo, useState } from 'react'\n\nimport { allProviderBlocks } from '../../ai/providers/blocks/index.js'\n\ntype Props = {\n name: string\n path: string\n}\n\nexport const DynamicProviderSelect: React.FC<Props> = (props) => {\n const { name, path } = props\n\n const { setValue, value } = useField<string>({ path })\n\n // State to hold fetched providers data\n const [providersData, setProvidersData] = useState<any[]>([])\n\n // Fetch AI Settings global to get configured providers\n useEffect(() => {\n const fetchSettings = async () => {\n try {\n const response = await fetch('/api/globals/ai-providers?depth=1')\n if (response.ok) {\n const data = await response.json()\n if (data && data.providers) {\n setProvidersData(data.providers)\n }\n }\n } catch (error) {\n console.error('Error fetching AI settings:', error)\n }\n }\n\n void fetchSettings()\n }, [])\n\n const options = useMemo(() => {\n const optionsList: { label: string; value: string }[] = []\n const processedProviders = new Set<string>()\n\n // Iterate through fetched providers to find custom names\n providersData.forEach((provider: any) => {\n if (!provider.enabled) {\n return\n }\n\n const blockType = provider.blockType\n const customName = provider.providerName\n\n // Get static label as fallback\n const staticBlock = allProviderBlocks.find((b) => b.slug === blockType)\n const staticLabel = staticBlock?.labels?.singular\n ? typeof staticBlock.labels.singular === 'string'\n ? staticBlock.labels.singular\n : blockType\n : blockType\n\n const label = customName || staticLabel\n\n if (!processedProviders.has(blockType)) {\n optionsList.push({\n label,\n value: blockType,\n })\n processedProviders.add(blockType)\n } else if (customName) {\n // Update existing label if custom name is available\n const existingOpt = optionsList.find((o) => o.value === blockType)\n if (existingOpt && existingOpt.label === staticLabel) {\n existingOpt.label = customName\n }\n }\n })\n\n // Add any other available providers from blocks that might not be configured yet?\n // Usually we only want to show configured providers in the selection list.\n // But for standard providers (OpenAI, Google), they might not need much config other than API key.\n // If they are not in the list, user can't select them.\n // However, if they are not enabled in settings, maybe we shouldn't show them?\n // Let's stick to showing all available blocks, but prioritizing configured ones with custom names.\n\n allProviderBlocks.forEach((block) => {\n if (!processedProviders.has(block.slug)) {\n optionsList.push({\n label: typeof block.labels?.singular === 'string' ? block.labels.singular : block.slug,\n value: block.slug,\n })\n }\n })\n\n return optionsList\n }, [providersData])\n\n return (\n <div className=\"field-type select\">\n <label className=\"field-label\" htmlFor={path}>\n Provider\n </label>\n <SelectInput\n name={name}\n onChange={(option) => {\n if (option && typeof option === 'object' && 'value' in option) {\n setValue(option.value)\n } else {\n setValue(option)\n }\n }}\n options={options as any}\n path={path}\n value={value}\n />\n </div>\n )\n}\n"],"names":["SelectInput","useField","React","useEffect","useMemo","useState","allProviderBlocks","DynamicProviderSelect","props","name","path","setValue","value","providersData","setProvidersData","fetchSettings","response","fetch","ok","data","json","providers","error","console","options","optionsList","processedProviders","Set","forEach","provider","enabled","blockType","customName","providerName","staticBlock","find","b","slug","staticLabel","labels","singular","label","has","push","add","existingOpt","o","block","div","className","htmlFor","onChange","option"],"mappings":"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"}
|
|
@@ -11,7 +11,7 @@ export const DynamicProviderSelect = (props) => {
|
|
|
11
11
|
useEffect(() => {
|
|
12
12
|
const fetchSettings = async () => {
|
|
13
13
|
try {
|
|
14
|
-
const response = await fetch('/api/globals/ai-
|
|
14
|
+
const response = await fetch('/api/globals/ai-providers?depth=1');
|
|
15
15
|
if (response.ok) {
|
|
16
16
|
const data = await response.json();
|
|
17
17
|
if (data && data.providers) {
|
|
@@ -20,7 +20,7 @@ export const DynamicVoiceSelect = (props)=>{
|
|
|
20
20
|
const fetchSettings = async ()=>{
|
|
21
21
|
setIsLoading(true);
|
|
22
22
|
try {
|
|
23
|
-
const response = await fetch('/api/globals/ai-
|
|
23
|
+
const response = await fetch('/api/globals/ai-providers?depth=1');
|
|
24
24
|
if (response.ok) {
|
|
25
25
|
const data = await response.json();
|
|
26
26
|
setAiSettings(data);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/DynamicVoiceSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField, useFormFields } from '@payloadcms/ui'\nimport React, { useEffect, useMemo, useState } from 'react'\n\ntype Props = {\n name: string\n path: string\n}\n\ninterface Voice {\n category?: string\n enabled?: boolean\n id: string\n labels?: Record<string, unknown>\n name: string\n preview_url?: string\n}\n\ninterface ProviderBlock {\n blockType: string\n enabled?: boolean\n voices?: Voice[]\n}\n\nexport const DynamicVoiceSelect: React.FC<Props> = (props) => {\n const { name, path } = props\n\n // Get provider from siblings\n const parentPath = path.split('.').slice(0, -1).join('.')\n const providerPath = `${parentPath}.provider`\n\n // Use useFormFields to get the provider field value - this will re-render when provider changes\n const providerField = useFormFields(([fields]) => fields[providerPath])\n const provider = (providerField?.value as string) || ''\n\n const { setValue, value } = useField<string>({ path })\n const [aiSettings, setAiSettings] = useState<{ providers?: ProviderBlock[] } | null>(null)\n const [isLoading, setIsLoading] = useState(true)\n\n // Fetch AI Settings - re-fetch when provider changes to ensure we have latest voices\n useEffect(() => {\n const fetchSettings = async () => {\n setIsLoading(true)\n try {\n const response = await fetch('/api/globals/ai-
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/DynamicVoiceSelect/index.tsx"],"sourcesContent":["'use client'\n\nimport { SelectInput, useField, useFormFields } from '@payloadcms/ui'\nimport React, { useEffect, useMemo, useState } from 'react'\n\ntype Props = {\n name: string\n path: string\n}\n\ninterface Voice {\n category?: string\n enabled?: boolean\n id: string\n labels?: Record<string, unknown>\n name: string\n preview_url?: string\n}\n\ninterface ProviderBlock {\n blockType: string\n enabled?: boolean\n voices?: Voice[]\n}\n\nexport const DynamicVoiceSelect: React.FC<Props> = (props) => {\n const { name, path } = props\n\n // Get provider from siblings\n const parentPath = path.split('.').slice(0, -1).join('.')\n const providerPath = `${parentPath}.provider`\n\n // Use useFormFields to get the provider field value - this will re-render when provider changes\n const providerField = useFormFields(([fields]) => fields[providerPath])\n const provider = (providerField?.value as string) || ''\n\n const { setValue, value } = useField<string>({ path })\n const [aiSettings, setAiSettings] = useState<{ providers?: ProviderBlock[] } | null>(null)\n const [isLoading, setIsLoading] = useState(true)\n\n // Fetch AI Settings - re-fetch when provider changes to ensure we have latest voices\n useEffect(() => {\n const fetchSettings = async () => {\n setIsLoading(true)\n try {\n const response = await fetch('/api/globals/ai-providers?depth=1')\n if (response.ok) {\n const data = await response.json()\n setAiSettings(data)\n }\n } catch (err) {\n console.error('Error fetching AI settings:', err)\n } finally {\n setIsLoading(false)\n }\n }\n\n void fetchSettings()\n }, [provider]) // Re-fetch when provider changes to ensure we have the latest voices\n\n const voices = useMemo(() => {\n if (!provider || !aiSettings?.providers) {\n return []\n }\n\n // Find the provider block matching the selected provider\n const providerBlock = aiSettings.providers.find(\n (p: ProviderBlock) => p.blockType === provider && p.enabled !== false,\n )\n\n if (!providerBlock?.voices) {\n return []\n }\n\n // Get enabled voices from provider block\n return providerBlock.voices\n .filter((v: Voice) => v.enabled !== false)\n .map((v: Voice) => ({\n label: v.name || v.id,\n value: v.id,\n }))\n }, [provider, aiSettings])\n\n // Clear voice selection when provider changes and current voice is not available\n useEffect(() => {\n if (value && voices.length > 0) {\n const voiceExists = voices.some((v) => v.value === value)\n if (!voiceExists) {\n setValue('')\n }\n }\n }, [voices, value, setValue])\n\n if (!provider) {\n return (\n <div className=\"field-type text\">\n <label className=\"field-label\" htmlFor={path}>\n Voice\n </label>\n <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px' }}>\n Please select a provider first.\n </p>\n </div>\n )\n }\n\n if (isLoading) {\n return (\n <div className=\"field-type text\">\n <label className=\"field-label\" htmlFor={path}>\n Voice\n </label>\n <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px' }}>Loading voices...</p>\n </div>\n )\n }\n\n if (voices.length === 0) {\n return (\n <div className=\"field-type text\">\n <label className=\"field-label\" htmlFor={path}>\n Voice\n </label>\n <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px' }}>\n No voices available. Please configure voices in AI Settings for {provider}.\n </p>\n </div>\n )\n }\n\n return (\n <div className=\"field-type select\">\n <label className=\"field-label\" htmlFor={path}>\n Voice\n </label>\n <SelectInput\n name={name}\n onChange={(option) => {\n if (option && typeof option === 'object' && 'value' in option) {\n setValue(option.value as string)\n } else {\n setValue(option)\n }\n }}\n options={voices}\n path={path}\n value={value}\n />\n </div>\n )\n}\n\n"],"names":["SelectInput","useField","useFormFields","React","useEffect","useMemo","useState","DynamicVoiceSelect","props","name","path","parentPath","split","slice","join","providerPath","providerField","fields","provider","value","setValue","aiSettings","setAiSettings","isLoading","setIsLoading","fetchSettings","response","fetch","ok","data","json","err","console","error","voices","providers","providerBlock","find","p","blockType","enabled","filter","v","map","label","id","length","voiceExists","some","div","className","htmlFor","style","color","fontSize","onChange","option","options"],"mappings":"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"}
|
|
@@ -17,7 +17,7 @@ export const DynamicVoiceSelect = (props) => {
|
|
|
17
17
|
const fetchSettings = async () => {
|
|
18
18
|
setIsLoading(true);
|
|
19
19
|
try {
|
|
20
|
-
const response = await fetch('/api/globals/ai-
|
|
20
|
+
const response = await fetch('/api/globals/ai-providers?depth=1');
|
|
21
21
|
if (response.ok) {
|
|
22
22
|
const data = await response.json();
|
|
23
23
|
setAiSettings(data);
|
|
@@ -86,7 +86,7 @@ export const ProviderOptionsEditor = (props)=>{
|
|
|
86
86
|
const [aiSettings, setAiSettings] = useState(null);
|
|
87
87
|
// Fetch AI Settings to get current provider defaults
|
|
88
88
|
useEffect(()=>{
|
|
89
|
-
fetch('/api/globals/ai-
|
|
89
|
+
fetch('/api/globals/ai-providers?depth=1').then((res)=>res.json()).then((data)=>setAiSettings(data)).catch((err)=>console.error('Error fetching AI settings:', err));
|
|
90
90
|
}, []);
|
|
91
91
|
// Get the configured default options from AI Settings for this provider
|
|
92
92
|
const configuredDefaults = useMemo(()=>{
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/ui/ProviderOptionsEditor/index.tsx"],"sourcesContent":["'use client'\n\nimport { RenderFields, useField, useFormFields } from '@payloadcms/ui'\nimport React, { useEffect, useMemo, useState } from 'react'\n\nimport { allProviderBlocks } from '../../ai/providers/blocks/index.js'\n\ntype UseCase = 'image' | 'text' | 'tts' | 'video'\n\ninterface ProviderOptionsEditorProps {\n name?: string\n path: string\n}\n\n/**\n * Find a field by name within a block's fields, searching through tabs\n */\nfunction findFieldInBlock(block: any, fieldName: string): any | undefined {\n const searchFields = (fields: any[]): any | undefined => {\n for (const field of fields) {\n if ('name' in field && field.name === fieldName) {\n return field\n }\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n const found = searchFields(tab.fields)\n if (found) {\n return found\n }\n }\n }\n if (field.type === 'group' && 'fields' in field) {\n const found = searchFields(field.fields)\n if (found) {\n return found\n }\n }\n }\n return undefined\n }\n\n return searchFields(block.fields)\n}\n\n/**\n * Get provider options fields for a given provider and use case\n */\nfunction getProviderOptionsFields(providerSlug: string, useCase: UseCase): any[] {\n const block = allProviderBlocks.find((b) => b.slug === providerSlug)\n if (!block) {\n return []\n }\n\n const groupName = `${useCase}ProviderOptions`\n const optionsGroup = findFieldInBlock(block, groupName)\n\n if (optionsGroup && optionsGroup.type === 'group' && 'fields' in optionsGroup) {\n return optionsGroup.fields\n }\n\n return []\n}\n\nexport const ProviderOptionsEditor: React.FC<ProviderOptionsEditorProps> = (props) => {\n const { path } = props\n\n // Get parent path to find sibling provider field\n const parentPath = path.split('.').slice(0, -1).join('.')\n const providerField = useFormFields(([fields]) => fields[`${parentPath}.provider`])\n const provider = providerField?.value as string\n\n // Infer use case from path\n // Handles:\n // - AISettings: 'defaults.text.options' -> useCase is 'text'\n // - Instructions: 'text-settings.providerOptions' -> useCase is 'text'\n const useCase: UseCase = useMemo(() => {\n // Check for AISettings paths first (e.g., 'defaults.text.options')\n const pathParts = path.split('.')\n const parentName = pathParts[pathParts.length - 2]\n\n if (['image', 'text', 'tts', 'video'].includes(parentName)) {\n return parentName as UseCase\n }\n\n // Check for Instructions paths\n if (path.includes('tts-settings')) {\n return 'tts'\n }\n if (path.includes('image-settings')) {\n return 'image'\n }\n if (path.includes('video-settings')) {\n return 'video'\n }\n return 'text'\n }, [path])\n\n const { setValue, value } = useField<Record<string, any>>({ path })\n const [aiSettings, setAiSettings] = useState<any>(null)\n\n // Fetch AI Settings to get current provider defaults\n useEffect(() => {\n fetch('/api/globals/ai-settings?depth=1')\n .then((res) => res.json())\n .then((data) => setAiSettings(data))\n .catch((err) => console.error('Error fetching AI settings:', err))\n }, [])\n\n // Get the configured default options from AI Settings for this provider\n const configuredDefaults = useMemo(() => {\n if (!provider || !aiSettings) {\n return null\n }\n\n const providerBlock = aiSettings.providers?.find(\n (p: any) => p.blockType === provider && p.enabled,\n )\n if (!providerBlock) {\n return null\n }\n\n // Get provider options by use case\n const optionsKey = `${useCase}ProviderOptions`\n return providerBlock[optionsKey] || null\n }, [provider, useCase, aiSettings])\n\n // Get field definitions from provider block\n const fields = useMemo(() => {\n if (!provider) {\n return []\n }\n return getProviderOptionsFields(provider, useCase)\n }, [provider, useCase])\n\n // Check if there are any overrides set\n const hasOverrides = useMemo(() => {\n return value && Object.keys(value).length > 0\n }, [value])\n\n if (!provider) {\n return (\n <div className=\"field-type\" style={{ padding: '12px 0' }}>\n <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px', margin: 0 }}>\n Please select a provider first to configure options.\n </p>\n </div>\n )\n }\n\n if (fields.length === 0) {\n return (\n <div className=\"field-type\" style={{ padding: '12px 0' }}>\n <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px', margin: 0 }}>\n No configurable options available for {provider} ({useCase}).\n </p>\n </div>\n )\n }\n\n return (\n <div className=\"field-type provider-options-editor\">\n <div style={{ marginBottom: '16px' }}>\n <label className=\"field-label\" style={{ display: 'block', marginBottom: '8px' }}>\n Provider Options\n </label>\n\n {configuredDefaults && (\n <div\n style={{\n background: 'var(--theme-elevation-50)',\n border: '1px solid var(--theme-elevation-100)',\n borderRadius: '4px',\n fontSize: '12px',\n marginBottom: '12px',\n padding: '12px',\n }}\n >\n <div\n style={{\n alignItems: 'center',\n display: 'flex',\n justifyContent: 'space-between',\n marginBottom: '8px',\n }}\n >\n <strong style={{ color: 'var(--theme-elevation-800)' }}>\n Defaults from AI Settings\n </strong>\n <span\n style={{\n background: 'var(--theme-elevation-100)',\n borderRadius: '10px',\n color: 'var(--theme-elevation-500)',\n fontSize: '11px',\n padding: '2px 8px',\n }}\n >\n Inherited\n </span>\n </div>\n <div\n style={{\n color: 'var(--theme-elevation-600)',\n display: 'flex',\n flexWrap: 'wrap',\n gap: '8px',\n }}\n >\n {Object.entries(configuredDefaults).map(([key, val]) => {\n // Skip nested objects for display\n if (typeof val === 'object' && val !== null) {\n return null\n }\n return (\n <span\n key={key}\n style={{\n background: 'var(--theme-elevation-100)',\n borderRadius: '3px',\n fontSize: '11px',\n padding: '2px 6px',\n }}\n >\n {key}: <strong>{String(val)}</strong>\n </span>\n )\n })}\n </div>\n </div>\n )}\n\n <p\n style={{\n color: 'var(--theme-elevation-500)',\n fontSize: '12px',\n fontStyle: 'italic',\n marginBottom: '12px',\n }}\n >\n Override defaults for this specific field. Empty values inherit from AI Settings.\n </p>\n </div>\n\n <RenderFields\n fields={fields}\n forceRender\n margins=\"small\"\n parentIndexPath=\"\"\n parentPath={path}\n parentSchemaPath={path}\n permissions={true}\n />\n\n {hasOverrides && (\n <button\n onClick={() => setValue({})}\n onMouseEnter={(e) => {\n e.currentTarget.style.background = 'var(--theme-elevation-100)'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.background = 'transparent'\n }}\n style={{\n background: 'transparent',\n border: '1px solid var(--theme-elevation-200)',\n borderRadius: '4px',\n color: 'var(--theme-text)',\n cursor: 'pointer',\n fontSize: '13px',\n marginTop: '12px',\n padding: '8px 16px',\n transition: 'all 0.15s ease',\n }}\n type=\"button\"\n >\n Reset to Defaults\n </button>\n )}\n </div>\n )\n}\n"],"names":["RenderFields","useField","useFormFields","React","useEffect","useMemo","useState","allProviderBlocks","findFieldInBlock","block","fieldName","searchFields","fields","field","name","type","tab","tabs","found","undefined","getProviderOptionsFields","providerSlug","useCase","find","b","slug","groupName","optionsGroup","ProviderOptionsEditor","props","path","parentPath","split","slice","join","providerField","provider","value","pathParts","parentName","length","includes","setValue","aiSettings","setAiSettings","fetch","then","res","json","data","catch","err","console","error","configuredDefaults","providerBlock","providers","p","blockType","enabled","optionsKey","hasOverrides","Object","keys","div","className","style","padding","color","fontSize","margin","marginBottom","label","display","background","border","borderRadius","alignItems","justifyContent","strong","span","flexWrap","gap","entries","map","key","val","String","fontStyle","forceRender","margins","parentIndexPath","parentSchemaPath","permissions","button","onClick","onMouseEnter","e","currentTarget","onMouseLeave","cursor","marginTop","transition"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../src/ui/ProviderOptionsEditor/index.tsx"],"sourcesContent":["'use client'\n\nimport { RenderFields, useField, useFormFields } from '@payloadcms/ui'\nimport React, { useEffect, useMemo, useState } from 'react'\n\nimport { allProviderBlocks } from '../../ai/providers/blocks/index.js'\n\ntype UseCase = 'image' | 'text' | 'tts' | 'video'\n\ninterface ProviderOptionsEditorProps {\n name?: string\n path: string\n}\n\n/**\n * Find a field by name within a block's fields, searching through tabs\n */\nfunction findFieldInBlock(block: any, fieldName: string): any | undefined {\n const searchFields = (fields: any[]): any | undefined => {\n for (const field of fields) {\n if ('name' in field && field.name === fieldName) {\n return field\n }\n if (field.type === 'tabs' && 'tabs' in field) {\n for (const tab of field.tabs) {\n const found = searchFields(tab.fields)\n if (found) {\n return found\n }\n }\n }\n if (field.type === 'group' && 'fields' in field) {\n const found = searchFields(field.fields)\n if (found) {\n return found\n }\n }\n }\n return undefined\n }\n\n return searchFields(block.fields)\n}\n\n/**\n * Get provider options fields for a given provider and use case\n */\nfunction getProviderOptionsFields(providerSlug: string, useCase: UseCase): any[] {\n const block = allProviderBlocks.find((b) => b.slug === providerSlug)\n if (!block) {\n return []\n }\n\n const groupName = `${useCase}ProviderOptions`\n const optionsGroup = findFieldInBlock(block, groupName)\n\n if (optionsGroup && optionsGroup.type === 'group' && 'fields' in optionsGroup) {\n return optionsGroup.fields\n }\n\n return []\n}\n\nexport const ProviderOptionsEditor: React.FC<ProviderOptionsEditorProps> = (props) => {\n const { path } = props\n\n // Get parent path to find sibling provider field\n const parentPath = path.split('.').slice(0, -1).join('.')\n const providerField = useFormFields(([fields]) => fields[`${parentPath}.provider`])\n const provider = providerField?.value as string\n\n // Infer use case from path\n // Handles:\n // - AISettings: 'defaults.text.options' -> useCase is 'text'\n // - Instructions: 'text-settings.providerOptions' -> useCase is 'text'\n const useCase: UseCase = useMemo(() => {\n // Check for AISettings paths first (e.g., 'defaults.text.options')\n const pathParts = path.split('.')\n const parentName = pathParts[pathParts.length - 2]\n\n if (['image', 'text', 'tts', 'video'].includes(parentName)) {\n return parentName as UseCase\n }\n\n // Check for Instructions paths\n if (path.includes('tts-settings')) {\n return 'tts'\n }\n if (path.includes('image-settings')) {\n return 'image'\n }\n if (path.includes('video-settings')) {\n return 'video'\n }\n return 'text'\n }, [path])\n\n const { setValue, value } = useField<Record<string, any>>({ path })\n const [aiSettings, setAiSettings] = useState<any>(null)\n\n // Fetch AI Settings to get current provider defaults\n useEffect(() => {\n fetch('/api/globals/ai-providers?depth=1')\n .then((res) => res.json())\n .then((data) => setAiSettings(data))\n .catch((err) => console.error('Error fetching AI settings:', err))\n }, [])\n\n // Get the configured default options from AI Settings for this provider\n const configuredDefaults = useMemo(() => {\n if (!provider || !aiSettings) {\n return null\n }\n\n const providerBlock = aiSettings.providers?.find(\n (p: any) => p.blockType === provider && p.enabled,\n )\n if (!providerBlock) {\n return null\n }\n\n // Get provider options by use case\n const optionsKey = `${useCase}ProviderOptions`\n return providerBlock[optionsKey] || null\n }, [provider, useCase, aiSettings])\n\n // Get field definitions from provider block\n const fields = useMemo(() => {\n if (!provider) {\n return []\n }\n return getProviderOptionsFields(provider, useCase)\n }, [provider, useCase])\n\n // Check if there are any overrides set\n const hasOverrides = useMemo(() => {\n return value && Object.keys(value).length > 0\n }, [value])\n\n if (!provider) {\n return (\n <div className=\"field-type\" style={{ padding: '12px 0' }}>\n <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px', margin: 0 }}>\n Please select a provider first to configure options.\n </p>\n </div>\n )\n }\n\n if (fields.length === 0) {\n return (\n <div className=\"field-type\" style={{ padding: '12px 0' }}>\n <p style={{ color: 'var(--theme-elevation-600)', fontSize: '13px', margin: 0 }}>\n No configurable options available for {provider} ({useCase}).\n </p>\n </div>\n )\n }\n\n return (\n <div className=\"field-type provider-options-editor\">\n <div style={{ marginBottom: '16px' }}>\n <label className=\"field-label\" style={{ display: 'block', marginBottom: '8px' }}>\n Provider Options\n </label>\n\n {configuredDefaults && (\n <div\n style={{\n background: 'var(--theme-elevation-50)',\n border: '1px solid var(--theme-elevation-100)',\n borderRadius: '4px',\n fontSize: '12px',\n marginBottom: '12px',\n padding: '12px',\n }}\n >\n <div\n style={{\n alignItems: 'center',\n display: 'flex',\n justifyContent: 'space-between',\n marginBottom: '8px',\n }}\n >\n <strong style={{ color: 'var(--theme-elevation-800)' }}>\n Defaults from AI Settings\n </strong>\n <span\n style={{\n background: 'var(--theme-elevation-100)',\n borderRadius: '10px',\n color: 'var(--theme-elevation-500)',\n fontSize: '11px',\n padding: '2px 8px',\n }}\n >\n Inherited\n </span>\n </div>\n <div\n style={{\n color: 'var(--theme-elevation-600)',\n display: 'flex',\n flexWrap: 'wrap',\n gap: '8px',\n }}\n >\n {Object.entries(configuredDefaults).map(([key, val]) => {\n // Skip nested objects for display\n if (typeof val === 'object' && val !== null) {\n return null\n }\n return (\n <span\n key={key}\n style={{\n background: 'var(--theme-elevation-100)',\n borderRadius: '3px',\n fontSize: '11px',\n padding: '2px 6px',\n }}\n >\n {key}: <strong>{String(val)}</strong>\n </span>\n )\n })}\n </div>\n </div>\n )}\n\n <p\n style={{\n color: 'var(--theme-elevation-500)',\n fontSize: '12px',\n fontStyle: 'italic',\n marginBottom: '12px',\n }}\n >\n Override defaults for this specific field. Empty values inherit from AI Settings.\n </p>\n </div>\n\n <RenderFields\n fields={fields}\n forceRender\n margins=\"small\"\n parentIndexPath=\"\"\n parentPath={path}\n parentSchemaPath={path}\n permissions={true}\n />\n\n {hasOverrides && (\n <button\n onClick={() => setValue({})}\n onMouseEnter={(e) => {\n e.currentTarget.style.background = 'var(--theme-elevation-100)'\n }}\n onMouseLeave={(e) => {\n e.currentTarget.style.background = 'transparent'\n }}\n style={{\n background: 'transparent',\n border: '1px solid var(--theme-elevation-200)',\n borderRadius: '4px',\n color: 'var(--theme-text)',\n cursor: 'pointer',\n fontSize: '13px',\n marginTop: '12px',\n padding: '8px 16px',\n transition: 'all 0.15s ease',\n }}\n type=\"button\"\n >\n Reset to Defaults\n </button>\n )}\n </div>\n )\n}\n"],"names":["RenderFields","useField","useFormFields","React","useEffect","useMemo","useState","allProviderBlocks","findFieldInBlock","block","fieldName","searchFields","fields","field","name","type","tab","tabs","found","undefined","getProviderOptionsFields","providerSlug","useCase","find","b","slug","groupName","optionsGroup","ProviderOptionsEditor","props","path","parentPath","split","slice","join","providerField","provider","value","pathParts","parentName","length","includes","setValue","aiSettings","setAiSettings","fetch","then","res","json","data","catch","err","console","error","configuredDefaults","providerBlock","providers","p","blockType","enabled","optionsKey","hasOverrides","Object","keys","div","className","style","padding","color","fontSize","margin","marginBottom","label","display","background","border","borderRadius","alignItems","justifyContent","strong","span","flexWrap","gap","entries","map","key","val","String","fontStyle","forceRender","margins","parentIndexPath","parentSchemaPath","permissions","button","onClick","onMouseEnter","e","currentTarget","onMouseLeave","cursor","marginTop","transition"],"mappings":"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"}
|
|
@@ -78,7 +78,7 @@ export const ProviderOptionsEditor = (props) => {
|
|
|
78
78
|
const [aiSettings, setAiSettings] = useState(null);
|
|
79
79
|
// Fetch AI Settings to get current provider defaults
|
|
80
80
|
useEffect(() => {
|
|
81
|
-
fetch('/api/globals/ai-
|
|
81
|
+
fetch('/api/globals/ai-providers?depth=1')
|
|
82
82
|
.then((res) => res.json())
|
|
83
83
|
.then((data) => setAiSettings(data))
|
|
84
84
|
.catch((err) => console.error('Error fetching AI settings:', err));
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export const updateFieldsConfig = (collectionConfig)=>{
|
|
2
2
|
let schemaPathMap = {};
|
|
3
3
|
function updateField(field, parentPath = '') {
|
|
4
|
-
const currentPath = parentPath ? `${parentPath}.${field.name}` : field.name;
|
|
4
|
+
const currentPath = field.name ? parentPath ? `${parentPath}.${field.name}` : field.name : parentPath;
|
|
5
5
|
const currentSchemaPath = `${collectionConfig.slug}.${currentPath}`;
|
|
6
6
|
// Disabled fields/ field types
|
|
7
7
|
if (field.admin?.disabled || field.admin?.readOnly || field.admin?.hidden || field.type === 'row') {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/utilities/updateFieldsConfig.ts"],"sourcesContent":["import type { CollectionConfig, GlobalConfig } from 'payload'\n\ninterface UpdateFieldsConfig {\n schemaPathMap: Record<string, any>\n updatedCollectionConfig: CollectionConfig | GlobalConfig\n}\n\nexport const updateFieldsConfig = (collectionConfig: CollectionConfig | GlobalConfig): UpdateFieldsConfig => {\n let schemaPathMap = {}\n\n function updateField(field: any, parentPath = ''): any {\n const currentPath = parentPath
|
|
1
|
+
{"version":3,"sources":["../../src/utilities/updateFieldsConfig.ts"],"sourcesContent":["import type { CollectionConfig, GlobalConfig } from 'payload'\n\ninterface UpdateFieldsConfig {\n schemaPathMap: Record<string, any>\n updatedCollectionConfig: CollectionConfig | GlobalConfig\n}\n\nexport const updateFieldsConfig = (collectionConfig: CollectionConfig | GlobalConfig): UpdateFieldsConfig => {\n let schemaPathMap = {}\n\n function updateField(field: any, parentPath = ''): any {\n const currentPath = field.name\n ? parentPath\n ? `${parentPath}.${field.name}`\n : field.name\n : parentPath\n const currentSchemaPath = `${collectionConfig.slug}.${currentPath}`\n\n // Disabled fields/ field types\n if (\n field.admin?.disabled ||\n field.admin?.readOnly ||\n field.admin?.hidden ||\n field.type === 'row'\n ) {\n return field\n }\n\n // Map field path for global fieldInstructionsMap to load related instructions\n // This is done due to save extra API call to get instructions when Field components are loaded in admin\n // Doing is will only call instructions data when user clicks on settings\n if (['array', 'richText', 'text', 'textarea', 'upload'].includes(field.type)) {\n schemaPathMap = {\n ...schemaPathMap,\n [currentSchemaPath]: {\n type: field.type,\n custom: field.custom,\n label: field.label || field.name,\n relationTo: field.relationTo,\n },\n }\n }\n\n // Inject AI actions, richText is not included here as it has to be explicitly defined by user\n // Array fields also get AI injection for bulk generation\n if (['array', 'text', 'textarea', 'upload'].includes(field.type)) {\n let customField = {}\n\n // Custom fields don't fully adhere to the Payload schema, making it difficult to\n // determine which components support injecting ComposeField as a Description.\n if (field.admin?.components?.Field || field.admin?.components?.Description) {\n // TODO: If a field already provides its own Description, we still inject our ComposeField\n // by overriding Description. If you need both, consider composing your own wrapper.\n customField = {}\n }\n\n // Array fields use ArrayComposeField (always visible) since they don't have focus events\n // Other fields use ComposeField with focus-dependent visibility\n const componentPath = field.type === 'array'\n ? '@ai-stack/payloadcms/fields#ArrayComposeField'\n : '@ai-stack/payloadcms/fields#ComposeField'\n\n return {\n ...field,\n admin: {\n ...field.admin,\n components: {\n ...(field.admin?.components || {}),\n Description: {\n clientProps: {\n schemaPath: currentSchemaPath,\n },\n path: componentPath,\n },\n ...customField,\n },\n },\n }\n }\n\n if (field.fields) {\n return {\n ...field,\n fields: field.fields.map((subField: any) => updateField(subField, currentPath)),\n }\n }\n\n if (field.tabs) {\n return {\n ...field,\n tabs: field.tabs.map((tab: any) => {\n return {\n ...tab,\n // Tabs are a UI construct and should not add to the schema path\n fields: (tab.fields || []).map((subField: any) => updateField(subField, parentPath)),\n }\n }),\n }\n }\n\n if (field.blocks) {\n return {\n ...field,\n blocks: field.blocks.map((block: any) => ({\n ...block,\n fields: block.fields.map((subField: any) =>\n updateField(subField, `${currentPath}.${block.slug}`),\n ),\n })),\n }\n }\n\n return field\n }\n\n const updatedCollectionConfig = {\n ...collectionConfig,\n fields: collectionConfig.fields.map((field) => updateField(field)),\n }\n\n return {\n schemaPathMap,\n updatedCollectionConfig,\n }\n}\n"],"names":["updateFieldsConfig","collectionConfig","schemaPathMap","updateField","field","parentPath","currentPath","name","currentSchemaPath","slug","admin","disabled","readOnly","hidden","type","includes","custom","label","relationTo","customField","components","Field","Description","componentPath","clientProps","schemaPath","path","fields","map","subField","tabs","tab","blocks","block","updatedCollectionConfig"],"mappings":"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"}
|
package/package.json
CHANGED