@ai-stack/payloadcms 3.76.0-beta.1 → 3.76.0-beta.2
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/generateObject.js +1 -4
- package/dist/ai/core/generateObject.js.map +1 -1
- package/dist/ai/core/generateText.js +1 -5
- package/dist/ai/core/generateText.js.map +1 -1
- package/dist/ai/core/media/generateMedia.js +1 -4
- package/dist/ai/core/media/generateMedia.js.map +1 -1
- package/dist/ai/core/media/image/generateImage.js +4 -14
- package/dist/ai/core/media/image/generateImage.js.map +1 -1
- package/dist/ai/core/media/image/handlers/multimodal.js +8 -25
- package/dist/ai/core/media/image/handlers/multimodal.js.map +1 -1
- package/dist/ai/core/media/image/handlers/standard.js +7 -2
- package/dist/ai/core/media/image/handlers/standard.js.map +1 -1
- package/dist/ai/core/media/speech/generateSpeech.js +2 -3
- package/dist/ai/core/media/speech/generateSpeech.js.map +1 -1
- package/dist/ai/core/media/types.d.ts +2 -3
- package/dist/ai/core/media/types.js.map +1 -1
- package/dist/ai/core/streamObject.js +0 -3
- package/dist/ai/core/streamObject.js.map +1 -1
- package/dist/ai/core/streamText.js +1 -4
- package/dist/ai/core/streamText.js.map +1 -1
- package/dist/ai/core/types.d.ts +2 -2
- package/dist/ai/core/types.js.map +1 -1
- package/dist/ai/providers/blocks/anthropic.js +0 -42
- package/dist/ai/providers/blocks/anthropic.js.map +1 -1
- package/dist/ai/providers/blocks/elevenlabs.js +1 -106
- package/dist/ai/providers/blocks/elevenlabs.js.map +1 -1
- package/dist/ai/providers/blocks/fal.js +0 -118
- package/dist/ai/providers/blocks/fal.js.map +1 -1
- package/dist/ai/providers/blocks/google.js +2 -237
- package/dist/ai/providers/blocks/google.js.map +1 -1
- package/dist/ai/providers/blocks/openai-compatible.js +0 -144
- package/dist/ai/providers/blocks/openai-compatible.js.map +1 -1
- package/dist/ai/providers/blocks/openai.js +0 -200
- package/dist/ai/providers/blocks/openai.js.map +1 -1
- package/dist/ai/providers/blocks/xai.js +0 -53
- package/dist/ai/providers/blocks/xai.js.map +1 -1
- package/dist/ai/providers/index.d.ts +1 -1
- package/dist/ai/providers/index.js +0 -2
- package/dist/ai/providers/index.js.map +1 -1
- package/dist/ai/providers/registry.d.ts +24 -28
- package/dist/ai/providers/registry.js +184 -138
- package/dist/ai/providers/registry.js.map +1 -1
- package/dist/ai/providers/types.d.ts +12 -33
- package/dist/ai/providers/types.js +0 -1
- package/dist/ai/providers/types.js.map +1 -1
- package/dist/ai/schemas/lexicalJsonSchema.js +1 -1
- package/dist/ai/schemas/lexicalJsonSchema.js.map +1 -1
- package/dist/ai/utilities/filterEditorSchemaByNodes.js.map +1 -0
- package/dist/ai/utilities/generateFileNameByPrompt.js.map +1 -0
- package/dist/ai/utilities/isObjectSchema.js.map +1 -0
- package/dist/ai/utilities/nodeToSchemaMap.js.map +1 -0
- package/dist/ai/{prompts.d.ts → utilities/prompts.d.ts} +1 -1
- package/dist/ai/utilities/prompts.js.map +1 -0
- package/dist/ai/utilities/systemGenerate.js.map +1 -0
- package/dist/collections/AIJobs.js +3 -12
- package/dist/collections/AIJobs.js.map +1 -1
- package/dist/collections/AIProviders.js +47 -20
- package/dist/collections/AIProviders.js.map +1 -1
- package/dist/collections/Instructions.js +86 -54
- package/dist/collections/Instructions.js.map +1 -1
- package/dist/collections/shared.d.ts +30 -0
- package/dist/collections/shared.js +15 -0
- package/dist/collections/shared.js.map +1 -0
- package/dist/endpoints/fetchFields.js +14 -6
- 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/generate.d.ts +7 -0
- package/dist/endpoints/generate.js +268 -0
- package/dist/endpoints/generate.js.map +1 -0
- package/dist/endpoints/index.js +9 -639
- package/dist/endpoints/index.js.map +1 -1
- package/dist/endpoints/promptMentions.d.ts +2 -0
- package/dist/endpoints/promptMentions.js +166 -0
- package/dist/endpoints/promptMentions.js.map +1 -0
- package/dist/endpoints/upload.d.ts +7 -0
- package/dist/endpoints/upload.js +294 -0
- package/dist/endpoints/upload.js.map +1 -0
- package/dist/endpoints/videogenWebhook.d.ts +7 -0
- package/dist/endpoints/videogenWebhook.js +132 -0
- package/dist/endpoints/videogenWebhook.js.map +1 -0
- package/dist/exports/client.d.ts +2 -1
- package/dist/exports/client.js +2 -1
- package/dist/exports/client.js.map +1 -1
- package/dist/exports/fields.d.ts +2 -1
- package/dist/exports/fields.js +2 -1
- package/dist/exports/fields.js.map +1 -1
- package/dist/fields/ArrayComposeField/ArrayComposeField.js +1 -1
- package/dist/fields/ArrayComposeField/ArrayComposeField.js.map +1 -1
- package/dist/fields/ArrayComposeField/ArrayComposeField.jsx +1 -1
- package/dist/fields/ComposeField/ComposeField.d.ts +1 -0
- package/dist/fields/ComposeField/ComposeField.js +18 -8
- package/dist/fields/ComposeField/ComposeField.js.map +1 -1
- package/dist/fields/ComposeField/ComposeField.jsx +12 -7
- package/dist/fields/PromptEditorField/feature.client.d.ts +1 -0
- package/dist/fields/PromptEditorField/feature.client.js +173 -0
- package/dist/fields/PromptEditorField/feature.client.js.map +1 -0
- package/dist/fields/PromptEditorField/feature.client.jsx +148 -0
- package/dist/fields/PromptEditorField/feature.server.d.ts +1 -0
- package/dist/fields/PromptEditorField/feature.server.js +30 -0
- package/dist/fields/PromptEditorField/feature.server.js.map +1 -0
- package/dist/fields/PromptField.d.ts +4 -0
- package/dist/fields/PromptField.js +18 -0
- package/dist/fields/PromptField.js.map +1 -0
- package/dist/fields/SelectField/SelectField.js +0 -1
- package/dist/fields/SelectField/SelectField.js.map +1 -1
- package/dist/fields/SelectField/SelectField.jsx +0 -1
- package/dist/index.d.ts +4 -3
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/libraries/handlebars/helpers.js +2 -2
- package/dist/libraries/handlebars/helpers.js.map +1 -1
- package/dist/libraries/handlebars/replacePlaceholders.js +5 -1
- package/dist/libraries/handlebars/replacePlaceholders.js.map +1 -1
- package/dist/payload-ai.d.ts +5 -19
- package/dist/plugin.js +17 -20
- package/dist/plugin.js.map +1 -1
- package/dist/providers/FieldProvider/FieldProvider.js +10 -19
- package/dist/providers/FieldProvider/FieldProvider.js.map +1 -1
- package/dist/providers/FieldProvider/FieldProvider.jsx +7 -17
- package/dist/providers/InstructionsProvider/InstructionsProvider.js +4 -1
- package/dist/providers/InstructionsProvider/InstructionsProvider.js.map +1 -1
- package/dist/providers/InstructionsProvider/InstructionsProvider.jsx +3 -0
- package/dist/translations/de.json +47 -0
- package/dist/translations/en.json +45 -2
- package/dist/translations/es.json +45 -2
- package/dist/translations/fa.json +45 -2
- package/dist/translations/fr.json +46 -3
- package/dist/translations/hi.json +47 -0
- package/dist/translations/index.d.ts +88 -26
- package/dist/translations/index.js +18 -32
- package/dist/translations/index.js.map +1 -1
- package/dist/translations/ja.json +47 -0
- package/dist/translations/nb.json +47 -0
- package/dist/translations/nl.json +47 -0
- package/dist/translations/pl.json +45 -2
- package/dist/translations/pt.json +47 -0
- package/dist/translations/ru.json +45 -2
- package/dist/translations/th.json +47 -0
- package/dist/translations/translation-schema.json +184 -11
- package/dist/translations/uk.json +45 -2
- package/dist/translations/zh.json +47 -0
- package/dist/types.d.ts +54 -28
- package/dist/types.js.map +1 -1
- package/dist/ui/Compose/Compose.js +42 -79
- package/dist/ui/Compose/Compose.js.map +1 -1
- package/dist/ui/Compose/Compose.jsx +32 -86
- package/dist/ui/Compose/ComposePlaceholder.js +1 -1
- package/dist/ui/Compose/ComposePlaceholder.js.map +1 -1
- package/dist/ui/Compose/ComposePlaceholder.jsx +1 -1
- package/dist/ui/Compose/{compose.module.css → compose.module.scss} +3 -5
- package/dist/ui/Compose/hooks/menu/Item.d.ts +1 -1
- package/dist/ui/Compose/hooks/menu/Item.js +7 -3
- package/dist/ui/Compose/hooks/menu/Item.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/Item.jsx +11 -5
- package/dist/ui/Compose/hooks/menu/TranslateMenu.js +3 -1
- package/dist/ui/Compose/hooks/menu/TranslateMenu.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/TranslateMenu.jsx +3 -1
- package/dist/ui/Compose/hooks/menu/items.d.ts +8 -8
- package/dist/ui/Compose/hooks/menu/itemsMap.d.ts +2 -1
- package/dist/ui/Compose/hooks/menu/itemsMap.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/types.d.ts +21 -0
- package/dist/ui/Compose/hooks/menu/types.js +3 -0
- package/dist/ui/Compose/hooks/menu/types.js.map +1 -0
- package/dist/ui/Compose/hooks/menu/useMenu.d.ts +2 -2
- package/dist/ui/Compose/hooks/menu/useMenu.js +45 -23
- package/dist/ui/Compose/hooks/menu/useMenu.js.map +1 -1
- package/dist/ui/Compose/hooks/menu/useMenu.jsx +43 -23
- package/dist/ui/Compose/hooks/mergeGeneratedValue.d.ts +14 -0
- package/dist/ui/Compose/hooks/mergeGeneratedValue.js +38 -0
- package/dist/ui/Compose/hooks/mergeGeneratedValue.js.map +1 -0
- package/dist/ui/Compose/hooks/useGenerate.js +37 -12
- package/dist/ui/Compose/hooks/useGenerate.js.map +1 -1
- package/dist/ui/Compose/hooks/useGenerateUpload.js +66 -24
- package/dist/ui/Compose/hooks/useGenerateUpload.js.map +1 -1
- package/dist/ui/Compose/hooks/useStreamingUpdate.js +4 -4
- package/dist/ui/Compose/hooks/useStreamingUpdate.js.map +1 -1
- package/dist/ui/ConfigDashboard/configDashboard.module.css +94 -0
- package/dist/ui/ConfigDashboard/index.js +27 -92
- package/dist/ui/ConfigDashboard/index.js.map +1 -1
- package/dist/ui/ConfigDashboard/index.jsx +24 -77
- package/dist/ui/DynamicModelSelect/index.js +6 -27
- package/dist/ui/DynamicModelSelect/index.js.map +1 -1
- package/dist/ui/DynamicModelSelect/index.jsx +6 -29
- package/dist/ui/DynamicProviderSelect/index.js +6 -27
- package/dist/ui/DynamicProviderSelect/index.js.map +1 -1
- package/dist/ui/DynamicProviderSelect/index.jsx +6 -29
- package/dist/ui/DynamicVoiceSelect/index.js +34 -83
- package/dist/ui/DynamicVoiceSelect/index.js.map +1 -1
- package/dist/ui/DynamicVoiceSelect/index.jsx +16 -53
- package/dist/ui/GlobalProviderOptions/index.d.ts +2 -0
- package/dist/ui/GlobalProviderOptions/index.js +118 -0
- package/dist/ui/GlobalProviderOptions/index.js.map +1 -0
- package/dist/ui/GlobalProviderOptions/index.jsx +60 -0
- package/dist/ui/Icons/Icons.js +1 -1
- package/dist/ui/Icons/Icons.js.map +1 -1
- package/dist/ui/Icons/Icons.jsx +1 -1
- package/dist/ui/Icons/LottieAnimation.js +1 -1
- package/dist/ui/Icons/LottieAnimation.js.map +1 -1
- package/dist/ui/Icons/LottieAnimation.jsx +1 -1
- package/dist/ui/InstructionProviderOptions/ProviderOptionsTree.d.ts +12 -0
- package/dist/ui/InstructionProviderOptions/ProviderOptionsTree.js +166 -0
- package/dist/ui/InstructionProviderOptions/ProviderOptionsTree.js.map +1 -0
- package/dist/ui/InstructionProviderOptions/ProviderOptionsTree.jsx +83 -0
- package/dist/ui/InstructionProviderOptions/index.d.ts +2 -0
- package/dist/ui/InstructionProviderOptions/index.js +157 -0
- package/dist/ui/InstructionProviderOptions/index.js.map +1 -0
- package/dist/ui/InstructionProviderOptions/index.jsx +92 -0
- package/dist/ui/VoicesFetcher/index.js.map +1 -1
- package/dist/ui/hooks/useAISettings.d.ts +26 -0
- package/dist/ui/hooks/useAISettings.js +73 -0
- package/dist/ui/hooks/useAISettings.js.map +1 -0
- package/dist/ui/providerOptions/updateProviderOptionsValue.d.ts +6 -0
- package/dist/ui/providerOptions/updateProviderOptionsValue.js +50 -0
- package/dist/ui/providerOptions/updateProviderOptionsValue.js.map +1 -0
- package/dist/ui/shared/handleSelectChange.d.ts +5 -0
- package/dist/ui/shared/handleSelectChange.js +12 -0
- package/dist/ui/shared/handleSelectChange.js.map +1 -0
- package/dist/ui/shared/types.d.ts +11 -0
- package/dist/ui/shared/types.js +5 -0
- package/dist/ui/shared/types.js.map +1 -0
- package/dist/utilities/ai/resolveEffectiveInstructionSettings.d.ts +15 -0
- package/dist/utilities/ai/resolveEffectiveInstructionSettings.js +136 -0
- package/dist/utilities/ai/resolveEffectiveInstructionSettings.js.map +1 -0
- package/dist/{endpoints → utilities}/buildPromptUtils.js +14 -5
- package/dist/utilities/buildPromptUtils.js.map +1 -0
- package/dist/utilities/buildSmartPrompt.js +3 -3
- package/dist/utilities/buildSmartPrompt.js.map +1 -1
- package/dist/utilities/fields/fieldToJsonSchema.js.map +1 -0
- package/dist/utilities/fields/getFieldBySchemaPath.js.map +1 -0
- package/dist/utilities/fields/getFieldInfo.js.map +1 -0
- package/dist/utilities/{updateFieldsConfig.js → fields/updateFieldsConfig.js} +7 -2
- package/dist/utilities/fields/updateFieldsConfig.js.map +1 -0
- package/dist/utilities/images/extractImageData.js.map +1 -0
- package/dist/utilities/images/extractPromptAttachments.js.map +1 -0
- package/dist/utilities/{fetchImages.d.ts → images/fetchImages.d.ts} +1 -1
- package/dist/utilities/images/fetchImages.js +49 -0
- package/dist/utilities/images/fetchImages.js.map +1 -0
- package/dist/utilities/images/resolveImageReferences.js +183 -0
- package/dist/utilities/images/resolveImageReferences.js.map +1 -0
- package/dist/utilities/init/autoSetupProviders.d.ts +3 -0
- package/dist/utilities/init/autoSetupProviders.js +216 -0
- package/dist/utilities/init/autoSetupProviders.js.map +1 -0
- package/dist/utilities/lexical/editorSchemaValidator.js.map +1 -0
- package/dist/utilities/lexical/lexicalToHTML.js.map +1 -0
- package/dist/utilities/lexical/lexicalToPromptTemplate.d.ts +2 -0
- package/dist/utilities/lexical/lexicalToPromptTemplate.js +50 -0
- package/dist/utilities/lexical/lexicalToPromptTemplate.js.map +1 -0
- package/dist/utilities/lexical/setSafeLexicalState.js.map +1 -0
- package/dist/utilities/lexical/stringToLexicalJSON.d.ts +2 -0
- package/dist/utilities/lexical/stringToLexicalJSON.js +39 -0
- package/dist/utilities/lexical/stringToLexicalJSON.js.map +1 -0
- package/dist/utilities/sanitizeLog.d.ts +1 -0
- package/dist/utilities/sanitizeLog.js +39 -0
- package/dist/utilities/sanitizeLog.js.map +1 -0
- package/dist/utilities/seedProperties.js +37 -22
- package/dist/utilities/seedProperties.js.map +1 -1
- package/package.json +5 -2
- package/dist/ai/analyse.d.ts +0 -1
- package/dist/ai/analyse.js +0 -3
- package/dist/ai/analyse.js.map +0 -1
- package/dist/ai/index.d.ts +0 -11
- package/dist/ai/index.js +0 -25
- package/dist/ai/index.js.map +0 -1
- package/dist/ai/prompts.js.map +0 -1
- package/dist/ai/utils/filterEditorSchemaByNodes.js.map +0 -1
- package/dist/ai/utils/generateFileNameByPrompt.js.map +0 -1
- package/dist/ai/utils/isObjectSchema.js.map +0 -1
- package/dist/ai/utils/nodeToSchemaMap.js.map +0 -1
- package/dist/ai/utils/systemGenerate.js.map +0 -1
- package/dist/endpoints/buildPromptUtils.js.map +0 -1
- package/dist/endpoints/chat.d.ts +0 -4
- package/dist/fields/PromptEditorField/PromptEditorField.d.ts +0 -3
- package/dist/fields/PromptEditorField/PromptEditorField.js +0 -217
- package/dist/fields/PromptEditorField/PromptEditorField.js.map +0 -1
- package/dist/fields/PromptEditorField/PromptEditorField.jsx +0 -160
- package/dist/ui/AIConfigDashboard/index.d.ts +0 -2
- package/dist/ui/AIConfigDashboard/index.js +0 -224
- package/dist/ui/AIConfigDashboard/index.js.map +0 -1
- package/dist/ui/AIConfigDashboard/index.jsx +0 -175
- package/dist/ui/ProviderOptionsEditor/index.d.ts +0 -7
- package/dist/ui/ProviderOptionsEditor/index.js +0 -291
- package/dist/ui/ProviderOptionsEditor/index.js.map +0 -1
- package/dist/ui/ProviderOptionsEditor/index.jsx +0 -210
- package/dist/utilities/editorSchemaValidator.js.map +0 -1
- package/dist/utilities/extractImageData.js.map +0 -1
- package/dist/utilities/extractPromptAttachments.js.map +0 -1
- package/dist/utilities/fetchImages.js +0 -38
- package/dist/utilities/fetchImages.js.map +0 -1
- package/dist/utilities/fieldToJsonSchema.js.map +0 -1
- package/dist/utilities/getFieldBySchemaPath.js.map +0 -1
- package/dist/utilities/getFieldInfo.js.map +0 -1
- package/dist/utilities/getProviderOptionsFields.d.ts +0 -16
- package/dist/utilities/getProviderOptionsFields.js +0 -80
- package/dist/utilities/getProviderOptionsFields.js.map +0 -1
- package/dist/utilities/isPluginActivated.d.ts +0 -2
- package/dist/utilities/isPluginActivated.js +0 -5
- package/dist/utilities/isPluginActivated.js.map +0 -1
- package/dist/utilities/lexicalToHTML.js.map +0 -1
- package/dist/utilities/resolveImageReferences.js +0 -167
- package/dist/utilities/resolveImageReferences.js.map +0 -1
- package/dist/utilities/schemaConverter.d.ts +0 -3
- package/dist/utilities/schemaConverter.js +0 -93
- package/dist/utilities/schemaConverter.js.map +0 -1
- package/dist/utilities/setSafeLexicalState.js.map +0 -1
- package/dist/utilities/updateFieldsConfig.js.map +0 -1
- /package/dist/ai/{utils → utilities}/filterEditorSchemaByNodes.d.ts +0 -0
- /package/dist/ai/{utils → utilities}/filterEditorSchemaByNodes.js +0 -0
- /package/dist/ai/{utils → utilities}/generateFileNameByPrompt.d.ts +0 -0
- /package/dist/ai/{utils → utilities}/generateFileNameByPrompt.js +0 -0
- /package/dist/ai/{utils → utilities}/isObjectSchema.d.ts +0 -0
- /package/dist/ai/{utils → utilities}/isObjectSchema.js +0 -0
- /package/dist/ai/{utils → utilities}/nodeToSchemaMap.d.ts +0 -0
- /package/dist/ai/{utils → utilities}/nodeToSchemaMap.js +0 -0
- /package/dist/ai/{prompts.js → utilities/prompts.js} +0 -0
- /package/dist/ai/{utils → utilities}/systemGenerate.d.ts +0 -0
- /package/dist/ai/{utils → utilities}/systemGenerate.js +0 -0
- /package/dist/ui/Icons/{icons.module.css → icons.module.scss} +0 -0
- /package/dist/{endpoints → utilities}/buildPromptUtils.d.ts +0 -0
- /package/dist/utilities/{fieldToJsonSchema.d.ts → fields/fieldToJsonSchema.d.ts} +0 -0
- /package/dist/utilities/{fieldToJsonSchema.js → fields/fieldToJsonSchema.js} +0 -0
- /package/dist/utilities/{getFieldBySchemaPath.d.ts → fields/getFieldBySchemaPath.d.ts} +0 -0
- /package/dist/utilities/{getFieldBySchemaPath.js → fields/getFieldBySchemaPath.js} +0 -0
- /package/dist/utilities/{getFieldInfo.d.ts → fields/getFieldInfo.d.ts} +0 -0
- /package/dist/utilities/{getFieldInfo.js → fields/getFieldInfo.js} +0 -0
- /package/dist/utilities/{updateFieldsConfig.d.ts → fields/updateFieldsConfig.d.ts} +0 -0
- /package/dist/utilities/{extractImageData.d.ts → images/extractImageData.d.ts} +0 -0
- /package/dist/utilities/{extractImageData.js → images/extractImageData.js} +0 -0
- /package/dist/utilities/{extractPromptAttachments.d.ts → images/extractPromptAttachments.d.ts} +0 -0
- /package/dist/utilities/{extractPromptAttachments.js → images/extractPromptAttachments.js} +0 -0
- /package/dist/utilities/{resolveImageReferences.d.ts → images/resolveImageReferences.d.ts} +0 -0
- /package/dist/utilities/{editorSchemaValidator.d.ts → lexical/editorSchemaValidator.d.ts} +0 -0
- /package/dist/utilities/{editorSchemaValidator.js → lexical/editorSchemaValidator.js} +0 -0
- /package/dist/utilities/{lexicalToHTML.d.ts → lexical/lexicalToHTML.d.ts} +0 -0
- /package/dist/utilities/{lexicalToHTML.js → lexical/lexicalToHTML.js} +0 -0
- /package/dist/utilities/{setSafeLexicalState.d.ts → lexical/setSafeLexicalState.d.ts} +0 -0
- /package/dist/utilities/{setSafeLexicalState.js → lexical/setSafeLexicalState.js} +0 -0
|
@@ -1,23 +1,47 @@
|
|
|
1
1
|
import { toast, useConfig, useDocumentInfo, useField, useForm, useLocale } from '@payloadcms/ui';
|
|
2
|
-
import { useCallback, useState } from 'react';
|
|
2
|
+
import { useCallback, useEffect, useRef, useState } from 'react';
|
|
3
3
|
import { PLUGIN_AI_JOBS_TABLE, PLUGIN_API_ENDPOINT_GENERATE_UPLOAD } from '../../../defaults.js';
|
|
4
4
|
import { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js';
|
|
5
|
+
import { useInstructions } from '../../../providers/InstructionsProvider/useInstructions.js';
|
|
6
|
+
import { mergeGeneratedValue } from './mergeGeneratedValue.js';
|
|
5
7
|
import { useHistory } from './useHistory.js';
|
|
6
8
|
export const useGenerateUpload = ({ instructionIdRef })=>{
|
|
7
9
|
const { config } = useConfig();
|
|
8
10
|
const { routes: { api }, serverURL } = config;
|
|
9
11
|
const { id: documentId, collectionSlug } = useDocumentInfo();
|
|
10
|
-
const
|
|
12
|
+
const locale = useLocale();
|
|
11
13
|
const { getData } = useForm();
|
|
12
14
|
const { set: setHistory } = useHistory();
|
|
13
|
-
const { field, path:
|
|
14
|
-
const {
|
|
15
|
-
|
|
15
|
+
const { field, path: fieldPath, schemaPath } = useFieldProps();
|
|
16
|
+
const { appendGenerated } = useInstructions({
|
|
17
|
+
schemaPath
|
|
16
18
|
});
|
|
19
|
+
const { setValue, value: currentFieldValue } = useField({
|
|
20
|
+
path: fieldPath ?? ''
|
|
21
|
+
});
|
|
22
|
+
const appendGeneratedRef = useRef(!!appendGenerated);
|
|
23
|
+
const currentFieldValueRef = useRef(currentFieldValue);
|
|
17
24
|
// Async job UI state
|
|
18
25
|
const [jobStatus, setJobStatus] = useState(undefined);
|
|
19
26
|
const [jobProgress, setJobProgress] = useState(0);
|
|
20
27
|
const [isJobActive, setIsJobActive] = useState(false);
|
|
28
|
+
// Track whether the component is still mounted to prevent orphaned polling
|
|
29
|
+
const cancelledRef = useRef(false);
|
|
30
|
+
useEffect(()=>{
|
|
31
|
+
return ()=>{
|
|
32
|
+
cancelledRef.current = true;
|
|
33
|
+
};
|
|
34
|
+
}, []);
|
|
35
|
+
useEffect(()=>{
|
|
36
|
+
appendGeneratedRef.current = !!appendGenerated;
|
|
37
|
+
}, [
|
|
38
|
+
appendGenerated
|
|
39
|
+
]);
|
|
40
|
+
useEffect(()=>{
|
|
41
|
+
currentFieldValueRef.current = currentFieldValue;
|
|
42
|
+
}, [
|
|
43
|
+
currentFieldValue
|
|
44
|
+
]);
|
|
21
45
|
const generateUpload = useCallback(async ()=>{
|
|
22
46
|
const doc = getData();
|
|
23
47
|
const currentInstructionId = instructionIdRef.current;
|
|
@@ -26,7 +50,7 @@ export const useGenerateUpload = ({ instructionIdRef })=>{
|
|
|
26
50
|
collectionSlug: collectionSlug ?? '',
|
|
27
51
|
doc,
|
|
28
52
|
documentId,
|
|
29
|
-
locale:
|
|
53
|
+
locale: locale?.code,
|
|
30
54
|
options: {
|
|
31
55
|
instructionId: currentInstructionId
|
|
32
56
|
}
|
|
@@ -41,14 +65,21 @@ export const useGenerateUpload = ({ instructionIdRef })=>{
|
|
|
41
65
|
const json = await uploadResponse.json();
|
|
42
66
|
const { job, result } = json || {};
|
|
43
67
|
if (result) {
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
68
|
+
const hasMany = field?.hasMany === true;
|
|
69
|
+
const generatedValue = Array.isArray(result) ? result.map((r)=>r.id) : result?.id;
|
|
70
|
+
const merged = mergeGeneratedValue({
|
|
71
|
+
appendGenerated: appendGeneratedRef.current,
|
|
72
|
+
currentValue: currentFieldValueRef.current,
|
|
73
|
+
generatedValue,
|
|
74
|
+
hasMany,
|
|
75
|
+
max: typeof field?.max === 'number' ? field.max : undefined,
|
|
76
|
+
maxRows: typeof field?.maxRows === 'number' ? field.maxRows : undefined
|
|
77
|
+
});
|
|
78
|
+
if (merged.truncated) {
|
|
79
|
+
toast.info('Appended values were truncated to this field maximum.');
|
|
51
80
|
}
|
|
81
|
+
setValue(merged.value);
|
|
82
|
+
setHistory(merged.value);
|
|
52
83
|
// Show toast to prompt user to save
|
|
53
84
|
toast.success('Image generated successfully! Click Save to see the preview.');
|
|
54
85
|
return uploadResponse;
|
|
@@ -56,15 +87,10 @@ export const useGenerateUpload = ({ instructionIdRef })=>{
|
|
|
56
87
|
// Async job: poll AI Jobs collection for status/progress/result_id
|
|
57
88
|
if (job && job.id) {
|
|
58
89
|
setIsJobActive(true);
|
|
59
|
-
const cancelled = false;
|
|
60
90
|
let attempts = 0;
|
|
61
91
|
const maxAttempts = 600 // up to ~10 minutes @ 1s
|
|
62
92
|
;
|
|
63
|
-
// Basic in-hook state via closure variables; UI will re-render off fetches below
|
|
64
93
|
const poll = async ()=>{
|
|
65
|
-
if (cancelled) {
|
|
66
|
-
return;
|
|
67
|
-
}
|
|
68
94
|
try {
|
|
69
95
|
const res = await fetch(`${serverURL}${api}/${PLUGIN_AI_JOBS_TABLE}/${job.id}`, {
|
|
70
96
|
credentials: 'include'
|
|
@@ -76,9 +102,10 @@ export const useGenerateUpload = ({ instructionIdRef })=>{
|
|
|
76
102
|
setJobProgress(progress ?? 0);
|
|
77
103
|
// When result present, set field and finish
|
|
78
104
|
if (status === 'completed' && result_id) {
|
|
105
|
+
const hasMany = field?.hasMany === true;
|
|
79
106
|
let valueToSet = result_id;
|
|
80
107
|
// Attempt to fetch full document for immediate preview
|
|
81
|
-
if (field && 'relationTo' in field && typeof field.relationTo === 'string') {
|
|
108
|
+
if (!hasMany && field && 'relationTo' in field && typeof field.relationTo === 'string') {
|
|
82
109
|
let attempts = 0;
|
|
83
110
|
const maxAttempts = 3;
|
|
84
111
|
while(attempts < maxAttempts){
|
|
@@ -103,8 +130,22 @@ export const useGenerateUpload = ({ instructionIdRef })=>{
|
|
|
103
130
|
}
|
|
104
131
|
}
|
|
105
132
|
}
|
|
106
|
-
|
|
107
|
-
|
|
133
|
+
const generatedValue = hasMany ? [
|
|
134
|
+
result_id
|
|
135
|
+
] : valueToSet;
|
|
136
|
+
const merged = mergeGeneratedValue({
|
|
137
|
+
appendGenerated: appendGeneratedRef.current,
|
|
138
|
+
currentValue: currentFieldValueRef.current,
|
|
139
|
+
generatedValue,
|
|
140
|
+
hasMany,
|
|
141
|
+
max: typeof field?.max === 'number' ? field.max : undefined,
|
|
142
|
+
maxRows: typeof field?.maxRows === 'number' ? field.maxRows : undefined
|
|
143
|
+
});
|
|
144
|
+
if (merged.truncated) {
|
|
145
|
+
toast.info('Appended values were truncated to this field maximum.');
|
|
146
|
+
}
|
|
147
|
+
setValue(merged.value);
|
|
148
|
+
setHistory(merged.value);
|
|
108
149
|
setIsJobActive(false);
|
|
109
150
|
return;
|
|
110
151
|
}
|
|
@@ -117,7 +158,7 @@ export const useGenerateUpload = ({ instructionIdRef })=>{
|
|
|
117
158
|
// silent retry
|
|
118
159
|
}
|
|
119
160
|
attempts += 1;
|
|
120
|
-
if (
|
|
161
|
+
if (attempts < maxAttempts && !cancelledRef.current) {
|
|
121
162
|
setTimeout(poll, 1000);
|
|
122
163
|
}
|
|
123
164
|
};
|
|
@@ -136,9 +177,10 @@ export const useGenerateUpload = ({ instructionIdRef })=>{
|
|
|
136
177
|
});
|
|
137
178
|
}, [
|
|
138
179
|
getData,
|
|
139
|
-
|
|
180
|
+
locale?.code,
|
|
140
181
|
instructionIdRef,
|
|
141
|
-
|
|
182
|
+
setValue,
|
|
183
|
+
field,
|
|
142
184
|
documentId,
|
|
143
185
|
collectionSlug,
|
|
144
186
|
serverURL,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../src/ui/Compose/hooks/useGenerateUpload.ts"],"sourcesContent":["import { toast, useConfig, useDocumentInfo, useField, useForm, useLocale } from '@payloadcms/ui'\nimport { type RefObject, useCallback, useState } from 'react'\n\nimport type { GenerateTextarea } from '../../../types.js'\n\nimport { PLUGIN_AI_JOBS_TABLE, PLUGIN_API_ENDPOINT_GENERATE_UPLOAD } from '../../../defaults.js'\nimport { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js'\nimport { useHistory } from './useHistory.js'\n\ntype UseGenerateUploadParams = {\n instructionIdRef: RefObject<string>\n}\n\nexport const useGenerateUpload = ({ instructionIdRef }: UseGenerateUploadParams) => {\n const { config } = useConfig()\n const {\n routes: { api },\n serverURL,\n } = config\n const { id: documentId, collectionSlug } = useDocumentInfo()\n const localFromContext = useLocale()\n const { getData } = useForm()\n const { set: setHistory } = useHistory()\n\n const { field, path: pathFromContext } = useFieldProps()\n const { setValue } = useField<any>({\n path: pathFromContext ?? '',\n })\n\n // Async job UI state\n const [jobStatus, setJobStatus] = useState<string | undefined>(undefined)\n const [jobProgress, setJobProgress] = useState<number>(0)\n const [isJobActive, setIsJobActive] = useState<boolean>(false)\n\n const generateUpload = useCallback(async () => {\n const doc = getData()\n const currentInstructionId = instructionIdRef.current\n\n return fetch(`${serverURL}${api}${PLUGIN_API_ENDPOINT_GENERATE_UPLOAD}`, {\n body: JSON.stringify({\n collectionSlug: collectionSlug ?? '',\n doc,\n documentId,\n locale: localFromContext?.code,\n options: {\n instructionId: currentInstructionId,\n },\n } satisfies Parameters<GenerateTextarea>[0]),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n .then(async (uploadResponse) => {\n if (uploadResponse.ok) {\n const json = await uploadResponse.json()\n const { job, result } = json || {}\n if (result) {\n if (Array.isArray(result)) {\n const ids = result.map((r: any) => r.id)\n setValue(ids)\n setHistory(ids)\n } else {\n setValue(result?.id)\n setHistory(result?.id)\n }\n\n // Show toast to prompt user to save\n toast.success('Image generated successfully! Click Save to see the preview.')\n\n return uploadResponse\n }\n\n // Async job: poll AI Jobs collection for status/progress/result_id\n if (job && job.id) {\n setIsJobActive(true)\n const cancelled = false\n let attempts = 0\n const maxAttempts = 600 // up to ~10 minutes @ 1s\n\n // Basic in-hook state via closure variables; UI will re-render off fetches below\n const poll = async (): Promise<void> => {\n if (cancelled) {\n return\n }\n try {\n const res = await fetch(`${serverURL}${api}/${PLUGIN_AI_JOBS_TABLE}/${job.id}`, {\n credentials: 'include',\n })\n if (res.ok) {\n const jobDoc = await res.json()\n const { progress, result_id, status } = jobDoc || {}\n setJobStatus(status)\n setJobProgress(progress ?? 0)\n // When result present, set field and finish\n if (status === 'completed' && result_id) {\n let valueToSet = result_id\n\n // Attempt to fetch full document for immediate preview\n if (field && 'relationTo' in field && typeof field.relationTo === 'string') {\n let attempts = 0\n const maxAttempts = 3\n while (attempts < maxAttempts) {\n try {\n const docRes = await fetch(\n `${serverURL}${api}/${field.relationTo}/${result_id}`,\n {\n credentials: 'include',\n },\n )\n if (docRes.ok) {\n const doc = await docRes.json()\n // Verify we have a URL for preview\n if (doc && doc.url) {\n valueToSet = doc\n break\n }\n }\n } catch (e) {\n console.error('Failed to fetch generated document for preview:', e)\n }\n attempts++\n if (attempts < maxAttempts) {\n await new Promise((resolve) => setTimeout(resolve, 500))\n }\n }\n }\n\n setValue(valueToSet)\n setHistory(result_id)\n setIsJobActive(false)\n return\n }\n if (status === 'failed') {\n setIsJobActive(false)\n throw new Error('Video generation failed')\n }\n }\n } catch (_) {\n // silent retry\n }\n\n attempts += 1\n if (!cancelled && attempts < maxAttempts) {\n setTimeout(poll, 1000)\n }\n }\n setTimeout(poll, 1000)\n return uploadResponse\n }\n\n throw new Error('generateUpload: Unexpected response')\n } else {\n const { errors = [] } = await uploadResponse.json()\n const errStr = errors.map((error: any) => error.message).join(', ')\n throw new Error(errStr)\n }\n })\n .catch((error) => {\n toast.error(`Failed to generate: ${error.message}`)\n console.error(\n 'Error generating or setting your upload, please set it manually if its saved in your media files.',\n error,\n )\n })\n }, [\n getData,\n localFromContext?.code,\n instructionIdRef,\n // setValue,\n documentId,\n collectionSlug,\n serverURL,\n api,\n setHistory,\n ])\n\n return {\n generateUpload,\n isJobActive,\n jobProgress,\n jobStatus,\n }\n}\n"],"names":["toast","useConfig","useDocumentInfo","useField","useForm","useLocale","useCallback","useState","PLUGIN_AI_JOBS_TABLE","PLUGIN_API_ENDPOINT_GENERATE_UPLOAD","useFieldProps","useHistory","useGenerateUpload","instructionIdRef","config","routes","api","serverURL","id","documentId","collectionSlug","localFromContext","getData","set","setHistory","field","path","pathFromContext","setValue","jobStatus","setJobStatus","undefined","jobProgress","setJobProgress","isJobActive","setIsJobActive","generateUpload","doc","currentInstructionId","current","fetch","body","JSON","stringify","locale","code","options","instructionId","credentials","headers","method","then","uploadResponse","ok","json","job","result","Array","isArray","ids","map","r","success","cancelled","attempts","maxAttempts","poll","res","jobDoc","progress","result_id","status","valueToSet","relationTo","docRes","url","e","console","error","Promise","resolve","setTimeout","Error","_","errors","errStr","message","join","catch"],"mappings":"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"}
|
|
1
|
+
{"version":3,"sources":["../../../../src/ui/Compose/hooks/useGenerateUpload.ts"],"sourcesContent":["import { toast, useConfig, useDocumentInfo, useField, useForm, useLocale } from '@payloadcms/ui'\nimport { type RefObject, useCallback, useEffect, useRef, useState } from 'react'\n\nimport type { GenerateTextarea } from '../../../types.js'\n\nimport { PLUGIN_AI_JOBS_TABLE, PLUGIN_API_ENDPOINT_GENERATE_UPLOAD } from '../../../defaults.js'\nimport { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js'\nimport { useInstructions } from '../../../providers/InstructionsProvider/useInstructions.js'\nimport { mergeGeneratedValue } from './mergeGeneratedValue.js'\nimport { useHistory } from './useHistory.js'\n\ntype UseGenerateUploadParams = {\n instructionIdRef: RefObject<string>\n}\n\nexport const useGenerateUpload = ({ instructionIdRef }: UseGenerateUploadParams) => {\n const { config } = useConfig()\n const {\n routes: { api },\n serverURL,\n } = config\n const { id: documentId, collectionSlug } = useDocumentInfo()\n const locale = useLocale()\n const { getData } = useForm()\n const { set: setHistory } = useHistory()\n\n const { field, path: fieldPath, schemaPath } = useFieldProps()\n const { appendGenerated } = useInstructions({ schemaPath })\n const { setValue, value: currentFieldValue } = useField<any>({\n path: fieldPath ?? '',\n })\n const appendGeneratedRef = useRef(!!appendGenerated)\n const currentFieldValueRef = useRef(currentFieldValue)\n\n // Async job UI state\n const [jobStatus, setJobStatus] = useState<string | undefined>(undefined)\n const [jobProgress, setJobProgress] = useState<number>(0)\n const [isJobActive, setIsJobActive] = useState<boolean>(false)\n\n // Track whether the component is still mounted to prevent orphaned polling\n const cancelledRef = useRef(false)\n useEffect(() => {\n return () => {\n cancelledRef.current = true\n }\n }, [])\n\n useEffect(() => {\n appendGeneratedRef.current = !!appendGenerated\n }, [appendGenerated])\n\n useEffect(() => {\n currentFieldValueRef.current = currentFieldValue\n }, [currentFieldValue])\n\n const generateUpload = useCallback(async () => {\n const doc = getData()\n const currentInstructionId = instructionIdRef.current\n\n return fetch(`${serverURL}${api}${PLUGIN_API_ENDPOINT_GENERATE_UPLOAD}`, {\n body: JSON.stringify({\n collectionSlug: collectionSlug ?? '',\n doc,\n documentId,\n locale: locale?.code,\n options: {\n instructionId: currentInstructionId,\n },\n } satisfies Parameters<GenerateTextarea>[0]),\n credentials: 'include',\n headers: {\n 'Content-Type': 'application/json',\n },\n method: 'POST',\n })\n .then(async (uploadResponse) => {\n if (uploadResponse.ok) {\n const json = await uploadResponse.json()\n const { job, result } = json || {}\n if (result) {\n const hasMany = (field as any)?.hasMany === true\n const generatedValue = Array.isArray(result) ? result.map((r: any) => r.id) : result?.id\n const merged = mergeGeneratedValue({\n appendGenerated: appendGeneratedRef.current,\n currentValue: currentFieldValueRef.current,\n generatedValue,\n hasMany,\n max: typeof (field as any)?.max === 'number' ? (field as any).max : undefined,\n maxRows: typeof (field as any)?.maxRows === 'number' ? (field as any).maxRows : undefined,\n })\n\n if (merged.truncated) {\n toast.info('Appended values were truncated to this field maximum.')\n }\n\n setValue(merged.value)\n setHistory(merged.value)\n\n // Show toast to prompt user to save\n toast.success('Image generated successfully! Click Save to see the preview.')\n\n return uploadResponse\n }\n\n // Async job: poll AI Jobs collection for status/progress/result_id\n if (job && job.id) {\n setIsJobActive(true)\n let attempts = 0\n const maxAttempts = 600 // up to ~10 minutes @ 1s\n\n const poll = async (): Promise<void> => {\n try {\n const res = await fetch(`${serverURL}${api}/${PLUGIN_AI_JOBS_TABLE}/${job.id}`, {\n credentials: 'include',\n })\n if (res.ok) {\n const jobDoc = await res.json()\n const { progress, result_id, status } = jobDoc || {}\n setJobStatus(status)\n setJobProgress(progress ?? 0)\n // When result present, set field and finish\n if (status === 'completed' && result_id) {\n const hasMany = (field as any)?.hasMany === true\n let valueToSet = result_id\n\n // Attempt to fetch full document for immediate preview\n if (\n !hasMany &&\n field &&\n 'relationTo' in field &&\n typeof field.relationTo === 'string'\n ) {\n let attempts = 0\n const maxAttempts = 3\n while (attempts < maxAttempts) {\n try {\n const docRes = await fetch(\n `${serverURL}${api}/${field.relationTo}/${result_id}`,\n {\n credentials: 'include',\n },\n )\n if (docRes.ok) {\n const doc = await docRes.json()\n // Verify we have a URL for preview\n if (doc && doc.url) {\n valueToSet = doc\n break\n }\n }\n } catch (e) {\n console.error('Failed to fetch generated document for preview:', e)\n }\n attempts++\n if (attempts < maxAttempts) {\n await new Promise((resolve) => setTimeout(resolve, 500))\n }\n }\n }\n\n const generatedValue = hasMany ? [result_id] : valueToSet\n const merged = mergeGeneratedValue({\n appendGenerated: appendGeneratedRef.current,\n currentValue: currentFieldValueRef.current,\n generatedValue,\n hasMany,\n max: typeof (field as any)?.max === 'number' ? (field as any).max : undefined,\n maxRows: typeof (field as any)?.maxRows === 'number' ? (field as any).maxRows : undefined,\n })\n\n if (merged.truncated) {\n toast.info('Appended values were truncated to this field maximum.')\n }\n\n setValue(merged.value)\n setHistory(merged.value)\n setIsJobActive(false)\n return\n }\n if (status === 'failed') {\n setIsJobActive(false)\n throw new Error('Video generation failed')\n }\n }\n } catch (_) {\n // silent retry\n }\n\n attempts += 1\n if (attempts < maxAttempts && !cancelledRef.current) {\n setTimeout(poll, 1000)\n }\n }\n setTimeout(poll, 1000)\n return uploadResponse\n }\n\n throw new Error('generateUpload: Unexpected response')\n } else {\n const { errors = [] } = await uploadResponse.json()\n const errStr = errors.map((error: any) => error.message).join(', ')\n throw new Error(errStr)\n }\n })\n .catch((error) => {\n toast.error(`Failed to generate: ${error.message}`)\n console.error(\n 'Error generating or setting your upload, please set it manually if its saved in your media files.',\n error,\n )\n })\n }, [\n getData,\n locale?.code,\n instructionIdRef,\n setValue,\n field,\n documentId,\n collectionSlug,\n serverURL,\n api,\n setHistory,\n ])\n\n return {\n generateUpload,\n isJobActive,\n jobProgress,\n jobStatus,\n }\n}\n"],"names":["toast","useConfig","useDocumentInfo","useField","useForm","useLocale","useCallback","useEffect","useRef","useState","PLUGIN_AI_JOBS_TABLE","PLUGIN_API_ENDPOINT_GENERATE_UPLOAD","useFieldProps","useInstructions","mergeGeneratedValue","useHistory","useGenerateUpload","instructionIdRef","config","routes","api","serverURL","id","documentId","collectionSlug","locale","getData","set","setHistory","field","path","fieldPath","schemaPath","appendGenerated","setValue","value","currentFieldValue","appendGeneratedRef","currentFieldValueRef","jobStatus","setJobStatus","undefined","jobProgress","setJobProgress","isJobActive","setIsJobActive","cancelledRef","current","generateUpload","doc","currentInstructionId","fetch","body","JSON","stringify","code","options","instructionId","credentials","headers","method","then","uploadResponse","ok","json","job","result","hasMany","generatedValue","Array","isArray","map","r","merged","currentValue","max","maxRows","truncated","info","success","attempts","maxAttempts","poll","res","jobDoc","progress","result_id","status","valueToSet","relationTo","docRes","url","e","console","error","Promise","resolve","setTimeout","Error","_","errors","errStr","message","join","catch"],"mappings":"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"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { useForm } from '@payloadcms/ui';
|
|
2
2
|
import { useEffect, useRef } from 'react';
|
|
3
3
|
import { useFieldProps } from '../../../providers/FieldProvider/useFieldProps.js';
|
|
4
|
-
import { setSafeLexicalState } from '../../../utilities/setSafeLexicalState.js';
|
|
4
|
+
import { setSafeLexicalState } from '../../../utilities/lexical/setSafeLexicalState.js';
|
|
5
5
|
export const useStreamingUpdate = ({ editor, isLoading, object })=>{
|
|
6
|
-
const { field, path:
|
|
6
|
+
const { field, path: fieldPath } = useFieldProps();
|
|
7
7
|
const { dispatchFields } = useForm();
|
|
8
8
|
// Ref for latest object to avoid effect re-runs during high-frequency streaming
|
|
9
9
|
const objectRef = useRef(object);
|
|
@@ -23,7 +23,7 @@ export const useStreamingUpdate = ({ editor, isLoading, object })=>{
|
|
|
23
23
|
// Use dispatchFields for high-frequency streaming updates to avoid re-renders
|
|
24
24
|
dispatchFields({
|
|
25
25
|
type: 'UPDATE',
|
|
26
|
-
path:
|
|
26
|
+
path: fieldPath ?? '',
|
|
27
27
|
value: currentObject[field.name]
|
|
28
28
|
});
|
|
29
29
|
}
|
|
@@ -41,7 +41,7 @@ export const useStreamingUpdate = ({ editor, isLoading, object })=>{
|
|
|
41
41
|
editor,
|
|
42
42
|
field,
|
|
43
43
|
dispatchFields,
|
|
44
|
-
|
|
44
|
+
fieldPath
|
|
45
45
|
]);
|
|
46
46
|
};
|
|
47
47
|
|
|
@@ -1 +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:
|
|
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/lexical/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: fieldPath } = 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: fieldPath ?? '',\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, fieldPath])\n}\n"],"names":["useForm","useEffect","useRef","useFieldProps","setSafeLexicalState","useStreamingUpdate","editor","isLoading","object","field","path","fieldPath","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,oDAAmD;AAQvF,OAAO,MAAMC,qBAAqB,CAAC,EAAEC,MAAM,EAAEC,SAAS,EAAEC,MAAM,EAA4B;IACxF,MAAM,EAAEC,KAAK,EAAEC,MAAMC,SAAS,EAAE,GAAGR;IACnC,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,aAAa;wBACnBS,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;KAAU;AAC1D,EAAC"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
.wrapper {
|
|
2
|
+
background: var(--theme-elevation-50);
|
|
3
|
+
margin-bottom: 20px;
|
|
4
|
+
overflow: hidden;
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
.header {
|
|
8
|
+
align-items: center;
|
|
9
|
+
border-bottom: 1px solid var(--theme-elevation-150);
|
|
10
|
+
display: flex;
|
|
11
|
+
justify-content: space-between;
|
|
12
|
+
padding: 8px var(--gutter-h);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
.title {
|
|
16
|
+
margin: 0 0 5px 0;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.subtitle {
|
|
20
|
+
color: var(--theme-elevation-500);
|
|
21
|
+
font-size: 14px;
|
|
22
|
+
margin: 0;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.headerActions {
|
|
26
|
+
display: flex;
|
|
27
|
+
gap: 10px;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.body {
|
|
31
|
+
padding: 24px var(--gutter-h);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.bodyTitle {
|
|
35
|
+
margin-bottom: 15px;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.grid {
|
|
39
|
+
display: grid;
|
|
40
|
+
gap: 15px;
|
|
41
|
+
grid-template-columns: repeat(auto-fill, minmax(250px, 1fr));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
.toggleButton {
|
|
45
|
+
align-items: center;
|
|
46
|
+
border: 1px solid var(--theme-elevation-200);
|
|
47
|
+
border-radius: 6px;
|
|
48
|
+
background: var(--theme-elevation-50);
|
|
49
|
+
cursor: pointer;
|
|
50
|
+
display: flex;
|
|
51
|
+
gap: 10px;
|
|
52
|
+
padding: 10px 15px;
|
|
53
|
+
text-align: left;
|
|
54
|
+
transition: all 0.2s ease;
|
|
55
|
+
width: 100%;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.toggleButton[data-enabled='true'] {
|
|
59
|
+
background: var(--theme-elevation-100);
|
|
60
|
+
border-color: var(--theme-text-success);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
.toggleTrack {
|
|
64
|
+
align-items: center;
|
|
65
|
+
background: var(--theme-elevation-200);
|
|
66
|
+
border-radius: 12px;
|
|
67
|
+
display: flex;
|
|
68
|
+
height: 24px;
|
|
69
|
+
justify-content: flex-start;
|
|
70
|
+
padding: 2px;
|
|
71
|
+
transition: all 0.2s ease;
|
|
72
|
+
width: 44px;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.toggleButton[data-enabled='true'] .toggleTrack {
|
|
76
|
+
background: var(--theme-text-success);
|
|
77
|
+
justify-content: flex-end;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
.toggleKnob {
|
|
81
|
+
background: white;
|
|
82
|
+
border-radius: 50%;
|
|
83
|
+
height: 20px;
|
|
84
|
+
width: 20px;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
.toggleLabel {
|
|
88
|
+
font-weight: 500;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
.loading {
|
|
92
|
+
padding: 20px;
|
|
93
|
+
text-align: center;
|
|
94
|
+
}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
-
import { Button, toast, useConfig } from '@payloadcms/ui';
|
|
3
|
+
import { Button, toast, useConfig, useTranslation } from '@payloadcms/ui';
|
|
4
4
|
// @ts-expect-error - Next.js types are not resolving correctly with nodenext but runtime is fine
|
|
5
5
|
import { useRouter } from 'next/navigation';
|
|
6
6
|
import React, { use, useEffect, useState } from 'react';
|
|
7
7
|
import { excludeCollections } from '../../defaults.js';
|
|
8
8
|
import { InstructionsContext } from '../../providers/InstructionsProvider/context.js';
|
|
9
|
+
import styles from './configDashboard.module.css';
|
|
9
10
|
export const ConfigDashboard = ()=>{
|
|
10
11
|
const { config: { collections, routes: { admin: adminRoute, api: apiRoute } } } = useConfig();
|
|
11
12
|
const router = useRouter();
|
|
@@ -13,6 +14,7 @@ export const ConfigDashboard = ()=>{
|
|
|
13
14
|
const [enabledCollections, setEnabledCollections] = useState([]);
|
|
14
15
|
const [isLoading, setIsLoading] = useState(true);
|
|
15
16
|
const [isSaving, setIsSaving] = useState(false);
|
|
17
|
+
const { t } = useTranslation();
|
|
16
18
|
const availableCollections = collections.filter((c)=>!excludeCollections.includes(c.slug) && !c.admin?.hidden);
|
|
17
19
|
useEffect(()=>{
|
|
18
20
|
const fetchSettings = async ()=>{
|
|
@@ -20,7 +22,6 @@ export const ConfigDashboard = ()=>{
|
|
|
20
22
|
const response = await fetch(`${apiRoute}/globals/ai-providers`);
|
|
21
23
|
if (response.ok) {
|
|
22
24
|
const data = await response.json();
|
|
23
|
-
// Handle both simple array and object wrapper if Payload wraps it
|
|
24
25
|
const storedEnabled = data.enabledCollections || [];
|
|
25
26
|
setEnabledCollections(Array.isArray(storedEnabled) ? storedEnabled : []);
|
|
26
27
|
}
|
|
@@ -30,9 +31,7 @@ export const ConfigDashboard = ()=>{
|
|
|
30
31
|
setIsLoading(false);
|
|
31
32
|
}
|
|
32
33
|
};
|
|
33
|
-
fetchSettings().catch(
|
|
34
|
-
console.log(e);
|
|
35
|
-
});
|
|
34
|
+
fetchSettings().catch(console.error);
|
|
36
35
|
}, [
|
|
37
36
|
apiRoute
|
|
38
37
|
]);
|
|
@@ -50,8 +49,6 @@ export const ConfigDashboard = ()=>{
|
|
|
50
49
|
const handleSave = async ()=>{
|
|
51
50
|
setIsSaving(true);
|
|
52
51
|
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
52
|
const response = await fetch(`${apiRoute}/globals/ai-providers`, {
|
|
56
53
|
body: JSON.stringify({
|
|
57
54
|
enabledCollections
|
|
@@ -62,7 +59,7 @@ export const ConfigDashboard = ()=>{
|
|
|
62
59
|
method: 'POST'
|
|
63
60
|
});
|
|
64
61
|
if (response.ok) {
|
|
65
|
-
toast.success('
|
|
62
|
+
toast.success(t('ai-plugin:configDashboard:settingsSaved'));
|
|
66
63
|
if (setEnabledCollectionsInContext) {
|
|
67
64
|
setEnabledCollectionsInContext(enabledCollections);
|
|
68
65
|
}
|
|
@@ -71,144 +68,82 @@ export const ConfigDashboard = ()=>{
|
|
|
71
68
|
}
|
|
72
69
|
router.refresh();
|
|
73
70
|
} else {
|
|
74
|
-
toast.error('
|
|
71
|
+
toast.error(t('ai-plugin:configDashboard:failedToSave'));
|
|
75
72
|
}
|
|
76
73
|
} catch (error) {
|
|
77
74
|
console.error('Error saving settings:', error);
|
|
78
|
-
toast.error('
|
|
75
|
+
toast.error(t('ai-plugin:configDashboard:errorSaving'));
|
|
79
76
|
} finally{
|
|
80
77
|
setIsSaving(false);
|
|
81
78
|
}
|
|
82
79
|
};
|
|
83
80
|
if (isLoading) {
|
|
84
81
|
return /*#__PURE__*/ _jsx("div", {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
textAlign: 'center'
|
|
88
|
-
},
|
|
89
|
-
children: "Loading configuration..."
|
|
82
|
+
className: styles.loading,
|
|
83
|
+
children: t('ai-plugin:configDashboard:loadingConfiguration')
|
|
90
84
|
});
|
|
91
85
|
}
|
|
92
86
|
return /*#__PURE__*/ _jsxs("div", {
|
|
93
|
-
|
|
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
|
-
},
|
|
87
|
+
className: styles.wrapper,
|
|
102
88
|
children: [
|
|
103
89
|
/*#__PURE__*/ _jsxs("div", {
|
|
104
|
-
|
|
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
|
-
},
|
|
90
|
+
className: styles.header,
|
|
111
91
|
children: [
|
|
112
92
|
/*#__PURE__*/ _jsxs("div", {
|
|
113
93
|
children: [
|
|
114
94
|
/*#__PURE__*/ _jsx("h2", {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
},
|
|
118
|
-
children: "Let's configure your AI Plugin"
|
|
95
|
+
className: styles.title,
|
|
96
|
+
children: t('ai-plugin:configDashboard:configureTitle')
|
|
119
97
|
}),
|
|
120
98
|
/*#__PURE__*/ _jsx("p", {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
fontSize: '14px',
|
|
124
|
-
margin: '0'
|
|
125
|
-
},
|
|
126
|
-
children: "Set up the provider → Choose the content → Refine the behavior."
|
|
99
|
+
className: styles.subtitle,
|
|
100
|
+
children: t('ai-plugin:configDashboard:configureSubtitle')
|
|
127
101
|
})
|
|
128
102
|
]
|
|
129
103
|
}),
|
|
130
104
|
/*#__PURE__*/ _jsxs("div", {
|
|
131
|
-
|
|
132
|
-
display: 'flex',
|
|
133
|
-
gap: '10px'
|
|
134
|
-
},
|
|
105
|
+
className: styles.headerActions,
|
|
135
106
|
children: [
|
|
136
107
|
/*#__PURE__*/ _jsx(Button, {
|
|
137
108
|
buttonStyle: "secondary",
|
|
138
109
|
el: "link",
|
|
139
110
|
to: `${adminRoute}/globals/ai-providers`,
|
|
140
|
-
children:
|
|
111
|
+
children: t('ai-plugin:configDashboard:providers')
|
|
141
112
|
}),
|
|
142
113
|
/*#__PURE__*/ _jsx(Button, {
|
|
143
114
|
disabled: isSaving,
|
|
144
115
|
onClick: handleSave,
|
|
145
|
-
children: isSaving ? '
|
|
116
|
+
children: isSaving ? t('ai-plugin:configDashboard:saving') : t('ai-plugin:configDashboard:saveChanges')
|
|
146
117
|
})
|
|
147
118
|
]
|
|
148
119
|
})
|
|
149
120
|
]
|
|
150
121
|
}),
|
|
151
122
|
/*#__PURE__*/ _jsxs("div", {
|
|
152
|
-
|
|
153
|
-
padding: '24px var(--gutter-h)'
|
|
154
|
-
},
|
|
123
|
+
className: styles.body,
|
|
155
124
|
children: [
|
|
156
125
|
/*#__PURE__*/ _jsx("h5", {
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
},
|
|
160
|
-
children: "Select the collections where AI features should be available, toggle them on or off, and save your changes."
|
|
126
|
+
className: styles.bodyTitle,
|
|
127
|
+
children: t('ai-plugin:configDashboard:selectCollectionsBody')
|
|
161
128
|
}),
|
|
162
129
|
/*#__PURE__*/ _jsx("div", {
|
|
163
|
-
|
|
164
|
-
display: 'grid',
|
|
165
|
-
gap: '15px',
|
|
166
|
-
gridTemplateColumns: 'repeat(auto-fill, minmax(250px, 1fr))'
|
|
167
|
-
},
|
|
130
|
+
className: styles.grid,
|
|
168
131
|
children: availableCollections.map((collection)=>{
|
|
169
132
|
const isEnabled = enabledCollections.includes(collection.slug);
|
|
170
133
|
return /*#__PURE__*/ _jsxs("button", {
|
|
134
|
+
className: styles.toggleButton,
|
|
135
|
+
"data-enabled": isEnabled,
|
|
171
136
|
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
137
|
type: "button",
|
|
186
138
|
children: [
|
|
187
139
|
/*#__PURE__*/ _jsx("div", {
|
|
188
|
-
|
|
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
|
-
},
|
|
140
|
+
className: styles.toggleTrack,
|
|
199
141
|
children: /*#__PURE__*/ _jsx("div", {
|
|
200
|
-
|
|
201
|
-
background: 'white',
|
|
202
|
-
borderRadius: '50%',
|
|
203
|
-
height: '20px',
|
|
204
|
-
width: '20px'
|
|
205
|
-
}
|
|
142
|
+
className: styles.toggleKnob
|
|
206
143
|
})
|
|
207
144
|
}),
|
|
208
145
|
/*#__PURE__*/ _jsx("span", {
|
|
209
|
-
|
|
210
|
-
fontWeight: 500
|
|
211
|
-
},
|
|
146
|
+
className: styles.toggleLabel,
|
|
212
147
|
children: typeof collection.labels?.singular === 'string' ? collection.labels.singular : collection.labels?.singular?.en || collection.slug
|
|
213
148
|
})
|
|
214
149
|
]
|