From 8a786bfc6af9381465a4c7a53df52790c70d4fad Mon Sep 17 00:00:00 2001 From: Caleb Pomar Date: Thu, 6 Mar 2025 10:18:01 -0700 Subject: [PATCH 1/3] fix(hub-common): fix issue where site catalog collections were not populating the display config has affects: @esri/hub-common --- .../common/src/search/types/IHubCatalog.ts | 11 ----- .../applyDefaultCollectionMigration.ts | 11 +++-- .../reflectCollectionsToSearchCategories.ts | 7 ++- packages/common/test/sites/HubSites.test.ts | 8 ++-- .../applyDefaultCollectionMigration.test.ts | 26 +++++------ ...flectCollectionsToSearchCategories.test.ts | 44 ++++++++++++------- 6 files changed, 57 insertions(+), 50 deletions(-) diff --git a/packages/common/src/search/types/IHubCatalog.ts b/packages/common/src/search/types/IHubCatalog.ts index 99ea93c9724..56553b0c794 100644 --- a/packages/common/src/search/types/IHubCatalog.ts +++ b/packages/common/src/search/types/IHubCatalog.ts @@ -101,17 +101,6 @@ export const targetEntities = [ ] as const; export type EntityType = (typeof targetEntities)[number]; -/** - * @private - * - * This interface wraps IHubCollection and provides additional fields - * for collection configuration. It is the actual interface used when - * when storing an entity's catalog collections. - */ -export interface IHubCollectionPersistance extends IHubCollection { - hidden?: boolean; -} - /** * IQuery is the fundamental unit used to execute a search. By composing * `Filter`'s and `IPredicate`s, we can express very complex queries diff --git a/packages/common/src/sites/_internal/applyDefaultCollectionMigration.ts b/packages/common/src/sites/_internal/applyDefaultCollectionMigration.ts index 39faa7d5845..8c37667d6aa 100644 --- a/packages/common/src/sites/_internal/applyDefaultCollectionMigration.ts +++ b/packages/common/src/sites/_internal/applyDefaultCollectionMigration.ts @@ -1,5 +1,5 @@ import { getWithDefault } from "../../objects"; -import { IHubCollectionPersistance } from "../../search/types/IHubCatalog"; +import { IHubCollection } from "../../search/types/IHubCatalog"; import { WellKnownCollection } from "../../search/wellKnownCatalog"; import { IModel } from "../../hub-types"; import { SearchCategories } from "./types"; @@ -21,7 +21,7 @@ import { defaultSiteCollectionKeys } from "../defaultSiteCollectionKeys"; * NOTE: The changes made in this migration will not be persisted to AGO at this time * * @param model site model to migrate - * @returns a migrated model with default `IHubCollectionPersistance` objects added + * @returns a migrated model with default `IHubCollection` objects added * to the catalog */ export function applyDefaultCollectionMigration(model: IModel): IModel { @@ -44,9 +44,12 @@ export function applyDefaultCollectionMigration(model: IModel): IModel { collection: key, filters: [], }, + displayConfig: { + hidden: false, + }, }; return map; - }, {} as Record); + }, {} as Record); const searchCategoryToCollection: Partial< Record > = { @@ -86,7 +89,7 @@ export function applyDefaultCollectionMigration(model: IModel): IModel { searchCategoryToCollection[searchCategory.key as SearchCategories]; const collection = baseCollectionMap[collectionKey]; collection.label = searchCategory.overrideText || null; - collection.hidden = searchCategory.hidden; + collection.displayConfig.hidden = searchCategory.hidden; return collection; }); diff --git a/packages/common/src/sites/_internal/reflectCollectionsToSearchCategories.ts b/packages/common/src/sites/_internal/reflectCollectionsToSearchCategories.ts index 42807cd3a37..549b3442873 100644 --- a/packages/common/src/sites/_internal/reflectCollectionsToSearchCategories.ts +++ b/packages/common/src/sites/_internal/reflectCollectionsToSearchCategories.ts @@ -1,5 +1,5 @@ import { WellKnownCollection } from "../../search"; -import { IHubCollectionPersistance } from "../../search/types/IHubCatalog"; +import { IHubCollection } from "../../search/types/IHubCatalog"; import { IModel } from "../../hub-types"; import { cloneObject } from "../../util"; import { SearchCategories } from "./types"; @@ -35,8 +35,7 @@ export function reflectCollectionsToSearchCategories(model: IModel) { [SearchCategories.APPS_AND_MAPS]: "App,Map", [SearchCategories.DOCUMENTS]: "Document", }; - const collections: IHubCollectionPersistance[] = - clone.data.catalog.collections; + const collections: IHubCollection[] = clone.data.catalog.collections; const updatedSearchCategories = collections // We don't want to persist any non-standard collection as a search category, @@ -46,7 +45,7 @@ export function reflectCollectionsToSearchCategories(model: IModel) { const searchCategoryKey = collectionToSearchCategory[c.key as WellKnownCollection]; const updated: any = { - hidden: c.hidden, + hidden: c.displayConfig?.hidden, key: searchCategoryKey, queryParams: { collection: searchCategoryToQueryParam[searchCategoryKey], diff --git a/packages/common/test/sites/HubSites.test.ts b/packages/common/test/sites/HubSites.test.ts index dcd048bfc98..8fd62e33c2a 100644 --- a/packages/common/test/sites/HubSites.test.ts +++ b/packages/common/test/sites/HubSites.test.ts @@ -11,7 +11,7 @@ import { cloneObject, enrichSiteSearchResult, fetchSite, - IHubCollectionPersistance, + IHubCollection, IHubRequestOptions, } from "../../src"; import * as slugUtils from "../../src/items/slugs"; @@ -477,13 +477,15 @@ describe("HubSites:", () => { label: "My Datasets", key: "dataset", targetEntity: "item", - hidden: true, scope: { targetEntity: "item", collection: "dataset", filters: [], }, - } as IHubCollectionPersistance, + displayConfig: { + hidden: true, + }, + } as IHubCollection, ]; const chk = await commonModule.updateSite(updatedSite, MOCK_HUB_REQOPTS); diff --git a/packages/common/test/sites/_internal/applyDefaultCollectionMigration.test.ts b/packages/common/test/sites/_internal/applyDefaultCollectionMigration.test.ts index 78d64211007..92a85c62e49 100644 --- a/packages/common/test/sites/_internal/applyDefaultCollectionMigration.test.ts +++ b/packages/common/test/sites/_internal/applyDefaultCollectionMigration.test.ts @@ -1,4 +1,4 @@ -import { IHubCollectionPersistance } from "../../../src/search/types/IHubCatalog"; +import { IHubCollection } from "../../../src/search/types/IHubCatalog"; import { applyDefaultCollectionMigration } from "../../../src/sites/_internal/applyDefaultCollectionMigration"; import { SearchCategories } from "../../../src/sites/_internal/types"; import { IModel } from "../../../src/hub-types"; @@ -31,7 +31,7 @@ describe("applyDefaultCollectionMigration", () => { it("Adds untouched default collections when no search categories are configured", () => { const result = applyDefaultCollectionMigration(site); const collectionKeys = result.data.catalog.collections.map( - (c: IHubCollectionPersistance) => c.key + (c: IHubCollection) => c.key ); expect(collectionKeys).toEqual([ "all", @@ -41,11 +41,11 @@ describe("applyDefaultCollectionMigration", () => { "appAndMap", ]); const collectionLabels = result.data.catalog.collections.map( - (c: IHubCollectionPersistance) => c.label + (c: IHubCollection) => c.label ); expect(collectionLabels).toEqual([null, null, null, null, null]); const hiddenStatuses = result.data.catalog.collections.map( - (c: IHubCollectionPersistance) => c.hidden + (c: IHubCollection) => c.displayConfig?.hidden ); expect(hiddenStatuses).toEqual([ undefined, @@ -78,7 +78,7 @@ describe("applyDefaultCollectionMigration", () => { ]; const result = applyDefaultCollectionMigration(site); const collectionKeys = result.data.catalog.collections.map( - (c: IHubCollectionPersistance) => c.key + (c: IHubCollection) => c.key ); // Note: 'all' collection is always prepended expect(collectionKeys).toEqual([ @@ -90,12 +90,12 @@ describe("applyDefaultCollectionMigration", () => { ]); const collectionLabels = result.data.catalog.collections.map( - (c: IHubCollectionPersistance) => c.label + (c: IHubCollection) => c.label ); expect(collectionLabels).toEqual([null, null, null, "My Sites", "My Data"]); const hiddenStatuses = result.data.catalog.collections.map( - (c: IHubCollectionPersistance) => c.hidden + (c: IHubCollection) => c.displayConfig.hidden ); expect(hiddenStatuses).toEqual([undefined, undefined, true, false, false]); }); @@ -110,18 +110,18 @@ describe("applyDefaultCollectionMigration", () => { ]; const result = applyDefaultCollectionMigration(site); const collectionKeys = result.data.catalog.collections.map( - (c: IHubCollectionPersistance) => c.key + (c: IHubCollection) => c.key ); // Note: 'all' collection is always prepended expect(collectionKeys).toEqual(["all", "site"]); const collectionLabels = result.data.catalog.collections.map( - (c: IHubCollectionPersistance) => c.label + (c: IHubCollection) => c.label ); expect(collectionLabels).toEqual([null, "My Initiatives"]); const hiddenStatuses = result.data.catalog.collections.map( - (c: IHubCollectionPersistance) => c.hidden + (c: IHubCollection) => c.displayConfig.hidden ); expect(hiddenStatuses).toEqual([undefined, true]); }); @@ -139,18 +139,18 @@ describe("applyDefaultCollectionMigration", () => { ]; const result = applyDefaultCollectionMigration(site); const collectionKeys = result.data.catalog.collections.map( - (c: IHubCollectionPersistance) => c.key + (c: IHubCollection) => c.key ); // Note: 'all' collection can never be relabeled, hidden, or reordered expect(collectionKeys).toEqual(["all"]); const collectionLabels = result.data.catalog.collections.map( - (c: IHubCollectionPersistance) => c.label + (c: IHubCollection) => c.label ); expect(collectionLabels).toEqual([null]); const hiddenStatuses = result.data.catalog.collections.map( - (c: IHubCollectionPersistance) => c.hidden + (c: IHubCollection) => c.displayConfig.hidden ); expect(hiddenStatuses).toEqual([undefined]); }); diff --git a/packages/common/test/sites/_internal/reflectCollectionsToSearchCategories.test.ts b/packages/common/test/sites/_internal/reflectCollectionsToSearchCategories.test.ts index 97c867bf385..5c0480c634f 100644 --- a/packages/common/test/sites/_internal/reflectCollectionsToSearchCategories.test.ts +++ b/packages/common/test/sites/_internal/reflectCollectionsToSearchCategories.test.ts @@ -1,4 +1,4 @@ -import { IHubCollectionPersistance } from "../../../src/search/types/IHubCatalog"; +import { IHubCollection } from "../../../src/search/types/IHubCatalog"; import { WellKnownCollection } from "../../../src/search/wellKnownCatalog"; import { reflectCollectionsToSearchCategories } from "../../../src/sites/_internal/reflectCollectionsToSearchCategories"; import { SearchCategories } from "../../../src/sites/_internal/types"; @@ -33,24 +33,28 @@ describe("reflectCollectionsToSearchCategories", () => { label: null, key: "dataset", targetEntity: "item", - hidden: true, scope: { targetEntity: "item", collection: "dataset", filters: [], }, - } as IHubCollectionPersistance, + displayConfig: { + hidden: true, + }, + } as IHubCollection, { label: null, key: "document", targetEntity: "item", - hidden: false, + displayConfig: { + hidden: false, + }, scope: { targetEntity: "item", collection: "document", filters: [], }, - } as IHubCollectionPersistance, + } as IHubCollection, ]; const result = reflectCollectionsToSearchCategories(site); @@ -77,24 +81,28 @@ describe("reflectCollectionsToSearchCategories", () => { label: "My Cool Sites!", key: "site", targetEntity: "item", - hidden: false, + displayConfig: { + hidden: false, + }, scope: { targetEntity: "item", collection: "site", filters: [], }, - } as IHubCollectionPersistance, + } as IHubCollection, { label: "Apps & Maps", key: "appAndMap", targetEntity: "item", - hidden: false, + displayConfig: { + hidden: false, + }, scope: { targetEntity: "item", collection: "appAndMap", filters: [], }, - } as IHubCollectionPersistance, + } as IHubCollection, ]; const result = reflectCollectionsToSearchCategories(site); @@ -124,36 +132,42 @@ describe("reflectCollectionsToSearchCategories", () => { label: null, key: "dataset", targetEntity: "item", - hidden: false, + displayConfig: { + hidden: false, + }, scope: { targetEntity: "item", collection: "dataset", filters: [], }, - } as IHubCollectionPersistance, + } as IHubCollection, // 'all' _can_ be converted to a search category, but we explicitly do not persist it { label: null, key: "all", targetEntity: "item", - hidden: false, + displayConfig: { + hidden: false, + }, scope: { targetEntity: "item", collection: "all" as WellKnownCollection, filters: [], }, - } as IHubCollectionPersistance, + } as IHubCollection, // Customer-defined collection, cannot be converted to search category { label: "My Custom Collection", key: "custom-collection", targetEntity: "event", - hidden: false, + displayConfig: { + hidden: false, + }, scope: { targetEntity: "event", filters: [], }, - } as IHubCollectionPersistance, + } as IHubCollection, ]; const result = reflectCollectionsToSearchCategories(site); From 444db219c25dd83e1ff437361885b8097eb0865c Mon Sep 17 00:00:00 2001 From: Aaron Putterman <60486980+abp6318@users.noreply.github.com> Date: Thu, 6 Mar 2025 13:46:58 -0500 Subject: [PATCH 2/3] fix: tets --- package-lock.json | 2 +- .../reflectCollectionsToSearchCategories.ts | 2 +- ...eflectCollectionsToSearchCategories.test.ts | 18 ++++++++++++++++++ ....ts => get-catalog-from-site-model.test.ts} | 10 +++++----- 4 files changed, 25 insertions(+), 7 deletions(-) rename packages/common/test/sites/{get-catalog-from-site-model.ts => get-catalog-from-site-model.test.ts} (80%) diff --git a/package-lock.json b/package-lock.json index 9d91054773b..cea607d263f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65003,7 +65003,7 @@ }, "packages/common": { "name": "@esri/hub-common", - "version": "15.38.1", + "version": "15.41.0", "license": "Apache-2.0", "dependencies": { "@terraformer/arcgis": "^2.1.2", diff --git a/packages/common/src/sites/_internal/reflectCollectionsToSearchCategories.ts b/packages/common/src/sites/_internal/reflectCollectionsToSearchCategories.ts index 549b3442873..734adc9115e 100644 --- a/packages/common/src/sites/_internal/reflectCollectionsToSearchCategories.ts +++ b/packages/common/src/sites/_internal/reflectCollectionsToSearchCategories.ts @@ -45,7 +45,7 @@ export function reflectCollectionsToSearchCategories(model: IModel) { const searchCategoryKey = collectionToSearchCategory[c.key as WellKnownCollection]; const updated: any = { - hidden: c.displayConfig?.hidden, + hidden: !!c.displayConfig?.hidden, key: searchCategoryKey, queryParams: { collection: searchCategoryToQueryParam[searchCategoryKey], diff --git a/packages/common/test/sites/_internal/reflectCollectionsToSearchCategories.test.ts b/packages/common/test/sites/_internal/reflectCollectionsToSearchCategories.test.ts index 5c0480c634f..989d586855b 100644 --- a/packages/common/test/sites/_internal/reflectCollectionsToSearchCategories.test.ts +++ b/packages/common/test/sites/_internal/reflectCollectionsToSearchCategories.test.ts @@ -55,6 +55,17 @@ describe("reflectCollectionsToSearchCategories", () => { filters: [], }, } as IHubCollection, + { + label: null, + key: "appAndMap", + targetEntity: "item", + // intentionally leaving out displayConfig.hidden for branch coverage + scope: { + targetEntity: "item", + collection: "appAndMap", + filters: [], + }, + } as IHubCollection, ]; const result = reflectCollectionsToSearchCategories(site); @@ -73,6 +84,13 @@ describe("reflectCollectionsToSearchCategories", () => { collection: "Document", }, }, + { + key: SearchCategories.APPS_AND_MAPS, + hidden: false, + queryParams: { + collection: "App,Map", + }, + }, ]); }); it("handles re-labeled collections", () => { diff --git a/packages/common/test/sites/get-catalog-from-site-model.ts b/packages/common/test/sites/get-catalog-from-site-model.test.ts similarity index 80% rename from packages/common/test/sites/get-catalog-from-site-model.ts rename to packages/common/test/sites/get-catalog-from-site-model.test.ts index 640dc2cc44d..a6e64315815 100644 --- a/packages/common/test/sites/get-catalog-from-site-model.ts +++ b/packages/common/test/sites/get-catalog-from-site-model.test.ts @@ -15,19 +15,19 @@ describe("getCatalogFromSiteModel", () => { expect(chk.title).toBe("Default Site Catalog"); expect(chk.scopes).toBeDefined(); - expect(chk.scopes?.item?.filters.length).toBe(1); - expect(chk.scopes?.item?.filters[0].predicates[0].group).toEqual([ + expect(chk.scopes.item.filters.length).toBe(1); + expect(chk.scopes.item.filters[0].predicates[0].group).toEqual([ "00c", "00d", ]); - expect(chk.scopes?.event?.filters.length).toBe(1); - expect(chk.scopes?.event?.filters[0].predicates[0].group).toEqual([ + expect(chk.scopes.event.filters.length).toBe(1); + expect(chk.scopes.event.filters[0].predicates[0].group).toEqual([ "00c", "00d", ]); // check for collections - expect(chk.collections?.map((c) => c.key)).toEqual([ + expect(chk.collections.map((c) => c.key)).toEqual([ "all", "site", "dataset", From 947f3e75cc380c83c99e30dbf0666d7f901bfb0f Mon Sep 17 00:00:00 2001 From: Aaron Putterman <60486980+abp6318@users.noreply.github.com> Date: Thu, 6 Mar 2025 14:17:41 -0500 Subject: [PATCH 3/3] fix: more tests --- .../_internal/applyDefaultCollectionMigration.ts | 2 +- .../applyDefaultCollectionMigration.test.ts | 14 ++++---------- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/packages/common/src/sites/_internal/applyDefaultCollectionMigration.ts b/packages/common/src/sites/_internal/applyDefaultCollectionMigration.ts index 8c37667d6aa..eb4b6242a01 100644 --- a/packages/common/src/sites/_internal/applyDefaultCollectionMigration.ts +++ b/packages/common/src/sites/_internal/applyDefaultCollectionMigration.ts @@ -89,7 +89,7 @@ export function applyDefaultCollectionMigration(model: IModel): IModel { searchCategoryToCollection[searchCategory.key as SearchCategories]; const collection = baseCollectionMap[collectionKey]; collection.label = searchCategory.overrideText || null; - collection.displayConfig.hidden = searchCategory.hidden; + collection.displayConfig.hidden = !!searchCategory.hidden; return collection; }); diff --git a/packages/common/test/sites/_internal/applyDefaultCollectionMigration.test.ts b/packages/common/test/sites/_internal/applyDefaultCollectionMigration.test.ts index 92a85c62e49..1368fab7ae0 100644 --- a/packages/common/test/sites/_internal/applyDefaultCollectionMigration.test.ts +++ b/packages/common/test/sites/_internal/applyDefaultCollectionMigration.test.ts @@ -47,13 +47,7 @@ describe("applyDefaultCollectionMigration", () => { const hiddenStatuses = result.data.catalog.collections.map( (c: IHubCollection) => c.displayConfig?.hidden ); - expect(hiddenStatuses).toEqual([ - undefined, - true, - undefined, - undefined, - undefined, - ]); + expect(hiddenStatuses).toEqual([false, true, false, false, false]); }); it("Reorders, re-labels, and hides default collections when search categories are configured", () => { @@ -97,7 +91,7 @@ describe("applyDefaultCollectionMigration", () => { const hiddenStatuses = result.data.catalog.collections.map( (c: IHubCollection) => c.displayConfig.hidden ); - expect(hiddenStatuses).toEqual([undefined, undefined, true, false, false]); + expect(hiddenStatuses).toEqual([false, false, true, false, false]); }); it("Handles when a site has the 'initiatives' search category saved", () => { @@ -123,7 +117,7 @@ describe("applyDefaultCollectionMigration", () => { const hiddenStatuses = result.data.catalog.collections.map( (c: IHubCollection) => c.displayConfig.hidden ); - expect(hiddenStatuses).toEqual([undefined, true]); + expect(hiddenStatuses).toEqual([false, true]); }); it("Omits unsupported search categories, like an explicit 'all' or events", () => { @@ -152,6 +146,6 @@ describe("applyDefaultCollectionMigration", () => { const hiddenStatuses = result.data.catalog.collections.map( (c: IHubCollection) => c.displayConfig.hidden ); - expect(hiddenStatuses).toEqual([undefined]); + expect(hiddenStatuses).toEqual([false]); }); });