From efd3e0fd2bafd7e77ca192b5a9f54c460cbd8f79 Mon Sep 17 00:00:00 2001 From: Sean Perkins <13732623+sean-perkins@users.noreply.github.com> Date: Mon, 20 Jan 2025 15:15:02 -0600 Subject: [PATCH 1/2] feat(config): add logLevel option to suppress ionic warnings and errors (#30015) resolves #29814 --------- - Developers can assign a value to `logLevel` in the Ionic config to control the log level that Ionic Framework will produce logs for. - `OFF` will completely disable all warnings and errors from Ionic - `WARN` will log warnings and errors - `ERROR` will log only errors - Default behavior is that developers receive both Ionic warnings and errors - Configuration only applies to usages of `printIonWarning` and `printIonError` --------- Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com> --- core/src/utils/config.ts | 10 ++ core/src/utils/logging/index.ts | 22 +++- core/src/utils/logging/test/logging.spec.ts | 114 ++++++++++++++++++++ 3 files changed, 142 insertions(+), 4 deletions(-) create mode 100644 core/src/utils/logging/test/logging.spec.ts diff --git a/core/src/utils/config.ts b/core/src/utils/config.ts index e38d43beb4..6b66417f7f 100644 --- a/core/src/utils/config.ts +++ b/core/src/utils/config.ts @@ -2,6 +2,7 @@ import type { SpinnerTypes } from '../components/spinner/spinner-configs'; import type { TabButtonLayout } from '../components/tab-bar/tab-bar-interface'; import type { AnimationBuilder, Mode } from '../interface'; +import type { LogLevel } from './logging'; import type { PlatformConfig } from './platform'; export interface IonicConfig { @@ -220,6 +221,15 @@ export interface IonicConfig { */ experimentalCloseWatcher?: boolean; + /** + * Configures the logging level for Ionic Framework: + * + * - `'OFF'`: No errors or warnings are logged. + * - `'ERROR'`: Logs only errors. + * - `'WARN'`: Logs errors and warnings. + */ + logLevel?: LogLevel; + // PRIVATE configs keyboardHeight?: number; inputShims?: boolean; diff --git a/core/src/utils/logging/index.ts b/core/src/utils/logging/index.ts index ee4234cb6a..4bf58ce629 100644 --- a/core/src/utils/logging/index.ts +++ b/core/src/utils/logging/index.ts @@ -1,3 +1,11 @@ +import { config } from '@global/config'; + +export const enum LogLevel { + OFF = 'OFF', + ERROR = 'ERROR', + WARN = 'WARN', +} + /** * Logs a warning to the console with an Ionic prefix * to indicate the library that is warning the developer. @@ -5,18 +13,24 @@ * @param message - The string message to be logged to the console. */ export const printIonWarning = (message: string, ...params: any[]) => { - return console.warn(`[Ionic Warning]: ${message}`, ...params); + const logLevel = config.get('logLevel', LogLevel.WARN); + if ([LogLevel.WARN].includes(logLevel)) { + return console.warn(`[Ionic Warning]: ${message}`, ...params); + } }; -/* +/** * Logs an error to the console with an Ionic prefix * to indicate the library that is warning the developer. * * @param message - The string message to be logged to the console. * @param params - Additional arguments to supply to the console.error. */ -export const printIonError = (message: string, ...params: any) => { - return console.error(`[Ionic Error]: ${message}`, ...params); +export const printIonError = (message: string, ...params: any[]) => { + const logLevel = config.get('logLevel', LogLevel.ERROR); + if ([LogLevel.ERROR, LogLevel.WARN].includes(logLevel)) { + return console.error(`[Ionic Error]: ${message}`, ...params); + } }; /** diff --git a/core/src/utils/logging/test/logging.spec.ts b/core/src/utils/logging/test/logging.spec.ts new file mode 100644 index 0000000000..e0f1bdcb92 --- /dev/null +++ b/core/src/utils/logging/test/logging.spec.ts @@ -0,0 +1,114 @@ +import { config } from '@global/config'; +import { LogLevel } from '../index'; + +import { printIonError, printIonWarning } from '../index'; + +describe('Logging', () => { + describe('#printIonWarning', () => { + let consoleWarnSpy: jest.SpyInstance; + + beforeEach(() => { + consoleWarnSpy = jest.spyOn(console, 'warn'); + // Suppress console.warn output from polluting the test output + consoleWarnSpy.mockImplementation(() => {}); + }); + + afterEach(() => { + consoleWarnSpy.mockRestore(); + }); + + describe('when the logLevel configuration is not set', () => { + it('logs a warning to the console', () => { + config.set('logLevel', undefined); + + printIonWarning('This is a warning message'); + + expect(consoleWarnSpy).toHaveBeenCalledWith('[Ionic Warning]: This is a warning message'); + }); + }); + + describe("when the logLevel configuration is set to 'WARN'", () => { + it('logs a warning to the console', () => { + config.set('logLevel', LogLevel.WARN); + + printIonWarning('This is a warning message'); + + expect(consoleWarnSpy).toHaveBeenCalledWith('[Ionic Warning]: This is a warning message'); + }); + }); + + describe("when the logLevel configuration is set to 'ERROR'", () => { + it('does not log a warning to the console', () => { + config.set('logLevel', LogLevel.ERROR); + + printIonWarning('This is a warning message'); + + expect(consoleWarnSpy).not.toHaveBeenCalled(); + }); + }); + + describe("when the logLevel configuration is set to 'OFF'", () => { + it('does not log a warning to the console', () => { + config.set('logLevel', LogLevel.OFF); + + printIonWarning('This is a warning message'); + + expect(consoleWarnSpy).not.toHaveBeenCalled(); + }); + }); + }); + + describe('#printIonError', () => { + let consoleErrorSpy: jest.SpyInstance; + + beforeEach(() => { + consoleErrorSpy = jest.spyOn(console, 'error'); + // Suppress console.error output from polluting the test output + consoleErrorSpy.mockImplementation(() => {}); + }); + + afterEach(() => { + consoleErrorSpy.mockRestore(); + }); + + describe('when the logLevel configuration is not set', () => { + it('logs an error to the console', () => { + config.set('logLevel', undefined); + + printIonError('This is an error message'); + + expect(consoleErrorSpy).toHaveBeenCalledWith('[Ionic Error]: This is an error message'); + }); + }); + + describe("when the logLevel configuration is set to 'ERROR'", () => { + it('logs an error to the console', () => { + config.set('logLevel', LogLevel.ERROR); + + printIonError('This is an error message'); + + expect(consoleErrorSpy).toHaveBeenCalledWith('[Ionic Error]: This is an error message'); + }); + }); + + describe("when the logLevel configuration is set to 'WARN'", () => { + it('logs an error to the console', () => { + config.set('logLevel', LogLevel.WARN); + + printIonError('This is an error message'); + + expect(consoleErrorSpy).toHaveBeenCalledWith('[Ionic Error]: This is an error message'); + }); + }); + + describe("when the logLevel configuration is set to 'OFF'", () => { + it('does not log an error to the console', () => { + config.set('logLevel', LogLevel.OFF); + + printIonError('This is an error message'); + + expect(consoleErrorSpy).not.toHaveBeenCalled(); + }); + }); + }); +}); From ac4ea3232b1ccffa1c31dc4c6c416e16848ff607 Mon Sep 17 00:00:00 2001 From: fudom <143608856+fudom@users.noreply.github.com> Date: Thu, 23 Jan 2025 21:48:58 +0100 Subject: [PATCH 2/2] feat(toolbar): add shadow parts for background, container, and content (#30069) Resolves #30068 --------- Add `part` attributes to toolbar for the `background`, `container` and `content`. --- core/api.txt | 5 ++++- core/src/components/toolbar/toolbar.tsx | 10 +++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/core/api.txt b/core/api.txt index 67d4941755..6679bd89aa 100644 --- a/core/api.txt +++ b/core/api.txt @@ -2000,4 +2000,7 @@ ion-toolbar,css-prop,--padding-end,md ion-toolbar,css-prop,--padding-start,ios ion-toolbar,css-prop,--padding-start,md ion-toolbar,css-prop,--padding-top,ios -ion-toolbar,css-prop,--padding-top,md \ No newline at end of file +ion-toolbar,css-prop,--padding-top,md +ion-toolbar,part,background +ion-toolbar,part,container +ion-toolbar,part,content \ No newline at end of file diff --git a/core/src/components/toolbar/toolbar.tsx b/core/src/components/toolbar/toolbar.tsx index 0999d40427..d742953d9a 100644 --- a/core/src/components/toolbar/toolbar.tsx +++ b/core/src/components/toolbar/toolbar.tsx @@ -13,6 +13,10 @@ import type { Color, CssClassMap, StyleEventDetail } from '../../interface'; * @slot secondary - Content is placed to the left of the toolbar text in `ios` mode, and directly to the right in `md` mode. * @slot primary - Content is placed to the right of the toolbar text in `ios` mode, and to the far right in `md` mode. * @slot end - Content is placed to the right of the toolbar text in LTR, and to the left in RTL. + * + * @part background - The background of the toolbar, covering the entire area behind the toolbar content. + * @part container - The container that wraps all toolbar content, including the default slot and named slot content. + * @part content - The container for the default slot, wrapping content provided without a named slot. */ @Component({ tag: 'ion-toolbar', @@ -97,11 +101,11 @@ export class Toolbar implements ComponentInterface { }), }} > -
-