@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/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,59 +1950,20 @@ function useApiClient() {
1906
1950
  return client;
1907
1951
  }, [client]);
1908
1952
  }
1953
+ const NO_RESULTS_VALUE = "";
1909
1954
  const NO_OPTIONS = [];
1910
1955
  const NO_FILTER = () => true;
1911
- function SemanticSearchReferenceInput(props) {
1912
- var _a, _b, _c;
1913
- const defaultEnabled = ((_c = (_b = (_a = props.schemaType) == null ? void 0 : _a.options) == null ? void 0 : _b.embeddingsIndex) == null ? void 0 : _c.searchMode) === "embeddings";
1914
- const [semantic, setSemantic] = require$$0.useState(defaultEnabled);
1915
- const toggleSemantic = require$$0.useCallback(() => setSemantic(current => !current), []);
1916
- return /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
1917
- gap: 2,
1918
- flex: 1,
1919
- style: {
1920
- width: "100%"
1921
- },
1922
- children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
1923
- flex: 1,
1924
- style: {
1925
- maxHeight: 36,
1926
- overflow: "hidden"
1927
- },
1928
- children: semantic ? /* @__PURE__ */jsxRuntime.jsx(SemanticSearchInput, {
1929
- ...props
1930
- }) : props.renderDefault(props)
1931
- }), /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
1932
- icon: semantic ? icons.EarthGlobeIcon : icons.LinkIcon,
1933
- onClick: toggleSemantic,
1934
- mode: "bleed",
1935
- title: semantic ? "Switch to standard reference search" : "Switch to semantic reference search"
1936
- })]
1937
- });
1938
- }
1939
- function useDebouncedValue(value, ms) {
1940
- const [debouncedValue, setDebouncedValue] = require$$0.useState(value);
1941
- require$$0.useEffect(() => {
1942
- const timeoutId = setTimeout(() => {
1943
- setDebouncedValue(value);
1944
- }, ms);
1945
- return () => clearTimeout(timeoutId);
1946
- }, [value, ms]);
1947
- return debouncedValue;
1948
- }
1949
- function SemanticSearchInput(props) {
1956
+ const SemanticSearchAutocomplete = require$$0.forwardRef(function SemanticSearchAutocomplete2(props, ref) {
1950
1957
  const {
1951
- onPathFocus,
1952
- onChange,
1958
+ indexConfig,
1959
+ filterResult,
1960
+ getEmptySearchValue,
1953
1961
  readOnly,
1954
- schemaType,
1955
- value
1962
+ onFocus,
1963
+ onBlur,
1964
+ onChange,
1965
+ typeFilter
1956
1966
  } = props;
1957
- const {
1958
- value: currentDocument
1959
- } = desk.useDocumentPane();
1960
- const docRef = require$$0.useRef(currentDocument);
1961
- const autocompleteRef = require$$0.useRef(null);
1962
1967
  const id = require$$0.useId();
1963
1968
  const [query, setQuery] = require$$0.useState("");
1964
1969
  const queryRef = require$$0.useRef(query);
@@ -1967,29 +1972,16 @@ function SemanticSearchInput(props) {
1967
1972
  const [searching, setSearching] = require$$0.useState(false);
1968
1973
  const [options, setOptions] = require$$0.useState(NO_OPTIONS);
1969
1974
  const client = useApiClient();
1970
- require$$0.useEffect(() => {
1971
- docRef.current = currentDocument;
1972
- }, [currentDocument]);
1973
- require$$0.useEffect(() => {
1974
- var _a;
1975
- if (value == null ? void 0 : value._ref) {
1976
- (_a = autocompleteRef.current) == null ? void 0 : _a.focus();
1977
- }
1978
- }, []);
1979
- const handleFocus = require$$0.useCallback(() => onPathFocus(["_ref"]), [onPathFocus]);
1980
- const handleBlur = require$$0.useCallback(() => onPathFocus([]), [onPathFocus]);
1981
1975
  const runIndexQuery = require$$0.useCallback(queryString => {
1982
- var _a, _b, _c, _d, _e;
1976
+ var _a;
1983
1977
  setSearching(true);
1984
- const refSchema = schemaType;
1985
- const indexName = (_b = (_a = refSchema.options) == null ? void 0 : _a.embeddingsIndex) == null ? void 0 : _b.indexName;
1986
- const maxResults = (_d = (_c = refSchema.options) == null ? void 0 : _c.embeddingsIndex) == null ? void 0 : _d.maxResults;
1987
- 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;
1988
1980
  if (!indexName) {
1989
- throw new Error("Reference option embeddingsIndex.indexName is required, but was missing in type ".concat(refSchema.name));
1981
+ throw new Error("Reference option embeddingsIndex.indexName is required, but was missing");
1990
1982
  }
1991
1983
  queryIndex({
1992
- query: queryString.trim().length ? queryString : (_e = JSON.stringify(docRef.current)) != null ? _e : "",
1984
+ query: queryString.trim().length ? queryString : (_a = getEmptySearchValue()) != null ? _a : "",
1993
1985
  indexName,
1994
1986
  maxResults,
1995
1987
  filter: {
@@ -1998,10 +1990,18 @@ function SemanticSearchInput(props) {
1998
1990
  }, client).then(result => {
1999
1991
  if (queryRef.current === queryString) {
2000
1992
  setSearching(false);
2001
- setOptions(result.filter(r => r.value.documentId !== publicId(docRef.current._id)).map(r => sanity.typed({
1993
+ setOptions([]);
1994
+ const resultOptions = result.filter(hit => filterResult ? filterResult(hit) : true).map(r => sanity.typed({
2002
1995
  result: r,
2003
1996
  value: r.value.documentId
2004
- })));
1997
+ }));
1998
+ if (resultOptions.length) {
1999
+ setOptions(resultOptions);
2000
+ } else {
2001
+ setOptions([{
2002
+ value: NO_RESULTS_VALUE
2003
+ }]);
2004
+ }
2005
2005
  }
2006
2006
  }).catch(e => {
2007
2007
  if (queryRef.current === queryString) {
@@ -2009,23 +2009,13 @@ function SemanticSearchInput(props) {
2009
2009
  }
2010
2010
  throw e;
2011
2011
  });
2012
- }, [client, schemaType]);
2012
+ }, [client, indexConfig, getEmptySearchValue, filterResult, typeFilter]);
2013
2013
  require$$0.useEffect(() => {
2014
2014
  if (prevDebouncedQuery.current !== debouncedQuery) {
2015
2015
  runIndexQuery(debouncedQuery);
2016
2016
  }
2017
2017
  prevDebouncedQuery.current = debouncedQuery;
2018
2018
  }, [debouncedQuery, runIndexQuery]);
2019
- const handleChange = require$$0.useCallback(nextId => {
2020
- if (!nextId) {
2021
- onChange(sanity.unset());
2022
- onPathFocus([]);
2023
- return;
2024
- }
2025
- const patches = [sanity.setIfMissing({}), sanity.set(schemaType.name, ["_type"]), sanity.set(publicId(nextId), ["_ref"]), sanity.unset(["_weak"]), sanity.unset(["_strengthenOnPublish"])];
2026
- onChange(patches);
2027
- onPathFocus([]);
2028
- }, [onChange, onPathFocus, schemaType.name]);
2029
2019
  const openButtonConfig = require$$0.useMemo(() => ({
2030
2020
  onClick: () => runIndexQuery(queryRef.current)
2031
2021
  }), [runIndexQuery, queryRef]);
@@ -2034,52 +2024,187 @@ function SemanticSearchInput(props) {
2034
2024
  queryRef.current = newQuery;
2035
2025
  setQuery(newQuery);
2036
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]);
2037
2034
  return /* @__PURE__ */jsxRuntime.jsx(ui.Autocomplete, {
2038
2035
  id,
2039
- ref: autocompleteRef,
2036
+ ref,
2040
2037
  "data-testid": "semantic-autocomplete",
2041
2038
  placeholder: "Type to search...",
2042
2039
  openButton: openButtonConfig,
2043
- onFocus: handleFocus,
2040
+ onFocus,
2044
2041
  onChange: handleChange,
2045
2042
  loading: searching,
2046
- onBlur: handleBlur,
2043
+ onBlur,
2047
2044
  readOnly,
2048
2045
  filterOption: NO_FILTER,
2049
2046
  onQueryChange: handleQueryChange,
2050
2047
  options,
2051
2048
  renderOption: AutocompleteOption
2052
2049
  });
2053
- }
2050
+ });
2054
2051
  function AutocompleteOption(props) {
2055
- const value = props.result.value;
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
+ }
2056
2081
  return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
2057
2082
  mode: "bleed",
2058
2083
  padding: 1,
2059
2084
  style: {
2060
2085
  width: "100%"
2061
2086
  },
2062
- children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
2087
+ disabled: true,
2088
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
2063
2089
  gap: 2,
2064
2090
  align: "center",
2065
- children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2066
- flex: 1,
2067
- children: /* @__PURE__ */jsxRuntime.jsx(DocumentPreview, {
2068
- documentId: value.documentId,
2069
- schemaTypeName: value.type
2070
- })
2071
- }), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2072
- padding: 2,
2073
- children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
2074
- size: 1,
2075
- muted: true,
2076
- title: "Relevance",
2077
- children: [Math.floor(props.result.score * 100), "%"]
2078
- })
2079
- })]
2091
+ children: "No results."
2080
2092
  })
2081
2093
  });
2082
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
+ }
2083
2208
  function isType(schemaType, typeName) {
2084
2209
  if (schemaType.name === typeName) {
2085
2210
  return true;
@@ -2089,21 +2214,35 @@ function isType(schemaType, typeName) {
2089
2214
  }
2090
2215
  return isType(schemaType.type, typeName);
2091
2216
  }
2092
- const embeddingsIndexReferenceInput = sanity.definePlugin({
2093
- name: "@sanity/embeddings-index-reference-input",
2094
- form: {
2095
- components: {
2096
- input: props => {
2097
- var _a, _b;
2098
- if (sanity.isObjectInputProps(props) && isType(props.schemaType, "reference") && ((_b = (_a = props.schemaType.options) == null ? void 0 : _a.embeddingsIndex) == null ? void 0 : _b.indexName)) {
2099
- return /* @__PURE__ */jsxRuntime.jsx(SemanticSearchReferenceInput, {
2100
- ...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)
2101
2226
  });
2102
2227
  }
2103
- return props.renderDefault(props);
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
+ }
2104
2243
  }
2105
2244
  }
2106
- }
2245
+ };
2107
2246
  });
2108
2247
  const defaultProjection = "{...}";
2109
2248
  function useDefaultIndex(schema, dataset) {
@@ -2118,6 +2257,7 @@ function IndexFormInput(props) {
2118
2257
  var _a;
2119
2258
  const {
2120
2259
  label,
2260
+ description,
2121
2261
  index,
2122
2262
  prop,
2123
2263
  onChange,
@@ -2131,6 +2271,7 @@ function IndexFormInput(props) {
2131
2271
  })), [onChange, prop]);
2132
2272
  return /* @__PURE__ */jsxRuntime.jsx(FormInput, {
2133
2273
  label,
2274
+ description,
2134
2275
  onChange: handleChange,
2135
2276
  value: (_a = index[prop]) != null ? _a : "",
2136
2277
  readOnly,
@@ -2141,6 +2282,7 @@ function IndexFormInput(props) {
2141
2282
  function FormInput(props) {
2142
2283
  const {
2143
2284
  label,
2285
+ description,
2144
2286
  onChange,
2145
2287
  value,
2146
2288
  readOnly,
@@ -2158,6 +2300,12 @@ function FormInput(props) {
2158
2300
  htmlFor: id,
2159
2301
  children: label
2160
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
+ })
2161
2309
  }), type === "text" ? /* @__PURE__ */jsxRuntime.jsx(ui.TextInput, {
2162
2310
  id,
2163
2311
  value,
@@ -2312,18 +2460,20 @@ function IndexEditor(props) {
2312
2460
  onChange: setIndex,
2313
2461
  readOnly: true
2314
2462
  }), /* @__PURE__ */jsxRuntime.jsx(IndexFormInput, {
2315
- label: "Projection",
2316
- placeholder: defaultIndex.projection,
2463
+ label: "Filter",
2464
+ description: "Must be a valid GROQ filter",
2465
+ placeholder: defaultIndex.filter,
2317
2466
  index,
2318
- prop: "projection",
2467
+ prop: "filter",
2319
2468
  onChange: setIndex,
2320
2469
  readOnly,
2321
2470
  type: "textarea"
2322
2471
  }), /* @__PURE__ */jsxRuntime.jsx(IndexFormInput, {
2323
- label: "Filter",
2324
- placeholder: defaultIndex.filter,
2472
+ label: "Projection",
2473
+ description: "Must be a valid GROQ projection, starting { and ending with }",
2474
+ placeholder: defaultIndex.projection,
2325
2475
  index,
2326
- prop: "filter",
2476
+ prop: "projection",
2327
2477
  onChange: setIndex,
2328
2478
  readOnly,
2329
2479
  type: "textarea"
@@ -2360,6 +2510,7 @@ function IndexList(props) {
2360
2510
  borderBottom: true,
2361
2511
  flex: 1,
2362
2512
  paddingBottom: 2,
2513
+ padding: 3,
2363
2514
  children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
2364
2515
  children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2365
2516
  flex: 1,
@@ -2414,12 +2565,15 @@ function IndexRow(props) {
2414
2565
  const onSelect = require$$0.useCallback(() => onIndexSelected(index), [onIndexSelected, index]);
2415
2566
  return /* @__PURE__ */jsxRuntime.jsx(ui.Button, {
2416
2567
  tone: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "primary" : "default",
2417
- mode: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "default" : "bleed",
2568
+ mode: (selectedIndex == null ? void 0 : selectedIndex.indexName) === index.indexName ? "default" : "ghost",
2418
2569
  onClick: onSelect,
2570
+ padding: 3,
2419
2571
  children: /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
2420
2572
  children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2421
2573
  flex: 1,
2422
- children: index.indexName
2574
+ children: /* @__PURE__ */jsxRuntime.jsx("strong", {
2575
+ children: index.indexName
2576
+ })
2423
2577
  }), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2424
2578
  flex: 1,
2425
2579
  children: index.dataset
@@ -2433,102 +2587,18 @@ function IndexRow(props) {
2433
2587
  })
2434
2588
  }, index.indexName);
2435
2589
  }
2436
- const NO_RESULTS = [];
2437
2590
  function QueryIndex(props) {
2438
2591
  const {
2439
2592
  indexName
2440
2593
  } = props;
2441
- const [query, setQuery] = require$$0.useState("");
2442
- const [searching, setSearching] = require$$0.useState(false);
2443
- const [results, setResults] = require$$0.useState(NO_RESULTS);
2444
- const client = useApiClient();
2445
- const search = require$$0.useCallback(queryString => {
2446
- setSearching(true);
2447
- return queryIndex({
2448
- query: queryString,
2449
- indexName,
2450
- maxResults: 5
2451
- }, client).then(setResults).finally(() => setSearching(false));
2452
- }, [client, indexName]);
2453
- const onInputChange = require$$0.useCallback(e => {
2454
- setQuery(e.currentTarget.value);
2455
- }, []);
2456
- const onKeyDown = require$$0.useCallback(e => {
2457
- if (e.key === "Enter") {
2458
- search(query).catch(console.error);
2459
- }
2460
- }, [search, query]);
2461
- return /* @__PURE__ */jsxRuntime.jsxs(ui.Stack, {
2462
- space: 3,
2463
- flex: 1,
2464
- children: [/* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
2465
- flex: 1,
2466
- children: /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
2467
- flex: 1,
2468
- children: /* @__PURE__ */jsxRuntime.jsx(ui.TextInput, {
2469
- iconRight: searching ? /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2470
- style: {
2471
- marginTop: 5
2472
- },
2473
- children: /* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {})
2474
- }) : icons.SearchIcon,
2475
- placeholder: "Find documents",
2476
- value: query,
2477
- disabled: searching,
2478
- onChange: onInputChange,
2479
- onKeyDown
2480
- })
2481
- })
2482
- }), /* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
2483
- gap: 4,
2484
- style: {
2485
- opacity: searching ? 0.5 : 1
2486
- },
2487
- children: /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2488
- flex: 1,
2489
- children: /* @__PURE__ */jsxRuntime.jsx(ResultList, {
2490
- results,
2491
- query
2492
- })
2493
- })
2494
- })]
2495
- });
2496
- }
2497
- function ResultList(props) {
2498
- const {
2499
- results,
2500
- query
2501
- } = props;
2502
- return /* @__PURE__ */jsxRuntime.jsx(ui.Stack, {
2503
- space: 4,
2504
- height: "fill",
2505
- children: /* @__PURE__ */jsxRuntime.jsxs(ui.Stack, {
2506
- space: 2,
2507
- children: [results.map(r => /* @__PURE__ */jsxRuntime.jsx(ResultEntry, {
2508
- result: r
2509
- }, r.value.documentId)), !results.length && query ? "No results." : null]
2510
- })
2511
- });
2512
- }
2513
- function ResultEntry(props) {
2514
- const value = props.result.value;
2515
- return /* @__PURE__ */jsxRuntime.jsxs(ui.Flex, {
2516
- gap: 4,
2517
- align: "center",
2518
- children: [/* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2519
- flex: 1,
2520
- children: /* @__PURE__ */jsxRuntime.jsx(DocumentPreview, {
2521
- documentId: value.documentId,
2522
- schemaTypeName: value.type,
2523
- button: true
2524
- })
2525
- }), /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2526
- children: /* @__PURE__ */jsxRuntime.jsxs(ui.Text, {
2527
- muted: true,
2528
- size: 1,
2529
- children: [Math.floor(props.result.score * 100), " %"]
2530
- })
2531
- })]
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
2532
2602
  });
2533
2603
  }
2534
2604
  function IndexInfo(_ref3) {
@@ -2660,17 +2730,21 @@ function IndexStatus(_ref4) {
2660
2730
  });
2661
2731
  }
2662
2732
  function EmbeddingsIndexTool() {
2733
+ const featureState = useIsFeatureEnabled();
2663
2734
  return /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
2664
2735
  children: /* @__PURE__ */jsxRuntime.jsx(ui.Flex, {
2665
2736
  justify: "center",
2666
2737
  flex: 1,
2667
- children: /* @__PURE__ */jsxRuntime.jsx(ui.Card, {
2738
+ children: /* @__PURE__ */jsxRuntime.jsxs(ui.Card, {
2668
2739
  flex: 1,
2669
2740
  style: {
2670
2741
  maxWidth: 1200
2671
2742
  },
2672
2743
  padding: 5,
2673
- children: /* @__PURE__ */jsxRuntime.jsx(Indexes, {})
2744
+ children: [featureState == "loading" ? /* @__PURE__ */jsxRuntime.jsx(ui.Box, {
2745
+ padding: 2,
2746
+ children: /* @__PURE__ */jsxRuntime.jsx(ui.Spinner, {})
2747
+ }) : null, featureState == "disabled" ? /* @__PURE__ */jsxRuntime.jsx(FeatureDisabledNotice, {}) : null, featureState == "enabled" ? /* @__PURE__ */jsxRuntime.jsx(Indexes, {}) : null]
2674
2748
  })
2675
2749
  })
2676
2750
  });