@ai-stack/payloadcms 3.68.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.
Files changed (187) hide show
  1. package/dist/ai/core/media/image/generateImage.js +2 -6
  2. package/dist/ai/core/media/image/generateImage.js.map +1 -1
  3. package/dist/ai/core/media/image/handlers/multimodal.js +13 -28
  4. package/dist/ai/core/media/image/handlers/multimodal.js.map +1 -1
  5. package/dist/ai/core/media/image/handlers/standard.js +10 -7
  6. package/dist/ai/core/media/image/handlers/standard.js.map +1 -1
  7. package/dist/ai/core/media/speech/generateSpeech.js +8 -8
  8. package/dist/ai/core/media/speech/generateSpeech.js.map +1 -1
  9. package/dist/ai/core/media/types.d.ts +1 -1
  10. package/dist/ai/core/media/types.js.map +1 -1
  11. package/dist/ai/core/streamObject.js +3 -3
  12. package/dist/ai/core/streamObject.js.map +1 -1
  13. package/dist/ai/core/types.d.ts +3 -0
  14. package/dist/ai/core/types.js.map +1 -1
  15. package/dist/ai/prompts.d.ts +1 -2
  16. package/dist/ai/prompts.js +0 -110
  17. package/dist/ai/prompts.js.map +1 -1
  18. package/dist/ai/providers/blocks/anthropic.js +2 -1
  19. package/dist/ai/providers/blocks/anthropic.js.map +1 -1
  20. package/dist/ai/providers/blocks/elevenlabs.js +3 -2
  21. package/dist/ai/providers/blocks/elevenlabs.js.map +1 -1
  22. package/dist/ai/providers/blocks/fal.js +2 -1
  23. package/dist/ai/providers/blocks/fal.js.map +1 -1
  24. package/dist/ai/providers/blocks/google.js +12 -6
  25. package/dist/ai/providers/blocks/google.js.map +1 -1
  26. package/dist/ai/providers/blocks/openai-compatible.js +2 -1
  27. package/dist/ai/providers/blocks/openai-compatible.js.map +1 -1
  28. package/dist/ai/providers/blocks/openai.js +3 -2
  29. package/dist/ai/providers/blocks/openai.js.map +1 -1
  30. package/dist/ai/providers/blocks/xai.js +2 -1
  31. package/dist/ai/providers/blocks/xai.js.map +1 -1
  32. package/dist/ai/providers/icons.d.ts +7 -0
  33. package/dist/ai/providers/icons.js +9 -0
  34. package/dist/ai/providers/icons.js.map +1 -0
  35. package/dist/ai/providers/registry.js +36 -26
  36. package/dist/ai/providers/registry.js.map +1 -1
  37. package/dist/ai/utils/filterEditorSchemaByNodes.d.ts +9 -0
  38. package/dist/ai/utils/filterEditorSchemaByNodes.js +30 -3
  39. package/dist/ai/utils/filterEditorSchemaByNodes.js.map +1 -1
  40. package/dist/ai/utils/nodeToSchemaMap.d.ts +22 -0
  41. package/dist/ai/utils/nodeToSchemaMap.js +72 -0
  42. package/dist/ai/utils/nodeToSchemaMap.js.map +1 -0
  43. package/dist/collections/AIJobs.js +1 -1
  44. package/dist/collections/AIJobs.js.map +1 -1
  45. package/dist/collections/AIProviders.d.ts +2 -0
  46. package/dist/collections/{AISettings.js → AIProviders.js} +53 -25
  47. package/dist/collections/AIProviders.js.map +1 -0
  48. package/dist/collections/Instructions.js +45 -4
  49. package/dist/collections/Instructions.js.map +1 -1
  50. package/dist/defaults.d.ts +1 -0
  51. package/dist/defaults.js +8 -0
  52. package/dist/defaults.js.map +1 -1
  53. package/dist/endpoints/chat.d.ts +4 -0
  54. package/dist/endpoints/fetchFields.js +10 -0
  55. package/dist/endpoints/fetchFields.js.map +1 -1
  56. package/dist/endpoints/fetchVoices.js +42 -25
  57. package/dist/endpoints/fetchVoices.js.map +1 -1
  58. package/dist/endpoints/index.js +248 -35
  59. package/dist/endpoints/index.js.map +1 -1
  60. package/dist/exports/client.d.ts +1 -1
  61. package/dist/exports/client.js +1 -1
  62. package/dist/exports/client.js.map +1 -1
  63. package/dist/exports/fields.d.ts +1 -0
  64. package/dist/exports/fields.js +1 -0
  65. package/dist/exports/fields.js.map +1 -1
  66. package/dist/fields/ArrayComposeField/ArrayComposeField.d.ts +15 -0
  67. package/dist/fields/ArrayComposeField/ArrayComposeField.js +87 -0
  68. package/dist/fields/ArrayComposeField/ArrayComposeField.js.map +1 -0
  69. package/dist/fields/ArrayComposeField/ArrayComposeField.jsx +73 -0
  70. package/dist/fields/PromptEditorField/PromptEditorField.js +7 -2
  71. package/dist/fields/PromptEditorField/PromptEditorField.js.map +1 -1
  72. package/dist/fields/PromptEditorField/PromptEditorField.jsx +5 -2
  73. package/dist/index.d.ts +3 -1
  74. package/dist/index.js +2 -1
  75. package/dist/index.js.map +1 -1
  76. package/dist/payload-ai.d.ts +152 -0
  77. package/dist/plugin.js +18 -34
  78. package/dist/plugin.js.map +1 -1
  79. package/dist/providers/InstructionsProvider/InstructionsProvider.js +47 -15
  80. package/dist/providers/InstructionsProvider/InstructionsProvider.js.map +1 -1
  81. package/dist/providers/InstructionsProvider/InstructionsProvider.jsx +39 -16
  82. package/dist/providers/InstructionsProvider/context.d.ts +3 -0
  83. package/dist/providers/InstructionsProvider/context.js +2 -0
  84. package/dist/providers/InstructionsProvider/context.js.map +1 -1
  85. package/dist/providers/InstructionsProvider/useInstructions.js +22 -3
  86. package/dist/providers/InstructionsProvider/useInstructions.js.map +1 -1
  87. package/dist/styles.d.ts +11 -0
  88. package/dist/types/handlebars-async-helpers.d.ts +1 -0
  89. package/dist/types/handlebars-dist-handlebars.d.ts +1 -0
  90. package/dist/types/react-mentions.d.ts +1 -0
  91. package/dist/types.d.ts +36 -7
  92. package/dist/types.js +1 -0
  93. package/dist/types.js.map +1 -1
  94. package/dist/ui/AIConfigDashboard/index.d.ts +1 -1
  95. package/dist/ui/AIConfigDashboard/index.js +201 -23
  96. package/dist/ui/AIConfigDashboard/index.js.map +1 -1
  97. package/dist/ui/AIConfigDashboard/index.jsx +166 -15
  98. package/dist/ui/Compose/Compose.d.ts +1 -0
  99. package/dist/ui/Compose/Compose.js +23 -4
  100. package/dist/ui/Compose/Compose.js.map +1 -1
  101. package/dist/ui/Compose/Compose.jsx +23 -4
  102. package/dist/ui/Compose/UndoRedoActions.d.ts +2 -2
  103. package/dist/ui/Compose/UndoRedoActions.js +8 -5
  104. package/dist/ui/Compose/UndoRedoActions.js.map +1 -1
  105. package/dist/ui/Compose/UndoRedoActions.jsx +6 -5
  106. package/dist/ui/Compose/compose.module.css +56 -16
  107. package/dist/ui/Compose/hooks/menu/TranslateMenu.d.ts +5 -0
  108. package/dist/ui/Compose/hooks/menu/TranslateMenu.js +45 -4
  109. package/dist/ui/Compose/hooks/menu/TranslateMenu.js.map +1 -1
  110. package/dist/ui/Compose/hooks/menu/TranslateMenu.jsx +41 -5
  111. package/dist/ui/Compose/hooks/menu/itemsMap.js +12 -6
  112. package/dist/ui/Compose/hooks/menu/itemsMap.js.map +1 -1
  113. package/dist/ui/Compose/hooks/menu/menu.module.scss +4 -1
  114. package/dist/ui/Compose/hooks/menu/useMenu.js +26 -15
  115. package/dist/ui/Compose/hooks/menu/useMenu.js.map +1 -1
  116. package/dist/ui/Compose/hooks/menu/useMenu.jsx +25 -12
  117. package/dist/ui/Compose/hooks/useActiveFieldTracking.js +34 -0
  118. package/dist/ui/Compose/hooks/useActiveFieldTracking.js.map +1 -1
  119. package/dist/ui/Compose/hooks/useGenerate.js +26 -174
  120. package/dist/ui/Compose/hooks/useGenerate.js.map +1 -1
  121. package/dist/ui/Compose/hooks/useGenerateUpload.d.ts +11 -0
  122. package/dist/ui/Compose/hooks/useGenerateUpload.js +156 -0
  123. package/dist/ui/Compose/hooks/useGenerateUpload.js.map +1 -0
  124. package/dist/ui/Compose/hooks/useHistory.d.ts +0 -1
  125. package/dist/ui/Compose/hooks/useHistory.js +65 -25
  126. package/dist/ui/Compose/hooks/useHistory.js.map +1 -1
  127. package/dist/ui/Compose/hooks/useStreamingUpdate.d.ts +8 -0
  128. package/dist/ui/Compose/hooks/useStreamingUpdate.js +48 -0
  129. package/dist/ui/Compose/hooks/useStreamingUpdate.js.map +1 -0
  130. package/dist/ui/ConfigDashboard/index.d.ts +2 -0
  131. package/dist/ui/ConfigDashboard/index.js +224 -0
  132. package/dist/ui/ConfigDashboard/index.js.map +1 -0
  133. package/dist/ui/ConfigDashboard/index.jsx +175 -0
  134. package/dist/ui/DynamicModelSelect/index.js +1 -1
  135. package/dist/ui/DynamicModelSelect/index.js.map +1 -1
  136. package/dist/ui/DynamicModelSelect/index.jsx +1 -1
  137. package/dist/ui/DynamicProviderSelect/index.js +1 -1
  138. package/dist/ui/DynamicProviderSelect/index.js.map +1 -1
  139. package/dist/ui/DynamicProviderSelect/index.jsx +1 -1
  140. package/dist/ui/DynamicVoiceSelect/index.js +63 -11
  141. package/dist/ui/DynamicVoiceSelect/index.js.map +1 -1
  142. package/dist/ui/DynamicVoiceSelect/index.jsx +47 -14
  143. package/dist/ui/EncryptedTextField/index.js +4 -4
  144. package/dist/ui/EncryptedTextField/index.js.map +1 -1
  145. package/dist/ui/EncryptedTextField/index.jsx +4 -4
  146. package/dist/ui/ProviderOptionsEditor/index.js +1 -1
  147. package/dist/ui/ProviderOptionsEditor/index.js.map +1 -1
  148. package/dist/ui/ProviderOptionsEditor/index.jsx +1 -1
  149. package/dist/ui/VoicesFetcher/index.js +34 -16
  150. package/dist/ui/VoicesFetcher/index.js.map +1 -1
  151. package/dist/ui/VoicesFetcher/index.jsx +32 -15
  152. package/dist/utilities/buildSmartPrompt.d.ts +22 -0
  153. package/dist/utilities/buildSmartPrompt.js +141 -0
  154. package/dist/utilities/buildSmartPrompt.js.map +1 -0
  155. package/dist/utilities/encryption.js +2 -1
  156. package/dist/utilities/encryption.js.map +1 -1
  157. package/dist/utilities/fieldToJsonSchema.js +32 -3
  158. package/dist/utilities/fieldToJsonSchema.js.map +1 -1
  159. package/dist/utilities/resolveImageReferences.d.ts +3 -1
  160. package/dist/utilities/resolveImageReferences.js +21 -2
  161. package/dist/utilities/resolveImageReferences.js.map +1 -1
  162. package/dist/utilities/seedProperties.d.ts +7 -0
  163. package/dist/utilities/seedProperties.js +100 -0
  164. package/dist/utilities/seedProperties.js.map +1 -0
  165. package/dist/utilities/setSafeLexicalState.js +79 -6
  166. package/dist/utilities/setSafeLexicalState.js.map +1 -1
  167. package/dist/utilities/updateFieldsConfig.d.ts +1 -1
  168. package/dist/utilities/updateFieldsConfig.js +9 -2
  169. package/dist/utilities/updateFieldsConfig.js.map +1 -1
  170. package/package.json +35 -33
  171. package/dist/collections/AISettings.d.ts +0 -2
  172. package/dist/collections/AISettings.js.map +0 -1
  173. package/dist/endpoints/chat.d.js +0 -3
  174. package/dist/endpoints/chat.d.js.map +0 -1
  175. package/dist/init.d.ts +0 -7
  176. package/dist/init.js +0 -135
  177. package/dist/init.js.map +0 -1
  178. package/dist/payload-ai.d.js +0 -3
  179. package/dist/payload-ai.d.js.map +0 -1
  180. package/dist/styles.d.js +0 -2
  181. package/dist/styles.d.js.map +0 -1
  182. package/dist/types/handlebars-async-helpers.d.js +0 -2
  183. package/dist/types/handlebars-async-helpers.d.js.map +0 -1
  184. package/dist/types/handlebars-dist-handlebars.d.js +0 -2
  185. package/dist/types/handlebars-dist-handlebars.d.js.map +0 -1
  186. package/dist/types/react-mentions.d.js +0 -2
  187. package/dist/types/react-mentions.d.js.map +0 -1
@@ -1,17 +1,17 @@
1
1
  'use client';
2
- import { useDocumentInfo, useField } from '@payloadcms/ui';
2
+ import { useDocumentInfo, useForm } from '@payloadcms/ui';
3
3
  import { useCallback, useEffect, useRef } from 'react';
4
+ import { getSiblingData } from 'payload/shared';
4
5
  import { PLUGIN_NAME } from '../../../defaults.js';
5
6
  import { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js';
6
7
  const STORAGE_KEY = `${PLUGIN_NAME}-fields-history`;
8
+ const MAX_HISTORY_SIZE = 50;
7
9
  // Global cache to prevent synchronous localStorage reads on every render
8
10
  let globalHistoryCache = null;
9
11
  export const useHistory = ()=>{
10
12
  const { id } = useDocumentInfo();
11
- const { path: pathFromContext, schemaPath } = useFieldProps();
12
- const { value: currentFieldValue } = useField({
13
- path: pathFromContext ?? ''
14
- });
13
+ const { path, schemaPath } = useFieldProps();
14
+ const { getData } = useForm();
15
15
  const fieldKey = `${id}.${schemaPath}`;
16
16
  const getLatestHistory = useCallback(()=>{
17
17
  // Return cache if available
@@ -43,21 +43,29 @@ export const useHistory = ()=>{
43
43
  if (saveTimerRef.current) {
44
44
  clearTimeout(saveTimerRef.current);
45
45
  }
46
- // Debounce the save operation by 300ms
46
+ // Debounce the save operation by 500ms
47
47
  saveTimerRef.current = setTimeout(()=>{
48
48
  // Use requestIdleCallback if available to avoid blocking the main thread
49
49
  if (typeof requestIdleCallback !== 'undefined') {
50
50
  requestIdleCallback(()=>{
51
- localStorage.setItem(STORAGE_KEY, JSON.stringify(newGlobalHistory));
51
+ try {
52
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(newGlobalHistory));
53
+ } catch (e) {
54
+ console.warn('Failed to save history to localStorage', e);
55
+ }
52
56
  }, {
53
57
  timeout: 2000
54
58
  });
55
59
  } else {
56
60
  // Fallback for browsers without requestIdleCallback
57
- localStorage.setItem(STORAGE_KEY, JSON.stringify(newGlobalHistory));
61
+ try {
62
+ localStorage.setItem(STORAGE_KEY, JSON.stringify(newGlobalHistory));
63
+ } catch (e) {
64
+ console.warn('Failed to save history to localStorage', e);
65
+ }
58
66
  }
59
67
  saveTimerRef.current = null;
60
- }, 300);
68
+ }, 500);
61
69
  }, []);
62
70
  // Sync with other tabs
63
71
  useEffect(()=>{
@@ -80,15 +88,18 @@ export const useHistory = ()=>{
80
88
  const latestHistory = {
81
89
  ...getLatestHistory()
82
90
  };
91
+ let hasChanges = false;
83
92
  Object.keys(latestHistory).forEach((k)=>{
84
93
  if (!k.startsWith(id?.toString() ?? '')) {
85
94
  delete latestHistory[k];
95
+ hasChanges = true;
86
96
  }
87
97
  });
88
- saveToLocalStorage(latestHistory);
98
+ if (hasChanges) {
99
+ saveToLocalStorage(latestHistory);
100
+ }
89
101
  }, [
90
102
  id,
91
- fieldKey,
92
103
  getLatestHistory,
93
104
  saveToLocalStorage
94
105
  ]);
@@ -101,22 +112,46 @@ export const useHistory = ()=>{
101
112
  history: []
102
113
  };
103
114
  let newIndex = currentIndex;
115
+ let historyUpdated = false;
116
+ const newHistoryArray = [
117
+ ...history
118
+ ];
104
119
  if (currentIndex == -1) {
105
120
  newIndex = 0;
106
- if (currentFieldValue) {
107
- history[newIndex] = currentFieldValue;
121
+ // Get initial value from form data instead of subscribing to useField
122
+ // This implementation avoids re-rendering on every keystroke
123
+ try {
124
+ const data = getData();
125
+ // We need to resolve the value from the data object using the path
126
+ // path might be 'group.subgroup.field'
127
+ if (path) {
128
+ const value = getSiblingData(data, path);
129
+ if (value) {
130
+ newHistoryArray[newIndex] = value;
131
+ historyUpdated = true;
132
+ }
133
+ }
134
+ } catch (e) {
135
+ // If we can't get the data, just ignore
108
136
  }
109
137
  }
110
- const newGlobalHistory = {
111
- ...latestHistory,
112
- [fieldKey]: {
113
- currentIndex: newIndex,
114
- history
115
- }
116
- };
117
- saveToLocalStorage(newGlobalHistory);
138
+ if (historyUpdated) {
139
+ const newGlobalHistory = {
140
+ ...latestHistory,
141
+ [fieldKey]: {
142
+ currentIndex: newIndex,
143
+ history: newHistoryArray
144
+ }
145
+ };
146
+ saveToLocalStorage(newGlobalHistory);
147
+ }
118
148
  }, [
119
- fieldKey
149
+ fieldKey,
150
+ getData,
151
+ path,
152
+ clearHistory,
153
+ getLatestHistory,
154
+ saveToLocalStorage
120
155
  ]);
121
156
  const set = useCallback((data)=>{
122
157
  const latestHistory = getLatestHistory();
@@ -124,10 +159,15 @@ export const useHistory = ()=>{
124
159
  currentIndex: -1,
125
160
  history: []
126
161
  };
127
- const newHistory = [
162
+ // Create new history array slice, appending new data
163
+ let newHistory = [
128
164
  ...history.slice(0, currentIndex + 1),
129
165
  data
130
166
  ];
167
+ // Enforce Max History Size
168
+ if (newHistory.length > MAX_HISTORY_SIZE) {
169
+ newHistory = newHistory.slice(newHistory.length - MAX_HISTORY_SIZE);
170
+ }
131
171
  const newGlobalHistory = {
132
172
  ...latestHistory,
133
173
  [fieldKey]: {
@@ -205,11 +245,11 @@ export const useHistory = ()=>{
205
245
  const fieldHistory = getLatestFieldHistory();
206
246
  const canUndo = fieldHistory.currentIndex > 0;
207
247
  const canRedo = fieldHistory.currentIndex < fieldHistory.history.length - 1;
208
- const currentValue = fieldHistory.history[fieldHistory.currentIndex];
248
+ // Note: We deliberately do not return currentValue to avoid subscription re-renders
249
+ // The consumers of this hook (UndoRedoActions) didn't use it anyway.
209
250
  return {
210
251
  canRedo,
211
252
  canUndo,
212
- currentValue,
213
253
  redo,
214
254
  set,
215
255
  undo
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../src/ui/Compose/hooks/useHistory.ts"],"sourcesContent":["'use client'\n\nimport { useDocumentInfo, useField } from '@payloadcms/ui'\nimport { useCallback, useEffect, useRef } from 'react'\n\nimport { PLUGIN_NAME } from '../../../defaults.js'\nimport { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js'\n\nconst STORAGE_KEY = `${PLUGIN_NAME}-fields-history`\n\ninterface HistoryState {\n [path: string]: {\n currentIndex: number\n history: any[]\n }\n}\n\n// Global cache to prevent synchronous localStorage reads on every render\nlet globalHistoryCache: HistoryState | null = null\n\nexport const useHistory = () => {\n const { id } = useDocumentInfo()\n const { path: pathFromContext, schemaPath } = useFieldProps()\n const { value: currentFieldValue } = useField<string>({\n path: pathFromContext ?? '',\n })\n\n const fieldKey = `${id}.${schemaPath}`\n\n const getLatestHistory = useCallback((): HistoryState => {\n // Return cache if available\n if (globalHistoryCache) {\n return globalHistoryCache\n }\n\n try {\n if (typeof localStorage !== 'undefined') {\n // Read once, cache it\n const stored = localStorage.getItem(STORAGE_KEY)\n globalHistoryCache = stored ? JSON.parse(stored) : {}\n return globalHistoryCache!\n }\n return {}\n } catch (e) {\n console.error('Error parsing history:', e)\n return {}\n }\n }, [])\n\n // Debounce timer ref to prevent excessive localStorage writes\n const saveTimerRef = useRef<null | ReturnType<typeof setTimeout>>(null)\n\n const saveToLocalStorage = useCallback((newGlobalHistory: HistoryState) => {\n // Update cache immediately\n globalHistoryCache = newGlobalHistory\n\n if (typeof localStorage === 'undefined') {\n return\n }\n\n // Clear any pending save\n if (saveTimerRef.current) {\n clearTimeout(saveTimerRef.current)\n }\n\n // Debounce the save operation by 300ms\n saveTimerRef.current = setTimeout(() => {\n // Use requestIdleCallback if available to avoid blocking the main thread\n if (typeof requestIdleCallback !== 'undefined') {\n requestIdleCallback(\n () => {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(newGlobalHistory))\n },\n { timeout: 2000 },\n )\n } else {\n // Fallback for browsers without requestIdleCallback\n localStorage.setItem(STORAGE_KEY, JSON.stringify(newGlobalHistory))\n }\n saveTimerRef.current = null\n }, 300)\n }, [])\n\n // Sync with other tabs\n useEffect(() => {\n const handleStorageChange = (e: StorageEvent) => {\n if (e.key === STORAGE_KEY && e.newValue) {\n try {\n globalHistoryCache = JSON.parse(e.newValue)\n } catch (err) {\n // ignore parse error\n }\n }\n }\n\n window.addEventListener('storage', handleStorageChange)\n return () => {\n window.removeEventListener('storage', handleStorageChange)\n }\n }, [])\n\n // Clear previous history\n const clearHistory = useCallback(() => {\n const latestHistory = { ...getLatestHistory() }\n Object.keys(latestHistory).forEach((k) => {\n if (!k.startsWith(id?.toString() ?? '')) {\n delete latestHistory[k]\n }\n })\n saveToLocalStorage(latestHistory)\n }, [id, fieldKey, getLatestHistory, saveToLocalStorage])\n\n useEffect(() => {\n // This is applied to clear out the document history which is not currently in use\n clearHistory()\n\n const latestHistory = getLatestHistory()\n const { currentIndex, history } = latestHistory[fieldKey] || {\n currentIndex: -1,\n history: [],\n }\n\n let newIndex = currentIndex\n if (currentIndex == -1) {\n newIndex = 0\n if (currentFieldValue) {\n history[newIndex] = currentFieldValue\n }\n }\n\n const newGlobalHistory = {\n ...latestHistory,\n [fieldKey]: { currentIndex: newIndex, history },\n }\n\n saveToLocalStorage(newGlobalHistory)\n }, [fieldKey])\n\n const set = useCallback(\n (data: any) => {\n const latestHistory = getLatestHistory()\n const { currentIndex, history } = latestHistory[fieldKey] || {\n currentIndex: -1,\n history: [],\n }\n const newHistory = [...history.slice(0, currentIndex + 1), data]\n const newGlobalHistory = {\n ...latestHistory,\n [fieldKey]: { currentIndex: newHistory.length - 1, history: newHistory },\n }\n saveToLocalStorage(newGlobalHistory)\n return data\n },\n [fieldKey, getLatestHistory, saveToLocalStorage],\n )\n\n const undo = useCallback(() => {\n const latestHistory = getLatestHistory()\n const { currentIndex, history } = latestHistory[fieldKey] || { currentIndex: -1, history: [] }\n if (currentIndex > 0) {\n const newIndex = currentIndex - 1\n const newValue = history[newIndex]\n const newGlobalHistory = {\n ...latestHistory,\n [fieldKey]: { currentIndex: newIndex, history },\n }\n saveToLocalStorage(newGlobalHistory)\n return newValue\n }\n return undefined\n }, [fieldKey, getLatestHistory, saveToLocalStorage])\n\n const redo = useCallback(() => {\n const latestHistory = getLatestHistory()\n const { currentIndex, history } = latestHistory[fieldKey] || { currentIndex: -1, history: [] }\n if (currentIndex < history.length - 1) {\n const newIndex = currentIndex + 1\n const newValue = history[newIndex]\n const newGlobalHistory = {\n ...latestHistory,\n [fieldKey]: { currentIndex: newIndex, history },\n }\n saveToLocalStorage(newGlobalHistory)\n return newValue\n }\n return undefined\n }, [fieldKey, getLatestHistory, saveToLocalStorage])\n\n const getLatestFieldHistory = useCallback(() => {\n const latestHistory = getLatestHistory()\n return latestHistory[fieldKey] || { currentIndex: -1, history: [] }\n }, [getLatestHistory, fieldKey])\n\n const fieldHistory = getLatestFieldHistory()\n\n const canUndo = fieldHistory.currentIndex > 0\n const canRedo = fieldHistory.currentIndex < fieldHistory.history.length - 1\n const currentValue = fieldHistory.history[fieldHistory.currentIndex]\n\n return {\n canRedo,\n canUndo,\n currentValue,\n redo,\n set,\n undo,\n }\n}\n"],"names":["useDocumentInfo","useField","useCallback","useEffect","useRef","PLUGIN_NAME","useFieldProps","STORAGE_KEY","globalHistoryCache","useHistory","id","path","pathFromContext","schemaPath","value","currentFieldValue","fieldKey","getLatestHistory","localStorage","stored","getItem","JSON","parse","e","console","error","saveTimerRef","saveToLocalStorage","newGlobalHistory","current","clearTimeout","setTimeout","requestIdleCallback","setItem","stringify","timeout","handleStorageChange","key","newValue","err","window","addEventListener","removeEventListener","clearHistory","latestHistory","Object","keys","forEach","k","startsWith","toString","currentIndex","history","newIndex","set","data","newHistory","slice","length","undo","undefined","redo","getLatestFieldHistory","fieldHistory","canUndo","canRedo","currentValue"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../src/ui/Compose/hooks/useHistory.ts"],"sourcesContent":["'use client'\n\nimport { useDocumentInfo, useForm } from '@payloadcms/ui'\nimport { useCallback, useEffect, useRef } from 'react'\nimport { getSiblingData } from 'payload/shared'\n\nimport { PLUGIN_NAME } from '../../../defaults.js'\nimport { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js'\n\nconst STORAGE_KEY = `${PLUGIN_NAME}-fields-history`\nconst MAX_HISTORY_SIZE = 50\n\ninterface HistoryState {\n [path: string]: {\n currentIndex: number\n history: any[]\n }\n}\n\n// Global cache to prevent synchronous localStorage reads on every render\nlet globalHistoryCache: HistoryState | null = null\n\nexport const useHistory = () => {\n const { id } = useDocumentInfo()\n const { path, schemaPath } = useFieldProps()\n const { getData } = useForm()\n\n const fieldKey = `${id}.${schemaPath}`\n\n const getLatestHistory = useCallback((): HistoryState => {\n // Return cache if available\n if (globalHistoryCache) {\n return globalHistoryCache\n }\n\n try {\n if (typeof localStorage !== 'undefined') {\n // Read once, cache it\n const stored = localStorage.getItem(STORAGE_KEY)\n globalHistoryCache = stored ? JSON.parse(stored) : {}\n return globalHistoryCache!\n }\n return {}\n } catch (e) {\n console.error('Error parsing history:', e)\n return {}\n }\n }, [])\n\n // Debounce timer ref to prevent excessive localStorage writes\n const saveTimerRef = useRef<null | ReturnType<typeof setTimeout>>(null)\n\n const saveToLocalStorage = useCallback((newGlobalHistory: HistoryState) => {\n // Update cache immediately\n globalHistoryCache = newGlobalHistory\n\n if (typeof localStorage === 'undefined') {\n return\n }\n\n // Clear any pending save\n if (saveTimerRef.current) {\n clearTimeout(saveTimerRef.current)\n }\n\n // Debounce the save operation by 500ms\n saveTimerRef.current = setTimeout(() => {\n // Use requestIdleCallback if available to avoid blocking the main thread\n if (typeof requestIdleCallback !== 'undefined') {\n requestIdleCallback(\n () => {\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(newGlobalHistory))\n } catch (e) {\n console.warn('Failed to save history to localStorage', e)\n }\n },\n { timeout: 2000 },\n )\n } else {\n // Fallback for browsers without requestIdleCallback\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(newGlobalHistory))\n } catch (e) {\n console.warn('Failed to save history to localStorage', e)\n }\n }\n saveTimerRef.current = null\n }, 500)\n }, [])\n\n // Sync with other tabs\n useEffect(() => {\n const handleStorageChange = (e: StorageEvent) => {\n if (e.key === STORAGE_KEY && e.newValue) {\n try {\n globalHistoryCache = JSON.parse(e.newValue)\n } catch (err) {\n // ignore parse error\n }\n }\n }\n\n window.addEventListener('storage', handleStorageChange)\n return () => {\n window.removeEventListener('storage', handleStorageChange)\n }\n }, [])\n\n // Clear previous history\n const clearHistory = useCallback(() => {\n const latestHistory = { ...getLatestHistory() }\n let hasChanges = false\n Object.keys(latestHistory).forEach((k) => {\n if (!k.startsWith(id?.toString() ?? '')) {\n delete latestHistory[k]\n hasChanges = true\n }\n })\n \n if (hasChanges) {\n saveToLocalStorage(latestHistory)\n }\n }, [id, getLatestHistory, saveToLocalStorage])\n\n useEffect(() => {\n // This is applied to clear out the document history which is not currently in use\n clearHistory()\n\n const latestHistory = getLatestHistory()\n const { currentIndex, history } = latestHistory[fieldKey] || {\n currentIndex: -1,\n history: [],\n }\n\n let newIndex = currentIndex\n let historyUpdated = false\n const newHistoryArray = [...history]\n\n if (currentIndex == -1) {\n newIndex = 0\n \n // Get initial value from form data instead of subscribing to useField\n // This implementation avoids re-rendering on every keystroke\n try {\n const data = getData()\n // We need to resolve the value from the data object using the path\n // path might be 'group.subgroup.field'\n if (path) {\n const value = getSiblingData(data, path)\n if (value) {\n newHistoryArray[newIndex] = value\n historyUpdated = true\n }\n }\n } catch (e) {\n // If we can't get the data, just ignore\n }\n }\n\n if (historyUpdated) {\n const newGlobalHistory = {\n ...latestHistory,\n [fieldKey]: { currentIndex: newIndex, history: newHistoryArray },\n }\n saveToLocalStorage(newGlobalHistory)\n }\n }, [fieldKey, getData, path, clearHistory, getLatestHistory, saveToLocalStorage])\n\n const set = useCallback(\n (data: any) => {\n const latestHistory = getLatestHistory()\n const { currentIndex, history } = latestHistory[fieldKey] || {\n currentIndex: -1,\n history: [],\n }\n \n // Create new history array slice, appending new data\n let newHistory = [...history.slice(0, currentIndex + 1), data]\n \n // Enforce Max History Size\n if (newHistory.length > MAX_HISTORY_SIZE) {\n newHistory = newHistory.slice(newHistory.length - MAX_HISTORY_SIZE)\n }\n \n const newGlobalHistory = {\n ...latestHistory,\n [fieldKey]: { currentIndex: newHistory.length - 1, history: newHistory },\n }\n saveToLocalStorage(newGlobalHistory)\n return data\n },\n [fieldKey, getLatestHistory, saveToLocalStorage],\n )\n\n const undo = useCallback(() => {\n const latestHistory = getLatestHistory()\n const { currentIndex, history } = latestHistory[fieldKey] || { currentIndex: -1, history: [] }\n if (currentIndex > 0) {\n const newIndex = currentIndex - 1\n const newValue = history[newIndex]\n const newGlobalHistory = {\n ...latestHistory,\n [fieldKey]: { currentIndex: newIndex, history },\n }\n saveToLocalStorage(newGlobalHistory)\n return newValue\n }\n return undefined\n }, [fieldKey, getLatestHistory, saveToLocalStorage])\n\n const redo = useCallback(() => {\n const latestHistory = getLatestHistory()\n const { currentIndex, history } = latestHistory[fieldKey] || { currentIndex: -1, history: [] }\n if (currentIndex < history.length - 1) {\n const newIndex = currentIndex + 1\n const newValue = history[newIndex]\n const newGlobalHistory = {\n ...latestHistory,\n [fieldKey]: { currentIndex: newIndex, history },\n }\n saveToLocalStorage(newGlobalHistory)\n return newValue\n }\n return undefined\n }, [fieldKey, getLatestHistory, saveToLocalStorage])\n\n const getLatestFieldHistory = useCallback(() => {\n const latestHistory = getLatestHistory()\n return latestHistory[fieldKey] || { currentIndex: -1, history: [] }\n }, [getLatestHistory, fieldKey])\n\n const fieldHistory = getLatestFieldHistory()\n\n const canUndo = fieldHistory.currentIndex > 0\n const canRedo = fieldHistory.currentIndex < fieldHistory.history.length - 1\n \n // Note: We deliberately do not return currentValue to avoid subscription re-renders\n // The consumers of this hook (UndoRedoActions) didn't use it anyway.\n\n return {\n canRedo,\n canUndo,\n redo,\n set,\n undo,\n }\n}\n"],"names":["useDocumentInfo","useForm","useCallback","useEffect","useRef","getSiblingData","PLUGIN_NAME","useFieldProps","STORAGE_KEY","MAX_HISTORY_SIZE","globalHistoryCache","useHistory","id","path","schemaPath","getData","fieldKey","getLatestHistory","localStorage","stored","getItem","JSON","parse","e","console","error","saveTimerRef","saveToLocalStorage","newGlobalHistory","current","clearTimeout","setTimeout","requestIdleCallback","setItem","stringify","warn","timeout","handleStorageChange","key","newValue","err","window","addEventListener","removeEventListener","clearHistory","latestHistory","hasChanges","Object","keys","forEach","k","startsWith","toString","currentIndex","history","newIndex","historyUpdated","newHistoryArray","data","value","set","newHistory","slice","length","undo","undefined","redo","getLatestFieldHistory","fieldHistory","canUndo","canRedo"],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { LexicalEditor } from 'lexical';
2
+ type UseStreamingUpdateParams = {
3
+ editor: LexicalEditor;
4
+ isLoading: boolean;
5
+ object: any;
6
+ };
7
+ export declare const useStreamingUpdate: ({ editor, isLoading, object }: UseStreamingUpdateParams) => void;
8
+ export {};
@@ -0,0 +1,48 @@
1
+ import { useForm } from '@payloadcms/ui';
2
+ import { useEffect, useRef } from 'react';
3
+ import { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js';
4
+ import { setSafeLexicalState } from '../../../utilities/setSafeLexicalState.js';
5
+ export const useStreamingUpdate = ({ editor, isLoading, object })=>{
6
+ const { field, path: pathFromContext } = useFieldProps();
7
+ const { dispatchFields } = useForm();
8
+ // Ref for latest object to avoid effect re-runs during high-frequency streaming
9
+ const objectRef = useRef(object);
10
+ objectRef.current = object;
11
+ useEffect(()=>{
12
+ // Only run the animation loop while loading (streaming)
13
+ if (!isLoading) {
14
+ return;
15
+ }
16
+ let reqId;
17
+ const loop = ()=>{
18
+ const currentObject = objectRef.current;
19
+ if (currentObject) {
20
+ if (field?.type === 'richText') {
21
+ setSafeLexicalState(currentObject, editor);
22
+ } else if (field && 'name' in field && currentObject[field.name]) {
23
+ // Use dispatchFields for high-frequency streaming updates to avoid re-renders
24
+ dispatchFields({
25
+ type: 'UPDATE',
26
+ path: pathFromContext ?? '',
27
+ value: currentObject[field.name]
28
+ });
29
+ }
30
+ }
31
+ // Continue loop
32
+ reqId = requestAnimationFrame(loop);
33
+ };
34
+ // Start loop
35
+ loop();
36
+ return ()=>{
37
+ cancelAnimationFrame(reqId);
38
+ };
39
+ }, [
40
+ isLoading,
41
+ editor,
42
+ field,
43
+ dispatchFields,
44
+ pathFromContext
45
+ ]);
46
+ };
47
+
48
+ //# sourceMappingURL=useStreamingUpdate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../../../../src/ui/Compose/hooks/useStreamingUpdate.ts"],"sourcesContent":["import type { LexicalEditor } from 'lexical'\n\nimport { useForm } from '@payloadcms/ui'\nimport { useEffect, useRef } from 'react'\n\nimport { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js'\nimport { setSafeLexicalState } from '../../../utilities/setSafeLexicalState.js'\n\ntype UseStreamingUpdateParams = {\n editor: LexicalEditor\n isLoading: boolean\n object: any\n}\n\nexport const useStreamingUpdate = ({ editor, isLoading, object }: UseStreamingUpdateParams) => {\n const { field, path: pathFromContext } = useFieldProps()\n const { dispatchFields } = useForm()\n\n // Ref for latest object to avoid effect re-runs during high-frequency streaming\n const objectRef = useRef(object)\n objectRef.current = object\n\n useEffect(() => {\n // Only run the animation loop while loading (streaming)\n if (!isLoading) {\n return\n }\n\n let reqId: number\n\n const loop = () => {\n const currentObject = objectRef.current\n\n if (currentObject) {\n if (field?.type === 'richText') {\n setSafeLexicalState(currentObject, editor)\n } else if (field && 'name' in field && currentObject[field.name]) {\n // Use dispatchFields for high-frequency streaming updates to avoid re-renders\n dispatchFields({\n type: 'UPDATE',\n path: pathFromContext ?? '',\n value: currentObject[field.name],\n } as any)\n }\n }\n\n // Continue loop\n reqId = requestAnimationFrame(loop)\n }\n\n // Start loop\n loop()\n\n return () => {\n cancelAnimationFrame(reqId)\n }\n }, [isLoading, editor, field, dispatchFields, pathFromContext])\n}\n"],"names":["useForm","useEffect","useRef","useFieldProps","setSafeLexicalState","useStreamingUpdate","editor","isLoading","object","field","path","pathFromContext","dispatchFields","objectRef","current","reqId","loop","currentObject","type","name","value","requestAnimationFrame","cancelAnimationFrame"],"mappings":"AAEA,SAASA,OAAO,QAAQ,iBAAgB;AACxC,SAASC,SAAS,EAAEC,MAAM,QAAQ,QAAO;AAEzC,SAASC,aAAa,QAAQ,oDAAmD;AACjF,SAASC,mBAAmB,QAAQ,4CAA2C;AAQ/E,OAAO,MAAMC,qBAAqB,CAAC,EAAEC,MAAM,EAAEC,SAAS,EAAEC,MAAM,EAA4B;IACxF,MAAM,EAAEC,KAAK,EAAEC,MAAMC,eAAe,EAAE,GAAGR;IACzC,MAAM,EAAES,cAAc,EAAE,GAAGZ;IAE3B,gFAAgF;IAChF,MAAMa,YAAYX,OAAOM;IACzBK,UAAUC,OAAO,GAAGN;IAEpBP,UAAU;QACR,wDAAwD;QACxD,IAAI,CAACM,WAAW;YACd;QACF;QAEA,IAAIQ;QAEJ,MAAMC,OAAO;YACX,MAAMC,gBAAgBJ,UAAUC,OAAO;YAEvC,IAAIG,eAAe;gBACjB,IAAIR,OAAOS,SAAS,YAAY;oBAC9Bd,oBAAoBa,eAAeX;gBACrC,OAAO,IAAIG,SAAS,UAAUA,SAASQ,aAAa,CAACR,MAAMU,IAAI,CAAC,EAAE;oBAChE,8EAA8E;oBAC9EP,eAAe;wBACbM,MAAM;wBACNR,MAAMC,mBAAmB;wBACzBS,OAAOH,aAAa,CAACR,MAAMU,IAAI,CAAC;oBAClC;gBACF;YACF;YAEA,gBAAgB;YAChBJ,QAAQM,sBAAsBL;QAChC;QAEA,aAAa;QACbA;QAEA,OAAO;YACLM,qBAAqBP;QACvB;IACF,GAAG;QAACR;QAAWD;QAAQG;QAAOG;QAAgBD;KAAgB;AAChE,EAAC"}
@@ -0,0 +1,2 @@
1
+ import React from 'react';
2
+ export declare const ConfigDashboard: React.FC;
@@ -0,0 +1,224 @@
1
+ 'use client';
2
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
3
+ import { Button, toast, useConfig } from '@payloadcms/ui';
4
+ // @ts-expect-error - Next.js types are not resolving correctly with nodenext but runtime is fine
5
+ import { useRouter } from 'next/navigation';
6
+ import React, { use, useEffect, useState } from 'react';
7
+ import { excludeCollections } from '../../defaults.js';
8
+ import { InstructionsContext } from '../../providers/InstructionsProvider/context.js';
9
+ export const ConfigDashboard = ()=>{
10
+ const { config: { collections, routes: { admin: adminRoute, api: apiRoute } } } = useConfig();
11
+ const router = useRouter();
12
+ const { refresh, setEnabledCollections: setEnabledCollectionsInContext } = use(InstructionsContext);
13
+ const [enabledCollections, setEnabledCollections] = useState([]);
14
+ const [isLoading, setIsLoading] = useState(true);
15
+ const [isSaving, setIsSaving] = useState(false);
16
+ const availableCollections = collections.filter((c)=>!excludeCollections.includes(c.slug) && !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
+ } catch (error) {
28
+ console.error('Failed to fetch AI settings:', error);
29
+ } finally{
30
+ setIsLoading(false);
31
+ }
32
+ };
33
+ fetchSettings().catch((e)=>{
34
+ console.log(e);
35
+ });
36
+ }, [
37
+ apiRoute
38
+ ]);
39
+ const handleToggle = (slug)=>{
40
+ setEnabledCollections((prev)=>{
41
+ if (prev.includes(slug)) {
42
+ return prev.filter((s)=>s !== slug);
43
+ }
44
+ return [
45
+ ...prev,
46
+ slug
47
+ ];
48
+ });
49
+ };
50
+ const handleSave = async ()=>{
51
+ setIsSaving(true);
52
+ try {
53
+ // First fetch current settings to get ID or just rely on global update behavior
54
+ // We need to adhere to Payload's global update API
55
+ const response = await fetch(`${apiRoute}/globals/ai-providers`, {
56
+ body: JSON.stringify({
57
+ enabledCollections
58
+ }),
59
+ headers: {
60
+ 'Content-Type': 'application/json'
61
+ },
62
+ method: 'POST'
63
+ });
64
+ if (response.ok) {
65
+ toast.success('Settings saved successfully');
66
+ if (setEnabledCollectionsInContext) {
67
+ setEnabledCollectionsInContext(enabledCollections);
68
+ }
69
+ if (refresh) {
70
+ await refresh();
71
+ }
72
+ router.refresh();
73
+ } else {
74
+ toast.error('Failed to save settings');
75
+ }
76
+ } catch (error) {
77
+ console.error('Error saving settings:', error);
78
+ toast.error('Error saving settings');
79
+ } finally{
80
+ setIsSaving(false);
81
+ }
82
+ };
83
+ if (isLoading) {
84
+ return /*#__PURE__*/ _jsx("div", {
85
+ style: {
86
+ padding: '20px',
87
+ textAlign: 'center'
88
+ },
89
+ children: "Loading configuration..."
90
+ });
91
+ }
92
+ return /*#__PURE__*/ _jsxs("div", {
93
+ style: {
94
+ background: 'var(--theme-elevation-50)',
95
+ // border: '1px solid var(--theme-elevation-150)',
96
+ // borderRadius: '8px',
97
+ // borderBottom: '1px solid var(--theme-elevation-150)',
98
+ // borderTop: '1px solid var(--theme-elevation-150)',
99
+ marginBottom: '20px',
100
+ overflow: 'hidden'
101
+ },
102
+ children: [
103
+ /*#__PURE__*/ _jsxs("div", {
104
+ style: {
105
+ alignItems: 'center',
106
+ borderBottom: '1px solid var(--theme-elevation-150)',
107
+ display: 'flex',
108
+ justifyContent: 'space-between',
109
+ padding: '8px var(--gutter-h)'
110
+ },
111
+ children: [
112
+ /*#__PURE__*/ _jsxs("div", {
113
+ children: [
114
+ /*#__PURE__*/ _jsx("h2", {
115
+ style: {
116
+ margin: '0 0 5px 0'
117
+ },
118
+ children: "Let's configure your AI Plugin"
119
+ }),
120
+ /*#__PURE__*/ _jsx("p", {
121
+ style: {
122
+ color: 'var(--theme-elevation-500)',
123
+ fontSize: '14px',
124
+ margin: '0'
125
+ },
126
+ children: "Set up the provider → Choose the content → Refine the behavior."
127
+ })
128
+ ]
129
+ }),
130
+ /*#__PURE__*/ _jsxs("div", {
131
+ style: {
132
+ display: 'flex',
133
+ gap: '10px'
134
+ },
135
+ children: [
136
+ /*#__PURE__*/ _jsx(Button, {
137
+ buttonStyle: "secondary",
138
+ el: "link",
139
+ to: `${adminRoute}/globals/ai-providers`,
140
+ children: "Providers"
141
+ }),
142
+ /*#__PURE__*/ _jsx(Button, {
143
+ disabled: isSaving,
144
+ onClick: handleSave,
145
+ children: isSaving ? 'Saving...' : 'Save Changes'
146
+ })
147
+ ]
148
+ })
149
+ ]
150
+ }),
151
+ /*#__PURE__*/ _jsxs("div", {
152
+ style: {
153
+ padding: '24px var(--gutter-h)'
154
+ },
155
+ children: [
156
+ /*#__PURE__*/ _jsx("h5", {
157
+ style: {
158
+ marginBottom: '15px'
159
+ },
160
+ children: "Select the collections where AI features should be available, toggle them on or off, and save your changes."
161
+ }),
162
+ /*#__PURE__*/ _jsx("div", {
163
+ style: {
164
+ display: 'grid',
165
+ gap: '15px',
166
+ gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))'
167
+ },
168
+ children: availableCollections.map((collection)=>{
169
+ const isEnabled = enabledCollections.includes(collection.slug);
170
+ return /*#__PURE__*/ _jsxs("button", {
171
+ onClick: ()=>handleToggle(collection.slug),
172
+ style: {
173
+ alignItems: 'center',
174
+ background: isEnabled ? 'var(--theme-elevation-100)' : 'var(--theme-elevation-50)',
175
+ border: `1px solid ${isEnabled ? 'var(--theme-text-success)' : 'var(--theme-elevation-200)'}`,
176
+ borderRadius: '6px',
177
+ cursor: 'pointer',
178
+ display: 'flex',
179
+ gap: '10px',
180
+ padding: '10px 15px',
181
+ textAlign: 'left',
182
+ transition: 'all 0.2s ease',
183
+ width: '100%'
184
+ },
185
+ type: "button",
186
+ children: [
187
+ /*#__PURE__*/ _jsx("div", {
188
+ style: {
189
+ alignItems: 'center',
190
+ background: isEnabled ? 'var(--theme-text-success)' : 'var(--theme-elevation-200)',
191
+ borderRadius: '12px',
192
+ display: 'flex',
193
+ height: '24px',
194
+ justifyContent: isEnabled ? 'flex-end' : 'flex-start',
195
+ padding: '2px',
196
+ transition: 'all 0.2s ease',
197
+ width: '44px'
198
+ },
199
+ children: /*#__PURE__*/ _jsx("div", {
200
+ style: {
201
+ background: 'white',
202
+ borderRadius: '50%',
203
+ height: '20px',
204
+ width: '20px'
205
+ }
206
+ })
207
+ }),
208
+ /*#__PURE__*/ _jsx("span", {
209
+ style: {
210
+ fontWeight: 500
211
+ },
212
+ children: typeof collection.labels?.singular === 'string' ? collection.labels.singular : collection.labels?.singular?.en || collection.slug
213
+ })
214
+ ]
215
+ }, collection.slug);
216
+ })
217
+ })
218
+ ]
219
+ })
220
+ ]
221
+ });
222
+ };
223
+
224
+ //# sourceMappingURL=index.js.map
@@ -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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"}