@nyris/nyris-webapp 0.3.97 → 0.3.99
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/build/asset-manifest.json +7 -6
- package/build/index.html +1 -1
- package/build/js/settings.example.js +41 -0
- package/build/static/css/main.5cb72c09.css +4 -0
- package/build/static/css/main.5cb72c09.css.map +1 -0
- package/build/static/js/main.2339271b.js +3 -0
- package/build/static/js/{main.9e7fb38a.js.map → main.2339271b.js.map} +1 -1
- package/build/static/media/plate_info.6beaea36d35053be3a45.png +0 -0
- package/package.json +3 -3
- package/public/js/settings.example.js +41 -0
- package/src/common/assets/images/plate_info.png +0 -0
- package/src/components/AuthApiKeySync.tsx +34 -0
- package/src/components/Cart.tsx +41 -0
- package/src/components/ChatAssistant/useChatAssistantLogic.ts +3 -2
- package/src/components/GoBackButton.tsx +29 -2
- package/src/components/Header.tsx +3 -0
- package/src/components/HitsPerPage.tsx +55 -18
- package/src/components/ImagePreview.tsx +31 -1
- package/src/components/ImageUpload.tsx +14 -3
- package/src/components/Inquiry/InquiryModal.tsx +3 -0
- package/src/components/LogoutModal.tsx +2 -0
- package/src/components/Pagination.tsx +33 -6
- package/src/components/PostFilter/PostFilter.tsx +8 -1
- package/src/components/PostFilter/PostFilterComponent.tsx +8 -22
- package/src/components/PostFilter/PostFilterFindApi.test.tsx +249 -0
- package/src/components/PostFilter/PostFilterFindApi.tsx +128 -52
- package/src/components/PreFilter/PreFilter.tsx +10 -2
- package/src/components/Product/Product.tsx +60 -10
- package/src/components/Product/ProductDetailView.tsx +23 -1
- package/src/components/Product/ProductDetailViewModal.tsx +5 -1
- package/src/components/Product/ProductList.tsx +51 -16
- package/src/components/Rfq/RfqModal.tsx +3 -0
- package/src/components/ScopeSelect/ScopeSelectForm.tsx +514 -0
- package/src/components/ScopeSelect/ScopeSelectImageActions.tsx +62 -0
- package/src/components/ScopeSelect/ScopeSelectImagePreview.tsx +141 -0
- package/src/components/ScopeSelect/ScopeSelectInfo.tsx +68 -0
- package/src/components/ScopeSelect/ScopeSelectInput.tsx +123 -0
- package/src/components/ScopeSelect/ScopeSelectModal.tsx +310 -0
- package/src/components/ScopeSelect/identifyTypePlateImage.test.ts +129 -0
- package/src/components/ScopeSelect/identifyTypePlateImage.ts +83 -0
- package/src/components/ScopeSelect/parseScopeIdResponse.test.ts +103 -0
- package/src/components/ScopeSelect/parseScopeIdResponse.ts +72 -0
- package/src/components/ScopeSelect/scopeSelectHelpers.ts +54 -0
- package/src/components/SidePanel.tsx +43 -0
- package/src/components/TextSearch.tsx +80 -14
- package/src/components/Tooltip/TooltipComponent.tsx +12 -4
- package/src/components/TypePlateUpload.tsx +132 -0
- package/src/hooks/useEffectiveGroundingResults.ts +8 -6
- package/src/hooks/useGoodResultsChat.ts +8 -22
- package/src/hooks/useImageSearch.ts +325 -20
- package/src/hooks/useMachinePartsListingPagination.ts +95 -0
- package/src/hooks/useResultEvaluator.ts +43 -19
- package/src/index.css +1 -1
- package/src/index.tsx +4 -0
- package/src/layouts/AppLayout.tsx +95 -9
- package/src/pages/Home.tsx +60 -14
- package/src/pages/Logout.tsx +2 -0
- package/src/pages/Result.tsx +206 -20
- package/src/providers/AuthProvider.tsx +5 -0
- package/src/services/Feedback.ts +224 -35
- package/src/services/feedbackSubtypes.ts +63 -0
- package/src/services/filter.ts +4 -3
- package/src/services/initialMachinePartsText.payload.test.ts +61 -0
- package/src/services/initialMachinePartsText.test.ts +33 -0
- package/src/services/initialMachinePartsText.ts +11 -0
- package/src/services/machinePartsPage.test.ts +74 -0
- package/src/services/machinePartsPage.ts +120 -0
- package/src/services/normalizeChatResponse.ts +26 -0
- package/src/services/scopeLookup.test.ts +67 -0
- package/src/services/scopeLookup.ts +39 -0
- package/src/services/visualSearch.listingOptions.test.ts +79 -0
- package/src/services/visualSearch.ts +76 -7
- package/src/services/vizo.ts +17 -5
- package/src/stores/machinePartsListing/machinePartsListingStore.ts +35 -0
- package/src/stores/request/filter/filter.initialState.ts +1 -0
- package/src/stores/request/filter/filter.slice.ts +2 -0
- package/src/stores/result/prodcuts/products.initialState.ts +1 -0
- package/src/stores/result/prodcuts/products.slice.ts +4 -0
- package/src/stores/scope/scopeStore.ts +67 -4
- package/src/stores/types.ts +19 -14
- package/src/translations.ts +213 -0
- package/src/types.ts +40 -0
- package/src/utils/derivePostFilterFacets.ts +68 -0
- package/src/utils/fetchProductImage.ts +1 -0
- package/src/utils/normalizeChatAssistantResponse.ts +227 -0
- package/src/utils/nyrisApiKey.ts +115 -0
- package/src/utils/productCardImageUrl.test.ts +41 -0
- package/src/utils/productCardImageUrl.ts +49 -0
- package/src/utils/textSearchFilter.test.ts +41 -0
- package/src/utils/textSearchFilter.ts +13 -6
- package/build/static/css/main.7c7f5447.css +0 -4
- package/build/static/css/main.7c7f5447.css.map +0 -1
- package/build/static/js/main.9e7fb38a.js +0 -3
- /package/build/static/js/{main.9e7fb38a.js.LICENSE.txt → main.2339271b.js.LICENSE.txt} +0 -0
|
@@ -9,6 +9,46 @@ import { isEqual } from 'lodash';
|
|
|
9
9
|
|
|
10
10
|
import { DEFAULT_REGION } from '../constants';
|
|
11
11
|
import { getUserLocation } from 'helpers/getGeoLocation';
|
|
12
|
+
import { getNyrisSettings } from 'utils/nyrisApiKey';
|
|
13
|
+
import useRequestStore from 'stores/request/requestStore';
|
|
14
|
+
import useScopeStore from 'stores/scope/scopeStore';
|
|
15
|
+
import { machinePartsPageText } from './machinePartsPage';
|
|
16
|
+
import useMachinePartsListingStore from 'stores/machinePartsListing/machinePartsListingStore';
|
|
17
|
+
|
|
18
|
+
const MACHINE_PARTS_LISTING_X_OPTIONS = 'hybrid_search.text.reranking=false';
|
|
19
|
+
|
|
20
|
+
/** Scope-only listing: generated item-key text, no keyword, image, or filters. */
|
|
21
|
+
export function machinePartsListingXOptions({
|
|
22
|
+
text,
|
|
23
|
+
hasSearchImage,
|
|
24
|
+
hasFilters,
|
|
25
|
+
scopeId,
|
|
26
|
+
itemKeys,
|
|
27
|
+
keyword,
|
|
28
|
+
pageIndex,
|
|
29
|
+
pageSize,
|
|
30
|
+
}: {
|
|
31
|
+
text?: string;
|
|
32
|
+
hasSearchImage: boolean;
|
|
33
|
+
hasFilters: boolean;
|
|
34
|
+
scopeId: string | null;
|
|
35
|
+
itemKeys: readonly string[];
|
|
36
|
+
keyword: string;
|
|
37
|
+
pageIndex: number;
|
|
38
|
+
pageSize: number;
|
|
39
|
+
}): string | undefined {
|
|
40
|
+
if (!scopeId || hasSearchImage || hasFilters) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
const listingText = machinePartsPageText(itemKeys, pageIndex, pageSize);
|
|
44
|
+
if (!listingText || text !== listingText) {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
if (keyword.trim().length > 0) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
50
|
+
return MACHINE_PARTS_LISTING_X_OPTIONS;
|
|
51
|
+
}
|
|
12
52
|
|
|
13
53
|
export interface Filter {
|
|
14
54
|
key?: string;
|
|
@@ -41,7 +81,7 @@ export const findRegions = async (
|
|
|
41
81
|
image: HTMLCanvasElement,
|
|
42
82
|
settings: NyrisAPISettings,
|
|
43
83
|
) => {
|
|
44
|
-
const nyrisApi = new NyrisAPI(settings);
|
|
84
|
+
const nyrisApi = new NyrisAPI(getNyrisSettings(settings));
|
|
45
85
|
let regions = await nyrisApi.findRegions(image);
|
|
46
86
|
const selectedRegion = getRegionByMaxConfidence(regions);
|
|
47
87
|
return {
|
|
@@ -52,6 +92,18 @@ export const findRegions = async (
|
|
|
52
92
|
};
|
|
53
93
|
};
|
|
54
94
|
|
|
95
|
+
/** Validated machine scope id. Item keys from /v1/scopes are not used. */
|
|
96
|
+
function appliedMachineScopeId(): string | null {
|
|
97
|
+
if (!window.settings?.scopes?.scopeID) {
|
|
98
|
+
return null;
|
|
99
|
+
}
|
|
100
|
+
const { scopeId } = useScopeStore.getState();
|
|
101
|
+
if (typeof scopeId !== 'string' || scopeId.trim().length === 0) {
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
104
|
+
return scopeId;
|
|
105
|
+
}
|
|
106
|
+
|
|
55
107
|
export const find = async ({
|
|
56
108
|
image,
|
|
57
109
|
settings,
|
|
@@ -67,8 +119,9 @@ export const find = async ({
|
|
|
67
119
|
text?: string;
|
|
68
120
|
scopeIds?: string;
|
|
69
121
|
}) => {
|
|
70
|
-
const nyrisApi = new NyrisAPI(settings);
|
|
71
|
-
let options: ImageSearchOptions =
|
|
122
|
+
const nyrisApi = new NyrisAPI(getNyrisSettings(settings));
|
|
123
|
+
let options: ImageSearchOptions =
|
|
124
|
+
typeof text === 'string' && text.length > 0 ? { text } : {};
|
|
72
125
|
|
|
73
126
|
if (window.settings?.geoLocation) {
|
|
74
127
|
try {
|
|
@@ -84,13 +137,29 @@ export const find = async ({
|
|
|
84
137
|
if (region) {
|
|
85
138
|
options = { ...options, cropRect: region };
|
|
86
139
|
}
|
|
140
|
+
const machineScopeId = appliedMachineScopeId();
|
|
141
|
+
const listingPage = useMachinePartsListingStore.getState();
|
|
142
|
+
const xOptions = machinePartsListingXOptions({
|
|
143
|
+
text,
|
|
144
|
+
hasSearchImage: Boolean(image),
|
|
145
|
+
hasFilters: Boolean(filters && filters.length > 0),
|
|
146
|
+
scopeId: machineScopeId,
|
|
147
|
+
itemKeys: useScopeStore.getState().itemKeys || [],
|
|
148
|
+
keyword: useRequestStore.getState().query || '',
|
|
149
|
+
pageIndex: listingPage.pageIndex,
|
|
150
|
+
pageSize: listingPage.pageSize,
|
|
151
|
+
});
|
|
87
152
|
return nyrisApi.find(
|
|
88
153
|
options,
|
|
89
154
|
image,
|
|
90
155
|
filters,
|
|
91
156
|
undefined,
|
|
92
|
-
|
|
93
|
-
|
|
157
|
+
xOptions,
|
|
158
|
+
machineScopeId
|
|
159
|
+
? [machineScopeId]
|
|
160
|
+
: scopeIds
|
|
161
|
+
? [scopeIds]
|
|
162
|
+
: [],
|
|
94
163
|
);
|
|
95
164
|
};
|
|
96
165
|
|
|
@@ -103,7 +172,7 @@ export const findCad = ({
|
|
|
103
172
|
settings: NyrisAPISettings;
|
|
104
173
|
filters?: Filter[];
|
|
105
174
|
}) => {
|
|
106
|
-
const nyrisApi = new NyrisAPI(settings);
|
|
175
|
+
const nyrisApi = new NyrisAPI(getNyrisSettings(settings));
|
|
107
176
|
|
|
108
177
|
return nyrisApi.findByCad(file, {}, filters);
|
|
109
178
|
};
|
|
@@ -115,7 +184,7 @@ export const getRequestImage = ({
|
|
|
115
184
|
url: string;
|
|
116
185
|
settings: NyrisAPISettings;
|
|
117
186
|
}) => {
|
|
118
|
-
const nyrisApi = new NyrisAPI(settings);
|
|
187
|
+
const nyrisApi = new NyrisAPI(getNyrisSettings(settings));
|
|
119
188
|
|
|
120
189
|
return nyrisApi.getCadRequestImage(url);
|
|
121
190
|
};
|
package/src/services/vizo.ts
CHANGED
|
@@ -1,6 +1,18 @@
|
|
|
1
1
|
import { RectCoords } from '@nyris/nyris-api';
|
|
2
2
|
import axios from 'axios';
|
|
3
3
|
import { cropImage } from 'utils/cropImageToBase64';
|
|
4
|
+
import { getEffectiveApiKey } from 'utils/nyrisApiKey';
|
|
5
|
+
import { normalizeChatResponse } from './normalizeChatResponse';
|
|
6
|
+
|
|
7
|
+
function resolveAiOrNyrisApiKey(explicitApiKey?: string): string {
|
|
8
|
+
if (explicitApiKey) {
|
|
9
|
+
return explicitApiKey;
|
|
10
|
+
}
|
|
11
|
+
if (window.settings.aiApiKey) {
|
|
12
|
+
return window.settings.aiApiKey;
|
|
13
|
+
}
|
|
14
|
+
return getEffectiveApiKey();
|
|
15
|
+
}
|
|
4
16
|
|
|
5
17
|
export interface ChatMultimodalInput {
|
|
6
18
|
metadata: string;
|
|
@@ -111,7 +123,7 @@ export async function rerankSmartFilters({
|
|
|
111
123
|
formData,
|
|
112
124
|
{
|
|
113
125
|
headers: {
|
|
114
|
-
'x-api-key': apiKey
|
|
126
|
+
'x-api-key': resolveAiOrNyrisApiKey(apiKey),
|
|
115
127
|
},
|
|
116
128
|
},
|
|
117
129
|
);
|
|
@@ -156,7 +168,7 @@ export async function generateSmartFilters({
|
|
|
156
168
|
formData,
|
|
157
169
|
{
|
|
158
170
|
headers: {
|
|
159
|
-
'x-api-key':
|
|
171
|
+
'x-api-key': resolveAiOrNyrisApiKey(),
|
|
160
172
|
},
|
|
161
173
|
},
|
|
162
174
|
);
|
|
@@ -319,20 +331,20 @@ export async function chatAnalysis({
|
|
|
319
331
|
}: ChatAnalysisParams): Promise<any> {
|
|
320
332
|
try {
|
|
321
333
|
const response = await axios.post(
|
|
322
|
-
|
|
334
|
+
`${window.settings.baseUrl}/api/ai-analysis/chat`,
|
|
323
335
|
{
|
|
324
336
|
promptKey,
|
|
325
337
|
multimodalInputs,
|
|
326
338
|
},
|
|
327
339
|
{
|
|
328
340
|
headers: {
|
|
329
|
-
'x-api-key': apiKey
|
|
341
|
+
'x-api-key': resolveAiOrNyrisApiKey(apiKey),
|
|
330
342
|
'Content-Type': 'application/json',
|
|
331
343
|
},
|
|
332
344
|
},
|
|
333
345
|
);
|
|
334
346
|
|
|
335
|
-
return response.data;
|
|
347
|
+
return normalizeChatResponse(response.data);
|
|
336
348
|
} catch (error: any) {
|
|
337
349
|
if (error.response) {
|
|
338
350
|
throw new Error(`API error: ${error.response.statusText}`);
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { create } from 'zustand';
|
|
2
|
+
import {
|
|
3
|
+
DEFAULT_MACHINE_PARTS_PAGE_SIZE,
|
|
4
|
+
machinePartsPageText,
|
|
5
|
+
} from 'services/machinePartsPage';
|
|
6
|
+
import useScopeStore from 'stores/scope/scopeStore';
|
|
7
|
+
|
|
8
|
+
interface MachinePartsListingState {
|
|
9
|
+
pageSize: number;
|
|
10
|
+
pageIndex: number;
|
|
11
|
+
setPageSize: (pageSize: number) => void;
|
|
12
|
+
setPageIndex: (pageIndex: number) => void;
|
|
13
|
+
resetPage: () => void;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
const useMachinePartsListingStore = create<MachinePartsListingState>()(set => ({
|
|
17
|
+
pageSize: DEFAULT_MACHINE_PARTS_PAGE_SIZE,
|
|
18
|
+
pageIndex: 0,
|
|
19
|
+
setPageSize: pageSize => set({ pageSize, pageIndex: 0 }),
|
|
20
|
+
setPageIndex: pageIndex => set({ pageIndex }),
|
|
21
|
+
resetPage: () => set({ pageIndex: 0 }),
|
|
22
|
+
}));
|
|
23
|
+
|
|
24
|
+
/** Scope-only listing restarts at page 1 and keeps the selected page size. */
|
|
25
|
+
export function firstMachinePartsListingText(): string | undefined {
|
|
26
|
+
useMachinePartsListingStore.getState().resetPage();
|
|
27
|
+
const { pageSize } = useMachinePartsListingStore.getState();
|
|
28
|
+
return machinePartsPageText(
|
|
29
|
+
useScopeStore.getState().itemKeys || [],
|
|
30
|
+
0,
|
|
31
|
+
pageSize,
|
|
32
|
+
);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export default useMachinePartsListingStore;
|
|
@@ -13,6 +13,8 @@ const filterSlice: StateCreator<FilterState & FilterAction> = set => ({
|
|
|
13
13
|
setPreFilterList: filter => set(() => ({ preFilterList: filter })),
|
|
14
14
|
setPreFilterLoading: isLoading =>
|
|
15
15
|
set(() => ({ preFilterLoading: isLoading })),
|
|
16
|
+
setTypePlatePreFilterValues: values =>
|
|
17
|
+
set(() => ({ typePlatePreFilterValues: values })),
|
|
16
18
|
setPostFilterSelections: filters =>
|
|
17
19
|
set(() => ({ postFilterSelections: filters })),
|
|
18
20
|
togglePostFilterSelection: (attribute, value) =>
|
|
@@ -61,6 +61,10 @@ const productsSlice: StateCreator<ProductsState & ProductsAction> = set => ({
|
|
|
61
61
|
set(() => ({
|
|
62
62
|
smartFilters,
|
|
63
63
|
})),
|
|
64
|
+
setRequestQuality: requestQuality =>
|
|
65
|
+
set(() => ({
|
|
66
|
+
requestQuality,
|
|
67
|
+
})),
|
|
64
68
|
setPostFilterFacets: facets =>
|
|
65
69
|
set(() => ({
|
|
66
70
|
postFilterFacets: facets,
|
|
@@ -1,35 +1,98 @@
|
|
|
1
1
|
import { create } from 'zustand';
|
|
2
2
|
import { Filter } from '@nyris/nyris-api';
|
|
3
3
|
|
|
4
|
+
export type ScopeSource = 'manual' | 'image';
|
|
5
|
+
|
|
6
|
+
export type AppliedScopeInput =
|
|
7
|
+
| { source: 'manual'; value: string }
|
|
8
|
+
| { source: 'image'; fileKey: string };
|
|
9
|
+
|
|
4
10
|
interface ScopeState {
|
|
5
11
|
itemKeys: string[];
|
|
6
12
|
filterAttributes: Filter[];
|
|
13
|
+
scopeId: string | null;
|
|
7
14
|
isLoading: boolean;
|
|
8
15
|
hasFetched: boolean;
|
|
16
|
+
formResetKey: number;
|
|
17
|
+
manualScopeId: string;
|
|
18
|
+
pendingFile: File | null;
|
|
19
|
+
previewUrl: string | null;
|
|
20
|
+
activeSource: ScopeSource | null;
|
|
21
|
+
lastAppliedInput: AppliedScopeInput | null;
|
|
22
|
+
lastExtractedFromImage: string;
|
|
9
23
|
}
|
|
10
24
|
|
|
11
25
|
interface ScopeAction {
|
|
12
|
-
setScope: (
|
|
26
|
+
setScope: (
|
|
27
|
+
itemKeys: string[],
|
|
28
|
+
filterAttributes: Filter[],
|
|
29
|
+
scopeId?: string | null,
|
|
30
|
+
) => void;
|
|
13
31
|
setScopeLoading: (isLoading: boolean) => void;
|
|
14
32
|
setScopeFetched: (hasFetched: boolean) => void;
|
|
33
|
+
setManualScopeId: (manualScopeId: string) => void;
|
|
34
|
+
setPendingFile: (pendingFile: File | null) => void;
|
|
35
|
+
setPreviewUrl: (previewUrl: string | null) => void;
|
|
36
|
+
setActiveSource: (activeSource: ScopeSource | null) => void;
|
|
37
|
+
setLastAppliedInput: (lastAppliedInput: AppliedScopeInput | null) => void;
|
|
38
|
+
setLastExtractedFromImage: (lastExtractedFromImage: string) => void;
|
|
15
39
|
resetScope: () => void;
|
|
16
40
|
}
|
|
17
41
|
|
|
18
42
|
const initialState: ScopeState = {
|
|
19
43
|
itemKeys: [],
|
|
20
44
|
filterAttributes: [],
|
|
45
|
+
scopeId: null,
|
|
21
46
|
isLoading: false,
|
|
22
47
|
hasFetched: false,
|
|
48
|
+
formResetKey: 0,
|
|
49
|
+
manualScopeId: '',
|
|
50
|
+
pendingFile: null,
|
|
51
|
+
previewUrl: null,
|
|
52
|
+
activeSource: null,
|
|
53
|
+
lastAppliedInput: null,
|
|
54
|
+
lastExtractedFromImage: '',
|
|
23
55
|
};
|
|
24
56
|
|
|
25
57
|
const useScopeStore = create<ScopeState & ScopeAction>()(set => ({
|
|
26
58
|
...initialState,
|
|
27
59
|
|
|
28
|
-
setScope: (itemKeys, filterAttributes) =>
|
|
29
|
-
set({ itemKeys, filterAttributes, hasFetched: true }),
|
|
60
|
+
setScope: (itemKeys, filterAttributes, scopeId = null) =>
|
|
61
|
+
set({ itemKeys, filterAttributes, scopeId, hasFetched: true }),
|
|
30
62
|
setScopeLoading: isLoading => set({ isLoading }),
|
|
31
63
|
setScopeFetched: hasFetched => set({ hasFetched }),
|
|
32
|
-
|
|
64
|
+
setManualScopeId: manualScopeId => set({ manualScopeId }),
|
|
65
|
+
setPendingFile: pendingFile => set({ pendingFile }),
|
|
66
|
+
setPreviewUrl: previewUrl => set({ previewUrl }),
|
|
67
|
+
setActiveSource: activeSource => set({ activeSource }),
|
|
68
|
+
setLastAppliedInput: lastAppliedInput => set({ lastAppliedInput }),
|
|
69
|
+
setLastExtractedFromImage: lastExtractedFromImage =>
|
|
70
|
+
set({ lastExtractedFromImage }),
|
|
71
|
+
resetScope: () =>
|
|
72
|
+
set(state => {
|
|
73
|
+
if (state.previewUrl) {
|
|
74
|
+
try {
|
|
75
|
+
URL.revokeObjectURL(state.previewUrl);
|
|
76
|
+
} catch {}
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
...initialState,
|
|
80
|
+
formResetKey: state.formResetKey + 1,
|
|
81
|
+
};
|
|
82
|
+
}),
|
|
33
83
|
}));
|
|
34
84
|
|
|
85
|
+
/** Machine scope that should constrain the results currently on screen. */
|
|
86
|
+
export function hasActiveMachineScope(): boolean {
|
|
87
|
+
if (!window.settings?.scopes?.scopeID) {
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
const { scopeId, itemKeys } = useScopeStore.getState();
|
|
91
|
+
return (
|
|
92
|
+
typeof scopeId === 'string' &&
|
|
93
|
+
scopeId.trim().length > 0 &&
|
|
94
|
+
itemKeys.length > 0
|
|
95
|
+
);
|
|
96
|
+
}
|
|
97
|
+
|
|
35
98
|
export default useScopeStore;
|
package/src/stores/types.ts
CHANGED
|
@@ -71,20 +71,21 @@ export interface ProductsState {
|
|
|
71
71
|
groundingError: string | null;
|
|
72
72
|
firstAlgoliaProducts: any[];
|
|
73
73
|
fullResultPool: any[];
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
74
|
+
smartFilters: {
|
|
75
|
+
status: 'idle' | 'loading' | 'success' | 'error';
|
|
76
|
+
filters: Array<{
|
|
77
|
+
key: string;
|
|
78
|
+
label: string;
|
|
79
|
+
value: string;
|
|
80
|
+
selected?: boolean;
|
|
81
|
+
}>;
|
|
82
|
+
selectedFilterKey: string | null;
|
|
83
|
+
selectedFilterValue: string | null;
|
|
84
|
+
rerankedSkus: string[];
|
|
85
|
+
rerankStatus: 'idle' | 'loading' | 'success' | 'error';
|
|
86
|
+
errorMessage: string | null;
|
|
87
|
+
};
|
|
88
|
+
requestQuality: string | null;
|
|
88
89
|
postFilterFacets: any[];
|
|
89
90
|
initialFindSearchSnapshot: {
|
|
90
91
|
results: any[];
|
|
@@ -110,6 +111,7 @@ export interface ProductsAction {
|
|
|
110
111
|
setFullResultPool: (products: any[]) => void;
|
|
111
112
|
resetGrounding: () => void;
|
|
112
113
|
setSmartFilters: (smartFilters: ProductsState['smartFilters']) => void;
|
|
114
|
+
setRequestQuality: (requestQuality: string | null) => void;
|
|
113
115
|
setPostFilterFacets: (facets: any[]) => void;
|
|
114
116
|
setInitialFindSearchSnapshot: (
|
|
115
117
|
snapshot: ProductsState['initialFindSearchSnapshot'],
|
|
@@ -132,6 +134,8 @@ export interface FilterState {
|
|
|
132
134
|
specificationFilter: Record<string, string>;
|
|
133
135
|
postFilterSelections: Record<string, string[]>;
|
|
134
136
|
preFilterLoading: boolean;
|
|
137
|
+
// Values applied from type-plate upload; cleared independently of manual picks.
|
|
138
|
+
typePlatePreFilterValues: string[];
|
|
135
139
|
}
|
|
136
140
|
|
|
137
141
|
export interface FilterAction {
|
|
@@ -144,6 +148,7 @@ export interface FilterAction {
|
|
|
144
148
|
togglePostFilterSelection: (attribute: string, value: string) => void;
|
|
145
149
|
clearPostFilterSelections: () => void;
|
|
146
150
|
setPreFilterLoading: (isLoading: boolean) => void;
|
|
151
|
+
setTypePlatePreFilterValues: (values: string[]) => void;
|
|
147
152
|
}
|
|
148
153
|
|
|
149
154
|
export interface MiscState {
|