Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(web): Tag filtering for generic lists #15196

Merged
merged 14 commits into from
Jun 19, 2024
317 changes: 257 additions & 60 deletions apps/web/components/GenericList/GenericList.tsx

Large diffs are not rendered by default.

4 changes: 1 addition & 3 deletions apps/web/components/Organization/Slice/SliceMachine.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -185,13 +185,11 @@ const renderSlice = (
return (
<GenericList
id={slice.id}
firstPageItemResponse={
(slice as GenericListSchema).firstPageListItemResponse
}
searchInputPlaceholder={
(slice as GenericListSchema).searchInputPlaceholder
}
itemType={(slice as GenericListSchema).itemType}
filterTags={(slice as GenericListSchema).filterTags}
/>
)
default:
Expand Down
6 changes: 6 additions & 0 deletions apps/web/screens/queries/GenericList.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export const GET_GENERIC_LIST_ITEMS_QUERY = gql`
input {
page
queryString
tags
}
items {
id
Expand All @@ -16,6 +17,11 @@ export const GET_GENERIC_LIST_ITEMS_QUERY = gql`
cardIntro {
...HtmlFields
}
filterTags {
id
title
slug
}
slug
}
total
Expand Down
19 changes: 5 additions & 14 deletions apps/web/screens/queries/fragments.ts
Original file line number Diff line number Diff line change
Expand Up @@ -855,24 +855,15 @@ export const slices = gql`
id
searchInputPlaceholder
itemType
firstPageListItemResponse {
input {
genericListId
lang
page
queryString
size
}
items {
filterTags {
id
title
slug
genericTagGroup {
id
date
title
slug
cardIntro {
...HtmlFields
}
}
total
}
}

Expand Down
2 changes: 1 addition & 1 deletion apps/web/utils/richText.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -191,9 +191,9 @@ const defaultRenderComponent = {
GenericList: (slice: GenericListSchema) => (
<GenericList
id={slice.id}
firstPageItemResponse={slice.firstPageListItemResponse}
searchInputPlaceholder={slice.searchInputPlaceholder}
itemType={slice.itemType}
filterTags={slice.filterTags}
/>
),
}
Expand Down
8 changes: 7 additions & 1 deletion libs/cms/src/lib/cms.elasticsearch.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -454,7 +454,7 @@ export class CmsElasticsearchService {
async getGenericListItems(
input: GetGenericListItemsInput,
): Promise<GenericListItemResponse> {
const must: Record<string, unknown>[] = [
let must: Record<string, unknown>[] = [
{
term: {
type: {
Expand Down Expand Up @@ -516,6 +516,12 @@ export class CmsElasticsearchService {
sort.unshift('_score')
}

if (input.tags && input.tags.length > 0 && input.tagGroups) {
must = must.concat(
generateGenericTagGroupQueries(input.tags, input.tagGroups),
)
}

const response: ApiResponse<SearchResponse<MappedData>> =
await this.elasticService.findByQuery(getElasticsearchIndex(input.lang), {
query: {
Expand Down
2 changes: 0 additions & 2 deletions libs/cms/src/lib/cms.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import {
FeaturedSupportQNAsResolver,
PowerBiSliceResolver,
LatestEventsSliceResolver,
GenericListResolver,
} from './cms.resolver'
import { CmsContentfulService } from './cms.contentful.service'
import { ContentfulRepository } from './contentful.repository'
Expand Down Expand Up @@ -51,7 +50,6 @@ import { OrganizationTitleEnByReferenceIdLoader } from './loaders/organizationTi
PowerBiService,
PowerBiSliceResolver,
LatestEventsSliceResolver,
GenericListResolver,
],
exports: [
ContentfulRepository,
Expand Down
15 changes: 0 additions & 15 deletions libs/cms/src/lib/cms.resolver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -818,18 +818,3 @@ export class FeaturedEventsResolver {
}
}
}

@Resolver(() => GenericList)
@CacheControl(defaultCache)
export class GenericListResolver {
constructor(
private readonly cmsElasticsearchService: CmsElasticsearchService,
) {}

@ResolveField(() => GenericListItemResponse)
firstPageListItemResponse(
@Parent() { firstPageListItemResponse: input }: GenericList,
) {
return this.cmsElasticsearchService.getGenericListItems(input)
}
}
9 changes: 8 additions & 1 deletion libs/cms/src/lib/dto/getGenericListItems.input.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { ElasticsearchIndexLocale } from '@island.is/content-search-index-manager'
import { Field, InputType, Int, ObjectType } from '@nestjs/graphql'
import { IsInt, IsOptional, IsString } from 'class-validator'
import GraphQLJSON from 'graphql-type-json'
import { ElasticsearchIndexLocale } from '@island.is/content-search-index-manager'

@InputType()
@ObjectType('GenericListItemResponseInput')
Expand All @@ -27,4 +28,10 @@ export class GetGenericListItemsInput {
@IsString()
@IsOptional()
queryString?: string

@Field(() => [String], { nullable: true })
tags?: string[]

@Field(() => GraphQLJSON, { nullable: true })
tagGroups?: Record<string, string[]>
}
10 changes: 8 additions & 2 deletions libs/cms/src/lib/generated/contentfulTypes.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1548,6 +1548,9 @@ export interface IGenericListFields {

/** Item Type */
itemType?: 'Non-clickable' | 'Clickable' | undefined

/** Filter Tags */
filterTags?: IGenericTag[] | undefined
}

/** A list of items which can be embedded into rich text */
Expand Down Expand Up @@ -1585,11 +1588,14 @@ export interface IGenericListItemFields {
/** Card Intro */
cardIntro?: Document | undefined

/** Slug */
slug?: string | undefined

/** Content */
content?: Document | undefined

/** Slug */
slug?: string | undefined
/** Filter Tags */
filterTags?: IGenericTag[] | undefined
}

/** An item that belongs to a generic list */
Expand Down
17 changes: 5 additions & 12 deletions libs/cms/src/lib/models/genericList.model.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { Field, ID, ObjectType, registerEnumType } from '@nestjs/graphql'
import { ElasticsearchIndexLocale } from '@island.is/content-search-index-manager'
import { SystemMetadata } from '@island.is/shared/types'
import { CacheField } from '@island.is/nest/graphql'
import { IGenericList, IGenericListFields } from '../generated/contentfulTypes'
import { GenericListItemResponse } from './genericListItemResponse.model'
import { GetGenericListItemsInput } from '../dto/getGenericListItems.input'
import { GenericTag, mapGenericTag } from './genericTag.model'

enum GenericListItemType {
NonClickable = 'NonClickable',
Expand All @@ -20,14 +18,14 @@ export class GenericList {
@Field(() => ID)
id!: string

@CacheField(() => GenericListItemResponse)
firstPageListItemResponse!: GetGenericListItemsInput

@Field(() => String, { nullable: true })
searchInputPlaceholder?: string

@CacheField(() => GenericListItemType, { nullable: true })
itemType?: GenericListItemType

@CacheField(() => [GenericTag], { nullable: true })
filterTags?: GenericTag[]
}

const mapItemType = (itemType?: IGenericListFields['itemType']) =>
Expand All @@ -41,12 +39,7 @@ export const mapGenericList = ({
}: IGenericList): SystemMetadata<GenericList> => ({
typename: 'GenericList',
id: sys.id,
firstPageListItemResponse: {
genericListId: sys.id,
lang:
sys.locale === 'is-IS' ? 'is' : (sys.locale as ElasticsearchIndexLocale),
page: 1,
},
searchInputPlaceholder: fields.searchInputPlaceholder,
itemType: mapItemType(fields.itemType),
filterTags: fields.filterTags ? fields.filterTags.map(mapGenericTag) : [],
})
5 changes: 5 additions & 0 deletions libs/cms/src/lib/models/genericListItem.model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Field, ID, ObjectType } from '@nestjs/graphql'
import { SliceUnion, mapDocument } from '../unions/slice.union'
import { GenericList, mapGenericList } from './genericList.model'
import { IGenericListItem } from '../generated/contentfulTypes'
import { GenericTag, mapGenericTag } from './genericTag.model'

@ObjectType()
export class GenericListItem {
Expand All @@ -26,6 +27,9 @@ export class GenericListItem {

@Field(() => String, { nullable: true })
slug?: string

@CacheField(() => [GenericTag], { nullable: true })
filterTags?: GenericTag[]
}

export const mapGenericListItem = ({
Expand All @@ -45,4 +49,5 @@ export const mapGenericListItem = ({
? mapDocument(fields.content, `${sys.id}:content`)
: [],
slug: fields.slug,
filterTags: fields.filterTags ? fields.filterTags.map(mapGenericTag) : [],
})
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,11 @@ export class GenericListItemSyncService
2,
)

const tags: MappedData['tags'] = []
const tags: MappedData['tags'] =
mapped.filterTags?.map((tag) => ({
type: 'genericTag',
key: tag.slug,
})) ?? []
RunarVestmann marked this conversation as resolved.
Show resolved Hide resolved

if (mapped.genericList) {
tags.push({
Expand Down
Loading