@braze/sanity-plugin-ai-translation 0.2.77 → 0.2.79
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 +517 -198
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { getPublishedId, pathToString, useClient, useValidationStatus, defineType, defineField, definePlugin } from "sanity";
|
|
2
2
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
3
|
-
import { WarningOutlineIcon,
|
|
3
|
+
import { WarningOutlineIcon, ErrorOutlineIcon, CheckmarkIcon, CloseIcon, PanelRightIcon, SyncIcon, SearchIcon, CircleIcon, ArrowRightIcon, ResetIcon, TranslateIcon } from "@sanity/icons";
|
|
4
4
|
import { createContext, useReducer, useRef, useEffect, useContext, useMemo, useState, useCallback } from "react";
|
|
5
5
|
import defaults from "lodash.defaults";
|
|
6
|
-
import { Card, Stack, Flex, Text, Box, Heading, Button, Spinner, Inline, Checkbox, Grid,
|
|
6
|
+
import { Card, Stack, Flex, Text, Box, Heading, Button, Spinner, Badge, Inline, Radio, Checkbox, Grid, TextInput, Select, Label, Code, Tooltip } from "@sanity/ui";
|
|
7
|
+
import { IntentLink } from "sanity/router";
|
|
8
|
+
import { useOpenInNewPane, useListeningQuery } from "sanity-plugin-utils";
|
|
7
9
|
import { toPlainText } from "@portabletext/react";
|
|
8
10
|
import { uuid } from "@sanity/uuid";
|
|
9
11
|
import cloneDeep from "lodash.clonedeep";
|
|
10
12
|
import get from "lodash.get";
|
|
11
13
|
import set from "lodash.set";
|
|
12
|
-
import { useListeningQuery, useOpenInNewPane } from "sanity-plugin-utils";
|
|
13
|
-
import { IntentLink } from "sanity/router";
|
|
14
14
|
const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLATION_PLUGIN_LOGGING === "true" || process.env.SANITY_STUDIO_AI_TRANSLATION_PLUGIN_LOGGING === "true", devLog = {
|
|
15
15
|
info: (message, context) => {
|
|
16
16
|
isLoggingEnabled() && console.info("[AI Translation]", message, context ? JSON.stringify(context, null, 2) : "");
|
|
@@ -123,6 +123,9 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
123
123
|
mode: "new",
|
|
124
124
|
newReleaseTitle: ""
|
|
125
125
|
},
|
|
126
|
+
hasDraft: !1,
|
|
127
|
+
hasPublished: !1,
|
|
128
|
+
documentSource: "draft",
|
|
126
129
|
reconcilingStatus: "idle",
|
|
127
130
|
reconciliationProgress: void 0,
|
|
128
131
|
dispatch: () => {
|
|
@@ -229,10 +232,21 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
229
232
|
...context,
|
|
230
233
|
reconciliationProgress: action.payload
|
|
231
234
|
};
|
|
235
|
+
case "SET_DOCUMENT_SOURCE":
|
|
236
|
+
return {
|
|
237
|
+
...context,
|
|
238
|
+
documentSource: action.payload
|
|
239
|
+
};
|
|
232
240
|
default:
|
|
233
241
|
return context;
|
|
234
242
|
}
|
|
235
|
-
}, generateDefaultReleaseTitle = (document) => `[AI Translation] ${document.title || document.name || document._id.split("-").slice(0, 2).join("-")}`, TranslationContextProvider = ({
|
|
243
|
+
}, generateDefaultReleaseTitle = (document) => `[AI Translation] ${document.title || document.name || document._id.split("-").slice(0, 2).join("-")}`, TranslationContextProvider = ({
|
|
244
|
+
document,
|
|
245
|
+
config,
|
|
246
|
+
hasDraft,
|
|
247
|
+
hasPublished,
|
|
248
|
+
children
|
|
249
|
+
}) => {
|
|
236
250
|
devLog.debug("TranslationContextProvider initialized", {
|
|
237
251
|
documentId: document._id,
|
|
238
252
|
documentType: document._type,
|
|
@@ -258,6 +272,9 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
258
272
|
mode: "new",
|
|
259
273
|
newReleaseTitle: defaultReleaseTitle
|
|
260
274
|
},
|
|
275
|
+
hasDraft,
|
|
276
|
+
hasPublished,
|
|
277
|
+
documentSource: "draft",
|
|
261
278
|
// Reconciliation state for existing releases
|
|
262
279
|
reconcilingStatus: "idle",
|
|
263
280
|
reconciliationProgress: void 0
|
|
@@ -344,9 +361,81 @@ const isLoggingEnabled = () => process.env.NEXT_PUBLIC_SANITY_STUDIO_AI_TRANSLAT
|
|
|
344
361
|
"useTranslationContext must be used within a TranslationContextProvider with document and config props"
|
|
345
362
|
);
|
|
346
363
|
return context;
|
|
364
|
+
}, checkSourceDrafts = async ({
|
|
365
|
+
client,
|
|
366
|
+
referenceIds
|
|
367
|
+
}) => {
|
|
368
|
+
if (referenceIds.length === 0)
|
|
369
|
+
return [];
|
|
370
|
+
const publishedIds = referenceIds.map((id) => getPublishedId(id)), draftIds = publishedIds.map((id) => `drafts.${id}`);
|
|
371
|
+
devLog.debug("Checking for unpublished changes on source references", {
|
|
372
|
+
referenceCount: publishedIds.length
|
|
373
|
+
});
|
|
374
|
+
const drafts = await client.fetch(
|
|
375
|
+
"*[_id in $draftIds]{ _id, _type, title, name }",
|
|
376
|
+
{ draftIds }
|
|
377
|
+
);
|
|
378
|
+
if (drafts.length === 0)
|
|
379
|
+
return devLog.debug("No source references have unpublished changes"), [];
|
|
380
|
+
const results = drafts.map((d) => ({
|
|
381
|
+
publishedId: getPublishedId(d._id),
|
|
382
|
+
_type: d._type,
|
|
383
|
+
title: d.title || d.name
|
|
384
|
+
}));
|
|
385
|
+
return devLog.debug("Source references with unpublished changes", {
|
|
386
|
+
count: results.length
|
|
387
|
+
}), results;
|
|
347
388
|
}, getExistingTranslationId = (translationMetadata, targetLanguage) => translationMetadata?.translations?.length && translationMetadata.translations.find(
|
|
348
389
|
(translation) => translation._key === targetLanguage
|
|
349
|
-
)?.value._ref || null,
|
|
390
|
+
)?.value._ref || null, checkTargetDrafts = async ({
|
|
391
|
+
client,
|
|
392
|
+
translationMetadata,
|
|
393
|
+
selectedTargetLanguages,
|
|
394
|
+
sourceDocumentId
|
|
395
|
+
}) => {
|
|
396
|
+
if (!translationMetadata?.translations?.length)
|
|
397
|
+
return devLog.debug("No translation metadata \u2014 skipping draft check", {
|
|
398
|
+
sourceDocumentId
|
|
399
|
+
}), [];
|
|
400
|
+
const targetEntries = [];
|
|
401
|
+
for (const lang of selectedTargetLanguages) {
|
|
402
|
+
const targetId = getExistingTranslationId(translationMetadata, lang);
|
|
403
|
+
targetId && targetEntries.push({ targetId, targetLanguage: lang });
|
|
404
|
+
}
|
|
405
|
+
if (targetEntries.length === 0)
|
|
406
|
+
return devLog.debug("No existing translations found for selected languages", {
|
|
407
|
+
sourceDocumentId,
|
|
408
|
+
selectedTargetLanguages
|
|
409
|
+
}), [];
|
|
410
|
+
const draftIds = targetEntries.map((e) => `drafts.${e.targetId}`);
|
|
411
|
+
devLog.debug("Checking for stale drafts on target documents", {
|
|
412
|
+
sourceDocumentId,
|
|
413
|
+
draftIdsToCheck: draftIds.length
|
|
414
|
+
});
|
|
415
|
+
const drafts = await client.fetch(
|
|
416
|
+
"*[_id in $draftIds]{ _id, _type, title, name }",
|
|
417
|
+
{ draftIds }
|
|
418
|
+
);
|
|
419
|
+
if (drafts.length === 0)
|
|
420
|
+
return devLog.debug("No stale drafts found", { sourceDocumentId }), [];
|
|
421
|
+
const draftMap = new Map(drafts.map((d) => [d._id, d])), results = [];
|
|
422
|
+
for (const entry of targetEntries) {
|
|
423
|
+
const draftId = `drafts.${entry.targetId}`, draft = draftMap.get(draftId);
|
|
424
|
+
draft && results.push({
|
|
425
|
+
targetId: entry.targetId,
|
|
426
|
+
draftId,
|
|
427
|
+
_type: draft._type,
|
|
428
|
+
title: draft.title || draft.name,
|
|
429
|
+
sourceDocumentId,
|
|
430
|
+
targetLanguage: entry.targetLanguage
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
return devLog.info("Stale drafts detected on target documents", {
|
|
434
|
+
sourceDocumentId,
|
|
435
|
+
staleDraftCount: results.length,
|
|
436
|
+
affectedLanguages: results.map((r) => r.targetLanguage)
|
|
437
|
+
}), results;
|
|
438
|
+
}, TRANSLATION_METADATA_TYPE = "translation.metadata", getTranslationMetadata = async ({
|
|
350
439
|
client,
|
|
351
440
|
sourceDocument,
|
|
352
441
|
sourceLanguage
|
|
@@ -3001,6 +3090,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3001
3090
|
excludeFields,
|
|
3002
3091
|
unsetFields,
|
|
3003
3092
|
releaseConfig,
|
|
3093
|
+
sourcePerspective,
|
|
3004
3094
|
telemetryConfig
|
|
3005
3095
|
}) => {
|
|
3006
3096
|
const batchStartTime = Date.now(), logContext = {
|
|
@@ -3104,7 +3194,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3104
3194
|
try {
|
|
3105
3195
|
await translationSemaphore.withPermit(async () => {
|
|
3106
3196
|
const document = await client.withConfig({
|
|
3107
|
-
perspective: "drafts"
|
|
3197
|
+
perspective: sourcePerspective ?? "drafts"
|
|
3108
3198
|
}).getDocument(documentId);
|
|
3109
3199
|
if (document || devLog.error("\u274C SOURCE DOCUMENT NOT FOUND", { documentId }), document && releaseId) {
|
|
3110
3200
|
const versionedTargetDocumentId = await translateDocument({
|
|
@@ -3275,24 +3365,187 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3275
3365
|
] })
|
|
3276
3366
|
] })
|
|
3277
3367
|
] }) });
|
|
3278
|
-
},
|
|
3368
|
+
}, DocumentOpenerButton = ({ documentId, documentType }) => {
|
|
3369
|
+
const publishedId = getPublishedId(documentId), openInNewPane = useOpenInNewPane(publishedId, documentType);
|
|
3370
|
+
return /* @__PURE__ */ jsx(
|
|
3371
|
+
Button,
|
|
3372
|
+
{
|
|
3373
|
+
mode: "bleed",
|
|
3374
|
+
icon: PanelRightIcon,
|
|
3375
|
+
onClick: () => openInNewPane(),
|
|
3376
|
+
"aria-label": "Open document",
|
|
3377
|
+
fontSize: 1,
|
|
3378
|
+
padding: 2
|
|
3379
|
+
}
|
|
3380
|
+
);
|
|
3381
|
+
}, VALIDATION_TIMEOUT_MS = 2e3, DocumentValidator = ({ documentId, documentType, onResult }) => {
|
|
3382
|
+
const publishedId = getPublishedId(documentId), { isValidating, validation } = useValidationStatus(publishedId, documentType), hasReceivedRealResult = useRef(!1), [timedOut, setTimedOut] = useState(!1);
|
|
3383
|
+
return useEffect(() => {
|
|
3384
|
+
const timer = setTimeout(() => setTimedOut(!0), VALIDATION_TIMEOUT_MS);
|
|
3385
|
+
return () => clearTimeout(timer);
|
|
3386
|
+
}, []), useEffect(() => {
|
|
3387
|
+
(isValidating || validation.length > 0) && (hasReceivedRealResult.current = !0);
|
|
3388
|
+
const stillWaitingForFirstResult = !hasReceivedRealResult.current && !timedOut, errors = validation.filter((v) => v.level === "error");
|
|
3389
|
+
onResult(documentId, {
|
|
3390
|
+
isValidating: isValidating || stillWaitingForFirstResult,
|
|
3391
|
+
errors
|
|
3392
|
+
});
|
|
3393
|
+
}, [isValidating, validation, documentId, onResult, timedOut]), null;
|
|
3394
|
+
}, PreflightView = () => {
|
|
3279
3395
|
const {
|
|
3280
3396
|
document,
|
|
3281
3397
|
config,
|
|
3282
|
-
overallStatus,
|
|
3283
3398
|
dispatch,
|
|
3284
3399
|
references,
|
|
3285
3400
|
selectedReferenceIds,
|
|
3286
3401
|
selectedTargetLanguages,
|
|
3402
|
+
shouldTranslateReferences,
|
|
3403
|
+
translationMetadata,
|
|
3287
3404
|
translationMode,
|
|
3288
|
-
releaseConfig
|
|
3289
|
-
|
|
3405
|
+
releaseConfig,
|
|
3406
|
+
documentSource
|
|
3407
|
+
} = useTranslationContext(), client = useClient({ apiVersion: "vX" }), [validationResults, setValidationResults] = useState(/* @__PURE__ */ new Map()), [sourceRefsWithDrafts, setSourceRefsWithDrafts] = useState([]), [isSourceDraftCheckLoading, setIsSourceDraftCheckLoading] = useState(!0), [staleDrafts, setStaleDrafts] = useState([]), [isDraftCheckLoading, setIsDraftCheckLoading] = useState(!0), [draftAction, setDraftAction] = useState("none"), [isDraftActionInProgress, setIsDraftActionInProgress] = useState(!1), [conflictContext, setConflictContext] = useState(null), [isCheckingConflicts, setIsCheckingConflicts] = useState(!0), filteredReferences = references.filter((ref) => selectedReferenceIds.has(ref._id)), documentsToValidate = useMemo(() => {
|
|
3408
|
+
const docs = [
|
|
3409
|
+
{
|
|
3410
|
+
_id: document._id,
|
|
3411
|
+
_type: document._type,
|
|
3412
|
+
title: document.title || document.name || document._id
|
|
3413
|
+
}
|
|
3414
|
+
];
|
|
3415
|
+
if (shouldTranslateReferences)
|
|
3416
|
+
for (const ref of references)
|
|
3417
|
+
selectedReferenceIds.has(ref._id) && docs.push(ref);
|
|
3418
|
+
return docs;
|
|
3419
|
+
}, [document, references, selectedReferenceIds, shouldTranslateReferences]), handleValidationResult = useCallback((id, result) => {
|
|
3420
|
+
setValidationResults((prev) => {
|
|
3421
|
+
const next = new Map(prev);
|
|
3422
|
+
return next.set(id, result), next;
|
|
3423
|
+
});
|
|
3424
|
+
}, []), { hasValidationErrors, someStillValidating, documentsWithErrors } = useMemo(() => {
|
|
3425
|
+
const allValidated = documentsToValidate.every((doc) => validationResults.has(doc._id)), validating = [...validationResults.values()].some((r) => r.isValidating) || !allValidated, docsWithErrors = [];
|
|
3426
|
+
for (const doc of documentsToValidate) {
|
|
3427
|
+
const result = validationResults.get(doc._id);
|
|
3428
|
+
result && result.errors.length > 0 && docsWithErrors.push({ ...doc, errors: result.errors });
|
|
3429
|
+
}
|
|
3430
|
+
return {
|
|
3431
|
+
hasValidationErrors: docsWithErrors.length > 0,
|
|
3432
|
+
someStillValidating: validating,
|
|
3433
|
+
documentsWithErrors: docsWithErrors
|
|
3434
|
+
};
|
|
3435
|
+
}, [documentsToValidate, validationResults]), runSourceDraftCheck = useCallback(async () => {
|
|
3436
|
+
if (filteredReferences.length === 0) {
|
|
3437
|
+
setIsSourceDraftCheckLoading(!1);
|
|
3438
|
+
return;
|
|
3439
|
+
}
|
|
3440
|
+
setIsSourceDraftCheckLoading(!0);
|
|
3441
|
+
try {
|
|
3442
|
+
const results = await checkSourceDrafts({
|
|
3443
|
+
client,
|
|
3444
|
+
referenceIds: filteredReferences.map((ref) => ref._id)
|
|
3445
|
+
});
|
|
3446
|
+
setSourceRefsWithDrafts(results);
|
|
3447
|
+
} catch (error) {
|
|
3448
|
+
devLog.error(
|
|
3449
|
+
"Failed to check source reference drafts",
|
|
3450
|
+
error instanceof Error ? error : new Error(String(error)),
|
|
3451
|
+
{ component: "PreflightView" }
|
|
3452
|
+
);
|
|
3453
|
+
} finally {
|
|
3454
|
+
setIsSourceDraftCheckLoading(!1);
|
|
3455
|
+
}
|
|
3456
|
+
}, [client, filteredReferences]), runDraftCheck = useCallback(async () => {
|
|
3457
|
+
setIsDraftCheckLoading(!0);
|
|
3458
|
+
try {
|
|
3459
|
+
const drafts = await checkTargetDrafts({
|
|
3460
|
+
client,
|
|
3461
|
+
translationMetadata,
|
|
3462
|
+
selectedTargetLanguages,
|
|
3463
|
+
sourceDocumentId: document._id
|
|
3464
|
+
});
|
|
3465
|
+
setStaleDrafts(drafts), drafts.length === 0 && setDraftAction("none");
|
|
3466
|
+
} catch (error) {
|
|
3467
|
+
devLog.error("Failed to check target drafts", error instanceof Error ? error : new Error(String(error)), {
|
|
3468
|
+
sourceDocumentId: document._id,
|
|
3469
|
+
component: "PreflightView"
|
|
3470
|
+
});
|
|
3471
|
+
} finally {
|
|
3472
|
+
setIsDraftCheckLoading(!1);
|
|
3473
|
+
}
|
|
3474
|
+
}, [client, translationMetadata, selectedTargetLanguages, document._id]), runConflictCheck = useCallback(async () => {
|
|
3475
|
+
if (releaseConfig.mode === "new") {
|
|
3476
|
+
setIsCheckingConflicts(!1), setConflictContext(null);
|
|
3477
|
+
return;
|
|
3478
|
+
}
|
|
3479
|
+
if (releaseConfig.mode === "existing" && releaseConfig.existingReleaseId) {
|
|
3480
|
+
setIsCheckingConflicts(!0);
|
|
3481
|
+
const checkedReleaseId = releaseConfig.existingReleaseId, foundConflicts = await checkReleaseConflicts({
|
|
3482
|
+
client,
|
|
3483
|
+
releaseId: checkedReleaseId,
|
|
3484
|
+
sourceDocument: document,
|
|
3485
|
+
targetLanguages: selectedTargetLanguages,
|
|
3486
|
+
languageFieldName: config.languageFieldName,
|
|
3487
|
+
references: filteredReferences
|
|
3488
|
+
});
|
|
3489
|
+
foundConflicts.length > 0 ? setConflictContext({ releaseId: checkedReleaseId, conflicts: foundConflicts }) : setConflictContext(null), setIsCheckingConflicts(!1);
|
|
3490
|
+
}
|
|
3491
|
+
}, [releaseConfig, client, document, selectedTargetLanguages, config.languageFieldName, filteredReferences]), hasRunChecks = useRef(!1);
|
|
3290
3492
|
useEffect(() => {
|
|
3291
|
-
|
|
3292
|
-
}, [
|
|
3293
|
-
const
|
|
3493
|
+
hasRunChecks.current || (hasRunChecks.current = !0, runSourceDraftCheck(), runDraftCheck(), runConflictCheck());
|
|
3494
|
+
}, [runSourceDraftCheck, runDraftCheck, runConflictCheck]);
|
|
3495
|
+
const handleDiscardDrafts = useCallback(async () => {
|
|
3496
|
+
setIsDraftActionInProgress(!0);
|
|
3497
|
+
try {
|
|
3498
|
+
const draftIds = staleDrafts.map((d) => d.draftId);
|
|
3499
|
+
devLog.info("Discarding stale drafts", { draftIds, component: "PreflightView" });
|
|
3500
|
+
const transaction = client.transaction();
|
|
3501
|
+
for (const id of draftIds)
|
|
3502
|
+
transaction.delete(id);
|
|
3503
|
+
await transaction.commit(), devLog.info("Successfully discarded stale drafts", {
|
|
3504
|
+
count: draftIds.length,
|
|
3505
|
+
component: "PreflightView"
|
|
3506
|
+
}), await runDraftCheck();
|
|
3507
|
+
} catch (error) {
|
|
3508
|
+
devLog.error("Failed to discard drafts", error instanceof Error ? error : new Error(String(error)), {
|
|
3509
|
+
component: "PreflightView"
|
|
3510
|
+
});
|
|
3511
|
+
} finally {
|
|
3512
|
+
setIsDraftActionInProgress(!1);
|
|
3513
|
+
}
|
|
3514
|
+
}, [staleDrafts, client, runDraftCheck]), handlePublishDrafts = useCallback(async () => {
|
|
3515
|
+
setIsDraftActionInProgress(!0);
|
|
3516
|
+
try {
|
|
3517
|
+
devLog.info("Publishing stale drafts", {
|
|
3518
|
+
count: staleDrafts.length,
|
|
3519
|
+
component: "PreflightView"
|
|
3520
|
+
});
|
|
3521
|
+
for (const draft of staleDrafts)
|
|
3522
|
+
await client.request({
|
|
3523
|
+
method: "POST",
|
|
3524
|
+
uri: "/data/actions/mutate",
|
|
3525
|
+
body: {
|
|
3526
|
+
actions: [
|
|
3527
|
+
{
|
|
3528
|
+
actionType: "sanity.action.document.publish",
|
|
3529
|
+
draftId: draft.draftId,
|
|
3530
|
+
publishedId: draft.targetId
|
|
3531
|
+
}
|
|
3532
|
+
]
|
|
3533
|
+
}
|
|
3534
|
+
});
|
|
3535
|
+
devLog.info("Successfully published stale drafts", {
|
|
3536
|
+
count: staleDrafts.length,
|
|
3537
|
+
component: "PreflightView"
|
|
3538
|
+
}), await runDraftCheck();
|
|
3539
|
+
} catch (error) {
|
|
3540
|
+
devLog.error("Failed to publish drafts", error instanceof Error ? error : new Error(String(error)), {
|
|
3541
|
+
component: "PreflightView"
|
|
3542
|
+
});
|
|
3543
|
+
} finally {
|
|
3544
|
+
setIsDraftActionInProgress(!1);
|
|
3545
|
+
}
|
|
3546
|
+
}, [staleDrafts, client, runDraftCheck]), startTranslation = useCallback(
|
|
3294
3547
|
(replaceExisting, overrideReleaseId, skipConflicts) => {
|
|
3295
|
-
|
|
3548
|
+
translateDocumentSet({
|
|
3296
3549
|
sourceDocument: document,
|
|
3297
3550
|
targetLanguages: selectedTargetLanguages,
|
|
3298
3551
|
client,
|
|
@@ -3310,10 +3563,9 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3310
3563
|
...releaseConfig,
|
|
3311
3564
|
replaceExisting,
|
|
3312
3565
|
skipConflicts,
|
|
3313
|
-
// Use the override release ID if provided (from conflict context),
|
|
3314
|
-
// otherwise use the current releaseConfig value
|
|
3315
3566
|
existingReleaseId: overrideReleaseId ?? releaseConfig.existingReleaseId
|
|
3316
3567
|
},
|
|
3568
|
+
sourcePerspective: documentSource === "published" ? "published" : "drafts",
|
|
3317
3569
|
telemetryConfig: config.telemetry
|
|
3318
3570
|
});
|
|
3319
3571
|
},
|
|
@@ -3322,58 +3574,179 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3322
3574
|
selectedTargetLanguages,
|
|
3323
3575
|
client,
|
|
3324
3576
|
dispatch,
|
|
3325
|
-
config
|
|
3326
|
-
config.schemaId,
|
|
3327
|
-
config.maxConcurrentTranslationJobs,
|
|
3328
|
-
config.maxReferenceDepth,
|
|
3329
|
-
config.openai,
|
|
3330
|
-
config.excludeFields,
|
|
3331
|
-
config.unsetFields,
|
|
3332
|
-
config.telemetry,
|
|
3577
|
+
config,
|
|
3333
3578
|
filteredReferences,
|
|
3334
3579
|
translationMode,
|
|
3335
|
-
releaseConfig
|
|
3580
|
+
releaseConfig,
|
|
3581
|
+
documentSource
|
|
3336
3582
|
]
|
|
3337
|
-
),
|
|
3338
|
-
|
|
3339
|
-
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
const foundConflicts = await checkReleaseConflicts({
|
|
3346
|
-
client,
|
|
3347
|
-
releaseId: checkedReleaseId,
|
|
3348
|
-
sourceDocument: document,
|
|
3349
|
-
targetLanguages: selectedTargetLanguages,
|
|
3350
|
-
languageFieldName: config.languageFieldName,
|
|
3351
|
-
references: filteredReferences
|
|
3352
|
-
});
|
|
3353
|
-
if (setIsCheckingConflicts(!1), foundConflicts.length > 0) {
|
|
3354
|
-
setConflictContext({
|
|
3355
|
-
releaseId: checkedReleaseId,
|
|
3356
|
-
conflicts: foundConflicts
|
|
3357
|
-
});
|
|
3358
|
-
return;
|
|
3359
|
-
}
|
|
3360
|
-
}
|
|
3361
|
-
startTranslation(!1);
|
|
3362
|
-
}, [
|
|
3363
|
-
releaseConfig,
|
|
3364
|
-
client,
|
|
3365
|
-
document,
|
|
3366
|
-
selectedTargetLanguages,
|
|
3367
|
-
config.languageFieldName,
|
|
3368
|
-
startTranslation,
|
|
3369
|
-
filteredReferences
|
|
3370
|
-
]), handleCancelConflict = useCallback(() => {
|
|
3583
|
+
), handleStartTranslation = useCallback(() => {
|
|
3584
|
+
conflictContext || startTranslation(!1);
|
|
3585
|
+
}, [conflictContext, startTranslation]), handleBack = useCallback(() => {
|
|
3586
|
+
dispatch({ type: "SET_OVERALL_STATUS", payload: "idle" });
|
|
3587
|
+
}, [dispatch]), sourceRefDraftIds = useMemo(
|
|
3588
|
+
() => new Set(sourceRefsWithDrafts.map((d) => d.publishedId)),
|
|
3589
|
+
[sourceRefsWithDrafts]
|
|
3590
|
+
), isLoading = someStillValidating || isSourceDraftCheckLoading || isDraftCheckLoading || isCheckingConflicts, hasStaleDrafts = staleDrafts.length > 0, draftsDismissed = draftAction === "continue", canStartTranslation = !isLoading && !hasValidationErrors && !conflictContext && (!hasStaleDrafts || draftsDismissed), handleCancelConflict = useCallback(() => {
|
|
3371
3591
|
setConflictContext(null);
|
|
3372
3592
|
}, []), handleReplaceConflict = useCallback(() => {
|
|
3373
3593
|
conflictContext && startTranslation(!0, conflictContext.releaseId);
|
|
3374
3594
|
}, [startTranslation, conflictContext]), handleSkipConflicts = useCallback(() => {
|
|
3375
3595
|
conflictContext && startTranslation(!1, conflictContext.releaseId, conflictContext.conflicts);
|
|
3376
|
-
}, [startTranslation, conflictContext]),
|
|
3596
|
+
}, [startTranslation, conflictContext]), totalTranslations = useMemo(() => (1 + filteredReferences.length) * selectedTargetLanguages.length, [filteredReferences.length, selectedTargetLanguages.length]);
|
|
3597
|
+
return conflictContext ? /* @__PURE__ */ jsx(Stack, { space: 4, children: /* @__PURE__ */ jsx(
|
|
3598
|
+
ReleaseConflictWarning,
|
|
3599
|
+
{
|
|
3600
|
+
conflicts: conflictContext.conflicts,
|
|
3601
|
+
totalTranslations,
|
|
3602
|
+
onCancel: handleCancelConflict,
|
|
3603
|
+
onReplace: handleReplaceConflict,
|
|
3604
|
+
onSkipConflicts: handleSkipConflicts
|
|
3605
|
+
}
|
|
3606
|
+
) }) : /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
3607
|
+
documentsToValidate.map((doc) => /* @__PURE__ */ jsx(
|
|
3608
|
+
DocumentValidator,
|
|
3609
|
+
{
|
|
3610
|
+
documentId: doc._id,
|
|
3611
|
+
documentType: doc._type,
|
|
3612
|
+
onResult: handleValidationResult
|
|
3613
|
+
},
|
|
3614
|
+
doc._id
|
|
3615
|
+
)),
|
|
3616
|
+
/* @__PURE__ */ jsx(Text, { weight: "semibold", size: 2, children: "Pre-flight Checks" }),
|
|
3617
|
+
/* @__PURE__ */ jsxs(Text, { size: 1, muted: !0, children: [
|
|
3618
|
+
"Using ",
|
|
3619
|
+
documentSource,
|
|
3620
|
+
" version of all documents \u2192 ",
|
|
3621
|
+
selectedTargetLanguages.length,
|
|
3622
|
+
" language",
|
|
3623
|
+
selectedTargetLanguages.length !== 1 ? "s" : "",
|
|
3624
|
+
" \xB7 ",
|
|
3625
|
+
1 + filteredReferences.length,
|
|
3626
|
+
" document",
|
|
3627
|
+
filteredReferences.length !== 0 ? "s" : ""
|
|
3628
|
+
] }),
|
|
3629
|
+
/* @__PURE__ */ jsx(Card, { padding: 4, border: !0, radius: 2, tone: hasValidationErrors ? "critical" : void 0, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
3630
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
3631
|
+
someStillValidating ? /* @__PURE__ */ jsx(Spinner, { muted: !0 }) : hasValidationErrors ? /* @__PURE__ */ jsx(Text, { size: 2, children: /* @__PURE__ */ jsx(ErrorOutlineIcon, {}) }) : /* @__PURE__ */ jsx(Text, { size: 2, children: /* @__PURE__ */ jsx(CheckmarkIcon, {}) }),
|
|
3632
|
+
/* @__PURE__ */ jsx(Text, { weight: "semibold", children: someStillValidating ? "Validating documents\u2026" : hasValidationErrors ? `Validation errors in ${documentsWithErrors.length} document${documentsWithErrors.length !== 1 ? "s" : ""}` : "All documents pass validation" })
|
|
3633
|
+
] }),
|
|
3634
|
+
documentsWithErrors.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3635
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: "Documents must pass validation before they can be translated. Click a document to open it and fix the errors." }),
|
|
3636
|
+
/* @__PURE__ */ jsx(Card, { padding: 3, border: !0, radius: 2, children: /* @__PURE__ */ jsx(Box, { style: { maxHeight: "300px", overflowY: "auto" }, children: /* @__PURE__ */ jsx(Stack, { space: 3, children: documentsWithErrors.map((doc) => {
|
|
3637
|
+
const publishedId = getPublishedId(doc._id), displayName = doc._id === document._id ? "This document" : doc.title || doc._id, hasUnpublishedChanges = sourceRefDraftIds.has(publishedId);
|
|
3638
|
+
return /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "space-between", gap: 2, children: [
|
|
3639
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, flex: 1, style: { minWidth: 0 }, children: [
|
|
3640
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: /* @__PURE__ */ jsx(
|
|
3641
|
+
IntentLink,
|
|
3642
|
+
{
|
|
3643
|
+
intent: "edit",
|
|
3644
|
+
params: { id: publishedId, type: doc._type },
|
|
3645
|
+
style: { color: "inherit" },
|
|
3646
|
+
children: displayName
|
|
3647
|
+
}
|
|
3648
|
+
) }),
|
|
3649
|
+
/* @__PURE__ */ jsx(Badge, { tone: "primary", fontSize: 0, children: doc._type }),
|
|
3650
|
+
hasUnpublishedChanges && /* @__PURE__ */ jsx(Badge, { tone: "caution", fontSize: 0, children: "unpublished changes" })
|
|
3651
|
+
] }),
|
|
3652
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
3653
|
+
/* @__PURE__ */ jsxs(Badge, { tone: "critical", fontSize: 0, children: [
|
|
3654
|
+
doc.errors.length,
|
|
3655
|
+
" error",
|
|
3656
|
+
doc.errors.length !== 1 ? "s" : ""
|
|
3657
|
+
] }),
|
|
3658
|
+
/* @__PURE__ */ jsx(DocumentOpenerButton, { documentId: doc._id, documentType: doc._type })
|
|
3659
|
+
] })
|
|
3660
|
+
] }, doc._id);
|
|
3661
|
+
}) }) }) })
|
|
3662
|
+
] })
|
|
3663
|
+
] }) }),
|
|
3664
|
+
filteredReferences.length > 0 && /* @__PURE__ */ jsx(Card, { padding: 4, border: !0, radius: 2, tone: sourceRefsWithDrafts.length > 0 ? "caution" : void 0, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
3665
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
3666
|
+
isSourceDraftCheckLoading ? /* @__PURE__ */ jsx(Spinner, { muted: !0 }) : sourceRefsWithDrafts.length > 0 ? /* @__PURE__ */ jsx(Text, { size: 2, children: /* @__PURE__ */ jsx(WarningOutlineIcon, {}) }) : /* @__PURE__ */ jsx(Text, { size: 2, children: /* @__PURE__ */ jsx(CheckmarkIcon, {}) }),
|
|
3667
|
+
/* @__PURE__ */ jsx(Text, { weight: "semibold", children: isSourceDraftCheckLoading ? "Checking referenced documents\u2026" : sourceRefsWithDrafts.length > 0 ? `${sourceRefsWithDrafts.length} referenced document${sourceRefsWithDrafts.length !== 1 ? "s have" : " has"} unpublished changes` : "All referenced documents are in sync" })
|
|
3668
|
+
] }),
|
|
3669
|
+
sourceRefsWithDrafts.length > 0 && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3670
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: documentSource === "draft" ? 'You are translating from drafts. These unpublished changes will be included in the translation. If this is not intended, go back and switch to "Translate from published".' : 'You are translating from published. Unpublished changes on these documents will be ignored. If you want to include them, go back and switch to "Translate from drafts".' }),
|
|
3671
|
+
/* @__PURE__ */ jsx(Card, { padding: 3, border: !0, radius: 2, children: /* @__PURE__ */ jsx(Box, { style: { maxHeight: "300px", overflowY: "auto" }, children: /* @__PURE__ */ jsx(Stack, { space: 3, children: sourceRefsWithDrafts.map((ref) => /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "space-between", gap: 2, children: [
|
|
3672
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, flex: 1, style: { minWidth: 0 }, children: [
|
|
3673
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: ref.title || ref.publishedId }),
|
|
3674
|
+
/* @__PURE__ */ jsx(Badge, { tone: "primary", fontSize: 0, children: ref._type })
|
|
3675
|
+
] }),
|
|
3676
|
+
/* @__PURE__ */ jsx(DocumentOpenerButton, { documentId: ref.publishedId, documentType: ref._type })
|
|
3677
|
+
] }, ref.publishedId)) }) }) })
|
|
3678
|
+
] })
|
|
3679
|
+
] }) }),
|
|
3680
|
+
(isDraftCheckLoading || hasStaleDrafts) && /* @__PURE__ */ jsx(Card, { padding: 4, border: !0, radius: 2, tone: hasStaleDrafts && !draftsDismissed ? "caution" : void 0, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
3681
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
3682
|
+
isDraftCheckLoading ? /* @__PURE__ */ jsx(Spinner, { muted: !0 }) : draftsDismissed ? /* @__PURE__ */ jsx(Text, { size: 2, children: /* @__PURE__ */ jsx(CheckmarkIcon, {}) }) : /* @__PURE__ */ jsx(Text, { size: 2, children: /* @__PURE__ */ jsx(WarningOutlineIcon, {}) }),
|
|
3683
|
+
/* @__PURE__ */ jsx(Text, { weight: "semibold", children: isDraftCheckLoading ? "Checking for stale drafts on target documents\u2026" : draftsDismissed ? "Stale drafts acknowledged" : `${staleDrafts.length} stale draft${staleDrafts.length !== 1 ? "s" : ""} found on target documents` })
|
|
3684
|
+
] }),
|
|
3685
|
+
hasStaleDrafts && !draftsDismissed && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3686
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: "These target documents have unpublished drafts that may contain outdated content. Close and reopen the dialog after resolving, or use the actions below." }),
|
|
3687
|
+
/* @__PURE__ */ jsx(Card, { padding: 3, border: !0, radius: 2, children: /* @__PURE__ */ jsx(Box, { style: { maxHeight: "300px", overflowY: "auto" }, children: /* @__PURE__ */ jsx(Stack, { space: 3, children: staleDrafts.map((draft) => /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "space-between", gap: 2, children: [
|
|
3688
|
+
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, flex: 1, style: { minWidth: 0 }, children: [
|
|
3689
|
+
/* @__PURE__ */ jsx(Text, { size: 1, children: draft.title || draft.targetId }),
|
|
3690
|
+
/* @__PURE__ */ jsx(Badge, { tone: "primary", fontSize: 0, children: draft.targetLanguage })
|
|
3691
|
+
] }),
|
|
3692
|
+
/* @__PURE__ */ jsx(DocumentOpenerButton, { documentId: draft.targetId, documentType: draft._type })
|
|
3693
|
+
] }, draft.draftId)) }) }) }),
|
|
3694
|
+
/* @__PURE__ */ jsxs(Flex, { gap: 2, wrap: "wrap", children: [
|
|
3695
|
+
/* @__PURE__ */ jsx(
|
|
3696
|
+
Button,
|
|
3697
|
+
{
|
|
3698
|
+
mode: "ghost",
|
|
3699
|
+
tone: "caution",
|
|
3700
|
+
text: "Discard All Drafts",
|
|
3701
|
+
icon: CloseIcon,
|
|
3702
|
+
onClick: handleDiscardDrafts,
|
|
3703
|
+
disabled: isDraftActionInProgress
|
|
3704
|
+
}
|
|
3705
|
+
),
|
|
3706
|
+
/* @__PURE__ */ jsx(
|
|
3707
|
+
Button,
|
|
3708
|
+
{
|
|
3709
|
+
mode: "ghost",
|
|
3710
|
+
tone: "caution",
|
|
3711
|
+
text: "Publish All Drafts",
|
|
3712
|
+
onClick: handlePublishDrafts,
|
|
3713
|
+
disabled: isDraftActionInProgress
|
|
3714
|
+
}
|
|
3715
|
+
),
|
|
3716
|
+
/* @__PURE__ */ jsx(
|
|
3717
|
+
Button,
|
|
3718
|
+
{
|
|
3719
|
+
mode: "ghost",
|
|
3720
|
+
text: "Continue Anyway",
|
|
3721
|
+
onClick: () => setDraftAction("continue"),
|
|
3722
|
+
disabled: isDraftActionInProgress
|
|
3723
|
+
}
|
|
3724
|
+
)
|
|
3725
|
+
] }),
|
|
3726
|
+
isDraftActionInProgress && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
3727
|
+
/* @__PURE__ */ jsx(Spinner, { muted: !0 }),
|
|
3728
|
+
/* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Processing\u2026" })
|
|
3729
|
+
] })
|
|
3730
|
+
] })
|
|
3731
|
+
] }) }),
|
|
3732
|
+
/* @__PURE__ */ jsxs(Flex, { justify: "space-between", gap: 2, children: [
|
|
3733
|
+
/* @__PURE__ */ jsx(Button, { mode: "ghost", text: "Back", onClick: handleBack }),
|
|
3734
|
+
/* @__PURE__ */ jsx(
|
|
3735
|
+
Button,
|
|
3736
|
+
{
|
|
3737
|
+
mode: "ghost",
|
|
3738
|
+
tone: "positive",
|
|
3739
|
+
text: isLoading ? "Checking\u2026" : "Start Translation",
|
|
3740
|
+
onClick: handleStartTranslation,
|
|
3741
|
+
disabled: !canStartTranslation
|
|
3742
|
+
}
|
|
3743
|
+
)
|
|
3744
|
+
] })
|
|
3745
|
+
] });
|
|
3746
|
+
}, ActionButtonBar = ({ setIsDialogOpen }) => {
|
|
3747
|
+
const { document, config, overallStatus, dispatch, selectedTargetLanguages, releaseConfig } = useTranslationContext(), handleTranslate = useCallback(() => {
|
|
3748
|
+
dispatch({ type: "SET_OVERALL_STATUS", payload: "preflight" });
|
|
3749
|
+
}, [dispatch]), handleSelectAll = useCallback(() => {
|
|
3377
3750
|
dispatch({
|
|
3378
3751
|
type: "SET_SELECTED_TARGET_LANGUAGES",
|
|
3379
3752
|
payload: config.supportedLanguages.map((lang) => lang.id).filter((id) => id !== document.language)
|
|
@@ -3384,16 +3757,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3384
3757
|
payload: []
|
|
3385
3758
|
});
|
|
3386
3759
|
}, [dispatch]);
|
|
3387
|
-
return
|
|
3388
|
-
ReleaseConflictWarning,
|
|
3389
|
-
{
|
|
3390
|
-
conflicts: conflictContext.conflicts,
|
|
3391
|
-
totalTranslations,
|
|
3392
|
-
onCancel: handleCancelConflict,
|
|
3393
|
-
onReplace: handleReplaceConflict,
|
|
3394
|
-
onSkipConflicts: handleSkipConflicts
|
|
3395
|
-
}
|
|
3396
|
-
) }) : /* @__PURE__ */ jsxs(Flex, { justify: "space-between", gap: 2, children: [
|
|
3760
|
+
return /* @__PURE__ */ jsxs(Flex, { justify: "space-between", gap: 2, children: [
|
|
3397
3761
|
/* @__PURE__ */ jsxs(Flex, { justify: "flex-start", gap: 2, children: [
|
|
3398
3762
|
/* @__PURE__ */ jsx(Button, { mode: "ghost", size: 2, onClick: handleSelectAll, children: "Select All" }),
|
|
3399
3763
|
/* @__PURE__ */ jsx(Button, { mode: "ghost", size: 2, onClick: handleSelectNone, children: "Select None" })
|
|
@@ -3407,12 +3771,61 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3407
3771
|
tone: "positive",
|
|
3408
3772
|
size: 2,
|
|
3409
3773
|
onClick: handleTranslate,
|
|
3410
|
-
disabled: selectedTargetLanguages.length === 0 || !["idle", "completed"].includes(overallStatus) || releaseConfig.mode === "existing" && !releaseConfig.existingReleaseId
|
|
3411
|
-
children:
|
|
3774
|
+
disabled: selectedTargetLanguages.length === 0 || !["idle", "completed"].includes(overallStatus) || releaseConfig.mode === "existing" && !releaseConfig.existingReleaseId,
|
|
3775
|
+
children: "Translate"
|
|
3412
3776
|
}
|
|
3413
3777
|
)
|
|
3414
3778
|
] })
|
|
3415
3779
|
] });
|
|
3780
|
+
}, DocumentSourcePanel = () => {
|
|
3781
|
+
const { hasDraft, hasPublished, documentSource, dispatch } = useTranslationContext();
|
|
3782
|
+
if (!hasDraft)
|
|
3783
|
+
return null;
|
|
3784
|
+
if (!hasPublished)
|
|
3785
|
+
return /* @__PURE__ */ jsx(Card, { tone: "transparent", padding: 4, border: !0, children: /* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "This document has not been published yet. The current draft will be used for translation, along with drafts of any referenced documents." }) });
|
|
3786
|
+
const handleSourceChange = (source) => {
|
|
3787
|
+
dispatch({
|
|
3788
|
+
type: "SET_DOCUMENT_SOURCE",
|
|
3789
|
+
payload: source
|
|
3790
|
+
});
|
|
3791
|
+
};
|
|
3792
|
+
return /* @__PURE__ */ jsx(Card, { tone: "caution", padding: 4, border: !0, children: /* @__PURE__ */ jsxs(Stack, { space: 3, children: [
|
|
3793
|
+
/* @__PURE__ */ jsx(Text, { weight: "semibold", children: "This document has unpublished changes" }),
|
|
3794
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
3795
|
+
/* @__PURE__ */ jsx(
|
|
3796
|
+
Button,
|
|
3797
|
+
{
|
|
3798
|
+
type: "button",
|
|
3799
|
+
mode: documentSource === "draft" ? "ghost" : "bleed",
|
|
3800
|
+
tone: documentSource === "draft" ? "primary" : "default",
|
|
3801
|
+
onClick: () => handleSourceChange("draft"),
|
|
3802
|
+
children: /* @__PURE__ */ jsxs(Inline, { space: 2, children: [
|
|
3803
|
+
/* @__PURE__ */ jsx(Radio, { checked: documentSource === "draft", readOnly: !0 }),
|
|
3804
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
3805
|
+
/* @__PURE__ */ jsx(Text, { children: "Translate from drafts" }),
|
|
3806
|
+
/* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Uses the latest draft of this document and all referenced documents" })
|
|
3807
|
+
] })
|
|
3808
|
+
] })
|
|
3809
|
+
}
|
|
3810
|
+
),
|
|
3811
|
+
/* @__PURE__ */ jsx(
|
|
3812
|
+
Button,
|
|
3813
|
+
{
|
|
3814
|
+
type: "button",
|
|
3815
|
+
mode: documentSource === "published" ? "ghost" : "bleed",
|
|
3816
|
+
tone: documentSource === "published" ? "primary" : "default",
|
|
3817
|
+
onClick: () => handleSourceChange("published"),
|
|
3818
|
+
children: /* @__PURE__ */ jsxs(Inline, { space: 2, children: [
|
|
3819
|
+
/* @__PURE__ */ jsx(Radio, { checked: documentSource === "published", readOnly: !0 }),
|
|
3820
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
3821
|
+
/* @__PURE__ */ jsx(Text, { children: "Translate from published" }),
|
|
3822
|
+
/* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Uses only published content for this document and all referenced documents" })
|
|
3823
|
+
] })
|
|
3824
|
+
] })
|
|
3825
|
+
}
|
|
3826
|
+
)
|
|
3827
|
+
] })
|
|
3828
|
+
] }) });
|
|
3416
3829
|
}, TRANSLATION_METADATA_QUERY = "*[_type == $translationMetadataType && references($documentId)][0]", useTranslationMetadata = ({ documentId }) => {
|
|
3417
3830
|
const { dispatch } = useTranslationContext(), { data, loading, error } = useListeningQuery(TRANSLATION_METADATA_QUERY, {
|
|
3418
3831
|
params: {
|
|
@@ -3855,104 +4268,6 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
3855
4268
|
)
|
|
3856
4269
|
] })
|
|
3857
4270
|
] }) });
|
|
3858
|
-
}, DocumentValidator = ({ documentId, documentType, onResult }) => {
|
|
3859
|
-
const publishedId = getPublishedId(documentId), { isValidating, validation } = useValidationStatus(publishedId, documentType);
|
|
3860
|
-
return useEffect(() => {
|
|
3861
|
-
const errors = validation.filter((v) => v.level === "error");
|
|
3862
|
-
onResult(documentId, { isValidating, errors });
|
|
3863
|
-
}, [isValidating, validation, documentId, onResult]), null;
|
|
3864
|
-
}, ValidationPanel = ({ onValidationChange }) => {
|
|
3865
|
-
const { document, references, selectedReferenceIds, shouldTranslateReferences } = useTranslationContext(), [results, setResults] = useState(/* @__PURE__ */ new Map()), documentsToValidate = useMemo(() => {
|
|
3866
|
-
const docs = [
|
|
3867
|
-
{
|
|
3868
|
-
_id: document._id,
|
|
3869
|
-
_type: document._type,
|
|
3870
|
-
title: document.title || document.name || document._id
|
|
3871
|
-
}
|
|
3872
|
-
];
|
|
3873
|
-
if (shouldTranslateReferences)
|
|
3874
|
-
for (const ref of references)
|
|
3875
|
-
selectedReferenceIds.has(ref._id) && docs.push(ref);
|
|
3876
|
-
return docs;
|
|
3877
|
-
}, [document, references, selectedReferenceIds, shouldTranslateReferences]), handleResult = useCallback((id, result) => {
|
|
3878
|
-
setResults((prev) => {
|
|
3879
|
-
const next = new Map(prev);
|
|
3880
|
-
return next.set(id, result), next;
|
|
3881
|
-
});
|
|
3882
|
-
}, []), { shouldBlock, someStillValidating, documentsWithErrors } = useMemo(() => {
|
|
3883
|
-
const allValidated = documentsToValidate.every((doc) => results.has(doc._id)), validating = [...results.values()].some((r) => r.isValidating) || !allValidated, docsWithErrors = [];
|
|
3884
|
-
for (const doc of documentsToValidate) {
|
|
3885
|
-
const result = results.get(doc._id);
|
|
3886
|
-
result && result.errors.length > 0 && docsWithErrors.push({ ...doc, errors: result.errors });
|
|
3887
|
-
}
|
|
3888
|
-
const hasErrors = docsWithErrors.length > 0;
|
|
3889
|
-
return {
|
|
3890
|
-
shouldBlock: validating || hasErrors,
|
|
3891
|
-
someStillValidating: validating,
|
|
3892
|
-
documentsWithErrors: docsWithErrors
|
|
3893
|
-
};
|
|
3894
|
-
}, [documentsToValidate, results]);
|
|
3895
|
-
useEffect(() => {
|
|
3896
|
-
onValidationChange(shouldBlock);
|
|
3897
|
-
}, [shouldBlock, onValidationChange]), useEffect(() => {
|
|
3898
|
-
documentsWithErrors.length > 0 && devLog.warn("Documents have validation errors that block translation", {
|
|
3899
|
-
documentsWithErrors: documentsWithErrors.map((d) => ({
|
|
3900
|
-
id: d._id,
|
|
3901
|
-
type: d._type,
|
|
3902
|
-
errorCount: d.errors.length
|
|
3903
|
-
})),
|
|
3904
|
-
component: "ValidationPanel"
|
|
3905
|
-
});
|
|
3906
|
-
}, [documentsWithErrors]);
|
|
3907
|
-
const totalErrors = useMemo(
|
|
3908
|
-
() => documentsWithErrors.reduce((sum, doc) => sum + doc.errors.length, 0),
|
|
3909
|
-
[documentsWithErrors]
|
|
3910
|
-
);
|
|
3911
|
-
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
3912
|
-
documentsToValidate.map((doc) => /* @__PURE__ */ jsx(DocumentValidator, { documentId: doc._id, documentType: doc._type, onResult: handleResult }, doc._id)),
|
|
3913
|
-
someStillValidating && documentsWithErrors.length === 0 && /* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, padding: 2, children: [
|
|
3914
|
-
/* @__PURE__ */ jsx(Spinner, { muted: !0 }),
|
|
3915
|
-
/* @__PURE__ */ jsx(Text, { size: 1, muted: !0, children: "Validating documents\u2026" })
|
|
3916
|
-
] }),
|
|
3917
|
-
documentsWithErrors.length > 0 && /* @__PURE__ */ jsx(Card, { tone: "critical", padding: 4, border: !0, radius: 2, children: /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
3918
|
-
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, children: [
|
|
3919
|
-
/* @__PURE__ */ jsx(Text, { size: 2, children: /* @__PURE__ */ jsx(ErrorOutlineIcon, {}) }),
|
|
3920
|
-
/* @__PURE__ */ jsxs(Text, { weight: "semibold", children: [
|
|
3921
|
-
totalErrors,
|
|
3922
|
-
" validation error",
|
|
3923
|
-
totalErrors !== 1 ? "s" : "",
|
|
3924
|
-
" found in ",
|
|
3925
|
-
documentsWithErrors.length,
|
|
3926
|
-
" ",
|
|
3927
|
-
"document",
|
|
3928
|
-
documentsWithErrors.length !== 1 ? "s" : ""
|
|
3929
|
-
] })
|
|
3930
|
-
] }),
|
|
3931
|
-
/* @__PURE__ */ jsx(Text, { size: 1, children: "Documents must pass validation before they can be translated. Click a document to open it and fix the errors." }),
|
|
3932
|
-
/* @__PURE__ */ jsx(Card, { padding: 3, border: !0, radius: 2, children: /* @__PURE__ */ jsx(Box, { style: { maxHeight: "300px", overflowY: "auto" }, children: /* @__PURE__ */ jsx(Stack, { space: 3, children: documentsWithErrors.map((doc) => {
|
|
3933
|
-
const publishedId = getPublishedId(doc._id);
|
|
3934
|
-
return /* @__PURE__ */ jsxs(Flex, { align: "center", justify: "space-between", gap: 2, children: [
|
|
3935
|
-
/* @__PURE__ */ jsxs(Flex, { align: "center", gap: 2, flex: 1, style: { minWidth: 0 }, children: [
|
|
3936
|
-
/* @__PURE__ */ jsx(Text, { size: 1, children: /* @__PURE__ */ jsx(
|
|
3937
|
-
IntentLink,
|
|
3938
|
-
{
|
|
3939
|
-
intent: "edit",
|
|
3940
|
-
params: { id: publishedId, type: doc._type },
|
|
3941
|
-
style: { color: "inherit" },
|
|
3942
|
-
children: doc.title || doc._id
|
|
3943
|
-
}
|
|
3944
|
-
) }),
|
|
3945
|
-
/* @__PURE__ */ jsx(Badge, { tone: "primary", fontSize: 0, children: doc._type })
|
|
3946
|
-
] }),
|
|
3947
|
-
/* @__PURE__ */ jsxs(Badge, { tone: "critical", fontSize: 0, children: [
|
|
3948
|
-
doc.errors.length,
|
|
3949
|
-
" error",
|
|
3950
|
-
doc.errors.length !== 1 ? "s" : ""
|
|
3951
|
-
] })
|
|
3952
|
-
] }, doc._id);
|
|
3953
|
-
}) }) }) })
|
|
3954
|
-
] }) })
|
|
3955
|
-
] });
|
|
3956
4271
|
}, assembleReferences = async ({
|
|
3957
4272
|
client,
|
|
3958
4273
|
sourceDocument,
|
|
@@ -4206,31 +4521,26 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
4206
4521
|
!isLoadingReferences && references.length > 0 && showSelectionPanel && /* @__PURE__ */ jsx(ReferenceSelectionPanel, {})
|
|
4207
4522
|
] }) : null
|
|
4208
4523
|
] });
|
|
4209
|
-
}, WriteSettingsPanel = () => /* @__PURE__ */ jsx(ReferenceConfigPanel, {}), TranslationConfigView = ({ setIsDialogOpen }) => {
|
|
4210
|
-
|
|
4211
|
-
|
|
4212
|
-
|
|
4213
|
-
|
|
4214
|
-
|
|
4215
|
-
|
|
4216
|
-
|
|
4217
|
-
|
|
4218
|
-
|
|
4219
|
-
|
|
4220
|
-
|
|
4221
|
-
|
|
4222
|
-
|
|
4223
|
-
|
|
4224
|
-
|
|
4225
|
-
|
|
4226
|
-
|
|
4227
|
-
|
|
4228
|
-
|
|
4229
|
-
] }),
|
|
4230
|
-
/* @__PURE__ */ jsx(ValidationPanel, { onValidationChange: handleValidationChange }),
|
|
4231
|
-
/* @__PURE__ */ jsx(ActionButtonBar, { setIsDialogOpen, hasValidationErrors })
|
|
4232
|
-
] });
|
|
4233
|
-
}, TERMINAL_STATUSES = ["completed", "skipped", "error"], TranslationStatusPanel = () => {
|
|
4524
|
+
}, WriteSettingsPanel = () => /* @__PURE__ */ jsx(ReferenceConfigPanel, {}), TranslationConfigView = ({ setIsDialogOpen }) => /* @__PURE__ */ jsxs(Stack, { space: 4, children: [
|
|
4525
|
+
/* @__PURE__ */ jsx(DocumentSourcePanel, {}),
|
|
4526
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
4527
|
+
/* @__PURE__ */ jsx(Label, { children: "Languages" }),
|
|
4528
|
+
/* @__PURE__ */ jsx(LanguageSelectionPanel, {})
|
|
4529
|
+
] }),
|
|
4530
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
4531
|
+
/* @__PURE__ */ jsx(Label, { children: "Translation Method" }),
|
|
4532
|
+
/* @__PURE__ */ jsx(TranslationModePanel, {})
|
|
4533
|
+
] }),
|
|
4534
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
4535
|
+
/* @__PURE__ */ jsx(Label, { children: "Content Release" }),
|
|
4536
|
+
/* @__PURE__ */ jsx(ReleaseSelectionPanel, {})
|
|
4537
|
+
] }),
|
|
4538
|
+
/* @__PURE__ */ jsxs(Stack, { space: 2, children: [
|
|
4539
|
+
/* @__PURE__ */ jsx(Label, { children: "Settings" }),
|
|
4540
|
+
/* @__PURE__ */ jsx(Card, { padding: 4, border: !0, muted: !0, children: /* @__PURE__ */ jsx(WriteSettingsPanel, {}) })
|
|
4541
|
+
] }),
|
|
4542
|
+
/* @__PURE__ */ jsx(ActionButtonBar, { setIsDialogOpen })
|
|
4543
|
+
] }), TERMINAL_STATUSES = ["completed", "skipped", "error"], TranslationStatusPanel = () => {
|
|
4234
4544
|
const { overallStatus, translationJobs, dispatch, document } = useTranslationContext(), headline = useMemo(() => overallStatus === "completed" ? "Translation completed" : overallStatus === "error" ? "Translation failed" : "Translation in progress", [overallStatus]), jobs = useMemo(() => Array.from(translationJobs.values()), [translationJobs]), isTerminalState = overallStatus === "completed" || overallStatus === "error", handleReset = useCallback(() => {
|
|
4235
4545
|
forceCleanupActiveTranslation(document._id), dispatch({ type: "RESET_TRANSLATION_STATE" });
|
|
4236
4546
|
}, [dispatch, document._id]);
|
|
@@ -4352,7 +4662,7 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
4352
4662
|
const { overallStatus, document } = useTranslationContext();
|
|
4353
4663
|
return useEffect(() => {
|
|
4354
4664
|
onStatusChange?.(overallStatus);
|
|
4355
|
-
}, [overallStatus, onStatusChange]), STATES_IN_WHICH_TO_SHOW_CONFIG.includes(overallStatus) ? /* @__PURE__ */ jsx(TranslationConfigView, { setIsDialogOpen }) : STATES_IN_WHICH_TO_SHOW_TRANSLATION_PROGRESS.includes(overallStatus) ? /* @__PURE__ */ jsx(TranslationStatusPanel, {}) : STATES_IN_WHICH_TO_SHOW_ERROR.includes(overallStatus) ? /* @__PURE__ */ jsx("div", { children: "Error occurred" }) : (devLog.warn("Unhandled translation dialog state", {
|
|
4665
|
+
}, [overallStatus, onStatusChange]), STATES_IN_WHICH_TO_SHOW_CONFIG.includes(overallStatus) ? /* @__PURE__ */ jsx(TranslationConfigView, { setIsDialogOpen }) : overallStatus === "preflight" ? /* @__PURE__ */ jsx(PreflightView, {}) : STATES_IN_WHICH_TO_SHOW_TRANSLATION_PROGRESS.includes(overallStatus) ? /* @__PURE__ */ jsx(TranslationStatusPanel, {}) : STATES_IN_WHICH_TO_SHOW_ERROR.includes(overallStatus) ? /* @__PURE__ */ jsx("div", { children: "Error occurred" }) : (devLog.warn("Unhandled translation dialog state", {
|
|
4356
4666
|
documentId: document._id,
|
|
4357
4667
|
overallStatus
|
|
4358
4668
|
}), /* @__PURE__ */ jsx("div", { children: "Unhandled overall state" }));
|
|
@@ -4392,7 +4702,16 @@ ${protectedPhrases.join(", ")}`, buildStyleGuideSection = (globalPrompt, localeP
|
|
|
4392
4702
|
type: "dialog",
|
|
4393
4703
|
onClose: handleClose,
|
|
4394
4704
|
header: "Translate Document",
|
|
4395
|
-
content: /* @__PURE__ */ jsx(
|
|
4705
|
+
content: /* @__PURE__ */ jsx(
|
|
4706
|
+
TranslationContextProvider,
|
|
4707
|
+
{
|
|
4708
|
+
document,
|
|
4709
|
+
config,
|
|
4710
|
+
hasDraft: !!draft,
|
|
4711
|
+
hasPublished: !!published,
|
|
4712
|
+
children: /* @__PURE__ */ jsx(TranslationDialog, { setIsDialogOpen, onStatusChange: handleStatusChange })
|
|
4713
|
+
}
|
|
4714
|
+
)
|
|
4396
4715
|
}
|
|
4397
4716
|
} : (devLog.error("Missing config in TranslateAction"), null);
|
|
4398
4717
|
}, translationGlossaryTerm = defineType({
|