From ca7c150316a657e75bd978488c5e68c135352a08 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Jun 2026 07:32:58 +0000 Subject: [PATCH 1/5] Initial plan From 98add2b93131abdf63969b6735d7a82e44cef4b8 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Jun 2026 07:51:03 +0000 Subject: [PATCH 2/5] fix: change useNullValueStorage log from error to warning, logged only once When `IModelApp.userPreferences` is not defined, the `IModelAppUserPreferencesStorage` now logs a warning instead of an error, and only logs it once per storage instance to avoid log spam. Closes #1714 --- .../api/PreferencesStorage.ts | 12 +++++- .../src/test/api/PreferencesStorage.test.ts | 37 ++++++++++++++----- 2 files changed, 38 insertions(+), 11 deletions(-) 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..dd13decb0 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,11 @@ export class IModelAppUserPreferencesStorage implements PreferencesStorage { } return undefined; } + + private logMissingPreferencesWarning(key: string, action: string) { + if (!this.#warnedAboutMissingPreferences) { + Logger.logWarning(LOGGER_CATEGORY, `Cannot ${action} persisted user preference ${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); }); }); }); From 46f996ff12c012c7d319a0512b38fa09133d4209 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 12 Jun 2026 07:57:17 +0000 Subject: [PATCH 3/5] Add beachball change file for property-grid-react patch --- ...ty-grid-react-5e8f999c-021a-422a-9a20-37213d3f8f5c.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 change/@itwin-property-grid-react-5e8f999c-021a-422a-9a20-37213d3f8f5c.json 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" +} From a7eb36689756abcb0d85c83518d7055ddfd4b533 Mon Sep 17 00:00:00 2001 From: Grigas <35135765+grigasp@users.noreply.github.com> Date: Fri, 12 Jun 2026 11:02:17 +0300 Subject: [PATCH 4/5] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- .../src/property-grid-react/api/PreferencesStorage.ts | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) 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 dd13decb0..b26b8bb80 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 @@ -70,10 +70,11 @@ export class IModelAppUserPreferencesStorage implements PreferencesStorage { return undefined; } - private logMissingPreferencesWarning(key: string, action: string) { - if (!this.#warnedAboutMissingPreferences) { - Logger.logWarning(LOGGER_CATEGORY, `Cannot ${action} persisted user preference ${key} because 'IModelApp.userPreferences' not defined.`); - this.#warnedAboutMissingPreferences = true; - } + 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; } } From 269a0d4cbce231bb0e4297af88eb9e6d79886840 Mon Sep 17 00:00:00 2001 From: JonasDov <100586436+JonasDov@users.noreply.github.com> Date: Fri, 12 Jun 2026 11:09:32 +0300 Subject: [PATCH 5/5] Update packages/itwin/property-grid/src/property-grid-react/api/PreferencesStorage.ts --- .../src/property-grid-react/api/PreferencesStorage.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) 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 b26b8bb80..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 @@ -71,8 +71,9 @@ export class IModelAppUserPreferencesStorage implements PreferencesStorage { } private logMissingPreferencesWarning(key: string, action: "save" | "get") { - if (this.#warnedAboutMissingPreferences) + 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;