Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions l10n/en.js
Original file line number Diff line number Diff line change
Expand Up @@ -508,8 +508,6 @@ OC.L10N.register(
"Organisation or new status is missing": "Organisation or new status is missing",
"An error occurred while changing the status": "An error occurred while changing the status",
"Search": "Search",
"Search applications and services…": "Search applications and services…",
"Clear search": "Clear search",
"Saved views": "Saved views",
"Save current filters as view": "Save current filters as view",
"GEMMA filters": "GEMMA filters",
Expand Down
2 changes: 0 additions & 2 deletions l10n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -507,8 +507,6 @@
"Organisation or new status is missing": "Organisation or new status is missing",
"An error occurred while changing the status": "An error occurred while changing the status",
"Search": "Search",
"Search applications and services…": "Search applications and services…",
"Clear search": "Clear search",
"Saved views": "Saved views",
"Save current filters as view": "Save current filters as view",
"GEMMA filters": "GEMMA filters",
Expand Down
2 changes: 0 additions & 2 deletions l10n/nl.js
Original file line number Diff line number Diff line change
Expand Up @@ -545,8 +545,6 @@ OC.L10N.register(
"Group members": "Groepsleden",
"Merge organisations": "Organisaties samenvoegen",
"Search": "Zoeken",
"Search applications and services…": "Zoek applicaties en diensten…",
"Clear search": "Zoekopdracht wissen",
"Saved views": "Opgeslagen weergaven",
"Save current filters as view": "Huidige filters opslaan als weergave",
"GEMMA filters": "GEMMA-filters",
Expand Down
2 changes: 0 additions & 2 deletions l10n/nl.json
Original file line number Diff line number Diff line change
Expand Up @@ -544,8 +544,6 @@
"Group members": "Groepsleden",
"Merge organisations": "Organisaties samenvoegen",
"Search": "Zoeken",
"Search applications and services…": "Zoek applicaties en diensten…",
"Clear search": "Zoekopdracht wissen",
"Saved views": "Opgeslagen weergaven",
"Save current filters as view": "Huidige filters opslaan als weergave",
"GEMMA filters": "GEMMA-filters",
Expand Down
2 changes: 1 addition & 1 deletion openspec/specs/gemma-faceted-search/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,7 +137,7 @@ The module (`Applications`) and dienst (`Services`) `CnIndexPage`-based index pa
- GIVEN a user navigates to the module index page
- WHEN the page renders
- THEN a facet filter panel MUST be visible showing all four GEMMA dimensions
- AND the existing free-text search box and any `quickFilters` MUST continue to render and function unchanged
- AND the free-text search (the Search tab of the page's Search and columns sidebar, sent by the list as `_search`) and any `quickFilters` MUST continue to render and function

#### Scenario: Selecting a facet value updates the object list without a full page reload

Expand Down
4 changes: 3 additions & 1 deletion src/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -616,12 +616,13 @@
"type": "custom",
"title": "Applications",
"component": "FacetedCatalogIndexView",
"_note": "Faceted index page (gemma-faceted-search): CnFacetSidebar (live GEMMA-dimension counts from FacetService) + a standalone CnIndexPage narrowed via { _ids: matchedObjectIds } (OpenRegister's list parameter; the objects endpoint ignores a plain id filter). Columns are objects: `provider` is a reference, so it renders through the fkResolve cell widget (uuid → organisation name) and carries its own label — object-typed properties get no schema-generated column, so a bare key showed the raw uuid under the header 'provider'. Stays custom rather than type:index — see customComponents.js's FacetedCatalogIndexView entry for why CnIndexPage's own embedded facet sidebar cannot drive this narrowing. bio-compliance-assessment: bbnLevel/dpiaStatus columns + BBN/DPIA quickFilters reconciled onto this page after gemma-faceted-search (#382) merged — see FacetedCatalogIndexView.vue's quickFilters prop docblock for how the quick filter's field constraints compose with the facet { _ids: ... } narrowing (disjoint keys, additive AND, no clobber).",
"_note": "Faceted index page (gemma-faceted-search): CnFacetSidebar (live GEMMA-dimension counts from FacetService) + a standalone CnIndexPage narrowed via { _ids: matchedObjectIds } (OpenRegister's list parameter; the objects endpoint ignores a plain id filter). Columns are objects: `provider` is a reference, so it renders through the fkResolve cell widget (uuid → organisation name) and carries its own label — object-typed properties get no schema-generated column, so a bare key showed the raw uuid under the header 'provider'. Stays custom rather than type:index — see customComponents.js's FacetedCatalogIndexView entry for why CnIndexPage's own embedded facet sidebar cannot drive this narrowing. bio-compliance-assessment: bbnLevel/dpiaStatus columns + BBN/DPIA quickFilters reconciled onto this page after gemma-faceted-search (#382) merged — see FacetedCatalogIndexView.vue's quickFilters prop docblock for how the quick filter's field constraints compose with the facet { _ids: ... } narrowing (disjoint keys, additive AND, no clobber). config.sidebar gives the page the Search and Columns sidebar of the other index pages; its search is the page's free-text search, sent by the list itself as _search, so only a GEMMA facet selection narrows by _ids (a search narrowed by _ids put every match in the URL and failed with HTTP 414 from about 170 matches).",
"config": {
"register": "@resolve:voorzieningen_register",
"schema": "module",
"detailRoute": "ModuleDetail",
"description": "Browse the application (module) catalogue, filtered by GEMMA architecture dimension.",
"sidebar": { "enabled": true, "showMetadata": true },
"columns": [
{ "key": "name", "label": "Name" },
{ "key": "provider", "label": "Supplier", "widget": "fkResolve", "widgetProps": { "register": "@resolve:voorzieningen_register", "schema": "organization", "labelField": "name" } },
Expand Down Expand Up @@ -677,6 +678,7 @@
"register": "@resolve:voorzieningen_register",
"schema": "catalogService",
"description": "Browse the service (dienst) catalogue, filtered by GEMMA architecture dimension.",
"sidebar": { "enabled": true, "showMetadata": true },
"columns": [
"name",
"provider",
Expand Down
30 changes: 30 additions & 0 deletions src/utils/facetNarrowing.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,33 @@ export function facetNarrowingFilter(ids) {
: []
return { _ids: list.length > 0 ? list : [FACET_NO_MATCH_SENTINEL] }
}

/**
* Whether any GEMMA facet dimension has a selected value.
*
* @param {object} activeFilters The facet store's `{ dimension: [values] }` map.
* @return {boolean} True when at least one dimension has a value.
* @spec openspec/specs/gemma-faceted-search/spec.md#requirement-facets-combine-with-free-text-search
*/
export function hasFacetSelection(activeFilters) {
return Object.values(activeFilters ?? {}).some(
(values) => Array.isArray(values) && values.length > 0,
)
}

/**
* The `CnIndexPage` `filter` prop of a faceted list.
*
* Only a GEMMA facet selection narrows by id. A free-text search alone goes
* through the list's own `_search`, which OpenRegister pages server side:
* narrowing it by the matched ids put every match in the URL, and from about
* 170 matches the request line was too long (HTTP 414) and the list failed.
*
* @param {object} activeFilters The facet store's `{ dimension: [values] }` map.
* @param {Array<string>} ids The `_meta.matchedObjectIds` of the last facets response.
* @return {object} `{}` without a facet selection, else `{ _ids: [...] }`.
* @spec openspec/specs/gemma-faceted-search/spec.md#requirement-facets-combine-with-free-text-search
*/
export function listNarrowingFilter(activeFilters, ids) {
return hasFacetSelection(activeFilters) ? facetNarrowingFilter(ids) : {}
}
26 changes: 26 additions & 0 deletions src/utils/facetNarrowing.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
import {
FACET_NO_MATCH_SENTINEL,
facetNarrowingFilter,
hasFacetSelection,
listNarrowingFilter,
} from '../../src/utils/facetNarrowing.js'

describe('facetNarrowingFilter', () => {
Expand All @@ -30,3 +32,27 @@ describe('facetNarrowingFilter', () => {
})
})
})

describe('listNarrowingFilter', () => {
it("does not narrow by id without a facet selection, so a search stays on the list's own _search", () => {
const many = Array.from({ length: 1200 }, (_, i) => `id-${i}`)
expect(listNarrowingFilter({}, many)).toEqual({})
expect(listNarrowingFilter({ domain: [] }, many)).toEqual({})
expect(listNarrowingFilter(undefined, many)).toEqual({})
})

it('narrows by the matched ids once a facet dimension has a value', () => {
expect(listNarrowingFilter({ domain: ['Burgerzaken'] }, ['a1'])).toEqual({
_ids: ['a1'],
})
expect(listNarrowingFilter({ standard: ['StUF'] }, [])).toEqual({
_ids: [FACET_NO_MATCH_SENTINEL],
})
})

it('tells a selection from an empty dimension', () => {
expect(hasFacetSelection({ domain: [], standard: ['StUF'] })).toBe(true)
expect(hasFacetSelection({ domain: [] })).toBe(false)
expect(hasFacetSelection(null)).toBe(false)
})
})
Loading
Loading