@sanity/embeddings-index-ui 1.0.3 → 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 +289 -276
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +285 -272
- package/dist/index.js.map +1 -1
- package/package.json +1 -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 +62 -140
- package/src/referenceInput/referencePlugin.tsx +35 -21
- package/src/schemas/typeDefExtensions.ts +21 -13
package/dist/index.js
CHANGED
|
@@ -8,14 +8,61 @@ var jsxRuntime = require('react/jsx-runtime');
|
|
|
8
8
|
var ui = require('@sanity/ui');
|
|
9
9
|
var icons = require('@sanity/icons');
|
|
10
10
|
var require$$0 = require('react');
|
|
11
|
-
var router = require('sanity/router');
|
|
12
11
|
var desk = require('sanity/desk');
|
|
12
|
+
var router = require('sanity/router');
|
|
13
13
|
function _interopDefaultCompat(e) {
|
|
14
14
|
return e && typeof e === 'object' && 'default' in e ? e : {
|
|
15
15
|
default: e
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
var require$$0__default = /*#__PURE__*/_interopDefaultCompat(require$$0);
|
|
19
|
+
function publicId(id) {
|
|
20
|
+
return id.replace("drafts.", "");
|
|
21
|
+
}
|
|
22
|
+
const featureName = "embeddingsIndexApi";
|
|
23
|
+
const FeatureEnabledContext = require$$0.createContext("loading");
|
|
24
|
+
function useIsFeatureEnabled() {
|
|
25
|
+
const client = sanity.useClient({
|
|
26
|
+
apiVersion: "2023-09-01"
|
|
27
|
+
});
|
|
28
|
+
const [status, setStatus] = require$$0.useState("loading");
|
|
29
|
+
require$$0.useEffect(() => {
|
|
30
|
+
client.request({
|
|
31
|
+
method: "GET",
|
|
32
|
+
url: "/projects/".concat(client.config().projectId, "/features/").concat(featureName)
|
|
33
|
+
}).then(isEnabled => {
|
|
34
|
+
setStatus(isEnabled === "true" || isEnabled === true ? "enabled" : "disabled");
|
|
35
|
+
}).catch(err => {
|
|
36
|
+
console.error(err);
|
|
37
|
+
setStatus("disabled");
|
|
38
|
+
});
|
|
39
|
+
}, [client]);
|
|
40
|
+
return status;
|
|
41
|
+
}
|
|
42
|
+
function FeatureEnabledProvider(props) {
|
|
43
|
+
const status = useIsFeatureEnabled();
|
|
44
|
+
return /* @__PURE__ */jsxRuntime.jsx(FeatureEnabledContext.Provider, {
|
|
45
|
+
value: status,
|
|
46
|
+
children: props.children
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
function useIsFeatureEnabledContext() {
|
|
50
|
+
return require$$0.useContext(FeatureEnabledContext);
|
|
51
|
+
}
|
|
52
|
+
function FeatureDisabledNotice() {
|
|
53
|
+
return /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
|
|
54
|
+
tone: "primary",
|
|
55
|
+
border: true,
|
|
56
|
+
padding: 2,
|
|
57
|
+
children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
|
|
58
|
+
size: 1,
|
|
59
|
+
children: ["Embeddings index APIs are only available on the", " ", /* @__PURE__ */jsxRuntime.jsx("a", {
|
|
60
|
+
href: "https://sanity.io/pricing",
|
|
61
|
+
children: "Team tier and above"
|
|
62
|
+
}), ". Please upgrade to enable access."]
|
|
63
|
+
})
|
|
64
|
+
});
|
|
65
|
+
}
|
|
19
66
|
|
|
20
67
|
/******************************************************************************
|
|
21
68
|
Copyright (c) Microsoft Corporation.
|
|
@@ -1887,9 +1934,6 @@ function deleteIndex(indexName, client) {
|
|
|
1887
1934
|
url: "/embeddings-index/".concat(dataset, "/").concat(indexName, "?projectId=").concat(projectId)
|
|
1888
1935
|
});
|
|
1889
1936
|
}
|
|
1890
|
-
function publicId(id) {
|
|
1891
|
-
return id.replace("drafts.", "");
|
|
1892
|
-
}
|
|
1893
1937
|
function useApiClient() {
|
|
1894
1938
|
const client = sanity.useClient({
|
|
1895
1939
|
apiVersion: "vX"
|
|
@@ -1906,107 +1950,20 @@ function useApiClient() {
|
|
|
1906
1950
|
return client;
|
|
1907
1951
|
}, [client]);
|
|
1908
1952
|
}
|
|
1909
|
-
const
|
|
1910
|
-
const FeatureEnabledContext = require$$0.createContext("loading");
|
|
1911
|
-
function useIsFeatureEnabled() {
|
|
1912
|
-
const client = sanity.useClient({
|
|
1913
|
-
apiVersion: "2023-09-01"
|
|
1914
|
-
});
|
|
1915
|
-
const [status, setStatus] = require$$0.useState("loading");
|
|
1916
|
-
require$$0.useEffect(() => {
|
|
1917
|
-
client.request({
|
|
1918
|
-
method: "GET",
|
|
1919
|
-
url: "/projects/".concat(client.config().projectId, "/features/").concat(featureName)
|
|
1920
|
-
}).then(isEnabled => {
|
|
1921
|
-
setStatus(isEnabled === "true" || isEnabled === true ? "enabled" : "disabled");
|
|
1922
|
-
}).catch(err => {
|
|
1923
|
-
console.error(err);
|
|
1924
|
-
setStatus("disabled");
|
|
1925
|
-
});
|
|
1926
|
-
}, [client]);
|
|
1927
|
-
return status;
|
|
1928
|
-
}
|
|
1929
|
-
function FeatureEnabledProvider(props) {
|
|
1930
|
-
const status = useIsFeatureEnabled();
|
|
1931
|
-
return /* @__PURE__ */jsxRuntime.jsx(FeatureEnabledContext.Provider, {
|
|
1932
|
-
value: status,
|
|
1933
|
-
children: props.children
|
|
1934
|
-
});
|
|
1935
|
-
}
|
|
1936
|
-
function useIsFeatureEnabledContext() {
|
|
1937
|
-
return require$$0.useContext(FeatureEnabledContext);
|
|
1938
|
-
}
|
|
1939
|
-
function FeatureDisabledNotice() {
|
|
1940
|
-
return /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
|
|
1941
|
-
tone: "primary",
|
|
1942
|
-
border: true,
|
|
1943
|
-
padding: 2,
|
|
1944
|
-
children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
|
|
1945
|
-
size: 1,
|
|
1946
|
-
children: ["Embeddings index APIs are only available on the", " ", /* @__PURE__ */jsxRuntime.jsx("a", {
|
|
1947
|
-
href: "https://sanity.io/pricing",
|
|
1948
|
-
children: "Team tier and above"
|
|
1949
|
-
}), ". Please upgrade to enable access."]
|
|
1950
|
-
})
|
|
1951
|
-
});
|
|
1952
|
-
}
|
|
1953
|
+
const NO_RESULTS_VALUE = "";
|
|
1953
1954
|
const NO_OPTIONS = [];
|
|
1954
1955
|
const NO_FILTER = () => true;
|
|
1955
|
-
function
|
|
1956
|
-
var _a, _b, _c;
|
|
1957
|
-
const defaultEnabled = ((_c = (_b = (_a = props.schemaType) == null ? void 0 : _a.options) == null ? void 0 : _b.embeddingsIndex) == null ? void 0 : _c.searchMode) === "embeddings";
|
|
1958
|
-
const featureState = useIsFeatureEnabledContext();
|
|
1959
|
-
const [semantic, setSemantic] = require$$0.useState(defaultEnabled);
|
|
1960
|
-
const toggleSemantic = require$$0.useCallback(() => setSemantic(current => !current), []);
|
|
1961
|
-
return /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
|
|
1962
|
-
gap: 2,
|
|
1963
|
-
flex: 1,
|
|
1964
|
-
style: {
|
|
1965
|
-
width: "100%"
|
|
1966
|
-
},
|
|
1967
|
-
children: [semantic && featureState == "loading" ? /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
1968
|
-
padding: 2,
|
|
1969
|
-
children: /* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {})
|
|
1970
|
-
}) : null, semantic && featureState == "disabled" ? /* @__PURE__ */jsxRuntime.jsx(FeatureDisabledNotice, {}) : null, /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
1971
|
-
flex: 1,
|
|
1972
|
-
style: {
|
|
1973
|
-
maxHeight: 36,
|
|
1974
|
-
overflow: "hidden"
|
|
1975
|
-
},
|
|
1976
|
-
children: semantic && featureState == "enabled" ? /* @__PURE__ */jsxRuntime.jsx(SemanticSearchInput, {
|
|
1977
|
-
...props
|
|
1978
|
-
}) : props.renderDefault(props)
|
|
1979
|
-
}), /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
|
|
1980
|
-
icon: semantic ? icons.EarthGlobeIcon : icons.LinkIcon,
|
|
1981
|
-
onClick: toggleSemantic,
|
|
1982
|
-
mode: "bleed",
|
|
1983
|
-
title: semantic ? "Switch to standard reference search" : "Switch to semantic reference search"
|
|
1984
|
-
})]
|
|
1985
|
-
});
|
|
1986
|
-
}
|
|
1987
|
-
function useDebouncedValue(value, ms) {
|
|
1988
|
-
const [debouncedValue, setDebouncedValue] = require$$0.useState(value);
|
|
1989
|
-
require$$0.useEffect(() => {
|
|
1990
|
-
const timeoutId = setTimeout(() => {
|
|
1991
|
-
setDebouncedValue(value);
|
|
1992
|
-
}, ms);
|
|
1993
|
-
return () => clearTimeout(timeoutId);
|
|
1994
|
-
}, [value, ms]);
|
|
1995
|
-
return debouncedValue;
|
|
1996
|
-
}
|
|
1997
|
-
function SemanticSearchInput(props) {
|
|
1956
|
+
const SemanticSearchAutocomplete = require$$0.forwardRef(function SemanticSearchAutocomplete2(props, ref) {
|
|
1998
1957
|
const {
|
|
1999
|
-
|
|
2000
|
-
|
|
1958
|
+
indexConfig,
|
|
1959
|
+
filterResult,
|
|
1960
|
+
getEmptySearchValue,
|
|
2001
1961
|
readOnly,
|
|
2002
|
-
|
|
2003
|
-
|
|
1962
|
+
onFocus,
|
|
1963
|
+
onBlur,
|
|
1964
|
+
onChange,
|
|
1965
|
+
typeFilter
|
|
2004
1966
|
} = props;
|
|
2005
|
-
const {
|
|
2006
|
-
value: currentDocument
|
|
2007
|
-
} = desk.useDocumentPane();
|
|
2008
|
-
const docRef = require$$0.useRef(currentDocument);
|
|
2009
|
-
const autocompleteRef = require$$0.useRef(null);
|
|
2010
1967
|
const id = require$$0.useId();
|
|
2011
1968
|
const [query, setQuery] = require$$0.useState("");
|
|
2012
1969
|
const queryRef = require$$0.useRef(query);
|
|
@@ -2015,29 +1972,16 @@ function SemanticSearchInput(props) {
|
|
|
2015
1972
|
const [searching, setSearching] = require$$0.useState(false);
|
|
2016
1973
|
const [options, setOptions] = require$$0.useState(NO_OPTIONS);
|
|
2017
1974
|
const client = useApiClient();
|
|
2018
|
-
require$$0.useEffect(() => {
|
|
2019
|
-
docRef.current = currentDocument;
|
|
2020
|
-
}, [currentDocument]);
|
|
2021
|
-
require$$0.useEffect(() => {
|
|
2022
|
-
var _a;
|
|
2023
|
-
if (value == null ? void 0 : value._ref) {
|
|
2024
|
-
(_a = autocompleteRef.current) == null ? void 0 : _a.focus();
|
|
2025
|
-
}
|
|
2026
|
-
}, []);
|
|
2027
|
-
const handleFocus = require$$0.useCallback(() => onPathFocus(["_ref"]), [onPathFocus]);
|
|
2028
|
-
const handleBlur = require$$0.useCallback(() => onPathFocus([]), [onPathFocus]);
|
|
2029
1975
|
const runIndexQuery = require$$0.useCallback(queryString => {
|
|
2030
|
-
var _a
|
|
1976
|
+
var _a;
|
|
2031
1977
|
setSearching(true);
|
|
2032
|
-
const
|
|
2033
|
-
const
|
|
2034
|
-
const maxResults = (_d = (_c = refSchema.options) == null ? void 0 : _c.embeddingsIndex) == null ? void 0 : _d.maxResults;
|
|
2035
|
-
const typeFilter = refSchema.to.map(ref => ref.name);
|
|
1978
|
+
const indexName = indexConfig == null ? void 0 : indexConfig.indexName;
|
|
1979
|
+
const maxResults = indexConfig == null ? void 0 : indexConfig.maxResults;
|
|
2036
1980
|
if (!indexName) {
|
|
2037
|
-
throw new Error("Reference option embeddingsIndex.indexName is required, but was missing
|
|
1981
|
+
throw new Error("Reference option embeddingsIndex.indexName is required, but was missing");
|
|
2038
1982
|
}
|
|
2039
1983
|
queryIndex({
|
|
2040
|
-
query: queryString.trim().length ? queryString : (
|
|
1984
|
+
query: queryString.trim().length ? queryString : (_a = getEmptySearchValue()) != null ? _a : "",
|
|
2041
1985
|
indexName,
|
|
2042
1986
|
maxResults,
|
|
2043
1987
|
filter: {
|
|
@@ -2046,10 +1990,18 @@ function SemanticSearchInput(props) {
|
|
|
2046
1990
|
}, client).then(result => {
|
|
2047
1991
|
if (queryRef.current === queryString) {
|
|
2048
1992
|
setSearching(false);
|
|
2049
|
-
setOptions(
|
|
1993
|
+
setOptions([]);
|
|
1994
|
+
const resultOptions = result.filter(hit => filterResult ? filterResult(hit) : true).map(r => sanity.typed({
|
|
2050
1995
|
result: r,
|
|
2051
1996
|
value: r.value.documentId
|
|
2052
|
-
}))
|
|
1997
|
+
}));
|
|
1998
|
+
if (resultOptions.length) {
|
|
1999
|
+
setOptions(resultOptions);
|
|
2000
|
+
} else {
|
|
2001
|
+
setOptions([{
|
|
2002
|
+
value: NO_RESULTS_VALUE
|
|
2003
|
+
}]);
|
|
2004
|
+
}
|
|
2053
2005
|
}
|
|
2054
2006
|
}).catch(e => {
|
|
2055
2007
|
if (queryRef.current === queryString) {
|
|
@@ -2057,23 +2009,13 @@ function SemanticSearchInput(props) {
|
|
|
2057
2009
|
}
|
|
2058
2010
|
throw e;
|
|
2059
2011
|
});
|
|
2060
|
-
}, [client,
|
|
2012
|
+
}, [client, indexConfig, getEmptySearchValue, filterResult, typeFilter]);
|
|
2061
2013
|
require$$0.useEffect(() => {
|
|
2062
2014
|
if (prevDebouncedQuery.current !== debouncedQuery) {
|
|
2063
2015
|
runIndexQuery(debouncedQuery);
|
|
2064
2016
|
}
|
|
2065
2017
|
prevDebouncedQuery.current = debouncedQuery;
|
|
2066
2018
|
}, [debouncedQuery, runIndexQuery]);
|
|
2067
|
-
const handleChange = require$$0.useCallback(nextId => {
|
|
2068
|
-
if (!nextId) {
|
|
2069
|
-
onChange(sanity.unset());
|
|
2070
|
-
onPathFocus([]);
|
|
2071
|
-
return;
|
|
2072
|
-
}
|
|
2073
|
-
const patches = [sanity.setIfMissing({}), sanity.set(schemaType.name, ["_type"]), sanity.set(publicId(nextId), ["_ref"]), sanity.unset(["_weak"]), sanity.unset(["_strengthenOnPublish"])];
|
|
2074
|
-
onChange(patches);
|
|
2075
|
-
onPathFocus([]);
|
|
2076
|
-
}, [onChange, onPathFocus, schemaType.name]);
|
|
2077
2019
|
const openButtonConfig = require$$0.useMemo(() => ({
|
|
2078
2020
|
onClick: () => runIndexQuery(queryRef.current)
|
|
2079
2021
|
}), [runIndexQuery, queryRef]);
|
|
@@ -2082,52 +2024,187 @@ function SemanticSearchInput(props) {
|
|
|
2082
2024
|
queryRef.current = newQuery;
|
|
2083
2025
|
setQuery(newQuery);
|
|
2084
2026
|
}, [setQuery]);
|
|
2027
|
+
const handleChange = require$$0.useCallback(value => {
|
|
2028
|
+
if (value === NO_RESULTS_VALUE) {
|
|
2029
|
+
setOptions(NO_OPTIONS);
|
|
2030
|
+
return;
|
|
2031
|
+
}
|
|
2032
|
+
onChange == null ? void 0 : onChange(value);
|
|
2033
|
+
}, [onChange]);
|
|
2085
2034
|
return /* @__PURE__ */jsxRuntime.jsx(ui.Autocomplete, {
|
|
2086
2035
|
id,
|
|
2087
|
-
ref
|
|
2036
|
+
ref,
|
|
2088
2037
|
"data-testid": "semantic-autocomplete",
|
|
2089
2038
|
placeholder: "Type to search...",
|
|
2090
2039
|
openButton: openButtonConfig,
|
|
2091
|
-
onFocus
|
|
2040
|
+
onFocus,
|
|
2092
2041
|
onChange: handleChange,
|
|
2093
2042
|
loading: searching,
|
|
2094
|
-
onBlur
|
|
2043
|
+
onBlur,
|
|
2095
2044
|
readOnly,
|
|
2096
2045
|
filterOption: NO_FILTER,
|
|
2097
2046
|
onQueryChange: handleQueryChange,
|
|
2098
2047
|
options,
|
|
2099
2048
|
renderOption: AutocompleteOption
|
|
2100
2049
|
});
|
|
2101
|
-
}
|
|
2050
|
+
});
|
|
2102
2051
|
function AutocompleteOption(props) {
|
|
2103
|
-
|
|
2052
|
+
if ("result" in props) {
|
|
2053
|
+
const value = props.result.value;
|
|
2054
|
+
return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
|
|
2055
|
+
mode: "bleed",
|
|
2056
|
+
padding: 1,
|
|
2057
|
+
style: {
|
|
2058
|
+
width: "100%"
|
|
2059
|
+
},
|
|
2060
|
+
children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
|
|
2061
|
+
gap: 2,
|
|
2062
|
+
align: "center",
|
|
2063
|
+
children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
2064
|
+
flex: 1,
|
|
2065
|
+
children: /* @__PURE__ */jsxRuntime.jsx(DocumentPreview, {
|
|
2066
|
+
documentId: value.documentId,
|
|
2067
|
+
schemaTypeName: value.type
|
|
2068
|
+
})
|
|
2069
|
+
}), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
2070
|
+
padding: 2,
|
|
2071
|
+
children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
|
|
2072
|
+
size: 1,
|
|
2073
|
+
muted: true,
|
|
2074
|
+
title: "Relevance",
|
|
2075
|
+
children: [Math.floor(props.result.score * 100), "%"]
|
|
2076
|
+
})
|
|
2077
|
+
})]
|
|
2078
|
+
})
|
|
2079
|
+
});
|
|
2080
|
+
}
|
|
2104
2081
|
return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
|
|
2105
2082
|
mode: "bleed",
|
|
2106
2083
|
padding: 1,
|
|
2107
2084
|
style: {
|
|
2108
2085
|
width: "100%"
|
|
2109
2086
|
},
|
|
2110
|
-
|
|
2087
|
+
disabled: true,
|
|
2088
|
+
children: /* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
|
|
2111
2089
|
gap: 2,
|
|
2112
2090
|
align: "center",
|
|
2113
|
-
children:
|
|
2114
|
-
flex: 1,
|
|
2115
|
-
children: /* @__PURE__ */jsxRuntime.jsx(DocumentPreview, {
|
|
2116
|
-
documentId: value.documentId,
|
|
2117
|
-
schemaTypeName: value.type
|
|
2118
|
-
})
|
|
2119
|
-
}), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
2120
|
-
padding: 2,
|
|
2121
|
-
children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
|
|
2122
|
-
size: 1,
|
|
2123
|
-
muted: true,
|
|
2124
|
-
title: "Relevance",
|
|
2125
|
-
children: [Math.floor(props.result.score * 100), "%"]
|
|
2126
|
-
})
|
|
2127
|
-
})]
|
|
2091
|
+
children: "No results."
|
|
2128
2092
|
})
|
|
2129
2093
|
});
|
|
2130
2094
|
}
|
|
2095
|
+
function useDebouncedValue(value, ms) {
|
|
2096
|
+
const [debouncedValue, setDebouncedValue] = require$$0.useState(value);
|
|
2097
|
+
require$$0.useEffect(() => {
|
|
2098
|
+
const timeoutId = setTimeout(() => {
|
|
2099
|
+
setDebouncedValue(value);
|
|
2100
|
+
}, ms);
|
|
2101
|
+
return () => clearTimeout(timeoutId);
|
|
2102
|
+
}, [value, ms]);
|
|
2103
|
+
return debouncedValue;
|
|
2104
|
+
}
|
|
2105
|
+
function useEmeddingsConfig(embeddingsIndexConfig, defaultConfig) {
|
|
2106
|
+
return require$$0.useMemo(() => {
|
|
2107
|
+
if (embeddingsIndexConfig === true || !embeddingsIndexConfig) {
|
|
2108
|
+
if (!(defaultConfig == null ? void 0 : defaultConfig.indexName)) {
|
|
2109
|
+
throw new Error("Default embeddingsIndex config is missing. When options.embeddingsIndex: true, embeddingsIndexReferenceInput plugin config is required.");
|
|
2110
|
+
}
|
|
2111
|
+
return defaultConfig;
|
|
2112
|
+
}
|
|
2113
|
+
const finalConfig = {
|
|
2114
|
+
...defaultConfig,
|
|
2115
|
+
...embeddingsIndexConfig
|
|
2116
|
+
};
|
|
2117
|
+
if (!(finalConfig == null ? void 0 : finalConfig.indexName)) {
|
|
2118
|
+
throw new Error("indexName is missing. Either set it in options.embeddingsIndex or configure defaults using plugin config.");
|
|
2119
|
+
}
|
|
2120
|
+
return finalConfig;
|
|
2121
|
+
}, [defaultConfig, embeddingsIndexConfig]);
|
|
2122
|
+
}
|
|
2123
|
+
function SemanticSearchReferenceInput(props) {
|
|
2124
|
+
var _a, _b;
|
|
2125
|
+
const embeddingsIndexConfig = (_b = (_a = props.schemaType) == null ? void 0 : _a.options) == null ? void 0 : _b.embeddingsIndex;
|
|
2126
|
+
const config = useEmeddingsConfig(embeddingsIndexConfig, props.defaultConfig);
|
|
2127
|
+
const defaultEnabled = config.searchMode === "embeddings";
|
|
2128
|
+
const featureState = useIsFeatureEnabledContext();
|
|
2129
|
+
const [semantic, setSemantic] = require$$0.useState(defaultEnabled);
|
|
2130
|
+
const toggleSemantic = require$$0.useCallback(() => setSemantic(current => !current), []);
|
|
2131
|
+
return /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
|
|
2132
|
+
gap: 2,
|
|
2133
|
+
flex: 1,
|
|
2134
|
+
style: {
|
|
2135
|
+
width: "100%"
|
|
2136
|
+
},
|
|
2137
|
+
children: [semantic && featureState == "loading" ? /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
2138
|
+
padding: 2,
|
|
2139
|
+
children: /* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {})
|
|
2140
|
+
}) : null, semantic && featureState == "disabled" ? /* @__PURE__ */jsxRuntime.jsx(FeatureDisabledNotice, {}) : null, /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
2141
|
+
flex: 1,
|
|
2142
|
+
style: {
|
|
2143
|
+
maxHeight: 36,
|
|
2144
|
+
overflow: "hidden"
|
|
2145
|
+
},
|
|
2146
|
+
children: semantic && featureState == "enabled" ? /* @__PURE__ */jsxRuntime.jsx(SemanticSearchInput, {
|
|
2147
|
+
...props,
|
|
2148
|
+
indexConfig: config
|
|
2149
|
+
}) : props.renderDefault(props)
|
|
2150
|
+
}), /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
|
|
2151
|
+
icon: semantic ? icons.EarthGlobeIcon : icons.LinkIcon,
|
|
2152
|
+
onClick: toggleSemantic,
|
|
2153
|
+
mode: "bleed",
|
|
2154
|
+
title: semantic ? "Switch to standard reference search" : "Switch to semantic reference search"
|
|
2155
|
+
})]
|
|
2156
|
+
});
|
|
2157
|
+
}
|
|
2158
|
+
function SemanticSearchInput(props) {
|
|
2159
|
+
const {
|
|
2160
|
+
indexConfig,
|
|
2161
|
+
onPathFocus,
|
|
2162
|
+
onChange,
|
|
2163
|
+
readOnly,
|
|
2164
|
+
schemaType,
|
|
2165
|
+
value
|
|
2166
|
+
} = props;
|
|
2167
|
+
const {
|
|
2168
|
+
value: currentDocument
|
|
2169
|
+
} = desk.useDocumentPane();
|
|
2170
|
+
const docRef = require$$0.useRef(currentDocument);
|
|
2171
|
+
const autocompleteRef = require$$0.useRef(null);
|
|
2172
|
+
require$$0.useEffect(() => {
|
|
2173
|
+
docRef.current = currentDocument;
|
|
2174
|
+
}, [currentDocument]);
|
|
2175
|
+
require$$0.useEffect(() => {
|
|
2176
|
+
var _a;
|
|
2177
|
+
if (value == null ? void 0 : value._ref) {
|
|
2178
|
+
(_a = autocompleteRef.current) == null ? void 0 : _a.focus();
|
|
2179
|
+
}
|
|
2180
|
+
}, []);
|
|
2181
|
+
const handleFocus = require$$0.useCallback(() => onPathFocus(["_ref"]), [onPathFocus]);
|
|
2182
|
+
const handleBlur = require$$0.useCallback(() => onPathFocus([]), [onPathFocus]);
|
|
2183
|
+
const handleChange = require$$0.useCallback(nextId => {
|
|
2184
|
+
if (!nextId) {
|
|
2185
|
+
onChange(sanity.unset());
|
|
2186
|
+
onPathFocus([]);
|
|
2187
|
+
return;
|
|
2188
|
+
}
|
|
2189
|
+
const patches = [sanity.setIfMissing({}), sanity.set(schemaType.name, ["_type"]), sanity.set(publicId(nextId), ["_ref"]), sanity.unset(["_weak"]), sanity.unset(["_strengthenOnPublish"])];
|
|
2190
|
+
onChange(patches);
|
|
2191
|
+
onPathFocus([]);
|
|
2192
|
+
}, [onChange, onPathFocus, schemaType.name]);
|
|
2193
|
+
const filterResult = require$$0.useCallback(r => r.value.documentId !== publicId(docRef.current._id), [docRef]);
|
|
2194
|
+
const getEmptySearchValue = require$$0.useCallback(() => JSON.stringify(docRef.current), [docRef]);
|
|
2195
|
+
const typeFilter = require$$0.useMemo(() => schemaType.to.map(refType => refType.name), [schemaType]);
|
|
2196
|
+
return /* @__PURE__ */jsxRuntime.jsx(SemanticSearchAutocomplete, {
|
|
2197
|
+
ref: autocompleteRef,
|
|
2198
|
+
typeFilter,
|
|
2199
|
+
indexConfig,
|
|
2200
|
+
onChange: handleChange,
|
|
2201
|
+
onFocus: handleFocus,
|
|
2202
|
+
onBlur: handleBlur,
|
|
2203
|
+
getEmptySearchValue,
|
|
2204
|
+
filterResult,
|
|
2205
|
+
readOnly
|
|
2206
|
+
});
|
|
2207
|
+
}
|
|
2131
2208
|
function isType(schemaType, typeName) {
|
|
2132
2209
|
if (schemaType.name === typeName) {
|
|
2133
2210
|
return true;
|
|
@@ -2137,30 +2214,35 @@ function isType(schemaType, typeName) {
|
|
|
2137
2214
|
}
|
|
2138
2215
|
return isType(schemaType.type, typeName);
|
|
2139
2216
|
}
|
|
2140
|
-
const embeddingsIndexReferenceInput = sanity.definePlugin({
|
|
2141
|
-
|
|
2142
|
-
|
|
2143
|
-
|
|
2144
|
-
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
}
|
|
2150
|
-
},
|
|
2151
|
-
form: {
|
|
2152
|
-
components: {
|
|
2153
|
-
input: props => {
|
|
2154
|
-
var _a, _b;
|
|
2155
|
-
if (sanity.isObjectInputProps(props) && isType(props.schemaType, "reference") && ((_b = (_a = props.schemaType.options) == null ? void 0 : _a.embeddingsIndex) == null ? void 0 : _b.indexName)) {
|
|
2156
|
-
return /* @__PURE__ */jsxRuntime.jsx(SemanticSearchReferenceInput, {
|
|
2157
|
-
...props
|
|
2217
|
+
const embeddingsIndexReferenceInput = sanity.definePlugin(defaultConfig => {
|
|
2218
|
+
const config = typeof defaultConfig === "object" ? defaultConfig : void 0;
|
|
2219
|
+
return {
|
|
2220
|
+
name: "@sanity/embeddings-index-reference-input",
|
|
2221
|
+
studio: {
|
|
2222
|
+
components: {
|
|
2223
|
+
layout: props => {
|
|
2224
|
+
return /* @__PURE__ */jsxRuntime.jsx(FeatureEnabledProvider, {
|
|
2225
|
+
children: props.renderDefault(props)
|
|
2158
2226
|
});
|
|
2159
2227
|
}
|
|
2160
|
-
|
|
2228
|
+
}
|
|
2229
|
+
},
|
|
2230
|
+
form: {
|
|
2231
|
+
components: {
|
|
2232
|
+
input: props => {
|
|
2233
|
+
var _a, _b;
|
|
2234
|
+
const embeddingsIndexConfig = (_b = (_a = props.schemaType) == null ? void 0 : _a.options) == null ? void 0 : _b.embeddingsIndex;
|
|
2235
|
+
if (sanity.isObjectInputProps(props) && isType(props.schemaType, "reference") && (embeddingsIndexConfig === true || (embeddingsIndexConfig == null ? void 0 : embeddingsIndexConfig.indexName))) {
|
|
2236
|
+
return /* @__PURE__ */jsxRuntime.jsx(SemanticSearchReferenceInput, {
|
|
2237
|
+
...props,
|
|
2238
|
+
defaultConfig: config
|
|
2239
|
+
});
|
|
2240
|
+
}
|
|
2241
|
+
return props.renderDefault(props);
|
|
2242
|
+
}
|
|
2161
2243
|
}
|
|
2162
2244
|
}
|
|
2163
|
-
}
|
|
2245
|
+
};
|
|
2164
2246
|
});
|
|
2165
2247
|
const defaultProjection = "{...}";
|
|
2166
2248
|
function useDefaultIndex(schema, dataset) {
|
|
@@ -2175,6 +2257,7 @@ function IndexFormInput(props) {
|
|
|
2175
2257
|
var _a;
|
|
2176
2258
|
const {
|
|
2177
2259
|
label,
|
|
2260
|
+
description,
|
|
2178
2261
|
index,
|
|
2179
2262
|
prop,
|
|
2180
2263
|
onChange,
|
|
@@ -2188,6 +2271,7 @@ function IndexFormInput(props) {
|
|
|
2188
2271
|
})), [onChange, prop]);
|
|
2189
2272
|
return /* @__PURE__ */jsxRuntime.jsx(FormInput, {
|
|
2190
2273
|
label,
|
|
2274
|
+
description,
|
|
2191
2275
|
onChange: handleChange,
|
|
2192
2276
|
value: (_a = index[prop]) != null ? _a : "",
|
|
2193
2277
|
readOnly,
|
|
@@ -2198,6 +2282,7 @@ function IndexFormInput(props) {
|
|
|
2198
2282
|
function FormInput(props) {
|
|
2199
2283
|
const {
|
|
2200
2284
|
label,
|
|
2285
|
+
description,
|
|
2201
2286
|
onChange,
|
|
2202
2287
|
value,
|
|
2203
2288
|
readOnly,
|
|
@@ -2215,6 +2300,12 @@ function FormInput(props) {
|
|
|
2215
2300
|
htmlFor: id,
|
|
2216
2301
|
children: label
|
|
2217
2302
|
})
|
|
2303
|
+
}), description && /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
2304
|
+
children: /* @__PURE__ */jsxRuntime.jsx(ui.Text, {
|
|
2305
|
+
size: 1,
|
|
2306
|
+
muted: true,
|
|
2307
|
+
children: description
|
|
2308
|
+
})
|
|
2218
2309
|
}), type === "text" ? /* @__PURE__ */jsxRuntime.jsx(ui.TextInput, {
|
|
2219
2310
|
id,
|
|
2220
2311
|
value,
|
|
@@ -2369,18 +2460,20 @@ function IndexEditor(props) {
|
|
|
2369
2460
|
onChange: setIndex,
|
|
2370
2461
|
readOnly: true
|
|
2371
2462
|
}), /* @__PURE__ */jsxRuntime.jsx(IndexFormInput, {
|
|
2372
|
-
label: "
|
|
2373
|
-
|
|
2463
|
+
label: "Filter",
|
|
2464
|
+
description: "Must be a valid GROQ filter",
|
|
2465
|
+
placeholder: defaultIndex.filter,
|
|
2374
2466
|
index,
|
|
2375
|
-
prop: "
|
|
2467
|
+
prop: "filter",
|
|
2376
2468
|
onChange: setIndex,
|
|
2377
2469
|
readOnly,
|
|
2378
2470
|
type: "textarea"
|
|
2379
2471
|
}), /* @__PURE__ */jsxRuntime.jsx(IndexFormInput, {
|
|
2380
|
-
label: "
|
|
2381
|
-
|
|
2472
|
+
label: "Projection",
|
|
2473
|
+
description: "Must be a valid GROQ projection, starting { and ending with }",
|
|
2474
|
+
placeholder: defaultIndex.projection,
|
|
2382
2475
|
index,
|
|
2383
|
-
prop: "
|
|
2476
|
+
prop: "projection",
|
|
2384
2477
|
onChange: setIndex,
|
|
2385
2478
|
readOnly,
|
|
2386
2479
|
type: "textarea"
|
|
@@ -2417,6 +2510,7 @@ function IndexList(props) {
|
|
|
2417
2510
|
borderBottom: true,
|
|
2418
2511
|
flex: 1,
|
|
2419
2512
|
paddingBottom: 2,
|
|
2513
|
+
padding: 3,
|
|
2420
2514
|
children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
|
|
2421
2515
|
children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
2422
2516
|
flex: 1,
|
|
@@ -2471,12 +2565,15 @@ function IndexRow(props) {
|
|
|
2471
2565
|
const onSelect = require$$0.useCallback(() => onIndexSelected(index), [onIndexSelected, index]);
|
|
2472
2566
|
return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
|
|
2473
2567
|
tone: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "primary" : "default",
|
|
2474
|
-
mode: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "default" : "
|
|
2568
|
+
mode: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "default" : "ghost",
|
|
2475
2569
|
onClick: onSelect,
|
|
2570
|
+
padding: 3,
|
|
2476
2571
|
children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
|
|
2477
2572
|
children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
2478
2573
|
flex: 1,
|
|
2479
|
-
children:
|
|
2574
|
+
children: /* @__PURE__ */jsxRuntime.jsx("strong", {
|
|
2575
|
+
children: index.indexName
|
|
2576
|
+
})
|
|
2480
2577
|
}), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
2481
2578
|
flex: 1,
|
|
2482
2579
|
children: index.dataset
|
|
@@ -2490,102 +2587,18 @@ function IndexRow(props) {
|
|
|
2490
2587
|
})
|
|
2491
2588
|
}, index.indexName);
|
|
2492
2589
|
}
|
|
2493
|
-
const NO_RESULTS = [];
|
|
2494
2590
|
function QueryIndex(props) {
|
|
2495
2591
|
const {
|
|
2496
2592
|
indexName
|
|
2497
2593
|
} = props;
|
|
2498
|
-
const
|
|
2499
|
-
const
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
indexName,
|
|
2507
|
-
maxResults: 5
|
|
2508
|
-
}, client).then(setResults).finally(() => setSearching(false));
|
|
2509
|
-
}, [client, indexName]);
|
|
2510
|
-
const onInputChange = require$$0.useCallback(e => {
|
|
2511
|
-
setQuery(e.currentTarget.value);
|
|
2512
|
-
}, []);
|
|
2513
|
-
const onKeyDown = require$$0.useCallback(e => {
|
|
2514
|
-
if (e.key === "Enter") {
|
|
2515
|
-
search(query).catch(console.error);
|
|
2516
|
-
}
|
|
2517
|
-
}, [search, query]);
|
|
2518
|
-
return /* @__PURE__ */jsxRuntime.jsxs(ui.Stack, {
|
|
2519
|
-
space: 3,
|
|
2520
|
-
flex: 1,
|
|
2521
|
-
children: [/* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
|
|
2522
|
-
flex: 1,
|
|
2523
|
-
children: /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
|
|
2524
|
-
flex: 1,
|
|
2525
|
-
children: /* @__PURE__ */jsxRuntime.jsx(ui.TextInput, {
|
|
2526
|
-
iconRight: searching ? /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
2527
|
-
style: {
|
|
2528
|
-
marginTop: 5
|
|
2529
|
-
},
|
|
2530
|
-
children: /* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {})
|
|
2531
|
-
}) : icons.SearchIcon,
|
|
2532
|
-
placeholder: "Find documents",
|
|
2533
|
-
value: query,
|
|
2534
|
-
disabled: searching,
|
|
2535
|
-
onChange: onInputChange,
|
|
2536
|
-
onKeyDown
|
|
2537
|
-
})
|
|
2538
|
-
})
|
|
2539
|
-
}), /* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
|
|
2540
|
-
gap: 4,
|
|
2541
|
-
style: {
|
|
2542
|
-
opacity: searching ? 0.5 : 1
|
|
2543
|
-
},
|
|
2544
|
-
children: /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
2545
|
-
flex: 1,
|
|
2546
|
-
children: /* @__PURE__ */jsxRuntime.jsx(ResultList, {
|
|
2547
|
-
results,
|
|
2548
|
-
query
|
|
2549
|
-
})
|
|
2550
|
-
})
|
|
2551
|
-
})]
|
|
2552
|
-
});
|
|
2553
|
-
}
|
|
2554
|
-
function ResultList(props) {
|
|
2555
|
-
const {
|
|
2556
|
-
results,
|
|
2557
|
-
query
|
|
2558
|
-
} = props;
|
|
2559
|
-
return /* @__PURE__ */jsxRuntime.jsx(ui.Stack, {
|
|
2560
|
-
space: 4,
|
|
2561
|
-
height: "fill",
|
|
2562
|
-
children: /* @__PURE__ */jsxRuntime.jsxs(ui.Stack, {
|
|
2563
|
-
space: 2,
|
|
2564
|
-
children: [results.map(r => /* @__PURE__ */jsxRuntime.jsx(ResultEntry, {
|
|
2565
|
-
result: r
|
|
2566
|
-
}, r.value.documentId)), !results.length && query ? "No results." : null]
|
|
2567
|
-
})
|
|
2568
|
-
});
|
|
2569
|
-
}
|
|
2570
|
-
function ResultEntry(props) {
|
|
2571
|
-
const value = props.result.value;
|
|
2572
|
-
return /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
|
|
2573
|
-
gap: 4,
|
|
2574
|
-
align: "center",
|
|
2575
|
-
children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
2576
|
-
flex: 1,
|
|
2577
|
-
children: /* @__PURE__ */jsxRuntime.jsx(DocumentPreview, {
|
|
2578
|
-
documentId: value.documentId,
|
|
2579
|
-
schemaTypeName: value.type,
|
|
2580
|
-
button: true
|
|
2581
|
-
})
|
|
2582
|
-
}), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
|
|
2583
|
-
children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
|
|
2584
|
-
muted: true,
|
|
2585
|
-
size: 1,
|
|
2586
|
-
children: [Math.floor(props.result.score * 100), " %"]
|
|
2587
|
-
})
|
|
2588
|
-
})]
|
|
2594
|
+
const getEmpty = require$$0.useCallback(() => "anything", []);
|
|
2595
|
+
const indexConfig = require$$0.useMemo(() => ({
|
|
2596
|
+
indexName,
|
|
2597
|
+
maxResults: 8
|
|
2598
|
+
}), [indexName]);
|
|
2599
|
+
return /* @__PURE__ */jsxRuntime.jsx(SemanticSearchAutocomplete, {
|
|
2600
|
+
getEmptySearchValue: getEmpty,
|
|
2601
|
+
indexConfig
|
|
2589
2602
|
});
|
|
2590
2603
|
}
|
|
2591
2604
|
function IndexInfo(_ref3) {
|