@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/dist/index.esm.js CHANGED
@@ -1,10 +1,57 @@
1
- import { useSchema, DefaultPreview, useDocumentPreviewStore, SanityDefaultPreview, getPreviewValueWithFallback, getPreviewStateObservable, useClient, typed, unset, setIfMissing, set, definePlugin, isObjectInputProps } from 'sanity';
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, Text, Flex, Spinner, Autocomplete, Stack, Label, TextInput, TextArea, Dialog, Heading, MenuButton, Menu, MenuItem } from '@sanity/ui';
4
- import { ErrorOutlineIcon, EarthGlobeIcon, LinkIcon, AddIcon, SearchIcon, EllipsisVerticalIcon, TrashIcon, UndoIcon } from '@sanity/icons';
5
- import require$$0, { useMemo, useRef, useEffect, createContext, useState, useContext, useCallback, useId } from 'react';
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,107 +1939,20 @@ function useApiClient() {
1895
1939
  return client;
1896
1940
  }, [client]);
1897
1941
  }
1898
- const featureName = "embeddingsIndexApi";
1899
- const FeatureEnabledContext = createContext("loading");
1900
- function useIsFeatureEnabled() {
1901
- const client = useClient({
1902
- apiVersion: "2023-09-01"
1903
- });
1904
- const [status, setStatus] = useState("loading");
1905
- useEffect(() => {
1906
- client.request({
1907
- method: "GET",
1908
- url: "/projects/".concat(client.config().projectId, "/features/").concat(featureName)
1909
- }).then(isEnabled => {
1910
- setStatus(isEnabled === "true" || isEnabled === true ? "enabled" : "disabled");
1911
- }).catch(err => {
1912
- console.error(err);
1913
- setStatus("disabled");
1914
- });
1915
- }, [client]);
1916
- return status;
1917
- }
1918
- function FeatureEnabledProvider(props) {
1919
- const status = useIsFeatureEnabled();
1920
- return /* @__PURE__ */jsx(FeatureEnabledContext.Provider, {
1921
- value: status,
1922
- children: props.children
1923
- });
1924
- }
1925
- function useIsFeatureEnabledContext() {
1926
- return useContext(FeatureEnabledContext);
1927
- }
1928
- function FeatureDisabledNotice() {
1929
- return /* @__PURE__ */jsx(Card, {
1930
- tone: "primary",
1931
- border: true,
1932
- padding: 2,
1933
- children: /* @__PURE__ */jsxs(Text, {
1934
- size: 1,
1935
- children: ["Embeddings index APIs are only available on the", " ", /* @__PURE__ */jsx("a", {
1936
- href: "https://sanity.io/pricing",
1937
- children: "Team tier and above"
1938
- }), ". Please upgrade to enable access."]
1939
- })
1940
- });
1941
- }
1942
+ const NO_RESULTS_VALUE = "";
1942
1943
  const NO_OPTIONS = [];
1943
1944
  const NO_FILTER = () => true;
1944
- function SemanticSearchReferenceInput(props) {
1945
- var _a, _b, _c;
1946
- const defaultEnabled = ((_c = (_b = (_a = props.schemaType) == null ? void 0 : _a.options) == null ? void 0 : _b.embeddingsIndex) == null ? void 0 : _c.searchMode) === "embeddings";
1947
- const featureState = useIsFeatureEnabledContext();
1948
- const [semantic, setSemantic] = useState(defaultEnabled);
1949
- const toggleSemantic = useCallback(() => setSemantic(current => !current), []);
1950
- return /* @__PURE__ */jsxs(Flex, {
1951
- gap: 2,
1952
- flex: 1,
1953
- style: {
1954
- width: "100%"
1955
- },
1956
- children: [semantic && featureState == "loading" ? /* @__PURE__ */jsx(Box, {
1957
- padding: 2,
1958
- children: /* @__PURE__ */jsx(Spinner, {})
1959
- }) : null, semantic && featureState == "disabled" ? /* @__PURE__ */jsx(FeatureDisabledNotice, {}) : null, /* @__PURE__ */jsx(Box, {
1960
- flex: 1,
1961
- style: {
1962
- maxHeight: 36,
1963
- overflow: "hidden"
1964
- },
1965
- children: semantic && featureState == "enabled" ? /* @__PURE__ */jsx(SemanticSearchInput, {
1966
- ...props
1967
- }) : props.renderDefault(props)
1968
- }), /* @__PURE__ */jsx(Button, {
1969
- icon: semantic ? EarthGlobeIcon : LinkIcon,
1970
- onClick: toggleSemantic,
1971
- mode: "bleed",
1972
- title: semantic ? "Switch to standard reference search" : "Switch to semantic reference search"
1973
- })]
1974
- });
1975
- }
1976
- function useDebouncedValue(value, ms) {
1977
- const [debouncedValue, setDebouncedValue] = useState(value);
1978
- useEffect(() => {
1979
- const timeoutId = setTimeout(() => {
1980
- setDebouncedValue(value);
1981
- }, ms);
1982
- return () => clearTimeout(timeoutId);
1983
- }, [value, ms]);
1984
- return debouncedValue;
1985
- }
1986
- function SemanticSearchInput(props) {
1945
+ const SemanticSearchAutocomplete = forwardRef(function SemanticSearchAutocomplete2(props, ref) {
1987
1946
  const {
1988
- onPathFocus,
1989
- onChange,
1947
+ indexConfig,
1948
+ filterResult,
1949
+ getEmptySearchValue,
1990
1950
  readOnly,
1991
- schemaType,
1992
- value
1951
+ onFocus,
1952
+ onBlur,
1953
+ onChange,
1954
+ typeFilter
1993
1955
  } = props;
1994
- const {
1995
- value: currentDocument
1996
- } = useDocumentPane();
1997
- const docRef = useRef(currentDocument);
1998
- const autocompleteRef = useRef(null);
1999
1956
  const id = useId();
2000
1957
  const [query, setQuery] = useState("");
2001
1958
  const queryRef = useRef(query);
@@ -2004,29 +1961,16 @@ function SemanticSearchInput(props) {
2004
1961
  const [searching, setSearching] = useState(false);
2005
1962
  const [options, setOptions] = useState(NO_OPTIONS);
2006
1963
  const client = useApiClient();
2007
- useEffect(() => {
2008
- docRef.current = currentDocument;
2009
- }, [currentDocument]);
2010
- useEffect(() => {
2011
- var _a;
2012
- if (value == null ? void 0 : value._ref) {
2013
- (_a = autocompleteRef.current) == null ? void 0 : _a.focus();
2014
- }
2015
- }, []);
2016
- const handleFocus = useCallback(() => onPathFocus(["_ref"]), [onPathFocus]);
2017
- const handleBlur = useCallback(() => onPathFocus([]), [onPathFocus]);
2018
1964
  const runIndexQuery = useCallback(queryString => {
2019
- var _a, _b, _c, _d, _e;
1965
+ var _a;
2020
1966
  setSearching(true);
2021
- const refSchema = schemaType;
2022
- const indexName = (_b = (_a = refSchema.options) == null ? void 0 : _a.embeddingsIndex) == null ? void 0 : _b.indexName;
2023
- const maxResults = (_d = (_c = refSchema.options) == null ? void 0 : _c.embeddingsIndex) == null ? void 0 : _d.maxResults;
2024
- 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;
2025
1969
  if (!indexName) {
2026
- throw new Error("Reference option embeddingsIndex.indexName is required, but was missing in type ".concat(refSchema.name));
1970
+ throw new Error("Reference option embeddingsIndex.indexName is required, but was missing");
2027
1971
  }
2028
1972
  queryIndex({
2029
- query: queryString.trim().length ? queryString : (_e = JSON.stringify(docRef.current)) != null ? _e : "",
1973
+ query: queryString.trim().length ? queryString : (_a = getEmptySearchValue()) != null ? _a : "",
2030
1974
  indexName,
2031
1975
  maxResults,
2032
1976
  filter: {
@@ -2035,10 +1979,18 @@ function SemanticSearchInput(props) {
2035
1979
  }, client).then(result => {
2036
1980
  if (queryRef.current === queryString) {
2037
1981
  setSearching(false);
2038
- setOptions(result.filter(r => r.value.documentId !== publicId(docRef.current._id)).map(r => typed({
1982
+ setOptions([]);
1983
+ const resultOptions = result.filter(hit => filterResult ? filterResult(hit) : true).map(r => typed({
2039
1984
  result: r,
2040
1985
  value: r.value.documentId
2041
- })));
1986
+ }));
1987
+ if (resultOptions.length) {
1988
+ setOptions(resultOptions);
1989
+ } else {
1990
+ setOptions([{
1991
+ value: NO_RESULTS_VALUE
1992
+ }]);
1993
+ }
2042
1994
  }
2043
1995
  }).catch(e => {
2044
1996
  if (queryRef.current === queryString) {
@@ -2046,23 +1998,13 @@ function SemanticSearchInput(props) {
2046
1998
  }
2047
1999
  throw e;
2048
2000
  });
2049
- }, [client, schemaType]);
2001
+ }, [client, indexConfig, getEmptySearchValue, filterResult, typeFilter]);
2050
2002
  useEffect(() => {
2051
2003
  if (prevDebouncedQuery.current !== debouncedQuery) {
2052
2004
  runIndexQuery(debouncedQuery);
2053
2005
  }
2054
2006
  prevDebouncedQuery.current = debouncedQuery;
2055
2007
  }, [debouncedQuery, runIndexQuery]);
2056
- const handleChange = useCallback(nextId => {
2057
- if (!nextId) {
2058
- onChange(unset());
2059
- onPathFocus([]);
2060
- return;
2061
- }
2062
- const patches = [setIfMissing({}), set(schemaType.name, ["_type"]), set(publicId(nextId), ["_ref"]), unset(["_weak"]), unset(["_strengthenOnPublish"])];
2063
- onChange(patches);
2064
- onPathFocus([]);
2065
- }, [onChange, onPathFocus, schemaType.name]);
2066
2008
  const openButtonConfig = useMemo(() => ({
2067
2009
  onClick: () => runIndexQuery(queryRef.current)
2068
2010
  }), [runIndexQuery, queryRef]);
@@ -2071,52 +2013,187 @@ function SemanticSearchInput(props) {
2071
2013
  queryRef.current = newQuery;
2072
2014
  setQuery(newQuery);
2073
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]);
2074
2023
  return /* @__PURE__ */jsx(Autocomplete, {
2075
2024
  id,
2076
- ref: autocompleteRef,
2025
+ ref,
2077
2026
  "data-testid": "semantic-autocomplete",
2078
2027
  placeholder: "Type to search...",
2079
2028
  openButton: openButtonConfig,
2080
- onFocus: handleFocus,
2029
+ onFocus,
2081
2030
  onChange: handleChange,
2082
2031
  loading: searching,
2083
- onBlur: handleBlur,
2032
+ onBlur,
2084
2033
  readOnly,
2085
2034
  filterOption: NO_FILTER,
2086
2035
  onQueryChange: handleQueryChange,
2087
2036
  options,
2088
2037
  renderOption: AutocompleteOption
2089
2038
  });
2090
- }
2039
+ });
2091
2040
  function AutocompleteOption(props) {
2092
- const value = props.result.value;
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
+ }
2093
2070
  return /* @__PURE__ */jsx(Button, {
2094
2071
  mode: "bleed",
2095
2072
  padding: 1,
2096
2073
  style: {
2097
2074
  width: "100%"
2098
2075
  },
2099
- children: /* @__PURE__ */jsxs(Flex, {
2076
+ disabled: true,
2077
+ children: /* @__PURE__ */jsx(Flex, {
2100
2078
  gap: 2,
2101
2079
  align: "center",
2102
- children: [/* @__PURE__ */jsx(Box, {
2103
- flex: 1,
2104
- children: /* @__PURE__ */jsx(DocumentPreview, {
2105
- documentId: value.documentId,
2106
- schemaTypeName: value.type
2107
- })
2108
- }), /* @__PURE__ */jsx(Box, {
2109
- padding: 2,
2110
- children: /* @__PURE__ */jsxs(Text, {
2111
- size: 1,
2112
- muted: true,
2113
- title: "Relevance",
2114
- children: [Math.floor(props.result.score * 100), "%"]
2115
- })
2116
- })]
2080
+ children: "No results."
2117
2081
  })
2118
2082
  });
2119
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
+ }
2120
2197
  function isType(schemaType, typeName) {
2121
2198
  if (schemaType.name === typeName) {
2122
2199
  return true;
@@ -2126,30 +2203,35 @@ function isType(schemaType, typeName) {
2126
2203
  }
2127
2204
  return isType(schemaType.type, typeName);
2128
2205
  }
2129
- const embeddingsIndexReferenceInput = definePlugin({
2130
- name: "@sanity/embeddings-index-reference-input",
2131
- studio: {
2132
- components: {
2133
- layout: props => {
2134
- return /* @__PURE__ */jsx(FeatureEnabledProvider, {
2135
- children: props.renderDefault(props)
2136
- });
2137
- }
2138
- }
2139
- },
2140
- form: {
2141
- components: {
2142
- input: props => {
2143
- var _a, _b;
2144
- if (isObjectInputProps(props) && isType(props.schemaType, "reference") && ((_b = (_a = props.schemaType.options) == null ? void 0 : _a.embeddingsIndex) == null ? void 0 : _b.indexName)) {
2145
- return /* @__PURE__ */jsx(SemanticSearchReferenceInput, {
2146
- ...props
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)
2147
2215
  });
2148
2216
  }
2149
- return props.renderDefault(props);
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
+ }
2150
2232
  }
2151
2233
  }
2152
- }
2234
+ };
2153
2235
  });
2154
2236
  const defaultProjection = "{...}";
2155
2237
  function useDefaultIndex(schema, dataset) {
@@ -2164,6 +2246,7 @@ function IndexFormInput(props) {
2164
2246
  var _a;
2165
2247
  const {
2166
2248
  label,
2249
+ description,
2167
2250
  index,
2168
2251
  prop,
2169
2252
  onChange,
@@ -2177,6 +2260,7 @@ function IndexFormInput(props) {
2177
2260
  })), [onChange, prop]);
2178
2261
  return /* @__PURE__ */jsx(FormInput, {
2179
2262
  label,
2263
+ description,
2180
2264
  onChange: handleChange,
2181
2265
  value: (_a = index[prop]) != null ? _a : "",
2182
2266
  readOnly,
@@ -2187,6 +2271,7 @@ function IndexFormInput(props) {
2187
2271
  function FormInput(props) {
2188
2272
  const {
2189
2273
  label,
2274
+ description,
2190
2275
  onChange,
2191
2276
  value,
2192
2277
  readOnly,
@@ -2204,6 +2289,12 @@ function FormInput(props) {
2204
2289
  htmlFor: id,
2205
2290
  children: label
2206
2291
  })
2292
+ }), description && /* @__PURE__ */jsx(Box, {
2293
+ children: /* @__PURE__ */jsx(Text, {
2294
+ size: 1,
2295
+ muted: true,
2296
+ children: description
2297
+ })
2207
2298
  }), type === "text" ? /* @__PURE__ */jsx(TextInput, {
2208
2299
  id,
2209
2300
  value,
@@ -2358,18 +2449,20 @@ function IndexEditor(props) {
2358
2449
  onChange: setIndex,
2359
2450
  readOnly: true
2360
2451
  }), /* @__PURE__ */jsx(IndexFormInput, {
2361
- label: "Projection",
2362
- placeholder: defaultIndex.projection,
2452
+ label: "Filter",
2453
+ description: "Must be a valid GROQ filter",
2454
+ placeholder: defaultIndex.filter,
2363
2455
  index,
2364
- prop: "projection",
2456
+ prop: "filter",
2365
2457
  onChange: setIndex,
2366
2458
  readOnly,
2367
2459
  type: "textarea"
2368
2460
  }), /* @__PURE__ */jsx(IndexFormInput, {
2369
- label: "Filter",
2370
- placeholder: defaultIndex.filter,
2461
+ label: "Projection",
2462
+ description: "Must be a valid GROQ projection, starting { and ending with }",
2463
+ placeholder: defaultIndex.projection,
2371
2464
  index,
2372
- prop: "filter",
2465
+ prop: "projection",
2373
2466
  onChange: setIndex,
2374
2467
  readOnly,
2375
2468
  type: "textarea"
@@ -2406,6 +2499,7 @@ function IndexList(props) {
2406
2499
  borderBottom: true,
2407
2500
  flex: 1,
2408
2501
  paddingBottom: 2,
2502
+ padding: 3,
2409
2503
  children: /* @__PURE__ */jsxs(Flex, {
2410
2504
  children: [/* @__PURE__ */jsx(Box, {
2411
2505
  flex: 1,
@@ -2460,12 +2554,15 @@ function IndexRow(props) {
2460
2554
  const onSelect = useCallback(() => onIndexSelected(index), [onIndexSelected, index]);
2461
2555
  return /* @__PURE__ */jsx(Button, {
2462
2556
  tone: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "primary" : "default",
2463
- mode: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "default" : "bleed",
2557
+ mode: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "default" : "ghost",
2464
2558
  onClick: onSelect,
2559
+ padding: 3,
2465
2560
  children: /* @__PURE__ */jsxs(Flex, {
2466
2561
  children: [/* @__PURE__ */jsx(Box, {
2467
2562
  flex: 1,
2468
- children: index.indexName
2563
+ children: /* @__PURE__ */jsx("strong", {
2564
+ children: index.indexName
2565
+ })
2469
2566
  }), /* @__PURE__ */jsx(Box, {
2470
2567
  flex: 1,
2471
2568
  children: index.dataset
@@ -2479,102 +2576,18 @@ function IndexRow(props) {
2479
2576
  })
2480
2577
  }, index.indexName);
2481
2578
  }
2482
- const NO_RESULTS = [];
2483
2579
  function QueryIndex(props) {
2484
2580
  const {
2485
2581
  indexName
2486
2582
  } = props;
2487
- const [query, setQuery] = useState("");
2488
- const [searching, setSearching] = useState(false);
2489
- const [results, setResults] = useState(NO_RESULTS);
2490
- const client = useApiClient();
2491
- const search = useCallback(queryString => {
2492
- setSearching(true);
2493
- return queryIndex({
2494
- query: queryString,
2495
- indexName,
2496
- maxResults: 5
2497
- }, client).then(setResults).finally(() => setSearching(false));
2498
- }, [client, indexName]);
2499
- const onInputChange = useCallback(e => {
2500
- setQuery(e.currentTarget.value);
2501
- }, []);
2502
- const onKeyDown = useCallback(e => {
2503
- if (e.key === "Enter") {
2504
- search(query).catch(console.error);
2505
- }
2506
- }, [search, query]);
2507
- return /* @__PURE__ */jsxs(Stack, {
2508
- space: 3,
2509
- flex: 1,
2510
- children: [/* @__PURE__ */jsx(Flex, {
2511
- flex: 1,
2512
- children: /* @__PURE__ */jsx(Card, {
2513
- flex: 1,
2514
- children: /* @__PURE__ */jsx(TextInput, {
2515
- iconRight: searching ? /* @__PURE__ */jsx(Box, {
2516
- style: {
2517
- marginTop: 5
2518
- },
2519
- children: /* @__PURE__ */jsx(Spinner, {})
2520
- }) : SearchIcon,
2521
- placeholder: "Find documents",
2522
- value: query,
2523
- disabled: searching,
2524
- onChange: onInputChange,
2525
- onKeyDown
2526
- })
2527
- })
2528
- }), /* @__PURE__ */jsx(Flex, {
2529
- gap: 4,
2530
- style: {
2531
- opacity: searching ? 0.5 : 1
2532
- },
2533
- children: /* @__PURE__ */jsx(Box, {
2534
- flex: 1,
2535
- children: /* @__PURE__ */jsx(ResultList, {
2536
- results,
2537
- query
2538
- })
2539
- })
2540
- })]
2541
- });
2542
- }
2543
- function ResultList(props) {
2544
- const {
2545
- results,
2546
- query
2547
- } = props;
2548
- return /* @__PURE__ */jsx(Stack, {
2549
- space: 4,
2550
- height: "fill",
2551
- children: /* @__PURE__ */jsxs(Stack, {
2552
- space: 2,
2553
- children: [results.map(r => /* @__PURE__ */jsx(ResultEntry, {
2554
- result: r
2555
- }, r.value.documentId)), !results.length && query ? "No results." : null]
2556
- })
2557
- });
2558
- }
2559
- function ResultEntry(props) {
2560
- const value = props.result.value;
2561
- return /* @__PURE__ */jsxs(Flex, {
2562
- gap: 4,
2563
- align: "center",
2564
- children: [/* @__PURE__ */jsx(Box, {
2565
- flex: 1,
2566
- children: /* @__PURE__ */jsx(DocumentPreview, {
2567
- documentId: value.documentId,
2568
- schemaTypeName: value.type,
2569
- button: true
2570
- })
2571
- }), /* @__PURE__ */jsx(Box, {
2572
- children: /* @__PURE__ */jsxs(Text, {
2573
- muted: true,
2574
- size: 1,
2575
- children: [Math.floor(props.result.score * 100), " %"]
2576
- })
2577
- })]
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
2578
2591
  });
2579
2592
  }
2580
2593
  function IndexInfo(_ref3) {