Skip to content

Commit 55e11bc

Browse files
committed
Implementerer tilpasset søk
1 parent d7753cf commit 55e11bc

13 files changed

+265
-88
lines changed

common/contentSearch.ts

+3-2
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,9 @@ export type ContentSearchSort = 'score' | 'datetime' | 'name';
1919
export type ContentSearchParams = {
2020
from: number;
2121
size: number;
22-
fullQuery?: boolean;
23-
categoryKeys?: string[];
2422
query?: string;
2523
sort?: ContentSearchSort;
24+
withContent?: boolean;
25+
withChildCategories?: boolean;
26+
categoryKeys?: string[];
2627
};

package-lock.json

+17-17
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+3-3
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,9 @@
2020
"@mui/material": "5.15.6",
2121
"@mui/system": "5.15.6",
2222
"@mui/x-tree-view": "6.17.0",
23-
"@navikt/aksel-icons": "5.15.1",
24-
"@navikt/ds-css": "5.15.1",
25-
"@navikt/ds-react": "5.15.1",
23+
"@navikt/aksel-icons": "5.17.4",
24+
"@navikt/ds-css": "5.17.4",
25+
"@navikt/ds-react": "5.17.4",
2626
"csp-header": "5.2.1",
2727
"lodash.debounce": "4.0.8",
2828
"react": "18.2.0",

server/src/cms/CmsArchiveCategoriesService.ts

+17-14
Original file line numberDiff line numberDiff line change
@@ -44,17 +44,6 @@ export class CmsArchiveCategoriesService {
4444
return this.rootCategories;
4545
}
4646

47-
public getCategory(categoryKey: string): CmsCategoryListItem | undefined {
48-
return this.categoriesMap.get(categoryKey);
49-
}
50-
51-
public async getCategoryFull(categoryKey: string): Promise<CmsCategoryDocument | null> {
52-
return this.client.getDocument<CmsCategoryDocument>({
53-
index: this.categoriesIndex,
54-
id: categoryKey,
55-
});
56-
}
57-
5847
public getCategories(categoryKeys: string[]): CmsCategoryListItem[] {
5948
return categoryKeys.reduce<CmsCategoryListItem[]>((acc, key) => {
6049
const category = this.categoriesMap.get(key);
@@ -66,6 +55,20 @@ export class CmsArchiveCategoriesService {
6655
}, []);
6756
}
6857

58+
public getDescendantCategories(categoryKey: string, keys: string[] = []): string[] {
59+
const category = this.categoriesMap.get(categoryKey);
60+
if (!category || category.categories.length === 0) {
61+
return keys;
62+
}
63+
64+
category.categories.forEach((child) => {
65+
keys.push(child.key);
66+
this.getDescendantCategories(child.key, keys);
67+
});
68+
69+
return keys;
70+
}
71+
6972
private populateCategoriesMap(categories: CmsCategoryListItem[]) {
7073
this.categoriesMap.clear();
7174
this.rootCategories.length = 0;
@@ -113,17 +116,17 @@ export class CmsArchiveCategoriesService {
113116
.search<CmsCategoryDocument>({
114117
index: this.categoriesIndex,
115118
_source_excludes: ['xmlAsString'],
116-
size: 10000,
119+
size: 5000,
117120
body: {
118121
query: {
119122
match_all: {},
120123
},
121124
},
122125
})
123126
.then((result) => {
124-
if (result && result.total > 10000) {
127+
if (result && result.total > result.hits.length) {
125128
console.error(
126-
`Found more than 10000 categories in ${this.categoriesIndex} - expected 3127 (sbs) or 3866 (fss)`
129+
`Found too many categories in ${this.categoriesIndex}! (${result.total}) - expected 3127 (sbs) or 3866 (fss)`
127130
);
128131
}
129132

server/src/cms/CmsArchiveContentService.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class CmsArchiveContentService {
3131

3232
public async contentSearch(params: ContentSearchParams): Promise<ContentSearchResult> {
3333
const result = await this.client.search<CmsContentDocument>({
34-
...buildContentSearchParams(params),
34+
...buildContentSearchParams(params, this.categoriesService),
3535
index: this.contentsIndex,
3636
});
3737

server/src/opensearch/queries/contentSearch.ts

+27-9
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
import { ContentSearchParams, ContentSearchSort } from '../../../../common/contentSearch';
77
import { Request } from 'express';
88
import { parseNumberParam, parseToStringArray } from '../../utils/queryParams';
9+
import { CmsArchiveCategoriesService } from '../../cms/CmsArchiveCategoriesService';
910

1011
const SIZE_DEFAULT = 50;
1112

@@ -27,15 +28,14 @@ const sortParams: Record<ContentSearchSort, SearchSort> = {
2728
} as const;
2829

2930
export const transformQueryToContentSearchParams = (req: Request): ContentSearchParams | null => {
30-
const { query, fullQuery, size, sort, from, categoryKeys } = req.query as Record<
31-
string,
32-
string
33-
>;
31+
const { query, withContent, size, sort, from, categoryKeys, withChildCategories } =
32+
req.query as Record<keyof ContentSearchParams, string>;
3433

3534
return {
3635
query,
37-
fullQuery: fullQuery === 'true',
36+
withContent: withContent === 'true',
3837
categoryKeys: parseToStringArray(categoryKeys),
38+
withChildCategories: withChildCategories === 'true',
3939
sort: isValidSort(sort) ? sort : 'score',
4040
from: parseNumberParam(from) ?? 0,
4141
size: parseNumberParam(size) ?? SIZE_DEFAULT,
@@ -45,9 +45,18 @@ export const transformQueryToContentSearchParams = (req: Request): ContentSearch
4545
const includedFields = ['contentKey', 'versionKey', 'displayName', 'category.key'];
4646

4747
export const buildContentSearchParams = (
48-
contentSearchParams: ContentSearchParams
48+
contentSearchParams: ContentSearchParams,
49+
categoriesService: CmsArchiveCategoriesService
4950
): SearchRequest => {
50-
const { query, from, size, sort = 'score', fullQuery, categoryKeys } = contentSearchParams;
51+
const {
52+
query,
53+
from,
54+
size,
55+
sort = 'score',
56+
withContent,
57+
categoryKeys,
58+
withChildCategories,
59+
} = contentSearchParams;
5160

5261
const must: QueryDslQueryContainer[] = [
5362
{
@@ -62,7 +71,7 @@ export const buildContentSearchParams = (
6271
if (query) {
6372
const fields = ['displayName^10'];
6473

65-
if (fullQuery) {
74+
if (withContent) {
6675
fields.push('xmlAsString');
6776
}
6877

@@ -76,9 +85,18 @@ export const buildContentSearchParams = (
7685
}
7786

7887
if (categoryKeys) {
88+
const categoryKeysFinal = [...categoryKeys];
89+
90+
if (withChildCategories) {
91+
const childCategoryKeys = categoryKeys.flatMap((key) =>
92+
categoriesService.getDescendantCategories(key)
93+
);
94+
categoryKeysFinal.push(...childCategoryKeys);
95+
}
96+
7997
must.push({
8098
terms: {
81-
'category.key': categoryKeys,
99+
'category.key': categoryKeysFinal,
82100
},
83101
});
84102
}

server/src/utils/queryParams.ts

+1-5
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,17 @@ export const parseNumberParam = (value: unknown): number | undefined => {
1313
export const parseToStringArray = (value: unknown): string[] | undefined => {
1414
try {
1515
if (typeof value !== 'string') {
16-
console.log('Value is not a string');
1716
return undefined;
1817
}
1918

2019
const parsed = JSON.parse(value);
2120

2221
if (Array.isArray(parsed)) {
23-
console.log('Parsed value is an array');
2422
return parsed.map((item) => item.toString());
2523
}
2624

27-
console.log(`Parsed value is something else: ${typeof parsed}`);
28-
return [parsed];
25+
return [parsed.toString()];
2926
} catch (e) {
30-
console.error(`Error parsing value: ${e}`);
3127
return undefined;
3228
}
3329
};

src/components/common/categories-path/CategoriesPath.tsx

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ export const CategoriesPath = ({ path, size = 'normal', tooltipPosition, classNa
2929
);
3030

3131
return tooltipPosition ? (
32-
<Tooltip content={pathString} placement={tooltipPosition}>
32+
<Tooltip content={pathString} placement={tooltipPosition} maxChar={1000}>
3333
{PathComponent}
3434
</Tooltip>
3535
) : (

src/components/left-section/search/SearchInput.module.css

-7
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,3 @@
33
flex-direction: column;
44
padding: 0 0.5rem 1rem 0.5rem;
55
}
6-
7-
.labels {
8-
display: flex;
9-
justify-content: space-between;
10-
align-items: center;
11-
margin-bottom: 0.25rem;
12-
}

src/components/left-section/search/SearchInput.tsx

+18-21
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
import React, { useRef, useState } from 'react';
2-
import { Button, Label, Search } from '@navikt/ds-react';
3-
import { ContentSearchResult } from '../../../../common/contentSearch';
2+
import { Search } from '@navikt/ds-react';
3+
import { ContentSearchParams, ContentSearchResult } from '../../../../common/contentSearch';
44
import { useApiFetch } from '../../../fetch/useApiFetch';
55
import { classNames } from '../../../utils/classNames';
6-
import { ChevronDownIcon } from '@navikt/aksel-icons';
6+
import { SearchSettings } from './search-settings/SearchSettings';
77

88
import style from './SearchInput.module.css';
99

@@ -14,42 +14,39 @@ type Props = {
1414

1515
export const SearchInput = ({ setSearchResult, className }: Props) => {
1616
const inputRef = useRef<HTMLInputElement>(null);
17-
const [advancedSearchOpen, setAdvancedSearchOpen] = useState(false);
17+
const [searchParams, setSearchParams] = useState<ContentSearchParams>({
18+
from: 0,
19+
size: 50,
20+
sort: 'score',
21+
withChildCategories: true,
22+
});
23+
24+
const setSearchParamsPartial = (params: Partial<ContentSearchParams>) => {
25+
setSearchParams({ ...searchParams, ...params });
26+
};
1827

1928
const { fetchSearch } = useApiFetch();
2029

2130
return (
2231
<div className={classNames(style.search, className)}>
23-
<div className={style.labels}>
24-
<Label size={'small'}>{'Søk'}</Label>
25-
<Button
26-
size={'xsmall'}
27-
variant={'tertiary'}
28-
onClick={() => setAdvancedSearchOpen(true)}
29-
>
30-
{'Tilpass søket (coming soon!)'}
31-
<ChevronDownIcon />
32-
</Button>
33-
</div>
32+
<SearchSettings searchParams={searchParams} setSearchParams={setSearchParamsPartial} />
3433
<form
3534
role={'search'}
3635
onSubmit={(e) => {
3736
e.preventDefault();
3837

39-
const queryInput = inputRef.current?.value;
40-
if (!queryInput) {
41-
setSearchResult(null);
38+
if (!searchParams.query) {
4239
return;
4340
}
4441

4542
setSearchResult({
4643
hits: [],
47-
params: { query: queryInput, from: 0, size: 0 },
44+
params: searchParams,
4845
total: 0,
4946
status: 'loading',
5047
});
5148

52-
fetchSearch({ query: queryInput, from: 0, size: 50 }).then((result) => {
49+
fetchSearch(searchParams).then((result) => {
5350
setSearchResult(result);
5451
});
5552
}}
@@ -59,7 +56,7 @@ export const SearchInput = ({ setSearchResult, className }: Props) => {
5956
hideLabel={true}
6057
size={'small'}
6158
ref={inputRef}
62-
onClear={() => setSearchResult(null)}
59+
onChange={(value) => setSearchParamsPartial({ query: value })}
6360
/>
6461
</form>
6562
</div>

0 commit comments

Comments
 (0)