@gooddata/sdk-ui-semantic-search 11.26.0-alpha.2 → 11.26.0-alpha.3
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 +106 -0
- package/esm/hooks/search/matchers.d.ts +12 -0
- package/esm/hooks/search/matchers.d.ts.map +1 -0
- package/esm/hooks/search/matchers.js +30 -0
- package/esm/hooks/search/matchers.js.map +1 -0
- package/esm/hooks/search/related.d.ts +4 -0
- package/esm/hooks/search/related.d.ts.map +1 -0
- package/esm/hooks/search/related.js +47 -0
- package/esm/hooks/search/related.js.map +1 -0
- package/esm/hooks/search/search.d.ts +4 -0
- package/esm/hooks/search/search.d.ts.map +1 -0
- package/esm/hooks/search/search.js +36 -0
- package/esm/hooks/search/search.js.map +1 -0
- package/esm/hooks/search/types.d.ts +47 -0
- package/esm/hooks/search/types.d.ts.map +1 -0
- package/esm/hooks/search/types.js +3 -0
- package/esm/hooks/search/types.js.map +1 -0
- package/esm/hooks/useHybridSearch.d.ts +125 -0
- package/esm/hooks/useHybridSearch.d.ts.map +1 -0
- package/esm/hooks/useHybridSearch.js +106 -0
- package/esm/hooks/useHybridSearch.js.map +1 -0
- package/esm/index.d.ts +3 -0
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +2 -0
- package/esm/index.js.map +1 -1
- package/esm/sdk-ui-semantic-search.d.ts +192 -0
- package/package.json +12 -12
package/README.md
CHANGED
|
@@ -9,6 +9,12 @@ To learn more, check [the source monorepo](https://github.com/gooddata/gooddata-
|
|
|
9
9
|
|
|
10
10
|
This package provides a set of React-based UI components and hooks for semantic search within your metadata.
|
|
11
11
|
|
|
12
|
+
## Components
|
|
13
|
+
|
|
14
|
+
### SemanticSearch
|
|
15
|
+
|
|
16
|
+
The `SemanticSearch` component provides a search input with semantic search capabilities.
|
|
17
|
+
|
|
12
18
|
Example usage:
|
|
13
19
|
|
|
14
20
|
```tsx
|
|
@@ -28,6 +34,106 @@ const App = () => {
|
|
|
28
34
|
|
|
29
35
|
You can also use providers for backend and workspace.
|
|
30
36
|
|
|
37
|
+
## Hooks
|
|
38
|
+
|
|
39
|
+
### useHybridSearch
|
|
40
|
+
|
|
41
|
+
The `useHybridSearch` hook is a powerful tool that combines traditional keyword-based search with AI-powered semantic search. It handles debouncing of the search query and manages the state of both search types.
|
|
42
|
+
|
|
43
|
+
#### Basic Usage
|
|
44
|
+
|
|
45
|
+
```tsx
|
|
46
|
+
import { useHybridSearch, SearchItem, SearchItemGroup } from "@gooddata/sdk-ui-semantic-search";
|
|
47
|
+
|
|
48
|
+
const MySearchComponent = ({ items }: { items: SearchItem[] }) => {
|
|
49
|
+
const { searchState, semanticSearchState, search, onSearchQueryChange } = useHybridSearch({
|
|
50
|
+
itemBuilder: (item, { ref, type }) => {
|
|
51
|
+
// Transform semantic search result to your SearchItem format
|
|
52
|
+
return items.find((i) => areObjRefsEqual(i.ref, ref));
|
|
53
|
+
},
|
|
54
|
+
debounceMs: 200,
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
// Perform the combined search
|
|
58
|
+
const results = search({ items });
|
|
59
|
+
|
|
60
|
+
return (
|
|
61
|
+
<div>
|
|
62
|
+
<input
|
|
63
|
+
type="text"
|
|
64
|
+
value={searchState.query}
|
|
65
|
+
onChange={(e) => onSearchQueryChange(e.target.value)}
|
|
66
|
+
placeholder="Search..."
|
|
67
|
+
/>
|
|
68
|
+
|
|
69
|
+
{searchState.state === "searching" && <div>Searching...</div>}
|
|
70
|
+
|
|
71
|
+
<h3>Results</h3>
|
|
72
|
+
<ul>
|
|
73
|
+
{results.searchItems.map((item) => (
|
|
74
|
+
<li key={objRefToString(item.ref)}>{item.title}</li>
|
|
75
|
+
))}
|
|
76
|
+
</ul>
|
|
77
|
+
|
|
78
|
+
{semanticSearchState.state === "loading" && <div>Loading semantic results...</div>}
|
|
79
|
+
|
|
80
|
+
{results.searchRelatedItems.length > 0 && (
|
|
81
|
+
<>
|
|
82
|
+
<h3>Related (Semantic) Results</h3>
|
|
83
|
+
<ul>
|
|
84
|
+
{results.searchRelatedItems.map((item) => (
|
|
85
|
+
<li key={objRefToString(item.ref)}>{item.title}</li>
|
|
86
|
+
))}
|
|
87
|
+
</ul>
|
|
88
|
+
</>
|
|
89
|
+
)}
|
|
90
|
+
</div>
|
|
91
|
+
);
|
|
92
|
+
};
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
#### Configuration Options
|
|
96
|
+
|
|
97
|
+
The `useHybridSearch` hook accepts an options object (`IUseHybridSearchOptions`):
|
|
98
|
+
|
|
99
|
+
| Property | Type | Description |
|
|
100
|
+
| :------------------- | :------------------------ | :---------------------------------------------------------------------------------------------- |
|
|
101
|
+
| `itemBuilder` | `HybridSearchItemBuilder` | **Required.** A function to transform semantic search results into your local item format. |
|
|
102
|
+
| `backend` | `IAnalyticalBackend` | Optional. Backend to use. If not provided, it's retrieved from `BackendContext`. |
|
|
103
|
+
| `workspace` | `string` | Optional. Workspace ID to use. If not provided, it's retrieved from `WorkspaceContext`. |
|
|
104
|
+
| `debounceMs` | `number` | Optional. Debounce time for the search query in milliseconds (default: 150ms). |
|
|
105
|
+
| `allowSematicSearch` | `boolean` | Optional. Enable or disable AI-powered semantic search (default: true). |
|
|
106
|
+
| `limit` | `number` | Optional. Maximum number of semantic search results to return. |
|
|
107
|
+
| `deepSearch` | `boolean` | Optional. Whether to perform a deep semantic search. |
|
|
108
|
+
| `objectTypes` | `ObjectType[]` | Optional. Restrict semantic search to specific object types (e.g., `'insight'`, `'dashboard'`). |
|
|
109
|
+
| `includeTags` | `string[]` | Optional. Tags that must be present on the searched objects. |
|
|
110
|
+
| `excludeTags` | `string[]` | Optional. Tags that must not be present on the searched objects. |
|
|
111
|
+
| `matcher` | `HybridSearchMatcher` | Optional. A custom matching function for local keyword search. |
|
|
112
|
+
|
|
113
|
+
#### Hook Return Value
|
|
114
|
+
|
|
115
|
+
The hook returns an object (`IHybridSearchResult`) with the following properties:
|
|
116
|
+
|
|
117
|
+
| Property | Type | Description |
|
|
118
|
+
| :-------------------- | :--------------------- | :-------------------------------------------------------------------------- |
|
|
119
|
+
| `searchState` | `ISearchState` | Current state of the keyword search (`query`, `debouncedQuery`, `state`). |
|
|
120
|
+
| `semanticSearchState` | `ISemanticSearchState` | Current state of the semantic search (`state`, `message`, `error`). |
|
|
121
|
+
| `search` | `Function` | A function that takes your local items and returns combined search results. |
|
|
122
|
+
| `onSearchQueryChange` | `Function` | Callback to update the search query. |
|
|
123
|
+
|
|
124
|
+
The `search` function returns `ICombinedSearchResults`, which extends the standard `SearchResults` with `searchRelatedItems` (items found via semantic search but transformed by your `itemBuilder`).
|
|
125
|
+
|
|
126
|
+
#### Search Function Parameters
|
|
127
|
+
|
|
128
|
+
The `search` function accepts the following properties:
|
|
129
|
+
|
|
130
|
+
| Property | Type | Description |
|
|
131
|
+
| :----------- | :----------------- | :-------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
132
|
+
| `items` | `ReadonlyArray<I>` | **Required.** The current list of items to search through (e.g., currently filtered or paged items). |
|
|
133
|
+
| `allItems` | `ReadonlyArray<I>` | Optional. The full list of all available items. If provided, it's used to calculate `searchAllItems` in the results. Defaults to `items` if not provided. |
|
|
134
|
+
| `itemGroups` | `ReadonlyArray<G>` | Optional. Groups of items to search through. Used to calculate `searchItemGroups` in the results. |
|
|
135
|
+
| `keywords` | `string[]` | Optional. A list of keywords to match against the search query. Used to calculate `searchKeywords` in the results. |
|
|
136
|
+
|
|
31
137
|
## License
|
|
32
138
|
|
|
33
139
|
(C) 2017-2022 GoodData Corporation
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { HybridSearchMatcher, SearchItem, SearchItemGroup } from "./types.js";
|
|
2
|
+
/**
|
|
3
|
+
* @alpha
|
|
4
|
+
* Default matcher for the search. Supports title, name, description, summary.
|
|
5
|
+
*/
|
|
6
|
+
export declare function defaultMatcher<I extends SearchItem, G extends SearchItemGroup<I>>(item: I | G | string, searchQueryUpper: string): boolean;
|
|
7
|
+
/**
|
|
8
|
+
* @alpha
|
|
9
|
+
* Custom matcher for the search. Can be used to match any property of the search item.
|
|
10
|
+
*/
|
|
11
|
+
export declare function customMatcher<I extends SearchItem, G extends SearchItemGroup<I>>(props: (keyof I & keyof G)[]): HybridSearchMatcher;
|
|
12
|
+
//# sourceMappingURL=matchers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchers.d.ts","sourceRoot":"","sources":["../../../src/hooks/search/matchers.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,mBAAmB,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEnF;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,eAAe,CAAC,CAAC,CAAC,EAC7E,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,EACpB,gBAAgB,EAAE,MAAM,GACzB,OAAO,CAQT;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,eAAe,CAAC,CAAC,CAAC,EAC5E,KAAK,EAAE,CAAC,MAAM,CAAC,GAAG,MAAM,CAAC,CAAC,EAAE,GAC7B,mBAAmB,CAcrB"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// (C) 2024-2026 GoodData Corporation
|
|
2
|
+
/**
|
|
3
|
+
* @alpha
|
|
4
|
+
* Default matcher for the search. Supports title, name, description, summary.
|
|
5
|
+
*/
|
|
6
|
+
export function defaultMatcher(item, searchQueryUpper) {
|
|
7
|
+
if (typeof item === "string") {
|
|
8
|
+
return isUpperCaseMatch(item, searchQueryUpper);
|
|
9
|
+
}
|
|
10
|
+
const searchIn = [item.title, item.name, item.description, item.summary].filter(Boolean);
|
|
11
|
+
return searchIn.some((name) => isUpperCaseMatch(name, searchQueryUpper));
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* @alpha
|
|
15
|
+
* Custom matcher for the search. Can be used to match any property of the search item.
|
|
16
|
+
*/
|
|
17
|
+
export function customMatcher(props) {
|
|
18
|
+
return (item, searchQueryUpper) => {
|
|
19
|
+
if (typeof item === "string") {
|
|
20
|
+
return isUpperCaseMatch(item, searchQueryUpper);
|
|
21
|
+
}
|
|
22
|
+
const values = props.map((prop) => item[prop]);
|
|
23
|
+
const searchIn = values.filter(Boolean);
|
|
24
|
+
return searchIn.some((name) => isUpperCaseMatch(name, searchQueryUpper));
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function isUpperCaseMatch(keyword, searchQueryUpper) {
|
|
28
|
+
return keyword.toUpperCase().includes(searchQueryUpper);
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=matchers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"matchers.js","sourceRoot":"","sources":["../../../src/hooks/search/matchers.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAIrC;;;GAGG;AACH,MAAM,UAAU,cAAc,CAC1B,IAAoB,EACpB,gBAAwB,EACjB;IACP,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;QAC3B,OAAO,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;IACpD,CAAC;IAED,MAAM,QAAQ,GAAG,CAAC,IAAI,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,OAAO,CAAa,CAAC;IAErG,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAAA,CAC5E;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CACzB,KAA4B,EACT;IACnB,OAAO,CACH,IAAoB,EACpB,gBAAwB,EACjB,EAAE,CAAC;QACV,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC3B,OAAO,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC;QACpD,CAAC;QAED,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAE,IAAgC,CAAC,IAAc,CAAC,CAAa,CAAC;QAClG,MAAM,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;QAExC,OAAO,QAAQ,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC;IAAA,CAC5E,CAAC;AAAA,CACL;AAED,SAAS,gBAAgB,CAAC,OAAe,EAAE,gBAAwB,EAAE;IACjE,OAAO,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,gBAAgB,CAAC,CAAC;AAAA,CAC3D"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type ISemanticSearchResultItem } from "@gooddata/sdk-model";
|
|
2
|
+
import { type HybridSearchItemBuilder, type SearchItem } from "./types.js";
|
|
3
|
+
export declare function doFilterRelatedItems<I extends SearchItem>(items: ReadonlyArray<I>, searchResults: ISemanticSearchResultItem[], itemBuilder: HybridSearchItemBuilder<I>): ReadonlyArray<I>;
|
|
4
|
+
//# sourceMappingURL=related.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"related.d.ts","sourceRoot":"","sources":["../../../src/hooks/search/related.ts"],"names":[],"mappings":"AAEA,OAAO,EAEH,KAAK,yBAAyB,EAKjC,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EAAE,KAAK,uBAAuB,EAAE,KAAK,UAAU,EAAE,MAAM,YAAY,CAAC;AAE3E,wBAAgB,oBAAoB,CAAC,CAAC,SAAS,UAAU,EACrD,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,aAAa,EAAE,yBAAyB,EAAE,EAC1C,WAAW,EAAE,uBAAuB,CAAC,CAAC,CAAC,GACxC,aAAa,CAAC,CAAC,CAAC,CAelB"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
// (C) 2024-2026 GoodData Corporation
|
|
2
|
+
import { areObjRefsEqual, assertNever, } from "@gooddata/sdk-model";
|
|
3
|
+
export function doFilterRelatedItems(items, searchResults, itemBuilder) {
|
|
4
|
+
const rest = searchResults.filter((item) => {
|
|
5
|
+
const objRef = createIdentifierRef(item);
|
|
6
|
+
return !items.some((searchItem) => areObjRefsEqual(searchItem.ref, objRef));
|
|
7
|
+
});
|
|
8
|
+
return rest
|
|
9
|
+
.map((item) => {
|
|
10
|
+
const objRef = createIdentifierRef(item);
|
|
11
|
+
return itemBuilder(item, {
|
|
12
|
+
ref: objRef,
|
|
13
|
+
type: convertGenAiTypeToObjectType(item.type),
|
|
14
|
+
});
|
|
15
|
+
})
|
|
16
|
+
.filter(Boolean);
|
|
17
|
+
}
|
|
18
|
+
function createIdentifierRef(item) {
|
|
19
|
+
return {
|
|
20
|
+
type: convertGenAiTypeToObjectType(item.type),
|
|
21
|
+
identifier: item.id,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
function convertGenAiTypeToObjectType(type) {
|
|
25
|
+
switch (type) {
|
|
26
|
+
case "attribute":
|
|
27
|
+
return "attribute";
|
|
28
|
+
case "fact":
|
|
29
|
+
return "fact";
|
|
30
|
+
case "dashboard":
|
|
31
|
+
return "analyticalDashboard";
|
|
32
|
+
case "dataset":
|
|
33
|
+
return "dataSet";
|
|
34
|
+
case "date":
|
|
35
|
+
return "dataSet";
|
|
36
|
+
case "label":
|
|
37
|
+
return "displayForm";
|
|
38
|
+
case "metric":
|
|
39
|
+
return "measure";
|
|
40
|
+
case "visualization":
|
|
41
|
+
return "insight";
|
|
42
|
+
default:
|
|
43
|
+
assertNever(type);
|
|
44
|
+
throw new Error(`Unknown type: ${type}`);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
//# sourceMappingURL=related.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"related.js","sourceRoot":"","sources":["../../../src/hooks/search/related.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAErC,OAAO,EAKH,eAAe,EACf,WAAW,GACd,MAAM,qBAAqB,CAAC;AAI7B,MAAM,UAAU,oBAAoB,CAChC,KAAuB,EACvB,aAA0C,EAC1C,WAAuC,EACvB;IAChB,MAAM,IAAI,GAAG,aAAa,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACzC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,EAAE,CAAC,eAAe,CAAC,UAAU,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC;IAAA,CAC/E,CAAC,CAAC;IAEH,OAAO,IAAI;SACN,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;QACX,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACzC,OAAO,WAAW,CAAC,IAAI,EAAE;YACrB,GAAG,EAAE,MAAM;YACX,IAAI,EAAE,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC;SAChD,CAAC,CAAC;IAAA,CACN,CAAC;SACD,MAAM,CAAC,OAAO,CAAQ,CAAC;AAAA,CAC/B;AAED,SAAS,mBAAmB,CAAC,IAA+B,EAAiB;IACzE,OAAO;QACH,IAAI,EAAE,4BAA4B,CAAC,IAAI,CAAC,IAAI,CAAC;QAC7C,UAAU,EAAE,IAAI,CAAC,EAAE;KACtB,CAAC;AAAA,CACL;AAED,SAAS,4BAA4B,CAAC,IAAqB,EAAc;IACrE,QAAQ,IAAI,EAAE,CAAC;QACX,KAAK,WAAW;YACZ,OAAO,WAAW,CAAC;QACvB,KAAK,MAAM;YACP,OAAO,MAAM,CAAC;QAClB,KAAK,WAAW;YACZ,OAAO,qBAAqB,CAAC;QACjC,KAAK,SAAS;YACV,OAAO,SAAS,CAAC;QACrB,KAAK,MAAM;YACP,OAAO,SAAS,CAAC;QACrB,KAAK,OAAO;YACR,OAAO,aAAa,CAAC;QACzB,KAAK,QAAQ;YACT,OAAO,SAAS,CAAC;QACrB,KAAK,eAAe;YAChB,OAAO,SAAS,CAAC;QACrB;YACI,WAAW,CAAC,IAAI,CAAC,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,iBAAiB,IAAI,EAAE,CAAC,CAAC;IACjD,CAAC;AAAA,CACJ"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { defaultMatcher } from "./matchers.js";
|
|
2
|
+
import { type SearchItem, type SearchItemGroup, type SearchResults } from "./types.js";
|
|
3
|
+
export declare function doSearch<I extends SearchItem, G extends SearchItemGroup<I>>(items: ReadonlyArray<I>, allItems: ReadonlyArray<I>, itemGroups: ReadonlyArray<G>, keywords: string[], searchQuery: string, matcher?: typeof defaultMatcher): SearchResults<I, G>;
|
|
4
|
+
//# sourceMappingURL=search.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../../src/hooks/search/search.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAEH,KAAK,UAAU,EACf,KAAK,eAAe,EACpB,KAAK,aAAa,EACrB,MAAM,YAAY,CAAC;AAEpB,wBAAgB,QAAQ,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,eAAe,CAAC,CAAC,CAAC,EACvE,KAAK,EAAE,aAAa,CAAC,CAAC,CAAC,EACvB,QAAQ,EAAE,aAAa,CAAC,CAAC,CAAC,EAC1B,UAAU,EAAE,aAAa,CAAC,CAAC,CAAC,EAC5B,QAAQ,EAAE,MAAM,EAAE,EAClB,WAAW,EAAE,MAAM,EACnB,OAAO,wBAAiB,GACzB,aAAa,CAAC,CAAC,EAAE,CAAC,CAAC,CAYrB"}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// (C) 2024-2026 GoodData Corporation
|
|
2
|
+
import { defaultMatcher } from "./matchers.js";
|
|
3
|
+
export function doSearch(items, allItems, itemGroups, keywords, searchQuery, matcher = defaultMatcher) {
|
|
4
|
+
const searchItems = isMatchingItems(items, itemGroups, searchQuery, matcher);
|
|
5
|
+
const searchAllItems = isMatchingItems(allItems, itemGroups, searchQuery, matcher);
|
|
6
|
+
const searchItemGroups = isMatchingItemGroups(itemGroups, searchQuery, matcher);
|
|
7
|
+
const searchKeywords = isMatchingKeywords(keywords, searchQuery, matcher);
|
|
8
|
+
return {
|
|
9
|
+
searchItems,
|
|
10
|
+
searchAllItems,
|
|
11
|
+
searchItemGroups,
|
|
12
|
+
searchKeywords,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
function isMatchingItems(items, itemGroups, searchQuery, matcher) {
|
|
16
|
+
const searchQueryUpper = upper(searchQuery);
|
|
17
|
+
if (searchQuery === "") {
|
|
18
|
+
if (itemGroups.length === 0) {
|
|
19
|
+
return items;
|
|
20
|
+
}
|
|
21
|
+
return [];
|
|
22
|
+
}
|
|
23
|
+
return items.filter((item) => matcher(item, searchQueryUpper));
|
|
24
|
+
}
|
|
25
|
+
function isMatchingItemGroups(itemGroups, searchQuery, matcher) {
|
|
26
|
+
const searchQueryUpper = upper(searchQuery);
|
|
27
|
+
return itemGroups.filter((itemGroup) => matcher(itemGroup, searchQueryUpper));
|
|
28
|
+
}
|
|
29
|
+
function isMatchingKeywords(keywords, searchQuery, matcher) {
|
|
30
|
+
const searchQueryUpper = upper(searchQuery);
|
|
31
|
+
return keywords.filter((keyword) => matcher(keyword, searchQueryUpper));
|
|
32
|
+
}
|
|
33
|
+
function upper(searchQuery) {
|
|
34
|
+
return searchQuery.toUpperCase();
|
|
35
|
+
}
|
|
36
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../../src/hooks/search/search.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAErC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAQ/C,MAAM,UAAU,QAAQ,CACpB,KAAuB,EACvB,QAA0B,EAC1B,UAA4B,EAC5B,QAAkB,EAClB,WAAmB,EACnB,OAAO,GAAG,cAAc,EACL;IACnB,MAAM,WAAW,GAAG,eAAe,CAAC,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IAC7E,MAAM,cAAc,GAAG,eAAe,CAAC,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IACnF,MAAM,gBAAgB,GAAG,oBAAoB,CAAC,UAAU,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IAChF,MAAM,cAAc,GAAG,kBAAkB,CAAC,QAAQ,EAAE,WAAW,EAAE,OAAO,CAAC,CAAC;IAE1E,OAAO;QACH,WAAW;QACX,cAAc;QACd,gBAAgB;QAChB,cAAc;KACjB,CAAC;AAAA,CACL;AAED,SAAS,eAAe,CACpB,KAAuB,EACvB,UAA4B,EAC5B,WAAmB,EACnB,OAA4B,EAC9B;IACE,MAAM,gBAAgB,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC;IAE5C,IAAI,WAAW,KAAK,EAAE,EAAE,CAAC;QACrB,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC1B,OAAO,KAAK,CAAC;QACjB,CAAC;QACD,OAAO,EAAE,CAAC;IACd,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,CAAC,IAAI,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAAA,CAClE;AAED,SAAS,oBAAoB,CACzB,UAA4B,EAC5B,WAAmB,EACnB,OAA4B,EAC9B;IACE,MAAM,gBAAgB,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC;IAC5C,OAAO,UAAU,CAAC,MAAM,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,OAAO,CAAC,SAAS,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAAA,CACjF;AAED,SAAS,kBAAkB,CAAC,QAAkB,EAAE,WAAmB,EAAE,OAA4B,EAAE;IAC/F,MAAM,gBAAgB,GAAG,KAAK,CAAC,WAAW,CAAC,CAAC;IAC5C,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC;AAAA,CAC3E;AAED,SAAS,KAAK,CAAC,WAAmB,EAAE;IAChC,OAAO,WAAW,CAAC,WAAW,EAAE,CAAC;AAAA,CACpC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { type ISemanticSearchResultItem, type ObjRef, type ObjectType } from "@gooddata/sdk-model";
|
|
2
|
+
/**
|
|
3
|
+
* @alpha
|
|
4
|
+
* Defines the shape of the search item.
|
|
5
|
+
*/
|
|
6
|
+
export type SearchItem = {
|
|
7
|
+
ref: ObjRef;
|
|
8
|
+
title?: string;
|
|
9
|
+
name?: string;
|
|
10
|
+
description?: string;
|
|
11
|
+
summary?: string;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* @alpha
|
|
15
|
+
* Defines the shape of the search item group.
|
|
16
|
+
*/
|
|
17
|
+
export type SearchItemGroup<I> = {
|
|
18
|
+
title?: string;
|
|
19
|
+
name?: string;
|
|
20
|
+
description?: string;
|
|
21
|
+
summary?: string;
|
|
22
|
+
items?: I[];
|
|
23
|
+
};
|
|
24
|
+
/**
|
|
25
|
+
* @alpha
|
|
26
|
+
* Defines the shape of the search results.
|
|
27
|
+
*/
|
|
28
|
+
export type SearchResults<I extends SearchItem, G extends SearchItemGroup<I>> = {
|
|
29
|
+
searchItems: ReadonlyArray<I>;
|
|
30
|
+
searchAllItems: ReadonlyArray<I>;
|
|
31
|
+
searchItemGroups: ReadonlyArray<G>;
|
|
32
|
+
searchKeywords: ReadonlyArray<string>;
|
|
33
|
+
};
|
|
34
|
+
/**
|
|
35
|
+
* @alpha
|
|
36
|
+
* Defines the shape of the search matcher.
|
|
37
|
+
*/
|
|
38
|
+
export type HybridSearchMatcher = <I extends SearchItem, G extends SearchItemGroup<I>>(item: I | G | string, searchQueryUpper: string) => boolean;
|
|
39
|
+
/**
|
|
40
|
+
* @alpha
|
|
41
|
+
* Defines the shape of the item builder.
|
|
42
|
+
*/
|
|
43
|
+
export type HybridSearchItemBuilder<I extends SearchItem> = (item: ISemanticSearchResultItem, props: {
|
|
44
|
+
ref: ObjRef;
|
|
45
|
+
type: ObjectType;
|
|
46
|
+
}) => I | null | undefined;
|
|
47
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/hooks/search/types.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,yBAAyB,EAAE,KAAK,MAAM,EAAE,KAAK,UAAU,EAAE,MAAM,qBAAqB,CAAC;AAEnG;;;GAGG;AACH,MAAM,MAAM,UAAU,GAAG;IACrB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CACpB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,eAAe,CAAC,CAAC,IAAI;IAC7B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC;CACf,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,eAAe,CAAC,CAAC,CAAC,IAAI;IAC5E,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAC9B,cAAc,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IACjC,gBAAgB,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IACnC,cAAc,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CACzC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,mBAAmB,GAAG,CAAC,CAAC,SAAS,UAAU,EAAE,CAAC,SAAS,eAAe,CAAC,CAAC,CAAC,EACjF,IAAI,EAAE,CAAC,GAAG,CAAC,GAAG,MAAM,EACpB,gBAAgB,EAAE,MAAM,KACvB,OAAO,CAAC;AAEb;;;GAGG;AACH,MAAM,MAAM,uBAAuB,CAAC,CAAC,SAAS,UAAU,IAAI,CACxD,IAAI,EAAE,yBAAyB,EAC/B,KAAK,EAAE;IACH,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,UAAU,CAAC;CACpB,KACA,CAAC,GAAG,IAAI,GAAG,SAAS,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../../src/hooks/search/types.ts"],"names":[],"mappings":"AAAA,qCAAqC"}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { type IAnalyticalBackend } from "@gooddata/sdk-backend-spi";
|
|
2
|
+
import { type HybridSearchItemBuilder, type HybridSearchMatcher, type SearchItem, type SearchItemGroup, type SearchResults } from "./search/types.js";
|
|
3
|
+
import { type SemanticSearchHookInput } from "./useSemanticSearch.js";
|
|
4
|
+
/**
|
|
5
|
+
* @alpha
|
|
6
|
+
* On search query change callback.
|
|
7
|
+
*/
|
|
8
|
+
export type OnSearchQueryChanged = (searchQuery: string) => void;
|
|
9
|
+
/**
|
|
10
|
+
* @alpha
|
|
11
|
+
* Options for the useHybridSearch hook.
|
|
12
|
+
*/
|
|
13
|
+
export interface IUseHybridSearchOptions<I extends SearchItem> extends Pick<SemanticSearchHookInput, "deepSearch" | "limit" | "includeTags" | "excludeTags" | "objectTypes"> {
|
|
14
|
+
/**
|
|
15
|
+
* The backend to use for the search.
|
|
16
|
+
* If omitted, will be retrieved from the context.
|
|
17
|
+
*/
|
|
18
|
+
backend?: IAnalyticalBackend;
|
|
19
|
+
/**
|
|
20
|
+
* The workspace to use for the search.
|
|
21
|
+
* If omitted, will be retrieved from the context.
|
|
22
|
+
*/
|
|
23
|
+
workspace?: string;
|
|
24
|
+
/**
|
|
25
|
+
* Allow semantic search.
|
|
26
|
+
* default: true
|
|
27
|
+
*/
|
|
28
|
+
allowSematicSearch?: boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Debounce time in milliseconds for search query.
|
|
31
|
+
* default: 150
|
|
32
|
+
*/
|
|
33
|
+
debounceMs?: number;
|
|
34
|
+
/**
|
|
35
|
+
* Custom matcher for the search results.
|
|
36
|
+
* If provided, the matcher will be used to filter the search results.
|
|
37
|
+
* The matcher should return true if the item should be included in the search results,
|
|
38
|
+
* and false otherwise.
|
|
39
|
+
*/
|
|
40
|
+
matcher?: HybridSearchMatcher;
|
|
41
|
+
/**
|
|
42
|
+
* Item builder for the search results.
|
|
43
|
+
* If provided, the item builder will be used to transform the search results into a different format.
|
|
44
|
+
* The item builder should return the transformed item.
|
|
45
|
+
*/
|
|
46
|
+
itemBuilder: HybridSearchItemBuilder<I>;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* @alpha
|
|
50
|
+
* State of the search.
|
|
51
|
+
*/
|
|
52
|
+
export interface ISearchState {
|
|
53
|
+
/**
|
|
54
|
+
* The current search query.
|
|
55
|
+
* This is the query that is currently being typed by the user.
|
|
56
|
+
* It may be different from the debouncedQuery if the user is still typing.
|
|
57
|
+
*/
|
|
58
|
+
query: string;
|
|
59
|
+
/**
|
|
60
|
+
* The debounced search query.
|
|
61
|
+
* This is the query that is currently being used for the search.
|
|
62
|
+
* It may be different from the query if the user is still typing.
|
|
63
|
+
*/
|
|
64
|
+
debouncedQuery: string;
|
|
65
|
+
/**
|
|
66
|
+
* The current state of the search.
|
|
67
|
+
* - idle - means the user has not typed anything yet
|
|
68
|
+
* - searching - means the user is currently typing
|
|
69
|
+
* - completed - means the user has stopped typing and the search is complete
|
|
70
|
+
*/
|
|
71
|
+
state: "idle" | "searching" | "completed";
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* @alpha
|
|
75
|
+
* State of semantic search.
|
|
76
|
+
*/
|
|
77
|
+
export interface ISemanticSearchState {
|
|
78
|
+
/**
|
|
79
|
+
* The current state of semantic search.
|
|
80
|
+
* - idle - means the semantic search is not running
|
|
81
|
+
* - loading - means the semantic search is running
|
|
82
|
+
* - error - means the semantic search failed
|
|
83
|
+
* - success - means the semantic search succeeded
|
|
84
|
+
*/
|
|
85
|
+
state: "idle" | "loading" | "error" | "success";
|
|
86
|
+
/**
|
|
87
|
+
* The message to show to the user that came from the backend.
|
|
88
|
+
*/
|
|
89
|
+
message: string;
|
|
90
|
+
/**
|
|
91
|
+
* The error message if the semantic search failed.
|
|
92
|
+
*/
|
|
93
|
+
error?: string;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* @alpha
|
|
97
|
+
* Result of the useHybridSearch hook.
|
|
98
|
+
*/
|
|
99
|
+
export interface IHybridSearchResult<I extends SearchItem, G extends SearchItemGroup<I>> {
|
|
100
|
+
searchState: ISearchState;
|
|
101
|
+
semanticSearchState: ISemanticSearchState;
|
|
102
|
+
search: (props: {
|
|
103
|
+
items: ReadonlyArray<I>;
|
|
104
|
+
allItems?: ReadonlyArray<I>;
|
|
105
|
+
itemGroups?: ReadonlyArray<G>;
|
|
106
|
+
keywords?: string[];
|
|
107
|
+
}) => ICombinedSearchResults<I, G>;
|
|
108
|
+
onSearchQueryChange: OnSearchQueryChanged;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* @alpha
|
|
112
|
+
* Search results that are combined from semantic search and normal search.
|
|
113
|
+
*/
|
|
114
|
+
export interface ICombinedSearchResults<I extends SearchItem, G extends SearchItemGroup<I>> extends SearchResults<I, G> {
|
|
115
|
+
searchRelatedItems: ReadonlyArray<I>;
|
|
116
|
+
searchState: ISearchState;
|
|
117
|
+
semanticSearchState: ISemanticSearchState;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* @alpha
|
|
121
|
+
* Use a hybrid search implementation that debounce the search query and provide semantic search
|
|
122
|
+
* related results
|
|
123
|
+
*/
|
|
124
|
+
export declare function useHybridSearch<I extends SearchItem, G extends SearchItemGroup<I>>({ limit, workspace, backend, debounceMs, allowSematicSearch, deepSearch, objectTypes, includeTags, excludeTags, matcher, itemBuilder }: IUseHybridSearchOptions<I>): IHybridSearchResult<I, G>;
|
|
125
|
+
//# sourceMappingURL=useHybridSearch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useHybridSearch.d.ts","sourceRoot":"","sources":["../../src/hooks/useHybridSearch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// (C) 2024-2026 GoodData Corporation
|
|
2
|
+
import { startTransition, useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
3
|
+
import { useBackendStrict, useWorkspaceStrict } from "@gooddata/sdk-ui";
|
|
4
|
+
import { doFilterRelatedItems } from "./search/related.js";
|
|
5
|
+
import { doSearch } from "./search/search.js";
|
|
6
|
+
import { useSemanticSearch } from "./useSemanticSearch.js";
|
|
7
|
+
const SEARCH_DEBOUNCE_MS = 150;
|
|
8
|
+
/**
|
|
9
|
+
* @alpha
|
|
10
|
+
* Use a hybrid search implementation that debounce the search query and provide semantic search
|
|
11
|
+
* related results
|
|
12
|
+
*/
|
|
13
|
+
export function useHybridSearch({ limit, workspace, backend, debounceMs = SEARCH_DEBOUNCE_MS, allowSematicSearch = true, deepSearch, objectTypes, includeTags, excludeTags, matcher, itemBuilder, }) {
|
|
14
|
+
const [searchQuery, setSearchQuery] = useState("");
|
|
15
|
+
const debouncedSearchQuery = useDebouncedValue(searchQuery, debounceMs);
|
|
16
|
+
const onSearchQueryChange = useOnSearchQueryChangeCallback(setSearchQuery);
|
|
17
|
+
const semanticSearchProps = useMemo(() => {
|
|
18
|
+
return {
|
|
19
|
+
objectTypes,
|
|
20
|
+
excludeTags,
|
|
21
|
+
includeTags,
|
|
22
|
+
};
|
|
23
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
24
|
+
}, [objectTypes?.join(), includeTags?.join(), excludeTags?.join()]);
|
|
25
|
+
const effectiveBackend = useBackendStrict(backend);
|
|
26
|
+
const effectiveWorkspace = useWorkspaceStrict(workspace);
|
|
27
|
+
const { searchStatus, searchError, searchResults, searchMessage } = useSemanticSearch({
|
|
28
|
+
searchTerm: allowSematicSearch ? debouncedSearchQuery : "",
|
|
29
|
+
backend: effectiveBackend,
|
|
30
|
+
workspace: effectiveWorkspace,
|
|
31
|
+
deepSearch,
|
|
32
|
+
limit,
|
|
33
|
+
...semanticSearchProps,
|
|
34
|
+
});
|
|
35
|
+
const searchState = useMemo(() => ({
|
|
36
|
+
query: searchQuery,
|
|
37
|
+
debouncedQuery: debouncedSearchQuery,
|
|
38
|
+
state: getSearchState(searchQuery, debouncedSearchQuery),
|
|
39
|
+
}), [debouncedSearchQuery, searchQuery]);
|
|
40
|
+
const semanticSearchState = useMemo(() => ({
|
|
41
|
+
state: searchStatus,
|
|
42
|
+
error: searchError,
|
|
43
|
+
message: searchMessage,
|
|
44
|
+
}), [searchStatus, searchError, searchMessage]);
|
|
45
|
+
const search = useCallback((({ items, allItems = items, itemGroups = [], keywords = [] }) => {
|
|
46
|
+
const results = doSearch(items, allItems, itemGroups, keywords, searchQuery, matcher);
|
|
47
|
+
const searchRelatedItems = doFilterRelatedItems(results.searchAllItems, searchResults, itemBuilder);
|
|
48
|
+
return {
|
|
49
|
+
...results,
|
|
50
|
+
searchRelatedItems,
|
|
51
|
+
//states
|
|
52
|
+
searchState,
|
|
53
|
+
semanticSearchState,
|
|
54
|
+
};
|
|
55
|
+
}), [searchQuery, searchState, semanticSearchState, searchResults, matcher, itemBuilder]);
|
|
56
|
+
return {
|
|
57
|
+
searchState,
|
|
58
|
+
semanticSearchState,
|
|
59
|
+
search,
|
|
60
|
+
onSearchQueryChange,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Debounce a string value by the given delay.
|
|
65
|
+
* Empty values are applied immediately (clearing search should feel instant).
|
|
66
|
+
*/
|
|
67
|
+
function useDebouncedValue(value, delay) {
|
|
68
|
+
const [debouncedValue, setDebouncedValue] = useState(value);
|
|
69
|
+
const timerRef = useRef(undefined);
|
|
70
|
+
useEffect(() => {
|
|
71
|
+
// Clear search immediately — no debounce, no transition
|
|
72
|
+
if (value === "") {
|
|
73
|
+
setDebouncedValue("");
|
|
74
|
+
return undefined;
|
|
75
|
+
}
|
|
76
|
+
timerRef.current = setTimeout(() => {
|
|
77
|
+
// Mark as low-priority so React can interrupt for input events
|
|
78
|
+
startTransition(() => setDebouncedValue(value));
|
|
79
|
+
}, delay);
|
|
80
|
+
return () => {
|
|
81
|
+
if (timerRef.current) {
|
|
82
|
+
clearTimeout(timerRef.current);
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
}, [value, delay]);
|
|
86
|
+
return debouncedValue;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Create a callback that updates the search query.
|
|
90
|
+
*/
|
|
91
|
+
function useOnSearchQueryChangeCallback(setSearchQuery) {
|
|
92
|
+
return useCallback((query) => {
|
|
93
|
+
setSearchQuery(query);
|
|
94
|
+
}, [setSearchQuery]);
|
|
95
|
+
}
|
|
96
|
+
//utils
|
|
97
|
+
function getSearchState(searchQuery, debouncedSearchQuery) {
|
|
98
|
+
if (searchQuery === "") {
|
|
99
|
+
return "idle";
|
|
100
|
+
}
|
|
101
|
+
if (debouncedSearchQuery !== searchQuery) {
|
|
102
|
+
return "searching";
|
|
103
|
+
}
|
|
104
|
+
return "completed";
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=useHybridSearch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useHybridSearch.js","sourceRoot":"","sources":["../../src/hooks/useHybridSearch.ts"],"names":[],"mappings":"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"}
|
package/esm/index.d.ts
CHANGED
|
@@ -6,4 +6,7 @@
|
|
|
6
6
|
export { type SemanticSearchInputResult, type SemanticSearchHookInput, useSemanticSearch, } from "./hooks/useSemanticSearch.js";
|
|
7
7
|
export { type FooterButtonAiAssistantProps, FooterButtonAiAssistant } from "./FooterButtonAiAssistant.js";
|
|
8
8
|
export { type SemanticSearchProps, SemanticSearch } from "./SemanticSearch.js";
|
|
9
|
+
export { type ICombinedSearchResults, type IHybridSearchResult, type ISearchState, type ISemanticSearchState, type IUseHybridSearchOptions, useHybridSearch, type OnSearchQueryChanged, } from "./hooks/useHybridSearch.js";
|
|
10
|
+
export type { HybridSearchMatcher, SearchItem, SearchItemGroup, SearchResults, HybridSearchItemBuilder, } from "./hooks/search/types.js";
|
|
11
|
+
export { defaultMatcher, customMatcher } from "./hooks/search/matchers.js";
|
|
9
12
|
//# sourceMappingURL=index.d.ts.map
|
package/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH,OAAO,EACH,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,iBAAiB,GACpB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,KAAK,4BAA4B,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAC1G,OAAO,EAAE,KAAK,mBAAmB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AAEH,OAAO,EACH,KAAK,yBAAyB,EAC9B,KAAK,uBAAuB,EAC5B,iBAAiB,GACpB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAE,KAAK,4BAA4B,EAAE,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAC1G,OAAO,EAAE,KAAK,mBAAmB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EACH,KAAK,sBAAsB,EAC3B,KAAK,mBAAmB,EACxB,KAAK,YAAY,EACjB,KAAK,oBAAoB,EACzB,KAAK,uBAAuB,EAC5B,eAAe,EACf,KAAK,oBAAoB,GAC5B,MAAM,4BAA4B,CAAC;AAEpC,YAAY,EACR,mBAAmB,EACnB,UAAU,EACV,eAAe,EACf,aAAa,EACb,uBAAuB,GAC1B,MAAM,yBAAyB,CAAC;AAEjC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC"}
|
package/esm/index.js
CHANGED
|
@@ -8,4 +8,6 @@
|
|
|
8
8
|
export { useSemanticSearch, } from "./hooks/useSemanticSearch.js";
|
|
9
9
|
export { FooterButtonAiAssistant } from "./FooterButtonAiAssistant.js";
|
|
10
10
|
export { SemanticSearch } from "./SemanticSearch.js";
|
|
11
|
+
export { useHybridSearch, } from "./hooks/useHybridSearch.js";
|
|
12
|
+
export { defaultMatcher, customMatcher } from "./hooks/search/matchers.js";
|
|
11
13
|
//# sourceMappingURL=index.js.map
|
package/esm/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAErC,oDAAoD;AAEpD;;;;GAIG;AAEH,OAAO,EAGH,iBAAiB,GACpB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAqC,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAC1G,OAAO,EAA4B,cAAc,EAAE,MAAM,qBAAqB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAErC,oDAAoD;AAEpD;;;;GAIG;AAEH,OAAO,EAGH,iBAAiB,GACpB,MAAM,8BAA8B,CAAC;AACtC,OAAO,EAAqC,uBAAuB,EAAE,MAAM,8BAA8B,CAAC;AAC1G,OAAO,EAA4B,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE/E,OAAO,EAMH,eAAe,GAElB,MAAM,4BAA4B,CAAC;AAUpC,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC"}
|
|
@@ -11,8 +11,22 @@ import { ISemanticSearchRelationship } from '@gooddata/sdk-model';
|
|
|
11
11
|
import { ISemanticSearchResultItem } from '@gooddata/sdk-model';
|
|
12
12
|
import { JSX } from 'react/jsx-runtime';
|
|
13
13
|
import { MouseEvent as MouseEvent_2 } from 'react';
|
|
14
|
+
import { ObjectType } from '@gooddata/sdk-model';
|
|
15
|
+
import { ObjRef } from '@gooddata/sdk-model';
|
|
14
16
|
import { ReactNode } from 'react';
|
|
15
17
|
|
|
18
|
+
/**
|
|
19
|
+
* @alpha
|
|
20
|
+
* Custom matcher for the search. Can be used to match any property of the search item.
|
|
21
|
+
*/
|
|
22
|
+
export declare function customMatcher<I extends SearchItem, G extends SearchItemGroup<I>>(props: (keyof I & keyof G)[]): HybridSearchMatcher;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @alpha
|
|
26
|
+
* Default matcher for the search. Supports title, name, description, summary.
|
|
27
|
+
*/
|
|
28
|
+
export declare function defaultMatcher<I extends SearchItem, G extends SearchItemGroup<I>>(item: I | G | string, searchQueryUpper: string): boolean;
|
|
29
|
+
|
|
16
30
|
/**
|
|
17
31
|
* @public
|
|
18
32
|
*/
|
|
@@ -25,6 +39,177 @@ export declare type FooterButtonAiAssistantProps = {
|
|
|
25
39
|
onClick?: (e: MouseEvent_2) => void;
|
|
26
40
|
};
|
|
27
41
|
|
|
42
|
+
/**
|
|
43
|
+
* @alpha
|
|
44
|
+
* Defines the shape of the item builder.
|
|
45
|
+
*/
|
|
46
|
+
export declare type HybridSearchItemBuilder<I extends SearchItem> = (item: ISemanticSearchResultItem, props: {
|
|
47
|
+
ref: ObjRef;
|
|
48
|
+
type: ObjectType;
|
|
49
|
+
}) => I | null | undefined;
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @alpha
|
|
53
|
+
* Defines the shape of the search matcher.
|
|
54
|
+
*/
|
|
55
|
+
export declare type HybridSearchMatcher = <I extends SearchItem, G extends SearchItemGroup<I>>(item: I | G | string, searchQueryUpper: string) => boolean;
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @alpha
|
|
59
|
+
* Search results that are combined from semantic search and normal search.
|
|
60
|
+
*/
|
|
61
|
+
export declare interface ICombinedSearchResults<I extends SearchItem, G extends SearchItemGroup<I>> extends SearchResults<I, G> {
|
|
62
|
+
searchRelatedItems: ReadonlyArray<I>;
|
|
63
|
+
searchState: ISearchState;
|
|
64
|
+
semanticSearchState: ISemanticSearchState;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* @alpha
|
|
69
|
+
* Result of the useHybridSearch hook.
|
|
70
|
+
*/
|
|
71
|
+
export declare interface IHybridSearchResult<I extends SearchItem, G extends SearchItemGroup<I>> {
|
|
72
|
+
searchState: ISearchState;
|
|
73
|
+
semanticSearchState: ISemanticSearchState;
|
|
74
|
+
search: (props: {
|
|
75
|
+
items: ReadonlyArray<I>;
|
|
76
|
+
allItems?: ReadonlyArray<I>;
|
|
77
|
+
itemGroups?: ReadonlyArray<G>;
|
|
78
|
+
keywords?: string[];
|
|
79
|
+
}) => ICombinedSearchResults<I, G>;
|
|
80
|
+
onSearchQueryChange: OnSearchQueryChanged;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* @alpha
|
|
85
|
+
* State of the search.
|
|
86
|
+
*/
|
|
87
|
+
export declare interface ISearchState {
|
|
88
|
+
/**
|
|
89
|
+
* The current search query.
|
|
90
|
+
* This is the query that is currently being typed by the user.
|
|
91
|
+
* It may be different from the debouncedQuery if the user is still typing.
|
|
92
|
+
*/
|
|
93
|
+
query: string;
|
|
94
|
+
/**
|
|
95
|
+
* The debounced search query.
|
|
96
|
+
* This is the query that is currently being used for the search.
|
|
97
|
+
* It may be different from the query if the user is still typing.
|
|
98
|
+
*/
|
|
99
|
+
debouncedQuery: string;
|
|
100
|
+
/**
|
|
101
|
+
* The current state of the search.
|
|
102
|
+
* - idle - means the user has not typed anything yet
|
|
103
|
+
* - searching - means the user is currently typing
|
|
104
|
+
* - completed - means the user has stopped typing and the search is complete
|
|
105
|
+
*/
|
|
106
|
+
state: "idle" | "searching" | "completed";
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/**
|
|
110
|
+
* @alpha
|
|
111
|
+
* State of semantic search.
|
|
112
|
+
*/
|
|
113
|
+
export declare interface ISemanticSearchState {
|
|
114
|
+
/**
|
|
115
|
+
* The current state of semantic search.
|
|
116
|
+
* - idle - means the semantic search is not running
|
|
117
|
+
* - loading - means the semantic search is running
|
|
118
|
+
* - error - means the semantic search failed
|
|
119
|
+
* - success - means the semantic search succeeded
|
|
120
|
+
*/
|
|
121
|
+
state: "idle" | "loading" | "error" | "success";
|
|
122
|
+
/**
|
|
123
|
+
* The message to show to the user that came from the backend.
|
|
124
|
+
*/
|
|
125
|
+
message: string;
|
|
126
|
+
/**
|
|
127
|
+
* The error message if the semantic search failed.
|
|
128
|
+
*/
|
|
129
|
+
error?: string;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* @alpha
|
|
134
|
+
* Options for the useHybridSearch hook.
|
|
135
|
+
*/
|
|
136
|
+
export declare interface IUseHybridSearchOptions<I extends SearchItem> extends Pick<SemanticSearchHookInput, "deepSearch" | "limit" | "includeTags" | "excludeTags" | "objectTypes"> {
|
|
137
|
+
/**
|
|
138
|
+
* The backend to use for the search.
|
|
139
|
+
* If omitted, will be retrieved from the context.
|
|
140
|
+
*/
|
|
141
|
+
backend?: IAnalyticalBackend;
|
|
142
|
+
/**
|
|
143
|
+
* The workspace to use for the search.
|
|
144
|
+
* If omitted, will be retrieved from the context.
|
|
145
|
+
*/
|
|
146
|
+
workspace?: string;
|
|
147
|
+
/**
|
|
148
|
+
* Allow semantic search.
|
|
149
|
+
* default: true
|
|
150
|
+
*/
|
|
151
|
+
allowSematicSearch?: boolean;
|
|
152
|
+
/**
|
|
153
|
+
* Debounce time in milliseconds for search query.
|
|
154
|
+
* default: 150
|
|
155
|
+
*/
|
|
156
|
+
debounceMs?: number;
|
|
157
|
+
/**
|
|
158
|
+
* Custom matcher for the search results.
|
|
159
|
+
* If provided, the matcher will be used to filter the search results.
|
|
160
|
+
* The matcher should return true if the item should be included in the search results,
|
|
161
|
+
* and false otherwise.
|
|
162
|
+
*/
|
|
163
|
+
matcher?: HybridSearchMatcher;
|
|
164
|
+
/**
|
|
165
|
+
* Item builder for the search results.
|
|
166
|
+
* If provided, the item builder will be used to transform the search results into a different format.
|
|
167
|
+
* The item builder should return the transformed item.
|
|
168
|
+
*/
|
|
169
|
+
itemBuilder: HybridSearchItemBuilder<I>;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
/**
|
|
173
|
+
* @alpha
|
|
174
|
+
* On search query change callback.
|
|
175
|
+
*/
|
|
176
|
+
export declare type OnSearchQueryChanged = (searchQuery: string) => void;
|
|
177
|
+
|
|
178
|
+
/**
|
|
179
|
+
* @alpha
|
|
180
|
+
* Defines the shape of the search item.
|
|
181
|
+
*/
|
|
182
|
+
export declare type SearchItem = {
|
|
183
|
+
ref: ObjRef;
|
|
184
|
+
title?: string;
|
|
185
|
+
name?: string;
|
|
186
|
+
description?: string;
|
|
187
|
+
summary?: string;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
/**
|
|
191
|
+
* @alpha
|
|
192
|
+
* Defines the shape of the search item group.
|
|
193
|
+
*/
|
|
194
|
+
export declare type SearchItemGroup<I> = {
|
|
195
|
+
title?: string;
|
|
196
|
+
name?: string;
|
|
197
|
+
description?: string;
|
|
198
|
+
summary?: string;
|
|
199
|
+
items?: I[];
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* @alpha
|
|
204
|
+
* Defines the shape of the search results.
|
|
205
|
+
*/
|
|
206
|
+
export declare type SearchResults<I extends SearchItem, G extends SearchItemGroup<I>> = {
|
|
207
|
+
searchItems: ReadonlyArray<I>;
|
|
208
|
+
searchAllItems: ReadonlyArray<I>;
|
|
209
|
+
searchItemGroups: ReadonlyArray<G>;
|
|
210
|
+
searchKeywords: ReadonlyArray<string>;
|
|
211
|
+
};
|
|
212
|
+
|
|
28
213
|
/**
|
|
29
214
|
* Semantic search filed with dropdown for selecting items.
|
|
30
215
|
* @beta
|
|
@@ -175,6 +360,13 @@ export declare type SemanticSearchProps = {
|
|
|
175
360
|
}) => ReactNode;
|
|
176
361
|
};
|
|
177
362
|
|
|
363
|
+
/**
|
|
364
|
+
* @alpha
|
|
365
|
+
* Use a hybrid search implementation that debounce the search query and provide semantic search
|
|
366
|
+
* related results
|
|
367
|
+
*/
|
|
368
|
+
export declare function useHybridSearch<I extends SearchItem, G extends SearchItemGroup<I>>({ limit, workspace, backend, debounceMs, allowSematicSearch, deepSearch, objectTypes, includeTags, excludeTags, matcher, itemBuilder }: IUseHybridSearchOptions<I>): IHybridSearchResult<I, G>;
|
|
369
|
+
|
|
178
370
|
/**
|
|
179
371
|
* Hook to perform semantic search.
|
|
180
372
|
* Makes the request to server and returns the search results.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gooddata/sdk-ui-semantic-search",
|
|
3
|
-
"version": "11.26.0-alpha.
|
|
3
|
+
"version": "11.26.0-alpha.3",
|
|
4
4
|
"description": "GoodData SDK TypeScript & React skeleton",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "GoodData Corporation",
|
|
@@ -35,12 +35,12 @@
|
|
|
35
35
|
"lodash-es": "^4.17.23",
|
|
36
36
|
"react-intl": "7.1.11",
|
|
37
37
|
"tslib": "2.8.1",
|
|
38
|
-
"@gooddata/sdk-
|
|
39
|
-
"@gooddata/sdk-
|
|
40
|
-
"@gooddata/sdk-ui": "11.26.0-alpha.
|
|
41
|
-
"@gooddata/sdk-ui
|
|
42
|
-
"@gooddata/sdk-ui-
|
|
43
|
-
"@gooddata/util": "11.26.0-alpha.
|
|
38
|
+
"@gooddata/sdk-backend-spi": "11.26.0-alpha.3",
|
|
39
|
+
"@gooddata/sdk-model": "11.26.0-alpha.3",
|
|
40
|
+
"@gooddata/sdk-ui-theme-provider": "11.26.0-alpha.3",
|
|
41
|
+
"@gooddata/sdk-ui": "11.26.0-alpha.3",
|
|
42
|
+
"@gooddata/sdk-ui-kit": "11.26.0-alpha.3",
|
|
43
|
+
"@gooddata/util": "11.26.0-alpha.3"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
46
|
"@microsoft/api-documenter": "^7.17.0",
|
|
@@ -80,11 +80,11 @@
|
|
|
80
80
|
"typescript": "5.9.3",
|
|
81
81
|
"vitest": "4.0.8",
|
|
82
82
|
"vitest-dom": "0.1.1",
|
|
83
|
-
"@gooddata/eslint-config": "11.26.0-alpha.
|
|
84
|
-
"@gooddata/i18n-toolkit": "11.26.0-alpha.
|
|
85
|
-
"@gooddata/oxlint-config": "11.26.0-alpha.
|
|
86
|
-
"@gooddata/
|
|
87
|
-
"@gooddata/
|
|
83
|
+
"@gooddata/eslint-config": "11.26.0-alpha.3",
|
|
84
|
+
"@gooddata/i18n-toolkit": "11.26.0-alpha.3",
|
|
85
|
+
"@gooddata/oxlint-config": "11.26.0-alpha.3",
|
|
86
|
+
"@gooddata/stylelint-config": "11.26.0-alpha.3",
|
|
87
|
+
"@gooddata/sdk-backend-mockingbird": "11.26.0-alpha.3"
|
|
88
88
|
},
|
|
89
89
|
"peerDependencies": {
|
|
90
90
|
"react": "^18.0.0 || ^19.0.0",
|