-
Notifications
You must be signed in to change notification settings - Fork 528
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: widget registry service & types
- Loading branch information
1 parent
817902d
commit eb104fc
Showing
4 changed files
with
220 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export * from './widget-registry.service'; | ||
export * from './widget-registry.types'; |
96 changes: 96 additions & 0 deletions
96
packages/ui-core/core/src/lib/services/widget/widget-registry.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { Injectable } from '@angular/core'; | ||
import { IWidgetRegistry, WidgetPageLocationId, WidgetRegistryConfig } from './widget-registry.types'; | ||
|
||
@Injectable({ | ||
providedIn: 'root' | ||
}) | ||
export class WidgetRegistryService implements IWidgetRegistry { | ||
/** | ||
* @description | ||
* Registry for storing page widget configurations. | ||
* | ||
* This Map stores arrays of WidgetRegistryConfig objects, keyed by WidgetPageLocationId. | ||
*/ | ||
private readonly registry = new Map<WidgetPageLocationId, WidgetRegistryConfig[]>(); | ||
|
||
/** | ||
* Retrieves the current widget registry. | ||
* | ||
* This method returns a map of widget configurations, organized by their page locations. | ||
* | ||
* @returns A `Map` where each key is a `WidgetPageLocationId` and each value is an array of | ||
* `WidgetRegistryConfig` objects associated with that page location. | ||
*/ | ||
public getRegistry(): ReadonlyMap<WidgetPageLocationId, WidgetRegistryConfig[]> { | ||
return new Map(this.registry); // Return a new Map to ensure immutability | ||
} | ||
|
||
/** | ||
* Registers a single widget with the service. | ||
* | ||
* This method is responsible for registering a widget by adding its configuration | ||
* to the widget registry. It ensures that the widget configuration includes the | ||
* necessary properties (`widgetId` and `location`) before proceeding to add it | ||
* to the registry. If any of these properties are missing, it throws an error. | ||
* | ||
* @param config - The configuration object for the widget to be registered. | ||
* @throws Error - Throws an error if the `widgetId` or `location` properties are missing. | ||
*/ | ||
public registerWidget(config: WidgetRegistryConfig): void { | ||
// Ensure the widget configuration includes a location. | ||
if (!config.location) { | ||
throw new Error('A widget configuration must have a location property'); | ||
} | ||
|
||
// Ensure the widget configuration includes a unique identifier. | ||
if (!config.widgetId) { | ||
throw new Error('A widget configuration must have a widgetId property'); | ||
} | ||
|
||
// Retrieve the existing widgets for the specified location from the registry, | ||
// or initialize an empty array if none exist. | ||
const widgets = this.registry.get(config.location) || []; | ||
|
||
// Check if a route with the same location and path already exists | ||
const isMatchingWidget = widgets.some( | ||
(widget: WidgetRegistryConfig) => widget.location === config.location && widget.widgetId === config.widgetId | ||
); | ||
|
||
// Check if a route with the same location already exists | ||
if (isMatchingWidget) { | ||
throw new Error(`Widget with id "${config.widgetId}" already exists at location "${config.location}"`); | ||
} | ||
|
||
// Add the new widget configuration to the list of widgets for the specified location | ||
widgets.push(config); | ||
|
||
// Update the registry with the new or updated list of widgets for the specified location. | ||
this.registry.set(config.location, widgets); | ||
} | ||
|
||
/** | ||
* Registers multiple widgets with the service. | ||
* | ||
* This method adds multiple widget configurations to the registry. It processes each | ||
* configuration sequentially by calling `registerWidget` for each one. | ||
* | ||
* @param configs An array of configuration objects for the widgets to be registered. Each | ||
* object in the array should follow the `WidgetRegistryConfig` schema. | ||
* @throws Error if any widget ID is missing or if any widget ID already exists. | ||
*/ | ||
public registerWidgets(configs: WidgetRegistryConfig[]): void { | ||
configs.forEach((config: WidgetRegistryConfig) => this.registerWidget(config)); | ||
} | ||
|
||
/** | ||
* Retrieves the widgets registered at a specific location. | ||
* | ||
* @param location - The location for which to retrieve the widgets. | ||
* | ||
* @returns An array of `WidgetRegistryConfig` objects registered at the specified location. | ||
* If no widgets are registered at the location, an empty array is returned. | ||
*/ | ||
getLocationWidgets(location: WidgetPageLocationId): WidgetRegistryConfig[] { | ||
return this.registry.get(location) || []; | ||
} | ||
} |
121 changes: 121 additions & 0 deletions
121
packages/ui-core/core/src/lib/services/widget/widget-registry.types.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,121 @@ | ||
import { Type } from '@angular/core'; | ||
import { ResolveFn } from '@angular/router'; | ||
import { PermissionsEnum } from '@gauzy/contracts'; | ||
|
||
/** | ||
* The width of a widget in terms of grid columns. | ||
*/ | ||
export type WidgetGridWidth = 3 | 4 | 6 | 8 | 12; | ||
|
||
/** | ||
* Enum representing the possible widget page locations. | ||
* | ||
* This enum is used to identify different sections of the application where widgets can be registered. | ||
* Each value corresponds to a specific page or section in the application. This allows for flexible | ||
* and dynamic registration based on the context and requirements of the application. | ||
* | ||
* @readonly | ||
* @enum {string} | ||
*/ | ||
export type WidgetPageLocationId = 'time-tracking' | 'accounting'; | ||
|
||
/** | ||
* Configuration for registering a widget. | ||
*/ | ||
export interface WidgetRegistryConfig { | ||
/** | ||
* @description | ||
* The location of the widget in the application. This is used to determine | ||
* where the widget should be rendered in the application. | ||
* | ||
* @example 'time-tracking' | ||
*/ | ||
location: WidgetPageLocationId; | ||
|
||
/** | ||
* @description | ||
* The unique identifier of the widget. This ID is used to distinguish | ||
* the widget from others and can be used to reference or load the widget | ||
* in the application. | ||
* | ||
* @example 'weekly-activity' | ||
*/ | ||
widgetId: string; | ||
|
||
/** | ||
* @description | ||
* The title of the widget. This title is typically used for display purposes, | ||
* such as in headers or menus, to give users an understanding of the widget's | ||
* purpose or content. The title can be: | ||
* | ||
* - A static string for a fixed title. | ||
* - A resolver function that returns a promise or direct value of the title. | ||
* - A translation key for a dynamic title. | ||
* | ||
* @example 'Time Tracking' // Static title | ||
* @example () => Promise.resolve('Time Tracking') // Resolver function returning a promise | ||
* @example () => 'Time Tracking' // Resolver function returning a direct value | ||
*/ | ||
title?: string | ResolveFn<string>; | ||
|
||
/** | ||
* @description | ||
* Function that returns a promise or a direct type of the component to be loaded. | ||
* This function is used to dynamically load the component associated with the widget. | ||
* It allows for lazy loading of components to optimize performance and reduce initial | ||
* load time. | ||
* | ||
* @example | ||
* () => import('./weekly-activity-widget.component').then(m => m.WeeklyActivityWidgetComponent) | ||
*/ | ||
loadComponent?: () => Promise<Type<any>> | Type<any>; | ||
|
||
/** | ||
* @description | ||
* Array of widths supported by the widget in the grid layout. Each width value | ||
* corresponds to the number of columns the widget can span. This allows the widget | ||
* to be responsive and adapt to different layout configurations. | ||
* | ||
* @example [3, 4, 6, 8, 12] | ||
*/ | ||
supportedWidths?: WidgetGridWidth[]; | ||
|
||
/** | ||
* @description | ||
* Array of permissions required to view or use the widget. Each permission is | ||
* represented as a string, and these permissions are checked to ensure that the | ||
* user has the necessary rights to access or interact with the widget. | ||
* | ||
* @example ['admin', 'user'] | ||
*/ | ||
permissions: string[] | PermissionsEnum[]; | ||
} | ||
|
||
/** | ||
* Widget registry service interface. | ||
* | ||
* This interface defines the contract for services that manage widget registrations, | ||
* including methods for registering single and multiple widgets. | ||
*/ | ||
export interface IWidgetRegistry { | ||
/** | ||
* Registers a single widget with the service. | ||
* | ||
* This method adds a single widget configuration to the registry. If a widget with | ||
* the same ID is already registered, an error will be thrown. | ||
* | ||
* @param config The configuration object for the widget to be registered. | ||
*/ | ||
registerWidget(config: WidgetRegistryConfig): void; | ||
|
||
/** | ||
* Registers multiple widgets with the service. | ||
* | ||
* This method adds multiple widget configurations to the registry. If any widget | ||
* within the provided configurations already exists, an error will be thrown for that | ||
* specific widget, but other widgets will still be registered. | ||
* | ||
* @param configs An array of configuration objects for the widgets to be registered. | ||
*/ | ||
registerWidgets(configs: WidgetRegistryConfig[]): void; | ||
} |