bways-report 0.1.8 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/README.md +463 -316
  2. package/esm2022/lib/core/config/bways-report-config.mjs +31 -32
  3. package/esm2022/lib/core/models/index.mjs +1 -1
  4. package/esm2022/lib/core/models/report-api-endpoint.model.mjs +8 -0
  5. package/esm2022/lib/core/models/report-component.model.mjs +1 -1
  6. package/esm2022/lib/core/models/report-datasource.model.mjs +1 -1
  7. package/esm2022/lib/core/services/index.mjs +2 -1
  8. package/esm2022/lib/core/services/report-api-execution.service.mjs +210 -0
  9. package/esm2022/lib/core/services/report-data-discovery.service.mjs +76 -4
  10. package/esm2022/lib/core/services/report-session-context.service.mjs +72 -3
  11. package/esm2022/lib/core/tokens/designer-config.token.mjs +4 -0
  12. package/esm2022/lib/core/tokens/reporting-config.token.mjs +1 -1
  13. package/esm2022/lib/core/utils/report-endpoint.util.mjs +22 -0
  14. package/esm2022/lib/core/utils/report-request-scope.mjs +48 -0
  15. package/esm2022/lib/data-access/adapters/endpoint-datasource.adapter.mjs +31 -1
  16. package/esm2022/lib/data-access/adapters/endpoint-lookup.adapter.mjs +27 -2
  17. package/esm2022/lib/data-access/adapters/endpoint-masterdata.adapter.mjs +5 -2
  18. package/esm2022/lib/data-access/adapters/endpoint-persistence.adapter.mjs +30 -14
  19. package/esm2022/lib/data-access/adapters/endpoint-schema-discovery.adapter.mjs +32 -28
  20. package/esm2022/lib/data-access/adapters/endpoint-tokens.mjs +1 -1
  21. package/esm2022/lib/data-access/adapters/http-datasource.adapter.mjs +4 -37
  22. package/esm2022/lib/data-access/adapters/http-lookup.adapter.mjs +28 -51
  23. package/esm2022/lib/data-access/adapters/http-persistence.adapter.mjs +43 -194
  24. package/esm2022/lib/data-access/adapters/http-schema-discovery.adapter.mjs +17 -65
  25. package/esm2022/lib/data-access/adapters/index.mjs +1 -1
  26. package/esm2022/lib/data-access/adapters/local-storage-persistence.adapter.mjs +13 -4
  27. package/esm2022/lib/data-access/adapters/report-id-availability.mjs +20 -0
  28. package/esm2022/lib/data-access/adapters/session-headers.mjs +11 -0
  29. package/esm2022/lib/data-access/contracts/index.mjs +1 -1
  30. package/esm2022/lib/data-access/contracts/lookup.contract.mjs +1 -1
  31. package/esm2022/lib/data-access/contracts/report-persistence.contract.mjs +13 -1
  32. package/esm2022/lib/features/designer/components/component-palette/component-palette.component.mjs +536 -6
  33. package/esm2022/lib/features/designer/components/design-canvas/design-canvas.component.mjs +55 -17
  34. package/esm2022/lib/features/designer/components/dialogs/report-saved-dialog.component.mjs +546 -119
  35. package/esm2022/lib/features/designer/components/property-editor/parameter-binding-editor.component.mjs +3 -3
  36. package/esm2022/lib/features/designer/components/property-editor/property-editor-action.component.mjs +3 -3
  37. package/esm2022/lib/features/designer/components/property-editor/property-editor-datasource.component.mjs +142 -8
  38. package/esm2022/lib/features/designer/components/property-editor/property-editor-general.component.mjs +3 -3
  39. package/esm2022/lib/features/designer/components/property-editor/property-editor-grid.component.mjs +129 -28
  40. package/esm2022/lib/features/designer/components/property-editor/property-editor-layout.component.mjs +3 -3
  41. package/esm2022/lib/features/designer/components/property-editor/property-editor-report.component.mjs +3 -3
  42. package/esm2022/lib/features/designer/components/property-editor/property-editor-validation.component.mjs +3 -3
  43. package/esm2022/lib/features/designer/components/property-editor/property-editor.component.mjs +27 -13
  44. package/esm2022/lib/features/designer/components/toolbar/designer-toolbar.component.mjs +54 -32
  45. package/esm2022/lib/features/designer/designer.component.mjs +109 -75
  46. package/esm2022/lib/features/designer/rpt-report-designer.component.mjs +10 -4
  47. package/esm2022/lib/features/designer/services/designer-config.service.mjs +56 -0
  48. package/esm2022/lib/features/designer/services/designer-endpoints.service.mjs +155 -0
  49. package/esm2022/lib/features/designer/services/designer-state.service.mjs +3 -2
  50. package/esm2022/lib/features/designer/utilities/canvas-layout.util.mjs +2 -1
  51. package/esm2022/lib/features/embed/bways-report-builder.component.mjs +3 -3
  52. package/esm2022/lib/features/export/services/report-export.service.mjs +11 -6
  53. package/esm2022/lib/features/persistence/services/report-store.service.mjs +78 -23
  54. package/esm2022/lib/features/persistence/services/schema-validator.service.mjs +59 -3
  55. package/esm2022/lib/features/routing/components/routed-report-designer.component.mjs +12 -17
  56. package/esm2022/lib/features/routing/components/routed-report-runtime.component.mjs +6 -4
  57. package/esm2022/lib/features/routing/report-routes.mjs +6 -6
  58. package/esm2022/lib/features/routing/resolvers/report-route-identifier.mjs +5 -0
  59. package/esm2022/lib/features/routing/resolvers/report.resolver.mjs +3 -2
  60. package/esm2022/lib/features/runtime/dynamic-renderer.component.mjs +23 -4
  61. package/esm2022/lib/features/runtime/report-execution.service.mjs +36 -6
  62. package/esm2022/lib/features/runtime/report-grid-bridge.component.mjs +54 -11
  63. package/esm2022/lib/features/runtime/report-runtime.component.mjs +105 -68
  64. package/esm2022/lib/features/runtime/rpt-report.component.mjs +50 -42
  65. package/esm2022/lib/primitives/components/chart-bridge/report-chart-bridge.component.mjs +7 -2
  66. package/esm2022/lib/primitives/components/dropdown/rpt-dropdown.component.mjs +16 -7
  67. package/esm2022/lib/primitives/components/icon/rpt-icon.component.mjs +53 -1
  68. package/esm2022/lib/primitives/components/index.mjs +2 -1
  69. package/esm2022/lib/primitives/components/radio/rpt-radio.component.mjs +428 -0
  70. package/esm2022/lib/primitives/register-builtins.mjs +51 -2
  71. package/esm2022/lib/provide-reporting.mjs +11 -29
  72. package/fesm2022/bways-report.mjs +3745 -1281
  73. package/fesm2022/bways-report.mjs.map +1 -1
  74. package/lib/core/config/bways-report-config.d.ts +27 -5
  75. package/lib/core/models/index.d.ts +2 -1
  76. package/lib/core/models/report-api-endpoint.model.d.ts +30 -0
  77. package/lib/core/models/report-component.model.d.ts +16 -4
  78. package/lib/core/models/report-datasource.model.d.ts +21 -2
  79. package/lib/core/services/index.d.ts +1 -0
  80. package/lib/core/services/report-api-execution.service.d.ts +41 -0
  81. package/lib/core/services/report-data-discovery.service.d.ts +23 -1
  82. package/lib/core/services/report-session-context.service.d.ts +9 -0
  83. package/lib/core/tokens/designer-config.token.d.ts +4 -0
  84. package/lib/core/tokens/reporting-config.token.d.ts +4 -0
  85. package/lib/core/utils/report-endpoint.util.d.ts +12 -0
  86. package/lib/core/utils/report-request-scope.d.ts +14 -0
  87. package/lib/data-access/adapters/endpoint-datasource.adapter.d.ts +2 -0
  88. package/lib/data-access/adapters/endpoint-lookup.adapter.d.ts +1 -0
  89. package/lib/data-access/adapters/endpoint-persistence.adapter.d.ts +6 -2
  90. package/lib/data-access/adapters/endpoint-schema-discovery.adapter.d.ts +4 -2
  91. package/lib/data-access/adapters/endpoint-tokens.d.ts +7 -0
  92. package/lib/data-access/adapters/http-datasource.adapter.d.ts +1 -3
  93. package/lib/data-access/adapters/http-lookup.adapter.d.ts +3 -4
  94. package/lib/data-access/adapters/http-persistence.adapter.d.ts +11 -16
  95. package/lib/data-access/adapters/http-schema-discovery.adapter.d.ts +3 -5
  96. package/lib/data-access/adapters/index.d.ts +1 -1
  97. package/lib/data-access/adapters/local-storage-persistence.adapter.d.ts +2 -2
  98. package/lib/data-access/adapters/report-id-availability.d.ts +6 -0
  99. package/lib/data-access/adapters/session-headers.d.ts +3 -0
  100. package/lib/data-access/contracts/index.d.ts +1 -0
  101. package/lib/data-access/contracts/lookup.contract.d.ts +3 -0
  102. package/lib/data-access/contracts/report-persistence.contract.d.ts +16 -1
  103. package/lib/features/designer/components/component-palette/component-palette.component.d.ts +16 -0
  104. package/lib/features/designer/components/design-canvas/design-canvas.component.d.ts +2 -0
  105. package/lib/features/designer/components/dialogs/report-saved-dialog.component.d.ts +37 -5
  106. package/lib/features/designer/components/property-editor/property-editor-datasource.component.d.ts +21 -3
  107. package/lib/features/designer/components/property-editor/property-editor-grid.component.d.ts +20 -7
  108. package/lib/features/designer/components/property-editor/property-editor.component.d.ts +2 -1
  109. package/lib/features/designer/components/toolbar/designer-toolbar.component.d.ts +7 -1
  110. package/lib/features/designer/designer.component.d.ts +16 -2
  111. package/lib/features/designer/rpt-report-designer.component.d.ts +5 -1
  112. package/lib/features/designer/services/designer-config.service.d.ts +13 -0
  113. package/lib/features/designer/services/designer-endpoints.service.d.ts +25 -0
  114. package/lib/features/persistence/services/report-store.service.d.ts +15 -1
  115. package/lib/features/persistence/services/schema-validator.service.d.ts +2 -0
  116. package/lib/features/routing/resolvers/report-route-identifier.d.ts +2 -0
  117. package/lib/features/runtime/report-execution.service.d.ts +4 -0
  118. package/lib/features/runtime/report-grid-bridge.component.d.ts +4 -1
  119. package/lib/features/runtime/report-runtime.component.d.ts +14 -1
  120. package/lib/features/runtime/rpt-report.component.d.ts +5 -0
  121. package/lib/primitives/components/chart-bridge/report-chart-bridge.component.d.ts +3 -1
  122. package/lib/primitives/components/index.d.ts +2 -0
  123. package/lib/primitives/components/radio/rpt-radio.component.d.ts +77 -0
  124. package/package.json +2 -1
package/README.md CHANGED
@@ -1,448 +1,595 @@
1
- # BWays-Report — Integration & Developer Guide
1
+ # BWays-Report — Enterprise Reporting & Visual Page Builder
2
2
 
3
- `bways-report` is an enterprise reporting platform and visual drag-and-drop page builder for Angular 18+ business & ERP applications with NestJS / SQL Server.
3
+ [![npm version](https://img.shields.io/npm/v/bways-report.svg)](https://www.npmjs.com/package/bways-report)
4
+ [![license](https://img.shields.io/badge/License-Proprietary-blue.svg)](LICENSE)
5
+ [![Angular](https://img.shields.io/badge/Angular-18%2B%20%7C%2019%2B-DD0031.svg)](https://angular.io)
6
+
7
+ `bways-report` is an enterprise-grade reporting engine and visual drag-and-drop page builder for Angular 18+ business & ERP applications with NestJS / Microsoft SQL Server.
4
8
 
5
- It empowers developers and business users to visually design reporting pages with filters, lookup dropdowns, metric cards, charts, and data grids. Report configurations are saved as clean JSON metadata (`ReportDefinition`), and the runtime engine dynamically generates reactive forms, controls, queries, and live grid views on the fly.
9
+ It eliminates the need to manually code components, reactive forms, date pickers, dropdowns, and data grids for every single report. Instead, reports are designed visually in the browser, stored permanently in the database as clean JSON metadata, and rendered dynamically at runtime with live stored procedures, server-side execution, and data export.
6
10
 
7
11
  ---
8
- [![npm version](https://img.shields.io/npm/v/bways-report.svg)](https://www.npmjs.com/package/bways-report)
9
- [![license](https://img.shields.io/badge/License-Proprietary-blue.svg)](LICENSE)
10
- [![Changelog](https://img.shields.io/badge/Changelog-v0.2.0-blue.svg)](CHANGELOG.md)
12
+
13
+ ## Why bways-report? (GUI vs. Manual Coding)
14
+
15
+ In traditional ERP and business applications, creating 50 reports requires:
16
+ - Generating 50 separate Angular components (`ng g c ...`)
17
+ - Writing thousands of lines of boilerplate HTML forms, labels, validation, and CSS grids
18
+ - Hardcoding TypeScript column definitions, formatting, sorting, and pagination
19
+ - Recompiling, testing, and **re-deploying the frontend application** for every column or label change requested by clients
20
+
21
+ ### With `bways-report`:
22
+ | Feature | Traditional Coding | With `bways-report` |
23
+ | :--- | :--- | :--- |
24
+ | **New Report Creation** | Hours of coding `.ts`, `.html`, `.css` | **2 minutes** in visual drag-and-drop designer |
25
+ | **Component Files** | 1 component per report (50 reports = 50 files) | **0 new files**. Handled dynamically by a single generic viewer |
26
+ | **Client Change Requests** | Edit code, re-build Angular bundle, redeploy | Edit in GUI, click **Save**. Changes are live instantly! |
27
+ | **Persistence** | Hardcoded templates | Stored in SQL Server (`CNFREPORTDEF`) |
28
+ | **Data Export** | Manual Excel/CSV export logic | Built-in 1-click Excel, CSV, and Print exports |
29
+
11
30
  ---
12
31
 
13
- ## What's New in v0.2.0
32
+ ## How It Works (The Lifecycle)
14
33
 
15
- - **1 Config Object + 3 Drop-in Components**: Eliminate boilerplate adapters with `BwaysReportConfig` and drop-in tags.
16
- - **`<bways-report-builder>`**: Drop-in visual designer shell with width/height controls, starter blueprints, and save flow.
17
- - **`<bways-report-page>`**: Live runtime form & dynamic grid page rendered automatically from a report slug.
18
- - **`<bways-report-menu>` & `injectReportMenu()`**: Responsive navigation menu (sidebar, navbar, dropdown) with search and category folding.
19
- - **`bwaysReportRoutes()`**: Declarative Angular routing for live report pages (`/reports/:slug`).
20
- - **Post-Save Interactive Modal**: Immediate live form preview with page routing settings (slug, menu group, publish toggle).
21
- - **CDK Overlay Viewport Flipping**: Zero clipping for searchable dropdowns inside cards and scroll containers.
22
- - **Quick Action ("+") & Inline Renaming**: Double-click report title to rename in place; `+` button to start fresh pages.
34
+ ```
35
+ ┌─────────────────────────────────────────────────────────────┐
36
+ │ 1. VISUAL DESIGNER (<rpt-designer>) │
37
+ │ • Drag & drop inputs, date ranges, lookup dropdowns │
38
+ │ • Connect stored procedures & select output grid columns │
39
+ │ • Click "Save" ───► Generates ReportDefinition JSON │
40
+ └──────────────────────────────┬──────────────────────────────┘
41
+ │ POST /api/reporting/reports
42
+ ▼
43
+ ┌─────────────────────────────────────────────────────────────┐
44
+ │ 2. DATABASE STORAGE (SQL Server) │
45
+ │ • Saved to table: CNFREPORTDEF │
46
+ │ • Column DEFJSON: Stores the report JSON schema │
47
+ │ • Relational columns: CODE, NAME, VERSION, STATUS_CODE │
48
+ └──────────────────────────────┬──────────────────────────────┘
49
+ │ GET /api/reporting/reports/:id
50
+ ▼
51
+ ┌─────────────────────────────────────────────────────────────┐
52
+ │ 3. RUNTIME ENGINE (<rpt-report> or bwaysReportRoutes) │
53
+ │ • User opens route: /reports/:slug │
54
+ │ • Fetches JSON schema from database │
55
+ │ • Renders live Reactive Forms, Parameter Validation, │
56
+ │ UltraGrid, Charts, and Excel/CSV/Print export toolbar │
57
+ └─────────────────────────────────────────────────────────────┘
58
+ ```
23
59
 
24
60
  ---
25
61
 
26
62
  ## Table of Contents
27
63
 
28
- 1. [Quick Start (5 Steps)](#1-quick-start-5-steps)
29
- - [Step 1: Install](#step-1-install)
30
- - [Step 2: Configure Once (`app.config.ts`)](#step-2-configure-once-appconfigts)
31
- - [Step 3: Drop-in Builder Component](#step-3-drop-in-builder-component)
32
- - [Step 4: Host Navigation Menu](#step-4-host-navigation-menu)
33
- - [Step 5: Declarative Routes (`app.routes.ts`)](#step-5-declarative-routes-approutests)
34
- 2. [Visual Designer Features](#2-visual-designer-features)
35
- - [Single-Mode Technical Property Editor](#single-mode-technical-property-editor)
36
- - [CDK Overlay Viewport Flip](#cdk-overlay-viewport-flip)
37
- - [Post-Save Live Preview & Settings Dialog](#post-save-live-preview--settings-dialog)
38
- - [Inline Double-Click Renaming](#inline-double-click-renaming)
39
- - [Report Switcher & Quick New Page ("+")](#report-switcher--quick-new-page-)
40
- 3. [Backend Contract Reference](#3-backend-contract-reference)
41
- 4. [Dynamic Session Context & Auto-Parameter Binding](#4-dynamic-session-context--auto-parameter-binding)
42
- 5. [Plugging in BWays-Grid (`UltraGridComponent`)](#5-plugging-in-bways-grid-ultragridcomponent)
43
- 6. [Advanced Custom Adapters](#6-advanced-custom-adapters)
44
- 7. [Theming & CSS Custom Properties](#7-theming--css-custom-properties)
45
- 8. [Exporting Data (CSV & JSON)](#8-exporting-data-csv--json)
64
+ 1. [Installation](#1-installation)
65
+ 2. [Designer Configuration](#2-designer-configuration)
66
+ 3. [Declarative Routes (`app.routes.ts`) — Zero Component Code](#3-declarative-routes-approutests)
67
+ 4. [Component Usage Patterns](#4-component-usage-patterns)
68
+ - [Pattern A: Embed a Saved Report by ID (`<rpt-report [id]>`)](#pattern-a-embed-a-saved-report-by-id)
69
+ - [Pattern B: Embed from In-Memory JSON (`<rpt-report [report]>`)](#pattern-b-embed-from-in-memory-json)
70
+ - [Pattern C: Embed the Visual Designer (`<rpt-designer>`)](#pattern-c-embed-the-visual-designer)
71
+ - [Pattern D: Toggle View / Edit on the Same Page](#pattern-d-toggle-view--edit-on-the-same-page)
72
+ 5. [Database Persistence & SQL Schema](#5-database-persistence--sql-schema)
73
+ 6. [Save Confirmation & Host Notifications](#6-save-confirmation--host-notifications)
74
+ 7. [Data Grid & UltraGrid Integration](#7-data-grid--ultragrid-integration)
75
+ 8. [Backend API Contract](#8-backend-api-contract)
46
76
 
47
77
  ---
48
78
 
49
- ## 1. Quick Start (5 Steps)
79
+ ## 1. Installation
50
80
 
51
- ### Step 1: Install
81
+ Install the package and its peer dependencies via npm:
52
82
 
53
83
  ```bash
54
- npm install bways-report bways-grid @angular/cdk
84
+ npm install bways-report @angular/cdk
55
85
  ```
56
86
 
57
- > **Compatibility**: Angular 18+ or 19+ standalone architecture with Zone.js or Zoneless change detection.
87
+ > **Requirements**: Angular 18+ or 19+ (standalone architecture). Compatible with both Zone.js and Zoneless change detection.
58
88
 
59
89
  ---
60
90
 
61
- ### Step 2: Configure Once (`app.config.ts`)
91
+ ## 2. Designer Configuration
62
92
 
63
- Configure `provideBwaysReport()` with a single `BwaysReportConfig` object:
93
+ ### Configure inside the designer page
94
+
95
+ Define a typed object in the page component and bind it through `[config]`. An embedded designer does not require `provideBwaysReport()` in `app.config.ts`. Register Angular's `provideHttpClient()` once in the host application so its authentication interceptors remain available.
64
96
 
65
97
  ```typescript
66
- // src/app/app.config.ts
67
- import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
98
+ // rpt-designer.component.ts
99
+ import { Component } from '@angular/core';
100
+ import { BwaysReportConfig, DesignerComponent } from 'bways-report';
101
+
102
+ @Component({
103
+ selector: 'app-rpt-designer',
104
+ standalone: true,
105
+ imports: [DesignerComponent],
106
+ templateUrl: './rpt-designer.component.html',
107
+ styles: [`
108
+ :host {
109
+ display: flex;
110
+ flex-direction: column;
111
+ height: calc(100dvh - 64px);
112
+ min-height: 0;
113
+ min-width: 0;
114
+ }
115
+ `],
116
+ })
117
+ export class RptDesignerComponent {
118
+ readonly designerConfig: BwaysReportConfig = {
119
+ spEndpoint: '/api/reporting/procedures',
120
+ tablesEndpoint: '/api/reporting/tables',
121
+ executeEndpoint: '/api/reporting/execute',
122
+ lookupEndpoint: '/api/reporting/lookup',
123
+ session: { companyId: 101, branchId: 1 },
124
+ autoParameter: true,
125
+ components: ['formInputs', 'actionButtons'],
126
+ routeBase: 'reports',
127
+ defaultPageSize: 25,
128
+ };
129
+ }
130
+ ```
131
+
132
+ ```html
133
+ <!-- rpt-designer.component.html -->
134
+ <rpt-designer [config]="designerConfig"></rpt-designer>
135
+ ```
136
+
137
+ Give the designer page a definite height, as above, adjusting `64px` for your application header. Inside an existing flex layout, use `flex: 1; height: 100%; min-height: 0` on every page wrapper and `min-height: 0` on the parent flex work area. Canvas, preview and JSON then scroll inside the available height. A wrapper that grows with its content inside an `overflow: hidden` application shell clips the page instead.
138
+
139
+ For an application embedding only the designer, the reporting-related bootstrap configuration is:
140
+
141
+ ```typescript
142
+ // app.config.ts
143
+ import { ApplicationConfig } from '@angular/core';
68
144
  import { provideHttpClient } from '@angular/common/http';
69
- import { provideRouter } from '@angular/router';
70
- import { provideBwaysReport, BwaysReportConfig } from 'bways-report';
71
- import { UltraGridComponent } from 'bways-grid';
72
- import { routes } from './app.routes';
73
- import { AuthService } from './services/auth.service';
74
-
75
- const reportConfig: BwaysReportConfig = {
76
- // Backend Endpoints (only these 3-4 URLs needed)
77
- spEndpoint: 'http://localhost:3000/api/reporting/procedures', // GET -> SPs + parameters
78
- tablesEndpoint: 'http://localhost:3000/api/reporting/tables', // GET -> Tables + columns
79
- executeEndpoint: 'http://localhost:3000/api/reporting/execute', // POST -> Query / SP execution
80
- lookupEndpoint: 'http://localhost:3000/api/reporting/lookup', // POST -> Dropdown master data / lookup (optional)
81
- reportsEndpoint: 'http://localhost:3000/api/reporting/reports', // Optional CRUD (defaults to localStorage)
82
-
83
- // Visual Designer Configuration
84
- components: ['formInputs', 'actionButtons', 'displayLabels'], // Palette categories to show (default: all)
85
- autoParameter: true, // Auto-bind @BranchId, @CompanyId from session
86
- session: () => inject(AuthService).currentSession(), // Session source for autoParameter
87
-
88
- // Live Pages & Data Grid
89
- routeBase: 'reports', // Live pages mount at /reports/:slug
90
- grid: UltraGridComponent, // UltraGrid from bways-grid (or built-in table)
91
- defaultPageSize: 25,
92
- };
93
145
 
94
146
  export const appConfig: ApplicationConfig = {
95
- providers: [
96
- provideZoneChangeDetection({ eventCoalescing: true }),
97
- provideHttpClient(),
98
- provideRouter(routes),
99
- provideBwaysReport(reportConfig),
100
- ],
147
+ providers: [provideHttpClient()],
101
148
  };
102
149
  ```
103
150
 
104
- ---
151
+ Retain your application's existing router, authentication interceptors, and other providers. Page configuration selects reporting URLs and tenant context; backend authorization remains the host application's responsibility.
105
152
 
106
- ### Step 3: Drop-in Builder Component
153
+ All fields are optional. Settings resolve in this order: library defaults, optional application defaults, `[config]`, then `[apiUrl]` for individual endpoint overrides. Omitted or undefined values inherit defaults. Arrays replace inherited arrays; an empty `components` array retains the existing meaning of unrestricted palette categories.
107
154
 
108
- Embed the full visual drag-and-drop report designer with one HTML tag:
155
+ | Source | Scope | Overrides |
156
+ | --- | --- | --- |
157
+ | Library defaults | Built-in fallback settings | None |
158
+ | `provideBwaysReport(...)` | Optional app-wide defaults, including separate viewers and menus | Library defaults |
159
+ | `[config]="designerConfig"` | One designer, including preview and save review | Supplied app settings |
160
+ | `[apiUrl]="apiUrls"` | Endpoint overrides for that designer | Supplied endpoint values from all other sources |
109
161
 
110
- ```html
111
- <!-- src/app/pages/admin-reports/admin-reports.component.html -->
112
- <bways-report-builder
113
- width="100%"
114
- height="calc(100vh - 64px)"
115
- (saved)="onReportSaved($event)"
116
- />
117
- ```
162
+ For example, a page can configure all settings locally while overriding only report storage:
118
163
 
119
164
  ```typescript
120
- // src/app/pages/admin-reports/admin-reports.component.ts
121
- import { Component } from '@angular/core';
122
- import { BwaysReportBuilderComponent, ReportDefinition } from 'bways-report';
165
+ // Inside the host component class; import BwaysReportApiUrls from bways-report.
166
+ readonly apiUrls: BwaysReportApiUrls = {
167
+ reportsEndpoint: 'https://reports.example.com:9004/api/reporting/reports',
168
+ };
169
+ ```
123
170
 
124
- @Component({
125
- standalone: true,
126
- imports: [BwaysReportBuilderComponent],
127
- templateUrl: './admin-reports.component.html',
128
- })
129
- export class AdminReportsComponent {
130
- onReportSaved(report: ReportDefinition): void {
131
- console.log('Report saved and published:', report.name, report.slug);
132
- }
133
- }
171
+ ```html
172
+ <rpt-designer [config]="designerConfig" [apiUrl]="apiUrls"></rpt-designer>
134
173
  ```
135
174
 
136
- ---
175
+ Each designer owns its effective settings, session resolution, preview, and storage adapters. Local `grid`, `chart`, `session`/`sessionProvider`, `apiEndpoints`, palette, routing, page size, timeout and date format follow this scope. Session sources support objects, signals, observables, factories using Angular `inject()`, and service classes. Replace the configuration object to update settings; session signals and observables update live. Existing draft edits are preserved and affected adapter caches are cleared. Setting `[config]="null"` restores application defaults while explicit `[apiUrl]` overrides remain active.
137
176
 
138
- ### Step 4: Host Navigation Menu
177
+ The public `<rpt-report-designer>` and `<rpt-designer-view>` facades also accept `[config]`. Configuration stays outside saved report JSON. Separately routed viewers and catalogs need their own application or route configuration; they do not inherit a destroyed designer page's settings. The save output is a notification after confirmed persistence and must not perform a second save.
139
178
 
140
- Display published reports in your host ERP navigation bar or sidebar:
179
+ See the complete example in [rpt-designer.component.ts](../playground/src/app/page-designer/rpt-designer.component.ts) and [rpt-designer.component.html](../playground/src/app/page-designer/rpt-designer.component.html).
141
180
 
142
- #### Option A: Drop-in Component
143
- ```html
144
- <!-- Sidebar variant with search filter and category folding -->
145
- <bways-report-menu variant="sidebar" />
181
+ ### Optional application defaults
182
+
183
+ Keep endpoint defaults in a typed configuration object. Supply any subset: procedures, tables, execution, lookup, and report storage are independent capabilities. Missing discovery endpoints produce no entries; executing without an execution URL reports a configuration error. Report storage uses the built-in reporting API and writes to `dbo.CNFREPORTDEF`. A separate save URL is not required: omitted `reportsEndpoint` is inferred from the configured reporting endpoints, or defaults to `/api/reporting/reports`. Absolute URLs (including ports) are supported. Server failures remain visible and never fall back to localStorage.
184
+
185
+ ```typescript
186
+ // src/app/config.ts
187
+ import { BwaysReportConfig } from 'bways-report';
188
+ import { environment } from '../environments/environment';
189
+
190
+ const apiBase = environment.baseUrl;
191
+ export const reportingConfig: BwaysReportConfig = {
192
+ spEndpoint: `${apiBase}/api/reporting/procedures`,
193
+ tablesEndpoint: `${apiBase}/api/reporting/tables`,
194
+ executeEndpoint: `${apiBase}/api/reporting/execute`,
195
+ lookupEndpoint: `${apiBase}/api/reporting/lookup`,
196
+ // Optional override; otherwise inferred automatically:
197
+ // reportsEndpoint: `${apiBase}/api/reporting/reports`,
198
+ autoParameter: true,
199
+ };
200
+ ```
201
+
202
+ ```typescript
203
+ // src/app/app.config.ts
204
+ import { ApplicationConfig } from '@angular/core';
205
+ import { provideHttpClient } from '@angular/common/http';
206
+ import { provideRouter } from '@angular/router';
207
+ import { provideBwaysReport } from 'bways-report';
208
+ import { reportingConfig } from './config';
209
+ import { routes } from './app.routes';
146
210
 
147
- <!-- Or dropdown variant for top navigation bars -->
148
- <bways-report-menu variant="dropdown" />
211
+ export const appConfig: ApplicationConfig = {
212
+ providers: [provideHttpClient(), provideRouter(routes), provideBwaysReport(reportingConfig)],
213
+ };
149
214
  ```
150
215
 
151
- #### Option B: Reactive Signal (`injectReportMenu`)
216
+ The legacy `apiBaseUrl` option remains available. `backendUrl` is not a configuration property.
217
+
218
+ ### Override endpoints for one designer
219
+
220
+ Bind a `BwaysReportApiUrls` object to `[apiUrl]`. Every property is optional. Only supplied properties override the effective page configuration and app defaults; the configuration object and other designer instances stay unchanged.
221
+
152
222
  ```typescript
153
223
  import { Component } from '@angular/core';
154
- import { RouterLink, RouterLinkActive } from '@angular/router';
155
- import { injectReportMenu } from 'bways-report';
224
+ import { BwaysReportApiUrls, DesignerComponent } from 'bways-report';
156
225
 
157
226
  @Component({
227
+ selector: 'app-custom-reports',
158
228
  standalone: true,
159
- imports: [RouterLink, RouterLinkActive],
160
- template: `
161
- <nav class="erp-menu">
162
- @for (group of menu(); track group.groupName) {
163
- <div class="menu-group">
164
- <h3>{{ group.groupName }}</h3>
165
- @for (item of group.items; track item.id) {
166
- <a [routerLink]="item.route" routerLinkActive="active">
167
- {{ item.name }}
168
- </a>
169
- }
170
- </div>
171
- }
172
- </nav>
173
- `,
229
+ imports: [DesignerComponent],
230
+ template: '<rpt-designer [apiUrl]="reportApis" />',
174
231
  })
175
- export class NavigationSidebarComponent {
176
- readonly menu = injectReportMenu();
232
+ export class CustomReportsComponent {
233
+ reportApis: BwaysReportApiUrls = {
234
+ spEndpoint: '/api/custom/procedures',
235
+ // The other URLs inherit reportingConfig defaults.
236
+ };
177
237
  }
178
238
  ```
179
239
 
240
+ You may provide only `tablesEndpoint`, only `reportsEndpoint`, or any combination of `spEndpoint`, `tablesEndpoint`, `executeEndpoint`, `lookupEndpoint`, `reportsEndpoint`, and `apisEndpoint`. Omitted or `undefined` properties inherit defaults. Supplied URLs must be non-empty strings.
241
+
242
+ Overrides apply to discovery, lookups, live preview execution, and persistence inside that designer. Replace the object to change URLs; newly requested data uses the new configuration, and local adapter caches are cleared. Set `[apiUrl]="null"` to restore app defaults. Discovery choices refresh when the bound object changes; existing form selections are retained. Per-designer URLs are not stored in report JSON and do not change separately routed report viewers.
243
+
244
+ `<rpt-report-designer>` and `<rpt-designer-view>` forward the same input. For NgModule applications, import the standalone `DesignerComponent` in your module's `imports` and use the same binding:
245
+
246
+ ```typescript
247
+ @NgModule({ imports: [CommonModule, DesignerComponent] })
248
+ export class ReportsModule {}
249
+ ```
250
+
180
251
  ---
181
252
 
182
- ### Step 5: Declarative Routes (`app.routes.ts`)
253
+ ## 3. Declarative Routes (`app.routes.ts`)
183
254
 
184
- Add one line to your route definitions to enable dynamic live report pages:
255
+ The helper supplies child routes. Mount them below your chosen path:
185
256
 
186
257
  ```typescript
187
- // src/app/app.routes.ts
188
258
  import { Routes } from '@angular/router';
189
259
  import { bwaysReportRoutes } from 'bways-report';
190
- import { AdminReportsComponent } from './pages/admin-reports/admin-reports.component';
191
260
 
192
261
  export const routes: Routes = [
193
- // Admin visual designer route
194
- { path: 'admin/reports', component: AdminReportsComponent },
195
-
196
- // Live user reporting pages: /reports/:slug (e.g. /reports/sale-report)
197
262
  {
198
263
  path: 'reports',
199
- children: bwaysReportRoutes({
200
- // includeBuilderRoute: false, // Set true to include /reports/new and /reports/:slug/edit
201
- }),
264
+ children: bwaysReportRoutes({ includeBuilder: true }),
202
265
  },
203
266
  ];
204
267
  ```
205
268
 
206
- When users click "Sale Report" in the menu, `/reports/sale-report` opens the **live interactive form** with reactive inputs and data grid without needing custom page components!
269
+ This creates `/reports/:slug`, `/reports/new`, and `/reports/:slug/edit`. Builder routes are opt-in. The helper does not create a catalog route; embed `<bways-report-menu>` in your own catalog page if needed. Use `runtimeGuards` and `builderGuards` to apply host access policies, and `slugParam` to customize the identifier parameter. Backend authorization is also required.
207
270
 
208
271
  ---
209
272
 
210
- ## 2. Visual Designer Features
273
+ ## 4. Component Usage Patterns
211
274
 
212
- ### Single-Mode Technical Property Editor
213
- Eliminates confusing simplified/advanced toggles. Standardized on technical database terminology:
214
- - `Database Table / View`
215
- - `Stored Proc`
216
- - `Display Field (Visible Text)`
217
- - `Value Field (Stored Key)`
218
- - `Dependent On (Cascading Parent Field)`
275
+ If you want to embed reports directly inside your existing dashboards or custom pages, use the standalone components:
219
276
 
220
- ### CDK Overlay Viewport Flip
221
- Searchable selects (`<rpt-searchable-select>`) and comboboxes (`<rpt-dropdown>`) render inside Angular CDK Overlays attached to the document body. They automatically evaluate available viewport space and flip between `below-start`, `above-start`, `below-end`, and `above-end` to eliminate clipping inside cards and scrollable drawers.
277
+ ### Pattern A: Embed a Saved Report by ID
222
278
 
223
- ### Post-Save Live Preview & Settings Dialog
224
- Saving a report in the builder automatically opens a two-column modal:
225
- - **Left Column**: Page settings (Display Name, URL Slug `/reports/:slug`, Menu Group, Publish to Menu toggle, and a Copy Route button).
226
- - **Right Column**: Live interactive form preview rendered via `<rpt-runtime>` allowing instant testing of validation and execution before publishing.
279
+ Import `RptReportComponent` from `bways-report` and add it to your standalone component's `imports`. The simplest viewer template is:
227
280
 
228
- ### Inline Double-Click Renaming
229
- Double-click the report title in the toolbar to edit it inline:
230
- - `Enter` saves the new name and suggests a URL slug.
231
- - `Escape` cancels edits.
232
- - `blur` persists the change.
233
- - Changes are pushed to the undo/redo history stack.
281
+ ```html
282
+ <rpt-report [id]="'sales-report-id'" />
283
+ ```
234
284
 
235
- ### Report Switcher & Quick New Page ("+")
236
- - **"+" Button**: Immediately instantiates a fresh blank canvas (with confirmation if unsaved changes exist).
237
- - **Report Switcher**: Dropdown populated from saved reports allowing rapid switching between report definitions.
285
+ The ID is the saved `CNFREPORTDEF.CODE`. The viewer fetches its definition through the configured reporting API, which reads and parses `DEFJSON`; the browser does not connect to SQL Server directly. Configure `provideHttpClient()` and `provideBwaysReport({ reportsEndpoint: '/api/reporting/reports' })` in application or route providers, along with any required execution/session settings. A viewer does not inherit another designer's local `[config]`.
238
286
 
239
- ---
287
+ You can also pass initial parameters and handle row clicks:
240
288
 
241
- ## 3. Backend Contract Reference
289
+ ```html
290
+ <!-- my-dashboard.component.html -->
291
+ <rpt-report
292
+ [id]="'rpt-sales-summary'"
293
+ [parameters]="{ fromDate: '2026-01-01', branchId: 101 }"
294
+ (rowClick)="onRowClick($event)">
295
+ </rpt-report>
296
+ ```
242
297
 
243
- | Endpoint | Method | Path | Request Format | Response Format |
244
- | :--- | :--- | :--- | :--- | :--- |
245
- | `spEndpoint` | `GET` | `/api/reporting/procedures` | None | `StoredProcedureSummary[]` |
246
- | `tablesEndpoint` | `GET` | `/api/reporting/tables` | None | `TableSummary[]` |
247
- | `executeEndpoint` | `POST` | `/api/reporting/execute` | `{ kind, name, schema, parameters, columns?, top? }` | `Record<string, unknown>[]` |
248
- | `reportsEndpoint` *(opt)* | `GET/POST/PUT/DELETE` | `/api/reporting/reports` | JSON `ReportDefinition` | `ReportSummary[]` / `ReportDefinition` |
298
+ ```typescript
299
+ // my-dashboard.component.ts
300
+ import { Component } from '@angular/core';
301
+ import { RptReportComponent } from 'bways-report';
249
302
 
250
- ### Stored Procedure Discovery Format
251
- ```json
252
- [
253
- {
254
- "name": "usp_GetCustomerList",
255
- "schema": "dbo",
256
- "parameters": [
257
- { "name": "@BranchId", "sqlType": "int", "required": true },
258
- { "name": "@SearchTerm", "sqlType": "varchar", "required": false, "defaultValue": "" }
259
- ]
303
+ @Component({
304
+ selector: 'app-my-dashboard',
305
+ standalone: true,
306
+ imports: [RptReportComponent],
307
+ templateUrl: './my-dashboard.component.html',
308
+ })
309
+ export class MyDashboardComponent {
310
+ onRowClick(event: { row: Record<string, unknown> }): void {
311
+ console.log('User clicked invoice row:', event.row);
260
312
  }
261
- ]
313
+ }
262
314
  ```
263
315
 
264
- ### Table Discovery Format
265
- ```json
266
- [
267
- {
268
- "name": "Customers",
269
- "schema": "dbo",
270
- "type": "table",
271
- "columns": [
272
- { "name": "CustomerId", "sqlType": "int" },
273
- { "name": "CustomerName", "sqlType": "nvarchar" }
274
- ]
275
- }
276
- ]
277
- ```
316
+ ---
278
317
 
279
- ### Execution Request Format
280
- Supports both simplified and enterprise DTO contracts out-of-the-box:
281
-
282
- **Option A (Simplified contract):**
283
- ```json
284
- {
285
- "kind": "procedure",
286
- "name": "usp_GetCustomerList",
287
- "schema": "dbo",
288
- "parameters": {
289
- "BranchId": 1,
290
- "SearchTerm": "Acme"
291
- }
318
+ ### Pattern B: Embed from In-Memory JSON
319
+
320
+ If your host project retrieves the report definition from its own custom service, database table, or static JSON file, pass the object directly:
321
+
322
+ ```html
323
+ @if (reportSchema) {
324
+ <rpt-report [report]="reportSchema"></rpt-report>
292
325
  }
293
326
  ```
294
327
 
295
- **Option B (Enterprise DTO contract):**
296
- ```json
297
- {
298
- "dataSource": {
299
- "id": "usp_GetCustomerList",
300
- "type": "stored_procedure",
301
- "name": "usp_GetCustomerList",
302
- "schema": "dbo"
303
- },
304
- "parameters": {
305
- "BranchId": 1
306
- },
307
- "sessionContext": {
308
- "companyId": 101,
309
- "branchId": 1
328
+ ```typescript
329
+ import { Component, OnInit, inject } from '@angular/core';
330
+ import { RptReportComponent, ReportDefinition } from 'bways-report';
331
+ import { MyCustomApiService } from './my-custom-api.service';
332
+
333
+ @Component({
334
+ standalone: true,
335
+ imports: [RptReportComponent],
336
+ template: `@if (reportSchema) { <rpt-report [report]="reportSchema" /> }`
337
+ })
338
+ export class CustomReportLoaderComponent implements OnInit {
339
+ private api = inject(MyCustomApiService);
340
+ reportSchema: ReportDefinition | null = null;
341
+
342
+ ngOnInit(): void {
343
+ this.api.fetchReportFromCustomDb('rpt-sales').subscribe((data) => {
344
+ // If data is stored as JSON text, parse it:
345
+ this.reportSchema = typeof data === 'string' ? JSON.parse(data) : data;
346
+ });
310
347
  }
311
348
  }
312
349
  ```
313
350
 
314
- ### Dropdown Lookup Request Format (`lookupEndpoint`)
315
- Dropdowns with database data sources query `/api/reporting/lookup` (or fallback to `executeEndpoint`):
316
- ```json
317
- {
318
- "entityName": "Sel_UserWiseCompUnit",
319
- "sourceType": "stored_procedure",
320
- "schema": "dbo",
321
- "valueField": "COMPUNIT_ID",
322
- "displayField": "COMPUNIT_NAME",
323
- "parameters": {}
324
- }
351
+ ---
352
+
353
+ ### Pattern C: Embed the Visual Designer
354
+
355
+ Import `DesignerComponent` and `BwaysReportConfig` from `bways-report`. Add `DesignerComponent` to your standalone component's `imports`, or to the `imports` of your NgModule. These template bindings are component inputs, not additional Angular modules. Keep the page's configuration in its TypeScript file:
356
+
357
+ ```typescript
358
+ // Inside the host component class.
359
+ readonly designerConfig: BwaysReportConfig = {
360
+ reportsEndpoint: '/api/reporting/reports',
361
+ // Add discovery, execution, lookup and session settings as required.
362
+ };
325
363
  ```
326
364
 
327
- ---
365
+ Give the host a definite height, for example `height: calc(100dvh - 64px)`, plus `display: flex; flex-direction: column; min-height: 0`. Inside an existing bounded flex layout, use `flex: 1; height: 100%; min-height: 0` on the page wrapper so canvas, preview and JSON can scroll. Register `provideHttpClient()` once in the application.
328
366
 
329
- ## 4. Dynamic Session Context & Auto-Parameter Binding
367
+ #### Template 1: Automatic database-backed report selector
330
368
 
331
- When `autoParameter: true` is configured, parameters matching active ERP session keys are automatically populated and hidden from non-technical users:
369
+ ```html
370
+ <!-- rpt-designer.component.html -->
371
+ <rpt-designer
372
+ [config]="designerConfig"
373
+ (save)="onReportSaved($event)"
374
+ />
375
+ ```
332
376
 
333
- | Stored Procedure Parameter | Matching Session Keys |
334
- | :--- | :--- |
335
- | `@BranchId`, `@branch_id`, `@bid`, `@branchcode`, `@locationid` | `branchId`, `branch`, `locationId` |
336
- | `@CompanyId`, `@company_id`, `@cid`, `@companycode`, `@tenantid` | `companyId`, `company`, `tenantId` |
337
- | `@UserId`, `@user_id`, `@uid`, `@usercode`, `@operatorid` | `userId`, `user`, `loginUser` |
338
- | `@FinancialYearId`, `@fyear`, `@fiscalyear`, `@yearid` | `financialYearId`, `fYear` |
377
+ The built-in toolbar selector requests `GET /api/reporting/reports` and displays the returned report summaries. Selecting an entry requests `GET /api/reporting/reports/:id`, where `id` maps to `CNFREPORTDEF.CODE`. The backend returns the parsed `DEFJSON` with authoritative ID, name and version metadata. These routes follow your configured `reportsEndpoint`.
378
+
379
+ To initially open a particular saved report, add `[reportId]`:
380
+
381
+ ```html
382
+ <rpt-designer
383
+ [config]="designerConfig"
384
+ [reportId]="'sales-report-id'"
385
+ (save)="onReportSaved($event)"
386
+ />
387
+ ```
388
+
389
+ #### Template 2: Host supplies the selected report definition
390
+
391
+ Use this when your application already fetches the saved report through its own service:
339
392
 
340
- Session values can be updated at runtime:
341
393
  ```typescript
342
- import { inject } from '@angular/core';
343
- import { ReportSessionContextService } from 'bways-report';
394
+ // Import ReportDefinition from bways-report.
395
+ selectedReport: ReportDefinition | null = null;
396
+ // Assign the parsed, validated report returned by your host service.
397
+ ```
398
+
399
+ ```html
400
+ @if (selectedReport) {
401
+ <rpt-designer
402
+ [config]="designerConfig"
403
+ [initialReport]="selectedReport"
404
+ (save)="onReportSaved($event)"
405
+ />
406
+ }
407
+ ```
408
+
409
+ `[initialReport]` accepts a complete `ReportDefinition` object, not a raw SQL row or an unparsed `DEFJSON` string. If your API returns `DEFJSON` as text, parse and validate it in your service and handle invalid JSON before assigning it. The standard backend already returns a parsed object. Use either `[reportId]` or `[initialReport]` as the loading source; when both are supplied, a non-null `[initialReport]` takes precedence.
410
+
411
+ This supported template controls the selected definition; it does not replace the library toolbar's report list. The built-in list still uses `reportsEndpoint`.
412
+
413
+ #### Planned host-controlled toolbar API (not implemented)
414
+
415
+ The following is a proposed extension for applications that also want to supply the toolbar list and handle selection themselves. It will not compile with the current library:
416
+
417
+ ```html
418
+ <!-- Proposed API only: reports and reportSelected are not available yet. -->
419
+ <rpt-designer
420
+ [config]="designerConfig"
421
+ [reports]="savedReports"
422
+ [initialReport]="selectedReport"
423
+ (reportSelected)="loadReport($event)"
424
+ (save)="onReportSaved($event)"
425
+ />
426
+ ```
427
+
428
+ Under this proposal, `savedReports` would contain `ReportSummary[]`, and `loadReport(reportId: string)` would retrieve the selected definition. Full report JSON would be fetched only after selection. There is currently no `[reportState]` input; use the supported `[initialReport]` input for a parsed definition.
429
+
430
+ For both supported templates, `(save)` runs only after successful persistence. Use the handler for notifications or refreshing host data; do not save the same report a second time. Existing IDs require Update or Cancel confirmation before writing.
431
+
432
+ ---
433
+
434
+ ### Pattern D: Toggle View / Edit on the Same Page
344
435
 
345
- export class SessionWidget {
346
- private readonly session = inject(ReportSessionContextService);
436
+ You can allow administrators to view a report and switch to edit mode on the same screen:
347
437
 
348
- onBranchSwitch(branchId: number): void {
349
- this.session.setSessionParameter('branchId', branchId);
438
+ ```html
439
+ <div class="toolbar">
440
+ @if (isAdmin) {
441
+ <button (click)="isEditMode = !isEditMode">
442
+ {{ isEditMode ? 'Exit Designer (View Mode)' : 'Edit Layout (Designer)' }}
443
+ </button>
350
444
  }
445
+ </div>
446
+
447
+ @if (isEditMode) {
448
+ <rpt-designer [reportId]="reportId" (save)="isEditMode = false"></rpt-designer>
449
+ } @else {
450
+ <rpt-report [id]="reportId"></rpt-report>
351
451
  }
352
452
  ```
353
453
 
354
454
  ---
355
455
 
356
- ## 5. Plugging in BWays-Grid (`UltraGridComponent`)
456
+ ## 5. Database Persistence & SQL Schema
457
+
458
+ Reports are stored in `dbo.CNFREPORTDEF`. The backend creates this table at startup when it is absent. Its `dbo` alias types must already be installed in the target ERP database.
459
+
460
+ `UTypeLongText1` must be valid for the `CODE` primary key. The complete report JSON needs `DEFJSON nvarchar(max)`: a finite ERP text alias cannot hold a full definition. Startup widens only this column for existing installations; the shared ERP alias types are retained. Other metadata respects the actual column limits (for example, `NAME` may allow only 10 characters). Oversized values produce a clear error in the review dialog without losing the draft.
461
+
462
+ ```sql
463
+ IF OBJECT_ID(N'dbo.CNFREPORTDEF', N'U') IS NULL
464
+ BEGIN
465
+ CREATE TABLE [dbo].[CNFREPORTDEF] (
466
+ [CODE] [dbo].[UTypeLongText1] PRIMARY KEY,
467
+ [NAME] [dbo].[UTypeShortText1] NULL,
468
+ [DESCRIPTION] [dbo].[UTypeLongText1] NULL,
469
+ [VERSION] [int] NULL,
470
+ [STATUS_CODE] [int] NULL,
471
+ [DEFJSON] nvarchar(max) NULL,
472
+ [SYSADD_DATETIME] [dbo].[UTypeDateTime] NULL,
473
+ [SYSCHNG_DATETIME] [dbo].[UTypeDateTime] NULL,
474
+ [SYSADD_LOGIN] [dbo].[UTypeUserLogin] NULL,
475
+ [SYSCHNG_LOGIN] [dbo].[UTypeUserLogin] NULL
476
+ );
477
+ END;
478
+ ```
479
+
480
+ The HTTP API keeps using `id`, `name`, `description`, `version`, `isPublished` and the complete report object. The backend maps these to `CODE`, `NAME`, `DESCRIPTION`, `VERSION`, `STATUS_CODE` and `DEFJSON`. Only `STATUS_CODE = 1` means published; `0` or `NULL` is treated as draft. Category, slug, layout, components and data sources stay in `DEFJSON`.
357
481
 
358
- `BWays-Report` provides first-class support for `bways-grid` (`v0.1.18+` / `v0.1.19+`). Pass `grid: UltraGridComponent` to `provideBwaysReport()`:
482
+ Creation fills both audit timestamps and login columns; updates and publication preserve creation audit values and change only `SYSCHNG_*`. Audit logins come from the backend authorization policy's `userLogin`, or remain `NULL` if no authenticated login is supplied.
359
483
 
360
- - **Runtime `@Input()` Safety**: Dynamic grid bridging inspects component metadata (`ɵcmp.inputs`) before calling `ComponentRef.setInput()`, preventing Angular `NG0303` runtime template binding errors.
361
- - **Row Selection Alignment**: Row selection mode (`single` vs `multiple`) is passed cleanly through `config.rowSelection` and `config.selectionMode`, preserving full compatibility with `UltraGridComponent`.
362
- - **Circular Echo Suppression**: Grid state changes originating from user interaction are tracked to avoid re-triggering parent input cycles. Column menus, search inputs, and drag-handles stay open and focused without flicker.
363
- - **Filter State Preservation**: Preserves both `activeFilters` (checkboxes) and `conditionFilters` (expressions) across runtime updates and JSON serialization.
364
- - **Selective Layout Auto-Persistence**: Structural layout changes (column widths, pinning, grouping) persist immediately, while interactive data filtering is debounced to avoid undo stack pollution.
484
+ For existing installations, run [create-report-definitions.sql](../../backend/sql/create-report-definitions.sql), then [migrate-report-definitions.sql](../../backend/sql/migrate-report-definitions.sql) in each intended ERP database. Migration copies missing records from the legacy tables, retains category in JSON, and preserves existing target records and source tables. It is not run automatically on server startup.
365
485
 
366
486
  ---
367
487
 
368
- ## 6. Advanced Custom Adapters
488
+ ## 6. Save Confirmation & Host Notifications
489
+
490
+ Clicking **Save** opens a review dialog before any write. Review the report ID, name, slug, description, category, menu group and publication status, then choose **Save Report** or **Save and Open**. Cancel leaves the draft unchanged. Each save makes a fresh ID check. If the ID exists, a confirmation panel identifies the saved report and version and offers **Update Report** (or **Update and Open**) and **Cancel**. No write occurs before Update. Cancel returns to the review with all entered details intact. During saving the controls are disabled; errors keep the dialog open for retry. Success and navigation happen only after the server confirms storage.
491
+
492
+ The **Report ID** field accepts a custom ID (up to 100 letters, numbers, underscores or hyphens; start with a letter or number). **Random ID** generates a new value, and **Verify ID** checks for duplicates in the designer's configured storage and company. Editing the ID clears its verification result. Every save checks the ID again, including unchanged IDs and IDs previously checked with Verify ID. Failed verification keeps the draft open and performs no write.
493
+
494
+ An available ID creates a new report using a create-only write. Any existing ID, including the original ID or an occupied custom ID, requires explicit update confirmation. Choosing an available custom ID leaves the original intact; review the URL slug for the new copy too. The bundled backend returns HTTP 409 if a new ID is taken after the check, or if a confirmed update targets a report that changed version or was deleted. The draft remains available and another save requires a fresh check and confirmation.
495
+
496
+ The persistence adapter supplies `checkId(id): Observable<boolean>` for Verify ID and `inspectId(id): Observable<ReportIdStatus>` for save confirmation (`exists`, optional `name` and `version`). Existing host adapters inherit catalog-based fallbacks. Built-in HTTP adapters use `GET /reports/:id/availability`; the bundled backend returns the name/version in this compact response without fetching report JSON. A 404 falls back to the catalog; older responses without a version require a read of that report. Verification does not select another report or replace the draft. Other failures never mean that an ID is available.
497
+
498
+ Custom hosts should honor `save(report, { createOnly: true })` for new IDs and `save(report, { expectedVersion })` for confirmed updates. The latter must update only an existing report at that version and reject missing/changed targets atomically. These options are mutually exclusive. Older hosts that ignore them cannot provide concurrency protection. Pending confirmations are invalidated if the ID or endpoint/session context changes.
369
499
 
370
- For applications with custom HTTP pipelines, gRPC, or microservice gateways, extend the library's abstract contracts:
500
+ The designer's `(save)` output is a notification containing the server-confirmed report, including its version. Do not persist it again in the handler:
501
+
502
+ ```html
503
+ <rpt-designer (save)="onReportSaved($event)"></rpt-designer>
504
+ ```
371
505
 
372
506
  ```typescript
373
- provideBwaysReport({
374
- gridComponent: UltraGridComponent,
375
- dataSourceAdapter: MyCustomDataSourceAdapter,
376
- persistenceAdapter: MyCustomPersistenceAdapter,
377
- schemaDiscoveryAdapter: MyCustomSchemaDiscoveryAdapter,
378
- lookupAdapter: MyCustomLookupAdapter,
379
- });
507
+ onReportSaved(report: ReportDefinition): void {
508
+ this.currentReport = report;
509
+ }
380
510
  ```
381
511
 
382
- Abstract base classes:
383
- - `ReportDataSourceAdapter`
384
- - `ReportPersistenceAdapter`
385
- - `ReportSchemaDiscoveryAdapter`
386
- - `ReportLookupAdapter`
512
+ The built-in backend handles inserts and updates in `CNFREPORTDEF`; no host save handler is needed. For a different backend contract, provide your own `ReportPersistenceAdapter` implementing load, save, list, delete and publish. Its save method must return the persisted report or propagate the failure. Browser storage remains available only through explicit `withLocalStorage()` for offline development.
513
+
514
+ ### Export to `.json` File (Git & Version Control)
515
+ In the designer toolbar, click the **JSON** tab and choose **Download / Export JSON**. This generates a `.json` file that can be committed to Git, reviewed, or imported into staging/production environments.
387
516
 
388
517
  ---
389
518
 
390
- ## 7. Theming & CSS Custom Properties
391
-
392
- `bways-report` uses Vanilla CSS custom properties. Customize the tokens in your application's `styles.css`:
393
-
394
- ```css
395
- :root {
396
- --rpt-color-primary: #2563eb;
397
- --rpt-color-primary-hover: #1d4ed8;
398
- --rpt-color-bg: #ffffff;
399
- --rpt-color-surface: #f8fafc;
400
- --rpt-color-text: #0f172a;
401
- --rpt-color-text-muted: #64748b;
402
- --rpt-color-border: #cbd5e1;
403
- --rpt-font-family: 'Inter', system-ui, sans-serif;
404
- --rpt-border-radius: 6px;
405
- --rpt-border-radius-lg: 8px;
406
- }
519
+ ## 7. Data Grid & UltraGrid Integration
407
520
 
408
- [data-theme='dark'] {
409
- --rpt-color-bg: #0f172a;
410
- --rpt-color-surface: #1e293b;
411
- --rpt-color-text: #f8fafc;
412
- --rpt-color-text-muted: #94a3b8;
413
- --rpt-color-border: #334155;
414
- }
415
- ```
521
+ `bways-report` includes a responsive built-in data table. To use the high-performance **UltraGrid** from `bways-grid` (virtual scrolling, Excel-like column filters, column pinning, summary rows):
522
+
523
+ 1. Install `bways-grid`:
524
+ ```bash
525
+ npm install bways-grid
526
+ ```
527
+ 2. Pass `UltraGridComponent` to `provideBwaysReport()`:
528
+ ```typescript
529
+ import { UltraGridComponent } from 'bways-grid';
530
+ import { provideBwaysReport } from 'bways-report';
531
+ import { reportingConfig } from './config';
532
+
533
+ provideBwaysReport({
534
+ ...reportingConfig,
535
+ grid: UltraGridComponent, // Uses UltraGrid for all reports
536
+ })
537
+ ```
416
538
 
417
539
  ---
418
540
 
419
- ## 8. Exporting Data (CSV & JSON)
541
+ ## 8. Backend API Contract
420
542
 
421
- Inject `ReportExportService` in any host component:
543
+ The reporting engine communicates with the backend via these REST endpoints:
422
544
 
423
- ```typescript
424
- import { Component, inject } from '@angular/core';
425
- import { ReportExportService } from 'bways-report';
426
-
427
- @Component({ ... })
428
- export class ExportComponent {
429
- private readonly exportService = inject(ReportExportService);
430
-
431
- onExportCsv(data: unknown[]): void {
432
- this.exportService.exportCsv(data, {
433
- fileName: 'sales-register.csv',
434
- columns: [
435
- { field: 'invoiceNo', header: 'Invoice #' },
436
- { field: 'amount', header: 'Amount' },
437
- ],
438
- addBom: true, // UTF-8 Excel compatibility
439
- });
440
- }
441
- }
442
- ```
545
+ | Endpoint | Method | Purpose | Payload / Response |
546
+ | :--- | :--- | :--- | :--- |
547
+ | `/api/reporting/procedures` | `GET` | Discovers available stored procedures & parameters | Returns `StoredProcedureSummary[]` |
548
+ | `/api/reporting/tables` | `GET` | Discovers database tables, views, and columns | Returns `TableSummary[]` |
549
+ | `/api/reporting/execute` | `POST` | Executes stored procedure or query with form values | Accepts `{ kind, name, parameters }`, returns `Record<string, unknown>[]` |
550
+ | `/api/reporting/reports` | `GET` | Lists all saved report summaries from database | Returns `ReportSummary[]` |
551
+ | `/api/reporting/reports/:id`| `GET` | Fetches single `ReportDefinition` JSON by ID | Returns `ReportDefinition` |
552
+ | `/api/reporting/reports` | `POST`| Inserts/updates `CNFREPORTDEF` | Accepts `{ id, name, definition }` |
553
+ | `/api/reporting/lookup` | `POST` | Fetches dynamic dropdown master data | Accepts `{ table, valueField, displayField }` |
443
554
 
444
555
  ---
445
556
 
446
557
  ## License
447
558
 
448
- Proprietary License. Copyright (c) 2026 CCPL / BWays Team. All rights reserved.
559
+ This package is proprietary software. Copyright (c) 2026 CCPL / BWays Team. All rights reserved.
560
+
561
+
562
+ ## Reliability and security configuration
563
+
564
+ API data sources forward session credentials, session headers and custom headers only to the application's own origin or an explicitly trusted origin. Public external APIs can still be called without these headers. Cross-origin forwarding requires an exact origin, including the port, configured by the host; report JSON cannot grant this permission. Session secrets interpolated into untrusted URL/body parameters are rejected. Host authentication interceptors must enforce their own matching destination policy.
565
+
566
+ ```typescript
567
+ readonly designerConfig: BwaysReportConfig = {
568
+ reportsEndpoint: '/api/reporting/reports',
569
+ executeEndpoint: '/api/reporting/execute',
570
+ trustedApiOrigins: ['https://trusted-api.example.com:9443'],
571
+ lookupTimeoutMs: 300000,
572
+ executionTimeoutMs: 60000,
573
+ };
574
+ ```
575
+
576
+ The same settings can be application defaults in `provideBwaysReport(...)`. Page-local settings remain isolated. Use origins without paths, trailing slashes, embedded credentials or wildcards. `executionTimeoutMs` controls execution requests; when omitted it follows the configured lookup timeout. Client timeouts unsubscribe requests; database command timeouts remain a separate backend setting.
577
+
578
+ Loading, switching, execution and drill-down cancel superseded requests and reject late results from an earlier session/endpoint context. Closing a drawer or destroying a component cancels its pending work. The report selector exposes loading, empty and retryable error states. Report definitions are checked before rendering; legacy omitted collections are normalized, while malformed structures and unsupported schema versions produce errors.
579
+
580
+ Viewer preset save/delete operations use `expectedVersion` and update the local report/version only after successful storage. Conflicts retain the current view and show an error. These are report-level shared presets; applications needing private per-user presets should provide separate user-scoped storage rather than embedding them in shared report JSON. Custom persistence adapters must implement atomic version checks.
581
+
582
+ For table/view execution, the data source can specify a projection, row limit and explicit equality filters:
583
+
584
+ ```typescript
585
+ const dataSource: ReportDataSourceDefinition = {
586
+ id: 'sales', name: 'Sales', endpoint: 'Sales', type: 'table', schema: 'dbo',
587
+ columns: ['InvoiceNo', 'Total', 'BranchId'],
588
+ top: 500,
589
+ filter: { BranchId: '{{session.branchId}}' },
590
+ };
591
+ ```
592
+
593
+ The adapter sends `columns`, `top` and resolved `filter` values to the execution API. Unmapped form parameters are not automatically treated as SQL column names. The supplied backend defaults table/view results to 1,000 rows and caps requests at 10,000; lookups default to 500. Table/view limits run inside SQL. Stored procedure results are capped in the response; expensive procedures should implement their own SQL-side paging/limits.
594
+
595
+ Generic backend execution preserves supplied values and leaves omitted procedure arguments for SQL Server to handle. ERP-specific synthetic defaults, flag coercions and legacy fallback behavior require the explicit `legacyErpDefaults` option. See the [backend compatibility settings](../../backend/README.md#query-limits-and-erp-compatibility).