diff --git a/package-lock.json b/package-lock.json index 4351cdd1d00..d6a9cb51a46 100644 --- a/package-lock.json +++ b/package-lock.json @@ -22659,9 +22659,10 @@ }, "node_modules/cz-lerna-changelog/node_modules/npm/node_modules/lodash._baseindexof": { "version": "3.1.0", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/cz-lerna-changelog/node_modules/npm/node_modules/lodash._baseuniq": { "version": "4.6.0", @@ -22676,21 +22677,24 @@ }, "node_modules/cz-lerna-changelog/node_modules/npm/node_modules/lodash._bindcallback": { "version": "3.0.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/cz-lerna-changelog/node_modules/npm/node_modules/lodash._cacheindexof": { "version": "3.0.2", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/cz-lerna-changelog/node_modules/npm/node_modules/lodash._createcache": { "version": "3.1.2", - "extraneous": true, + "dev": true, "inBundle": true, "license": "MIT", + "peer": true, "dependencies": { "lodash._getnative": "^3.0.0" } @@ -22704,9 +22708,10 @@ }, "node_modules/cz-lerna-changelog/node_modules/npm/node_modules/lodash._getnative": { "version": "3.9.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/cz-lerna-changelog/node_modules/npm/node_modules/lodash._root": { "version": "3.0.1", @@ -22724,9 +22729,10 @@ }, "node_modules/cz-lerna-changelog/node_modules/npm/node_modules/lodash.restparam": { "version": "3.6.1", - "extraneous": true, + "dev": true, "inBundle": true, - "license": "MIT" + "license": "MIT", + "peer": true }, "node_modules/cz-lerna-changelog/node_modules/npm/node_modules/lodash.union": { "version": "4.6.0", @@ -64981,7 +64987,7 @@ }, "packages/common": { "name": "@esri/hub-common", - "version": "14.30.0", + "version": "14.35.0", "license": "Apache-2.0", "dependencies": { "abab": "^2.0.5", @@ -65007,7 +65013,7 @@ }, "packages/discussions": { "name": "@esri/hub-discussions", - "version": "26.1.0", + "version": "26.1.1", "license": "Apache-2.0", "dependencies": { "tslib": "^1.13.0" @@ -83401,7 +83407,8 @@ "lodash._baseindexof": { "version": "3.1.0", "bundled": true, - "extraneous": true + "dev": true, + "peer": true }, "lodash._baseuniq": { "version": "4.6.0", @@ -83416,17 +83423,20 @@ "lodash._bindcallback": { "version": "3.0.1", "bundled": true, - "extraneous": true + "dev": true, + "peer": true }, "lodash._cacheindexof": { "version": "3.0.2", "bundled": true, - "extraneous": true + "dev": true, + "peer": true }, "lodash._createcache": { "version": "3.1.2", "bundled": true, - "extraneous": true, + "dev": true, + "peer": true, "requires": { "lodash._getnative": "^3.0.0" } @@ -83440,7 +83450,8 @@ "lodash._getnative": { "version": "3.9.1", "bundled": true, - "extraneous": true + "dev": true, + "peer": true }, "lodash._root": { "version": "3.0.1", @@ -83457,7 +83468,8 @@ "lodash.restparam": { "version": "3.6.1", "bundled": true, - "extraneous": true + "dev": true, + "peer": true }, "lodash.union": { "version": "4.6.0", diff --git a/packages/common/src/core/schemas/internal/getEntityEditorSchemas.ts b/packages/common/src/core/schemas/internal/getEntityEditorSchemas.ts index 3d9c771f7d5..5e2952451d2 100644 --- a/packages/common/src/core/schemas/internal/getEntityEditorSchemas.ts +++ b/packages/common/src/core/schemas/internal/getEntityEditorSchemas.ts @@ -63,6 +63,8 @@ export async function getEntityEditorSchemas( import("../../../sites/_internal/SiteUiSchemaFollowers"), "hub:site:discussions": () => import("../../../sites/_internal/SiteUiSchemaDiscussions"), + "hub:site:settings": () => + import("../../../sites/_internal/SiteUiSchemaSettings"), }[type as SiteEditorType](); uiSchema = await siteModule.buildUiSchema( i18nScope, diff --git a/packages/common/src/core/schemas/shared/subschemas.ts b/packages/common/src/core/schemas/shared/subschemas.ts index f329e38d9cb..c9285adc03e 100644 --- a/packages/common/src/core/schemas/shared/subschemas.ts +++ b/packages/common/src/core/schemas/shared/subschemas.ts @@ -100,3 +100,12 @@ export const ENTITY_TIMELINE_SCHEMA = { }, }, }; + +export const PRIVACY_CONFIG_SCHEMA = { + type: "object", + properties: { + consentNotice: { + type: "object", + }, + }, +}; diff --git a/packages/common/src/sites/_internal/SiteSchema.ts b/packages/common/src/sites/_internal/SiteSchema.ts index 782ebb2f0fd..8f54eb9d8c1 100644 --- a/packages/common/src/sites/_internal/SiteSchema.ts +++ b/packages/common/src/sites/_internal/SiteSchema.ts @@ -1,5 +1,8 @@ import { IConfigurationSchema } from "../../core"; -import { ENTITY_IS_DISCUSSABLE_SCHEMA } from "../../core/schemas/shared"; +import { + ENTITY_IS_DISCUSSABLE_SCHEMA, + PRIVACY_CONFIG_SCHEMA, +} from "../../core/schemas/shared"; import { HubItemEntitySchema } from "../../core/schemas/shared/HubItemEntitySchema"; export type SiteEditorType = (typeof SiteEditorTypes)[number]; @@ -8,6 +11,7 @@ export const SiteEditorTypes = [ "hub:site:create", "hub:site:followers", "hub:site:discussions", + "hub:site:settings", ] as const; /** @@ -18,5 +22,6 @@ export const SiteSchema: IConfigurationSchema = { properties: { ...HubItemEntitySchema.properties, _discussions: ENTITY_IS_DISCUSSABLE_SCHEMA, + telemetry: PRIVACY_CONFIG_SCHEMA, }, } as IConfigurationSchema; diff --git a/packages/common/src/sites/_internal/SiteUiSchemaSettings.ts b/packages/common/src/sites/_internal/SiteUiSchemaSettings.ts new file mode 100644 index 00000000000..304e3e279f9 --- /dev/null +++ b/packages/common/src/sites/_internal/SiteUiSchemaSettings.ts @@ -0,0 +1,33 @@ +import { IHubSite } from "../../core/types"; +import { IArcGISContext } from "../../ArcGISContext"; +import { IUiSchema } from "../../core/schemas/types"; + +/** + * @private + * constructs the edit uiSchema for Hub Sites. + * This defines how the schema properties should + * be rendered in the site editing experience + */ +export const buildUiSchema = async ( + i18nScope: string, + entity: IHubSite, + context: IArcGISContext +): Promise => { + return { + type: "Layout", + elements: [ + { + type: "Section", + elements: [ + { + scope: "/properties/telemetry/properties/consentNotice", + type: "Control", + options: { + control: "arcgis-privacy-config", + }, + }, + ], + }, + ], + }; +}; diff --git a/packages/common/src/sites/_internal/_migrate-telemetry-config.ts b/packages/common/src/sites/_internal/_migrate-telemetry-config.ts new file mode 100644 index 00000000000..a2a24372a18 --- /dev/null +++ b/packages/common/src/sites/_internal/_migrate-telemetry-config.ts @@ -0,0 +1,59 @@ +import { getProp, setProp } from "../../objects"; +import { IModel, IDraft } from "../../types"; +import { cloneObject } from "../../util"; + +/** + * Reconfigure event list card properties + * @private + * @param {object} model Site Model + * @returns {object} + */ +export function _migrateTelemetryConfig( + model: T +): T { + const newSchemaVersion = 1.7; + // do nothing if migration already applied + if (getProp(model, "item.properties.schemaVersion") >= newSchemaVersion) { + return model; + } + + // apply migration + const clone = cloneObject(model); + + clone.data.telemetry = {}; + // get allowPrivacyConfig from consentNotice capability + const capabilities = getProp(model, "data.values.capabilities") || []; + const allowPrivacyConfig = capabilities.includes("consentNotice"); + + // migrate consentNotice + clone.data.telemetry.consentNotice = { + allowPrivacyConfig, + disclaimer: [ + { + text: + getProp(model, "data.values.telemetry.consentNotice.consentText") || + "", + default: true, + }, + ], + policyURL: + getProp(model, "data.values.telemetry.consentNotice.policyURL") || "", + }; + + // this doesn't actually have any effect - not sure we have a way to get rid of stuff + // delete clone.data?.values?.telemetry; + + // if we have item.properties.telemetry.plugins, move it to data.telemetry + const plugins = getProp(model, "item.properties.telemetry.plugins"); + if (plugins) { + clone.data.telemetry.plugins = plugins; + + // this doesn't actually have any effect - not sure we have a way to get rid of stuff + // delete clone.item?.properties?.telemetry; + } + + // increment schemaVersion + setProp("item.properties.schemaVersion", newSchemaVersion, clone); + + return clone; +} diff --git a/packages/common/src/sites/_internal/getPropertyMap.ts b/packages/common/src/sites/_internal/getPropertyMap.ts index c3f05fe51bb..0158f778be3 100644 --- a/packages/common/src/sites/_internal/getPropertyMap.ts +++ b/packages/common/src/sites/_internal/getPropertyMap.ts @@ -24,7 +24,6 @@ export function getPropertyMap(): IPropertyMap[] { "clientId", "defaultExtent", "map", - "telemetry", "headerSass", "headContent", "layout", @@ -67,5 +66,11 @@ export function getPropertyMap(): IPropertyMap[] { entityKey: "features", storeKey: "data.settings.features", }); + + map.push({ + entityKey: "telemetry", + storeKey: "data.telemetry", + }); + return map; } diff --git a/packages/common/src/sites/index.ts b/packages/common/src/sites/index.ts index 01cebb60214..b244a8657ea 100644 --- a/packages/common/src/sites/index.ts +++ b/packages/common/src/sites/index.ts @@ -1,6 +1,7 @@ export * from "./_internal/_ensure-telemetry"; export * from "./_internal/_migrate-feed-config"; export * from "./_internal/_migrate-event-list-card-configs"; +export * from "./_internal/_migrate-telemetry-config"; export * from "./domains"; export * from "./drafts"; export * from "./fetchSiteModel"; diff --git a/packages/common/src/sites/site-schema-version.ts b/packages/common/src/sites/site-schema-version.ts index 8215ba649f2..7d29f6dcf56 100644 --- a/packages/common/src/sites/site-schema-version.ts +++ b/packages/common/src/sites/site-schema-version.ts @@ -1 +1 @@ -export const SITE_SCHEMA_VERSION = 1.6; +export const SITE_SCHEMA_VERSION = 1.7; diff --git a/packages/common/src/sites/upgrade-site-schema.ts b/packages/common/src/sites/upgrade-site-schema.ts index 684440138de..dae0eccd4ef 100644 --- a/packages/common/src/sites/upgrade-site-schema.ts +++ b/packages/common/src/sites/upgrade-site-schema.ts @@ -9,6 +9,7 @@ import { _ensureTelemetry } from "./_internal/_ensure-telemetry"; import { _migrateFeedConfig } from "./_internal/_migrate-feed-config"; import { _migrateEventListCardConfigs } from "./_internal/_migrate-event-list-card-configs"; import { migrateLegacyCapabilitiesToFeatures } from "./_internal/capabilities/migrateLegacyCapabilitiesToFeatures"; +import { _migrateTelemetryConfig } from "./_internal/_migrate-telemetry-config"; /** * Upgrades the schema upgrades @@ -27,6 +28,7 @@ export function upgradeSiteSchema(model: IModel) { model = _migrateFeedConfig(model); model = _migrateEventListCardConfigs(model); model = migrateLegacyCapabilitiesToFeatures(model); + model = _migrateTelemetryConfig(model); // WARNING - If you are writing a site schema migration, // you probably need to apply it to site drafts as well! diff --git a/packages/common/test/core/schemas/internal/getEntityEditorSchemas.test.ts b/packages/common/test/core/schemas/internal/getEntityEditorSchemas.test.ts index dd92c8a7270..4e8c8084250 100644 --- a/packages/common/test/core/schemas/internal/getEntityEditorSchemas.test.ts +++ b/packages/common/test/core/schemas/internal/getEntityEditorSchemas.test.ts @@ -14,6 +14,7 @@ import * as SiteBuildEditUiSchema from "../../../../src/sites/_internal/SiteUiSc import * as SiteBuildCreateUiSchema from "../../../../src/sites/_internal/SiteUiSchemaCreate"; import * as SiteBuildFollowersUiSchema from "../../../../src/sites/_internal/SiteUiSchemaFollowers"; import * as SiteBuildDiscussionsUiSchema from "../../../../src/sites/_internal/SiteUiSchemaDiscussions"; +import * as SiteBuildTelemetryUiSchema from "../../../../src/sites/_internal/SiteUiSchemaSettings"; import { DiscussionEditorTypes } from "../../../../src/discussions/_internal/DiscussionSchema"; import * as DiscussionBuildEditUiSchema from "../../../../src/discussions/_internal/DiscussionUiSchemaEdit"; @@ -53,6 +54,7 @@ describe("getEntityEditorSchemas: ", () => { { type: SiteEditorTypes[1], buildFn: SiteBuildCreateUiSchema }, { type: SiteEditorTypes[2], buildFn: SiteBuildFollowersUiSchema }, { type: SiteEditorTypes[3], buildFn: SiteBuildDiscussionsUiSchema }, + { type: SiteEditorTypes[4], buildFn: SiteBuildTelemetryUiSchema }, { type: DiscussionEditorTypes[0], buildFn: DiscussionBuildEditUiSchema }, { type: DiscussionEditorTypes[1], buildFn: DiscussionBuildCreateUiSchema }, { diff --git a/packages/common/test/sites/_internal/SiteuUiSchemaTelemetry.test.ts b/packages/common/test/sites/_internal/SiteuUiSchemaTelemetry.test.ts new file mode 100644 index 00000000000..b834904c94e --- /dev/null +++ b/packages/common/test/sites/_internal/SiteuUiSchemaTelemetry.test.ts @@ -0,0 +1,25 @@ +import { buildUiSchema } from "../../../src/sites/_internal/SiteUiSchemaSettings"; +import { MOCK_CONTEXT } from "../../mocks/mock-auth"; + +describe("buildUiSchema: site telemetry", () => { + it("returns the full site telemetry uiSchema", async () => { + const uiSchema = await buildUiSchema("some.scope", {} as any, MOCK_CONTEXT); + expect(uiSchema).toEqual({ + type: "Layout", + elements: [ + { + type: "Section", + elements: [ + { + scope: "/properties/telemetry/properties/consentNotice", + type: "Control", + options: { + control: "arcgis-privacy-config", + }, + }, + ], + }, + ], + }); + }); +}); diff --git a/packages/common/test/sites/_internal/_migrate-telemetry-config.test.ts b/packages/common/test/sites/_internal/_migrate-telemetry-config.test.ts new file mode 100644 index 00000000000..03d4c8358bf --- /dev/null +++ b/packages/common/test/sites/_internal/_migrate-telemetry-config.test.ts @@ -0,0 +1,85 @@ +import { IModel } from "../../../src"; +import { _migrateTelemetryConfig } from "../../../src/sites/_internal/_migrate-telemetry-config"; + +describe("_migrateTelemetryConfig", () => { + it("Bumps the item.properties.schemaVersion if schemaVersion is < 1.7", () => { + const siteModel = { + item: { properties: { schemaVersion: 1.6 } }, + data: { values: {} }, + } as unknown as IModel; + const result = _migrateTelemetryConfig(siteModel); + expect(result.item.properties.schemaVersion).toEqual( + 1.7, + "site.item.properties.schemaVersion should be 1.7" + ); + }); + + it("Does not run the migration if schemaVersion is >= 1.7", () => { + const siteModel = { + item: { + properties: { + schemaVersion: 1.7, + }, + }, + } as unknown as IModel; + + const result = _migrateTelemetryConfig(siteModel); + expect(result).toEqual(siteModel, "The site object should be unchanged."); + }); + + it("should apply migration if schemaVersion < newSchemaVersion", () => { + const model = { + item: { properties: { schemaVersion: 1.6 } }, + data: { + values: { + capabilities: ["consentNotice"], + telemetry: { consentNotice: { consentText: "some text" } }, + }, + }, + }; + const result = _migrateTelemetryConfig(model); + expect(result.item.properties.schemaVersion).toEqual(1.7); + expect( + (result.data as any).telemetry.consentNotice.allowPrivacyConfig + ).toEqual(true); + expect( + (result.data as any).telemetry.consentNotice.disclaimer[0].text + ).toEqual("some text"); + }); + + it("should move plugins to data.telemetry if it exists", () => { + const model = { + item: { + properties: { + schemaVersion: 1, + telemetry: { plugins: ["plugin1", "plugin2"] }, + }, + }, + data: { + values: { + capabilities: ["consentNotice"], + telemetry: { consentNotice: { consentText: "some text" } }, + }, + }, + }; + const result = _migrateTelemetryConfig(model); + expect((result.data as any).telemetry.plugins).toEqual([ + "plugin1", + "plugin2", + ]); + }); + + it("should not move plugins to data.telemetry if it does not exist", () => { + const model = { + item: { properties: { schemaVersion: 1 } }, + data: { + values: { + capabilities: ["consentNotice"], + telemetry: { consentNotice: { consentText: "some text" } }, + }, + }, + }; + const result = _migrateTelemetryConfig(model); + expect((result.data as any).telemetry.plugins).toBeUndefined(); + }); +}); diff --git a/packages/common/test/sites/upgrade-site-schema.test.ts b/packages/common/test/sites/upgrade-site-schema.test.ts index 07491eb54cd..e022b68de60 100644 --- a/packages/common/test/sites/upgrade-site-schema.test.ts +++ b/packages/common/test/sites/upgrade-site-schema.test.ts @@ -7,6 +7,7 @@ import * as _ensureTelemetryModule from "../../src/sites/_internal/_ensure-telem import * as _migrateFeedConfigModule from "../../src/sites/_internal/_migrate-feed-config"; import * as _migrateEventListCardConfigs from "../../src/sites/_internal/_migrate-event-list-card-configs"; import * as migrateLegacyCapabilitiesToFeatures from "../../src/sites/_internal/capabilities/migrateLegacyCapabilitiesToFeatures"; +import * as _migrateTelemetryConfig from "../../src/sites/_internal/_migrate-telemetry-config"; import { IModel } from "../../src"; import { SITE_SCHEMA_VERSION } from "../../src/sites/site-schema-version"; import { expectAllCalled, expectAll } from "./test-helpers.test"; @@ -20,6 +21,7 @@ describe("upgradeSiteSchema", () => { let migrateFeedConfigSpy: jasmine.Spy; let migrateEventListCardConfigsSpy: jasmine.Spy; let migrateLegacyCapabilitiesToFeaturesSpy: jasmine.Spy; + let migrateTelemetryConfigSpy: jasmine.Spy; beforeEach(() => { applySpy = spyOn(_applySiteSchemaModule, "_applySiteSchema").and.callFake( (model: IModel) => model @@ -52,6 +54,10 @@ describe("upgradeSiteSchema", () => { migrateLegacyCapabilitiesToFeatures, "migrateLegacyCapabilitiesToFeatures" ).and.callFake((model: IModel) => model); + migrateTelemetryConfigSpy = spyOn( + _migrateTelemetryConfig, + "_migrateTelemetryConfig" + ).and.callFake((model: IModel) => model); }); it("runs schema upgrades", async () => { @@ -75,6 +81,7 @@ describe("upgradeSiteSchema", () => { migrateFeedConfigSpy, migrateEventListCardConfigsSpy, migrateLegacyCapabilitiesToFeaturesSpy, + migrateTelemetryConfigSpy, ], expect ); diff --git a/packages/sites/src/drafts/upgrade-draft-schema.ts b/packages/sites/src/drafts/upgrade-draft-schema.ts index 97fa7f384c5..2b33f55dead 100644 --- a/packages/sites/src/drafts/upgrade-draft-schema.ts +++ b/packages/sites/src/drafts/upgrade-draft-schema.ts @@ -4,6 +4,7 @@ import { _ensureTelemetry, _migrateFeedConfig, _migrateEventListCardConfigs, + _migrateTelemetryConfig, } from "@esri/hub-common"; const schemaVersionPath = "item.properties.schemaVersion"; @@ -28,6 +29,7 @@ export function upgradeDraftSchema(draft: IDraft) { migrated = _ensureTelemetry(draft); migrated = _migrateFeedConfig(draft); migrated = _migrateEventListCardConfigs(draft); + migrated = _migrateTelemetryConfig(draft); return migrated; } } diff --git a/packages/sites/test/drafts/upgrade-draft-schema.test.ts b/packages/sites/test/drafts/upgrade-draft-schema.test.ts index f403e9999c9..331a7aa429c 100644 --- a/packages/sites/test/drafts/upgrade-draft-schema.test.ts +++ b/packages/sites/test/drafts/upgrade-draft-schema.test.ts @@ -9,6 +9,7 @@ describe("upgradeDraftSchema", () => { let ensureTelemetrySpy: jasmine.Spy; let migrateFeedConfigSpy: jasmine.Spy; let migrateEventListCardConfigsSpy: jasmine.Spy; + let migrateTelemetryConfigSpy: jasmine.Spy; beforeEach(() => { ensureTelemetrySpy = spyOn(commonModule, "_ensureTelemetry").and.callFake( (model: IModel) => model @@ -21,6 +22,10 @@ describe("upgradeDraftSchema", () => { commonModule, "_migrateEventListCardConfigs" ).and.callFake((model: IModel) => model); + migrateTelemetryConfigSpy = spyOn( + commonModule, + "_migrateTelemetryConfig" + ).and.callFake((model: IModel) => model); }); it("runs schema upgrades when schema out of date", async () => { @@ -39,6 +44,7 @@ describe("upgradeDraftSchema", () => { ensureTelemetrySpy, migrateFeedConfigSpy, migrateEventListCardConfigsSpy, + migrateTelemetryConfigSpy, ], expect ); @@ -58,6 +64,7 @@ describe("upgradeDraftSchema", () => { ensureTelemetrySpy, migrateFeedConfigSpy, migrateEventListCardConfigsSpy, + migrateTelemetryConfigSpy, ], expect ); @@ -79,6 +86,7 @@ describe("upgradeDraftSchema", () => { ensureTelemetrySpy, migrateFeedConfigSpy, migrateEventListCardConfigsSpy, + migrateTelemetryConfigSpy, ], expect ); @@ -100,6 +108,7 @@ describe("upgradeDraftSchema", () => { ensureTelemetrySpy, migrateFeedConfigSpy, migrateEventListCardConfigsSpy, + migrateTelemetryConfigSpy, ], "toHaveBeenCalled", false,