@sanity/assist 4.4.6 → 4.4.7
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.d.mts +2 -3
- package/dist/index.d.ts +2 -3
- package/dist/index.esm.js +309 -267
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +307 -265
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +309 -267
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/assistDocument/hooks/useAssistDocumentContextValue.tsx +6 -7
- package/src/assistInspector/FieldAutocomplete.tsx +9 -4
- package/src/assistInspector/helpers.ts +15 -26
- package/src/assistLayout/AiAssistanceConfigContext.tsx +5 -67
- package/src/assistLayout/AiAssistanceConfigProvider.tsx +98 -0
- package/src/assistLayout/AssistLayout.tsx +1 -1
- package/src/assistLayout/fieldRefCache.tsx +34 -0
- package/src/fieldActions/customFieldActions.tsx +2 -1
- package/src/schemas/assistDocumentSchema.tsx +9 -6
- package/src/schemas/typeDefExtensions.ts +1 -0
package/dist/index.mjs
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import { jsx, jsxs, Fragment } from "react/jsx-runtime";
|
|
2
|
-
import { pathToString, getVersionFromId, getPublishedId, isVersionId, useEditState, useCurrentUser, useClient, typed,
|
|
2
|
+
import { pathToString, getVersionFromId, getPublishedId, isVersionId, useEditState, useCurrentUser, useClient, typed, FormFieldHeaderText, PatchEvent, unset, isObjectSchemaType, stringToPath, isKeySegment, useSchema, getVersionId, getDraftId, useColorSchemeValue, isArraySchemaType, useFormCallbacks, useDocumentStore, useDocumentPresence, createPatchChannel, FormBuilder, fromMutationPatches, StatusButton, PresenceOverlay, VirtualizerScrollInstanceProvider, isDocumentSchemaType, useSyncState, set, useWorkspaceSchemaId, MemberFieldError, FormCallbacksProvider, FormInput, setIfMissing, insert, ObjectInputMember, isArrayOfObjectsSchemaType, defineType, defineField, defineArrayMember, definePlugin } from "sanity";
|
|
3
3
|
import { useToast, useLayer, Dialog, Stack, Flex, Tooltip, Text, TextArea, Button, Badge, Popover, Card, Box, ErrorBoundary, focusFirstDescendant, Spinner, Container, Autocomplete, Breadcrumbs, useClickOutside, useGlobalKeyDown, useTheme, rgba, Radio, Checkbox, ThemeProvider, MenuButton, Menu, MenuItem, Switch, Label } from "@sanity/ui";
|
|
4
4
|
import { useRef, useState, useEffect, useMemo, createContext, useContext, useCallback, useId, forwardRef, createElement, useReducer } from "react";
|
|
5
5
|
import { useDocumentPane, usePaneRouter, DocumentInspectorHeader, DocumentPaneProvider } from "sanity/structure";
|
|
6
6
|
import { minutesToMilliseconds, isAfter, addSeconds, formatDistanceToNow } from "date-fns";
|
|
7
|
-
import { DocumentIcon, LinkIcon, ImageIcon, BlockContentIcon, OlistIcon, BlockquoteIcon, StringIcon,
|
|
7
|
+
import { PlayIcon, DocumentIcon, LinkIcon, ImageIcon, BlockContentIcon, OlistIcon, BlockquoteIcon, StringIcon, SparklesIcon, ArrowRightIcon, CheckmarkIcon, SearchIcon, SyncIcon, ErrorOutlineIcon, CheckmarkCircleIcon, ClockIcon, CloseCircleIcon, RetryIcon, CloseIcon, icons, TranslateIcon, LockIcon, ControlsIcon, ArrowLeftIcon, TokenIcon, DocumentTextIcon, ThListIcon, CodeIcon, ComposeIcon } from "@sanity/icons";
|
|
8
8
|
import { extractWithPath } from "@sanity/mutator";
|
|
9
9
|
import { keyframes, styled } from "styled-components";
|
|
10
10
|
import { tap, mergeMap, share, take, filter, distinctUntilChanged, catchError } from "rxjs/operators";
|
|
@@ -392,221 +392,6 @@ function useAssistDocumentContext() {
|
|
|
392
392
|
throw new Error("AssistDocumentContext value is missing");
|
|
393
393
|
return context;
|
|
394
394
|
}
|
|
395
|
-
const SelectedFieldContext = createContext(void 0), SelectedFieldContextProvider = SelectedFieldContext.Provider, maxDepth = 6;
|
|
396
|
-
function getTypeIcon(schemaType) {
|
|
397
|
-
let t = schemaType;
|
|
398
|
-
for (; t; ) {
|
|
399
|
-
if (t.icon) return t.icon;
|
|
400
|
-
t = t.type;
|
|
401
|
-
}
|
|
402
|
-
return isType(schemaType, "slug") ? LinkIcon : isType(schemaType, "image") ? ImageIcon : schemaType.jsonType === "array" && isPortableTextArray(schemaType) ? BlockContentIcon : schemaType.jsonType === "array" ? OlistIcon : schemaType.jsonType === "object" ? BlockquoteIcon : schemaType.jsonType === "string" ? StringIcon : DocumentIcon;
|
|
403
|
-
}
|
|
404
|
-
function asFieldRefsByTypePath(fieldRefs) {
|
|
405
|
-
return fieldRefs.reduce(
|
|
406
|
-
(acc, ref) => ({ ...acc, [ref.key]: ref }),
|
|
407
|
-
{}
|
|
408
|
-
);
|
|
409
|
-
}
|
|
410
|
-
function getFieldRefsWithDocument(schemaType) {
|
|
411
|
-
const fields = getFieldRefs(schemaType);
|
|
412
|
-
return [
|
|
413
|
-
{
|
|
414
|
-
key: documentRootKey,
|
|
415
|
-
icon: schemaType.icon ?? DocumentIcon,
|
|
416
|
-
title: "The entire document",
|
|
417
|
-
path: [],
|
|
418
|
-
schemaType
|
|
419
|
-
},
|
|
420
|
-
...fields
|
|
421
|
-
];
|
|
422
|
-
}
|
|
423
|
-
function getFieldRefs(schemaType, parent, depth = 0) {
|
|
424
|
-
return depth >= maxDepth ? [] : schemaType.fields.filter((f) => !f.name.startsWith("_")).flatMap((field) => {
|
|
425
|
-
const path = parent ? [...parent.path, field.name] : [field.name], title = field.type.title ?? field.name, fieldRef = {
|
|
426
|
-
key: patchableKey(pathToString(path)),
|
|
427
|
-
path,
|
|
428
|
-
title: parent ? [parent.title, title].join(" / ") : title,
|
|
429
|
-
schemaType: field.type,
|
|
430
|
-
icon: getTypeIcon(field.type)
|
|
431
|
-
}, fields = field.type.jsonType === "object" ? getFieldRefs(field.type, fieldRef, depth + 1) : [], syntheticFields = field.type.jsonType === "array" ? getSyntheticFields(field.type, fieldRef, depth + 1) : [];
|
|
432
|
-
return isAssistSupported(field.type) ? [fieldRef, ...fields, ...syntheticFields] : [...fields, ...syntheticFields];
|
|
433
|
-
});
|
|
434
|
-
}
|
|
435
|
-
function getSyntheticFields(schemaType, parent, depth = 0) {
|
|
436
|
-
return depth >= maxDepth ? [] : schemaType.of.filter((itemType) => !isType(itemType, "block")).flatMap((itemType) => {
|
|
437
|
-
const segment = { _key: itemType.name }, title = itemType.title ?? itemType.name, path = parent ? [...parent.path, segment] : [segment], fieldRef = {
|
|
438
|
-
key: patchableKey(pathToString(path)),
|
|
439
|
-
path,
|
|
440
|
-
title: parent ? [parent.title, title].join(" / ") : title,
|
|
441
|
-
schemaType: itemType,
|
|
442
|
-
icon: getTypeIcon(itemType),
|
|
443
|
-
synthetic: !0
|
|
444
|
-
}, fields = itemType.jsonType === "object" ? getFieldRefs(itemType, fieldRef, depth + 1) : [];
|
|
445
|
-
return isAssistSupported(itemType) ? [fieldRef, ...fields] : fields;
|
|
446
|
-
});
|
|
447
|
-
}
|
|
448
|
-
function getTypePath(doc, pathString) {
|
|
449
|
-
if (!pathString)
|
|
450
|
-
return;
|
|
451
|
-
const path = stringToPath(pathString), currentPath = [];
|
|
452
|
-
let valid = !0;
|
|
453
|
-
const syntheticPath = path.map((segment) => {
|
|
454
|
-
if (currentPath.push(segment), isKeySegment(segment)) {
|
|
455
|
-
const match = extractWithPath(pathToString(currentPath), doc)[0], value = match?.value;
|
|
456
|
-
if (match && value && typeof value == "object" && "_type" in value)
|
|
457
|
-
return { _key: value._type };
|
|
458
|
-
valid = !1;
|
|
459
|
-
}
|
|
460
|
-
return segment;
|
|
461
|
-
});
|
|
462
|
-
return valid ? patchableKey(pathToString(syntheticPath)) : void 0;
|
|
463
|
-
}
|
|
464
|
-
function patchableKey(pathKey) {
|
|
465
|
-
return pathKey.replace(/[=]=/g, ":").replace(/[[\]]/g, "|").replace(/"/g, "");
|
|
466
|
-
}
|
|
467
|
-
function useTypePath(doc, pathString) {
|
|
468
|
-
return useMemo(() => getTypePath(doc, pathString), [doc, pathString]);
|
|
469
|
-
}
|
|
470
|
-
function useSelectedField(documentSchemaType, path) {
|
|
471
|
-
const selectableFields = useMemo(
|
|
472
|
-
() => documentSchemaType && isObjectSchemaType(documentSchemaType) ? getFieldRefsWithDocument(documentSchemaType) : [],
|
|
473
|
-
[documentSchemaType]
|
|
474
|
-
);
|
|
475
|
-
return useMemo(() => path ? selectableFields?.find((f) => f.key === path) : void 0, [selectableFields, path]);
|
|
476
|
-
}
|
|
477
|
-
function getFieldTitle(field) {
|
|
478
|
-
const schemaType = field?.schemaType;
|
|
479
|
-
return field?.title ?? schemaType?.title ?? schemaType?.name ?? "Untitled";
|
|
480
|
-
}
|
|
481
|
-
function useAiPaneRouter() {
|
|
482
|
-
const paneRouter = usePaneRouter();
|
|
483
|
-
return useMemo(
|
|
484
|
-
() => ({ ...paneRouter, params: paneRouter.params ?? {} }),
|
|
485
|
-
[paneRouter]
|
|
486
|
-
);
|
|
487
|
-
}
|
|
488
|
-
const hiddenTypes = [
|
|
489
|
-
"any",
|
|
490
|
-
"array",
|
|
491
|
-
"block",
|
|
492
|
-
"boolean",
|
|
493
|
-
"crossDatasetReference",
|
|
494
|
-
"date",
|
|
495
|
-
"datetime",
|
|
496
|
-
"document",
|
|
497
|
-
"email",
|
|
498
|
-
"file",
|
|
499
|
-
"globalDocumentReference",
|
|
500
|
-
"image",
|
|
501
|
-
"number",
|
|
502
|
-
"object",
|
|
503
|
-
"reference",
|
|
504
|
-
"span",
|
|
505
|
-
"string",
|
|
506
|
-
"text",
|
|
507
|
-
"url",
|
|
508
|
-
"slug",
|
|
509
|
-
"geopoint",
|
|
510
|
-
"sanity.assetSourceData",
|
|
511
|
-
"sanity.imageAsset",
|
|
512
|
-
"sanity.fileAsset",
|
|
513
|
-
"sanity.imageCrop",
|
|
514
|
-
"sanity.imageHotspot",
|
|
515
|
-
"sanity.imageMetadata",
|
|
516
|
-
"sanity.imageDimensions",
|
|
517
|
-
"sanity.imagePalette",
|
|
518
|
-
"sanity.imagePaletteSwatch",
|
|
519
|
-
assistSerializedTypeName,
|
|
520
|
-
assistSerializedFieldTypeName,
|
|
521
|
-
"sanity-agent.job.document"
|
|
522
|
-
], inlineTypes = ["document", "object", "image", "file"];
|
|
523
|
-
function serializeSchema(schema, options2) {
|
|
524
|
-
const list = schema.getTypeNames().filter((t) => !(hiddenTypes.includes(t) || t.startsWith("sanity."))).map((t) => schema.get(t)).filter((t) => !!t).map((t) => getSchemaStub(t, schema, options2)).filter((t) => !("to" in t && t.to && !t.to.length || "of" in t && t.of && !t.of.length || "fields" in t && t.fields && !t.fields.length));
|
|
525
|
-
return list.sort((a, b) => (a?.name ?? "").localeCompare(b?.name ?? "")), list;
|
|
526
|
-
}
|
|
527
|
-
function getSchemaStub(schemaType, schema, options2) {
|
|
528
|
-
if (!schemaType.type?.name)
|
|
529
|
-
throw console.error("Missing type name", schemaType.type), new Error("Type is missing name!");
|
|
530
|
-
const baseSchema = {
|
|
531
|
-
// we dont need type or id when we send using POST, so leave these out to save bandwidth
|
|
532
|
-
...options2?.leanFormat ? {} : { _id: `${assistSchemaIdPrefix}${schemaType.name}`, _type: assistSerializedTypeName },
|
|
533
|
-
name: schemaType.name,
|
|
534
|
-
title: schemaType.title,
|
|
535
|
-
type: schemaType.type.name,
|
|
536
|
-
...getBaseFields(schema, schemaType, schemaType.type.name, options2)
|
|
537
|
-
};
|
|
538
|
-
return removeUndef(baseSchema);
|
|
539
|
-
}
|
|
540
|
-
function getBaseFields(schema, type, typeName, options2) {
|
|
541
|
-
const schemaOptions = removeUndef({
|
|
542
|
-
imagePromptField: type.options?.aiAssist?.imageInstructionField,
|
|
543
|
-
embeddingsIndex: type.options?.aiAssist?.embeddingsIndex
|
|
544
|
-
});
|
|
545
|
-
return removeUndef({
|
|
546
|
-
options: Object.keys(schemaOptions).length ? schemaOptions : void 0,
|
|
547
|
-
values: Array.isArray(type?.options?.list) ? type?.options?.list.map(
|
|
548
|
-
(v) => typeof v == "string" ? v : v.value ?? `${v.title}`
|
|
549
|
-
) : void 0,
|
|
550
|
-
of: "of" in type && typeName === "array" ? arrayOf(type, schema, options2) : void 0,
|
|
551
|
-
to: "to" in type && typeName === "reference" ? refToTypeNames(type) : void 0,
|
|
552
|
-
fields: "fields" in type && inlineTypes.includes(typeName) ? serializeFields(schema, type, options2) : void 0,
|
|
553
|
-
annotations: typeName === "block" && "fields" in type ? serializeAnnotations(type, schema, options2) : void 0,
|
|
554
|
-
inlineOf: typeName === "block" && "fields" in type ? serializeInlineOf(type, schema, options2) : void 0,
|
|
555
|
-
hidden: typeof type.hidden == "function" ? "function" : type.hidden ? !0 : void 0,
|
|
556
|
-
readOnly: typeof type.readOnly == "function" ? "function" : type.readOnly ? !0 : void 0
|
|
557
|
-
});
|
|
558
|
-
}
|
|
559
|
-
function serializeFields(schema, schemaType, options2) {
|
|
560
|
-
return (schemaType.fieldsets ? schemaType.fieldsets.flatMap(
|
|
561
|
-
(fs) => fs.single ? fs.field : fs.fields.map((f) => ({
|
|
562
|
-
...f,
|
|
563
|
-
type: {
|
|
564
|
-
...f.type,
|
|
565
|
-
// if fieldset is (conditionally) hidden, the field must be considered the same way
|
|
566
|
-
// ie, if the field does not show up in conditionalMembers, it is hidden
|
|
567
|
-
// regardless of weather or not it is the field function or the fieldset function that hides it
|
|
568
|
-
hidden: typeof fs.hidden == "function" ? fs.hidden : fs.hidden ? !0 : f.type.hidden
|
|
569
|
-
}
|
|
570
|
-
}))
|
|
571
|
-
) : schemaType.fields).filter((f) => !["sanity.imageHotspot", "sanity.imageCrop"].includes(f.type?.name ?? "")).filter((f) => isAssistSupported(f.type)).map((field) => serializeMember(schema, field.type, field.name, options2));
|
|
572
|
-
}
|
|
573
|
-
function serializeMember(schema, type, name, options2) {
|
|
574
|
-
const typeName = schema.get(type?.name) ? type.name : type.type?.name ?? "";
|
|
575
|
-
return removeUndef({
|
|
576
|
-
...options2?.leanFormat ? {} : { _type: assistSerializedFieldTypeName },
|
|
577
|
-
name,
|
|
578
|
-
type: typeName,
|
|
579
|
-
title: type.title,
|
|
580
|
-
...getBaseFields(schema, type, typeName, options2)
|
|
581
|
-
});
|
|
582
|
-
}
|
|
583
|
-
function serializeInlineOf(blockSchemaType, schema, options2) {
|
|
584
|
-
const childrenType = blockSchemaType.fields.find((f) => f.name === "children")?.type;
|
|
585
|
-
if (!(!childrenType || !isArraySchemaType(childrenType)))
|
|
586
|
-
return arrayOf(
|
|
587
|
-
{
|
|
588
|
-
of: childrenType.of.filter((t) => !isType(t, "span"))
|
|
589
|
-
},
|
|
590
|
-
schema,
|
|
591
|
-
options2
|
|
592
|
-
);
|
|
593
|
-
}
|
|
594
|
-
function serializeAnnotations(blockSchemaType, schema, options2) {
|
|
595
|
-
const marksType = blockSchemaType.fields.find((f) => f.name === "markDefs")?.type;
|
|
596
|
-
if (!(!marksType || !isArraySchemaType(marksType)))
|
|
597
|
-
return arrayOf(marksType, schema, options2);
|
|
598
|
-
}
|
|
599
|
-
function arrayOf(arrayType, schema, options2) {
|
|
600
|
-
return arrayType.of.filter((type) => isAssistSupported(type)).map((t) => serializeMember(schema, t, t.name, options2));
|
|
601
|
-
}
|
|
602
|
-
function refToTypeNames(type) {
|
|
603
|
-
return type.to.map((t) => ({
|
|
604
|
-
type: typed(t.name)
|
|
605
|
-
}));
|
|
606
|
-
}
|
|
607
|
-
function removeUndef(obj) {
|
|
608
|
-
return Object.keys(obj).forEach((key) => obj[key] === void 0 ? delete obj[key] : {}), obj;
|
|
609
|
-
}
|
|
610
395
|
const AiAssistanceConfigContext = createContext({});
|
|
611
396
|
function useAiAssistanceConfig() {
|
|
612
397
|
const context = useContext(AiAssistanceConfigContext);
|
|
@@ -617,33 +402,6 @@ function useAiAssistanceConfig() {
|
|
|
617
402
|
function useSerializedTypes() {
|
|
618
403
|
return useAiAssistanceConfig().serializedTypes;
|
|
619
404
|
}
|
|
620
|
-
function AiAssistanceConfigProvider(props) {
|
|
621
|
-
const [status, setStatus] = useState(), [error, setError] = useState(), apiClient = useApiClient(props.config?.__customApiClient), { getInstructStatus, loading: statusLoading } = useGetInstructStatus(apiClient), { initInstruct, loading: initLoading } = useInitInstruct(apiClient), schema = useSchema(), serializedTypes = useMemo(() => serializeSchema(schema, { leanFormat: !0 }), [schema]);
|
|
622
|
-
useEffect(() => {
|
|
623
|
-
getInstructStatus().then((s) => setStatus(s)).catch((e) => {
|
|
624
|
-
console.error(e), setError(e);
|
|
625
|
-
});
|
|
626
|
-
}, [getInstructStatus]);
|
|
627
|
-
const init = useCallback(async () => {
|
|
628
|
-
setError(void 0);
|
|
629
|
-
try {
|
|
630
|
-
await initInstruct();
|
|
631
|
-
const status2 = await getInstructStatus();
|
|
632
|
-
setStatus(status2);
|
|
633
|
-
} catch (e) {
|
|
634
|
-
console.error("Failed to init ai assistance", e), setError(e);
|
|
635
|
-
}
|
|
636
|
-
}, [initInstruct, getInstructStatus, setStatus]), { config, children } = props, context = useMemo(() => ({
|
|
637
|
-
config,
|
|
638
|
-
status,
|
|
639
|
-
statusLoading,
|
|
640
|
-
init,
|
|
641
|
-
initLoading,
|
|
642
|
-
error,
|
|
643
|
-
serializedTypes
|
|
644
|
-
}), [config, status, init, statusLoading, initLoading, error, serializedTypes]);
|
|
645
|
-
return /* @__PURE__ */ jsx(AiAssistanceConfigContext.Provider, { value: context, children });
|
|
646
|
-
}
|
|
647
405
|
const basePath = "/assist/tasks/instruction", API_VERSION_WITH_EXTENDED_TYPES = "2025-04-01";
|
|
648
406
|
function canUseAssist(status) {
|
|
649
407
|
return status?.enabled && status.initialized && status.validToken;
|
|
@@ -1022,19 +780,105 @@ function useDraftDelayedTask(args) {
|
|
|
1022
780
|
[setQueuedArgs, documentOnChange]
|
|
1023
781
|
);
|
|
1024
782
|
}
|
|
783
|
+
const maxDepth = 6;
|
|
784
|
+
function getTypeIcon(schemaType) {
|
|
785
|
+
let t = schemaType;
|
|
786
|
+
for (; t; ) {
|
|
787
|
+
if (t.icon) return t.icon;
|
|
788
|
+
t = t.type;
|
|
789
|
+
}
|
|
790
|
+
return isType(schemaType, "slug") ? LinkIcon : isType(schemaType, "image") ? ImageIcon : schemaType.jsonType === "array" && isPortableTextArray(schemaType) ? BlockContentIcon : schemaType.jsonType === "array" ? OlistIcon : schemaType.jsonType === "object" ? BlockquoteIcon : schemaType.jsonType === "string" ? StringIcon : DocumentIcon;
|
|
791
|
+
}
|
|
792
|
+
function asFieldRefsByTypePath(fieldRefs) {
|
|
793
|
+
return fieldRefs.reduce(
|
|
794
|
+
(acc, ref) => ({ ...acc, [ref.key]: ref }),
|
|
795
|
+
{}
|
|
796
|
+
);
|
|
797
|
+
}
|
|
798
|
+
function getDocumentFieldRef(schemaType) {
|
|
799
|
+
return {
|
|
800
|
+
key: documentRootKey,
|
|
801
|
+
icon: schemaType.icon ?? DocumentIcon,
|
|
802
|
+
title: "The entire document",
|
|
803
|
+
path: [],
|
|
804
|
+
schemaType
|
|
805
|
+
};
|
|
806
|
+
}
|
|
807
|
+
function getFieldRefs(schemaType, parent, depth = 0) {
|
|
808
|
+
return depth >= maxDepth ? [] : schemaType.fields.filter((f) => !f.name.startsWith("_")).flatMap((field) => {
|
|
809
|
+
const path = parent ? [...parent.path, field.name] : [field.name], title = field.type.title ?? field.name, fieldRef = {
|
|
810
|
+
key: patchableKey(pathToString(path)),
|
|
811
|
+
path,
|
|
812
|
+
title: parent ? [parent.title, title].join(" / ") : title,
|
|
813
|
+
schemaType: field.type,
|
|
814
|
+
icon: getTypeIcon(field.type)
|
|
815
|
+
}, fields = field.type.jsonType === "object" ? getFieldRefs(field.type, fieldRef, depth + 1) : [], syntheticFields = field.type.jsonType === "array" ? getSyntheticFields(field.type, fieldRef, depth + 1) : [];
|
|
816
|
+
return isAssistSupported(field.type) ? [fieldRef, ...fields, ...syntheticFields] : [...fields, ...syntheticFields];
|
|
817
|
+
});
|
|
818
|
+
}
|
|
819
|
+
function getSyntheticFields(schemaType, parent, depth = 0) {
|
|
820
|
+
return depth >= maxDepth ? [] : schemaType.of.filter((itemType) => !isType(itemType, "block")).flatMap((itemType) => {
|
|
821
|
+
const segment = { _key: itemType.name }, title = itemType.title ?? itemType.name, path = parent ? [...parent.path, segment] : [segment], fieldRef = {
|
|
822
|
+
key: patchableKey(pathToString(path)),
|
|
823
|
+
path,
|
|
824
|
+
title: parent ? [parent.title, title].join(" / ") : title,
|
|
825
|
+
schemaType: itemType,
|
|
826
|
+
icon: getTypeIcon(itemType),
|
|
827
|
+
synthetic: !0
|
|
828
|
+
}, fields = itemType.jsonType === "object" ? getFieldRefs(itemType, fieldRef, depth + 1) : [];
|
|
829
|
+
return isAssistSupported(itemType) ? [fieldRef, ...fields] : fields;
|
|
830
|
+
});
|
|
831
|
+
}
|
|
832
|
+
function getTypePath(doc, pathString) {
|
|
833
|
+
if (!pathString)
|
|
834
|
+
return;
|
|
835
|
+
const path = stringToPath(pathString), currentPath = [];
|
|
836
|
+
let valid = !0;
|
|
837
|
+
const syntheticPath = path.map((segment) => {
|
|
838
|
+
if (currentPath.push(segment), isKeySegment(segment)) {
|
|
839
|
+
const match = extractWithPath(pathToString(currentPath), doc)[0], value = match?.value;
|
|
840
|
+
if (match && value && typeof value == "object" && "_type" in value)
|
|
841
|
+
return { _key: value._type };
|
|
842
|
+
valid = !1;
|
|
843
|
+
}
|
|
844
|
+
return segment;
|
|
845
|
+
});
|
|
846
|
+
return valid ? patchableKey(pathToString(syntheticPath)) : void 0;
|
|
847
|
+
}
|
|
848
|
+
function patchableKey(pathKey) {
|
|
849
|
+
return pathKey.replace(/[=]=/g, ":").replace(/[[\]]/g, "|").replace(/"/g, "");
|
|
850
|
+
}
|
|
851
|
+
function useTypePath(doc, pathString) {
|
|
852
|
+
return useMemo(() => getTypePath(doc, pathString), [doc, pathString]);
|
|
853
|
+
}
|
|
854
|
+
function useSelectedField(documentSchemaType, path) {
|
|
855
|
+
const { getFieldRefs: getFieldRefs2 } = useAiAssistanceConfig(), selectableFields = useMemo(
|
|
856
|
+
() => documentSchemaType && isObjectSchemaType(documentSchemaType) ? [getDocumentFieldRef(documentSchemaType), ...getFieldRefs2(documentSchemaType.name)] : [],
|
|
857
|
+
[documentSchemaType, getFieldRefs2]
|
|
858
|
+
);
|
|
859
|
+
return useMemo(() => path ? selectableFields?.find((f) => f.key === path) : void 0, [selectableFields, path]);
|
|
860
|
+
}
|
|
861
|
+
function getFieldTitle(field) {
|
|
862
|
+
const schemaType = field?.schemaType;
|
|
863
|
+
return field?.title ?? schemaType?.title ?? schemaType?.name ?? "Untitled";
|
|
864
|
+
}
|
|
865
|
+
function useAiPaneRouter() {
|
|
866
|
+
const paneRouter = usePaneRouter();
|
|
867
|
+
return useMemo(
|
|
868
|
+
() => ({ ...paneRouter, params: paneRouter.params ?? {} }),
|
|
869
|
+
[paneRouter]
|
|
870
|
+
);
|
|
871
|
+
}
|
|
1025
872
|
function useAssistDocumentContextValue(documentId, documentType) {
|
|
1026
|
-
const schema = useSchema(), documentSchemaType = useMemo(() => {
|
|
873
|
+
const schema = useSchema(), { getFieldRefs: getFieldRefs2, getFieldRefsByTypePath } = useAiAssistanceConfig(), documentSchemaType = useMemo(() => {
|
|
1027
874
|
const schemaType = schema.get(documentType);
|
|
1028
875
|
if (!schemaType)
|
|
1029
876
|
throw new Error(`Schema type "${documentType}" not found`);
|
|
1030
877
|
return schemaType;
|
|
1031
|
-
}, [documentType, schema]), { fieldRefs, fieldRefsByTypePath } = useMemo(() => {
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
fieldRefsByTypePath: fieldRefsByTypePath2
|
|
1036
|
-
};
|
|
1037
|
-
}, [documentSchemaType]), {
|
|
878
|
+
}, [documentType, schema]), { fieldRefs, fieldRefsByTypePath } = useMemo(() => ({
|
|
879
|
+
fieldRefs: getFieldRefs2(documentType),
|
|
880
|
+
fieldRefsByTypePath: getFieldRefsByTypePath(documentType)
|
|
881
|
+
}), [getFieldRefs2, getFieldRefsByTypePath, documentType]), {
|
|
1038
882
|
openInspector,
|
|
1039
883
|
closeInspector,
|
|
1040
884
|
inspector,
|
|
@@ -1601,7 +1445,10 @@ function InspectorOnboarding(props) {
|
|
|
1601
1445
|
] }) }) });
|
|
1602
1446
|
}
|
|
1603
1447
|
function FieldAutocomplete(props) {
|
|
1604
|
-
const { id, schemaType, fieldPath, onSelect, includeDocument, filter: filter2 } = props,
|
|
1448
|
+
const { id, schemaType, fieldPath, onSelect, includeDocument, filter: filter2 } = props, { getFieldRefs: getFieldRefs2 } = useAiAssistanceConfig(), fieldRefs = useMemo(() => {
|
|
1449
|
+
const refs = getFieldRefs2(schemaType.name);
|
|
1450
|
+
return includeDocument ? [getDocumentFieldRef(schemaType), ...refs] : refs;
|
|
1451
|
+
}, [schemaType, includeDocument, getFieldRefs2]), currentField = useMemo(
|
|
1605
1452
|
() => fieldRefs.find((f) => f.key === fieldPath),
|
|
1606
1453
|
[fieldPath, fieldRefs]
|
|
1607
1454
|
), autocompleteOptions = useMemo(
|
|
@@ -2602,6 +2449,195 @@ function FromLanguageRadio(props) {
|
|
|
2602
2449
|
/* @__PURE__ */ jsx(Text, { children: radioLanguage.title ?? radioLanguage.id })
|
|
2603
2450
|
] }, langId);
|
|
2604
2451
|
}
|
|
2452
|
+
const hiddenTypes = [
|
|
2453
|
+
"any",
|
|
2454
|
+
"array",
|
|
2455
|
+
"block",
|
|
2456
|
+
"boolean",
|
|
2457
|
+
"crossDatasetReference",
|
|
2458
|
+
"date",
|
|
2459
|
+
"datetime",
|
|
2460
|
+
"document",
|
|
2461
|
+
"email",
|
|
2462
|
+
"file",
|
|
2463
|
+
"globalDocumentReference",
|
|
2464
|
+
"image",
|
|
2465
|
+
"number",
|
|
2466
|
+
"object",
|
|
2467
|
+
"reference",
|
|
2468
|
+
"span",
|
|
2469
|
+
"string",
|
|
2470
|
+
"text",
|
|
2471
|
+
"url",
|
|
2472
|
+
"slug",
|
|
2473
|
+
"geopoint",
|
|
2474
|
+
"sanity.assetSourceData",
|
|
2475
|
+
"sanity.imageAsset",
|
|
2476
|
+
"sanity.fileAsset",
|
|
2477
|
+
"sanity.imageCrop",
|
|
2478
|
+
"sanity.imageHotspot",
|
|
2479
|
+
"sanity.imageMetadata",
|
|
2480
|
+
"sanity.imageDimensions",
|
|
2481
|
+
"sanity.imagePalette",
|
|
2482
|
+
"sanity.imagePaletteSwatch",
|
|
2483
|
+
assistSerializedTypeName,
|
|
2484
|
+
assistSerializedFieldTypeName,
|
|
2485
|
+
"sanity-agent.job.document"
|
|
2486
|
+
], inlineTypes = ["document", "object", "image", "file"];
|
|
2487
|
+
function serializeSchema(schema, options2) {
|
|
2488
|
+
const list = schema.getTypeNames().filter((t) => !(hiddenTypes.includes(t) || t.startsWith("sanity."))).map((t) => schema.get(t)).filter((t) => !!t).map((t) => getSchemaStub(t, schema, options2)).filter((t) => !("to" in t && t.to && !t.to.length || "of" in t && t.of && !t.of.length || "fields" in t && t.fields && !t.fields.length));
|
|
2489
|
+
return list.sort((a, b) => (a?.name ?? "").localeCompare(b?.name ?? "")), list;
|
|
2490
|
+
}
|
|
2491
|
+
function getSchemaStub(schemaType, schema, options2) {
|
|
2492
|
+
if (!schemaType.type?.name)
|
|
2493
|
+
throw console.error("Missing type name", schemaType.type), new Error("Type is missing name!");
|
|
2494
|
+
const baseSchema = {
|
|
2495
|
+
// we dont need type or id when we send using POST, so leave these out to save bandwidth
|
|
2496
|
+
...options2?.leanFormat ? {} : { _id: `${assistSchemaIdPrefix}${schemaType.name}`, _type: assistSerializedTypeName },
|
|
2497
|
+
name: schemaType.name,
|
|
2498
|
+
title: schemaType.title,
|
|
2499
|
+
type: schemaType.type.name,
|
|
2500
|
+
...getBaseFields(schema, schemaType, schemaType.type.name, options2)
|
|
2501
|
+
};
|
|
2502
|
+
return removeUndef(baseSchema);
|
|
2503
|
+
}
|
|
2504
|
+
function getBaseFields(schema, type, typeName, options2) {
|
|
2505
|
+
const schemaOptions = removeUndef({
|
|
2506
|
+
imagePromptField: type.options?.aiAssist?.imageInstructionField,
|
|
2507
|
+
embeddingsIndex: type.options?.aiAssist?.embeddingsIndex
|
|
2508
|
+
});
|
|
2509
|
+
return removeUndef({
|
|
2510
|
+
options: Object.keys(schemaOptions).length ? schemaOptions : void 0,
|
|
2511
|
+
values: Array.isArray(type?.options?.list) ? type?.options?.list.map(
|
|
2512
|
+
(v) => typeof v == "string" ? v : v.value ?? `${v.title}`
|
|
2513
|
+
) : void 0,
|
|
2514
|
+
of: "of" in type && typeName === "array" ? arrayOf(type, schema, options2) : void 0,
|
|
2515
|
+
to: "to" in type && typeName === "reference" ? refToTypeNames(type) : void 0,
|
|
2516
|
+
fields: "fields" in type && inlineTypes.includes(typeName) ? serializeFields(schema, type, options2) : void 0,
|
|
2517
|
+
annotations: typeName === "block" && "fields" in type ? serializeAnnotations(type, schema, options2) : void 0,
|
|
2518
|
+
inlineOf: typeName === "block" && "fields" in type ? serializeInlineOf(type, schema, options2) : void 0,
|
|
2519
|
+
hidden: typeof type.hidden == "function" ? "function" : type.hidden ? !0 : void 0,
|
|
2520
|
+
readOnly: typeof type.readOnly == "function" ? "function" : type.readOnly ? !0 : void 0
|
|
2521
|
+
});
|
|
2522
|
+
}
|
|
2523
|
+
function serializeFields(schema, schemaType, options2) {
|
|
2524
|
+
return (schemaType.fieldsets ? schemaType.fieldsets.flatMap(
|
|
2525
|
+
(fs) => fs.single ? fs.field : fs.fields.map((f) => ({
|
|
2526
|
+
...f,
|
|
2527
|
+
type: {
|
|
2528
|
+
...f.type,
|
|
2529
|
+
// if fieldset is (conditionally) hidden, the field must be considered the same way
|
|
2530
|
+
// ie, if the field does not show up in conditionalMembers, it is hidden
|
|
2531
|
+
// regardless of weather or not it is the field function or the fieldset function that hides it
|
|
2532
|
+
hidden: typeof fs.hidden == "function" ? fs.hidden : fs.hidden ? !0 : f.type.hidden
|
|
2533
|
+
}
|
|
2534
|
+
}))
|
|
2535
|
+
) : schemaType.fields).filter((f) => !["sanity.imageHotspot", "sanity.imageCrop"].includes(f.type?.name ?? "")).filter((f) => isAssistSupported(f.type)).map((field) => serializeMember(schema, field.type, field.name, options2));
|
|
2536
|
+
}
|
|
2537
|
+
function serializeMember(schema, type, name, options2) {
|
|
2538
|
+
const typeName = schema.get(type?.name) ? type.name : type.type?.name ?? "";
|
|
2539
|
+
return removeUndef({
|
|
2540
|
+
...options2?.leanFormat ? {} : { _type: assistSerializedFieldTypeName },
|
|
2541
|
+
name,
|
|
2542
|
+
type: typeName,
|
|
2543
|
+
title: type.title,
|
|
2544
|
+
...getBaseFields(schema, type, typeName, options2)
|
|
2545
|
+
});
|
|
2546
|
+
}
|
|
2547
|
+
function serializeInlineOf(blockSchemaType, schema, options2) {
|
|
2548
|
+
const childrenType = blockSchemaType.fields.find((f) => f.name === "children")?.type;
|
|
2549
|
+
if (!(!childrenType || !isArraySchemaType(childrenType)))
|
|
2550
|
+
return arrayOf(
|
|
2551
|
+
{
|
|
2552
|
+
of: childrenType.of.filter((t) => !isType(t, "span"))
|
|
2553
|
+
},
|
|
2554
|
+
schema,
|
|
2555
|
+
options2
|
|
2556
|
+
);
|
|
2557
|
+
}
|
|
2558
|
+
function serializeAnnotations(blockSchemaType, schema, options2) {
|
|
2559
|
+
const marksType = blockSchemaType.fields.find((f) => f.name === "markDefs")?.type;
|
|
2560
|
+
if (!(!marksType || !isArraySchemaType(marksType)))
|
|
2561
|
+
return arrayOf(marksType, schema, options2);
|
|
2562
|
+
}
|
|
2563
|
+
function arrayOf(arrayType, schema, options2) {
|
|
2564
|
+
return arrayType.of.filter((type) => isAssistSupported(type)).map((t) => serializeMember(schema, t, t.name, options2));
|
|
2565
|
+
}
|
|
2566
|
+
function refToTypeNames(type) {
|
|
2567
|
+
return type.to.map((t) => ({
|
|
2568
|
+
type: typed(t.name)
|
|
2569
|
+
}));
|
|
2570
|
+
}
|
|
2571
|
+
function removeUndef(obj) {
|
|
2572
|
+
return Object.keys(obj).forEach((key) => obj[key] === void 0 ? delete obj[key] : {}), obj;
|
|
2573
|
+
}
|
|
2574
|
+
function createFieldRefCache() {
|
|
2575
|
+
const byType = {};
|
|
2576
|
+
function getRefsForType(schemaType) {
|
|
2577
|
+
const documentType = schemaType.name, cached = byType[documentType];
|
|
2578
|
+
if (cached) return cached;
|
|
2579
|
+
const fieldRefs = getFieldRefs(schemaType), fieldRefsByTypePath = asFieldRefsByTypePath(fieldRefs), refs = {
|
|
2580
|
+
fieldRefs,
|
|
2581
|
+
fieldRefsByTypePath
|
|
2582
|
+
};
|
|
2583
|
+
return byType[documentType] = refs, refs;
|
|
2584
|
+
}
|
|
2585
|
+
return getRefsForType;
|
|
2586
|
+
}
|
|
2587
|
+
function AiAssistanceConfigProvider(props) {
|
|
2588
|
+
const [status, setStatus] = useState(), [error, setError] = useState(), apiClient = useApiClient(props.config?.__customApiClient), { getInstructStatus, loading: statusLoading } = useGetInstructStatus(apiClient), { initInstruct, loading: initLoading } = useInitInstruct(apiClient), schema = useSchema(), serializedTypes = useMemo(() => serializeSchema(schema, { leanFormat: !0 }), [schema]), { getFieldRefs: getFieldRefs2, getFieldRefsByTypePath } = useFieldRefGetters(schema);
|
|
2589
|
+
useEffect(() => {
|
|
2590
|
+
getInstructStatus().then((s) => setStatus(s)).catch((e) => {
|
|
2591
|
+
console.error(e), setError(e);
|
|
2592
|
+
});
|
|
2593
|
+
}, [getInstructStatus]);
|
|
2594
|
+
const init = useCallback(async () => {
|
|
2595
|
+
setError(void 0);
|
|
2596
|
+
try {
|
|
2597
|
+
await initInstruct();
|
|
2598
|
+
const status2 = await getInstructStatus();
|
|
2599
|
+
setStatus(status2);
|
|
2600
|
+
} catch (e) {
|
|
2601
|
+
console.error("Failed to init ai assistance", e), setError(e);
|
|
2602
|
+
}
|
|
2603
|
+
}, [initInstruct, getInstructStatus, setStatus]), { config, children } = props, context = useMemo(() => ({
|
|
2604
|
+
config,
|
|
2605
|
+
status,
|
|
2606
|
+
statusLoading,
|
|
2607
|
+
init,
|
|
2608
|
+
initLoading,
|
|
2609
|
+
error,
|
|
2610
|
+
serializedTypes,
|
|
2611
|
+
getFieldRefs: getFieldRefs2,
|
|
2612
|
+
getFieldRefsByTypePath
|
|
2613
|
+
}), [
|
|
2614
|
+
config,
|
|
2615
|
+
status,
|
|
2616
|
+
init,
|
|
2617
|
+
statusLoading,
|
|
2618
|
+
initLoading,
|
|
2619
|
+
error,
|
|
2620
|
+
serializedTypes,
|
|
2621
|
+
getFieldRefs2,
|
|
2622
|
+
getFieldRefsByTypePath
|
|
2623
|
+
]);
|
|
2624
|
+
return /* @__PURE__ */ jsx(AiAssistanceConfigContext.Provider, { value: context, children });
|
|
2625
|
+
}
|
|
2626
|
+
function useFieldRefGetters(schema) {
|
|
2627
|
+
return useMemo(() => {
|
|
2628
|
+
const getForSchemaType = createFieldRefCache();
|
|
2629
|
+
function getRefsForType(documentType) {
|
|
2630
|
+
const schemaType = schema.get(documentType);
|
|
2631
|
+
if (!schemaType)
|
|
2632
|
+
throw new Error(`Schema type "${documentType}" not found`);
|
|
2633
|
+
return getForSchemaType(schemaType);
|
|
2634
|
+
}
|
|
2635
|
+
return {
|
|
2636
|
+
getFieldRefs: (documentType) => getRefsForType(documentType).fieldRefs,
|
|
2637
|
+
getFieldRefsByTypePath: (documentType) => getRefsForType(documentType).fieldRefsByTypePath
|
|
2638
|
+
};
|
|
2639
|
+
}, [schema]);
|
|
2640
|
+
}
|
|
2605
2641
|
function AssistLayout(props) {
|
|
2606
2642
|
const [connectors, setConnectors] = useState([]);
|
|
2607
2643
|
return /* @__PURE__ */ jsx(AiAssistanceConfigProvider, { config: props.config, children: /* @__PURE__ */ jsx(RunInstructionProvider, { children: /* @__PURE__ */ jsx(FieldTranslationProvider, { children: /* @__PURE__ */ jsxs(ConnectorsProvider, { onConnectorsChange: setConnectors, children: [
|
|
@@ -3187,7 +3223,7 @@ function BackToInstructionListLink() {
|
|
|
3187
3223
|
}
|
|
3188
3224
|
) });
|
|
3189
3225
|
}
|
|
3190
|
-
const EMPTY_FIELDS = [];
|
|
3226
|
+
const SelectedFieldContext = createContext(void 0), SelectedFieldContextProvider = SelectedFieldContext.Provider, EMPTY_FIELDS = [];
|
|
3191
3227
|
function AssistDocumentForm(props) {
|
|
3192
3228
|
return props.readOnly ? /* @__PURE__ */ jsx(Card, { border: !0, tone: "caution", padding: 2, children: /* @__PURE__ */ jsx(Text, { size: 1, children: " You do not have sufficient permissions to manage instructions." }) }) : /* @__PURE__ */ jsx(AssistDocumentFormEditable, { ...props });
|
|
3193
3229
|
}
|
|
@@ -3687,19 +3723,25 @@ const contextDocumentSchema = defineType({
|
|
|
3687
3723
|
components: {
|
|
3688
3724
|
input: FieldRefPathInput
|
|
3689
3725
|
},
|
|
3690
|
-
validation: (rule) =>
|
|
3691
|
-
|
|
3692
|
-
|
|
3693
|
-
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
|
|
3702
|
-
|
|
3726
|
+
validation: (rule) => {
|
|
3727
|
+
const getForSchemaType = createFieldRefCache();
|
|
3728
|
+
return rule.custom((value, context) => {
|
|
3729
|
+
if (!value)
|
|
3730
|
+
return "Please select a field";
|
|
3731
|
+
try {
|
|
3732
|
+
const docId = context.document?._id;
|
|
3733
|
+
if (!docId)
|
|
3734
|
+
return "Field reference cannot be used outside document inspector context. Could not resolve document id.";
|
|
3735
|
+
const targetDocType = docId.replace(new RegExp(`^${assistDocumentIdPrefix}`), ""), schema = context.schema.get(targetDocType);
|
|
3736
|
+
if (!schema)
|
|
3737
|
+
return `Field reference cannot be used outside document inspector context. Could not resolve schema: ${targetDocType}`;
|
|
3738
|
+
const { fieldRefs } = getForSchemaType(schema);
|
|
3739
|
+
return fieldRefs.find((r) => r.key === value) ? !0 : `Field with path "${value}" does not exist in the schema.`;
|
|
3740
|
+
} catch (e) {
|
|
3741
|
+
return console.error("Failed to resolve field reference", e), "Invalid field reference.";
|
|
3742
|
+
}
|
|
3743
|
+
});
|
|
3744
|
+
}
|
|
3703
3745
|
})
|
|
3704
3746
|
],
|
|
3705
3747
|
preview: {
|