@braze/sanity-plugin-ai-translation 0.2.53 → 0.2.54
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 +157 -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,13 @@ 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
|
-
const jobKey = `${action.payload._id}_${action.payload.language}`, newTranslationJobs = new Map(context.translationJobs), existingJob = newTranslationJobs.get(jobKey), mergedJob = defaults(action.payload, existingJob);
|
|
177
|
+
const jobKey = `${undraftId(action.payload._id)}_${action.payload.language}`, newTranslationJobs = new Map(context.translationJobs), existingJob = newTranslationJobs.get(jobKey), mergedJob = defaults(action.payload, existingJob);
|
|
172
178
|
return newTranslationJobs.set(jobKey, mergedJob), {
|
|
173
179
|
...context,
|
|
174
180
|
translationJobs: newTranslationJobs
|
|
@@ -191,6 +197,7 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
191
197
|
...context,
|
|
192
198
|
overallStatus: "idle",
|
|
193
199
|
translationJobs: /* @__PURE__ */ new Map(),
|
|
200
|
+
selectedReferenceIds: /* @__PURE__ */ new Set(),
|
|
194
201
|
// Clear any release conflicts from previous run
|
|
195
202
|
releaseConfig: {
|
|
196
203
|
...context.releaseConfig,
|
|
@@ -218,6 +225,7 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
218
225
|
shouldTranslateReferences: !1,
|
|
219
226
|
maxReferenceDepth: 1,
|
|
220
227
|
references: [],
|
|
228
|
+
selectedReferenceIds: /* @__PURE__ */ new Set(),
|
|
221
229
|
// Restore jobs from active translation if available
|
|
222
230
|
translationJobs: activeTranslation?.translationJobs ?? /* @__PURE__ */ new Map(),
|
|
223
231
|
translationMode: config?.openai?.defaultMode || "sanity-only",
|
|
@@ -233,7 +241,7 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
233
241
|
jobCount: activeTranslation.translationJobs.size,
|
|
234
242
|
component: "TranslationContextProvider"
|
|
235
243
|
});
|
|
236
|
-
const [context, dispatch] = useReducer(translationReducer, initialContext);
|
|
244
|
+
const [context, dispatch] = useReducer(translationReducer, initialContext), lastProcessedRefsRef = useRef("");
|
|
237
245
|
return useEffect(() => {
|
|
238
246
|
const handleActiveTranslationUpdate = (state) => {
|
|
239
247
|
dispatch({
|
|
@@ -273,7 +281,28 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
273
281
|
});
|
|
274
282
|
}
|
|
275
283
|
})();
|
|
276
|
-
}, [config?.openai?.apiKey, config?.openai?.enabled, config?.openai?.model]),
|
|
284
|
+
}, [config?.openai?.apiKey, config?.openai?.enabled, config?.openai?.model]), useEffect(() => {
|
|
285
|
+
const currentRefsKey = context.references.map((ref) => ref._id).sort().join(",");
|
|
286
|
+
if (currentRefsKey !== lastProcessedRefsRef.current) {
|
|
287
|
+
if (context.references.length > 0) {
|
|
288
|
+
const currentReferenceIds = new Set(context.references.map((ref) => ref._id)), previousReferenceIds = new Set(
|
|
289
|
+
lastProcessedRefsRef.current ? lastProcessedRefsRef.current.split(",") : []
|
|
290
|
+
), hasNewReferences = Array.from(currentReferenceIds).some((id) => !previousReferenceIds.has(id)), currentSelection = context.selectedReferenceIds;
|
|
291
|
+
if (currentSelection.size === 0 || hasNewReferences) {
|
|
292
|
+
const newSelection = new Set(currentSelection);
|
|
293
|
+
currentReferenceIds.forEach((id) => {
|
|
294
|
+
newSelection.add(id);
|
|
295
|
+
});
|
|
296
|
+
const currentIds = Array.from(currentSelection).sort(), newIds = Array.from(newSelection).sort();
|
|
297
|
+
(currentIds.length !== newIds.length || !currentIds.every((id, i) => id === newIds[i])) && dispatch({
|
|
298
|
+
type: "SET_SELECTED_REFERENCE_IDS",
|
|
299
|
+
payload: newSelection
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
}
|
|
303
|
+
lastProcessedRefsRef.current = currentRefsKey;
|
|
304
|
+
}
|
|
305
|
+
}, [context.references, context.selectedReferenceIds]), devLog.debug("Translation context state initialized", {
|
|
277
306
|
documentId: document._id,
|
|
278
307
|
overallStatus: context.overallStatus,
|
|
279
308
|
selectedLanguages: context.selectedTargetLanguages,
|
|
@@ -290,7 +319,7 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
290
319
|
return context;
|
|
291
320
|
}, getExistingTranslationId = (translationMetadata, targetLanguage) => translationMetadata?.translations?.length && translationMetadata.translations.find(
|
|
292
321
|
(translation) => translation._key === targetLanguage
|
|
293
|
-
)?.value._ref || null,
|
|
322
|
+
)?.value._ref || null, TRANSLATION_METADATA_TYPE = "translation.metadata", getTranslationMetadata = async ({
|
|
294
323
|
client,
|
|
295
324
|
sourceDocument,
|
|
296
325
|
sourceLanguage
|
|
@@ -2662,10 +2691,11 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2662
2691
|
overallStatus,
|
|
2663
2692
|
dispatch,
|
|
2664
2693
|
references,
|
|
2694
|
+
selectedReferenceIds,
|
|
2665
2695
|
selectedTargetLanguages,
|
|
2666
2696
|
translationMode,
|
|
2667
2697
|
releaseConfig
|
|
2668
|
-
} = useTranslationContext(), client = useClient({ apiVersion: "vX" }), [conflictContext, setConflictContext] = useState(null), [isCheckingConflicts, setIsCheckingConflicts] = useState(!1);
|
|
2698
|
+
} = useTranslationContext(), client = useClient({ apiVersion: "vX" }), [conflictContext, setConflictContext] = useState(null), [isCheckingConflicts, setIsCheckingConflicts] = useState(!1), filteredReferences = references.filter((ref) => selectedReferenceIds.has(ref._id));
|
|
2669
2699
|
useEffect(() => {
|
|
2670
2700
|
releaseConfig.mode === "new" && conflictContext && setConflictContext(null);
|
|
2671
2701
|
}, [releaseConfig.mode, conflictContext]);
|
|
@@ -2678,7 +2708,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2678
2708
|
dispatch,
|
|
2679
2709
|
languageFieldName: config.languageFieldName,
|
|
2680
2710
|
schemaId: config.schemaId,
|
|
2681
|
-
references,
|
|
2711
|
+
references: filteredReferences,
|
|
2682
2712
|
maxConcurrentTranslationJobs: config.maxConcurrentTranslationJobs,
|
|
2683
2713
|
maxReferenceDepth: config.maxReferenceDepth,
|
|
2684
2714
|
translationMode,
|
|
@@ -2704,7 +2734,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2704
2734
|
config.maxReferenceDepth,
|
|
2705
2735
|
config.openai,
|
|
2706
2736
|
config.excludeFields,
|
|
2707
|
-
|
|
2737
|
+
filteredReferences,
|
|
2708
2738
|
translationMode,
|
|
2709
2739
|
releaseConfig
|
|
2710
2740
|
]
|
|
@@ -2722,7 +2752,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2722
2752
|
sourceDocument: document,
|
|
2723
2753
|
targetLanguages: selectedTargetLanguages,
|
|
2724
2754
|
languageFieldName: config.languageFieldName,
|
|
2725
|
-
references
|
|
2755
|
+
references: filteredReferences
|
|
2726
2756
|
});
|
|
2727
2757
|
if (setIsCheckingConflicts(!1), foundConflicts.length > 0) {
|
|
2728
2758
|
setConflictContext({
|
|
@@ -2733,7 +2763,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
2733
2763
|
}
|
|
2734
2764
|
}
|
|
2735
2765
|
startTranslation(!1);
|
|
2736
|
-
}, [releaseConfig, client, document, selectedTargetLanguages, config.languageFieldName, startTranslation,
|
|
2766
|
+
}, [releaseConfig, client, document, selectedTargetLanguages, config.languageFieldName, startTranslation, filteredReferences]), handleCancelConflict = useCallback(() => {
|
|
2737
2767
|
setConflictContext(null);
|
|
2738
2768
|
}, []), handleReplaceConflict = useCallback(() => {
|
|
2739
2769
|
conflictContext && startTranslation(!0, conflictContext.releaseId);
|
|
@@ -3107,8 +3137,104 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3107
3137
|
});
|
|
3108
3138
|
}
|
|
3109
3139
|
return result;
|
|
3140
|
+
}, ReferenceSelectionPanel = () => {
|
|
3141
|
+
const { references, selectedReferenceIds, dispatch } = useTranslationContext(), [typeFilter, setTypeFilter] = useState("all"), documentTypes = useMemo(() => {
|
|
3142
|
+
const types = new Set(references.map((ref) => ref._type));
|
|
3143
|
+
return Array.from(types).sort();
|
|
3144
|
+
}, [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) => {
|
|
3145
|
+
const newSelection = new Set(selectedReferenceIds);
|
|
3146
|
+
newSelection.has(referenceId) ? newSelection.delete(referenceId) : newSelection.add(referenceId), dispatch({
|
|
3147
|
+
type: "SET_SELECTED_REFERENCE_IDS",
|
|
3148
|
+
payload: newSelection
|
|
3149
|
+
});
|
|
3150
|
+
}, handleSelectAll = () => {
|
|
3151
|
+
const newSelection = new Set(selectedReferenceIds);
|
|
3152
|
+
filteredReferences.forEach((ref) => {
|
|
3153
|
+
newSelection.add(ref._id);
|
|
3154
|
+
}), dispatch({
|
|
3155
|
+
type: "SET_SELECTED_REFERENCE_IDS",
|
|
3156
|
+
payload: newSelection
|
|
3157
|
+
});
|
|
3158
|
+
}, handleSelectNone = () => {
|
|
3159
|
+
const newSelection = new Set(selectedReferenceIds);
|
|
3160
|
+
filteredReferences.forEach((ref) => {
|
|
3161
|
+
newSelection.delete(ref._id);
|
|
3162
|
+
}), dispatch({
|
|
3163
|
+
type: "SET_SELECTED_REFERENCE_IDS",
|
|
3164
|
+
payload: newSelection
|
|
3165
|
+
});
|
|
3166
|
+
};
|
|
3167
|
+
return references.length === 0 ? null : /* @__PURE__ */ jsx(Card, { padding: 4, border: !0, muted: !0, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
3168
|
+
/* @__PURE__ */ jsxs(Flex, { justify: "space-between", align: "center", gap: 2, children: [
|
|
3169
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, align: "center", children: [
|
|
3170
|
+
/* @__PURE__ */ jsx(Text, { size: 1, weight: "semibold", children: "Select References" }),
|
|
3171
|
+
/* @__PURE__ */ jsxs(Text, { size: 1, muted: !0, children: [
|
|
3172
|
+
"(",
|
|
3173
|
+
selectedCount,
|
|
3174
|
+
" of ",
|
|
3175
|
+
filteredReferences.length,
|
|
3176
|
+
" selected)"
|
|
3177
|
+
] })
|
|
3178
|
+
] }),
|
|
3179
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, children: [
|
|
3180
|
+
/* @__PURE__ */ jsx(Button, { mode: "ghost", size: 1, onClick: handleSelectAll, text: "Select All" }),
|
|
3181
|
+
/* @__PURE__ */ jsx(Button, { mode: "ghost", size: 1, onClick: handleSelectNone, text: "Select None" })
|
|
3182
|
+
] })
|
|
3183
|
+
] }),
|
|
3184
|
+
documentTypes.length > 1 && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
3185
|
+
/* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Filter by type:" }),
|
|
3186
|
+
/* @__PURE__ */ jsxs(
|
|
3187
|
+
Select,
|
|
3188
|
+
{
|
|
3189
|
+
value: typeFilter,
|
|
3190
|
+
onChange: (event) => setTypeFilter(event.target.value),
|
|
3191
|
+
style: { minWidth: "150px" },
|
|
3192
|
+
children: [
|
|
3193
|
+
/* @__PURE__ */ jsxs("option", { value: "all", children: [
|
|
3194
|
+
"All types (",
|
|
3195
|
+
references.length,
|
|
3196
|
+
")"
|
|
3197
|
+
] }),
|
|
3198
|
+
documentTypes.map((type) => {
|
|
3199
|
+
const count = references.filter((ref) => ref._type === type).length;
|
|
3200
|
+
return /* @__PURE__ */ jsxs("option", { value: type, children: [
|
|
3201
|
+
type,
|
|
3202
|
+
" (",
|
|
3203
|
+
count,
|
|
3204
|
+
")"
|
|
3205
|
+
] }, type);
|
|
3206
|
+
})
|
|
3207
|
+
]
|
|
3208
|
+
}
|
|
3209
|
+
)
|
|
3210
|
+
] }),
|
|
3211
|
+
/* @__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) => {
|
|
3212
|
+
const isSelected = selectedReferenceIds.has(reference._id), displayTitle = reference.title || reference._id;
|
|
3213
|
+
return /* @__PURE__ */ jsx(Card, { padding: 3, border: !0, radius: 2, children: /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 3, children: [
|
|
3214
|
+
/* @__PURE__ */ jsx(
|
|
3215
|
+
Checkbox,
|
|
3216
|
+
{
|
|
3217
|
+
checked: isSelected,
|
|
3218
|
+
onChange: () => handleToggleReference(reference._id)
|
|
3219
|
+
}
|
|
3220
|
+
),
|
|
3221
|
+
/* @__PURE__ */ jsxs(Flex, { flex: 1, align: "center", gap: 2, children: [
|
|
3222
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: displayTitle }),
|
|
3223
|
+
/* @__PURE__ */ jsx(Badge, { tone: "primary", fontSize: 0, children: reference._type })
|
|
3224
|
+
] })
|
|
3225
|
+
] }) }, reference._id);
|
|
3226
|
+
}) }) })
|
|
3227
|
+
] }) });
|
|
3110
3228
|
}, ReferenceConfigPanel = () => {
|
|
3111
|
-
const {
|
|
3229
|
+
const {
|
|
3230
|
+
dispatch,
|
|
3231
|
+
document,
|
|
3232
|
+
shouldTranslateReferences,
|
|
3233
|
+
maxReferenceDepth,
|
|
3234
|
+
config,
|
|
3235
|
+
references,
|
|
3236
|
+
selectedReferenceIds
|
|
3237
|
+
} = useTranslationContext(), client = useClient({ apiVersion: "vX" }), [isLoadingReferences, setIsLoadingReferences] = useState(!1), [showSelectionPanel, setShowSelectionPanel] = useState(!1), maxDepth = config.maxReferenceDepth || 3;
|
|
3112
3238
|
useEffect(() => {
|
|
3113
3239
|
(async () => {
|
|
3114
3240
|
if (setIsLoadingReferences(!0), !shouldTranslateReferences) {
|
|
@@ -3178,7 +3304,24 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3178
3304
|
)
|
|
3179
3305
|
] }) : null
|
|
3180
3306
|
] }),
|
|
3181
|
-
shouldTranslateReferences ? /* @__PURE__ */
|
|
3307
|
+
shouldTranslateReferences ? /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3308
|
+
/* @__PURE__ */ jsxs(Flex, { padding: 2, justify: "space-between", align: "center", children: [
|
|
3309
|
+
/* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: isLoadingReferences ? "Loading references..." : references.length === 0 ? "No translatable references found." : (() => {
|
|
3310
|
+
const selectedCount = references.filter((ref) => selectedReferenceIds.has(ref._id)).length, totalCount = references.length;
|
|
3311
|
+
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.`;
|
|
3312
|
+
})() }),
|
|
3313
|
+
!isLoadingReferences && references.length > 0 && /* @__PURE__ */ jsx(
|
|
3314
|
+
Button,
|
|
3315
|
+
{
|
|
3316
|
+
mode: "ghost",
|
|
3317
|
+
size: 1,
|
|
3318
|
+
text: showSelectionPanel ? "Hide selection" : "Select specific references...",
|
|
3319
|
+
onClick: () => setShowSelectionPanel(!showSelectionPanel)
|
|
3320
|
+
}
|
|
3321
|
+
)
|
|
3322
|
+
] }),
|
|
3323
|
+
!isLoadingReferences && references.length > 0 && showSelectionPanel && /* @__PURE__ */ jsx(ReferenceSelectionPanel, {})
|
|
3324
|
+
] }) : null
|
|
3182
3325
|
] });
|
|
3183
3326
|
}, WriteSettingsPanel = () => /* @__PURE__ */ jsx(ReferenceConfigPanel, {}), TranslationConfigView = ({ setIsDialogOpen }) => /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
3184
3327
|
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|