@sanity/embeddings-index-ui 1.0.2 → 1.1.0
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/README.md +33 -1
- package/dist/index.d.ts +21 -14
- package/dist/index.esm.js +295 -221
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +291 -217
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/api/isEnabled.tsx +53 -0
- package/src/embeddingsIndexDashboard/EmbeddingsIndexTool.tsx +11 -1
- package/src/embeddingsIndexDashboard/IndexEditor.tsx +8 -6
- package/src/embeddingsIndexDashboard/IndexFormInput.tsx +13 -3
- package/src/embeddingsIndexDashboard/IndexList.tsx +6 -3
- package/src/embeddingsIndexDashboard/QueryIndex.tsx +8 -103
- package/src/referenceInput/SemanticSearchAutocomplete.tsx +205 -0
- package/src/referenceInput/SemanticSearchReferenceInput.tsx +78 -133
- package/src/referenceInput/referencePlugin.tsx +37 -15
- package/src/schemas/typeDefExtensions.ts +21 -13
package/dist/index.esm.js
CHANGED
|
@@ -1,10 +1,57 @@
|
|
|
1
|
-
import { useSchema, DefaultPreview, useDocumentPreviewStore, SanityDefaultPreview, getPreviewValueWithFallback, getPreviewStateObservable,
|
|
1
|
+
import { useClient, useSchema, DefaultPreview, useDocumentPreviewStore, SanityDefaultPreview, getPreviewValueWithFallback, getPreviewStateObservable, typed, unset, setIfMissing, set, definePlugin, isObjectInputProps } from 'sanity';
|
|
2
2
|
import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
|
|
3
|
-
import { Card, Button, Box,
|
|
4
|
-
import { ErrorOutlineIcon, EarthGlobeIcon, LinkIcon, AddIcon,
|
|
5
|
-
import require$$0, {
|
|
6
|
-
import { useIntentLink } from 'sanity/router';
|
|
3
|
+
import { Card, Text, Button, Box, Autocomplete, Flex, Spinner, Stack, Label, TextInput, TextArea, Dialog, Heading, MenuButton, Menu, MenuItem } from '@sanity/ui';
|
|
4
|
+
import { ErrorOutlineIcon, EarthGlobeIcon, LinkIcon, AddIcon, EllipsisVerticalIcon, TrashIcon, UndoIcon } from '@sanity/icons';
|
|
5
|
+
import require$$0, { createContext, useState, useEffect, useContext, useMemo, useRef, forwardRef, useId, useCallback } from 'react';
|
|
7
6
|
import { useDocumentPane } from 'sanity/desk';
|
|
7
|
+
import { useIntentLink } from 'sanity/router';
|
|
8
|
+
function publicId(id) {
|
|
9
|
+
return id.replace("drafts.", "");
|
|
10
|
+
}
|
|
11
|
+
const featureName = "embeddingsIndexApi";
|
|
12
|
+
const FeatureEnabledContext = createContext("loading");
|
|
13
|
+
function useIsFeatureEnabled() {
|
|
14
|
+
const client = useClient({
|
|
15
|
+
apiVersion: "2023-09-01"
|
|
16
|
+
});
|
|
17
|
+
const [status, setStatus] = useState("loading");
|
|
18
|
+
useEffect(() => {
|
|
19
|
+
client.request({
|
|
20
|
+
method: "GET",
|
|
21
|
+
url: "/projects/".concat(client.config().projectId, "/features/").concat(featureName)
|
|
22
|
+
}).then(isEnabled => {
|
|
23
|
+
setStatus(isEnabled === "true" || isEnabled === true ? "enabled" : "disabled");
|
|
24
|
+
}).catch(err => {
|
|
25
|
+
console.error(err);
|
|
26
|
+
setStatus("disabled");
|
|
27
|
+
});
|
|
28
|
+
}, [client]);
|
|
29
|
+
return status;
|
|
30
|
+
}
|
|
31
|
+
function FeatureEnabledProvider(props) {
|
|
32
|
+
const status = useIsFeatureEnabled();
|
|
33
|
+
return /* @__PURE__ */jsx(FeatureEnabledContext.Provider, {
|
|
34
|
+
value: status,
|
|
35
|
+
children: props.children
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
function useIsFeatureEnabledContext() {
|
|
39
|
+
return useContext(FeatureEnabledContext);
|
|
40
|
+
}
|
|
41
|
+
function FeatureDisabledNotice() {
|
|
42
|
+
return /* @__PURE__ */jsx(Card, {
|
|
43
|
+
tone: "primary",
|
|
44
|
+
border: true,
|
|
45
|
+
padding: 2,
|
|
46
|
+
children: /* @__PURE__ */jsxs(Text, {
|
|
47
|
+
size: 1,
|
|
48
|
+
children: ["Embeddings index APIs are only available on the", " ", /* @__PURE__ */jsx("a", {
|
|
49
|
+
href: "https://sanity.io/pricing",
|
|
50
|
+
children: "Team tier and above"
|
|
51
|
+
}), ". Please upgrade to enable access."]
|
|
52
|
+
})
|
|
53
|
+
});
|
|
54
|
+
}
|
|
8
55
|
|
|
9
56
|
/******************************************************************************
|
|
10
57
|
Copyright (c) Microsoft Corporation.
|
|
@@ -1876,9 +1923,6 @@ function deleteIndex(indexName, client) {
|
|
|
1876
1923
|
url: "/embeddings-index/".concat(dataset, "/").concat(indexName, "?projectId=").concat(projectId)
|
|
1877
1924
|
});
|
|
1878
1925
|
}
|
|
1879
|
-
function publicId(id) {
|
|
1880
|
-
return id.replace("drafts.", "");
|
|
1881
|
-
}
|
|
1882
1926
|
function useApiClient() {
|
|
1883
1927
|
const client = useClient({
|
|
1884
1928
|
apiVersion: "vX"
|
|
@@ -1895,59 +1939,20 @@ function useApiClient() {
|
|
|
1895
1939
|
return client;
|
|
1896
1940
|
}, [client]);
|
|
1897
1941
|
}
|
|
1942
|
+
const NO_RESULTS_VALUE = "";
|
|
1898
1943
|
const NO_OPTIONS = [];
|
|
1899
1944
|
const NO_FILTER = () => true;
|
|
1900
|
-
function
|
|
1901
|
-
var _a, _b, _c;
|
|
1902
|
-
const defaultEnabled = ((_c = (_b = (_a = props.schemaType) == null ? void 0 : _a.options) == null ? void 0 : _b.embeddingsIndex) == null ? void 0 : _c.searchMode) === "embeddings";
|
|
1903
|
-
const [semantic, setSemantic] = useState(defaultEnabled);
|
|
1904
|
-
const toggleSemantic = useCallback(() => setSemantic(current => !current), []);
|
|
1905
|
-
return /* @__PURE__ */jsxs(Flex, {
|
|
1906
|
-
gap: 2,
|
|
1907
|
-
flex: 1,
|
|
1908
|
-
style: {
|
|
1909
|
-
width: "100%"
|
|
1910
|
-
},
|
|
1911
|
-
children: [/* @__PURE__ */jsx(Box, {
|
|
1912
|
-
flex: 1,
|
|
1913
|
-
style: {
|
|
1914
|
-
maxHeight: 36,
|
|
1915
|
-
overflow: "hidden"
|
|
1916
|
-
},
|
|
1917
|
-
children: semantic ? /* @__PURE__ */jsx(SemanticSearchInput, {
|
|
1918
|
-
...props
|
|
1919
|
-
}) : props.renderDefault(props)
|
|
1920
|
-
}), /* @__PURE__ */jsx(Button, {
|
|
1921
|
-
icon: semantic ? EarthGlobeIcon : LinkIcon,
|
|
1922
|
-
onClick: toggleSemantic,
|
|
1923
|
-
mode: "bleed",
|
|
1924
|
-
title: semantic ? "Switch to standard reference search" : "Switch to semantic reference search"
|
|
1925
|
-
})]
|
|
1926
|
-
});
|
|
1927
|
-
}
|
|
1928
|
-
function useDebouncedValue(value, ms) {
|
|
1929
|
-
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
1930
|
-
useEffect(() => {
|
|
1931
|
-
const timeoutId = setTimeout(() => {
|
|
1932
|
-
setDebouncedValue(value);
|
|
1933
|
-
}, ms);
|
|
1934
|
-
return () => clearTimeout(timeoutId);
|
|
1935
|
-
}, [value, ms]);
|
|
1936
|
-
return debouncedValue;
|
|
1937
|
-
}
|
|
1938
|
-
function SemanticSearchInput(props) {
|
|
1945
|
+
const SemanticSearchAutocomplete = forwardRef(function SemanticSearchAutocomplete2(props, ref) {
|
|
1939
1946
|
const {
|
|
1940
|
-
|
|
1941
|
-
|
|
1947
|
+
indexConfig,
|
|
1948
|
+
filterResult,
|
|
1949
|
+
getEmptySearchValue,
|
|
1942
1950
|
readOnly,
|
|
1943
|
-
|
|
1944
|
-
|
|
1951
|
+
onFocus,
|
|
1952
|
+
onBlur,
|
|
1953
|
+
onChange,
|
|
1954
|
+
typeFilter
|
|
1945
1955
|
} = props;
|
|
1946
|
-
const {
|
|
1947
|
-
value: currentDocument
|
|
1948
|
-
} = useDocumentPane();
|
|
1949
|
-
const docRef = useRef(currentDocument);
|
|
1950
|
-
const autocompleteRef = useRef(null);
|
|
1951
1956
|
const id = useId();
|
|
1952
1957
|
const [query, setQuery] = useState("");
|
|
1953
1958
|
const queryRef = useRef(query);
|
|
@@ -1956,29 +1961,16 @@ function SemanticSearchInput(props) {
|
|
|
1956
1961
|
const [searching, setSearching] = useState(false);
|
|
1957
1962
|
const [options, setOptions] = useState(NO_OPTIONS);
|
|
1958
1963
|
const client = useApiClient();
|
|
1959
|
-
useEffect(() => {
|
|
1960
|
-
docRef.current = currentDocument;
|
|
1961
|
-
}, [currentDocument]);
|
|
1962
|
-
useEffect(() => {
|
|
1963
|
-
var _a;
|
|
1964
|
-
if (value == null ? void 0 : value._ref) {
|
|
1965
|
-
(_a = autocompleteRef.current) == null ? void 0 : _a.focus();
|
|
1966
|
-
}
|
|
1967
|
-
}, []);
|
|
1968
|
-
const handleFocus = useCallback(() => onPathFocus(["_ref"]), [onPathFocus]);
|
|
1969
|
-
const handleBlur = useCallback(() => onPathFocus([]), [onPathFocus]);
|
|
1970
1964
|
const runIndexQuery = useCallback(queryString => {
|
|
1971
|
-
var _a
|
|
1965
|
+
var _a;
|
|
1972
1966
|
setSearching(true);
|
|
1973
|
-
const
|
|
1974
|
-
const
|
|
1975
|
-
const maxResults = (_d = (_c = refSchema.options) == null ? void 0 : _c.embeddingsIndex) == null ? void 0 : _d.maxResults;
|
|
1976
|
-
const typeFilter = refSchema.to.map(ref => ref.name);
|
|
1967
|
+
const indexName = indexConfig == null ? void 0 : indexConfig.indexName;
|
|
1968
|
+
const maxResults = indexConfig == null ? void 0 : indexConfig.maxResults;
|
|
1977
1969
|
if (!indexName) {
|
|
1978
|
-
throw new Error("Reference option embeddingsIndex.indexName is required, but was missing
|
|
1970
|
+
throw new Error("Reference option embeddingsIndex.indexName is required, but was missing");
|
|
1979
1971
|
}
|
|
1980
1972
|
queryIndex({
|
|
1981
|
-
query: queryString.trim().length ? queryString : (
|
|
1973
|
+
query: queryString.trim().length ? queryString : (_a = getEmptySearchValue()) != null ? _a : "",
|
|
1982
1974
|
indexName,
|
|
1983
1975
|
maxResults,
|
|
1984
1976
|
filter: {
|
|
@@ -1987,10 +1979,18 @@ function SemanticSearchInput(props) {
|
|
|
1987
1979
|
}, client).then(result => {
|
|
1988
1980
|
if (queryRef.current === queryString) {
|
|
1989
1981
|
setSearching(false);
|
|
1990
|
-
setOptions(
|
|
1982
|
+
setOptions([]);
|
|
1983
|
+
const resultOptions = result.filter(hit => filterResult ? filterResult(hit) : true).map(r => typed({
|
|
1991
1984
|
result: r,
|
|
1992
1985
|
value: r.value.documentId
|
|
1993
|
-
}))
|
|
1986
|
+
}));
|
|
1987
|
+
if (resultOptions.length) {
|
|
1988
|
+
setOptions(resultOptions);
|
|
1989
|
+
} else {
|
|
1990
|
+
setOptions([{
|
|
1991
|
+
value: NO_RESULTS_VALUE
|
|
1992
|
+
}]);
|
|
1993
|
+
}
|
|
1994
1994
|
}
|
|
1995
1995
|
}).catch(e => {
|
|
1996
1996
|
if (queryRef.current === queryString) {
|
|
@@ -1998,23 +1998,13 @@ function SemanticSearchInput(props) {
|
|
|
1998
1998
|
}
|
|
1999
1999
|
throw e;
|
|
2000
2000
|
});
|
|
2001
|
-
}, [client,
|
|
2001
|
+
}, [client, indexConfig, getEmptySearchValue, filterResult, typeFilter]);
|
|
2002
2002
|
useEffect(() => {
|
|
2003
2003
|
if (prevDebouncedQuery.current !== debouncedQuery) {
|
|
2004
2004
|
runIndexQuery(debouncedQuery);
|
|
2005
2005
|
}
|
|
2006
2006
|
prevDebouncedQuery.current = debouncedQuery;
|
|
2007
2007
|
}, [debouncedQuery, runIndexQuery]);
|
|
2008
|
-
const handleChange = useCallback(nextId => {
|
|
2009
|
-
if (!nextId) {
|
|
2010
|
-
onChange(unset());
|
|
2011
|
-
onPathFocus([]);
|
|
2012
|
-
return;
|
|
2013
|
-
}
|
|
2014
|
-
const patches = [setIfMissing({}), set(schemaType.name, ["_type"]), set(publicId(nextId), ["_ref"]), unset(["_weak"]), unset(["_strengthenOnPublish"])];
|
|
2015
|
-
onChange(patches);
|
|
2016
|
-
onPathFocus([]);
|
|
2017
|
-
}, [onChange, onPathFocus, schemaType.name]);
|
|
2018
2008
|
const openButtonConfig = useMemo(() => ({
|
|
2019
2009
|
onClick: () => runIndexQuery(queryRef.current)
|
|
2020
2010
|
}), [runIndexQuery, queryRef]);
|
|
@@ -2023,52 +2013,187 @@ function SemanticSearchInput(props) {
|
|
|
2023
2013
|
queryRef.current = newQuery;
|
|
2024
2014
|
setQuery(newQuery);
|
|
2025
2015
|
}, [setQuery]);
|
|
2016
|
+
const handleChange = useCallback(value => {
|
|
2017
|
+
if (value === NO_RESULTS_VALUE) {
|
|
2018
|
+
setOptions(NO_OPTIONS);
|
|
2019
|
+
return;
|
|
2020
|
+
}
|
|
2021
|
+
onChange == null ? void 0 : onChange(value);
|
|
2022
|
+
}, [onChange]);
|
|
2026
2023
|
return /* @__PURE__ */jsx(Autocomplete, {
|
|
2027
2024
|
id,
|
|
2028
|
-
ref
|
|
2025
|
+
ref,
|
|
2029
2026
|
"data-testid": "semantic-autocomplete",
|
|
2030
2027
|
placeholder: "Type to search...",
|
|
2031
2028
|
openButton: openButtonConfig,
|
|
2032
|
-
onFocus
|
|
2029
|
+
onFocus,
|
|
2033
2030
|
onChange: handleChange,
|
|
2034
2031
|
loading: searching,
|
|
2035
|
-
onBlur
|
|
2032
|
+
onBlur,
|
|
2036
2033
|
readOnly,
|
|
2037
2034
|
filterOption: NO_FILTER,
|
|
2038
2035
|
onQueryChange: handleQueryChange,
|
|
2039
2036
|
options,
|
|
2040
2037
|
renderOption: AutocompleteOption
|
|
2041
2038
|
});
|
|
2042
|
-
}
|
|
2039
|
+
});
|
|
2043
2040
|
function AutocompleteOption(props) {
|
|
2044
|
-
|
|
2041
|
+
if ("result" in props) {
|
|
2042
|
+
const value = props.result.value;
|
|
2043
|
+
return /* @__PURE__ */jsx(Button, {
|
|
2044
|
+
mode: "bleed",
|
|
2045
|
+
padding: 1,
|
|
2046
|
+
style: {
|
|
2047
|
+
width: "100%"
|
|
2048
|
+
},
|
|
2049
|
+
children: /* @__PURE__ */jsxs(Flex, {
|
|
2050
|
+
gap: 2,
|
|
2051
|
+
align: "center",
|
|
2052
|
+
children: [/* @__PURE__ */jsx(Box, {
|
|
2053
|
+
flex: 1,
|
|
2054
|
+
children: /* @__PURE__ */jsx(DocumentPreview, {
|
|
2055
|
+
documentId: value.documentId,
|
|
2056
|
+
schemaTypeName: value.type
|
|
2057
|
+
})
|
|
2058
|
+
}), /* @__PURE__ */jsx(Box, {
|
|
2059
|
+
padding: 2,
|
|
2060
|
+
children: /* @__PURE__ */jsxs(Text, {
|
|
2061
|
+
size: 1,
|
|
2062
|
+
muted: true,
|
|
2063
|
+
title: "Relevance",
|
|
2064
|
+
children: [Math.floor(props.result.score * 100), "%"]
|
|
2065
|
+
})
|
|
2066
|
+
})]
|
|
2067
|
+
})
|
|
2068
|
+
});
|
|
2069
|
+
}
|
|
2045
2070
|
return /* @__PURE__ */jsx(Button, {
|
|
2046
2071
|
mode: "bleed",
|
|
2047
2072
|
padding: 1,
|
|
2048
2073
|
style: {
|
|
2049
2074
|
width: "100%"
|
|
2050
2075
|
},
|
|
2051
|
-
|
|
2076
|
+
disabled: true,
|
|
2077
|
+
children: /* @__PURE__ */jsx(Flex, {
|
|
2052
2078
|
gap: 2,
|
|
2053
2079
|
align: "center",
|
|
2054
|
-
children:
|
|
2055
|
-
flex: 1,
|
|
2056
|
-
children: /* @__PURE__ */jsx(DocumentPreview, {
|
|
2057
|
-
documentId: value.documentId,
|
|
2058
|
-
schemaTypeName: value.type
|
|
2059
|
-
})
|
|
2060
|
-
}), /* @__PURE__ */jsx(Box, {
|
|
2061
|
-
padding: 2,
|
|
2062
|
-
children: /* @__PURE__ */jsxs(Text, {
|
|
2063
|
-
size: 1,
|
|
2064
|
-
muted: true,
|
|
2065
|
-
title: "Relevance",
|
|
2066
|
-
children: [Math.floor(props.result.score * 100), "%"]
|
|
2067
|
-
})
|
|
2068
|
-
})]
|
|
2080
|
+
children: "No results."
|
|
2069
2081
|
})
|
|
2070
2082
|
});
|
|
2071
2083
|
}
|
|
2084
|
+
function useDebouncedValue(value, ms) {
|
|
2085
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
2086
|
+
useEffect(() => {
|
|
2087
|
+
const timeoutId = setTimeout(() => {
|
|
2088
|
+
setDebouncedValue(value);
|
|
2089
|
+
}, ms);
|
|
2090
|
+
return () => clearTimeout(timeoutId);
|
|
2091
|
+
}, [value, ms]);
|
|
2092
|
+
return debouncedValue;
|
|
2093
|
+
}
|
|
2094
|
+
function useEmeddingsConfig(embeddingsIndexConfig, defaultConfig) {
|
|
2095
|
+
return useMemo(() => {
|
|
2096
|
+
if (embeddingsIndexConfig === true || !embeddingsIndexConfig) {
|
|
2097
|
+
if (!(defaultConfig == null ? void 0 : defaultConfig.indexName)) {
|
|
2098
|
+
throw new Error("Default embeddingsIndex config is missing. When options.embeddingsIndex: true, embeddingsIndexReferenceInput plugin config is required.");
|
|
2099
|
+
}
|
|
2100
|
+
return defaultConfig;
|
|
2101
|
+
}
|
|
2102
|
+
const finalConfig = {
|
|
2103
|
+
...defaultConfig,
|
|
2104
|
+
...embeddingsIndexConfig
|
|
2105
|
+
};
|
|
2106
|
+
if (!(finalConfig == null ? void 0 : finalConfig.indexName)) {
|
|
2107
|
+
throw new Error("indexName is missing. Either set it in options.embeddingsIndex or configure defaults using plugin config.");
|
|
2108
|
+
}
|
|
2109
|
+
return finalConfig;
|
|
2110
|
+
}, [defaultConfig, embeddingsIndexConfig]);
|
|
2111
|
+
}
|
|
2112
|
+
function SemanticSearchReferenceInput(props) {
|
|
2113
|
+
var _a, _b;
|
|
2114
|
+
const embeddingsIndexConfig = (_b = (_a = props.schemaType) == null ? void 0 : _a.options) == null ? void 0 : _b.embeddingsIndex;
|
|
2115
|
+
const config = useEmeddingsConfig(embeddingsIndexConfig, props.defaultConfig);
|
|
2116
|
+
const defaultEnabled = config.searchMode === "embeddings";
|
|
2117
|
+
const featureState = useIsFeatureEnabledContext();
|
|
2118
|
+
const [semantic, setSemantic] = useState(defaultEnabled);
|
|
2119
|
+
const toggleSemantic = useCallback(() => setSemantic(current => !current), []);
|
|
2120
|
+
return /* @__PURE__ */jsxs(Flex, {
|
|
2121
|
+
gap: 2,
|
|
2122
|
+
flex: 1,
|
|
2123
|
+
style: {
|
|
2124
|
+
width: "100%"
|
|
2125
|
+
},
|
|
2126
|
+
children: [semantic && featureState == "loading" ? /* @__PURE__ */jsx(Box, {
|
|
2127
|
+
padding: 2,
|
|
2128
|
+
children: /* @__PURE__ */jsx(Spinner, {})
|
|
2129
|
+
}) : null, semantic && featureState == "disabled" ? /* @__PURE__ */jsx(FeatureDisabledNotice, {}) : null, /* @__PURE__ */jsx(Box, {
|
|
2130
|
+
flex: 1,
|
|
2131
|
+
style: {
|
|
2132
|
+
maxHeight: 36,
|
|
2133
|
+
overflow: "hidden"
|
|
2134
|
+
},
|
|
2135
|
+
children: semantic && featureState == "enabled" ? /* @__PURE__ */jsx(SemanticSearchInput, {
|
|
2136
|
+
...props,
|
|
2137
|
+
indexConfig: config
|
|
2138
|
+
}) : props.renderDefault(props)
|
|
2139
|
+
}), /* @__PURE__ */jsx(Button, {
|
|
2140
|
+
icon: semantic ? EarthGlobeIcon : LinkIcon,
|
|
2141
|
+
onClick: toggleSemantic,
|
|
2142
|
+
mode: "bleed",
|
|
2143
|
+
title: semantic ? "Switch to standard reference search" : "Switch to semantic reference search"
|
|
2144
|
+
})]
|
|
2145
|
+
});
|
|
2146
|
+
}
|
|
2147
|
+
function SemanticSearchInput(props) {
|
|
2148
|
+
const {
|
|
2149
|
+
indexConfig,
|
|
2150
|
+
onPathFocus,
|
|
2151
|
+
onChange,
|
|
2152
|
+
readOnly,
|
|
2153
|
+
schemaType,
|
|
2154
|
+
value
|
|
2155
|
+
} = props;
|
|
2156
|
+
const {
|
|
2157
|
+
value: currentDocument
|
|
2158
|
+
} = useDocumentPane();
|
|
2159
|
+
const docRef = useRef(currentDocument);
|
|
2160
|
+
const autocompleteRef = useRef(null);
|
|
2161
|
+
useEffect(() => {
|
|
2162
|
+
docRef.current = currentDocument;
|
|
2163
|
+
}, [currentDocument]);
|
|
2164
|
+
useEffect(() => {
|
|
2165
|
+
var _a;
|
|
2166
|
+
if (value == null ? void 0 : value._ref) {
|
|
2167
|
+
(_a = autocompleteRef.current) == null ? void 0 : _a.focus();
|
|
2168
|
+
}
|
|
2169
|
+
}, []);
|
|
2170
|
+
const handleFocus = useCallback(() => onPathFocus(["_ref"]), [onPathFocus]);
|
|
2171
|
+
const handleBlur = useCallback(() => onPathFocus([]), [onPathFocus]);
|
|
2172
|
+
const handleChange = useCallback(nextId => {
|
|
2173
|
+
if (!nextId) {
|
|
2174
|
+
onChange(unset());
|
|
2175
|
+
onPathFocus([]);
|
|
2176
|
+
return;
|
|
2177
|
+
}
|
|
2178
|
+
const patches = [setIfMissing({}), set(schemaType.name, ["_type"]), set(publicId(nextId), ["_ref"]), unset(["_weak"]), unset(["_strengthenOnPublish"])];
|
|
2179
|
+
onChange(patches);
|
|
2180
|
+
onPathFocus([]);
|
|
2181
|
+
}, [onChange, onPathFocus, schemaType.name]);
|
|
2182
|
+
const filterResult = useCallback(r => r.value.documentId !== publicId(docRef.current._id), [docRef]);
|
|
2183
|
+
const getEmptySearchValue = useCallback(() => JSON.stringify(docRef.current), [docRef]);
|
|
2184
|
+
const typeFilter = useMemo(() => schemaType.to.map(refType => refType.name), [schemaType]);
|
|
2185
|
+
return /* @__PURE__ */jsx(SemanticSearchAutocomplete, {
|
|
2186
|
+
ref: autocompleteRef,
|
|
2187
|
+
typeFilter,
|
|
2188
|
+
indexConfig,
|
|
2189
|
+
onChange: handleChange,
|
|
2190
|
+
onFocus: handleFocus,
|
|
2191
|
+
onBlur: handleBlur,
|
|
2192
|
+
getEmptySearchValue,
|
|
2193
|
+
filterResult,
|
|
2194
|
+
readOnly
|
|
2195
|
+
});
|
|
2196
|
+
}
|
|
2072
2197
|
function isType(schemaType, typeName) {
|
|
2073
2198
|
if (schemaType.name === typeName) {
|
|
2074
2199
|
return true;
|
|
@@ -2078,21 +2203,35 @@ function isType(schemaType, typeName) {
|
|
|
2078
2203
|
}
|
|
2079
2204
|
return isType(schemaType.type, typeName);
|
|
2080
2205
|
}
|
|
2081
|
-
const embeddingsIndexReferenceInput = definePlugin({
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
return /* @__PURE__ */jsx(
|
|
2089
|
-
|
|
2206
|
+
const embeddingsIndexReferenceInput = definePlugin(defaultConfig => {
|
|
2207
|
+
const config = typeof defaultConfig === "object" ? defaultConfig : void 0;
|
|
2208
|
+
return {
|
|
2209
|
+
name: "@sanity/embeddings-index-reference-input",
|
|
2210
|
+
studio: {
|
|
2211
|
+
components: {
|
|
2212
|
+
layout: props => {
|
|
2213
|
+
return /* @__PURE__ */jsx(FeatureEnabledProvider, {
|
|
2214
|
+
children: props.renderDefault(props)
|
|
2090
2215
|
});
|
|
2091
2216
|
}
|
|
2092
|
-
|
|
2217
|
+
}
|
|
2218
|
+
},
|
|
2219
|
+
form: {
|
|
2220
|
+
components: {
|
|
2221
|
+
input: props => {
|
|
2222
|
+
var _a, _b;
|
|
2223
|
+
const embeddingsIndexConfig = (_b = (_a = props.schemaType) == null ? void 0 : _a.options) == null ? void 0 : _b.embeddingsIndex;
|
|
2224
|
+
if (isObjectInputProps(props) && isType(props.schemaType, "reference") && (embeddingsIndexConfig === true || (embeddingsIndexConfig == null ? void 0 : embeddingsIndexConfig.indexName))) {
|
|
2225
|
+
return /* @__PURE__ */jsx(SemanticSearchReferenceInput, {
|
|
2226
|
+
...props,
|
|
2227
|
+
defaultConfig: config
|
|
2228
|
+
});
|
|
2229
|
+
}
|
|
2230
|
+
return props.renderDefault(props);
|
|
2231
|
+
}
|
|
2093
2232
|
}
|
|
2094
2233
|
}
|
|
2095
|
-
}
|
|
2234
|
+
};
|
|
2096
2235
|
});
|
|
2097
2236
|
const defaultProjection = "{...}";
|
|
2098
2237
|
function useDefaultIndex(schema, dataset) {
|
|
@@ -2107,6 +2246,7 @@ function IndexFormInput(props) {
|
|
|
2107
2246
|
var _a;
|
|
2108
2247
|
const {
|
|
2109
2248
|
label,
|
|
2249
|
+
description,
|
|
2110
2250
|
index,
|
|
2111
2251
|
prop,
|
|
2112
2252
|
onChange,
|
|
@@ -2120,6 +2260,7 @@ function IndexFormInput(props) {
|
|
|
2120
2260
|
})), [onChange, prop]);
|
|
2121
2261
|
return /* @__PURE__ */jsx(FormInput, {
|
|
2122
2262
|
label,
|
|
2263
|
+
description,
|
|
2123
2264
|
onChange: handleChange,
|
|
2124
2265
|
value: (_a = index[prop]) != null ? _a : "",
|
|
2125
2266
|
readOnly,
|
|
@@ -2130,6 +2271,7 @@ function IndexFormInput(props) {
|
|
|
2130
2271
|
function FormInput(props) {
|
|
2131
2272
|
const {
|
|
2132
2273
|
label,
|
|
2274
|
+
description,
|
|
2133
2275
|
onChange,
|
|
2134
2276
|
value,
|
|
2135
2277
|
readOnly,
|
|
@@ -2147,6 +2289,12 @@ function FormInput(props) {
|
|
|
2147
2289
|
htmlFor: id,
|
|
2148
2290
|
children: label
|
|
2149
2291
|
})
|
|
2292
|
+
}), description && /* @__PURE__ */jsx(Box, {
|
|
2293
|
+
children: /* @__PURE__ */jsx(Text, {
|
|
2294
|
+
size: 1,
|
|
2295
|
+
muted: true,
|
|
2296
|
+
children: description
|
|
2297
|
+
})
|
|
2150
2298
|
}), type === "text" ? /* @__PURE__ */jsx(TextInput, {
|
|
2151
2299
|
id,
|
|
2152
2300
|
value,
|
|
@@ -2301,18 +2449,20 @@ function IndexEditor(props) {
|
|
|
2301
2449
|
onChange: setIndex,
|
|
2302
2450
|
readOnly: true
|
|
2303
2451
|
}), /* @__PURE__ */jsx(IndexFormInput, {
|
|
2304
|
-
label: "
|
|
2305
|
-
|
|
2452
|
+
label: "Filter",
|
|
2453
|
+
description: "Must be a valid GROQ filter",
|
|
2454
|
+
placeholder: defaultIndex.filter,
|
|
2306
2455
|
index,
|
|
2307
|
-
prop: "
|
|
2456
|
+
prop: "filter",
|
|
2308
2457
|
onChange: setIndex,
|
|
2309
2458
|
readOnly,
|
|
2310
2459
|
type: "textarea"
|
|
2311
2460
|
}), /* @__PURE__ */jsx(IndexFormInput, {
|
|
2312
|
-
label: "
|
|
2313
|
-
|
|
2461
|
+
label: "Projection",
|
|
2462
|
+
description: "Must be a valid GROQ projection, starting { and ending with }",
|
|
2463
|
+
placeholder: defaultIndex.projection,
|
|
2314
2464
|
index,
|
|
2315
|
-
prop: "
|
|
2465
|
+
prop: "projection",
|
|
2316
2466
|
onChange: setIndex,
|
|
2317
2467
|
readOnly,
|
|
2318
2468
|
type: "textarea"
|
|
@@ -2349,6 +2499,7 @@ function IndexList(props) {
|
|
|
2349
2499
|
borderBottom: true,
|
|
2350
2500
|
flex: 1,
|
|
2351
2501
|
paddingBottom: 2,
|
|
2502
|
+
padding: 3,
|
|
2352
2503
|
children: /* @__PURE__ */jsxs(Flex, {
|
|
2353
2504
|
children: [/* @__PURE__ */jsx(Box, {
|
|
2354
2505
|
flex: 1,
|
|
@@ -2403,12 +2554,15 @@ function IndexRow(props) {
|
|
|
2403
2554
|
const onSelect = useCallback(() => onIndexSelected(index), [onIndexSelected, index]);
|
|
2404
2555
|
return /* @__PURE__ */jsx(Button, {
|
|
2405
2556
|
tone: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "primary" : "default",
|
|
2406
|
-
mode: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "default" : "
|
|
2557
|
+
mode: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "default" : "ghost",
|
|
2407
2558
|
onClick: onSelect,
|
|
2559
|
+
padding: 3,
|
|
2408
2560
|
children: /* @__PURE__ */jsxs(Flex, {
|
|
2409
2561
|
children: [/* @__PURE__ */jsx(Box, {
|
|
2410
2562
|
flex: 1,
|
|
2411
|
-
children:
|
|
2563
|
+
children: /* @__PURE__ */jsx("strong", {
|
|
2564
|
+
children: index.indexName
|
|
2565
|
+
})
|
|
2412
2566
|
}), /* @__PURE__ */jsx(Box, {
|
|
2413
2567
|
flex: 1,
|
|
2414
2568
|
children: index.dataset
|
|
@@ -2422,102 +2576,18 @@ function IndexRow(props) {
|
|
|
2422
2576
|
})
|
|
2423
2577
|
}, index.indexName);
|
|
2424
2578
|
}
|
|
2425
|
-
const NO_RESULTS = [];
|
|
2426
2579
|
function QueryIndex(props) {
|
|
2427
2580
|
const {
|
|
2428
2581
|
indexName
|
|
2429
2582
|
} = props;
|
|
2430
|
-
const
|
|
2431
|
-
const
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
|
|
2436
|
-
|
|
2437
|
-
|
|
2438
|
-
indexName,
|
|
2439
|
-
maxResults: 5
|
|
2440
|
-
}, client).then(setResults).finally(() => setSearching(false));
|
|
2441
|
-
}, [client, indexName]);
|
|
2442
|
-
const onInputChange = useCallback(e => {
|
|
2443
|
-
setQuery(e.currentTarget.value);
|
|
2444
|
-
}, []);
|
|
2445
|
-
const onKeyDown = useCallback(e => {
|
|
2446
|
-
if (e.key === "Enter") {
|
|
2447
|
-
search(query).catch(console.error);
|
|
2448
|
-
}
|
|
2449
|
-
}, [search, query]);
|
|
2450
|
-
return /* @__PURE__ */jsxs(Stack, {
|
|
2451
|
-
space: 3,
|
|
2452
|
-
flex: 1,
|
|
2453
|
-
children: [/* @__PURE__ */jsx(Flex, {
|
|
2454
|
-
flex: 1,
|
|
2455
|
-
children: /* @__PURE__ */jsx(Card, {
|
|
2456
|
-
flex: 1,
|
|
2457
|
-
children: /* @__PURE__ */jsx(TextInput, {
|
|
2458
|
-
iconRight: searching ? /* @__PURE__ */jsx(Box, {
|
|
2459
|
-
style: {
|
|
2460
|
-
marginTop: 5
|
|
2461
|
-
},
|
|
2462
|
-
children: /* @__PURE__ */jsx(Spinner, {})
|
|
2463
|
-
}) : SearchIcon,
|
|
2464
|
-
placeholder: "Find documents",
|
|
2465
|
-
value: query,
|
|
2466
|
-
disabled: searching,
|
|
2467
|
-
onChange: onInputChange,
|
|
2468
|
-
onKeyDown
|
|
2469
|
-
})
|
|
2470
|
-
})
|
|
2471
|
-
}), /* @__PURE__ */jsx(Flex, {
|
|
2472
|
-
gap: 4,
|
|
2473
|
-
style: {
|
|
2474
|
-
opacity: searching ? 0.5 : 1
|
|
2475
|
-
},
|
|
2476
|
-
children: /* @__PURE__ */jsx(Box, {
|
|
2477
|
-
flex: 1,
|
|
2478
|
-
children: /* @__PURE__ */jsx(ResultList, {
|
|
2479
|
-
results,
|
|
2480
|
-
query
|
|
2481
|
-
})
|
|
2482
|
-
})
|
|
2483
|
-
})]
|
|
2484
|
-
});
|
|
2485
|
-
}
|
|
2486
|
-
function ResultList(props) {
|
|
2487
|
-
const {
|
|
2488
|
-
results,
|
|
2489
|
-
query
|
|
2490
|
-
} = props;
|
|
2491
|
-
return /* @__PURE__ */jsx(Stack, {
|
|
2492
|
-
space: 4,
|
|
2493
|
-
height: "fill",
|
|
2494
|
-
children: /* @__PURE__ */jsxs(Stack, {
|
|
2495
|
-
space: 2,
|
|
2496
|
-
children: [results.map(r => /* @__PURE__ */jsx(ResultEntry, {
|
|
2497
|
-
result: r
|
|
2498
|
-
}, r.value.documentId)), !results.length && query ? "No results." : null]
|
|
2499
|
-
})
|
|
2500
|
-
});
|
|
2501
|
-
}
|
|
2502
|
-
function ResultEntry(props) {
|
|
2503
|
-
const value = props.result.value;
|
|
2504
|
-
return /* @__PURE__ */jsxs(Flex, {
|
|
2505
|
-
gap: 4,
|
|
2506
|
-
align: "center",
|
|
2507
|
-
children: [/* @__PURE__ */jsx(Box, {
|
|
2508
|
-
flex: 1,
|
|
2509
|
-
children: /* @__PURE__ */jsx(DocumentPreview, {
|
|
2510
|
-
documentId: value.documentId,
|
|
2511
|
-
schemaTypeName: value.type,
|
|
2512
|
-
button: true
|
|
2513
|
-
})
|
|
2514
|
-
}), /* @__PURE__ */jsx(Box, {
|
|
2515
|
-
children: /* @__PURE__ */jsxs(Text, {
|
|
2516
|
-
muted: true,
|
|
2517
|
-
size: 1,
|
|
2518
|
-
children: [Math.floor(props.result.score * 100), " %"]
|
|
2519
|
-
})
|
|
2520
|
-
})]
|
|
2583
|
+
const getEmpty = useCallback(() => "anything", []);
|
|
2584
|
+
const indexConfig = useMemo(() => ({
|
|
2585
|
+
indexName,
|
|
2586
|
+
maxResults: 8
|
|
2587
|
+
}), [indexName]);
|
|
2588
|
+
return /* @__PURE__ */jsx(SemanticSearchAutocomplete, {
|
|
2589
|
+
getEmptySearchValue: getEmpty,
|
|
2590
|
+
indexConfig
|
|
2521
2591
|
});
|
|
2522
2592
|
}
|
|
2523
2593
|
function IndexInfo(_ref3) {
|
|
@@ -2649,17 +2719,21 @@ function IndexStatus(_ref4) {
|
|
|
2649
2719
|
});
|
|
2650
2720
|
}
|
|
2651
2721
|
function EmbeddingsIndexTool() {
|
|
2722
|
+
const featureState = useIsFeatureEnabled();
|
|
2652
2723
|
return /* @__PURE__ */jsx(Card, {
|
|
2653
2724
|
children: /* @__PURE__ */jsx(Flex, {
|
|
2654
2725
|
justify: "center",
|
|
2655
2726
|
flex: 1,
|
|
2656
|
-
children: /* @__PURE__ */
|
|
2727
|
+
children: /* @__PURE__ */jsxs(Card, {
|
|
2657
2728
|
flex: 1,
|
|
2658
2729
|
style: {
|
|
2659
2730
|
maxWidth: 1200
|
|
2660
2731
|
},
|
|
2661
2732
|
padding: 5,
|
|
2662
|
-
children: /* @__PURE__ */jsx(
|
|
2733
|
+
children: [featureState == "loading" ? /* @__PURE__ */jsx(Box, {
|
|
2734
|
+
padding: 2,
|
|
2735
|
+
children: /* @__PURE__ */jsx(Spinner, {})
|
|
2736
|
+
}) : null, featureState == "disabled" ? /* @__PURE__ */jsx(FeatureDisabledNotice, {}) : null, featureState == "enabled" ? /* @__PURE__ */jsx(Indexes, {}) : null]
|
|
2663
2737
|
})
|
|
2664
2738
|
})
|
|
2665
2739
|
});
|