@braze/sanity-plugin-ai-translation 0.2.53 → 0.2.55
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +162 -14
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { getPublishedId, pathToString, useClient, defineType, defineField, definePlugin } from "sanity";
|
|
2
2
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
3
3
|
import { WarningOutlineIcon, SearchIcon, CheckmarkIcon, ErrorOutlineIcon, CircleIcon, ArrowRightIcon, ResetIcon, PanelRightIcon, TranslateIcon } from "@sanity/icons";
|
|
4
|
-
import { createContext, useReducer, useEffect, useContext, useMemo, useState, useCallback } from "react";
|
|
4
|
+
import { createContext, useReducer, useRef, useEffect, useContext, useMemo, useState, useCallback } from "react";
|
|
5
5
|
import defaults from "lodash.defaults";
|
|
6
6
|
import { Card, Stack, Flex, Text, Box, Heading, Button, Spinner, Inline, Checkbox, Grid, Radio, TextInput, Badge, Select, Label, Code, Tooltip } from "@sanity/ui";
|
|
7
7
|
import { toPlainText } from "@portabletext/react";
|
|
@@ -62,7 +62,7 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
62
62
|
error: error instanceof Error ? error.message : "Network error"
|
|
63
63
|
};
|
|
64
64
|
}
|
|
65
|
-
}, activeTranslations = /* @__PURE__ */ new Map(), registerActiveTranslation = (documentId, releaseId) => {
|
|
65
|
+
}, undraftId = (id) => id.replace(/^drafts\./, ""), activeTranslations = /* @__PURE__ */ new Map(), registerActiveTranslation = (documentId, releaseId) => {
|
|
66
66
|
const entry = {
|
|
67
67
|
state: {
|
|
68
68
|
documentId,
|
|
@@ -80,7 +80,7 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
80
80
|
}, updateActiveTranslationJob = (documentId, job) => {
|
|
81
81
|
const entry = activeTranslations.get(documentId);
|
|
82
82
|
if (entry) {
|
|
83
|
-
const jobKey = `${job._id}_${job.language}`, existingJob = entry.state.translationJobs.get(jobKey), jobWithDefinedValues = Object.fromEntries(
|
|
83
|
+
const jobKey = `${undraftId(job._id)}_${job.language}`, existingJob = entry.state.translationJobs.get(jobKey), jobWithDefinedValues = Object.fromEntries(
|
|
84
84
|
Object.entries(job).filter(([_, value]) => value !== void 0)
|
|
85
85
|
), mergedJob = existingJob ? { ...existingJob, ...jobWithDefinedValues } : jobWithDefinedValues;
|
|
86
86
|
entry.state.translationJobs.set(jobKey, mergedJob), notifySubscribers(entry);
|
|
@@ -114,6 +114,7 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
114
114
|
shouldTranslateReferences: !1,
|
|
115
115
|
maxReferenceDepth: 1,
|
|
116
116
|
references: [],
|
|
117
|
+
selectedReferenceIds: /* @__PURE__ */ new Set(),
|
|
117
118
|
translationMetadata: null,
|
|
118
119
|
translationMode: "sanity-only",
|
|
119
120
|
openaiValidated: !1,
|
|
@@ -167,8 +168,18 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
167
168
|
...context,
|
|
168
169
|
references: action.payload
|
|
169
170
|
};
|
|
171
|
+
case "SET_SELECTED_REFERENCE_IDS":
|
|
172
|
+
return {
|
|
173
|
+
...context,
|
|
174
|
+
selectedReferenceIds: action.payload
|
|
175
|
+
};
|
|
170
176
|
case "SET_TRANSLATION_JOB_STATUS": {
|
|
171
|
-
|
|
177
|
+
if (!action.payload._id)
|
|
178
|
+
return devLog.warn("SET_TRANSLATION_JOB_STATUS action missing _id", {
|
|
179
|
+
...logContext,
|
|
180
|
+
payload: action.payload
|
|
181
|
+
}), context;
|
|
182
|
+
const jobKey = `${undraftId(action.payload._id)}_${action.payload.language}`, newTranslationJobs = new Map(context.translationJobs), existingJob = newTranslationJobs.get(jobKey), mergedJob = defaults(action.payload, existingJob);
|
|
172
183
|
return newTranslationJobs.set(jobKey, mergedJob), {
|
|
173
184
|
...context,
|
|
174
185
|
translationJobs: newTranslationJobs
|
|
@@ -191,6 +202,7 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
191
202
|
...context,
|
|
192
203
|
overallStatus: "idle",
|
|
193
204
|
translationJobs: /* @__PURE__ */ new Map(),
|
|
205
|
+
selectedReferenceIds: /* @__PURE__ */ new Set(),
|
|
194
206
|
// Clear any release conflicts from previous run
|
|
195
207
|
releaseConfig: {
|
|
196
208
|
...context.releaseConfig,
|
|
@@ -218,6 +230,7 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
218
230
|
shouldTranslateReferences: !1,
|
|
219
231
|
maxReferenceDepth: 1,
|
|
220
232
|
references: [],
|
|
233
|
+
selectedReferenceIds: /* @__PURE__ */ new Set(),
|
|
221
234
|
// Restore jobs from active translation if available
|
|
222
235
|
translationJobs: activeTranslation?.translationJobs ?? /* @__PURE__ */ new Map(),
|
|
223
236
|
translationMode: config?.openai?.defaultMode || "sanity-only",
|
|
@@ -233,7 +246,7 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
233
246
|
jobCount: activeTranslation.translationJobs.size,
|
|
234
247
|
component: "TranslationContextProvider"
|
|
235
248
|
});
|
|
236
|
-
const [context, dispatch] = useReducer(translationReducer, initialContext);
|
|
249
|
+
const [context, dispatch] = useReducer(translationReducer, initialContext), lastProcessedRefsRef = useRef("");
|
|
237
250
|
return useEffect(() => {
|
|
238
251
|
const handleActiveTranslationUpdate = (state) => {
|
|
239
252
|
dispatch({
|
|
@@ -273,7 +286,28 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
273
286
|
});
|
|
274
287
|
}
|
|
275
288
|
})();
|
|
276
|
-
}, [config?.openai?.apiKey, config?.openai?.enabled, config?.openai?.model]),
|
|
289
|
+
}, [config?.openai?.apiKey, config?.openai?.enabled, config?.openai?.model]), useEffect(() => {
|
|
290
|
+
const currentRefsKey = context.references.map((ref) => ref._id).sort().join(",");
|
|
291
|
+
if (currentRefsKey !== lastProcessedRefsRef.current) {
|
|
292
|
+
if (context.references.length > 0) {
|
|
293
|
+
const currentReferenceIds = new Set(context.references.map((ref) => ref._id)), previousReferenceIds = new Set(
|
|
294
|
+
lastProcessedRefsRef.current ? lastProcessedRefsRef.current.split(",") : []
|
|
295
|
+
), hasNewReferences = Array.from(currentReferenceIds).some((id) => !previousReferenceIds.has(id)), currentSelection = context.selectedReferenceIds;
|
|
296
|
+
if (currentSelection.size === 0 || hasNewReferences) {
|
|
297
|
+
const newSelection = new Set(currentSelection);
|
|
298
|
+
currentReferenceIds.forEach((id) => {
|
|
299
|
+
newSelection.add(id);
|
|
300
|
+
});
|
|
301
|
+
const currentIds = Array.from(currentSelection).sort(), newIds = Array.from(newSelection).sort();
|
|
302
|
+
(currentIds.length !== newIds.length || !currentIds.every((id, i) => id === newIds[i])) && dispatch({
|
|
303
|
+
type: "SET_SELECTED_REFERENCE_IDS",
|
|
304
|
+
payload: newSelection
|
|
305
|
+
});
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
lastProcessedRefsRef.current = currentRefsKey;
|
|
309
|
+
}
|
|
310
|
+
}, [context.references, context.selectedReferenceIds]), devLog.debug("Translation context state initialized", {
|
|
277
311
|
documentId: document._id,
|
|
278
312
|
overallStatus: context.overallStatus,
|
|
279
313
|
selectedLanguages: context.selectedTargetLanguages,
|
|
@@ -290,7 +324,7 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
290
324
|
return context;
|
|
291
325
|
}, getExistingTranslationId = (translationMetadata, targetLanguage) => translationMetadata?.translations?.length && translationMetadata.translations.find(
|
|
292
326
|
(translation) => translation._key === targetLanguage
|
|
293
|
-
)?.value._ref || null,
|
|
327
|
+
)?.value._ref || null, TRANSLATION_METADATA_TYPE = "translation.metadata", getTranslationMetadata = async ({
|
|
294
328
|
client,
|
|
295
329
|
sourceDocument,
|
|
296
330
|
sourceLanguage
|
|
@@ -2662,10 +2696,11 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2662
2696
|
overallStatus,
|
|
2663
2697
|
dispatch,
|
|
2664
2698
|
references,
|
|
2699
|
+
selectedReferenceIds,
|
|
2665
2700
|
selectedTargetLanguages,
|
|
2666
2701
|
translationMode,
|
|
2667
2702
|
releaseConfig
|
|
2668
|
-
} = useTranslationContext(), client = useClient({ apiVersion: "vX" }), [conflictContext, setConflictContext] = useState(null), [isCheckingConflicts, setIsCheckingConflicts] = useState(!1);
|
|
2703
|
+
} = useTranslationContext(), client = useClient({ apiVersion: "vX" }), [conflictContext, setConflictContext] = useState(null), [isCheckingConflicts, setIsCheckingConflicts] = useState(!1), filteredReferences = references.filter((ref) => selectedReferenceIds.has(ref._id));
|
|
2669
2704
|
useEffect(() => {
|
|
2670
2705
|
releaseConfig.mode === "new" && conflictContext && setConflictContext(null);
|
|
2671
2706
|
}, [releaseConfig.mode, conflictContext]);
|
|
@@ -2678,7 +2713,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2678
2713
|
dispatch,
|
|
2679
2714
|
languageFieldName: config.languageFieldName,
|
|
2680
2715
|
schemaId: config.schemaId,
|
|
2681
|
-
references,
|
|
2716
|
+
references: filteredReferences,
|
|
2682
2717
|
maxConcurrentTranslationJobs: config.maxConcurrentTranslationJobs,
|
|
2683
2718
|
maxReferenceDepth: config.maxReferenceDepth,
|
|
2684
2719
|
translationMode,
|
|
@@ -2704,7 +2739,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2704
2739
|
config.maxReferenceDepth,
|
|
2705
2740
|
config.openai,
|
|
2706
2741
|
config.excludeFields,
|
|
2707
|
-
|
|
2742
|
+
filteredReferences,
|
|
2708
2743
|
translationMode,
|
|
2709
2744
|
releaseConfig
|
|
2710
2745
|
]
|
|
@@ -2722,7 +2757,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2722
2757
|
sourceDocument: document,
|
|
2723
2758
|
targetLanguages: selectedTargetLanguages,
|
|
2724
2759
|
languageFieldName: config.languageFieldName,
|
|
2725
|
-
references
|
|
2760
|
+
references: filteredReferences
|
|
2726
2761
|
});
|
|
2727
2762
|
if (setIsCheckingConflicts(!1), foundConflicts.length > 0) {
|
|
2728
2763
|
setConflictContext({
|
|
@@ -2733,7 +2768,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2733
2768
|
}
|
|
2734
2769
|
}
|
|
2735
2770
|
startTranslation(!1);
|
|
2736
|
-
}, [releaseConfig, client, document, selectedTargetLanguages, config.languageFieldName, startTranslation,
|
|
2771
|
+
}, [releaseConfig, client, document, selectedTargetLanguages, config.languageFieldName, startTranslation, filteredReferences]), handleCancelConflict = useCallback(() => {
|
|
2737
2772
|
setConflictContext(null);
|
|
2738
2773
|
}, []), handleReplaceConflict = useCallback(() => {
|
|
2739
2774
|
conflictContext && startTranslation(!0, conflictContext.releaseId);
|
|
@@ -3107,8 +3142,104 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3107
3142
|
});
|
|
3108
3143
|
}
|
|
3109
3144
|
return result;
|
|
3145
|
+
}, ReferenceSelectionPanel = () => {
|
|
3146
|
+
const { references, selectedReferenceIds, dispatch } = useTranslationContext(), [typeFilter, setTypeFilter] = useState("all"), documentTypes = useMemo(() => {
|
|
3147
|
+
const types = new Set(references.map((ref) => ref._type));
|
|
3148
|
+
return Array.from(types).sort();
|
|
3149
|
+
}, [references]), filteredReferences = useMemo(() => typeFilter === "all" ? references : references.filter((ref) => ref._type === typeFilter), [references, typeFilter]), selectedCount = useMemo(() => filteredReferences.filter((ref) => selectedReferenceIds.has(ref._id)).length, [filteredReferences, selectedReferenceIds]), handleToggleReference = (referenceId) => {
|
|
3150
|
+
const newSelection = new Set(selectedReferenceIds);
|
|
3151
|
+
newSelection.has(referenceId) ? newSelection.delete(referenceId) : newSelection.add(referenceId), dispatch({
|
|
3152
|
+
type: "SET_SELECTED_REFERENCE_IDS",
|
|
3153
|
+
payload: newSelection
|
|
3154
|
+
});
|
|
3155
|
+
}, handleSelectAll = () => {
|
|
3156
|
+
const newSelection = new Set(selectedReferenceIds);
|
|
3157
|
+
filteredReferences.forEach((ref) => {
|
|
3158
|
+
newSelection.add(ref._id);
|
|
3159
|
+
}), dispatch({
|
|
3160
|
+
type: "SET_SELECTED_REFERENCE_IDS",
|
|
3161
|
+
payload: newSelection
|
|
3162
|
+
});
|
|
3163
|
+
}, handleSelectNone = () => {
|
|
3164
|
+
const newSelection = new Set(selectedReferenceIds);
|
|
3165
|
+
filteredReferences.forEach((ref) => {
|
|
3166
|
+
newSelection.delete(ref._id);
|
|
3167
|
+
}), dispatch({
|
|
3168
|
+
type: "SET_SELECTED_REFERENCE_IDS",
|
|
3169
|
+
payload: newSelection
|
|
3170
|
+
});
|
|
3171
|
+
};
|
|
3172
|
+
return references.length === 0 ? null : /* @__PURE__ */ jsx(Card, { padding: 4, border: !0, muted: !0, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
3173
|
+
/* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", gap: 2, children: [
|
|
3174
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, align: "center", children: [
|
|
3175
|
+
/* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "Select References" }),
|
|
3176
|
+
/* @__PURE__ */ jsxs(Text, { size: 1, muted: !0, children: [
|
|
3177
|
+
"(",
|
|
3178
|
+
selectedCount,
|
|
3179
|
+
" of ",
|
|
3180
|
+
filteredReferences.length,
|
|
3181
|
+
" selected)"
|
|
3182
|
+
] })
|
|
3183
|
+
] }),
|
|
3184
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
|
3185
|
+
/* @__PURE__ */ jsx(Button, { mode: "ghost", size: 1, onClick: handleSelectAll, text: "Select All" }),
|
|
3186
|
+
/* @__PURE__ */ jsx(Button, { mode: "ghost", size: 1, onClick: handleSelectNone, text: "Select None" })
|
|
3187
|
+
] })
|
|
3188
|
+
] }),
|
|
3189
|
+
documentTypes.length > 1 && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
3190
|
+
/* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Filter by type:" }),
|
|
3191
|
+
/* @__PURE__ */ jsxs(
|
|
3192
|
+
Select,
|
|
3193
|
+
{
|
|
3194
|
+
value: typeFilter,
|
|
3195
|
+
onChange: (event) => setTypeFilter(event.target.value),
|
|
3196
|
+
style: { minWidth: "150px" },
|
|
3197
|
+
children: [
|
|
3198
|
+
/* @__PURE__ */ jsxs("option", { value: "all", children: [
|
|
3199
|
+
"All types (",
|
|
3200
|
+
references.length,
|
|
3201
|
+
")"
|
|
3202
|
+
] }),
|
|
3203
|
+
documentTypes.map((type) => {
|
|
3204
|
+
const count = references.filter((ref) => ref._type === type).length;
|
|
3205
|
+
return /* @__PURE__ */ jsxs("option", { value: type, children: [
|
|
3206
|
+
type,
|
|
3207
|
+
" (",
|
|
3208
|
+
count,
|
|
3209
|
+
")"
|
|
3210
|
+
] }, type);
|
|
3211
|
+
})
|
|
3212
|
+
]
|
|
3213
|
+
}
|
|
3214
|
+
)
|
|
3215
|
+
] }),
|
|
3216
|
+
/* @__PURE__ */ jsx(Box, { style: { maxHeight: "400px", overflowY: "auto" }, children: /* @__PURE__ */ jsx(Stack, { space: 2, children: filteredReferences.length === 0 ? /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "No references match the selected filter." }) : filteredReferences.map((reference) => {
|
|
3217
|
+
const isSelected = selectedReferenceIds.has(reference._id), displayTitle = reference.title || reference._id;
|
|
3218
|
+
return /* @__PURE__ */ jsx(Card, { padding: 3, border: !0, radius: 2, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 3, children: [
|
|
3219
|
+
/* @__PURE__ */ jsx(
|
|
3220
|
+
Checkbox,
|
|
3221
|
+
{
|
|
3222
|
+
checked: isSelected,
|
|
3223
|
+
onChange: () => handleToggleReference(reference._id)
|
|
3224
|
+
}
|
|
3225
|
+
),
|
|
3226
|
+
/* @__PURE__ */ jsxs(Flex, { flex: 1, align: "center", gap: 2, children: [
|
|
3227
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: displayTitle }),
|
|
3228
|
+
/* @__PURE__ */ jsx(Badge, { tone: "primary", fontSize: 0, children: reference._type })
|
|
3229
|
+
] })
|
|
3230
|
+
] }) }, reference._id);
|
|
3231
|
+
}) }) })
|
|
3232
|
+
] }) });
|
|
3110
3233
|
}, ReferenceConfigPanel = () => {
|
|
3111
|
-
const {
|
|
3234
|
+
const {
|
|
3235
|
+
dispatch,
|
|
3236
|
+
document,
|
|
3237
|
+
shouldTranslateReferences,
|
|
3238
|
+
maxReferenceDepth,
|
|
3239
|
+
config,
|
|
3240
|
+
references,
|
|
3241
|
+
selectedReferenceIds
|
|
3242
|
+
} = useTranslationContext(), client = useClient({ apiVersion: "vX" }), [isLoadingReferences, setIsLoadingReferences] = useState(!1), [showSelectionPanel, setShowSelectionPanel] = useState(!1), maxDepth = config.maxReferenceDepth || 3;
|
|
3112
3243
|
useEffect(() => {
|
|
3113
3244
|
(async () => {
|
|
3114
3245
|
if (setIsLoadingReferences(!0), !shouldTranslateReferences) {
|
|
@@ -3178,7 +3309,24 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3178
3309
|
)
|
|
3179
3310
|
] }) : null
|
|
3180
3311
|
] }),
|
|
3181
|
-
shouldTranslateReferences ? /* @__PURE__ */
|
|
3312
|
+
shouldTranslateReferences ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3313
|
+
/* @__PURE__ */ jsxs(Flex, { padding: 2, justify: "space-between", align: "center", children: [
|
|
3314
|
+
/* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: isLoadingReferences ? "Loading references..." : references.length === 0 ? "No translatable references found." : (() => {
|
|
3315
|
+
const selectedCount = references.filter((ref) => selectedReferenceIds.has(ref._id)).length, totalCount = references.length;
|
|
3316
|
+
return selectedCount === totalCount ? `${totalCount} reference${totalCount === 1 ? "" : "s"} will be translated along with this document.` : `${selectedCount} of ${totalCount} reference${totalCount === 1 ? "" : "s"} will be translated along with this document.`;
|
|
3317
|
+
})() }),
|
|
3318
|
+
!isLoadingReferences && references.length > 0 && /* @__PURE__ */ jsx(
|
|
3319
|
+
Button,
|
|
3320
|
+
{
|
|
3321
|
+
mode: "ghost",
|
|
3322
|
+
size: 1,
|
|
3323
|
+
text: showSelectionPanel ? "Hide selection" : "Select specific references...",
|
|
3324
|
+
onClick: () => setShowSelectionPanel(!showSelectionPanel)
|
|
3325
|
+
}
|
|
3326
|
+
)
|
|
3327
|
+
] }),
|
|
3328
|
+
!isLoadingReferences && references.length > 0 && showSelectionPanel && /* @__PURE__ */ jsx(ReferenceSelectionPanel, {})
|
|
3329
|
+
] }) : null
|
|
3182
3330
|
] });
|
|
3183
3331
|
}, WriteSettingsPanel = () => /* @__PURE__ */ jsx(ReferenceConfigPanel, {}), TranslationConfigView = ({ setIsDialogOpen }) => /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
3184
3332
|
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|