Skip to content

Commit 69aa1c0

Browse files
committed
URL-søk
1 parent 55e11bc commit 69aa1c0

File tree

9 files changed

+76
-28
lines changed

9 files changed

+76
-28
lines changed

.env-template

+1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
NODE_ENV=development
22
APP_PORT=3399
33
APP_BASEPATH=/
4+
APP_ORIGIN=http://localhost:3399
45
OPEN_SEARCH_URI:http://my-opensearch-instance
56
OPEN_SEARCH_USERNAME: username
67
OPEN_SEARCH_PASSWORD: password

.github/workflows/build-and-deploy.yml

+1
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ jobs:
2626
cat > .env <<EOF
2727
APP_PORT=3399
2828
APP_BASEPATH=/
29+
APP_ORIGIN=https://cms-arkiv.intern.nav.no
2930
EOF
3031
- name: Install dependencies
3132
run: npm ci

common/contentSearch.ts

+3-1
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,14 @@ export type ContentSearchResult = {
1616

1717
export type ContentSearchSort = 'score' | 'datetime' | 'name';
1818

19+
export type ContentSearchType = 'titles' | 'locations' | 'all';
20+
1921
export type ContentSearchParams = {
2022
from: number;
2123
size: number;
2224
query?: string;
2325
sort?: ContentSearchSort;
24-
withContent?: boolean;
26+
type?: ContentSearchType;
2527
withChildCategories?: boolean;
2628
categoryKeys?: string[];
2729
};

server/src/global.d.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ declare global {
44
NODE_ENV: 'development' | 'production';
55
APP_BASEPATH: string;
66
APP_PORT: string;
7+
APP_ORIGIN: string;
78
OPEN_SEARCH_URI: string;
89
OPEN_SEARCH_USERNAME: string;
910
OPEN_SEARCH_PASSWORD: string;

server/src/opensearch/queries/contentSearch.ts

+38-16
Original file line numberDiff line numberDiff line change
@@ -3,18 +3,26 @@ import {
33
SearchRequest,
44
SearchSort,
55
} from '@opensearch-project/opensearch/api/types';
6-
import { ContentSearchParams, ContentSearchSort } from '../../../../common/contentSearch';
6+
import {
7+
ContentSearchParams,
8+
ContentSearchSort,
9+
ContentSearchType,
10+
} from '../../../../common/contentSearch';
711
import { Request } from 'express';
812
import { parseNumberParam, parseToStringArray } from '../../utils/queryParams';
913
import { CmsArchiveCategoriesService } from '../../cms/CmsArchiveCategoriesService';
1014

1115
const SIZE_DEFAULT = 50;
1216

1317
const sortParamsSet: ReadonlySet<ContentSearchSort> = new Set(['name', 'datetime', 'score']);
18+
const typeParamsSet: ReadonlySet<ContentSearchType> = new Set(['all', 'locations', 'titles']);
1419

1520
const isValidSort = (sort: string): sort is ContentSearchSort =>
1621
sortParamsSet.has(sort as ContentSearchSort);
1722

23+
const isValidType = (type: string): type is ContentSearchType =>
24+
typeParamsSet.has(type as ContentSearchType);
25+
1826
const sortParams: Record<ContentSearchSort, SearchSort> = {
1927
score: {
2028
_score: 'desc',
@@ -28,12 +36,12 @@ const sortParams: Record<ContentSearchSort, SearchSort> = {
2836
} as const;
2937

3038
export const transformQueryToContentSearchParams = (req: Request): ContentSearchParams | null => {
31-
const { query, withContent, size, sort, from, categoryKeys, withChildCategories } =
39+
const { query, type, size, sort, from, categoryKeys, withChildCategories } =
3240
req.query as Record<keyof ContentSearchParams, string>;
3341

3442
return {
3543
query,
36-
withContent: withContent === 'true',
44+
type: isValidType(type) ? type : undefined,
3745
categoryKeys: parseToStringArray(categoryKeys),
3846
withChildCategories: withChildCategories === 'true',
3947
sort: isValidSort(sort) ? sort : 'score',
@@ -53,7 +61,7 @@ export const buildContentSearchParams = (
5361
from,
5462
size,
5563
sort = 'score',
56-
withContent,
64+
type,
5765
categoryKeys,
5866
withChildCategories,
5967
} = contentSearchParams;
@@ -69,19 +77,33 @@ export const buildContentSearchParams = (
6977
];
7078

7179
if (query) {
72-
const fields = ['displayName^10'];
73-
74-
if (withContent) {
75-
fields.push('xmlAsString');
80+
if (type === 'locations') {
81+
const { pathname } = new URL(query, process.env.APP_ORIGIN);
82+
83+
must.push({
84+
prefix: {
85+
'locations.menuItemPath': {
86+
value: decodeURIComponent(pathname),
87+
// @ts-expect-error (this is a valid field, not yet part of the library type def)
88+
case_insensitive: true,
89+
},
90+
},
91+
});
92+
} else {
93+
const fields = ['displayName^5'];
94+
95+
if (type === 'all') {
96+
fields.push('xmlAsString');
97+
}
98+
99+
must.push({
100+
multi_match: {
101+
query,
102+
fields,
103+
type: 'phrase_prefix',
104+
},
105+
});
76106
}
77-
78-
must.push({
79-
multi_match: {
80-
query,
81-
fields,
82-
type: 'phrase_prefix',
83-
},
84-
});
85107
}
86108

87109
if (categoryKeys) {

server/src/utils/validateEnv.ts

+1
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const EXPECTED_KEYS: Array<keyof NodeJS.ProcessEnv> = [
44
'NODE_ENV',
55
'APP_PORT',
66
'APP_BASEPATH',
7+
'APP_ORIGIN',
78
'OPEN_SEARCH_URI',
89
'OPEN_SEARCH_USERNAME',
910
'OPEN_SEARCH_PASSWORD',

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

+1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ export const SearchInput = ({ setSearchResult, className }: Props) => {
1818
from: 0,
1919
size: 50,
2020
sort: 'score',
21+
type: 'titles',
2122
withChildCategories: true,
2223
});
2324

src/components/left-section/search/search-settings/SearchSettings.module.css

+14-4
Original file line numberDiff line numberDiff line change
@@ -54,9 +54,19 @@
5454
align-items: center;
5555
}
5656

57+
.withHelp {
58+
display: flex;
59+
gap: 0.5rem;
60+
align-items: center;
61+
:global(.navds-popover__content) {
62+
font-size: var(--a-font-size-small);
63+
line-height: var(--a-font-line-height-medium);
64+
}
65+
}
66+
5767
.categoriesSelector {
58-
/*ul {*/
59-
/* gap: 0.25rem;*/
60-
/* font-size: 0.75rem;*/
61-
/*}*/
68+
ul {
69+
gap: 0.25rem;
70+
font-size: 0.75rem;
71+
}
6272
}

src/components/left-section/search/search-settings/SearchSettings.tsx

+16-7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import React, { useState } from 'react';
2-
import { Button, Label, Radio, RadioGroup, UNSAFE_Combobox } from '@navikt/ds-react';
2+
import { Button, HelpText, Label, Radio, RadioGroup, UNSAFE_Combobox } from '@navikt/ds-react';
33
import { ChevronDownIcon } from '@navikt/aksel-icons';
44
import { ContentSearchParams } from '../../../../../common/contentSearch';
55
import { classNames } from '../../../../utils/classNames';
@@ -18,7 +18,7 @@ export const SearchSettings = ({ searchParams, setSearchParams }: Props) => {
1818

1919
const { appContext } = useAppState();
2020

21-
const { sort, categoryKeys, withContent } = searchParams;
21+
const { sort, categoryKeys, type } = searchParams;
2222

2323
const { titlesToKeys, keysToTitles } = createKeysTitlesMaps(appContext.rootCategories);
2424
const categoryKeysSelected = new Set<string>(categoryKeys);
@@ -42,11 +42,20 @@ export const SearchSettings = ({ searchParams, setSearchParams }: Props) => {
4242
<div className={classNames(style.settings, isOpen && style.open)}>
4343
<RadioGroup
4444
size={'small'}
45-
legend={'Søk i...'}
46-
value={withContent ? 'all' : 'titles'}
47-
onChange={(value) => setSearchParams({ withContent: value === 'all' })}
45+
legend={'Søk etter...'}
46+
value={type}
47+
onChange={(value) => setSearchParams({ type: value })}
4848
>
49-
<Radio value={'titles'}>{'Kun innholdstitler'}</Radio>
49+
<Radio value={'titles'}>{'Tittel'}</Radio>
50+
<span className={style.withHelp}>
51+
<Radio value={'locations'}>{'URL'}</Radio>
52+
<HelpText wrapperClassName={style.help}>
53+
{'Prefix-søk på pathname. F.eks. vil '}
54+
<code>{'https://www.nav.no/no/person/arbeid'}</code>
55+
{' gi treff på alle sider med en path som starter med '}
56+
<code>{'/no/person/arbeid'}</code>
57+
</HelpText>
58+
</span>
5059
<Radio value={'all'}>{'Alt innhold'}</Radio>
5160
</RadioGroup>
5261
<RadioGroup
@@ -60,7 +69,7 @@ export const SearchSettings = ({ searchParams, setSearchParams }: Props) => {
6069
<Radio value={'datetime'}>{'Sist endret'}</Radio>
6170
</RadioGroup>
6271
<UNSAFE_Combobox
63-
label={'Velg hovedkategorier'}
72+
label={'Avgrens til valgte kategorier'}
6473
size={'small'}
6574
className={style.categoriesSelector}
6675
clearButton={true}

0 commit comments

Comments
 (0)