Widget System Guide
Comprehensive guide to the Barcoding widget system - a dynamic, database-driven dashboard architecture used by all three application instances (Backend, Front, Dashboard).
Overview
The Barcoding widget system provides a powerful, user-customizable dashboard experience where widgets are:
- Database-Driven: Widget definitions and configurations stored in MySQL database
- Dynamically Loaded: Widgets loaded on-demand using Angular's dynamic component loading
- User-Customizable: Users can add, remove, resize, and reposition widgets
- Multi-Instance: Widgets can be shared across Backend, Front, and Dashboard instances
- Persistent: Layout and configuration saved per user and synchronized across sessions
Key Concepts
What is a Widget?
A widget is a self-contained, reusable Angular component that can be:
- Dynamically loaded into a gridster dashboard
- Configured with custom settings
- Positioned and sized by users
- Integrated with the application state and API services
Widget System Architecture
┌─────────────────────────────────────────────────────────────┐
│ User Dashboard View │
├─────────────────────────────────────────────────────────────┤
│ ┌────────────┐ ┌────────────┐ ┌────────────┐ │
│ │ Widget A │ │ Widget B │ │ Widget C │ │
│ │ (Info) │ │ (Chart) │ │ (List) │ │
│ └────────────┘ └────────────┘ └────────────┘ │
└─────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ @barcoding/gridster-core │
│ - DynamicComponentLoader (lazy loading) │
│ - WidgetWrapper (rendering) │
│ - DashboardStore (state management) │
└─────────────────────────────────────────────────────────────┘
│ │ │
▼ ▼ ▼
┌─────────────────────────────────────────────────────────────┐
│ MySQL Database │
│ ┌──────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ Widget │ │ WidgetConfig │ │ DashboardView │ │
│ │ (defs) │ │ (instances) │ │ (layouts) │ │
│ └──────────┘ └──────────────┘ └───────────────┘ │
└─────────────────────────────────────────────────────────────┘Database Schema
The widget system uses three main database tables:
Widget Table
Stores widget definitions (controller names, categories, metadata):
| Field | Type | Description |
|---|---|---|
id | int | Primary key |
controller | varchar(512) | Widget controller name (e.g., "WidgetComments") |
general_name | varchar(512) | Display name for users |
category_id | int | Widget category for organization |
dashboard | tinyint(1) | Dashboard availability flag |
status | tinyint(1) | Active/inactive status |
duplication_option | tinyint(1) | Allow multiple instances per dashboard |
package_name | varchar(255) | Optional package name for shared widgets |
WidgetConfig Table
Stores widget instances on dashboards (position, size, configuration):
| Field | Type | Description |
|---|---|---|
id | int | Primary key |
widget_id | int | Foreign key to Widget table |
dashboard_view_id | int | Foreign key to DashboardView (tab) |
rows | int | Widget height in grid rows |
cols | int | Widget width in grid columns |
x | int | X position on grid |
y | int | Y position on grid |
config | text | JSON configuration for widget |
DashboardView Table
Stores dashboard tabs/views that contain widgets:
| Field | Type | Description |
|---|---|---|
id | int | Primary key |
name | varchar(512) | Tab/view name |
dashboard_id | int | Foreign key to Dashboard |
sort | int | Tab display order |
Relationship Flow:
Dashboard (1) ──→ (n) DashboardView (1) ──→ (n) WidgetConfig (n) ──→ (1) WidgetWidget Types
Shared/Package Widgets
Universal widgets packaged as npm packages in @barcoding/widget-* that can be used across all three instances (Backend, Front, Dashboard).
Location: web/projects/packages/@barcoding/widgets/
Characteristics:
- Published as separate npm packages
- Can be imported by any instance
- Follow package dependency hierarchy
- Must be built before use:
ng build @barcoding/widget-example
Example Structure:
web/projects/packages/@barcoding/widget-calendar/
├── src/
│ ├── lib/
│ │ ├── widget-calendar.component.ts
│ │ ├── widget-calendar.component.html
│ │ ├── widget-calendar.component.scss
│ │ └── widget-calendar.module.ts
│ └── public-api.ts
├── package.json
└── ng-package.jsonInstance-Specific Widgets
Widgets that exist only in a specific instance and are not shared.
Locations:
- Backend:
web/projects/backend/src/widgets/ - Front:
web/projects/front/src/widgets/ - Dashboard:
web/projects/dashboard/src/widgets/
Characteristics:
- Scoped to single instance
- Direct access to instance-specific services
- Registered in instance's
widgets.tsmanifest - Not published as separate packages
Example Structure:
web/projects/backend/src/widgets/widget-ncr-info/
├── widget-ncr-info/
│ ├── widget-ncr-info.component.ts
│ ├── widget-ncr-info.component.html
│ └── widget-ncr-info.component.scss
├── config/
│ ├── config.component.ts
│ └── modal.html
├── editModal/
│ └── editModal.component.ts
└── widget-ncr-info.module.tsWidget Categories
Info Widgets
Display information about a specific model/entity being viewed in the application.
Characteristics:
- Tied to a specific module (NCR, Job, Part, etc.)
- Display data about the current object in context
- Usually read-only or minimal interaction
- Receive state via Observable of current object
Example: widget-ncr-info
@Component({
selector: 'widget-ncr-info',
templateUrl: './widget-ncr-info.component.html'
})
export class WidgetNcrInfoComponent implements WidgetInterface {
public item: WidgetConfigWithRelations;
public params: WidgetParams;
public state: Observable<NcrWithRelations>; // Observes current NCR
ngOnInit() {
this.objectSubscription = this.state.subscribe(ncr => {
this.object = ncr; // Display NCR information
});
}
}Use Cases:
- Show NCR details (status, description, dates)
- Display job information (work order, part, timeline)
- Show employee info (contact, department, schedule)
- Display document metadata (title, version, owner)
Universal Widgets
Use module_id and object_id to provide a universal data layer that works across multiple modules.
Characteristics:
- Module-agnostic design
- Use generic module_id/object_id parameters
- Can be used on any entity across different modules
- Typically interact with universal tables (Comments, Documents, History)
Example: widget-comments
@Component({
selector: 'widget-comments',
templateUrl: './widget-comments.component.html'
})
export class WidgetCommentsComponent implements WidgetInterface {
public item: WidgetConfigWithRelations;
public params: WidgetParams; // Contains module_id and object_id
ngOnInit() {
this.objectSubscription = this.state.subscribe(object => {
const currentModuleId = this.store.selectSnapshot(ModuleState.module).id;
// Universal approach: works for any module/object combination
this.store.dispatch(new FindComments({
where: {
module_id: currentModuleId,
object_id: object.id
}
}));
});
}
}Use Cases:
- Comments system (works on NCR, Jobs, Parts, etc.)
- Document attachments (works on any entity)
- Audit history (works on any entity)
- User favorites (works on any entity)
Chart/Visualization Widgets
Display data visualizations, charts, and analytical dashboards.
Characteristics:
- Data aggregation and visualization
- Often use Kendo Charts or custom D3.js
- May have refresh intervals
- Configuration for data sources and display options
Use Cases:
- Production line status charts
- Time tracking visualizations
- Sales/revenue dashboards
- Quality metrics and KPIs
List/Management Widgets
Display lists of data with management capabilities (CRUD operations).
Characteristics:
- Use Kendo Grid for data display
- Support filtering, sorting, pagination
- May include inline editing
- Action buttons for create/edit/delete
Use Cases:
- Employee assignment lists
- Tool usage management
- Production schedule management
- Ticket category management
Core Interfaces and Contracts
WidgetInterface
Every widget component must implement the WidgetInterface:
import { WidgetInterface, WidgetParams } from '@barcoding/gridster-core';
import { WidgetConfigWithRelations } from '@barcoding/sdk';
export interface WidgetInterface {
item: WidgetConfigWithRelations; // Widget instance configuration
params: WidgetParams; // Runtime parameters
state?: Observable<any>; // Optional state observable
}WidgetParams
Parameters passed to widgets at runtime:
export interface WidgetParams {
model?: string; // Model name (e.g., 'Ncr', 'Job')
object?: any; // Current object being viewed
module_id?: number; // Current module ID
object_id?: number; // Current object ID
[key: string]: any; // Additional custom parameters
}WidgetConfigWithRelations
Widget instance configuration from database:
export interface WidgetConfigWithRelations {
id: number; // WidgetConfig instance ID
widget_id: number; // Widget definition ID
dashboard_view_id: number; // Parent DashboardView ID
rows: number; // Grid height
cols: number; // Grid width
x: number; // X position
y: number; // Y position
config: any; // JSON widget configuration
widget?: WidgetWithRelations; // Related Widget definition
}ConfigInterfaceDashboard
Abstract class for widgets with configurable settings:
import { ConfigInterfaceDashboard } from '@barcoding/gridster-core';
export class WidgetCommentsComponent
extends ConfigInterfaceDashboard
implements WidgetInterface {
public configChanged$: Subject<any> = new Subject<any>();
constructor(
public dialog: MatDialog,
public store: Store
) {
super(dialog, CommentsConfigDialog, store);
}
ngOnDestroy() {
super.destroy(); // Clean up config subscriptions
}
}Related Documentation
- Widget Creation Guide - Step-by-step guide to creating widgets
- Widget Development - Best practices and patterns
- Widget Configuration - Configuring widget behavior
- Gridster Core Package - Core widget system
- Multi-Instance Architecture - Instance architecture