diff --git a/change/@itwin-property-grid-react-5e8f999c-021a-422a-9a20-37213d3f8f5c.json b/change/@itwin-property-grid-react-5e8f999c-021a-422a-9a20-37213d3f8f5c.json new file mode 100644 index 000000000..e15c523c0 --- /dev/null +++ b/change/@itwin-property-grid-react-5e8f999c-021a-422a-9a20-37213d3f8f5c.json @@ -0,0 +1,7 @@ +{ + "type": "patch", + "comment": "Downgrade missing `IModelApp.userPreferences` log from error to warning and deduplicate", + "packageName": "@itwin/property-grid-react", + "email": "AzureDevOps@users.noreply.github.com", + "dependentChangeType": "patch" +} diff --git a/packages/itwin/property-grid/src/property-grid-react/api/PreferencesStorage.ts b/packages/itwin/property-grid/src/property-grid-react/api/PreferencesStorage.ts index dec6ef0d3..da7803594 100644 --- a/packages/itwin/property-grid/src/property-grid-react/api/PreferencesStorage.ts +++ b/packages/itwin/property-grid/src/property-grid-react/api/PreferencesStorage.ts @@ -25,13 +25,14 @@ export interface PreferencesStorage { */ export class IModelAppUserPreferencesStorage implements PreferencesStorage { #nameSpace = PROPERTY_GRID_NAMESPACE; + #warnedAboutMissingPreferences = false; constructor(nameSpace = PROPERTY_GRID_NAMESPACE) { this.#nameSpace = nameSpace; } public async set(key: string, value: string): Promise { if (!IModelApp.userPreferences) { - Logger.logError(LOGGER_CATEGORY, `Cannot save user preference ${key} because 'IModelApp.userPreferences' not defined.`); + this.logMissingPreferencesWarning(key, "save"); return; } @@ -51,7 +52,7 @@ export class IModelAppUserPreferencesStorage implements PreferencesStorage { public async get(key: string): Promise { if (!IModelApp.userPreferences) { - Logger.logError(LOGGER_CATEGORY, `Cannot get persisted user preference ${key} because 'IModelApp.userPreferences' not defined.`); + this.logMissingPreferencesWarning(key, "get"); return undefined; } @@ -68,4 +69,13 @@ export class IModelAppUserPreferencesStorage implements PreferencesStorage { } return undefined; } + + private logMissingPreferencesWarning(key: string, action: "save" | "get") { + if (this.#warnedAboutMissingPreferences) { + return; + } + const subject = action === "get" ? "persisted user preference" : "user preference"; + Logger.logWarning(LOGGER_CATEGORY, `Cannot ${action} ${subject} ${key} because 'IModelApp.userPreferences' not defined.`); + this.#warnedAboutMissingPreferences = true; + } } diff --git a/packages/itwin/property-grid/src/test/api/PreferencesStorage.test.ts b/packages/itwin/property-grid/src/test/api/PreferencesStorage.test.ts index 012359ad4..4c9b01713 100644 --- a/packages/itwin/property-grid/src/test/api/PreferencesStorage.test.ts +++ b/packages/itwin/property-grid/src/test/api/PreferencesStorage.test.ts @@ -18,19 +18,22 @@ describe("IModelAppUserPreferencesStorage", () => { }; let userPreferencesStub: ReturnType; - let loggerStub: ReturnType; + let logErrorStub: ReturnType; + let logWarningStub: ReturnType; let storage: IModelAppUserPreferencesStorage; beforeEach(() => { userPreferencesStub = vi.spyOn(IModelApp, "userPreferences", "get"); - loggerStub = vi.spyOn(Logger, "logError"); + logErrorStub = vi.spyOn(Logger, "logError"); + logWarningStub = vi.spyOn(Logger, "logWarning"); userPreferencesStub.mockReturnValue(imodelUserPreferences); storage = new IModelAppUserPreferencesStorage(); }); afterEach(() => { userPreferencesStub.mockReset(); - loggerStub.mockReset(); + logErrorStub.mockReset(); + logWarningStub.mockReset(); imodelUserPreferences.get.mockReset(); imodelUserPreferences.save.mockReset(); }); @@ -46,14 +49,22 @@ describe("IModelAppUserPreferencesStorage", () => { throw new Error("Invalid Key"); }); await storage.set("test-key", "test-value"); - expect(loggerStub).toHaveBeenCalledWith("PropertyGrid", expect.stringContaining("Invalid Key")); + expect(logErrorStub).toHaveBeenCalledWith("PropertyGrid", expect.stringContaining("Invalid Key")); }); - it("logs error if `IModelApp.userPreferences` not defined", async () => { + it("logs warning if `IModelApp.userPreferences` not defined", async () => { userPreferencesStub.mockReset(); userPreferencesStub.mockReturnValue(undefined); await storage.set("test-key", "test-value"); - expect(loggerStub).toHaveBeenCalledWith("PropertyGrid", expect.stringContaining("'IModelApp.userPreferences' not defined")); + expect(logWarningStub).toHaveBeenCalledWith("PropertyGrid", expect.stringContaining("'IModelApp.userPreferences' not defined")); + }); + + it("logs warning only once if `IModelApp.userPreferences` not defined", async () => { + userPreferencesStub.mockReset(); + userPreferencesStub.mockReturnValue(undefined); + await storage.set("test-key", "test-value"); + await storage.set("test-key-2", "test-value-2"); + expect(logWarningStub).toHaveBeenCalledTimes(1); }); }); @@ -68,14 +79,22 @@ describe("IModelAppUserPreferencesStorage", () => { throw new Error("Invalid Key"); }); await storage.get("test-key"); - expect(loggerStub).toHaveBeenCalledWith("PropertyGrid", expect.stringContaining("Invalid Key")); + expect(logErrorStub).toHaveBeenCalledWith("PropertyGrid", expect.stringContaining("Invalid Key")); }); - it("logs error if `IModelApp.userPreferences` not defined", async () => { + it("logs warning if `IModelApp.userPreferences` not defined", async () => { userPreferencesStub.mockReset(); userPreferencesStub.mockReturnValue(undefined); expect(await storage.get("test-key")).toBeUndefined(); - expect(loggerStub).toHaveBeenCalledWith("PropertyGrid", expect.stringContaining("'IModelApp.userPreferences' not defined")); + expect(logWarningStub).toHaveBeenCalledWith("PropertyGrid", expect.stringContaining("'IModelApp.userPreferences' not defined")); + }); + + it("logs warning only once if `IModelApp.userPreferences` not defined", async () => { + userPreferencesStub.mockReset(); + userPreferencesStub.mockReturnValue(undefined); + await storage.get("test-key"); + await storage.get("test-key-2"); + expect(logWarningStub).toHaveBeenCalledTimes(1); }); }); });