bways-report 0.1.6 → 0.1.7
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.
- package/README.md +293 -464
- package/esm2022/lib/core/config/bways-report-config.mjs +83 -0
- package/esm2022/lib/core/index.mjs +2 -1
- package/esm2022/lib/core/models/report-definition.model.mjs +1 -1
- package/esm2022/lib/core/services/report-data-discovery.service.mjs +6 -3
- package/esm2022/lib/core/services/report-session-context.service.mjs +11 -7
- package/esm2022/lib/core/tokens/reporting-config.token.mjs +1 -1
- package/esm2022/lib/core/utils/data-normalization.util.mjs +87 -1
- package/esm2022/lib/core/utils/report-parameter.util.mjs +119 -3
- package/esm2022/lib/data-access/adapters/endpoint-datasource.adapter.mjs +69 -0
- package/esm2022/lib/data-access/adapters/endpoint-lookup.adapter.mjs +98 -0
- package/esm2022/lib/data-access/adapters/endpoint-masterdata.adapter.mjs +57 -0
- package/esm2022/lib/data-access/adapters/endpoint-persistence.adapter.mjs +85 -0
- package/esm2022/lib/data-access/adapters/endpoint-schema-discovery.adapter.mjs +163 -0
- package/esm2022/lib/data-access/adapters/endpoint-tokens.mjs +12 -0
- package/esm2022/lib/data-access/adapters/http-lookup.adapter.mjs +4 -23
- package/esm2022/lib/data-access/adapters/index.mjs +8 -1
- package/esm2022/lib/data-access/contracts/lookup.contract.mjs +1 -1
- package/esm2022/lib/features/designer/components/component-palette/component-palette.component.mjs +12 -2
- package/esm2022/lib/features/designer/components/design-canvas/design-canvas.component.mjs +5 -5
- package/esm2022/lib/features/designer/components/dialogs/report-saved-dialog.component.mjs +407 -0
- package/esm2022/lib/features/designer/components/property-editor/parameter-binding-editor.component.mjs +109 -60
- package/esm2022/lib/features/designer/components/property-editor/property-editor-action.component.mjs +3 -3
- package/esm2022/lib/features/designer/components/property-editor/property-editor-datasource.component.mjs +110 -20
- package/esm2022/lib/features/designer/components/property-editor/property-editor-general.component.mjs +3 -3
- package/esm2022/lib/features/designer/components/property-editor/property-editor-grid.component.mjs +60 -3
- package/esm2022/lib/features/designer/components/property-editor/property-editor-layout.component.mjs +11 -5
- package/esm2022/lib/features/designer/components/property-editor/property-editor-report.component.mjs +3 -3
- package/esm2022/lib/features/designer/components/property-editor/property-editor-validation.component.mjs +15 -3
- package/esm2022/lib/features/designer/components/toolbar/designer-toolbar.component.mjs +204 -10
- package/esm2022/lib/features/designer/designer.component.mjs +43 -2
- package/esm2022/lib/features/designer/services/designer-state.service.mjs +9 -2
- package/esm2022/lib/features/embed/bways-report-builder.component.mjs +207 -0
- package/esm2022/lib/features/embed/bways-report-menu.component.mjs +433 -0
- package/esm2022/lib/features/embed/bways-report-page.component.mjs +204 -0
- package/esm2022/lib/features/embed/index.mjs +5 -0
- package/esm2022/lib/features/embed/inject-report-menu.mjs +99 -0
- package/esm2022/lib/features/index.mjs +2 -1
- package/esm2022/lib/features/persistence/services/report-store.service.mjs +43 -5
- package/esm2022/lib/features/routing/components/routed-report-runtime.component.mjs +4 -4
- package/esm2022/lib/features/routing/index.mjs +2 -2
- package/esm2022/lib/features/routing/models/report-route.models.mjs +1 -1
- package/esm2022/lib/features/routing/report-routes.mjs +42 -1
- package/esm2022/lib/features/routing/resolvers/report.resolver.mjs +6 -8
- package/esm2022/lib/features/routing/services/report-menu.service.mjs +14 -4
- package/esm2022/lib/features/runtime/dynamic-renderer.component.mjs +22 -3
- package/esm2022/lib/features/runtime/report-grid-bridge.component.mjs +16 -2
- package/esm2022/lib/primitives/components/button/rpt-button.component.mjs +28 -5
- package/esm2022/lib/primitives/components/dropdown/rpt-dropdown.component.mjs +86 -19
- package/esm2022/lib/primitives/components/icon/rpt-icon.component.mjs +8 -1
- package/esm2022/lib/primitives/components/index.mjs +2 -1
- package/esm2022/lib/primitives/components/number/rpt-number.component.mjs +9 -3
- package/esm2022/lib/primitives/components/searchable-select/rpt-searchable-select.component.mjs +386 -0
- package/esm2022/lib/provide-reporting.mjs +137 -7
- package/fesm2022/bways-report.mjs +4053 -840
- package/fesm2022/bways-report.mjs.map +1 -1
- package/lib/core/config/bways-report-config.d.ts +161 -0
- package/lib/core/index.d.ts +1 -0
- package/lib/core/models/report-definition.model.d.ts +16 -0
- package/lib/core/services/report-session-context.service.d.ts +1 -0
- package/lib/core/tokens/reporting-config.token.d.ts +16 -0
- package/lib/core/utils/data-normalization.util.d.ts +10 -0
- package/lib/core/utils/report-parameter.util.d.ts +18 -1
- package/lib/data-access/adapters/endpoint-datasource.adapter.d.ts +13 -0
- package/lib/data-access/adapters/endpoint-lookup.adapter.d.ts +14 -0
- package/lib/data-access/adapters/endpoint-masterdata.adapter.d.ts +11 -0
- package/lib/data-access/adapters/endpoint-persistence.adapter.d.ts +15 -0
- package/lib/data-access/adapters/endpoint-schema-discovery.adapter.d.ts +21 -0
- package/lib/data-access/adapters/endpoint-tokens.d.ts +21 -0
- package/lib/data-access/adapters/index.d.ts +7 -0
- package/lib/data-access/contracts/lookup.contract.d.ts +2 -2
- package/lib/features/designer/components/component-palette/component-palette.component.d.ts +1 -0
- package/lib/features/designer/components/design-canvas/design-canvas.component.d.ts +1 -1
- package/lib/features/designer/components/dialogs/report-saved-dialog.component.d.ts +34 -0
- package/lib/features/designer/components/property-editor/parameter-binding-editor.component.d.ts +1 -0
- package/lib/features/designer/components/property-editor/property-editor-datasource.component.d.ts +12 -2
- package/lib/features/designer/components/property-editor/property-editor-grid.component.d.ts +10 -0
- package/lib/features/designer/components/toolbar/designer-toolbar.component.d.ts +13 -1
- package/lib/features/designer/designer.component.d.ts +4 -0
- package/lib/features/embed/bways-report-builder.component.d.ts +48 -0
- package/lib/features/embed/bways-report-menu.component.d.ts +40 -0
- package/lib/features/embed/bways-report-page.component.d.ts +61 -0
- package/lib/features/embed/index.d.ts +4 -0
- package/lib/features/embed/inject-report-menu.d.ts +44 -0
- package/lib/features/index.d.ts +1 -0
- package/lib/features/persistence/services/report-store.service.d.ts +5 -0
- package/lib/features/routing/index.d.ts +1 -1
- package/lib/features/routing/models/report-route.models.d.ts +3 -0
- package/lib/features/routing/report-routes.d.ts +40 -0
- package/lib/features/routing/resolvers/report.resolver.d.ts +1 -1
- package/lib/features/runtime/dynamic-renderer.component.d.ts +1 -0
- package/lib/features/runtime/report-grid-bridge.component.d.ts +1 -1
- package/lib/primitives/components/button/rpt-button.component.d.ts +3 -0
- package/lib/primitives/components/dropdown/rpt-dropdown.component.d.ts +16 -3
- package/lib/primitives/components/index.d.ts +2 -0
- package/lib/primitives/components/searchable-select/rpt-searchable-select.component.d.ts +89 -0
- package/lib/provide-reporting.d.ts +22 -6
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,605 +1,441 @@
|
|
|
1
1
|
# BWays-Report — Integration & Developer Guide
|
|
2
2
|
|
|
3
|
-
`bways-report` is an enterprise
|
|
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.
|
|
4
4
|
|
|
5
|
-
It
|
|
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.
|
|
6
6
|
|
|
7
7
|
---
|
|
8
8
|
[](https://www.npmjs.com/package/bways-report)
|
|
9
|
-
[](LICENSE)
|
|
10
|
+
[](CHANGELOG.md)
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## What's New in v0.2.0
|
|
14
|
+
|
|
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.
|
|
23
|
+
|
|
11
24
|
---
|
|
12
25
|
|
|
13
26
|
## Table of Contents
|
|
14
27
|
|
|
15
|
-
1. [
|
|
16
|
-
|
|
17
|
-
- [
|
|
18
|
-
- [
|
|
19
|
-
- [
|
|
20
|
-
- [
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
- [
|
|
24
|
-
- [
|
|
25
|
-
- [
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
12. [Changelog & Version History](#12-changelog--version-history)
|
|
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)
|
|
34
46
|
|
|
35
47
|
---
|
|
36
48
|
|
|
37
|
-
## 1.
|
|
49
|
+
## 1. Quick Start (5 Steps)
|
|
38
50
|
|
|
39
|
-
|
|
51
|
+
### Step 1: Install
|
|
40
52
|
|
|
41
53
|
```bash
|
|
42
|
-
|
|
54
|
+
npm install bways-report bways-grid @angular/cdk
|
|
43
55
|
```
|
|
44
56
|
|
|
45
|
-
|
|
57
|
+
> **Compatibility**: Angular 18+ or 19+ standalone architecture with Zone.js or Zoneless change detection.
|
|
46
58
|
|
|
47
59
|
---
|
|
48
60
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
### A. 1-Line App Setup
|
|
61
|
+
### Step 2: Configure Once (`app.config.ts`)
|
|
52
62
|
|
|
53
|
-
|
|
63
|
+
Configure `provideBwaysReport()` with a single `BwaysReportConfig` object:
|
|
54
64
|
|
|
55
65
|
```typescript
|
|
56
66
|
// src/app/app.config.ts
|
|
57
|
-
import { ApplicationConfig } from '@angular/core';
|
|
58
|
-
import {
|
|
67
|
+
import { ApplicationConfig, provideZoneChangeDetection } from '@angular/core';
|
|
68
|
+
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
|
+
};
|
|
59
93
|
|
|
60
94
|
export const appConfig: ApplicationConfig = {
|
|
61
95
|
providers: [
|
|
62
|
-
|
|
63
|
-
|
|
96
|
+
provideZoneChangeDetection({ eventCoalescing: true }),
|
|
97
|
+
provideHttpClient(),
|
|
98
|
+
provideRouter(routes),
|
|
99
|
+
provideBwaysReport(reportConfig),
|
|
64
100
|
],
|
|
65
101
|
};
|
|
66
102
|
```
|
|
67
103
|
|
|
68
|
-
> **Zero-Backend / Local Storage Mode:**
|
|
69
|
-
> For local prototyping, offline demos, or frontend-only dev, use:
|
|
70
|
-
> ```typescript
|
|
71
|
-
> provideReporting(withLocalStorage()); // seeds built-in blueprints and saves to browser localStorage
|
|
72
|
-
> ```
|
|
73
|
-
|
|
74
104
|
---
|
|
75
105
|
|
|
76
|
-
###
|
|
106
|
+
### Step 3: Drop-in Builder Component
|
|
77
107
|
|
|
78
|
-
|
|
108
|
+
Embed the full visual drag-and-drop report designer with one HTML tag:
|
|
109
|
+
|
|
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
|
+
```
|
|
79
118
|
|
|
80
119
|
```typescript
|
|
120
|
+
// src/app/pages/admin-reports/admin-reports.component.ts
|
|
81
121
|
import { Component } from '@angular/core';
|
|
82
|
-
import {
|
|
122
|
+
import { BwaysReportBuilderComponent, ReportDefinition } from 'bways-report';
|
|
83
123
|
|
|
84
124
|
@Component({
|
|
85
125
|
standalone: true,
|
|
86
|
-
imports: [
|
|
87
|
-
|
|
88
|
-
<!-- 1 tag to run and render the full report page -->
|
|
89
|
-
<rpt-report [id]="'sales-ledger'" />
|
|
90
|
-
`,
|
|
126
|
+
imports: [BwaysReportBuilderComponent],
|
|
127
|
+
templateUrl: './admin-reports.component.html',
|
|
91
128
|
})
|
|
92
|
-
export class
|
|
129
|
+
export class AdminReportsComponent {
|
|
130
|
+
onReportSaved(report: ReportDefinition): void {
|
|
131
|
+
console.log('Report saved and published:', report.name, report.slug);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
93
134
|
```
|
|
94
135
|
|
|
95
136
|
---
|
|
96
137
|
|
|
97
|
-
###
|
|
138
|
+
### Step 4: Host Navigation Menu
|
|
139
|
+
|
|
140
|
+
Display published reports in your host ERP navigation bar or sidebar:
|
|
98
141
|
|
|
99
|
-
|
|
142
|
+
#### Option A: Drop-in Component
|
|
143
|
+
```html
|
|
144
|
+
<!-- Sidebar variant with search filter and category folding -->
|
|
145
|
+
<bways-report-menu variant="sidebar" />
|
|
100
146
|
|
|
147
|
+
<!-- Or dropdown variant for top navigation bars -->
|
|
148
|
+
<bways-report-menu variant="dropdown" />
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
#### Option B: Reactive Signal (`injectReportMenu`)
|
|
101
152
|
```typescript
|
|
102
153
|
import { Component } from '@angular/core';
|
|
103
|
-
import {
|
|
154
|
+
import { RouterLink, RouterLinkActive } from '@angular/router';
|
|
155
|
+
import { injectReportMenu } from 'bways-report';
|
|
104
156
|
|
|
105
157
|
@Component({
|
|
106
158
|
standalone: true,
|
|
107
|
-
imports: [
|
|
159
|
+
imports: [RouterLink, RouterLinkActive],
|
|
108
160
|
template: `
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
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>
|
|
114
173
|
`,
|
|
115
174
|
})
|
|
116
|
-
export class
|
|
117
|
-
|
|
118
|
-
console.log('Report saved successfully:', definition);
|
|
119
|
-
}
|
|
175
|
+
export class NavigationSidebarComponent {
|
|
176
|
+
readonly menu = injectReportMenu();
|
|
120
177
|
}
|
|
121
178
|
```
|
|
122
179
|
|
|
123
180
|
---
|
|
124
181
|
|
|
125
|
-
###
|
|
126
|
-
|
|
127
|
-
When users filter, reorder, group, or format columns in the grid, they can click **"+ Save View"** to persist their customized view preset. Presets are saved directly into the report's JSON:
|
|
182
|
+
### Step 5: Declarative Routes (`app.routes.ts`)
|
|
128
183
|
|
|
129
|
-
|
|
130
|
-
{
|
|
131
|
-
"grid": {
|
|
132
|
-
"dataSourceId": "ds-sales",
|
|
133
|
-
"columns": [...],
|
|
134
|
-
"options": {
|
|
135
|
-
"presets": [
|
|
136
|
-
{
|
|
137
|
-
"id": "preset_1728200000",
|
|
138
|
-
"name": "Q3 High Value Clients",
|
|
139
|
-
"gridState": {
|
|
140
|
-
"filters": { "amount": { "operator": "gte", "value": 50000 } },
|
|
141
|
-
"columnOrder": ["invoiceId", "amount", "customerName"]
|
|
142
|
-
}
|
|
143
|
-
}
|
|
144
|
-
]
|
|
145
|
-
}
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
Users can switch between views seamlessly from the top dropdown, keeping all formatting and custom filters intact.
|
|
150
|
-
|
|
151
|
-
---
|
|
152
|
-
|
|
153
|
-
### Backend Integration: Mounting `BwaysReportingModule` in NestJS
|
|
154
|
-
|
|
155
|
-
To power the built-in HTTP adapters, mount `BwaysReportingModule` directly inside your existing NestJS host application:
|
|
184
|
+
Add one line to your route definitions to enable dynamic live report pages:
|
|
156
185
|
|
|
157
186
|
```typescript
|
|
158
|
-
// app.
|
|
159
|
-
import {
|
|
160
|
-
import {
|
|
161
|
-
|
|
162
|
-
@Module({
|
|
163
|
-
imports: [
|
|
164
|
-
BwaysReportingModule.forRoot({
|
|
165
|
-
security: {
|
|
166
|
-
allowedSchemas: ['dbo', 'reporting'],
|
|
167
|
-
disallowRawSql: true, // SQL injection prevention
|
|
168
|
-
validateEntitiesAgainstCatalog: true, // Checks sys.procedures catalog
|
|
169
|
-
},
|
|
170
|
-
}),
|
|
171
|
-
],
|
|
172
|
-
})
|
|
173
|
-
export class AppModule {}
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
---
|
|
177
|
-
|
|
178
|
-
### Option B: Custom Adapters (Full Manual Control)
|
|
187
|
+
// src/app/app.routes.ts
|
|
188
|
+
import { Routes } from '@angular/router';
|
|
189
|
+
import { bwaysReportRoutes } from 'bways-report';
|
|
190
|
+
import { AdminReportsComponent } from './pages/admin-reports/admin-reports.component';
|
|
179
191
|
|
|
180
|
-
|
|
192
|
+
export const routes: Routes = [
|
|
193
|
+
// Admin visual designer route
|
|
194
|
+
{ path: 'admin/reports', component: AdminReportsComponent },
|
|
181
195
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
provideBwaysReport({
|
|
188
|
-
gridComponent: BWaysGridComponent,
|
|
189
|
-
dataSourceAdapter: MyCustomDataSourceAdapter,
|
|
190
|
-
persistenceAdapter: MyCustomPersistenceAdapter,
|
|
191
|
-
masterDataProvider: MyCustomMasterDataProvider,
|
|
192
|
-
defaultPageSize: 25,
|
|
193
|
-
enableDesigner: true,
|
|
196
|
+
// Live user reporting pages: /reports/:slug (e.g. /reports/sale-report)
|
|
197
|
+
{
|
|
198
|
+
path: 'reports',
|
|
199
|
+
children: bwaysReportRoutes({
|
|
200
|
+
// includeBuilderRoute: false, // Set true to include /reports/new and /reports/:slug/edit
|
|
194
201
|
}),
|
|
195
|
-
|
|
196
|
-
|
|
202
|
+
},
|
|
203
|
+
];
|
|
197
204
|
```
|
|
198
205
|
|
|
199
|
-
|
|
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!
|
|
200
207
|
|
|
201
|
-
|
|
208
|
+
---
|
|
202
209
|
|
|
203
|
-
|
|
210
|
+
## 2. Visual Designer Features
|
|
204
211
|
|
|
205
|
-
###
|
|
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)`
|
|
206
219
|
|
|
207
|
-
|
|
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.
|
|
208
222
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
import { Observable } from 'rxjs';
|
|
214
|
-
import { ReportDataSourceAdapter, ReportDataSourceDefinition } from 'bways-report';
|
|
215
|
-
|
|
216
|
-
@Injectable({ providedIn: 'root' })
|
|
217
|
-
export class ErpDataSourceAdapter extends ReportDataSourceAdapter {
|
|
218
|
-
private readonly http = inject(HttpClient);
|
|
219
|
-
|
|
220
|
-
execute(
|
|
221
|
-
dataSource: ReportDataSourceDefinition,
|
|
222
|
-
parameters: Record<string, unknown>
|
|
223
|
-
): Observable<unknown[]> {
|
|
224
|
-
// Send report filter parameters to your backend API endpoint
|
|
225
|
-
return this.http.post<unknown[]>(dataSource.endpoint, parameters);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
```
|
|
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.
|
|
229
227
|
|
|
230
|
-
###
|
|
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.
|
|
231
234
|
|
|
232
|
-
|
|
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.
|
|
233
238
|
|
|
234
|
-
|
|
235
|
-
// src/app/services/erp-persistence.adapter.ts
|
|
236
|
-
import { Injectable, inject } from '@angular/core';
|
|
237
|
-
import { HttpClient } from '@angular/common/http';
|
|
238
|
-
import { Observable } from 'rxjs';
|
|
239
|
-
import {
|
|
240
|
-
ReportPersistenceAdapter,
|
|
241
|
-
ReportDefinition,
|
|
242
|
-
ReportSummary,
|
|
243
|
-
} from 'bways-report';
|
|
244
|
-
|
|
245
|
-
@Injectable({ providedIn: 'root' })
|
|
246
|
-
export class ErpPersistenceAdapter extends ReportPersistenceAdapter {
|
|
247
|
-
private readonly http = inject(HttpClient);
|
|
248
|
-
private readonly baseUrl = '/api/reports';
|
|
249
|
-
|
|
250
|
-
load(reportId: string): Observable<ReportDefinition> {
|
|
251
|
-
return this.http.get<ReportDefinition>(`${this.baseUrl}/${reportId}`);
|
|
252
|
-
}
|
|
239
|
+
---
|
|
253
240
|
|
|
254
|
-
|
|
255
|
-
return this.http.post<ReportDefinition>(this.baseUrl, report);
|
|
256
|
-
}
|
|
241
|
+
## 3. Backend Contract Reference
|
|
257
242
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
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` |
|
|
261
249
|
|
|
262
|
-
|
|
263
|
-
|
|
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
|
+
]
|
|
264
260
|
}
|
|
261
|
+
]
|
|
262
|
+
```
|
|
265
263
|
|
|
266
|
-
|
|
267
|
-
|
|
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
|
+
]
|
|
268
275
|
}
|
|
269
|
-
|
|
276
|
+
]
|
|
270
277
|
```
|
|
271
278
|
|
|
272
|
-
###
|
|
279
|
+
### Execution Request Format
|
|
280
|
+
Supports both simplified and enterprise DTO contracts out-of-the-box:
|
|
273
281
|
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
@Injectable({ providedIn: 'root' })
|
|
284
|
-
export class ErpMasterDataProvider extends MasterDataProvider {
|
|
285
|
-
private readonly http = inject(HttpClient);
|
|
286
|
-
|
|
287
|
-
getOptions(
|
|
288
|
-
masterName: string,
|
|
289
|
-
filter?: Record<string, unknown>
|
|
290
|
-
): Observable<DropdownOption[]> {
|
|
291
|
-
return this.http.get<DropdownOption[]>(`/api/master-data/${masterName}`, {
|
|
292
|
-
params: filter as any,
|
|
293
|
-
});
|
|
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"
|
|
294
291
|
}
|
|
295
292
|
}
|
|
296
293
|
```
|
|
297
294
|
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
```typescript
|
|
307
|
-
// src/app/app.routes.ts
|
|
308
|
-
import { Routes } from '@angular/router';
|
|
309
|
-
import { createReportRoutes } from 'bways-report';
|
|
310
|
-
|
|
311
|
-
export const routes: Routes = [
|
|
312
|
-
{
|
|
313
|
-
path: 'reports',
|
|
314
|
-
children: createReportRoutes({
|
|
315
|
-
// Optional: enforce auth or role guards
|
|
316
|
-
runtimeGuards: [],
|
|
317
|
-
designerGuards: [], // e.g. [AdminGuard]
|
|
318
|
-
enableDesignerRoutes: true, // creates 'new' and ':reportId/edit' routes
|
|
319
|
-
}),
|
|
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"
|
|
320
303
|
},
|
|
321
|
-
|
|
304
|
+
"parameters": {
|
|
305
|
+
"BranchId": 1
|
|
306
|
+
},
|
|
307
|
+
"sessionContext": {
|
|
308
|
+
"companyId": 101,
|
|
309
|
+
"branchId": 1
|
|
310
|
+
}
|
|
311
|
+
}
|
|
322
312
|
```
|
|
323
313
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
// src/app/components/sidebar/erp-sidebar.component.ts
|
|
335
|
-
import { Component, inject } from '@angular/core';
|
|
336
|
-
import { CommonModule } from '@angular/common';
|
|
337
|
-
import { RouterModule } from '@angular/router';
|
|
338
|
-
import { ReportMenuService } from 'bways-report';
|
|
339
|
-
|
|
340
|
-
@Component({
|
|
341
|
-
selector: 'erp-sidebar',
|
|
342
|
-
standalone: true,
|
|
343
|
-
imports: [CommonModule, RouterModule],
|
|
344
|
-
template: `
|
|
345
|
-
<aside class="sidebar">
|
|
346
|
-
<input
|
|
347
|
-
type="search"
|
|
348
|
-
placeholder="Search reports..."
|
|
349
|
-
(input)="onSearch($event)"
|
|
350
|
-
/>
|
|
351
|
-
|
|
352
|
-
@for (group of menuService.menuGroups(); track group.category) {
|
|
353
|
-
<div class="menu-group">
|
|
354
|
-
<h4>{{ group.displayName }}</h4>
|
|
355
|
-
<ul>
|
|
356
|
-
@for (item of group.items; track item.id) {
|
|
357
|
-
<li>
|
|
358
|
-
<a [routerLink]="item.route" routerLinkActive="active">
|
|
359
|
-
{{ item.name }}
|
|
360
|
-
@if (item.isDraft) {
|
|
361
|
-
<span class="badge">Draft</span>
|
|
362
|
-
}
|
|
363
|
-
</a>
|
|
364
|
-
</li>
|
|
365
|
-
}
|
|
366
|
-
</ul>
|
|
367
|
-
</div>
|
|
368
|
-
}
|
|
369
|
-
</aside>
|
|
370
|
-
`,
|
|
371
|
-
})
|
|
372
|
-
export class ErpSidebarComponent {
|
|
373
|
-
readonly menuService = inject(ReportMenuService);
|
|
374
|
-
|
|
375
|
-
onSearch(event: Event): void {
|
|
376
|
-
const query = (event.target as HTMLInputElement).value;
|
|
377
|
-
this.menuService.setSearchQuery(query);
|
|
378
|
-
}
|
|
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": {}
|
|
379
324
|
}
|
|
380
325
|
```
|
|
381
326
|
|
|
382
327
|
---
|
|
383
328
|
|
|
384
|
-
##
|
|
329
|
+
## 4. Dynamic Session Context & Auto-Parameter Binding
|
|
385
330
|
|
|
386
|
-
|
|
331
|
+
When `autoParameter: true` is configured, parameters matching active ERP session keys are automatically populated and hidden from non-technical users:
|
|
387
332
|
|
|
388
|
-
|
|
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` |
|
|
389
339
|
|
|
340
|
+
Session values can be updated at runtime:
|
|
390
341
|
```typescript
|
|
391
|
-
import {
|
|
392
|
-
import {
|
|
342
|
+
import { inject } from '@angular/core';
|
|
343
|
+
import { ReportSessionContextService } from 'bways-report';
|
|
393
344
|
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
standalone: true,
|
|
397
|
-
imports: [ReportRuntimeComponent],
|
|
398
|
-
template: `
|
|
399
|
-
<!-- Option A: Load by ID via persistence adapter -->
|
|
400
|
-
<rpt-runtime [reportId]="'sales-register-2024'" />
|
|
401
|
-
|
|
402
|
-
<!-- Option B: Pass ReportDefinition directly -->
|
|
403
|
-
<!-- <rpt-runtime [report]="customDefinition" /> -->
|
|
404
|
-
`,
|
|
405
|
-
})
|
|
406
|
-
export class MyReportPageComponent {}
|
|
407
|
-
```
|
|
408
|
-
|
|
409
|
-
### Visual Drag-and-Drop Designer
|
|
410
|
-
|
|
411
|
-
```typescript
|
|
412
|
-
import { Component } from '@angular/core';
|
|
413
|
-
import { DesignerComponent, ReportDefinition } from 'bways-report';
|
|
345
|
+
export class SessionWidget {
|
|
346
|
+
private readonly session = inject(ReportSessionContextService);
|
|
414
347
|
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
standalone: true,
|
|
418
|
-
imports: [DesignerComponent],
|
|
419
|
-
template: `
|
|
420
|
-
<rpt-designer
|
|
421
|
-
[initialReport]="reportDefinition"
|
|
422
|
-
(save)="onSaveReport($event)"
|
|
423
|
-
/>
|
|
424
|
-
`,
|
|
425
|
-
})
|
|
426
|
-
export class MyDesignerPageComponent {
|
|
427
|
-
reportDefinition: ReportDefinition = /* ... */;
|
|
428
|
-
|
|
429
|
-
onSaveReport(updatedReport: ReportDefinition): void {
|
|
430
|
-
console.log('Saved report schema:', updatedReport);
|
|
348
|
+
onBranchSwitch(branchId: number): void {
|
|
349
|
+
this.session.setSessionParameter('branchId', branchId);
|
|
431
350
|
}
|
|
432
351
|
}
|
|
433
352
|
```
|
|
434
353
|
|
|
435
354
|
---
|
|
436
355
|
|
|
437
|
-
##
|
|
356
|
+
## 5. Plugging in BWays-Grid (`UltraGridComponent`)
|
|
438
357
|
|
|
439
|
-
|
|
358
|
+
`BWays-Report` provides first-class support for `bways-grid` (`v0.1.18+` / `v0.1.19+`). Pass `grid: UltraGridComponent` to `provideBwaysReport()`:
|
|
440
359
|
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
})
|
|
447
|
-
```
|
|
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.
|
|
448
365
|
|
|
449
|
-
|
|
366
|
+
---
|
|
450
367
|
|
|
451
|
-
|
|
368
|
+
## 6. Advanced Custom Adapters
|
|
452
369
|
|
|
453
|
-
|
|
370
|
+
For applications with custom HTTP pipelines, gRPC, or microservice gateways, extend the library's abstract contracts:
|
|
454
371
|
|
|
455
372
|
```typescript
|
|
456
373
|
provideBwaysReport({
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
---
|
|
464
|
-
|
|
465
|
-
## 8. Grid Bridge & Circular Echo Suppression
|
|
466
|
-
|
|
467
|
-
`bways-report` features an intelligent runtime bridge (`ReportGridBridgeComponent` and `RptGridOutletDirective`) that connects any underlying grid library (e.g., `UltraGridComponent` from `bways-grid`) to the dynamic report state:
|
|
468
|
-
|
|
469
|
-
```
|
|
470
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
471
|
-
│ Design Canvas / Runtime │
|
|
472
|
-
│ │
|
|
473
|
-
│ [gridDefinition] (ReportGridDefinition) │
|
|
474
|
-
│ │ │
|
|
475
|
-
│ ▼ │
|
|
476
|
-
│ ┌─────────────────────────────────────────────────────┐ │
|
|
477
|
-
│ │ ReportGridBridgeComponent │ │
|
|
478
|
-
│ │ │ │
|
|
479
|
-
│ │ - gridInputs: transforms definition into inputs │ │
|
|
480
|
-
│ │ - gridReportState: preserves active & condition │ │
|
|
481
|
-
│ │ filters from serialized report state │ │
|
|
482
|
-
│ │ │ │
|
|
483
|
-
│ │ ┌─────────────────────────────────────────────┐ │ │
|
|
484
|
-
│ │ │ RptGridOutletDirective │ │ │
|
|
485
|
-
│ │ │ │ │ │
|
|
486
|
-
│ │ │ - Circular Echo Suppression: │ │ │
|
|
487
|
-
│ │ │ Tracks last emitted state & col-defs │ │ │
|
|
488
|
-
│ │ │ Skips setInput when update came from │ │ │
|
|
489
|
-
│ │ │ the grid itself. │ │ │
|
|
490
|
-
│ │ └─────────────────────┬───────────────────────┘ │ │
|
|
491
|
-
│ └─────────────────────────┼───────────────────────────┘ │
|
|
492
|
-
│ │ │
|
|
493
|
-
│ ▼ │
|
|
494
|
-
│ ┌───────────────────────┐ │
|
|
495
|
-
│ │ UltraGridComponent │ │
|
|
496
|
-
│ │ (Live ERP Grid) │ │
|
|
497
|
-
│ └───────────────────────┘ │
|
|
498
|
-
└─────────────────────────────────────────────────────────────┘
|
|
374
|
+
gridComponent: UltraGridComponent,
|
|
375
|
+
dataSourceAdapter: MyCustomDataSourceAdapter,
|
|
376
|
+
persistenceAdapter: MyCustomPersistenceAdapter,
|
|
377
|
+
schemaDiscoveryAdapter: MyCustomSchemaDiscoveryAdapter,
|
|
378
|
+
lookupAdapter: MyCustomLookupAdapter,
|
|
379
|
+
});
|
|
499
380
|
```
|
|
500
381
|
|
|
501
|
-
|
|
502
|
-
-
|
|
503
|
-
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
- **Full Filter State Preservation**: Filter sets and expressions are preserved intact in `options.reportState` when saved or exported.
|
|
382
|
+
Abstract base classes:
|
|
383
|
+
- `ReportDataSourceAdapter`
|
|
384
|
+
- `ReportPersistenceAdapter`
|
|
385
|
+
- `ReportSchemaDiscoveryAdapter`
|
|
386
|
+
- `ReportLookupAdapter`
|
|
507
387
|
|
|
508
388
|
---
|
|
509
389
|
|
|
510
|
-
##
|
|
390
|
+
## 7. Theming & CSS Custom Properties
|
|
511
391
|
|
|
512
|
-
`bways-report`
|
|
513
|
-
|
|
514
|
-
1. **Introspection (`sys.parameters`)**: Queries stored procedure signatures, determining data types, nullability, and default expressions.
|
|
515
|
-
2. **Smart Control Inference**:
|
|
516
|
-
- Date parameters (`@FromDate`, `@ToDate`, `@AsOnDate`) automatically suggest date-picker or date-range controls.
|
|
517
|
-
- Master entity parameters (`@SubGLCode`, `@BranchId`, `@CustomerId`) infer dropdown lookups from associated tables or views.
|
|
518
|
-
3. **Lookup Deduplication & Account Resolution**:
|
|
519
|
-
- `identifier-humanizer.ts` prioritizes unique account numbers (`_acno`, `glacno`, `account_no`) over category codes (`_code`), preventing duplicate collapsing of customer accounts in dropdown lookups.
|
|
520
|
-
4. **Session Token Binding**:
|
|
521
|
-
- Parameters matching ERP session context (`@BranchId`, `@CompanyId`, `@FinYearId`) are automatically resolved via `SessionContextProvider` without manual user intervention.
|
|
522
|
-
|
|
523
|
-
---
|
|
524
|
-
|
|
525
|
-
## 10. Theming & CSS Custom Properties
|
|
526
|
-
|
|
527
|
-
`bways-report` uses CSS custom properties (`--rpt-*`) throughout all components, ensuring seamless alignment with your ERP application's design system:
|
|
392
|
+
`bways-report` uses Vanilla CSS custom properties. Customize the tokens in your application's `styles.css`:
|
|
528
393
|
|
|
529
394
|
```css
|
|
530
|
-
/* In your host application's styles.scss or theme file */
|
|
531
395
|
:root {
|
|
532
|
-
|
|
533
|
-
--rpt-primary: #
|
|
534
|
-
--rpt-
|
|
535
|
-
--rpt-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
--rpt-
|
|
539
|
-
--rpt-bg-subtle: #f8fafc;
|
|
540
|
-
--rpt-text-color: #0f172a;
|
|
541
|
-
--rpt-text-muted: #64748b;
|
|
542
|
-
--rpt-border-color: #e2e8f0;
|
|
543
|
-
|
|
544
|
-
/* Geometry & Typography */
|
|
545
|
-
--rpt-radius-md: 6px;
|
|
546
|
-
--rpt-radius-lg: 12px;
|
|
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;
|
|
547
403
|
--rpt-font-family: 'Inter', system-ui, sans-serif;
|
|
548
|
-
--rpt-
|
|
404
|
+
--rpt-border-radius: 6px;
|
|
405
|
+
--rpt-border-radius-lg: 8px;
|
|
406
|
+
}
|
|
549
407
|
|
|
550
|
-
|
|
551
|
-
--rpt-
|
|
552
|
-
--rpt-
|
|
553
|
-
--rpt-
|
|
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;
|
|
554
414
|
}
|
|
555
415
|
```
|
|
556
416
|
|
|
557
417
|
---
|
|
558
418
|
|
|
559
|
-
##
|
|
419
|
+
## 8. Exporting Data (CSV & JSON)
|
|
560
420
|
|
|
561
|
-
|
|
421
|
+
Inject `ReportExportService` in any host component:
|
|
562
422
|
|
|
563
423
|
```typescript
|
|
564
424
|
import { Component, inject } from '@angular/core';
|
|
565
425
|
import { ReportExportService } from 'bways-report';
|
|
566
426
|
|
|
567
|
-
@Component({
|
|
568
|
-
|
|
569
|
-
standalone: true,
|
|
570
|
-
template: `
|
|
571
|
-
<button (click)="downloadCsv()">Download CSV</button>
|
|
572
|
-
<button (click)="downloadJson()">Download Metadata</button>
|
|
573
|
-
`,
|
|
574
|
-
})
|
|
575
|
-
export class ExportActionsComponent {
|
|
427
|
+
@Component({ ... })
|
|
428
|
+
export class ExportComponent {
|
|
576
429
|
private readonly exportService = inject(ReportExportService);
|
|
577
430
|
|
|
578
|
-
|
|
579
|
-
const data = [
|
|
580
|
-
{ invoiceNo: 'INV-001', customer: 'Acme Corp', total: 4950 },
|
|
581
|
-
{ invoiceNo: 'INV-002', customer: 'Globex Inc', total: 14080 },
|
|
582
|
-
];
|
|
583
|
-
|
|
431
|
+
onExportCsv(data: unknown[]): void {
|
|
584
432
|
this.exportService.exportCsv(data, {
|
|
585
|
-
fileName: '
|
|
433
|
+
fileName: 'sales-register.csv',
|
|
586
434
|
columns: [
|
|
587
435
|
{ field: 'invoiceNo', header: 'Invoice #' },
|
|
588
|
-
{ field: '
|
|
589
|
-
{
|
|
590
|
-
field: 'total',
|
|
591
|
-
header: 'Total ($)',
|
|
592
|
-
formatter: (val: number) => `$${val.toLocaleString()}`
|
|
593
|
-
},
|
|
436
|
+
{ field: 'amount', header: 'Amount' },
|
|
594
437
|
],
|
|
595
|
-
addBom: true, //
|
|
596
|
-
});
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
downloadJson(): void {
|
|
600
|
-
this.exportService.exportJson(myReportDefinition, {
|
|
601
|
-
fileName: 'report-schema.json',
|
|
602
|
-
pretty: true,
|
|
438
|
+
addBom: true, // UTF-8 Excel compatibility
|
|
603
439
|
});
|
|
604
440
|
}
|
|
605
441
|
}
|
|
@@ -607,13 +443,6 @@ export class ExportActionsComponent {
|
|
|
607
443
|
|
|
608
444
|
---
|
|
609
445
|
|
|
610
|
-
## 12. Changelog & Version History
|
|
611
|
-
|
|
612
|
-
For a complete record of releases, breaking changes, and bug fixes, refer to the **[Changelog](CHANGELOG.md)**.
|
|
613
|
-
|
|
614
|
-
---
|
|
615
|
-
|
|
616
446
|
## License
|
|
617
447
|
|
|
618
|
-
|
|
619
|
-
|
|
448
|
+
Proprietary License. Copyright (c) 2026 CCPL / BWays Team. All rights reserved.
|