@sanity/assist 3.0.5 → 3.0.6

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.esm.js CHANGED
@@ -1,8 +1,8 @@
1
1
  import { jsx, jsxs, Fragment } from "react/jsx-runtime";
2
- import { SyncIcon, DocumentIcon, LinkIcon, ImageIcon, BlockContentIcon, OlistIcon, BlockquoteIcon, StringIcon, ArrowLeftIcon, PlayIcon, SparklesIcon, SearchIcon, ErrorOutlineIcon, CheckmarkCircleIcon, CloseCircleIcon, ClockIcon, RetryIcon, ArrowRightIcon, CloseIcon, CheckmarkIcon, icons, TokenIcon, DocumentTextIcon, ThListIcon, CodeIcon, ComposeIcon, LockIcon, TranslateIcon, ControlsIcon } from "@sanity/icons";
2
+ import { SyncIcon, PlayIcon, SparklesIcon, DocumentIcon, LinkIcon, ImageIcon, BlockContentIcon, OlistIcon, BlockquoteIcon, StringIcon, SearchIcon, ErrorOutlineIcon, CheckmarkCircleIcon, CloseCircleIcon, ClockIcon, RetryIcon, ArrowRightIcon, CloseIcon, CheckmarkIcon, ArrowLeftIcon, icons, TokenIcon, DocumentTextIcon, ThListIcon, CodeIcon, ComposeIcon, LockIcon, TranslateIcon, ControlsIcon } from "@sanity/icons";
3
3
  import { Card, Stack, Box, Button, Spinner, Flex, Label, focusFirstDescendant, Text, useToast, Dialog, Tooltip, TextArea, Container, Autocomplete, Breadcrumbs, useClickOutside, Popover, useLayer, useGlobalKeyDown, Badge, useTheme, rgba, Checkbox, Radio, ThemeProvider, ErrorBoundary, MenuButton, Menu, MenuItem, Switch } from "@sanity/ui";
4
4
  import { useState, useRef, useEffect, useMemo, useCallback, createContext, useContext, useId, createElement, useReducer, forwardRef } from "react";
5
- import { useClient, isArraySchemaType, typed, useSchema, isKeySegment, isDocumentSchemaType, pathToString, useDocumentStore, useDocumentPresence, createPatchChannel, FormBuilder, fromMutationPatches, isObjectSchemaType, stringToPath, useCurrentUser, set, useFormCallbacks, FormCallbacksProvider, FormInput, PatchEvent, setIfMissing, insert, useEditState, FormFieldHeaderText, unset, StatusButton, PresenceOverlay, VirtualizerScrollInstanceProvider, useColorSchemeValue, ObjectInputMember, isArrayOfObjectsSchemaType, defineType, defineField, defineArrayMember, getPublishedId, useSyncState, definePlugin } from "sanity";
5
+ import { useClient, isArraySchemaType, typed, useSchema, isKeySegment, isDocumentSchemaType, pathToString, useDocumentStore, useDocumentPresence, createPatchChannel, FormBuilder, fromMutationPatches, useEditState, useCurrentUser, FormFieldHeaderText, PatchEvent, unset, isObjectSchemaType, stringToPath, StatusButton, PresenceOverlay, VirtualizerScrollInstanceProvider, useColorSchemeValue, useFormCallbacks, set, FormCallbacksProvider, FormInput, setIfMissing, insert, ObjectInputMember, isArrayOfObjectsSchemaType, defineType, defineField, defineArrayMember, getPublishedId, useSyncState, definePlugin } from "sanity";
6
6
  import isEqual from "react-fast-compare";
7
7
  import { mergeMap, share, take, filter, distinctUntilChanged, catchError, tap } from "rxjs/operators";
8
8
  import { throwError, of, partition, merge, switchMap, delay, defer } from "rxjs";
@@ -482,100 +482,81 @@ function prepareRebaseEvent(event) {
482
482
  )
483
483
  };
484
484
  }
485
- const SelectedFieldContext = createContext(void 0), SelectedFieldContextProvider = SelectedFieldContext.Provider, maxDepth = 6;
486
- function getTypeIcon(schemaType) {
487
- let t = schemaType;
488
- for (; t; ) {
489
- if (t.icon)
490
- return t.icon;
491
- t = t.type;
492
- }
493
- 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;
494
- }
495
- function getFieldRefsWithDocument(schemaType) {
496
- var _a;
497
- const fields = getFieldRefs(schemaType);
498
- return [
499
- {
500
- key: documentRootKey,
501
- icon: (_a = schemaType.icon) != null ? _a : DocumentIcon,
502
- title: "The entire document",
503
- path: [],
504
- schemaType
505
- },
506
- ...fields
507
- ];
485
+ const AssistTypeContext = createContext({}), illegalIdChars = /[^a-zA-Z0-9._-]/g;
486
+ function publicId(id) {
487
+ return id.replace("drafts.", "");
508
488
  }
509
- function getFieldRefs(schemaType, parent, depth = 0) {
510
- return depth >= maxDepth ? [] : schemaType.fields.filter((f) => !f.name.startsWith("_")).flatMap((field) => {
511
- var _a;
512
- const path = parent ? [...parent.path, field.name] : [field.name], title = (_a = field.type.title) != null ? _a : field.name, fieldRef = {
513
- key: patchableKey(pathToString(path)),
514
- path,
515
- title: parent ? [parent.title, title].join(" / ") : title,
516
- schemaType: field.type,
517
- icon: getTypeIcon(field.type)
518
- }, fields = field.type.jsonType === "object" ? getFieldRefs(field.type, fieldRef, depth + 1) : [], syntheticFields = field.type.jsonType === "array" ? getSyntheticFields(field.type, fieldRef, depth + 1) : [];
519
- return isAssistSupported(field.type) ? [fieldRef, ...fields, ...syntheticFields] : [...fields, ...syntheticFields];
520
- });
489
+ function assistDocumentId(documentType) {
490
+ return `${assistDocumentIdPrefix}${documentType}`.replace(illegalIdChars, "_");
521
491
  }
522
- function getSyntheticFields(schemaType, parent, depth = 0) {
523
- return depth >= maxDepth ? [] : schemaType.of.filter((itemType) => !isType(itemType, "block")).flatMap((itemType) => {
524
- var _a;
525
- const segment = { _key: itemType.name }, title = (_a = itemType.title) != null ? _a : itemType.name, path = parent ? [...parent.path, segment] : [segment], fieldRef = {
526
- key: patchableKey(pathToString(path)),
527
- path,
528
- title: parent ? [parent.title, title].join(" / ") : title,
529
- schemaType: itemType,
530
- icon: getTypeIcon(itemType),
531
- synthetic: !0
532
- }, fields = itemType.jsonType === "object" ? getFieldRefs(itemType, fieldRef, depth + 1) : [];
533
- return isAssistSupported(itemType) ? [fieldRef, ...fields] : fields;
534
- });
492
+ function assistTasksStatusId(documentId) {
493
+ return `${assistDocumentStatusIdPrefix}${publicId(documentId)}`;
535
494
  }
536
- function getTypePath(doc, pathString) {
537
- if (!pathString)
538
- return;
539
- const path = stringToPath(pathString), currentPath = [];
540
- let valid = !0;
541
- const syntheticPath = path.map((segment) => {
542
- if (currentPath.push(segment), isKeySegment(segment)) {
543
- const match = extractWithPath(pathToString(currentPath), doc)[0], value = match == null ? void 0 : match.value;
544
- if (match && value && typeof value == "object" && "_type" in value)
545
- return { _key: value._type };
546
- valid = !1;
547
- }
548
- return segment;
549
- });
550
- return valid ? patchableKey(pathToString(syntheticPath)) : void 0;
495
+ function useDocumentState(id, docType) {
496
+ const state = useEditState(id, docType);
497
+ return state.draft || state.published;
551
498
  }
552
- function patchableKey(pathKey) {
553
- return pathKey.replace(/[=]=/g, ":").replace(/[[\]]/g, "|").replace(/"/g, "");
499
+ function useStudioAssistDocument({
500
+ documentId,
501
+ schemaType,
502
+ initDoc
503
+ }) {
504
+ const documentTypeName = schemaType.name, currentUser = useCurrentUser(), assistDocument = useDocumentState(
505
+ assistDocumentId(documentTypeName),
506
+ assistDocumentTypeName
507
+ ), assistTasksStatus = useDocumentState(
508
+ assistTasksStatusId(documentId != null ? documentId : ""),
509
+ assistTasksStatusTypeName
510
+ ), client = useClient({ apiVersion: "2023-01-01" });
511
+ return useEffect(() => {
512
+ !assistDocument && initDoc && client.createIfNotExists({
513
+ _id: assistDocumentId(documentTypeName),
514
+ _type: assistDocumentTypeName
515
+ }).catch(() => {
516
+ });
517
+ }, [client, assistDocument, documentTypeName, initDoc]), useMemo(() => {
518
+ var _a, _b;
519
+ if (!assistDocument)
520
+ return;
521
+ const tasks = (_a = assistTasksStatus == null ? void 0 : assistTasksStatus.tasks) != null ? _a : [], fields = ((_b = assistDocument == null ? void 0 : assistDocument.fields) != null ? _b : []).map((assistField) => {
522
+ var _a2;
523
+ return {
524
+ ...assistField,
525
+ tasks: tasks.filter((task) => task.path === assistField.path),
526
+ instructions: (_a2 = assistField.instructions) == null ? void 0 : _a2.filter((p) => !p.userId || p.userId === (currentUser == null ? void 0 : currentUser.id)).map((instruction2) => asStudioInstruction(instruction2, tasks))
527
+ };
528
+ });
529
+ return typed({
530
+ ...assistDocument,
531
+ tasks: tasks == null ? void 0 : tasks.map((task) => {
532
+ var _a2, _b2;
533
+ const instruction2 = (_b2 = (_a2 = fields.find((f) => f.path === task.path)) == null ? void 0 : _a2.instructions) == null ? void 0 : _b2.find((i) => i._key === task.instructionKey);
534
+ return {
535
+ ...task,
536
+ instruction: instruction2
537
+ };
538
+ }),
539
+ fields
540
+ });
541
+ }, [assistDocument, assistTasksStatus, currentUser]);
554
542
  }
555
- function useTypePath(doc, pathString) {
556
- return useMemo(() => getTypePath(doc, pathString), [doc, pathString]);
543
+ function asStudioInstruction(instruction2, run) {
544
+ return {
545
+ ...instruction2,
546
+ tasks: run.filter((task) => task.instructionKey === instruction2._key).filter(
547
+ (task) => task.started && (/* @__PURE__ */ new Date()).getTime() - new Date(task.started).getTime() < maxHistoryVisibilityMs
548
+ )
549
+ };
557
550
  }
558
- function useSelectedField(documentSchemaType, path) {
559
- const selectableFields = useMemo(
560
- () => documentSchemaType && isObjectSchemaType(documentSchemaType) ? getFieldRefsWithDocument(documentSchemaType) : [],
561
- [documentSchemaType]
562
- );
563
- return useMemo(() => path ? selectableFields == null ? void 0 : selectableFields.find((f) => f.key === path) : void 0, [selectableFields, path]);
551
+ function usePathKey(path) {
552
+ return useMemo(() => getPathKey(path), [path]);
564
553
  }
565
- function getFieldTitle(field) {
566
- var _a, _b, _c;
567
- const schemaType = field == null ? void 0 : field.schemaType;
568
- return (_c = (_b = (_a = field == null ? void 0 : field.title) != null ? _a : schemaType == null ? void 0 : schemaType.title) != null ? _b : schemaType == null ? void 0 : schemaType.name) != null ? _c : "Untitled";
554
+ function getPathKey(path) {
555
+ return path.length ? Array.isArray(path) ? pathToString(path) : path : documentRootKey;
569
556
  }
570
- function useAiPaneRouter() {
571
- const paneRouter = usePaneRouter();
572
- return useMemo(
573
- () => {
574
- var _a;
575
- return { ...paneRouter, params: (_a = paneRouter.params) != null ? _a : {} };
576
- },
577
- [paneRouter]
578
- );
557
+ function getInstructionTitle(instruction2) {
558
+ var _a;
559
+ return (_a = instruction2 == null ? void 0 : instruction2.title) != null ? _a : "Untitled";
579
560
  }
580
561
  const basePath = "/assist/tasks/instruction";
581
562
  function canUseAssist(status) {
@@ -779,252 +760,12 @@ function AiAssistanceConfigProvider(props) {
779
760
  }, [initInstruct, getInstructStatus, setStatus]), { config, children } = props, context = useMemo(() => ({
780
761
  config,
781
762
  status,
782
- statusLoading,
783
- init,
784
- initLoading,
785
- error
786
- }), [config, status, init, statusLoading, initLoading, error]);
787
- return /* @__PURE__ */ jsx(AiAssistanceConfigContext.Provider, { value: context, children });
788
- }
789
- const aiDocPrefixPattern = new RegExp(`^${assistDocumentIdPrefix}`);
790
- function publicId(id) {
791
- return id.replace("drafts.", "");
792
- }
793
- function assistDocumentId(documentType) {
794
- return `${assistDocumentIdPrefix}${documentType}`;
795
- }
796
- function documentTypeFromAiDocumentId(id) {
797
- return id.replace(aiDocPrefixPattern, "");
798
- }
799
- function assistTasksStatusId(documentId) {
800
- return `${assistDocumentStatusIdPrefix}${publicId(documentId)}`;
801
- }
802
- const aiInspectorId = "ai-assistance";
803
- function BackToInstructionListLink() {
804
- const { openInspector } = useDocumentPane(), goBack = useCallback(
805
- () => openInspector(aiInspectorId, { [instructionParam]: void 0 }),
806
- [openInspector]
807
- );
808
- return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
809
- Button,
810
- {
811
- as: "a",
812
- fontSize: 1,
813
- icon: ArrowLeftIcon,
814
- mode: "bleed",
815
- padding: 1,
816
- space: 2,
817
- onClick: goBack,
818
- text: " Instructions",
819
- textAlign: "left"
820
- }
821
- ) });
822
- }
823
- const EMPTY_FIELDS = [], TypePathContext = createContext(void 0);
824
- function AssistDocumentForm(props) {
825
- 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 });
826
- }
827
- function AssistDocumentFormEditable(props) {
828
- const { onChange } = props, value = props.value, id = value == null ? void 0 : value._id, fields = value == null ? void 0 : value.fields, targetDocumentType = useMemo(() => {
829
- if (id)
830
- return documentTypeFromAiDocumentId(id);
831
- }, [id]), { params, setParams } = useAiPaneRouter(), pathKey = params[fieldPathParam], typePath = useContext(TypePathContext), instruction2 = params[instructionParam], activeKey = useMemo(() => {
832
- var _a;
833
- if (typePath)
834
- return (_a = (fields != null ? fields : EMPTY_FIELDS).find((f) => f.path === typePath)) == null ? void 0 : _a._key;
835
- }, [fields, typePath]), activePath = useMemo(() => {
836
- if (!activeKey)
837
- return;
838
- const base = ["fields", { _key: activeKey }];
839
- return instruction2 ? [...base, "instructions", { _key: instruction2 }] : base;
840
- }, [activeKey, instruction2]), schema = useSchema(), documentSchema = useMemo(() => {
841
- if (targetDocumentType)
842
- return schema.get(targetDocumentType);
843
- }, [schema, targetDocumentType]), fieldSchema = useSelectedSchema(pathKey, documentSchema), context = useMemo(
844
- () => ({
845
- documentSchema,
846
- fieldSchema: fieldSchema != null ? fieldSchema : documentSchema
847
- }),
848
- [fieldSchema, documentSchema]
849
- ), title = value == null ? void 0 : value.title;
850
- useEffect(() => {
851
- var _a;
852
- !title && documentSchema && !(id != null && id.startsWith("drafts.")) && onChange(set((_a = documentSchema.title) != null ? _a : documentSchema.name, ["title"]));
853
- }, [title, documentSchema, onChange, id]);
854
- const { onPathOpen, ...formCallbacks } = useFormCallbacks(), newCallbacks = useMemo(
855
- () => ({
856
- ...formCallbacks,
857
- onPathOpen: (path) => {
858
- var _a;
859
- !instruction2 && path.length === 4 && path[2] === "instructions" ? (setParams(
860
- typed({
861
- ...params,
862
- [instructionParam]: (_a = path[3]) == null ? void 0 : _a._key
863
- })
864
- ), onPathOpen([])) : setTimeout(() => onPathOpen(path), 0);
865
- }
866
- }),
867
- [formCallbacks, onPathOpen, params, setParams, instruction2]
868
- );
869
- return useEffect(() => {
870
- activePath && !instruction2 && onPathOpen([]);
871
- }, [activePath, instruction2, onPathOpen]), /* @__PURE__ */ jsx(SelectedFieldContextProvider, { value: context, children: /* @__PURE__ */ jsxs(Stack, { space: 5, children: [
872
- /* @__PURE__ */ jsx(
873
- FieldsInitializer,
874
- {
875
- pathKey: typePath,
876
- activePath,
877
- fields,
878
- documentSchema,
879
- onChange
880
- },
881
- typePath
882
- ),
883
- instruction2 && /* @__PURE__ */ jsx(BackToInstructionListLink, {}),
884
- activePath && /* @__PURE__ */ jsx(FormCallbacksProvider, { ...newCallbacks, children: /* @__PURE__ */ jsx("div", { style: { lineHeight: "1.25em" }, children: /* @__PURE__ */ jsx(FormInput, { ...props, absolutePath: activePath }) }) }),
885
- !activePath && props.renderDefault(props)
886
- ] }) });
887
- }
888
- function useSelectedSchema(fieldPath, documentSchema) {
889
- return useMemo(() => {
890
- if (!fieldPath)
891
- return;
892
- if (fieldPath === documentRootKey)
893
- return documentSchema;
894
- const path = stringToPath(fieldPath);
895
- let currentSchema = documentSchema;
896
- for (let i = 0; i < path.length; i++) {
897
- const segment = path[i], field = currentSchema == null ? void 0 : currentSchema.fields.find((f) => f.name === segment);
898
- if (!field)
899
- return;
900
- if (i === path.length - 1)
901
- return field.type;
902
- if (field.type.jsonType !== "object")
903
- return;
904
- currentSchema = field.type;
905
- }
906
- return currentSchema;
907
- }, [documentSchema, fieldPath]);
908
- }
909
- function FieldsInitializer({
910
- pathKey,
911
- activePath,
912
- fields,
913
- documentSchema,
914
- onChange
915
- }) {
916
- const {
917
- config: { __presets: presets }
918
- } = useAiAssistanceConfig(), existingField = fields == null ? void 0 : fields.find((f) => f._key === pathKey), documentPresets = !!(documentSchema != null && documentSchema.name) && (presets == null ? void 0 : presets[documentSchema == null ? void 0 : documentSchema.name]), missingPresetInstructions = useMemo(() => {
919
- var _a, _b;
920
- if (!documentPresets || !pathKey)
921
- return;
922
- const existingInstructions = existingField == null ? void 0 : existingField.instructions, presetField = (_a = documentPresets.fields) == null ? void 0 : _a.find((f) => f.path === pathKey);
923
- return (_b = presetField == null ? void 0 : presetField.instructions) == null ? void 0 : _b.filter(
924
- (i) => !(existingInstructions != null && existingInstructions.some((ei) => ei._key === i._key))
925
- );
926
- }, [documentPresets, pathKey, existingField]), initialized = useRef(!1);
927
- return useEffect(() => {
928
- var _a;
929
- if (initialized.current || !pathKey || existingField && !(missingPresetInstructions != null && missingPresetInstructions.length))
930
- return;
931
- let event = PatchEvent.from([setIfMissing([], ["fields"])]);
932
- existingField || (event = event.append(
933
- insert(
934
- [
935
- typed({
936
- _key: pathKey,
937
- _type: assistFieldTypeName,
938
- path: pathKey,
939
- instructions: []
940
- })
941
- ],
942
- "after",
943
- ["fields", -1]
944
- )
945
- )), (_a = existingField == null ? void 0 : existingField.instructions) != null && _a.length || (event = event.append([setIfMissing([], ["fields", { _key: pathKey }, "instructions"])])), missingPresetInstructions != null && missingPresetInstructions.length && (event = event.append(
946
- insert(
947
- missingPresetInstructions.map(
948
- (preset) => {
949
- var _a2;
950
- return {
951
- ...preset,
952
- _type: "sanity.assist.instruction",
953
- prompt: (_a2 = preset.prompt) == null ? void 0 : _a2.map((p) => ({ markDefs: [], ...p }))
954
- };
955
- }
956
- ),
957
- "after",
958
- ["fields", { _key: pathKey }, "instructions", -1]
959
- )
960
- )), onChange(event), initialized.current = !0;
961
- }, [activePath, onChange, pathKey, existingField, missingPresetInstructions]), null;
962
- }
963
- function useDocumentState(id, docType) {
964
- const state = useEditState(id, docType);
965
- return state.draft || state.published;
966
- }
967
- function useStudioAssistDocument({
968
- documentId,
969
- schemaType,
970
- initDoc
971
- }) {
972
- const documentTypeName = schemaType.name, currentUser = useCurrentUser(), assistDocument = useDocumentState(
973
- assistDocumentId(documentTypeName),
974
- assistDocumentTypeName
975
- ), assistTasksStatus = useDocumentState(
976
- assistTasksStatusId(documentId != null ? documentId : ""),
977
- assistTasksStatusTypeName
978
- ), client = useClient({ apiVersion: "2023-01-01" });
979
- return useEffect(() => {
980
- !assistDocument && initDoc && client.createIfNotExists({
981
- _id: assistDocumentId(documentTypeName),
982
- _type: assistDocumentTypeName
983
- }).catch(() => {
984
- });
985
- }, [client, assistDocument, documentTypeName, initDoc]), useMemo(() => {
986
- var _a, _b;
987
- if (!assistDocument)
988
- return;
989
- const tasks = (_a = assistTasksStatus == null ? void 0 : assistTasksStatus.tasks) != null ? _a : [], fields = ((_b = assistDocument == null ? void 0 : assistDocument.fields) != null ? _b : []).map((assistField) => {
990
- var _a2;
991
- return {
992
- ...assistField,
993
- tasks: tasks.filter((task) => task.path === assistField.path),
994
- instructions: (_a2 = assistField.instructions) == null ? void 0 : _a2.filter((p) => !p.userId || p.userId === (currentUser == null ? void 0 : currentUser.id)).map((instruction2) => asStudioInstruction(instruction2, tasks))
995
- };
996
- });
997
- return typed({
998
- ...assistDocument,
999
- tasks: tasks == null ? void 0 : tasks.map((task) => {
1000
- var _a2, _b2;
1001
- const instruction2 = (_b2 = (_a2 = fields.find((f) => f.path === task.path)) == null ? void 0 : _a2.instructions) == null ? void 0 : _b2.find((i) => i._key === task.instructionKey);
1002
- return {
1003
- ...task,
1004
- instruction: instruction2
1005
- };
1006
- }),
1007
- fields
1008
- });
1009
- }, [assistDocument, assistTasksStatus, currentUser]);
1010
- }
1011
- function asStudioInstruction(instruction2, run) {
1012
- return {
1013
- ...instruction2,
1014
- tasks: run.filter((task) => task.instructionKey === instruction2._key).filter(
1015
- (task) => task.started && (/* @__PURE__ */ new Date()).getTime() - new Date(task.started).getTime() < maxHistoryVisibilityMs
1016
- )
1017
- };
1018
- }
1019
- function usePathKey(path) {
1020
- return useMemo(() => getPathKey(path), [path]);
1021
- }
1022
- function getPathKey(path) {
1023
- return path.length ? Array.isArray(path) ? pathToString(path) : path : documentRootKey;
1024
- }
1025
- function getInstructionTitle(instruction2) {
1026
- var _a;
1027
- return (_a = instruction2 == null ? void 0 : instruction2.title) != null ? _a : "Untitled";
763
+ statusLoading,
764
+ init,
765
+ initLoading,
766
+ error
767
+ }), [config, status, init, statusLoading, initLoading, error]);
768
+ return /* @__PURE__ */ jsx(AiAssistanceConfigContext.Provider, { value: context, children });
1028
769
  }
1029
770
  const NO_INPUT = {}, RunInstructionContext = createContext({
1030
771
  runInstruction: () => {
@@ -1301,6 +1042,101 @@ function useOnboardingFeature(featureKey) {
1301
1042
  }, [setShowOnboarding, featureKey]);
1302
1043
  return { showOnboarding, dismissOnboarding };
1303
1044
  }
1045
+ const SelectedFieldContext = createContext(void 0), SelectedFieldContextProvider = SelectedFieldContext.Provider, maxDepth = 6;
1046
+ function getTypeIcon(schemaType) {
1047
+ let t = schemaType;
1048
+ for (; t; ) {
1049
+ if (t.icon)
1050
+ return t.icon;
1051
+ t = t.type;
1052
+ }
1053
+ 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;
1054
+ }
1055
+ function getFieldRefsWithDocument(schemaType) {
1056
+ var _a;
1057
+ const fields = getFieldRefs(schemaType);
1058
+ return [
1059
+ {
1060
+ key: documentRootKey,
1061
+ icon: (_a = schemaType.icon) != null ? _a : DocumentIcon,
1062
+ title: "The entire document",
1063
+ path: [],
1064
+ schemaType
1065
+ },
1066
+ ...fields
1067
+ ];
1068
+ }
1069
+ function getFieldRefs(schemaType, parent, depth = 0) {
1070
+ return depth >= maxDepth ? [] : schemaType.fields.filter((f) => !f.name.startsWith("_")).flatMap((field) => {
1071
+ var _a;
1072
+ const path = parent ? [...parent.path, field.name] : [field.name], title = (_a = field.type.title) != null ? _a : field.name, fieldRef = {
1073
+ key: patchableKey(pathToString(path)),
1074
+ path,
1075
+ title: parent ? [parent.title, title].join(" / ") : title,
1076
+ schemaType: field.type,
1077
+ icon: getTypeIcon(field.type)
1078
+ }, fields = field.type.jsonType === "object" ? getFieldRefs(field.type, fieldRef, depth + 1) : [], syntheticFields = field.type.jsonType === "array" ? getSyntheticFields(field.type, fieldRef, depth + 1) : [];
1079
+ return isAssistSupported(field.type) ? [fieldRef, ...fields, ...syntheticFields] : [...fields, ...syntheticFields];
1080
+ });
1081
+ }
1082
+ function getSyntheticFields(schemaType, parent, depth = 0) {
1083
+ return depth >= maxDepth ? [] : schemaType.of.filter((itemType) => !isType(itemType, "block")).flatMap((itemType) => {
1084
+ var _a;
1085
+ const segment = { _key: itemType.name }, title = (_a = itemType.title) != null ? _a : itemType.name, path = parent ? [...parent.path, segment] : [segment], fieldRef = {
1086
+ key: patchableKey(pathToString(path)),
1087
+ path,
1088
+ title: parent ? [parent.title, title].join(" / ") : title,
1089
+ schemaType: itemType,
1090
+ icon: getTypeIcon(itemType),
1091
+ synthetic: !0
1092
+ }, fields = itemType.jsonType === "object" ? getFieldRefs(itemType, fieldRef, depth + 1) : [];
1093
+ return isAssistSupported(itemType) ? [fieldRef, ...fields] : fields;
1094
+ });
1095
+ }
1096
+ function getTypePath(doc, pathString) {
1097
+ if (!pathString)
1098
+ return;
1099
+ const path = stringToPath(pathString), currentPath = [];
1100
+ let valid = !0;
1101
+ const syntheticPath = path.map((segment) => {
1102
+ if (currentPath.push(segment), isKeySegment(segment)) {
1103
+ const match = extractWithPath(pathToString(currentPath), doc)[0], value = match == null ? void 0 : match.value;
1104
+ if (match && value && typeof value == "object" && "_type" in value)
1105
+ return { _key: value._type };
1106
+ valid = !1;
1107
+ }
1108
+ return segment;
1109
+ });
1110
+ return valid ? patchableKey(pathToString(syntheticPath)) : void 0;
1111
+ }
1112
+ function patchableKey(pathKey) {
1113
+ return pathKey.replace(/[=]=/g, ":").replace(/[[\]]/g, "|").replace(/"/g, "");
1114
+ }
1115
+ function useTypePath(doc, pathString) {
1116
+ return useMemo(() => getTypePath(doc, pathString), [doc, pathString]);
1117
+ }
1118
+ function useSelectedField(documentSchemaType, path) {
1119
+ const selectableFields = useMemo(
1120
+ () => documentSchemaType && isObjectSchemaType(documentSchemaType) ? getFieldRefsWithDocument(documentSchemaType) : [],
1121
+ [documentSchemaType]
1122
+ );
1123
+ return useMemo(() => path ? selectableFields == null ? void 0 : selectableFields.find((f) => f.key === path) : void 0, [selectableFields, path]);
1124
+ }
1125
+ function getFieldTitle(field) {
1126
+ var _a, _b, _c;
1127
+ const schemaType = field == null ? void 0 : field.schemaType;
1128
+ return (_c = (_b = (_a = field == null ? void 0 : field.title) != null ? _a : schemaType == null ? void 0 : schemaType.title) != null ? _b : schemaType == null ? void 0 : schemaType.name) != null ? _c : "Untitled";
1129
+ }
1130
+ function useAiPaneRouter() {
1131
+ const paneRouter = usePaneRouter();
1132
+ return useMemo(
1133
+ () => {
1134
+ var _a;
1135
+ return { ...paneRouter, params: (_a = paneRouter.params) != null ? _a : {} };
1136
+ },
1137
+ [paneRouter]
1138
+ );
1139
+ }
1304
1140
  function FieldAutocomplete(props) {
1305
1141
  const { id, schemaType, fieldPath, onSelect, includeDocument, filter: filter2 } = props, fieldRefs = useMemo(() => includeDocument ? getFieldRefsWithDocument(schemaType) : getFieldRefs(schemaType), [schemaType, includeDocument]), currentField = useMemo(
1306
1142
  () => fieldRefs.find((f) => f.key === fieldPath),
@@ -1480,6 +1316,7 @@ const TASK_STATUS_BUTTON_TOOLTIP_PROPS = {
1480
1316
  StatusButton,
1481
1317
  {
1482
1318
  label: `${pluginTitle} status`,
1319
+ "aria-label": `${pluginTitle} status`,
1483
1320
  icon: isRunning ? SyncSpinningIcon : hasErrors ? ErrorOutlineIcon : CheckmarkCircleIcon,
1484
1321
  mode: "bleed",
1485
1322
  onClick,
@@ -1691,7 +1528,7 @@ function AssistInspector(props) {
1691
1528
  conditionalMembers: formStateRef.current ? getConditionalMembers(formStateRef.current) : []
1692
1529
  }),
1693
1530
  [pathKey, instruction2, typePath, documentType, assistableDocId, requestRunInstruction]
1694
- ), Region = useCallback((_props) => /* @__PURE__ */ jsx("div", { ..._props, style: { height: "100%", flex: 1, overflow: "auto" } }), []);
1531
+ ), Region = useCallback((_props) => /* @__PURE__ */ jsx("div", { ..._props, style: { height: "100%", flex: 1, overflow: "auto" } }), []), assistTypeContext = useMemo(() => ({ typePath, documentType }), [typePath, documentType]);
1695
1532
  return !documentId || !schemaType || schemaType.jsonType !== "object" ? /* @__PURE__ */ jsx(Card, { flex: 1, padding: 4, children: /* @__PURE__ */ jsx(Text, { children: "Document not ready yet." }) }) : /* @__PURE__ */ jsxs(
1696
1533
  Flex,
1697
1534
  {
@@ -1711,7 +1548,7 @@ function AssistInspector(props) {
1711
1548
  }
1712
1549
  ),
1713
1550
  /* @__PURE__ */ jsx(Card, { as: Region, flex: 1, overflow: "auto", children: /* @__PURE__ */ jsxs(Flex, { direction: "column", style: { minHeight: "100%" }, children: [
1714
- /* @__PURE__ */ jsx(Box, { flex: 1, children: /* @__PURE__ */ jsx(PresenceOverlay, { children: /* @__PURE__ */ jsx(Box, { padding: 4, children: selectedField && /* @__PURE__ */ jsx(TypePathContext.Provider, { value: typePath, children: /* @__PURE__ */ jsx(
1551
+ /* @__PURE__ */ jsx(Box, { flex: 1, children: /* @__PURE__ */ jsx(PresenceOverlay, { children: /* @__PURE__ */ jsx(Box, { padding: 4, children: selectedField && /* @__PURE__ */ jsx(AssistTypeContext.Provider, { value: assistTypeContext, children: /* @__PURE__ */ jsx(
1715
1552
  VirtualizerScrollInstanceProvider,
1716
1553
  {
1717
1554
  scrollElement: boundary.current,
@@ -1786,7 +1623,7 @@ function AiInspectorHeader(props) {
1786
1623
  showOnboarding && /* @__PURE__ */ jsx(InspectorOnboarding, { onDismiss: dismissOnboarding })
1787
1624
  ] });
1788
1625
  }
1789
- const assistInspector = {
1626
+ const aiInspectorId = "ai-assistance", assistInspector = {
1790
1627
  name: aiInspectorId,
1791
1628
  useMenuItem: () => ({
1792
1629
  icon: SparklesIcon,
@@ -2728,6 +2565,163 @@ function AssistItem(props) {
2728
2565
  presence.map((pre) => /* @__PURE__ */ jsx(Box, { style: { position: "absolute", right: 35 }, children: /* @__PURE__ */ jsx(AiFieldPresence, { presence: pre }) }, pre.user.id))
2729
2566
  ] });
2730
2567
  }
2568
+ function BackToInstructionListLink() {
2569
+ const { openInspector } = useDocumentPane(), goBack = useCallback(
2570
+ () => openInspector(aiInspectorId, { [instructionParam]: void 0 }),
2571
+ [openInspector]
2572
+ );
2573
+ return /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(
2574
+ Button,
2575
+ {
2576
+ as: "a",
2577
+ fontSize: 1,
2578
+ icon: ArrowLeftIcon,
2579
+ mode: "bleed",
2580
+ padding: 1,
2581
+ space: 2,
2582
+ onClick: goBack,
2583
+ text: " Instructions",
2584
+ textAlign: "left"
2585
+ }
2586
+ ) });
2587
+ }
2588
+ const EMPTY_FIELDS = [];
2589
+ function AssistDocumentForm(props) {
2590
+ 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 });
2591
+ }
2592
+ function AssistDocumentFormEditable(props) {
2593
+ const { onChange } = props, value = props.value, id = value == null ? void 0 : value._id, fields = value == null ? void 0 : value.fields, { params, setParams } = useAiPaneRouter(), pathKey = params[fieldPathParam], { typePath, documentType: targetDocumentType } = useContext(AssistTypeContext), instruction2 = params[instructionParam], activeKey = useMemo(() => {
2594
+ var _a;
2595
+ if (typePath)
2596
+ return (_a = (fields != null ? fields : EMPTY_FIELDS).find((f) => f.path === typePath)) == null ? void 0 : _a._key;
2597
+ }, [fields, typePath]), activePath = useMemo(() => {
2598
+ if (!activeKey)
2599
+ return;
2600
+ const base = ["fields", { _key: activeKey }];
2601
+ return instruction2 ? [...base, "instructions", { _key: instruction2 }] : base;
2602
+ }, [activeKey, instruction2]), schema = useSchema(), documentSchema = useMemo(() => {
2603
+ if (targetDocumentType)
2604
+ return schema.get(targetDocumentType);
2605
+ }, [schema, targetDocumentType]), fieldSchema = useSelectedSchema(pathKey, documentSchema), context = useMemo(
2606
+ () => ({
2607
+ documentSchema,
2608
+ fieldSchema: fieldSchema != null ? fieldSchema : documentSchema
2609
+ }),
2610
+ [fieldSchema, documentSchema]
2611
+ ), title = value == null ? void 0 : value.title;
2612
+ useEffect(() => {
2613
+ var _a;
2614
+ !title && documentSchema && !(id != null && id.startsWith("drafts.")) && onChange(set((_a = documentSchema.title) != null ? _a : documentSchema.name, ["title"]));
2615
+ }, [title, documentSchema, onChange, id]);
2616
+ const { onPathOpen, ...formCallbacks } = useFormCallbacks(), newCallbacks = useMemo(
2617
+ () => ({
2618
+ ...formCallbacks,
2619
+ onPathOpen: (path) => {
2620
+ var _a;
2621
+ !instruction2 && path.length === 4 && path[2] === "instructions" ? (setParams(
2622
+ typed({
2623
+ ...params,
2624
+ [instructionParam]: (_a = path[3]) == null ? void 0 : _a._key
2625
+ })
2626
+ ), onPathOpen([])) : setTimeout(() => onPathOpen(path), 0);
2627
+ }
2628
+ }),
2629
+ [formCallbacks, onPathOpen, params, setParams, instruction2]
2630
+ );
2631
+ return useEffect(() => {
2632
+ activePath && !instruction2 && onPathOpen([]);
2633
+ }, [activePath, instruction2, onPathOpen]), /* @__PURE__ */ jsx(SelectedFieldContextProvider, { value: context, children: /* @__PURE__ */ jsxs(Stack, { space: 5, children: [
2634
+ /* @__PURE__ */ jsx(
2635
+ FieldsInitializer,
2636
+ {
2637
+ pathKey: typePath,
2638
+ activePath,
2639
+ fields,
2640
+ documentSchema,
2641
+ onChange
2642
+ },
2643
+ typePath
2644
+ ),
2645
+ instruction2 && /* @__PURE__ */ jsx(BackToInstructionListLink, {}),
2646
+ activePath && /* @__PURE__ */ jsx(FormCallbacksProvider, { ...newCallbacks, children: /* @__PURE__ */ jsx("div", { style: { lineHeight: "1.25em" }, children: /* @__PURE__ */ jsx(FormInput, { ...props, absolutePath: activePath }) }) }),
2647
+ !activePath && props.renderDefault(props)
2648
+ ] }) });
2649
+ }
2650
+ function useSelectedSchema(fieldPath, documentSchema) {
2651
+ return useMemo(() => {
2652
+ if (!fieldPath)
2653
+ return;
2654
+ if (fieldPath === documentRootKey)
2655
+ return documentSchema;
2656
+ const path = stringToPath(fieldPath);
2657
+ let currentSchema = documentSchema;
2658
+ for (let i = 0; i < path.length; i++) {
2659
+ const segment = path[i], field = currentSchema == null ? void 0 : currentSchema.fields.find((f) => f.name === segment);
2660
+ if (!field)
2661
+ return;
2662
+ if (i === path.length - 1)
2663
+ return field.type;
2664
+ if (field.type.jsonType !== "object")
2665
+ return;
2666
+ currentSchema = field.type;
2667
+ }
2668
+ return currentSchema;
2669
+ }, [documentSchema, fieldPath]);
2670
+ }
2671
+ function FieldsInitializer({
2672
+ pathKey,
2673
+ activePath,
2674
+ fields,
2675
+ documentSchema,
2676
+ onChange
2677
+ }) {
2678
+ const {
2679
+ config: { __presets: presets }
2680
+ } = useAiAssistanceConfig(), existingField = fields == null ? void 0 : fields.find((f) => f._key === pathKey), documentPresets = !!(documentSchema != null && documentSchema.name) && (presets == null ? void 0 : presets[documentSchema == null ? void 0 : documentSchema.name]), missingPresetInstructions = useMemo(() => {
2681
+ var _a, _b;
2682
+ if (!documentPresets || !pathKey)
2683
+ return;
2684
+ const existingInstructions = existingField == null ? void 0 : existingField.instructions, presetField = (_a = documentPresets.fields) == null ? void 0 : _a.find((f) => f.path === pathKey);
2685
+ return (_b = presetField == null ? void 0 : presetField.instructions) == null ? void 0 : _b.filter(
2686
+ (i) => !(existingInstructions != null && existingInstructions.some((ei) => ei._key === i._key))
2687
+ );
2688
+ }, [documentPresets, pathKey, existingField]), initialized = useRef(!1);
2689
+ return useEffect(() => {
2690
+ var _a;
2691
+ if (initialized.current || !pathKey || existingField && !(missingPresetInstructions != null && missingPresetInstructions.length))
2692
+ return;
2693
+ let event = PatchEvent.from([setIfMissing([], ["fields"])]);
2694
+ existingField || (event = event.append(
2695
+ insert(
2696
+ [
2697
+ typed({
2698
+ _key: pathKey,
2699
+ _type: assistFieldTypeName,
2700
+ path: pathKey,
2701
+ instructions: []
2702
+ })
2703
+ ],
2704
+ "after",
2705
+ ["fields", -1]
2706
+ )
2707
+ )), (_a = existingField == null ? void 0 : existingField.instructions) != null && _a.length || (event = event.append([setIfMissing([], ["fields", { _key: pathKey }, "instructions"])])), missingPresetInstructions != null && missingPresetInstructions.length && (event = event.append(
2708
+ insert(
2709
+ missingPresetInstructions.map(
2710
+ (preset) => {
2711
+ var _a2;
2712
+ return {
2713
+ ...preset,
2714
+ _type: "sanity.assist.instruction",
2715
+ prompt: (_a2 = preset.prompt) == null ? void 0 : _a2.map((p) => ({ markDefs: [], ...p }))
2716
+ };
2717
+ }
2718
+ ),
2719
+ "after",
2720
+ ["fields", { _key: pathKey }, "instructions", -1]
2721
+ )
2722
+ )), onChange(event), initialized.current = !0;
2723
+ }, [activePath, onChange, pathKey, existingField, missingPresetInstructions]), null;
2724
+ }
2731
2725
  const InlineBlockValueContext = createContext(void 0);
2732
2726
  function AssistInlineFormBlock(props) {
2733
2727
  return /* @__PURE__ */ jsx(InlineBlockValueContext.Provider, { value: props.value, children: /* @__PURE__ */ jsx(Fragment, { children: props.renderDefault(props) }) });
@@ -2793,7 +2787,7 @@ function InstructionVisibility(props) {
2793
2787
  }
2794
2788
  function FieldRefPathInput(props) {
2795
2789
  var _a;
2796
- const documentSchema = (_a = useContext(SelectedFieldContext)) == null ? void 0 : _a.documentSchema, typePath = useContext(TypePathContext), ref = useRef(null), id = useId(), { onChange } = props;
2790
+ const documentSchema = (_a = useContext(SelectedFieldContext)) == null ? void 0 : _a.documentSchema, { typePath } = useContext(AssistTypeContext), ref = useRef(null), id = useId(), { onChange } = props;
2797
2791
  useEffect(() => {
2798
2792
  var _a2, _b;
2799
2793
  (_b = (_a2 = ref.current) == null ? void 0 : _a2.querySelector("input")) == null || _b.focus();