tin-spa 20.5.1 → 20.5.2
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/fesm2022/tin-spa.mjs +424 -90
- package/fesm2022/tin-spa.mjs.map +1 -1
- package/index.d.ts +40 -4
- package/package.json +1 -1
package/fesm2022/tin-spa.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { Injectable, Inject, Component, InjectionToken, Optional, inject, Input, Directive, NgModule, EventEmitter, Output, forwardRef, HostListener, ViewChild, Pipe, ContentChild } from '@angular/core';
|
|
2
|
+
import { Injectable, Inject, Component, InjectionToken, Optional, inject, Input, Directive, NgModule, EventEmitter, Output, forwardRef, HostListener, ViewChild, Pipe, ContentChild, ViewEncapsulation } from '@angular/core';
|
|
3
3
|
import * as i1 from '@angular/material/dialog';
|
|
4
4
|
import { MAT_DIALOG_DATA, MatDialogModule, MAT_DIALOG_DEFAULT_OPTIONS, MatDialog } from '@angular/material/dialog';
|
|
5
5
|
import * as i2 from '@angular/common';
|
|
@@ -10,7 +10,7 @@ import * as i4$1 from '@angular/material/icon';
|
|
|
10
10
|
import { MatIconModule } from '@angular/material/icon';
|
|
11
11
|
import * as i3 from '@angular/material/form-field';
|
|
12
12
|
import { MatFormFieldModule, MAT_FORM_FIELD_DEFAULT_OPTIONS } from '@angular/material/form-field';
|
|
13
|
-
import { of, BehaviorSubject, tap, timeout, finalize, share, Observable,
|
|
13
|
+
import { of, BehaviorSubject, Subject, tap, timeout, finalize, share, Observable, throwError, interval } from 'rxjs';
|
|
14
14
|
import { mergeMap, filter, startWith, map, finalize as finalize$1, catchError, take, switchMap } from 'rxjs/operators';
|
|
15
15
|
import * as i2$1 from '@angular/material/snack-bar';
|
|
16
16
|
import { MatSnackBarModule } from '@angular/material/snack-bar';
|
|
@@ -42,7 +42,7 @@ import * as i14 from '@angular/material/list';
|
|
|
42
42
|
import { MatListModule } from '@angular/material/list';
|
|
43
43
|
import * as i4$4 from '@angular/material/menu';
|
|
44
44
|
import { MatMenuModule } from '@angular/material/menu';
|
|
45
|
-
import * as
|
|
45
|
+
import * as i13 from '@angular/material/paginator';
|
|
46
46
|
import { MatPaginatorModule } from '@angular/material/paginator';
|
|
47
47
|
import * as i18$1 from '@angular/material/progress-spinner';
|
|
48
48
|
import { MatProgressSpinnerModule } from '@angular/material/progress-spinner';
|
|
@@ -53,7 +53,7 @@ import { MatSliderModule } from '@angular/material/slider';
|
|
|
53
53
|
import { MatSortModule } from '@angular/material/sort';
|
|
54
54
|
import * as i4$3 from '@angular/material/stepper';
|
|
55
55
|
import { MatStepperModule } from '@angular/material/stepper';
|
|
56
|
-
import * as
|
|
56
|
+
import * as i12$2 from '@angular/material/table';
|
|
57
57
|
import { MatTableModule, MatTableDataSource } from '@angular/material/table';
|
|
58
58
|
import * as i4$5 from '@angular/material/tabs';
|
|
59
59
|
import { MatTabsModule } from '@angular/material/tabs';
|
|
@@ -1464,14 +1464,24 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
|
|
|
1464
1464
|
}]
|
|
1465
1465
|
}], ctorParameters: () => [] });
|
|
1466
1466
|
|
|
1467
|
-
// SignalR service for real-time notification count push
|
|
1467
|
+
// SignalR service for real-time notification count push and entity change broadcasts
|
|
1468
1468
|
class SignalRService {
|
|
1469
1469
|
constructor() {
|
|
1470
1470
|
this.hubConnection = null;
|
|
1471
1471
|
this.notificationCount = new BehaviorSubject(0);
|
|
1472
1472
|
this.notificationCount$ = this.notificationCount.asObservable();
|
|
1473
|
-
// Changed:
|
|
1473
|
+
// Changed: Data hub connection for real-time entity changes
|
|
1474
|
+
this.dataHubConnection = null;
|
|
1475
|
+
this.entityCreated = new Subject();
|
|
1476
|
+
this.entityUpdated = new Subject();
|
|
1477
|
+
this.entityDeleted = new Subject();
|
|
1478
|
+
this.entityCreated$ = this.entityCreated.asObservable(); // Changed: Observable for new entity rows
|
|
1479
|
+
this.entityUpdated$ = this.entityUpdated.asObservable(); // Changed: Observable for updated entity rows
|
|
1480
|
+
this.entityDeleted$ = this.entityDeleted.asObservable(); // Changed: Observable for deleted entity IDs
|
|
1481
|
+
// Changed: Callback for reconnection — notification count refresh (set by NotificationsService)
|
|
1474
1482
|
this.onReconnected = null;
|
|
1483
|
+
// Changed: Callback for data hub reconnection — tables should reload (set by table components)
|
|
1484
|
+
this.onDataReconnected = null;
|
|
1475
1485
|
}
|
|
1476
1486
|
startConnection(hubUrl, token) {
|
|
1477
1487
|
if (this.hubConnection)
|
|
@@ -1489,7 +1499,34 @@ class SignalRService {
|
|
|
1489
1499
|
if (this.onReconnected)
|
|
1490
1500
|
this.onReconnected();
|
|
1491
1501
|
});
|
|
1492
|
-
this.hubConnection.start().catch(err => console.error('SignalR connection error:', err));
|
|
1502
|
+
this.hubConnection.start().catch(err => console.error('SignalR notification connection error:', err));
|
|
1503
|
+
}
|
|
1504
|
+
// Changed: Start data hub connection for real-time entity change broadcasts
|
|
1505
|
+
startDataConnection(hubUrl, token) {
|
|
1506
|
+
if (this.dataHubConnection?.state === signalR.HubConnectionState.Connected)
|
|
1507
|
+
return; // Changed: Skip if already connected
|
|
1508
|
+
if (this.dataHubConnection)
|
|
1509
|
+
this.stopDataConnection();
|
|
1510
|
+
this.dataHubConnection = new signalR.HubConnectionBuilder()
|
|
1511
|
+
.withUrl(hubUrl, { accessTokenFactory: () => token })
|
|
1512
|
+
.withAutomaticReconnect()
|
|
1513
|
+
.build();
|
|
1514
|
+
// Changed: Listen for entity CRUD broadcasts from backend DataHub
|
|
1515
|
+
this.dataHubConnection.on('EntityCreated', (entityName, data) => {
|
|
1516
|
+
this.entityCreated.next({ entityName, data });
|
|
1517
|
+
});
|
|
1518
|
+
this.dataHubConnection.on('EntityUpdated', (entityName, data) => {
|
|
1519
|
+
this.entityUpdated.next({ entityName, data });
|
|
1520
|
+
});
|
|
1521
|
+
this.dataHubConnection.on('EntityDeleted', (entityName, data) => {
|
|
1522
|
+
this.entityDeleted.next({ entityName, data });
|
|
1523
|
+
});
|
|
1524
|
+
// Changed: On data hub reconnect, notify tables to do a full reload (catch missed events)
|
|
1525
|
+
this.dataHubConnection.onreconnected(() => {
|
|
1526
|
+
if (this.onDataReconnected)
|
|
1527
|
+
this.onDataReconnected();
|
|
1528
|
+
});
|
|
1529
|
+
this.dataHubConnection.start().catch(err => console.error('SignalR data connection error:', err));
|
|
1493
1530
|
}
|
|
1494
1531
|
stopConnection() {
|
|
1495
1532
|
if (this.hubConnection) {
|
|
@@ -1497,6 +1534,13 @@ class SignalRService {
|
|
|
1497
1534
|
this.hubConnection = null;
|
|
1498
1535
|
}
|
|
1499
1536
|
}
|
|
1537
|
+
// Changed: Stop data hub connection
|
|
1538
|
+
stopDataConnection() {
|
|
1539
|
+
if (this.dataHubConnection) {
|
|
1540
|
+
this.dataHubConnection.stop();
|
|
1541
|
+
this.dataHubConnection = null;
|
|
1542
|
+
}
|
|
1543
|
+
}
|
|
1500
1544
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: SignalRService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
1501
1545
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: SignalRService, providedIn: 'root' }); }
|
|
1502
1546
|
}
|
|
@@ -1580,7 +1624,8 @@ class AuthService {
|
|
|
1580
1624
|
});
|
|
1581
1625
|
}
|
|
1582
1626
|
}
|
|
1583
|
-
this.signalRService.stopConnection(); // Changed: Stop SignalR connection before clearing session
|
|
1627
|
+
this.signalRService.stopConnection(); // Changed: Stop SignalR notification connection before clearing session
|
|
1628
|
+
this.signalRService.stopDataConnection(); // Changed: Stop SignalR data connection before clearing session
|
|
1584
1629
|
this.Updateloggedin(false);
|
|
1585
1630
|
this.UpdateAutoLogin(false);
|
|
1586
1631
|
this.UpdateRole(new Role());
|
|
@@ -2170,7 +2215,9 @@ class DataServiceLib {
|
|
|
2170
2215
|
{ name: 'delete', dialog: true, action: { url: 'employees?action=delete', method: 'post' } },
|
|
2171
2216
|
],
|
|
2172
2217
|
loadAction: { url: 'employees/all/x' },
|
|
2173
|
-
formConfig: this.employeeFormConfig
|
|
2218
|
+
formConfig: this.employeeFormConfig,
|
|
2219
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
2220
|
+
entityName: 'Employee' // Changed: Match backend entity name for SignalR broadcasts
|
|
2174
2221
|
};
|
|
2175
2222
|
//--------------------------Positions-------------------------
|
|
2176
2223
|
this.positionsTableConfig = {
|
|
@@ -2205,7 +2252,9 @@ class DataServiceLib {
|
|
|
2205
2252
|
{ name: 'delete', dialog: true, action: { url: 'positions?action=delete', method: 'post' } },
|
|
2206
2253
|
],
|
|
2207
2254
|
loadAction: { url: 'positions/all/x' },
|
|
2208
|
-
formConfig: this.positionFormConfig
|
|
2255
|
+
formConfig: this.positionFormConfig,
|
|
2256
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
2257
|
+
entityName: 'Position' // Changed: Match backend entity name for SignalR broadcasts
|
|
2209
2258
|
};
|
|
2210
2259
|
//--------------------------Departments-------------------------
|
|
2211
2260
|
this.departmentTableConfig = {
|
|
@@ -2246,7 +2295,9 @@ class DataServiceLib {
|
|
|
2246
2295
|
{ name: 'delete', dialog: true, action: { url: 'departments?action=delete', method: 'post' } },
|
|
2247
2296
|
],
|
|
2248
2297
|
loadAction: { url: 'departments/all/x' },
|
|
2249
|
-
formConfig: this.departmentFormConfig
|
|
2298
|
+
formConfig: this.departmentFormConfig,
|
|
2299
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
2300
|
+
entityName: 'Department' // Changed: Match backend entity name for SignalR broadcasts
|
|
2250
2301
|
};
|
|
2251
2302
|
//--------------------------Contact Persons-------------------------
|
|
2252
2303
|
this.contactPersonFormConfig = {
|
|
@@ -2346,7 +2397,9 @@ class DataServiceLib {
|
|
|
2346
2397
|
{ name: 'delete', dialog: true, action: { url: 'customers?action=delete', method: 'post' } },
|
|
2347
2398
|
],
|
|
2348
2399
|
loadAction: { url: 'customers/all/x' },
|
|
2349
|
-
formConfig: this.customerFormConfig
|
|
2400
|
+
formConfig: this.customerFormConfig,
|
|
2401
|
+
// realTime: true, // Disabled: testing realtime on transactions table only — no re-fetch after CUD
|
|
2402
|
+
entityName: 'Customer' // Changed: Match backend typeof(Customer).Name for SignalR broadcasts
|
|
2350
2403
|
};
|
|
2351
2404
|
//--------------------------Suppliers-------------------------
|
|
2352
2405
|
this.supplierFormConfig = {
|
|
@@ -2397,7 +2450,9 @@ class DataServiceLib {
|
|
|
2397
2450
|
{ name: 'delete', dialog: true, action: { url: 'suppliers?action=delete', method: 'post' } },
|
|
2398
2451
|
],
|
|
2399
2452
|
loadAction: { url: 'suppliers/all/x' },
|
|
2400
|
-
formConfig: this.supplierFormConfig
|
|
2453
|
+
formConfig: this.supplierFormConfig,
|
|
2454
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
2455
|
+
entityName: 'Supplier' // Changed: Match backend entity name for SignalR broadcasts
|
|
2401
2456
|
};
|
|
2402
2457
|
//--------------------------GPT Caches-------------------------
|
|
2403
2458
|
this.gptCachesFormConfig = {
|
|
@@ -3681,7 +3736,9 @@ class AccountingService {
|
|
|
3681
3736
|
],
|
|
3682
3737
|
loadAction: { url: 'invoices/all/x' },
|
|
3683
3738
|
formConfig: this.invoiceFormConfig,
|
|
3684
|
-
tileConfig: this.invoicesTileConfig
|
|
3739
|
+
tileConfig: this.invoicesTileConfig,
|
|
3740
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
3741
|
+
entityName: 'Invoice'
|
|
3685
3742
|
};
|
|
3686
3743
|
//--------------------------Aging Report-------------------------
|
|
3687
3744
|
// Added: Aging report summary tiles
|
|
@@ -3842,7 +3899,9 @@ class AccountingService {
|
|
|
3842
3899
|
this.taxRateDeleteButton
|
|
3843
3900
|
],
|
|
3844
3901
|
loadAction: { url: 'taxrates/all/x' },
|
|
3845
|
-
formConfig: this.taxRateFormConfig
|
|
3902
|
+
formConfig: this.taxRateFormConfig,
|
|
3903
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
3904
|
+
entityName: 'TaxRate'
|
|
3846
3905
|
};
|
|
3847
3906
|
//--------------------------Currencies-------------------------
|
|
3848
3907
|
// Changed: Currency form configuration for multi-currency management
|
|
@@ -3887,7 +3946,9 @@ class AccountingService {
|
|
|
3887
3946
|
this.currencyDeleteButton
|
|
3888
3947
|
],
|
|
3889
3948
|
loadAction: { url: 'currencies/all/x' },
|
|
3890
|
-
formConfig: this.currencyFormConfig
|
|
3949
|
+
formConfig: this.currencyFormConfig,
|
|
3950
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
3951
|
+
entityName: 'Currency'
|
|
3891
3952
|
};
|
|
3892
3953
|
//--------------------------Transaction Types-------------------------
|
|
3893
3954
|
this.transactionTypeFormConfig = {
|
|
@@ -3942,7 +4003,9 @@ class AccountingService {
|
|
|
3942
4003
|
{ name: 'delete', dialog: true, action: { url: 'transactiontypes?action=delete', method: 'post' } },
|
|
3943
4004
|
],
|
|
3944
4005
|
loadAction: { url: 'transactiontypes/all/x' },
|
|
3945
|
-
formConfig: this.transactionTypeFormConfig
|
|
4006
|
+
formConfig: this.transactionTypeFormConfig,
|
|
4007
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
4008
|
+
entityName: 'TransactionType'
|
|
3946
4009
|
};
|
|
3947
4010
|
//--------------------------Transaction Import-------------------------
|
|
3948
4011
|
// Edit form for a single import item (sub-dialog)
|
|
@@ -3958,6 +4021,7 @@ class AccountingService {
|
|
|
3958
4021
|
};
|
|
3959
4022
|
// Nested table showing imported items in the review dialog
|
|
3960
4023
|
this.transactionImportItemsTableConfig = {
|
|
4024
|
+
tabTitle: 'Imported Items', // Changed: Add meaningful tab title instead of default 'Untitled'
|
|
3961
4025
|
showFilter: false,
|
|
3962
4026
|
causeFormRefresh: true,
|
|
3963
4027
|
minColumns: ['date', 'description', 'amount', 'transactionTypeName'],
|
|
@@ -4109,7 +4173,23 @@ class AccountingService {
|
|
|
4109
4173
|
this.transactionVoidButton,
|
|
4110
4174
|
],
|
|
4111
4175
|
loadAction: { url: 'transactions/all/x' },
|
|
4112
|
-
formConfig: this.transactionFormConfig
|
|
4176
|
+
formConfig: this.transactionFormConfig,
|
|
4177
|
+
realTime: true,
|
|
4178
|
+
entityName: 'Transaction'
|
|
4179
|
+
};
|
|
4180
|
+
// Changed: Search mode config for transactions — date range, description contains, account filter
|
|
4181
|
+
this.transactionSearchTableConfig = {
|
|
4182
|
+
...this.transactionsTableConfig,
|
|
4183
|
+
searchConfig: {
|
|
4184
|
+
fields: [
|
|
4185
|
+
{ name: 'dateFrom', type: 'date', alias: 'From Date', show: true },
|
|
4186
|
+
{ name: 'dateTo', type: 'date', alias: 'To Date', show: true },
|
|
4187
|
+
{ name: 'description', type: 'text', alias: 'Description', show: true },
|
|
4188
|
+
{ name: 'accountID', type: 'select', alias: 'Account', show: true, loadAction: { url: 'accounts/list/x' } },
|
|
4189
|
+
{ name: 'typeName', type: 'select', alias: 'Transaction Type', show: true, loadAction: { url: 'transactiontypes/list/x' } },
|
|
4190
|
+
],
|
|
4191
|
+
searchAction: { url: 'transactions/search', method: 'post' }
|
|
4192
|
+
}
|
|
4113
4193
|
};
|
|
4114
4194
|
this.accountTransactionsTableConfig = {
|
|
4115
4195
|
...this.transactionsTableConfig,
|
|
@@ -4291,7 +4371,9 @@ class AccountingService {
|
|
|
4291
4371
|
this.standingOrderDeleteButton
|
|
4292
4372
|
],
|
|
4293
4373
|
loadAction: { url: 'standingorders/all/x' },
|
|
4294
|
-
formConfig: this.standingOrderFormConfig
|
|
4374
|
+
formConfig: this.standingOrderFormConfig,
|
|
4375
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
4376
|
+
entityName: 'StandingOrder'
|
|
4295
4377
|
};
|
|
4296
4378
|
//--------------------------Accounts-------------------------
|
|
4297
4379
|
this.accountDetailsConfig = {
|
|
@@ -4327,13 +4409,15 @@ class AccountingService {
|
|
|
4327
4409
|
{ name: 'view', dialog: true, detailsConfig: this.accountDetailsConfig },
|
|
4328
4410
|
this.finAccounEditButton,
|
|
4329
4411
|
{ name: 'delete', dialog: true, action: { url: 'accounts?action=delete', method: 'post' } },
|
|
4330
|
-
{ name: 'revalue', display: 'Revalue Forex', inHeader: true, icon: { name: 'currency_exchange', color: 'blue' }, // Changed:
|
|
4331
|
-
|
|
4332
|
-
|
|
4333
|
-
},
|
|
4412
|
+
// { name: 'revalue', display: 'Revalue Forex', inHeader: true, icon: { name: 'currency_exchange', color: 'blue' }, // Changed: Commented out — forex revaluation deferred
|
|
4413
|
+
// action: { url: 'accounts?action=revalue', method: 'post', successMessage: 'Forex revaluation complete' },
|
|
4414
|
+
// confirm: { message: 'Revalue all forex accounts at current exchange rates?' }
|
|
4415
|
+
// },
|
|
4334
4416
|
],
|
|
4335
4417
|
loadAction: { url: 'accounts/all/x' },
|
|
4336
|
-
formConfig: this.accountFormConfig
|
|
4418
|
+
formConfig: this.accountFormConfig,
|
|
4419
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
4420
|
+
entityName: 'Account'
|
|
4337
4421
|
};
|
|
4338
4422
|
//--------------------------Financial Reports-------------------------
|
|
4339
4423
|
// Trial Balance table config — shows all accounts with debit/credit totals
|
|
@@ -4493,10 +4577,12 @@ class AccountingService {
|
|
|
4493
4577
|
{ name: 'updatedByDetails', alias: 'Last Updated', type: 'text' },
|
|
4494
4578
|
],
|
|
4495
4579
|
buttons: [
|
|
4496
|
-
{ name: 'create', dialog: true, detailsConfig: this.categoryDetailsConfig, action: { url: 'fixedassetcategories?action=create', method: 'post' } },
|
|
4580
|
+
{ name: 'create', display: 'Create Category', dialog: true, detailsConfig: this.categoryDetailsConfig, action: { url: 'fixedassetcategories?action=create', method: 'post' } }, // Changed: Added missing display text
|
|
4497
4581
|
{ name: 'delete', display: 'Delete', icon: { name: 'delete', color: 'red' }, action: { url: 'fixedassetcategories?action=delete', method: 'post' }, confirm: { message: 'Delete this category?' } },
|
|
4498
4582
|
],
|
|
4499
4583
|
loadAction: { url: 'fixedassetcategories/all/x' },
|
|
4584
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
4585
|
+
entityName: 'FixedAssetCategory'
|
|
4500
4586
|
};
|
|
4501
4587
|
//--------------------------Fixed Assets-------------------------
|
|
4502
4588
|
// Fixed asset form config for create/edit dialog
|
|
@@ -4593,13 +4679,15 @@ class AccountingService {
|
|
|
4593
4679
|
{ name: 'updatedByDetails', alias: 'Last Updated', type: 'text' },
|
|
4594
4680
|
],
|
|
4595
4681
|
buttons: [
|
|
4596
|
-
{ name: 'create', dialog: true, detailsConfig: this.assetDetailsConfig, action: { url: 'fixedassets?action=create', method: 'post' } },
|
|
4682
|
+
{ name: 'create', display: 'Create Asset', dialog: true, detailsConfig: this.assetDetailsConfig, action: { url: 'fixedassets?action=create', method: 'post' } }, // Changed: Added missing display text
|
|
4597
4683
|
this.assetActivateButton,
|
|
4598
4684
|
this.assetDepreciateButton,
|
|
4599
4685
|
{ name: 'delete', display: 'Delete', icon: { name: 'delete', color: 'red' }, action: { url: 'fixedassets?action=delete', method: 'post' }, confirm: { message: 'Delete this asset?' }, visible: x => x.status == AssetStatus.Draft },
|
|
4600
4686
|
],
|
|
4601
4687
|
loadAction: { url: 'fixedassets/all/x' },
|
|
4602
|
-
tileConfig: this.assetTileConfig
|
|
4688
|
+
tileConfig: this.assetTileConfig,
|
|
4689
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
4690
|
+
entityName: 'FixedAsset'
|
|
4603
4691
|
};
|
|
4604
4692
|
//--------------------------Budgets-------------------------
|
|
4605
4693
|
// Budget form configuration
|
|
@@ -4693,7 +4781,9 @@ class AccountingService {
|
|
|
4693
4781
|
{ name: 'delete', inDialog: true, icon: { name: 'delete', color: 'red' }, action: { url: 'budgets?action=delete', method: 'post', successMessage: 'Budget deleted' }, confirm: { message: 'Delete this budget?' }, visible: (x) => x.status == 1 }
|
|
4694
4782
|
],
|
|
4695
4783
|
loadAction: { url: 'budgets/all/x' },
|
|
4696
|
-
formConfig: this.budgetFormConfig
|
|
4784
|
+
formConfig: this.budgetFormConfig,
|
|
4785
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
4786
|
+
entityName: 'Budget'
|
|
4697
4787
|
};
|
|
4698
4788
|
//--------------------------Budget vs Actual Report-------------------------
|
|
4699
4789
|
// Budget vs Actual - By Period detail table
|
|
@@ -4920,7 +5010,9 @@ class LoansService {
|
|
|
4920
5010
|
loadAction: { url: 'loans/all/x' },
|
|
4921
5011
|
minColumns: ['borrowerName', 'principalAmount', 'statusName'],
|
|
4922
5012
|
formConfig: this.loanFormConfig,
|
|
4923
|
-
buttons: [this.loanViewButton, this.loanCreateButton, this.loanEditButton, this.loanDisburseButton]
|
|
5013
|
+
buttons: [this.loanViewButton, this.loanCreateButton, this.loanEditButton, this.loanDisburseButton],
|
|
5014
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
5015
|
+
entityName: 'Loan'
|
|
4924
5016
|
};
|
|
4925
5017
|
// ========== LOAN PAYMENTS BUTTONS ==========
|
|
4926
5018
|
this.loanPaymentCreateButton = { name: 'create', display: 'Record Payment', dialog: true, action: { url: 'loanpayments?action=create', method: 'post' } };
|
|
@@ -4951,7 +5043,9 @@ class LoansService {
|
|
|
4951
5043
|
loadAction: { url: 'loanpayments/all/x' },
|
|
4952
5044
|
minColumns: ['paymentDate', 'customerName', 'amount'],
|
|
4953
5045
|
formConfig: this.loanPaymentFormConfig,
|
|
4954
|
-
buttons: [this.loanPaymentCreateButton]
|
|
5046
|
+
buttons: [this.loanPaymentCreateButton],
|
|
5047
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
5048
|
+
entityName: 'LoanPayment'
|
|
4955
5049
|
};
|
|
4956
5050
|
}
|
|
4957
5051
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: LoansService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
@@ -5002,7 +5096,9 @@ class GeneralService {
|
|
|
5002
5096
|
this.categoryDeleteButton
|
|
5003
5097
|
],
|
|
5004
5098
|
loadAction: { url: 'categories/all/x' },
|
|
5005
|
-
formConfig: this.categoryFormConfig
|
|
5099
|
+
formConfig: this.categoryFormConfig,
|
|
5100
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
5101
|
+
entityName: 'Category'
|
|
5006
5102
|
};
|
|
5007
5103
|
//--------------------------SubCategories-------------------------
|
|
5008
5104
|
this.subCategoryFormConfig = {
|
|
@@ -5041,7 +5137,9 @@ class GeneralService {
|
|
|
5041
5137
|
this.subCategoryDeleteButton
|
|
5042
5138
|
],
|
|
5043
5139
|
loadAction: { url: 'subcategories/all/x' },
|
|
5044
|
-
formConfig: this.subCategoryFormConfig
|
|
5140
|
+
formConfig: this.subCategoryFormConfig,
|
|
5141
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
5142
|
+
entityName: 'SubCategory'
|
|
5045
5143
|
};
|
|
5046
5144
|
//--------------------------Brands-------------------------
|
|
5047
5145
|
this.brandFormConfig = {
|
|
@@ -5077,7 +5175,9 @@ class GeneralService {
|
|
|
5077
5175
|
this.brandDeleteButton
|
|
5078
5176
|
],
|
|
5079
5177
|
loadAction: { url: 'brands/all/x' },
|
|
5080
|
-
formConfig: this.brandFormConfig
|
|
5178
|
+
formConfig: this.brandFormConfig,
|
|
5179
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
5180
|
+
entityName: 'Brand'
|
|
5081
5181
|
};
|
|
5082
5182
|
//--------------------------ListItems-------------------------
|
|
5083
5183
|
this.listItemFormConfig = {
|
|
@@ -5113,7 +5213,9 @@ class GeneralService {
|
|
|
5113
5213
|
this.listItemDeleteButton
|
|
5114
5214
|
],
|
|
5115
5215
|
loadAction: { url: 'listitems/all/x' },
|
|
5116
|
-
formConfig: this.listItemFormConfig
|
|
5216
|
+
formConfig: this.listItemFormConfig,
|
|
5217
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
5218
|
+
entityName: 'ListItem'
|
|
5117
5219
|
};
|
|
5118
5220
|
}
|
|
5119
5221
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: GeneralService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
@@ -5187,7 +5289,9 @@ class InventoryService {
|
|
|
5187
5289
|
this.productDeleteButton,
|
|
5188
5290
|
],
|
|
5189
5291
|
loadAction: { url: 'products/all/x' },
|
|
5190
|
-
formConfig: this.productFormConfig
|
|
5292
|
+
formConfig: this.productFormConfig,
|
|
5293
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
5294
|
+
entityName: 'Product'
|
|
5191
5295
|
};
|
|
5192
5296
|
//--------------------------Product Components (Bundle Configuration)-------------------------
|
|
5193
5297
|
// Product component form for adding/editing bundle components
|
|
@@ -5329,7 +5433,9 @@ class InventoryService {
|
|
|
5329
5433
|
this.serviceItemDeleteButton
|
|
5330
5434
|
],
|
|
5331
5435
|
loadAction: { url: 'serviceitems/all/x' },
|
|
5332
|
-
formConfig: this.serviceItemFormConfig
|
|
5436
|
+
formConfig: this.serviceItemFormConfig,
|
|
5437
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
5438
|
+
entityName: 'ServiceItem'
|
|
5333
5439
|
};
|
|
5334
5440
|
//--------------------------Requisitions-------------------------
|
|
5335
5441
|
this.requisitionItemFormConfig = {
|
|
@@ -5418,7 +5524,9 @@ class InventoryService {
|
|
|
5418
5524
|
this.requisitionCancelButton
|
|
5419
5525
|
],
|
|
5420
5526
|
loadAction: { url: 'requisitions/all/x' },
|
|
5421
|
-
formConfig: this.requisitionFormConfig
|
|
5527
|
+
formConfig: this.requisitionFormConfig,
|
|
5528
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
5529
|
+
entityName: 'Requisition'
|
|
5422
5530
|
};
|
|
5423
5531
|
// Removed: Purchase Orders configs moved to PurchasingService
|
|
5424
5532
|
// Removed: Inventory Receipts configs moved to PurchasingService
|
|
@@ -5462,7 +5570,9 @@ class InventoryService {
|
|
|
5462
5570
|
{ name: 'view', dialog: true, detailsConfig: this.inventoryItemDetailsConfig }
|
|
5463
5571
|
],
|
|
5464
5572
|
loadAction: { url: 'inventoryitems/all/x' },
|
|
5465
|
-
formConfig: this.inventoryItemFormConfig
|
|
5573
|
+
formConfig: this.inventoryItemFormConfig,
|
|
5574
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
5575
|
+
entityName: 'InventoryItem'
|
|
5466
5576
|
};
|
|
5467
5577
|
//--------------------------Inventory Adjustments-------------------------
|
|
5468
5578
|
// Updated: Changed form from all-readonly to editable fields for create/edit
|
|
@@ -5515,7 +5625,9 @@ class InventoryService {
|
|
|
5515
5625
|
this.inventoryAdjustmentDeleteButton
|
|
5516
5626
|
],
|
|
5517
5627
|
loadAction: { url: 'inventoryadjustments/all/x' },
|
|
5518
|
-
formConfig: this.inventoryAdjustmentFormConfig
|
|
5628
|
+
formConfig: this.inventoryAdjustmentFormConfig,
|
|
5629
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
5630
|
+
entityName: 'InventoryAdjustment'
|
|
5519
5631
|
};
|
|
5520
5632
|
//--------------------------Inventory Returns-------------------------
|
|
5521
5633
|
// Added: Return item form config with conditional fields based on return type
|
|
@@ -5619,7 +5731,9 @@ class InventoryService {
|
|
|
5619
5731
|
this.inventoryReturnRejectButton
|
|
5620
5732
|
],
|
|
5621
5733
|
loadAction: { url: 'inventoryreturns/all/x' },
|
|
5622
|
-
formConfig: this.inventoryReturnFormConfig
|
|
5734
|
+
formConfig: this.inventoryReturnFormConfig,
|
|
5735
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
5736
|
+
entityName: 'InventoryReturn'
|
|
5623
5737
|
};
|
|
5624
5738
|
//--------------------------Inventory Transactions-------------------------
|
|
5625
5739
|
this.inventoryTransactionFormConfig = {
|
|
@@ -5660,7 +5774,9 @@ class InventoryService {
|
|
|
5660
5774
|
{ name: 'view', dialog: true, detailsConfig: this.inventoryTransactionDetailsConfig }
|
|
5661
5775
|
],
|
|
5662
5776
|
loadAction: { url: 'inventorytransactions/all/x' },
|
|
5663
|
-
formConfig: this.inventoryTransactionFormConfig
|
|
5777
|
+
formConfig: this.inventoryTransactionFormConfig,
|
|
5778
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
5779
|
+
entityName: 'InventoryTransaction'
|
|
5664
5780
|
};
|
|
5665
5781
|
//--------------------------Inventory Stock (Grouped by Product)-------------------------
|
|
5666
5782
|
// Changed: Reuse existing inventoryItemsTableConfig with product criteria filter
|
|
@@ -6259,9 +6375,20 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
|
|
|
6259
6375
|
|
|
6260
6376
|
// Functional guard for Angular 15+ (replaces deprecated class-based CanActivate)
|
|
6261
6377
|
// Changed: Returns Promise<boolean> to properly await token refresh before allowing navigation
|
|
6262
|
-
const authGuard = (route, state) => {
|
|
6378
|
+
const authGuard = async (route, state) => {
|
|
6263
6379
|
const authService = inject(AuthService);
|
|
6264
|
-
|
|
6380
|
+
const signalRService = inject(SignalRService);
|
|
6381
|
+
const httpService = inject(HttpService);
|
|
6382
|
+
const storageService = inject(StorageService);
|
|
6383
|
+
const isAuthenticated = await authService.checkAuthentication();
|
|
6384
|
+
// Changed: Ensure SignalR data hub connection is started on every authenticated route access
|
|
6385
|
+
if (isAuthenticated) {
|
|
6386
|
+
const dataHubUrl = httpService.apiUrl.replace(/\/api\/$/, '/hubs/data');
|
|
6387
|
+
const token = await storageService.get(Constants.AUTH_TOKEN);
|
|
6388
|
+
if (token)
|
|
6389
|
+
signalRService.startDataConnection(dataHubUrl, token);
|
|
6390
|
+
}
|
|
6391
|
+
return isAuthenticated;
|
|
6265
6392
|
};
|
|
6266
6393
|
|
|
6267
6394
|
// Functional guard for plan-based feature gating — blocks navigation to restricted routes
|
|
@@ -11260,11 +11387,11 @@ class TableHeaderComponent {
|
|
|
11260
11387
|
return this.buttonService.getButtonColor(button, row);
|
|
11261
11388
|
}
|
|
11262
11389
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TableHeaderComponent, deps: [{ token: ButtonService }, { token: DialogService }, { token: MessageService }, { token: CsvService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11263
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TableHeaderComponent, isStandalone: false, selector: "app-table-header", inputs: { lastSearch: "lastSearch", config: "config", hideTitle: "hideTitle", tableDataSource: "tableDataSource", tileConfig: "tileConfig", smallScreen: "smallScreen", tileReload: "tileReload", showFilterButton: "showFilterButton", data: "data", tileData: "tileData" }, outputs: { createClick: "createClick", customClick: "customClick", refreshClick: "refreshClick", tileClick: "tileClick", tileUnClick: "tileUnClick" }, ngImport: i0, template: "<!--Tiles Top Position -->\r\n<ng-container *ngIf=\"config.tileConfig && !smallScreen && config.tileConfig.headerPosition == 'top'\">\r\n <spa-tiles [config]=\"config.tileConfig\" [reload]=\"tileReload\" [data]=\"tileData\" [lastSearch]=\"lastSearch\" (tileClick)=\"onTileClick($event)\" (tileUnClick)=\"onTileUnClick($event)\"></spa-tiles>\r\n</ng-container>\r\n\r\n<div class=\"top\">\r\n\r\n <!-- buttons -->\r\n <div class=\"tin-row\" style=\"margin-right: 10px;\" *ngIf=\"getHeaderButtons().length > 0\" >\r\n\r\n <ng-container *ngFor=\"let button of getHeaderButtons()\">\r\n <ng-container *ngIf=\"testVisible(button)\" >\r\n <button *ngIf=\"!config.flatButtons\" mat-raised-button color=\"primary\" [disabled]=\"testDisabled(button)\" (click)=\"onButtonClick(button)\" >\r\n {{button.display}}\r\n </button>\r\n <button *ngIf=\"config.flatButtons\" mat-stroked-button [disabled]=\"testDisabled(button)\" (click)=\"onButtonClick(button)\" [ngStyle]=\"{'color': getButtonColor(button, config.parentData)}\">\r\n {{button.display}}\r\n </button>\r\n </ng-container>\r\n </ng-container>\r\n\r\n </div>\r\n <div *ngIf=\"getHeaderButtons().length == 0 && config.holdHeaderButtonSpace || getHeaderButtons().length == 0 && !config.tileConfig\"></div>\r\n\r\n <!-- tiles -->\r\n <div *ngIf=\"config.tileConfig && !smallScreen && (!config.tileConfig.headerPosition || config.tileConfig.headerPosition == 'middle')\" style=\"min-width: 75%;\">\r\n <spa-tiles [config]=\"config.tileConfig\" [reload]=\"tileReload\" [data]=\"tileData\" [lastSearch]=\"lastSearch\" (tileClick)=\"onTileClick($event)\" (tileUnClick)=\"onTileUnClick($event)\"></spa-tiles>\r\n </div>\r\n\r\n <!-- filter -->\r\n <div class=\"tin-row d-flex justify-content-end\" >\r\n\r\n <button *ngIf=\"config.download && testVisibleHeaderButton(config.download)\" mat-icon-button class=\"header-action-btn\" matTooltip=\"Download\" matTooltipPosition=\"above\" color=\"primary\" (click)=\"onDownloadClick()\">\r\n <mat-icon>download</mat-icon>\r\n </button>\r\n\r\n <button *ngIf=\"config.upload && testVisibleHeaderButton(config.upload)\" mat-icon-button class=\"header-action-btn\" matTooltip=\"Upload\" matTooltipPosition=\"above\" color=\"primary\" (click)=\"onUploadClick()\">\r\n <mat-icon>upload</mat-icon>\r\n </button>\r\n\r\n <div *ngIf=\"config.showFilter\" >\r\n <spa-filter [showText]=\"!smallScreen || (smallScreen && tableDataSource?.data?.length > 10)\" [showButton]=\"showFilterButton\" [data]=\"tableDataSource\" [flatButtons]=\"config.flatButtons\" [smallScreen]=\"smallScreen\" (refreshClick)=\"onRefreshClick()\"></spa-filter> <!-- Changed: Use .data.length for MatTableDataSource, pass smallScreen for compact width -->\r\n </div>\r\n <div *ngIf=\"!config.showFilter && config.holdFilterSpace\"></div>\r\n </div>\r\n\r\n\r\n</div>\r\n\r\n
|
|
11390
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TableHeaderComponent, isStandalone: false, selector: "app-table-header", inputs: { lastSearch: "lastSearch", config: "config", hideTitle: "hideTitle", tableDataSource: "tableDataSource", tileConfig: "tileConfig", smallScreen: "smallScreen", tileReload: "tileReload", showFilterButton: "showFilterButton", data: "data", tileData: "tileData" }, outputs: { createClick: "createClick", customClick: "customClick", refreshClick: "refreshClick", tileClick: "tileClick", tileUnClick: "tileUnClick" }, ngImport: i0, template: "<!--Tiles Top Position -->\r\n<ng-container *ngIf=\"config.tileConfig && !smallScreen && config.tileConfig.headerPosition == 'top'\">\r\n <spa-tiles [config]=\"config.tileConfig\" [reload]=\"tileReload\" [data]=\"tileData\" [lastSearch]=\"lastSearch\" (tileClick)=\"onTileClick($event)\" (tileUnClick)=\"onTileUnClick($event)\"></spa-tiles>\r\n</ng-container>\r\n\r\n<!-- Changed: Small screen tiles render above header buttons/filter -->\r\n<div *ngIf=\"config.tileConfig && smallScreen\" style=\"width: 100%;\">\r\n <spa-tiles [config]=\"config.tileConfig\" [reload]=\"tileReload\" [data]=\"tileData\" [lastSearch]=\"lastSearch\" (tileClick)=\"onTileClick($event)\" (tileUnClick)=\"onTileUnClick($event)\"></spa-tiles>\r\n</div>\r\n\r\n<div class=\"top\">\r\n\r\n <!-- buttons -->\r\n <div class=\"tin-row\" style=\"margin-right: 10px;\" *ngIf=\"getHeaderButtons().length > 0\" >\r\n\r\n <ng-container *ngFor=\"let button of getHeaderButtons()\">\r\n <ng-container *ngIf=\"testVisible(button)\" >\r\n <button *ngIf=\"!config.flatButtons\" mat-raised-button color=\"primary\" [disabled]=\"testDisabled(button)\" (click)=\"onButtonClick(button)\" >\r\n {{button.display}}\r\n </button>\r\n <button *ngIf=\"config.flatButtons\" mat-stroked-button [disabled]=\"testDisabled(button)\" (click)=\"onButtonClick(button)\" [ngStyle]=\"{'color': getButtonColor(button, config.parentData)}\">\r\n {{button.display}}\r\n </button>\r\n </ng-container>\r\n </ng-container>\r\n\r\n </div>\r\n <div *ngIf=\"getHeaderButtons().length == 0 && config.holdHeaderButtonSpace || getHeaderButtons().length == 0 && !config.tileConfig\"></div>\r\n\r\n <!-- tiles -->\r\n <div *ngIf=\"config.tileConfig && !smallScreen && (!config.tileConfig.headerPosition || config.tileConfig.headerPosition == 'middle')\" style=\"min-width: 75%;\">\r\n <spa-tiles [config]=\"config.tileConfig\" [reload]=\"tileReload\" [data]=\"tileData\" [lastSearch]=\"lastSearch\" (tileClick)=\"onTileClick($event)\" (tileUnClick)=\"onTileUnClick($event)\"></spa-tiles>\r\n </div>\r\n\r\n <!-- filter -->\r\n <div class=\"tin-row d-flex justify-content-end\" >\r\n\r\n <button *ngIf=\"config.download && testVisibleHeaderButton(config.download)\" mat-icon-button class=\"header-action-btn\" matTooltip=\"Download\" matTooltipPosition=\"above\" color=\"primary\" (click)=\"onDownloadClick()\">\r\n <mat-icon>download</mat-icon>\r\n </button>\r\n\r\n <button *ngIf=\"config.upload && testVisibleHeaderButton(config.upload)\" mat-icon-button class=\"header-action-btn\" matTooltip=\"Upload\" matTooltipPosition=\"above\" color=\"primary\" (click)=\"onUploadClick()\">\r\n <mat-icon>upload</mat-icon>\r\n </button>\r\n\r\n <div *ngIf=\"config.showFilter\" >\r\n <spa-filter [showText]=\"!smallScreen || (smallScreen && tableDataSource?.data?.length > 10)\" [showButton]=\"showFilterButton\" [data]=\"tableDataSource\" [flatButtons]=\"config.flatButtons\" [smallScreen]=\"smallScreen\" (refreshClick)=\"onRefreshClick()\"></spa-filter> <!-- Changed: Use .data.length for MatTableDataSource, pass smallScreen for compact width -->\r\n </div>\r\n <div *ngIf=\"!config.showFilter && config.holdFilterSpace\"></div>\r\n </div>\r\n\r\n\r\n</div>\r\n\r\n<!-- <div *ngIf=\"config.title && !hideTitle\" class=\"title\">\r\n {{config.title | camelToWords}}\r\n</div> -->\r\n", styles: [".top{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:center;row-gap:8px;margin-bottom:10px;margin-top:10px}.mat-mini-fab{width:32px;height:32px}.mat-mini-fab mat-icon{font-size:16px;margin-top:-3px}.header-action-btn{width:20px!important;height:20px!important}.header-action-btn mat-icon{font-size:18px!important;margin-top:0!important}.col-icon{margin-left:10px}.title{margin-top:10px;font-size:larger;font-weight:300}.make-gray{background-color:#e5e5e5}.right-padding{padding-right:10px}.action-buttons-container{display:flex;justify-content:flex-end;align-items:center}.refreshIcon{font-size:22px!important;margin-top:-7px!important}.tin-row{display:flex;align-items:center}\n"], dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: FilterComponent, selector: "spa-filter", inputs: ["flatButtons", "showText", "showButton", "smallScreen", "data"], outputs: ["refreshClick"] }, { kind: "component", type: TilesComponent, selector: "spa-tiles", inputs: ["config", "lastSearch", "data", "reload"], outputs: ["tileActionSelected", "tileClick", "tileUnClick"] }] }); }
|
|
11264
11391
|
}
|
|
11265
11392
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TableHeaderComponent, decorators: [{
|
|
11266
11393
|
type: Component,
|
|
11267
|
-
args: [{ selector: 'app-table-header', standalone: false, template: "<!--Tiles Top Position -->\r\n<ng-container *ngIf=\"config.tileConfig && !smallScreen && config.tileConfig.headerPosition == 'top'\">\r\n <spa-tiles [config]=\"config.tileConfig\" [reload]=\"tileReload\" [data]=\"tileData\" [lastSearch]=\"lastSearch\" (tileClick)=\"onTileClick($event)\" (tileUnClick)=\"onTileUnClick($event)\"></spa-tiles>\r\n</ng-container>\r\n\r\n<div class=\"top\">\r\n\r\n <!-- buttons -->\r\n <div class=\"tin-row\" style=\"margin-right: 10px;\" *ngIf=\"getHeaderButtons().length > 0\" >\r\n\r\n <ng-container *ngFor=\"let button of getHeaderButtons()\">\r\n <ng-container *ngIf=\"testVisible(button)\" >\r\n <button *ngIf=\"!config.flatButtons\" mat-raised-button color=\"primary\" [disabled]=\"testDisabled(button)\" (click)=\"onButtonClick(button)\" >\r\n {{button.display}}\r\n </button>\r\n <button *ngIf=\"config.flatButtons\" mat-stroked-button [disabled]=\"testDisabled(button)\" (click)=\"onButtonClick(button)\" [ngStyle]=\"{'color': getButtonColor(button, config.parentData)}\">\r\n {{button.display}}\r\n </button>\r\n </ng-container>\r\n </ng-container>\r\n\r\n </div>\r\n <div *ngIf=\"getHeaderButtons().length == 0 && config.holdHeaderButtonSpace || getHeaderButtons().length == 0 && !config.tileConfig\"></div>\r\n\r\n <!-- tiles -->\r\n <div *ngIf=\"config.tileConfig && !smallScreen && (!config.tileConfig.headerPosition || config.tileConfig.headerPosition == 'middle')\" style=\"min-width: 75%;\">\r\n <spa-tiles [config]=\"config.tileConfig\" [reload]=\"tileReload\" [data]=\"tileData\" [lastSearch]=\"lastSearch\" (tileClick)=\"onTileClick($event)\" (tileUnClick)=\"onTileUnClick($event)\"></spa-tiles>\r\n </div>\r\n\r\n <!-- filter -->\r\n <div class=\"tin-row d-flex justify-content-end\" >\r\n\r\n <button *ngIf=\"config.download && testVisibleHeaderButton(config.download)\" mat-icon-button class=\"header-action-btn\" matTooltip=\"Download\" matTooltipPosition=\"above\" color=\"primary\" (click)=\"onDownloadClick()\">\r\n <mat-icon>download</mat-icon>\r\n </button>\r\n\r\n <button *ngIf=\"config.upload && testVisibleHeaderButton(config.upload)\" mat-icon-button class=\"header-action-btn\" matTooltip=\"Upload\" matTooltipPosition=\"above\" color=\"primary\" (click)=\"onUploadClick()\">\r\n <mat-icon>upload</mat-icon>\r\n </button>\r\n\r\n <div *ngIf=\"config.showFilter\" >\r\n <spa-filter [showText]=\"!smallScreen || (smallScreen && tableDataSource?.data?.length > 10)\" [showButton]=\"showFilterButton\" [data]=\"tableDataSource\" [flatButtons]=\"config.flatButtons\" [smallScreen]=\"smallScreen\" (refreshClick)=\"onRefreshClick()\"></spa-filter> <!-- Changed: Use .data.length for MatTableDataSource, pass smallScreen for compact width -->\r\n </div>\r\n <div *ngIf=\"!config.showFilter && config.holdFilterSpace\"></div>\r\n </div>\r\n\r\n\r\n</div>\r\n\r\n
|
|
11394
|
+
args: [{ selector: 'app-table-header', standalone: false, template: "<!--Tiles Top Position -->\r\n<ng-container *ngIf=\"config.tileConfig && !smallScreen && config.tileConfig.headerPosition == 'top'\">\r\n <spa-tiles [config]=\"config.tileConfig\" [reload]=\"tileReload\" [data]=\"tileData\" [lastSearch]=\"lastSearch\" (tileClick)=\"onTileClick($event)\" (tileUnClick)=\"onTileUnClick($event)\"></spa-tiles>\r\n</ng-container>\r\n\r\n<!-- Changed: Small screen tiles render above header buttons/filter -->\r\n<div *ngIf=\"config.tileConfig && smallScreen\" style=\"width: 100%;\">\r\n <spa-tiles [config]=\"config.tileConfig\" [reload]=\"tileReload\" [data]=\"tileData\" [lastSearch]=\"lastSearch\" (tileClick)=\"onTileClick($event)\" (tileUnClick)=\"onTileUnClick($event)\"></spa-tiles>\r\n</div>\r\n\r\n<div class=\"top\">\r\n\r\n <!-- buttons -->\r\n <div class=\"tin-row\" style=\"margin-right: 10px;\" *ngIf=\"getHeaderButtons().length > 0\" >\r\n\r\n <ng-container *ngFor=\"let button of getHeaderButtons()\">\r\n <ng-container *ngIf=\"testVisible(button)\" >\r\n <button *ngIf=\"!config.flatButtons\" mat-raised-button color=\"primary\" [disabled]=\"testDisabled(button)\" (click)=\"onButtonClick(button)\" >\r\n {{button.display}}\r\n </button>\r\n <button *ngIf=\"config.flatButtons\" mat-stroked-button [disabled]=\"testDisabled(button)\" (click)=\"onButtonClick(button)\" [ngStyle]=\"{'color': getButtonColor(button, config.parentData)}\">\r\n {{button.display}}\r\n </button>\r\n </ng-container>\r\n </ng-container>\r\n\r\n </div>\r\n <div *ngIf=\"getHeaderButtons().length == 0 && config.holdHeaderButtonSpace || getHeaderButtons().length == 0 && !config.tileConfig\"></div>\r\n\r\n <!-- tiles -->\r\n <div *ngIf=\"config.tileConfig && !smallScreen && (!config.tileConfig.headerPosition || config.tileConfig.headerPosition == 'middle')\" style=\"min-width: 75%;\">\r\n <spa-tiles [config]=\"config.tileConfig\" [reload]=\"tileReload\" [data]=\"tileData\" [lastSearch]=\"lastSearch\" (tileClick)=\"onTileClick($event)\" (tileUnClick)=\"onTileUnClick($event)\"></spa-tiles>\r\n </div>\r\n\r\n <!-- filter -->\r\n <div class=\"tin-row d-flex justify-content-end\" >\r\n\r\n <button *ngIf=\"config.download && testVisibleHeaderButton(config.download)\" mat-icon-button class=\"header-action-btn\" matTooltip=\"Download\" matTooltipPosition=\"above\" color=\"primary\" (click)=\"onDownloadClick()\">\r\n <mat-icon>download</mat-icon>\r\n </button>\r\n\r\n <button *ngIf=\"config.upload && testVisibleHeaderButton(config.upload)\" mat-icon-button class=\"header-action-btn\" matTooltip=\"Upload\" matTooltipPosition=\"above\" color=\"primary\" (click)=\"onUploadClick()\">\r\n <mat-icon>upload</mat-icon>\r\n </button>\r\n\r\n <div *ngIf=\"config.showFilter\" >\r\n <spa-filter [showText]=\"!smallScreen || (smallScreen && tableDataSource?.data?.length > 10)\" [showButton]=\"showFilterButton\" [data]=\"tableDataSource\" [flatButtons]=\"config.flatButtons\" [smallScreen]=\"smallScreen\" (refreshClick)=\"onRefreshClick()\"></spa-filter> <!-- Changed: Use .data.length for MatTableDataSource, pass smallScreen for compact width -->\r\n </div>\r\n <div *ngIf=\"!config.showFilter && config.holdFilterSpace\"></div>\r\n </div>\r\n\r\n\r\n</div>\r\n\r\n<!-- <div *ngIf=\"config.title && !hideTitle\" class=\"title\">\r\n {{config.title | camelToWords}}\r\n</div> -->\r\n", styles: [".top{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:center;row-gap:8px;margin-bottom:10px;margin-top:10px}.mat-mini-fab{width:32px;height:32px}.mat-mini-fab mat-icon{font-size:16px;margin-top:-3px}.header-action-btn{width:20px!important;height:20px!important}.header-action-btn mat-icon{font-size:18px!important;margin-top:0!important}.col-icon{margin-left:10px}.title{margin-top:10px;font-size:larger;font-weight:300}.make-gray{background-color:#e5e5e5}.right-padding{padding-right:10px}.action-buttons-container{display:flex;justify-content:flex-end;align-items:center}.refreshIcon{font-size:22px!important;margin-top:-7px!important}.tin-row{display:flex;align-items:center}\n"] }]
|
|
11268
11395
|
}], ctorParameters: () => [{ type: ButtonService }, { type: DialogService }, { type: MessageService }, { type: CsvService }], propDecorators: { lastSearch: [{
|
|
11269
11396
|
type: Input
|
|
11270
11397
|
}], config: [{
|
|
@@ -11359,11 +11486,11 @@ class TableRowComponent {
|
|
|
11359
11486
|
return false;
|
|
11360
11487
|
}
|
|
11361
11488
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TableRowComponent, deps: [{ token: ButtonService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
11362
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TableRowComponent, isStandalone: false, selector: "app-table-row", inputs: { column: "column", row: "row", config: "config", smallScreen: "smallScreen" }, outputs: { actionClick: "actionClick", columnClick: "columnClick", showBannerEvent: "showBannerEvent" }, ngImport: i0, template: "<ng-container [ngSwitch]=\"column.type\">\r\n <ng-container *ngSwitchCase=\"'checkbox'\">\r\n <spa-check [value]=\"row[column.name]\" [readonly]=\"true\"></spa-check>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'select'\">\r\n <spa-select-lite [options]=\"column.options\" [optionDisplay]=\"column.optionDisplay\" [optionValue]=\"column.optionValue\" [(value)]=\"row[column.name]\" width=\"90%\"></spa-select-lite>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'chip'\">\r\n <button mat-stroked-button (click)=\"onColumnClick(column, row)\" [ngStyle]=\"{'background-color': getColorOnCondition(row, column), 'color': 'rgba(0, 0, 0, 0.87)', 'border': 'none'}\">{{row[column.name]}}</button>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'icon'\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'date'\">\r\n {{row[column.name] | date : 'dd/MM/yyyy'}}\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'datetime'\">\r\n {{row[column.name] | date : 'dd/MM/yyyy HH:mm'}}\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'datetimesec'\">\r\n {{row[column.name] | date : 'dd/MM/yyyy HH:mm:ss'}}\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'money'\">\r\n <label [ngStyle]=\"{'color': getColorOnCondition(row, column) }\">{{row[column.name] | currency:'':''}}</label>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'button'\">\r\n <button mat-stroked-button (click)=\"onColumnClick(column, row)\" [ngStyle]=\"{'color': getColorOnCondition(row, column)}\" >{{row[column.name]}}</button>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchDefault>\r\n <label [ngStyle]=\"{'color': getColorOnCondition(row, column) }\">\r\n <ng-container *ngIf=\"column.type === 'number'\">\r\n {{row[column.name] | number:'1.0-2'}}\r\n </ng-container>\r\n <ng-container *ngIf=\"column.type !== 'number'\">\r\n {{textDisplayed(row, column)}}\r\n </ng-container>\r\n </label>\r\n <mat-icon class=\"col-icon\" *ngIf=\"textTruncated(row, column)\" matTooltip='Show more' matTooltipPosition=\"above\" (click)=\"showBanner(row[column.name])\">more_horiz</mat-icon>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n</ng-container>\r\n", styles: [".top{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:center;margin-bottom:10px;margin-top:10px}.mat-mini-fab{width:32px;height:32px}.mat-mini-fab mat-icon{font-size:16px;margin-top:-3px}.mat-icon-button{width:32px;height:32px}.mat-icon-button mat-icon{font-size:20px;margin-top:-7px}.col-icon{margin-left:10px;vertical-align:middle}.title{margin-top:10px;font-size:larger;font-weight:300}.make-gray{background-color:#e5e5e5}.right-padding{padding-right:10px}.action-buttons-container{display:flex;justify-content:flex-end;align-items:center}.refreshIcon{font-size:22px!important;margin-top:-7px!important}.table-chip{font-size:14px!important;font-weight:500!important;letter-spacing:.25px!important;padding:8px 20px!important;min-height:36px!important;height:auto!important;border-radius:24px!important;cursor:pointer!important;transition:all .2s ease!important;color:#000000de!important;box-shadow:none!important;border:1.5px solid rgba(0,0,0,.2)!important;text-transform:none!important;white-space:nowrap!important;background-clip:padding-box!important}.table-chip:hover{transform:none!important;box-shadow:none!important;filter:brightness(.96)!important;border-color:#0000004d!important}.table-chip:active{transform:scale(.98)!important;box-shadow:none!important;transition-duration:.1s!important;filter:brightness(.92)!important}\n"], dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i2.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i2.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: CheckComponent, selector: "spa-check", inputs: ["readonly", "display", "value", "infoMessage"], outputs: ["valueChange", "click", "check", "uncheck", "infoClick"] }, { kind: "component", type: SelectLiteComponent, selector: "spa-select-lite" }, { kind: "pipe", type: i2.DecimalPipe, name: "number" }, { kind: "pipe", type: i2.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i2.DatePipe, name: "date" }] }); }
|
|
11489
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TableRowComponent, isStandalone: false, selector: "app-table-row", inputs: { column: "column", row: "row", config: "config", smallScreen: "smallScreen" }, outputs: { actionClick: "actionClick", columnClick: "columnClick", showBannerEvent: "showBannerEvent" }, ngImport: i0, template: "<ng-container [ngSwitch]=\"column.type\">\r\n <ng-container *ngSwitchCase=\"'checkbox'\">\r\n <spa-check [value]=\"row[column.name]\" [readonly]=\"true\"></spa-check>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'select'\">\r\n <spa-select-lite [options]=\"column.options\" [optionDisplay]=\"column.optionDisplay\" [optionValue]=\"column.optionValue\" [(value)]=\"row[column.name]\" width=\"90%\"></spa-select-lite>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'chip'\">\r\n <button mat-stroked-button (click)=\"onColumnClick(column, row)\" [ngStyle]=\"{'background-color': getColorOnCondition(row, column), 'color': 'rgba(0, 0, 0, 0.87)', 'border': 'none'}\">{{row[column.name]}}</button>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'icon'\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'date'\">\r\n {{row[column.name] | date : 'dd/MM/yyyy'}}\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'datetime'\">\r\n {{row[column.name] | date : 'dd/MM/yyyy HH:mm'}}\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'datetimesec'\">\r\n {{row[column.name] | date : 'dd/MM/yyyy HH:mm:ss'}}\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'money'\">\r\n <label [ngStyle]=\"{'color': getColorOnCondition(row, column) }\">{{row[column.name] | currency:'':''}}</label>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'button'\">\r\n <button mat-stroked-button (click)=\"onColumnClick(column, row)\" [ngStyle]=\"{'color': getColorOnCondition(row, column)}\" >{{row[column.name]}}</button>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchDefault>\r\n <label [ngStyle]=\"{'color': getColorOnCondition(row, column) }\">\r\n <ng-container *ngIf=\"column.type === 'number'\">\r\n {{row[column.name] | number:'1.0-2'}}\r\n </ng-container>\r\n <ng-container *ngIf=\"column.type !== 'number'\">\r\n {{textDisplayed(row, column)}}\r\n </ng-container>\r\n </label>\r\n <mat-icon class=\"col-icon\" *ngIf=\"textTruncated(row, column)\" matTooltip='Show more' matTooltipPosition=\"above\" (click)=\"showBanner(row[column.name])\">more_horiz</mat-icon>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n</ng-container>\r\n", styles: [".top{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:center;margin-bottom:10px;margin-top:10px}.mat-mini-fab{width:32px;height:32px}.mat-mini-fab mat-icon{font-size:16px;margin-top:-3px}.mat-icon-button{width:32px;height:32px}.mat-icon-button mat-icon{font-size:20px;margin-top:-7px}.col-icon{margin-left:10px;vertical-align:middle}.title{margin-top:10px;font-size:larger;font-weight:300}.make-gray{background-color:#e5e5e5}.right-padding{padding-right:10px}.action-buttons-container{display:flex;justify-content:flex-end;align-items:center}.refreshIcon{font-size:22px!important;margin-top:-7px!important}.mat-mdc-cell .mat-mdc-outlined-button,.mat-mdc-cell .mat-mdc-button-base:not(.mat-mdc-icon-button){height:auto!important;min-height:36px!important;white-space:normal!important;word-break:break-word!important;overflow-wrap:break-word!important;line-height:1.4!important;text-align:left!important;padding:6px 16px!important}.mat-mdc-cell .mat-mdc-outlined-button .mdc-button__label,.mat-mdc-cell .mat-mdc-button-base:not(.mat-mdc-icon-button) .mdc-button__label{white-space:normal!important;word-break:break-word!important;overflow-wrap:break-word!important}\n"], dependencies: [{ kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "directive", type: i2.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { kind: "directive", type: i2.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { kind: "directive", type: i2.NgSwitchDefault, selector: "[ngSwitchDefault]" }, { kind: "component", type: i4.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i4$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: i8.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "component", type: CheckComponent, selector: "spa-check", inputs: ["readonly", "display", "value", "infoMessage"], outputs: ["valueChange", "click", "check", "uncheck", "infoClick"] }, { kind: "component", type: SelectLiteComponent, selector: "spa-select-lite" }, { kind: "pipe", type: i2.DecimalPipe, name: "number" }, { kind: "pipe", type: i2.CurrencyPipe, name: "currency" }, { kind: "pipe", type: i2.DatePipe, name: "date" }], encapsulation: i0.ViewEncapsulation.None }); }
|
|
11363
11490
|
}
|
|
11364
11491
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TableRowComponent, decorators: [{
|
|
11365
11492
|
type: Component,
|
|
11366
|
-
args: [{ selector: 'app-table-row', standalone: false, template: "<ng-container [ngSwitch]=\"column.type\">\r\n <ng-container *ngSwitchCase=\"'checkbox'\">\r\n <spa-check [value]=\"row[column.name]\" [readonly]=\"true\"></spa-check>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'select'\">\r\n <spa-select-lite [options]=\"column.options\" [optionDisplay]=\"column.optionDisplay\" [optionValue]=\"column.optionValue\" [(value)]=\"row[column.name]\" width=\"90%\"></spa-select-lite>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'chip'\">\r\n <button mat-stroked-button (click)=\"onColumnClick(column, row)\" [ngStyle]=\"{'background-color': getColorOnCondition(row, column), 'color': 'rgba(0, 0, 0, 0.87)', 'border': 'none'}\">{{row[column.name]}}</button>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'icon'\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'date'\">\r\n {{row[column.name] | date : 'dd/MM/yyyy'}}\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'datetime'\">\r\n {{row[column.name] | date : 'dd/MM/yyyy HH:mm'}}\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'datetimesec'\">\r\n {{row[column.name] | date : 'dd/MM/yyyy HH:mm:ss'}}\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'money'\">\r\n <label [ngStyle]=\"{'color': getColorOnCondition(row, column) }\">{{row[column.name] | currency:'':''}}</label>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'button'\">\r\n <button mat-stroked-button (click)=\"onColumnClick(column, row)\" [ngStyle]=\"{'color': getColorOnCondition(row, column)}\" >{{row[column.name]}}</button>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchDefault>\r\n <label [ngStyle]=\"{'color': getColorOnCondition(row, column) }\">\r\n <ng-container *ngIf=\"column.type === 'number'\">\r\n {{row[column.name] | number:'1.0-2'}}\r\n </ng-container>\r\n <ng-container *ngIf=\"column.type !== 'number'\">\r\n {{textDisplayed(row, column)}}\r\n </ng-container>\r\n </label>\r\n <mat-icon class=\"col-icon\" *ngIf=\"textTruncated(row, column)\" matTooltip='Show more' matTooltipPosition=\"above\" (click)=\"showBanner(row[column.name])\">more_horiz</mat-icon>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n</ng-container>\r\n", styles: [".top{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:center;margin-bottom:10px;margin-top:10px}.mat-mini-fab{width:32px;height:32px}.mat-mini-fab mat-icon{font-size:16px;margin-top:-3px}.mat-icon-button{width:32px;height:32px}.mat-icon-button mat-icon{font-size:20px;margin-top:-7px}.col-icon{margin-left:10px;vertical-align:middle}.title{margin-top:10px;font-size:larger;font-weight:300}.make-gray{background-color:#e5e5e5}.right-padding{padding-right:10px}.action-buttons-container{display:flex;justify-content:flex-end;align-items:center}.refreshIcon{font-size:22px!important;margin-top:-7px!important}.
|
|
11493
|
+
args: [{ selector: 'app-table-row', encapsulation: ViewEncapsulation.None, standalone: false, template: "<ng-container [ngSwitch]=\"column.type\">\r\n <ng-container *ngSwitchCase=\"'checkbox'\">\r\n <spa-check [value]=\"row[column.name]\" [readonly]=\"true\"></spa-check>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'select'\">\r\n <spa-select-lite [options]=\"column.options\" [optionDisplay]=\"column.optionDisplay\" [optionValue]=\"column.optionValue\" [(value)]=\"row[column.name]\" width=\"90%\"></spa-select-lite>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'chip'\">\r\n <button mat-stroked-button (click)=\"onColumnClick(column, row)\" [ngStyle]=\"{'background-color': getColorOnCondition(row, column), 'color': 'rgba(0, 0, 0, 0.87)', 'border': 'none'}\">{{row[column.name]}}</button>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'icon'\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'date'\">\r\n {{row[column.name] | date : 'dd/MM/yyyy'}}\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'datetime'\">\r\n {{row[column.name] | date : 'dd/MM/yyyy HH:mm'}}\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'datetimesec'\">\r\n {{row[column.name] | date : 'dd/MM/yyyy HH:mm:ss'}}\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'money'\">\r\n <label [ngStyle]=\"{'color': getColorOnCondition(row, column) }\">{{row[column.name] | currency:'':''}}</label>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchCase=\"'button'\">\r\n <button mat-stroked-button (click)=\"onColumnClick(column, row)\" [ngStyle]=\"{'color': getColorOnCondition(row, column)}\" >{{row[column.name]}}</button>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n\r\n <ng-container *ngSwitchDefault>\r\n <label [ngStyle]=\"{'color': getColorOnCondition(row, column) }\">\r\n <ng-container *ngIf=\"column.type === 'number'\">\r\n {{row[column.name] | number:'1.0-2'}}\r\n </ng-container>\r\n <ng-container *ngIf=\"column.type !== 'number'\">\r\n {{textDisplayed(row, column)}}\r\n </ng-container>\r\n </label>\r\n <mat-icon class=\"col-icon\" *ngIf=\"textTruncated(row, column)\" matTooltip='Show more' matTooltipPosition=\"above\" (click)=\"showBanner(row[column.name])\">more_horiz</mat-icon>\r\n <mat-icon class=\"col-icon\" *ngIf=\"column.icon && testIconCondition(row, column.icon)\" [matTooltip]=\"row[column.icon.tipField] ?? column.icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[column.icon.tipField])\" [ngStyle]=\"{'color':column.icon?.color}\">{{column.icon.name }}</mat-icon>\r\n <ng-container *ngFor=\"let icon of column.icons\">\r\n <mat-icon class=\"col-icon\" *ngIf=\"testIconCondition(row, icon)\" [matTooltip]=\"row[icon.tipField] ?? icon?.tip\" matTooltipPosition=\"above\" (click)=\"showBanner(row[icon.tipField])\" [ngStyle]=\"{'color':icon?.color}\">{{icon.name }}</mat-icon>\r\n </ng-container>\r\n </ng-container>\r\n</ng-container>\r\n", styles: [".top{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:center;margin-bottom:10px;margin-top:10px}.mat-mini-fab{width:32px;height:32px}.mat-mini-fab mat-icon{font-size:16px;margin-top:-3px}.mat-icon-button{width:32px;height:32px}.mat-icon-button mat-icon{font-size:20px;margin-top:-7px}.col-icon{margin-left:10px;vertical-align:middle}.title{margin-top:10px;font-size:larger;font-weight:300}.make-gray{background-color:#e5e5e5}.right-padding{padding-right:10px}.action-buttons-container{display:flex;justify-content:flex-end;align-items:center}.refreshIcon{font-size:22px!important;margin-top:-7px!important}.mat-mdc-cell .mat-mdc-outlined-button,.mat-mdc-cell .mat-mdc-button-base:not(.mat-mdc-icon-button){height:auto!important;min-height:36px!important;white-space:normal!important;word-break:break-word!important;overflow-wrap:break-word!important;line-height:1.4!important;text-align:left!important;padding:6px 16px!important}.mat-mdc-cell .mat-mdc-outlined-button .mdc-button__label,.mat-mdc-cell .mat-mdc-button-base:not(.mat-mdc-icon-button) .mdc-button__label{white-space:normal!important;word-break:break-word!important;overflow-wrap:break-word!important}\n"] }]
|
|
11367
11494
|
}], ctorParameters: () => [{ type: ButtonService }], propDecorators: { column: [{
|
|
11368
11495
|
type: Input
|
|
11369
11496
|
}], row: [{
|
|
@@ -12245,7 +12372,7 @@ class TableLiteComponent {
|
|
|
12245
12372
|
}
|
|
12246
12373
|
}
|
|
12247
12374
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TableLiteComponent, deps: [{ token: DataServiceLib }, { token: MessageService }, { token: i1$3.BreakpointObserver }, { token: i1.MatDialog }, { token: ButtonService }, { token: DialogService }, { token: TableConfigService }, { token: ConditionService }, { token: AuthService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
12248
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TableLiteComponent, isStandalone: false, selector: "spa-table-lite", inputs: { data: "data", tileData: "tileData", config: "config", reload: "reload", activeTab: "activeTab", inTab: "inTab" }, outputs: { dataLoad: "dataLoad", actionSuccess: "actionSuccess", refreshClick: "refreshClick", searchClick: "searchClick", createClick: "createClick", actionClick: "actionClick", inputChange: "inputChange", actionResponse: "actionResponse" }, viewQueries: [{ propertyName: "tablePaginator", first: true, predicate: ["tablePaginator"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "\r\n<ng-container *ngIf=\"hasFormAccess\">\r\n\r\n <!-- Search -->\r\n <spa-search\r\n *ngIf=\"config.searchConfig\" [config]=\"config.searchConfig\" [smallScreen]=\"smallScreen\" [tableDataSource]=\"tableDataSource\" style=\"margin-bottom: 20px;\" (searchClick)=\"searchClicked($event)\">\r\n </spa-search>\r\n\r\n <!-- Header -->\r\n <app-table-header\r\n [config]=\"config\" [data]=\"dataSource\" [tableDataSource]=\"tableDataSource\" [tileConfig]=\"config.tileConfig\" [tileData]=\"tileData\" [tileReload]=\"tileReload\" [lastSearch]=\"lastSearch\" [smallScreen]=\"smallScreen\"\r\n [showFilterButton]=\"showFilterButton\" (createClick)=\"newModel()\" (customClick)=\"customModel($event,null)\"\r\n (refreshClick)=\"refreshClicked()\" (tileClick)=\"tileClicked($event)\" (tileUnClick)=\"tileUnClicked($event)\">\r\n </app-table-header>\r\n\r\n\r\n <!-- Table -->\r\n <div *ngIf=\"!config.viewType || config?.viewType === 'table'\">\r\n\r\n <p *ngIf=\"!config\"><em>Configure Table</em></p>\r\n <p *ngIf=\"!dataSource\"><em>Loading...</em></p>\r\n\r\n <div *ngIf=\"dataSource && (!smallScreen || (smallScreen && dataSource?.length > 0))\">\r\n\r\n <table mat-table [dataSource]=\"tableDataSource\" [ngClass]=\"elevation\">\r\n\r\n <ng-container *ngFor=\"let column of config.columns\" [matColumnDef]=\"column.name\">\r\n <th mat-header-cell *matHeaderCellDef >{{ column.alias ?? column.name | camelToWords }}</th>\r\n <td mat-cell *matCellDef=\"let row;\" class=\"right-padding\" >\r\n\r\n <!-- Rows -->\r\n <app-table-row [column]=\"column\" [row]=\"row\" [config]=\"config\" [smallScreen]=\"smallScreen\"\r\n (actionClick)=\"actionClicked(column.name, row)\" (columnClick)=\"columnClicked(column, row)\" (showBannerEvent)=\"showBanner($event)\">\r\n </app-table-row>\r\n\r\n </td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"action\">\r\n <th mat-header-cell *matHeaderCellDef> Action </th>\r\n <td mat-cell *matCellDef=\"let row\" [ngStyle]=\"{width:false ? '50px' : actionsWidth}\">\r\n <div class=\"action-buttons-container\">\r\n\r\n <!-- Actions -->\r\n <app-table-action\r\n [displayedButtons]=\"displayedButtons\" [config]=\"config\" [smallScreen]=\"smallScreen\" [row]=\"row\" (actionClick)=\"actionClicked($event.name, $event.row)\">\r\n </app-table-action>\r\n\r\n </div>\r\n </td>\r\n </ng-container>\r\n\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" [ngClass]=\"{'make-gray': (config.greyOut && config.greyOut(row)) || row.pendingApproval}\"></tr>\r\n </table>\r\n\r\n </div>\r\n\r\n <!-- Changed: Removed *ngIf condition to keep paginator always in DOM and maintain ViewChild reference -->\r\n <!-- Changed: Added CSS class binding to hide when no data instead of conditional rendering -->\r\n <mat-paginator \r\n #tablePaginator \r\n [pageSizeOptions]=\"config.pageSizes ?? [10, 20, 50]\" \r\n [ngClass]=\"{'paginator-hidden': !dataSource || (smallScreen && dataSource?.length === 0)}\"\r\n showFirstLastButtons>\r\n </mat-paginator>\r\n\r\n </div>\r\n \r\n <!-- Capsules -->\r\n <spa-capsules *ngIf=\"config?.viewType === 'capsule'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n (actionClick)=\"actionClicked($event.name, $event.row)\">\r\n </spa-capsules>\r\n\r\n <!-- Cards -->\r\n <spa-cards *ngIf=\"config?.viewType === 'card'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n [smallScreen]=\"smallScreen\"\r\n (actionClick)=\"actionClicked($event.name, $event.row)\"\r\n (columnClick)=\"columnClicked($event.column, $event.row)\"\r\n (showBannerEvent)=\"showBanner($event)\">\r\n </spa-cards>\r\n\r\n <!-- Groups -->\r\n <spa-groups *ngIf=\"config?.viewType === 'grouped'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n (actionClick)=\"actionClicked($event.name, $event.row, $event.group, $event.button)\">\r\n </spa-groups>\r\n\r\n <div class=\"tin-center\">\r\n <p *ngIf=\"dataSource?.length == 0\"><em>{{config.noDataMessage ?? 'No Data'}}</em></p>\r\n </div>\r\n\r\n</ng-container>\r\n\r\n\r\n<ng-container *ngIf=\"!hasFormAccess\">\r\n <div class=\"tin-center\">\r\n <p><em>Access Restricted</em></p>\r\n </div>\r\n</ng-container>\r\n\r\n", styles: [".top{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:center;margin-bottom:10px;margin-top:10px}.mat-mini-fab{width:32px;height:32px}.mat-mini-fab mat-icon{font-size:16px;margin-top:-3px}.mat-icon-button{width:32px;height:32px}.mat-icon-button mat-icon{font-size:20px;margin-top:-7px}.col-icon{margin-left:10px}.title{margin-top:10px;font-size:larger;font-weight:300}.make-gray{background-color:#f5f5f5}.right-padding{padding-right:10px}.action-buttons-container{display:flex;justify-content:flex-end;align-items:center}.refreshIcon{font-size:22px!important;margin-top:-7px!important}.dialog-container{display:flex;flex-direction:column;height:100%}.dialog-content{flex:1;overflow:hidden;display:flex;flex-direction:column}.dialog-scroll-content{flex:1;overflow-y:auto}mat-dialog-actions{flex-shrink:0;justify-content:flex-start}.paginator-hidden{display:none!important}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type:
|
|
12375
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TableLiteComponent, isStandalone: false, selector: "spa-table-lite", inputs: { data: "data", tileData: "tileData", config: "config", reload: "reload", activeTab: "activeTab", inTab: "inTab" }, outputs: { dataLoad: "dataLoad", actionSuccess: "actionSuccess", refreshClick: "refreshClick", searchClick: "searchClick", createClick: "createClick", actionClick: "actionClick", inputChange: "inputChange", actionResponse: "actionResponse" }, viewQueries: [{ propertyName: "tablePaginator", first: true, predicate: ["tablePaginator"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "\r\n<ng-container *ngIf=\"hasFormAccess\">\r\n\r\n <!-- Search -->\r\n <spa-search\r\n *ngIf=\"config.searchConfig\" [config]=\"config.searchConfig\" [smallScreen]=\"smallScreen\" [tableDataSource]=\"tableDataSource\" style=\"margin-bottom: 20px;\" (searchClick)=\"searchClicked($event)\">\r\n </spa-search>\r\n\r\n <!-- Header -->\r\n <app-table-header\r\n [config]=\"config\" [data]=\"dataSource\" [tableDataSource]=\"tableDataSource\" [tileConfig]=\"config.tileConfig\" [tileData]=\"tileData\" [tileReload]=\"tileReload\" [lastSearch]=\"lastSearch\" [smallScreen]=\"smallScreen\"\r\n [showFilterButton]=\"showFilterButton\" (createClick)=\"newModel()\" (customClick)=\"customModel($event,null)\"\r\n (refreshClick)=\"refreshClicked()\" (tileClick)=\"tileClicked($event)\" (tileUnClick)=\"tileUnClicked($event)\">\r\n </app-table-header>\r\n\r\n\r\n <!-- Table -->\r\n <div *ngIf=\"!config.viewType || config?.viewType === 'table'\">\r\n\r\n <p *ngIf=\"!config\"><em>Configure Table</em></p>\r\n <p *ngIf=\"!dataSource\"><em>Loading...</em></p>\r\n\r\n <div *ngIf=\"dataSource && (!smallScreen || (smallScreen && dataSource?.length > 0))\">\r\n\r\n <table mat-table [dataSource]=\"tableDataSource\" [ngClass]=\"elevation\">\r\n\r\n <ng-container *ngFor=\"let column of config.columns\" [matColumnDef]=\"column.name\">\r\n <th mat-header-cell *matHeaderCellDef >{{ column.alias ?? column.name | camelToWords }}</th>\r\n <td mat-cell *matCellDef=\"let row;\" class=\"right-padding\" >\r\n\r\n <!-- Rows -->\r\n <app-table-row [column]=\"column\" [row]=\"row\" [config]=\"config\" [smallScreen]=\"smallScreen\"\r\n (actionClick)=\"actionClicked(column.name, row)\" (columnClick)=\"columnClicked(column, row)\" (showBannerEvent)=\"showBanner($event)\">\r\n </app-table-row>\r\n\r\n </td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"action\">\r\n <th mat-header-cell *matHeaderCellDef> Action </th>\r\n <td mat-cell *matCellDef=\"let row\" [ngStyle]=\"{width:false ? '50px' : actionsWidth}\">\r\n <div class=\"action-buttons-container\">\r\n\r\n <!-- Actions -->\r\n <app-table-action\r\n [displayedButtons]=\"displayedButtons\" [config]=\"config\" [smallScreen]=\"smallScreen\" [row]=\"row\" (actionClick)=\"actionClicked($event.name, $event.row)\">\r\n </app-table-action>\r\n\r\n </div>\r\n </td>\r\n </ng-container>\r\n\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" [ngClass]=\"{'make-gray': (config.greyOut && config.greyOut(row)) || row.pendingApproval}\"></tr>\r\n </table>\r\n\r\n </div>\r\n\r\n <!-- Changed: Removed *ngIf condition to keep paginator always in DOM and maintain ViewChild reference -->\r\n <!-- Changed: Added CSS class binding to hide when no data instead of conditional rendering -->\r\n <mat-paginator \r\n #tablePaginator \r\n [pageSizeOptions]=\"config.pageSizes ?? [10, 20, 50]\" \r\n [ngClass]=\"{'paginator-hidden': !dataSource || (smallScreen && dataSource?.length === 0)}\"\r\n showFirstLastButtons>\r\n </mat-paginator>\r\n\r\n </div>\r\n \r\n <!-- Capsules -->\r\n <spa-capsules *ngIf=\"config?.viewType === 'capsule'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n (actionClick)=\"actionClicked($event.name, $event.row)\">\r\n </spa-capsules>\r\n\r\n <!-- Cards -->\r\n <spa-cards *ngIf=\"config?.viewType === 'card'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n [smallScreen]=\"smallScreen\"\r\n (actionClick)=\"actionClicked($event.name, $event.row)\"\r\n (columnClick)=\"columnClicked($event.column, $event.row)\"\r\n (showBannerEvent)=\"showBanner($event)\">\r\n </spa-cards>\r\n\r\n <!-- Groups -->\r\n <spa-groups *ngIf=\"config?.viewType === 'grouped'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n (actionClick)=\"actionClicked($event.name, $event.row, $event.group, $event.button)\">\r\n </spa-groups>\r\n\r\n <div class=\"tin-center\">\r\n <p *ngIf=\"dataSource?.length == 0\"><em>{{config.noDataMessage ?? 'No Data'}}</em></p>\r\n </div>\r\n\r\n</ng-container>\r\n\r\n\r\n<ng-container *ngIf=\"!hasFormAccess\">\r\n <div class=\"tin-center\">\r\n <p><em>Access Restricted</em></p>\r\n </div>\r\n</ng-container>\r\n\r\n", styles: [".top{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:center;margin-bottom:10px;margin-top:10px}.mat-mini-fab{width:32px;height:32px}.mat-mini-fab mat-icon{font-size:16px;margin-top:-3px}.mat-icon-button{width:32px;height:32px}.mat-icon-button mat-icon{font-size:20px;margin-top:-7px}.col-icon{margin-left:10px}.title{margin-top:10px;font-size:larger;font-weight:300}.make-gray{background-color:#f5f5f5}.right-padding{padding-right:10px}.action-buttons-container{display:flex;justify-content:flex-end;align-items:center}.refreshIcon{font-size:22px!important;margin-top:-7px!important}.dialog-container{display:flex;flex-direction:column;height:100%}.dialog-content{flex:1;overflow:hidden;display:flex;flex-direction:column}.dialog-scroll-content{flex:1;overflow-y:auto}mat-dialog-actions{flex-shrink:0;justify-content:flex-start}.paginator-hidden{display:none!important}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i12$2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i12$2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i12$2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i12$2.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i12$2.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i12$2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i12$2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i12$2.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i12$2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i12$2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i13.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: SearchComponent, selector: "spa-search", inputs: ["config", "smallScreen", "tableDataSource"], outputs: ["searchClick"] }, { kind: "component", type: TableHeaderComponent, selector: "app-table-header", inputs: ["lastSearch", "config", "hideTitle", "tableDataSource", "tileConfig", "smallScreen", "tileReload", "showFilterButton", "data", "tileData"], outputs: ["createClick", "customClick", "refreshClick", "tileClick", "tileUnClick"] }, { kind: "component", type: TableRowComponent, selector: "app-table-row", inputs: ["column", "row", "config", "smallScreen"], outputs: ["actionClick", "columnClick", "showBannerEvent"] }, { kind: "component", type: TableActionComponent, selector: "app-table-action", inputs: ["displayedButtons", "config", "row", "smallScreen"], outputs: ["actionClick"] }, { kind: "component", type: CapsulesComponent, selector: "spa-capsules", inputs: ["config", "dataSource", "displayedButtons"], outputs: ["actionClick"] }, { kind: "component", type: CardsComponent, selector: "spa-cards", inputs: ["config", "dataSource", "displayedButtons", "smallScreen"], outputs: ["actionClick", "columnClick", "showBannerEvent"] }, { kind: "component", type: GroupsComponent, selector: "spa-groups", inputs: ["config", "dataSource", "displayedButtons"], outputs: ["actionClick"] }, { kind: "pipe", type: CamelToWordsPipe, name: "camelToWords" }] }); }
|
|
12249
12376
|
}
|
|
12250
12377
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TableLiteComponent, decorators: [{
|
|
12251
12378
|
type: Component,
|
|
@@ -12742,7 +12869,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
|
|
|
12742
12869
|
;
|
|
12743
12870
|
|
|
12744
12871
|
class TableInternalComponent {
|
|
12745
|
-
constructor(dataService, messageService, breakpointObserver, dialog, buttonService, dialogService, tableConfigService, conditionService, authService) {
|
|
12872
|
+
constructor(dataService, messageService, breakpointObserver, dialog, buttonService, dialogService, tableConfigService, conditionService, authService, signalRService) {
|
|
12746
12873
|
this.dataService = dataService;
|
|
12747
12874
|
this.messageService = messageService;
|
|
12748
12875
|
this.breakpointObserver = breakpointObserver;
|
|
@@ -12752,6 +12879,7 @@ class TableInternalComponent {
|
|
|
12752
12879
|
this.tableConfigService = tableConfigService;
|
|
12753
12880
|
this.conditionService = conditionService;
|
|
12754
12881
|
this.authService = authService;
|
|
12882
|
+
this.signalRService = signalRService;
|
|
12755
12883
|
this.elevation = "mat-elevation-z5";
|
|
12756
12884
|
this.actionsWidth = "50px";
|
|
12757
12885
|
this.showFilterButton = true;
|
|
@@ -12773,6 +12901,10 @@ class TableInternalComponent {
|
|
|
12773
12901
|
this.actionClick = new EventEmitter();
|
|
12774
12902
|
this.inputChange = new EventEmitter();
|
|
12775
12903
|
this.actionResponse = new EventEmitter();
|
|
12904
|
+
// Changed: Real-time SignalR subscription management
|
|
12905
|
+
this.realTimeSubs = [];
|
|
12906
|
+
this.realTimeEntityName = '';
|
|
12907
|
+
this.pendingRealTimeUpdate = false;
|
|
12776
12908
|
// detect screen size changes
|
|
12777
12909
|
this.breakpointObserver.observe(["(max-width: 600px)"]).subscribe((result) => {
|
|
12778
12910
|
this.smallScreen = result.matches;
|
|
@@ -12812,6 +12944,8 @@ class TableInternalComponent {
|
|
|
12812
12944
|
this.dataSource = this.data;
|
|
12813
12945
|
this.tableDataSource = new MatTableDataSource(this.dataSource);
|
|
12814
12946
|
this.setPaginator(); // Set paginator after datasource initialization
|
|
12947
|
+
if (this.config.realTime)
|
|
12948
|
+
this.setupRealTimeSubscriptions(); // Changed: Subscribe to SignalR entity changes
|
|
12815
12949
|
}
|
|
12816
12950
|
updateTableConfiguration() {
|
|
12817
12951
|
this.elevation = this.getElevationClass(this.config?.elevation);
|
|
@@ -13057,7 +13191,7 @@ class TableInternalComponent {
|
|
|
13057
13191
|
else if (result.message === 'success') {
|
|
13058
13192
|
this.actionClickedEmit(buttonName, result.data);
|
|
13059
13193
|
this.actionResponse.emit({ name: buttonName, data: result.data });
|
|
13060
|
-
this.
|
|
13194
|
+
this.realTimeRefreshOrFallback(); // Changed: Use real-time update if enabled, otherwise refresh
|
|
13061
13195
|
this.actionSuccess.emit();
|
|
13062
13196
|
if (buttonName == 'create' && btn.editOnSuccess) {
|
|
13063
13197
|
this.editModel(result.data.data);
|
|
@@ -13123,7 +13257,7 @@ class TableInternalComponent {
|
|
|
13123
13257
|
else {
|
|
13124
13258
|
this.messageService.toast("Updated");
|
|
13125
13259
|
}
|
|
13126
|
-
this.
|
|
13260
|
+
this.realTimeRefreshOrFallback(); // Changed: Use real-time update if enabled, otherwise refresh
|
|
13127
13261
|
this.actionSuccess.emit();
|
|
13128
13262
|
}
|
|
13129
13263
|
else {
|
|
@@ -13152,13 +13286,87 @@ class TableInternalComponent {
|
|
|
13152
13286
|
return "mat-elevation-z5";
|
|
13153
13287
|
}
|
|
13154
13288
|
}
|
|
13155
|
-
|
|
13156
|
-
|
|
13289
|
+
// Changed: Skip refresh if real-time is enabled — SignalR will handle it. 3s safety fallback.
|
|
13290
|
+
realTimeRefreshOrFallback() {
|
|
13291
|
+
if (!this.config.realTime) {
|
|
13292
|
+
this.refreshClicked();
|
|
13293
|
+
return;
|
|
13294
|
+
}
|
|
13295
|
+
this.pendingRealTimeUpdate = false;
|
|
13296
|
+
setTimeout(() => {
|
|
13297
|
+
if (!this.pendingRealTimeUpdate)
|
|
13298
|
+
this.refreshClicked(); // Fallback if SignalR event didn't arrive
|
|
13299
|
+
}, 3000);
|
|
13300
|
+
}
|
|
13301
|
+
// Changed: Set up SignalR subscriptions for real-time entity change updates
|
|
13302
|
+
setupRealTimeSubscriptions() {
|
|
13303
|
+
this.realTimeEntityName = this.config.entityName || this.deriveEntityName();
|
|
13304
|
+
// Changed: Subscribe to entity created — add new row to table
|
|
13305
|
+
this.realTimeSubs.push(this.signalRService.entityCreated$.subscribe(event => {
|
|
13306
|
+
if (event.entityName !== this.realTimeEntityName)
|
|
13307
|
+
return;
|
|
13308
|
+
if (!this.tableDataSource)
|
|
13309
|
+
return;
|
|
13310
|
+
this.pendingRealTimeUpdate = true;
|
|
13311
|
+
const data = [...this.tableDataSource.data, event.data];
|
|
13312
|
+
this.tableDataSource.data = data;
|
|
13313
|
+
this.dataSource = data;
|
|
13314
|
+
}));
|
|
13315
|
+
// Changed: Subscribe to entity updated — replace existing row by ID
|
|
13316
|
+
this.realTimeSubs.push(this.signalRService.entityUpdated$.subscribe(event => {
|
|
13317
|
+
if (event.entityName !== this.realTimeEntityName)
|
|
13318
|
+
return;
|
|
13319
|
+
if (!this.tableDataSource)
|
|
13320
|
+
return;
|
|
13321
|
+
this.pendingRealTimeUpdate = true;
|
|
13322
|
+
const idKey = this.findIdKey(event.data);
|
|
13323
|
+
if (!idKey)
|
|
13324
|
+
return;
|
|
13325
|
+
const data = this.tableDataSource.data.map(row => row[idKey] === event.data[idKey] ? event.data : row);
|
|
13326
|
+
this.tableDataSource.data = data;
|
|
13327
|
+
this.dataSource = data;
|
|
13328
|
+
}));
|
|
13329
|
+
// Changed: Subscribe to entity deleted — remove row by ID
|
|
13330
|
+
this.realTimeSubs.push(this.signalRService.entityDeleted$.subscribe(event => {
|
|
13331
|
+
if (event.entityName !== this.realTimeEntityName)
|
|
13332
|
+
return;
|
|
13333
|
+
if (!this.tableDataSource)
|
|
13334
|
+
return;
|
|
13335
|
+
this.pendingRealTimeUpdate = true;
|
|
13336
|
+
const idKey = this.findIdKey(this.tableDataSource.data[0]);
|
|
13337
|
+
if (!idKey)
|
|
13338
|
+
return;
|
|
13339
|
+
const data = this.tableDataSource.data.filter(row => row[idKey] !== event.data);
|
|
13340
|
+
this.tableDataSource.data = data;
|
|
13341
|
+
this.dataSource = data;
|
|
13342
|
+
}));
|
|
13343
|
+
}
|
|
13344
|
+
// Changed: Derive entity name from loadAction URL (e.g. 'products/all/x' → 'Product')
|
|
13345
|
+
deriveEntityName() {
|
|
13346
|
+
const url = this.config.loadAction?.url || '';
|
|
13347
|
+
const segment = url.split('/')[0];
|
|
13348
|
+
if (!segment)
|
|
13349
|
+
return '';
|
|
13350
|
+
const name = segment.charAt(0).toUpperCase() + segment.slice(1);
|
|
13351
|
+
return name.endsWith('s') ? name.slice(0, -1) : name;
|
|
13352
|
+
}
|
|
13353
|
+
// Changed: Find the ID property key in a row object (convention: ends with 'ID')
|
|
13354
|
+
findIdKey(row) {
|
|
13355
|
+
if (!row)
|
|
13356
|
+
return null;
|
|
13357
|
+
return Object.keys(row).find(k => k.endsWith('ID') && k !== 'TenantID') || null;
|
|
13358
|
+
}
|
|
13359
|
+
// Changed: Clean up SignalR subscriptions on component destroy
|
|
13360
|
+
ngOnDestroy() {
|
|
13361
|
+
this.realTimeSubs.forEach(s => s.unsubscribe());
|
|
13362
|
+
}
|
|
13363
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TableInternalComponent, deps: [{ token: DataServiceLib }, { token: MessageService }, { token: i1$3.BreakpointObserver }, { token: i1.MatDialog }, { token: ButtonService }, { token: DialogService }, { token: TableConfigService }, { token: ConditionService }, { token: AuthService }, { token: SignalRService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
13364
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TableInternalComponent, isStandalone: false, selector: "spa-table-internal", inputs: { data: "data", tileData: "tileData", config: "config", reload: "reload", activeTab: "activeTab", inTab: "inTab" }, outputs: { dataLoad: "dataLoad", actionSuccess: "actionSuccess", refreshClick: "refreshClick", searchClick: "searchClick", createClick: "createClick", actionClick: "actionClick", inputChange: "inputChange", actionResponse: "actionResponse" }, viewQueries: [{ propertyName: "tablePaginator", first: true, predicate: ["tablePaginator"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "\r\n<ng-container *ngIf=\"hasFormAccess\">\r\n\r\n <!-- Search -->\r\n <spa-search\r\n *ngIf=\"config.searchConfig\" [config]=\"config.searchConfig\" [smallScreen]=\"smallScreen\" [tableDataSource]=\"tableDataSource\" style=\"margin-bottom: 20px;\" (searchClick)=\"searchClicked($event)\">\r\n </spa-search>\r\n\r\n <!-- Header -->\r\n <app-table-header\r\n [config]=\"config\" [data]=\"dataSource\" [tableDataSource]=\"tableDataSource\" [tileConfig]=\"config.tileConfig\" [tileData]=\"tileData\" [tileReload]=\"tileReload\" [lastSearch]=\"lastSearch\" [smallScreen]=\"smallScreen\"\r\n [showFilterButton]=\"showFilterButton\" (createClick)=\"newModel()\" (customClick)=\"customModel($event,null)\"\r\n (refreshClick)=\"refreshClicked()\" (tileClick)=\"tileClicked($event)\" (tileUnClick)=\"tileUnClicked($event)\">\r\n </app-table-header>\r\n\r\n\r\n <!-- Table -->\r\n <div *ngIf=\"!config.viewType || config?.viewType === 'table'\">\r\n\r\n <p *ngIf=\"!config\"><em>Configure Table</em></p>\r\n <p *ngIf=\"!dataSource\"><em>Loading...</em></p>\r\n\r\n <div *ngIf=\"dataSource && (!smallScreen || (smallScreen && dataSource?.length > 0))\">\r\n\r\n <table mat-table [dataSource]=\"tableDataSource\" [ngClass]=\"elevation\">\r\n\r\n <ng-container *ngFor=\"let column of config.columns\" [matColumnDef]=\"column.name\">\r\n <th mat-header-cell *matHeaderCellDef >{{ column.alias ?? column.name | camelToWords }}</th>\r\n <td mat-cell *matCellDef=\"let row;\" class=\"right-padding\" >\r\n\r\n <!-- Rows -->\r\n <app-table-row [column]=\"column\" [row]=\"row\" [config]=\"config\" [smallScreen]=\"smallScreen\"\r\n (actionClick)=\"actionClicked(column.name, row)\" (columnClick)=\"columnClicked(column, row)\" (showBannerEvent)=\"showBanner($event)\">\r\n </app-table-row>\r\n\r\n </td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"action\">\r\n <th mat-header-cell *matHeaderCellDef> Action </th>\r\n <td mat-cell *matCellDef=\"let row\" [ngStyle]=\"{width:false ? '50px' : actionsWidth}\">\r\n <div class=\"action-buttons-container\">\r\n\r\n <!-- Actions -->\r\n <app-table-action\r\n [displayedButtons]=\"displayedButtons\" [config]=\"config\" [smallScreen]=\"smallScreen\" [row]=\"row\" (actionClick)=\"actionClicked($event.name, $event.row)\">\r\n </app-table-action>\r\n\r\n </div>\r\n </td>\r\n </ng-container>\r\n\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" [ngClass]=\"{'make-gray': (config.greyOut && config.greyOut(row)) || row.pendingApproval}\"></tr>\r\n </table>\r\n\r\n </div>\r\n\r\n <!-- Changed: Removed *ngIf condition to keep paginator always in DOM and maintain ViewChild reference -->\r\n <!-- Changed: Added CSS class binding to hide when no data instead of conditional rendering -->\r\n <mat-paginator \r\n #tablePaginator \r\n [pageSizeOptions]=\"config.pageSizes ?? [10, 20, 50]\" \r\n [ngClass]=\"{'paginator-hidden': !dataSource || (smallScreen && dataSource?.length === 0)}\"\r\n showFirstLastButtons>\r\n </mat-paginator>\r\n\r\n </div>\r\n \r\n <!-- Capsules -->\r\n <spa-capsules *ngIf=\"config?.viewType === 'capsule'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n (actionClick)=\"actionClicked($event.name, $event.row)\">\r\n </spa-capsules>\r\n\r\n <!-- Cards -->\r\n <spa-cards *ngIf=\"config?.viewType === 'card'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n [smallScreen]=\"smallScreen\"\r\n (actionClick)=\"actionClicked($event.name, $event.row)\"\r\n (columnClick)=\"columnClicked($event.column, $event.row)\"\r\n (showBannerEvent)=\"showBanner($event)\">\r\n </spa-cards>\r\n\r\n <!-- Groups -->\r\n <spa-groups *ngIf=\"config?.viewType === 'grouped'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n (actionClick)=\"actionClicked($event.name, $event.row, $event.group, $event.button)\">\r\n </spa-groups>\r\n\r\n <div class=\"tin-center\">\r\n <p *ngIf=\"dataSource?.length == 0\"><em>{{config.noDataMessage ?? 'No Data'}}</em></p>\r\n </div>\r\n\r\n</ng-container>\r\n\r\n\r\n<ng-container *ngIf=\"!hasFormAccess\">\r\n <div class=\"tin-center\">\r\n <p><em>Access Restricted</em></p>\r\n </div>\r\n</ng-container>\r\n\r\n", styles: [".top{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:center;margin-bottom:10px;margin-top:10px}.mat-mini-fab{width:32px;height:32px}.mat-mini-fab mat-icon{font-size:16px;margin-top:-3px}.mat-icon-button{width:32px;height:32px}.mat-icon-button mat-icon{font-size:20px;margin-top:-7px}.col-icon{margin-left:10px}.title{margin-top:10px;font-size:larger;font-weight:300}.make-gray{background-color:#f5f5f5}.right-padding{padding-right:10px}.action-buttons-container{display:flex;justify-content:flex-end;align-items:center}.refreshIcon{font-size:22px!important;margin-top:-7px!important}.dialog-container{display:flex;flex-direction:column;height:100%}.dialog-content{flex:1;overflow:hidden;display:flex;flex-direction:column}.dialog-scroll-content{flex:1;overflow-y:auto}mat-dialog-actions{flex-shrink:0;justify-content:flex-start}.paginator-hidden{display:none!important}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i12$2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i12$2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i12$2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i12$2.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i12$2.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i12$2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i12$2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i12$2.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i12$2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i12$2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i13.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: SearchComponent, selector: "spa-search", inputs: ["config", "smallScreen", "tableDataSource"], outputs: ["searchClick"] }, { kind: "component", type: TableHeaderComponent, selector: "app-table-header", inputs: ["lastSearch", "config", "hideTitle", "tableDataSource", "tileConfig", "smallScreen", "tileReload", "showFilterButton", "data", "tileData"], outputs: ["createClick", "customClick", "refreshClick", "tileClick", "tileUnClick"] }, { kind: "component", type: TableRowComponent, selector: "app-table-row", inputs: ["column", "row", "config", "smallScreen"], outputs: ["actionClick", "columnClick", "showBannerEvent"] }, { kind: "component", type: TableActionComponent, selector: "app-table-action", inputs: ["displayedButtons", "config", "row", "smallScreen"], outputs: ["actionClick"] }, { kind: "component", type: CapsulesComponent, selector: "spa-capsules", inputs: ["config", "dataSource", "displayedButtons"], outputs: ["actionClick"] }, { kind: "component", type: CardsComponent, selector: "spa-cards", inputs: ["config", "dataSource", "displayedButtons", "smallScreen"], outputs: ["actionClick", "columnClick", "showBannerEvent"] }, { kind: "component", type: GroupsComponent, selector: "spa-groups", inputs: ["config", "dataSource", "displayedButtons"], outputs: ["actionClick"] }, { kind: "pipe", type: CamelToWordsPipe, name: "camelToWords" }] }); }
|
|
13157
13365
|
}
|
|
13158
13366
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TableInternalComponent, decorators: [{
|
|
13159
13367
|
type: Component,
|
|
13160
13368
|
args: [{ selector: 'spa-table-internal', standalone: false, template: "\r\n<ng-container *ngIf=\"hasFormAccess\">\r\n\r\n <!-- Search -->\r\n <spa-search\r\n *ngIf=\"config.searchConfig\" [config]=\"config.searchConfig\" [smallScreen]=\"smallScreen\" [tableDataSource]=\"tableDataSource\" style=\"margin-bottom: 20px;\" (searchClick)=\"searchClicked($event)\">\r\n </spa-search>\r\n\r\n <!-- Header -->\r\n <app-table-header\r\n [config]=\"config\" [data]=\"dataSource\" [tableDataSource]=\"tableDataSource\" [tileConfig]=\"config.tileConfig\" [tileData]=\"tileData\" [tileReload]=\"tileReload\" [lastSearch]=\"lastSearch\" [smallScreen]=\"smallScreen\"\r\n [showFilterButton]=\"showFilterButton\" (createClick)=\"newModel()\" (customClick)=\"customModel($event,null)\"\r\n (refreshClick)=\"refreshClicked()\" (tileClick)=\"tileClicked($event)\" (tileUnClick)=\"tileUnClicked($event)\">\r\n </app-table-header>\r\n\r\n\r\n <!-- Table -->\r\n <div *ngIf=\"!config.viewType || config?.viewType === 'table'\">\r\n\r\n <p *ngIf=\"!config\"><em>Configure Table</em></p>\r\n <p *ngIf=\"!dataSource\"><em>Loading...</em></p>\r\n\r\n <div *ngIf=\"dataSource && (!smallScreen || (smallScreen && dataSource?.length > 0))\">\r\n\r\n <table mat-table [dataSource]=\"tableDataSource\" [ngClass]=\"elevation\">\r\n\r\n <ng-container *ngFor=\"let column of config.columns\" [matColumnDef]=\"column.name\">\r\n <th mat-header-cell *matHeaderCellDef >{{ column.alias ?? column.name | camelToWords }}</th>\r\n <td mat-cell *matCellDef=\"let row;\" class=\"right-padding\" >\r\n\r\n <!-- Rows -->\r\n <app-table-row [column]=\"column\" [row]=\"row\" [config]=\"config\" [smallScreen]=\"smallScreen\"\r\n (actionClick)=\"actionClicked(column.name, row)\" (columnClick)=\"columnClicked(column, row)\" (showBannerEvent)=\"showBanner($event)\">\r\n </app-table-row>\r\n\r\n </td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"action\">\r\n <th mat-header-cell *matHeaderCellDef> Action </th>\r\n <td mat-cell *matCellDef=\"let row\" [ngStyle]=\"{width:false ? '50px' : actionsWidth}\">\r\n <div class=\"action-buttons-container\">\r\n\r\n <!-- Actions -->\r\n <app-table-action\r\n [displayedButtons]=\"displayedButtons\" [config]=\"config\" [smallScreen]=\"smallScreen\" [row]=\"row\" (actionClick)=\"actionClicked($event.name, $event.row)\">\r\n </app-table-action>\r\n\r\n </div>\r\n </td>\r\n </ng-container>\r\n\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" [ngClass]=\"{'make-gray': (config.greyOut && config.greyOut(row)) || row.pendingApproval}\"></tr>\r\n </table>\r\n\r\n </div>\r\n\r\n <!-- Changed: Removed *ngIf condition to keep paginator always in DOM and maintain ViewChild reference -->\r\n <!-- Changed: Added CSS class binding to hide when no data instead of conditional rendering -->\r\n <mat-paginator \r\n #tablePaginator \r\n [pageSizeOptions]=\"config.pageSizes ?? [10, 20, 50]\" \r\n [ngClass]=\"{'paginator-hidden': !dataSource || (smallScreen && dataSource?.length === 0)}\"\r\n showFirstLastButtons>\r\n </mat-paginator>\r\n\r\n </div>\r\n \r\n <!-- Capsules -->\r\n <spa-capsules *ngIf=\"config?.viewType === 'capsule'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n (actionClick)=\"actionClicked($event.name, $event.row)\">\r\n </spa-capsules>\r\n\r\n <!-- Cards -->\r\n <spa-cards *ngIf=\"config?.viewType === 'card'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n [smallScreen]=\"smallScreen\"\r\n (actionClick)=\"actionClicked($event.name, $event.row)\"\r\n (columnClick)=\"columnClicked($event.column, $event.row)\"\r\n (showBannerEvent)=\"showBanner($event)\">\r\n </spa-cards>\r\n\r\n <!-- Groups -->\r\n <spa-groups *ngIf=\"config?.viewType === 'grouped'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n (actionClick)=\"actionClicked($event.name, $event.row, $event.group, $event.button)\">\r\n </spa-groups>\r\n\r\n <div class=\"tin-center\">\r\n <p *ngIf=\"dataSource?.length == 0\"><em>{{config.noDataMessage ?? 'No Data'}}</em></p>\r\n </div>\r\n\r\n</ng-container>\r\n\r\n\r\n<ng-container *ngIf=\"!hasFormAccess\">\r\n <div class=\"tin-center\">\r\n <p><em>Access Restricted</em></p>\r\n </div>\r\n</ng-container>\r\n\r\n", styles: [".top{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:center;margin-bottom:10px;margin-top:10px}.mat-mini-fab{width:32px;height:32px}.mat-mini-fab mat-icon{font-size:16px;margin-top:-3px}.mat-icon-button{width:32px;height:32px}.mat-icon-button mat-icon{font-size:20px;margin-top:-7px}.col-icon{margin-left:10px}.title{margin-top:10px;font-size:larger;font-weight:300}.make-gray{background-color:#f5f5f5}.right-padding{padding-right:10px}.action-buttons-container{display:flex;justify-content:flex-end;align-items:center}.refreshIcon{font-size:22px!important;margin-top:-7px!important}.dialog-container{display:flex;flex-direction:column;height:100%}.dialog-content{flex:1;overflow:hidden;display:flex;flex-direction:column}.dialog-scroll-content{flex:1;overflow-y:auto}mat-dialog-actions{flex-shrink:0;justify-content:flex-start}.paginator-hidden{display:none!important}\n"] }]
|
|
13161
|
-
}], ctorParameters: () => [{ type: DataServiceLib }, { type: MessageService }, { type: i1$3.BreakpointObserver }, { type: i1.MatDialog }, { type: ButtonService }, { type: DialogService }, { type: TableConfigService }, { type: ConditionService }, { type: AuthService }], propDecorators: { tablePaginator: [{
|
|
13369
|
+
}], ctorParameters: () => [{ type: DataServiceLib }, { type: MessageService }, { type: i1$3.BreakpointObserver }, { type: i1.MatDialog }, { type: ButtonService }, { type: DialogService }, { type: TableConfigService }, { type: ConditionService }, { type: AuthService }, { type: SignalRService }], propDecorators: { tablePaginator: [{
|
|
13162
13370
|
type: ViewChild,
|
|
13163
13371
|
args: ['tablePaginator', { static: false }]
|
|
13164
13372
|
}], data: [{
|
|
@@ -13690,7 +13898,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
|
|
|
13690
13898
|
;
|
|
13691
13899
|
|
|
13692
13900
|
class TableComponent {
|
|
13693
|
-
constructor(dataService, messageService, breakpointObserver, dialog, buttonService, dialogService, tableConfigService, conditionService, authService) {
|
|
13901
|
+
constructor(dataService, messageService, breakpointObserver, dialog, buttonService, dialogService, tableConfigService, conditionService, authService, signalRService) {
|
|
13694
13902
|
this.dataService = dataService;
|
|
13695
13903
|
this.messageService = messageService;
|
|
13696
13904
|
this.breakpointObserver = breakpointObserver;
|
|
@@ -13700,6 +13908,7 @@ class TableComponent {
|
|
|
13700
13908
|
this.tableConfigService = tableConfigService;
|
|
13701
13909
|
this.conditionService = conditionService;
|
|
13702
13910
|
this.authService = authService;
|
|
13911
|
+
this.signalRService = signalRService;
|
|
13703
13912
|
this.elevation = "mat-elevation-z5";
|
|
13704
13913
|
this.actionsWidth = "50px";
|
|
13705
13914
|
this.showFilterButton = true;
|
|
@@ -13721,6 +13930,10 @@ class TableComponent {
|
|
|
13721
13930
|
this.actionClick = new EventEmitter();
|
|
13722
13931
|
this.inputChange = new EventEmitter();
|
|
13723
13932
|
this.actionResponse = new EventEmitter();
|
|
13933
|
+
// Changed: Real-time SignalR subscription management
|
|
13934
|
+
this.realTimeSubs = [];
|
|
13935
|
+
this.realTimeEntityName = '';
|
|
13936
|
+
this.pendingRealTimeUpdate = false; // Changed: Flag to skip refreshClicked when SignalR handles it
|
|
13724
13937
|
// detect screen size changes
|
|
13725
13938
|
this.breakpointObserver.observe(["(max-width: 600px)"]).subscribe((result) => {
|
|
13726
13939
|
this.smallScreen = result.matches;
|
|
@@ -13760,6 +13973,8 @@ class TableComponent {
|
|
|
13760
13973
|
this.dataSource = this.data;
|
|
13761
13974
|
this.tableDataSource = new MatTableDataSource(this.dataSource);
|
|
13762
13975
|
this.setPaginator(); // Set paginator after datasource initialization
|
|
13976
|
+
if (this.config.realTime)
|
|
13977
|
+
this.setupRealTimeSubscriptions(); // Changed: Subscribe to SignalR entity changes
|
|
13763
13978
|
}
|
|
13764
13979
|
updateTableConfiguration() {
|
|
13765
13980
|
this.elevation = this.getElevationClass(this.config?.elevation);
|
|
@@ -14005,7 +14220,7 @@ class TableComponent {
|
|
|
14005
14220
|
else if (result.message === 'success') {
|
|
14006
14221
|
this.actionClickedEmit(buttonName, result.data);
|
|
14007
14222
|
this.actionResponse.emit({ name: buttonName, data: result.data });
|
|
14008
|
-
this.
|
|
14223
|
+
this.realTimeRefreshOrFallback(); // Changed: Use real-time update if enabled, otherwise refresh
|
|
14009
14224
|
this.actionSuccess.emit();
|
|
14010
14225
|
if (buttonName == 'create' && btn.editOnSuccess) {
|
|
14011
14226
|
this.editModel(result.data.data);
|
|
@@ -14071,7 +14286,7 @@ class TableComponent {
|
|
|
14071
14286
|
else {
|
|
14072
14287
|
this.messageService.toast("Updated");
|
|
14073
14288
|
}
|
|
14074
|
-
this.
|
|
14289
|
+
this.realTimeRefreshOrFallback(); // Changed: Use real-time update if enabled, otherwise refresh
|
|
14075
14290
|
this.actionSuccess.emit();
|
|
14076
14291
|
}
|
|
14077
14292
|
else {
|
|
@@ -14100,13 +14315,87 @@ class TableComponent {
|
|
|
14100
14315
|
return "mat-elevation-z5";
|
|
14101
14316
|
}
|
|
14102
14317
|
}
|
|
14103
|
-
|
|
14104
|
-
|
|
14318
|
+
// Changed: Skip refresh if real-time is enabled — SignalR will handle it. 3s safety fallback.
|
|
14319
|
+
realTimeRefreshOrFallback() {
|
|
14320
|
+
if (!this.config.realTime) {
|
|
14321
|
+
this.refreshClicked();
|
|
14322
|
+
return;
|
|
14323
|
+
}
|
|
14324
|
+
this.pendingRealTimeUpdate = false;
|
|
14325
|
+
setTimeout(() => {
|
|
14326
|
+
if (!this.pendingRealTimeUpdate)
|
|
14327
|
+
this.refreshClicked(); // Fallback if SignalR event didn't arrive
|
|
14328
|
+
}, 3000);
|
|
14329
|
+
}
|
|
14330
|
+
// Changed: Set up SignalR subscriptions for real-time entity change updates
|
|
14331
|
+
setupRealTimeSubscriptions() {
|
|
14332
|
+
this.realTimeEntityName = this.config.entityName || this.deriveEntityName();
|
|
14333
|
+
// Changed: Subscribe to entity created — add new row to table
|
|
14334
|
+
this.realTimeSubs.push(this.signalRService.entityCreated$.subscribe(event => {
|
|
14335
|
+
if (event.entityName !== this.realTimeEntityName)
|
|
14336
|
+
return;
|
|
14337
|
+
if (!this.tableDataSource)
|
|
14338
|
+
return;
|
|
14339
|
+
this.pendingRealTimeUpdate = true;
|
|
14340
|
+
const data = [...this.tableDataSource.data, event.data];
|
|
14341
|
+
this.tableDataSource.data = data;
|
|
14342
|
+
this.dataSource = data;
|
|
14343
|
+
}));
|
|
14344
|
+
// Changed: Subscribe to entity updated — replace existing row by ID
|
|
14345
|
+
this.realTimeSubs.push(this.signalRService.entityUpdated$.subscribe(event => {
|
|
14346
|
+
if (event.entityName !== this.realTimeEntityName)
|
|
14347
|
+
return;
|
|
14348
|
+
if (!this.tableDataSource)
|
|
14349
|
+
return;
|
|
14350
|
+
this.pendingRealTimeUpdate = true;
|
|
14351
|
+
const idKey = this.findIdKey(event.data);
|
|
14352
|
+
if (!idKey)
|
|
14353
|
+
return;
|
|
14354
|
+
const data = this.tableDataSource.data.map(row => row[idKey] === event.data[idKey] ? event.data : row);
|
|
14355
|
+
this.tableDataSource.data = data;
|
|
14356
|
+
this.dataSource = data;
|
|
14357
|
+
}));
|
|
14358
|
+
// Changed: Subscribe to entity deleted — remove row by ID
|
|
14359
|
+
this.realTimeSubs.push(this.signalRService.entityDeleted$.subscribe(event => {
|
|
14360
|
+
if (event.entityName !== this.realTimeEntityName)
|
|
14361
|
+
return;
|
|
14362
|
+
if (!this.tableDataSource)
|
|
14363
|
+
return;
|
|
14364
|
+
this.pendingRealTimeUpdate = true;
|
|
14365
|
+
const idKey = this.findIdKey(this.tableDataSource.data[0]);
|
|
14366
|
+
if (!idKey)
|
|
14367
|
+
return;
|
|
14368
|
+
const data = this.tableDataSource.data.filter(row => row[idKey] !== event.data);
|
|
14369
|
+
this.tableDataSource.data = data;
|
|
14370
|
+
this.dataSource = data;
|
|
14371
|
+
}));
|
|
14372
|
+
}
|
|
14373
|
+
// Changed: Derive entity name from loadAction URL (e.g. 'products/all/x' → 'Product')
|
|
14374
|
+
deriveEntityName() {
|
|
14375
|
+
const url = this.config.loadAction?.url || '';
|
|
14376
|
+
const segment = url.split('/')[0]; // First URL segment (e.g. 'products')
|
|
14377
|
+
if (!segment)
|
|
14378
|
+
return '';
|
|
14379
|
+
const name = segment.charAt(0).toUpperCase() + segment.slice(1); // Capitalize
|
|
14380
|
+
return name.endsWith('s') ? name.slice(0, -1) : name; // Remove trailing 's' for singular
|
|
14381
|
+
}
|
|
14382
|
+
// Changed: Find the ID property key in a row object (convention: ends with 'ID')
|
|
14383
|
+
findIdKey(row) {
|
|
14384
|
+
if (!row)
|
|
14385
|
+
return null;
|
|
14386
|
+
return Object.keys(row).find(k => k.endsWith('ID') && k !== 'TenantID') || null;
|
|
14387
|
+
}
|
|
14388
|
+
// Changed: Clean up SignalR subscriptions on component destroy
|
|
14389
|
+
ngOnDestroy() {
|
|
14390
|
+
this.realTimeSubs.forEach(s => s.unsubscribe());
|
|
14391
|
+
}
|
|
14392
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TableComponent, deps: [{ token: DataServiceLib }, { token: MessageService }, { token: i1$3.BreakpointObserver }, { token: i1.MatDialog }, { token: ButtonService }, { token: DialogService }, { token: TableConfigService }, { token: ConditionService }, { token: AuthService }, { token: SignalRService }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
14393
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: TableComponent, isStandalone: false, selector: "spa-table", inputs: { data: "data", tileData: "tileData", config: "config", reload: "reload", activeTab: "activeTab", inTab: "inTab" }, outputs: { dataLoad: "dataLoad", actionSuccess: "actionSuccess", refreshClick: "refreshClick", searchClick: "searchClick", createClick: "createClick", actionClick: "actionClick", inputChange: "inputChange", actionResponse: "actionResponse" }, viewQueries: [{ propertyName: "tablePaginator", first: true, predicate: ["tablePaginator"], descendants: true }], usesOnChanges: true, ngImport: i0, template: "\r\n<ng-container *ngIf=\"hasFormAccess\">\r\n\r\n <!-- Search -->\r\n <spa-search\r\n *ngIf=\"config.searchConfig\" [config]=\"config.searchConfig\" [smallScreen]=\"smallScreen\" [tableDataSource]=\"tableDataSource\" style=\"margin-bottom: 20px;\" (searchClick)=\"searchClicked($event)\">\r\n </spa-search>\r\n\r\n <!-- Header -->\r\n <app-table-header\r\n [config]=\"config\" [data]=\"dataSource\" [tableDataSource]=\"tableDataSource\" [tileConfig]=\"config.tileConfig\" [tileData]=\"tileData\" [tileReload]=\"tileReload\" [lastSearch]=\"lastSearch\" [smallScreen]=\"smallScreen\"\r\n [showFilterButton]=\"showFilterButton\" (createClick)=\"newModel()\" (customClick)=\"customModel($event,null)\"\r\n (refreshClick)=\"refreshClicked()\" (tileClick)=\"tileClicked($event)\" (tileUnClick)=\"tileUnClicked($event)\">\r\n </app-table-header>\r\n\r\n\r\n <!-- Table -->\r\n <div *ngIf=\"!config.viewType || config?.viewType === 'table'\">\r\n\r\n <p *ngIf=\"!config\"><em>Configure Table</em></p>\r\n <p *ngIf=\"!dataSource\"><em>Loading...</em></p>\r\n\r\n <div *ngIf=\"dataSource && (!smallScreen || (smallScreen && dataSource?.length > 0))\">\r\n\r\n <table mat-table [dataSource]=\"tableDataSource\" [ngClass]=\"elevation\">\r\n\r\n <ng-container *ngFor=\"let column of config.columns\" [matColumnDef]=\"column.name\">\r\n <th mat-header-cell *matHeaderCellDef >{{ column.alias ?? column.name | camelToWords }}</th>\r\n <td mat-cell *matCellDef=\"let row;\" class=\"right-padding\" >\r\n\r\n <!-- Rows -->\r\n <app-table-row [column]=\"column\" [row]=\"row\" [config]=\"config\" [smallScreen]=\"smallScreen\"\r\n (actionClick)=\"actionClicked(column.name, row)\" (columnClick)=\"columnClicked(column, row)\" (showBannerEvent)=\"showBanner($event)\">\r\n </app-table-row>\r\n\r\n </td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"action\">\r\n <th mat-header-cell *matHeaderCellDef> Action </th>\r\n <td mat-cell *matCellDef=\"let row\" [ngStyle]=\"{width:false ? '20px' : actionsWidth}\">\r\n <div class=\"action-buttons-container\">\r\n\r\n <!-- Actions -->\r\n <app-table-action\r\n [displayedButtons]=\"displayedButtons\" [config]=\"config\" [smallScreen]=\"smallScreen\" [row]=\"row\" (actionClick)=\"actionClicked($event.name, $event.row)\">\r\n </app-table-action>\r\n\r\n </div>\r\n </td>\r\n </ng-container>\r\n\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" [ngClass]=\"{'make-gray': (config.greyOut && config.greyOut(row)) || row.pendingApproval}\"></tr>\r\n </table>\r\n\r\n </div>\r\n\r\n <!-- Changed: Removed *ngIf condition to keep paginator always in DOM and maintain ViewChild reference -->\r\n <!-- Changed: Added CSS class binding to hide when no data instead of conditional rendering -->\r\n <mat-paginator \r\n #tablePaginator \r\n [pageSizeOptions]=\"config.pageSizes ?? [10, 20, 50]\" \r\n [ngClass]=\"{'paginator-hidden': !dataSource || (smallScreen && dataSource?.length === 0)}\"\r\n showFirstLastButtons>\r\n </mat-paginator>\r\n\r\n </div>\r\n \r\n <!-- Capsules -->\r\n <spa-capsules *ngIf=\"config?.viewType === 'capsule'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n (actionClick)=\"actionClicked($event.name, $event.row)\">\r\n </spa-capsules>\r\n\r\n\r\n <!-- Cards -->\r\n <spa-cards *ngIf=\"config?.viewType === 'card'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n [smallScreen]=\"smallScreen\"\r\n (actionClick)=\"actionClicked($event.name, $event.row)\"\r\n (columnClick)=\"columnClicked($event.column, $event.row)\"\r\n (showBannerEvent)=\"showBanner($event)\">\r\n </spa-cards>\r\n\r\n <!-- Groups - Added: New grouped view type -->\r\n <spa-groups *ngIf=\"config?.viewType === 'grouped'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n (actionClick)=\"actionClicked($event.name, $event.row, $event.group, $event.button)\">\r\n </spa-groups>\r\n\r\n\r\n <div class=\"tin-center\">\r\n <p *ngIf=\"dataSource?.length == 0\"><em>{{config.noDataMessage ?? 'No Data'}}</em></p>\r\n </div>\r\n\r\n</ng-container>\r\n\r\n\r\n<ng-container *ngIf=\"!hasFormAccess\">\r\n <div class=\"tin-center\">\r\n <p><em>Access Restricted</em></p>\r\n </div>\r\n</ng-container>\r\n\r\n", styles: [".top{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:center;margin-bottom:10px;margin-top:10px}.mat-mini-fab{width:32px;height:32px}.mat-mini-fab mat-icon{font-size:16px;margin-top:-3px}.mat-icon-button{width:32px;height:32px}.mat-icon-button mat-icon{font-size:20px;margin-top:-7px}.col-icon{margin-left:10px}.title{margin-top:10px;font-size:larger;font-weight:300}.make-gray{background-color:#f5f5f5}.right-padding{padding-right:10px}.action-buttons-container{display:flex;justify-content:flex-end;align-items:center}.refreshIcon{font-size:22px!important;margin-top:-7px!important}.dialog-container{display:flex;flex-direction:column;height:100%}.dialog-content{flex:1;overflow:hidden;display:flex;flex-direction:column}.dialog-scroll-content{flex:1;overflow-y:auto;max-height:none!important;display:flex;flex-direction:column}.dialog-scroll-content>.tin-input{flex:1;display:flex;flex-direction:column}.dialog-scroll-content>.tin-input>spa-tabs-internal{flex:1;display:flex;flex-direction:column}mat-dialog-actions{flex-shrink:0;justify-content:flex-start}.paginator-hidden{display:none!important}\n"], dependencies: [{ kind: "directive", type: i2.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: i2.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i2.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "component", type: i12$2.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i12$2.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i12$2.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i12$2.MatColumnDef, selector: "[matColumnDef]", inputs: ["matColumnDef"] }, { kind: "directive", type: i12$2.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i12$2.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i12$2.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i12$2.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i12$2.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i12$2.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i13.MatPaginator, selector: "mat-paginator", inputs: ["color", "pageIndex", "length", "pageSize", "pageSizeOptions", "hidePageSize", "showFirstLastButtons", "selectConfig", "disabled"], outputs: ["page"], exportAs: ["matPaginator"] }, { kind: "component", type: SearchComponent, selector: "spa-search", inputs: ["config", "smallScreen", "tableDataSource"], outputs: ["searchClick"] }, { kind: "component", type: TableHeaderComponent, selector: "app-table-header", inputs: ["lastSearch", "config", "hideTitle", "tableDataSource", "tileConfig", "smallScreen", "tileReload", "showFilterButton", "data", "tileData"], outputs: ["createClick", "customClick", "refreshClick", "tileClick", "tileUnClick"] }, { kind: "component", type: TableRowComponent, selector: "app-table-row", inputs: ["column", "row", "config", "smallScreen"], outputs: ["actionClick", "columnClick", "showBannerEvent"] }, { kind: "component", type: TableActionComponent, selector: "app-table-action", inputs: ["displayedButtons", "config", "row", "smallScreen"], outputs: ["actionClick"] }, { kind: "component", type: CapsulesComponent, selector: "spa-capsules", inputs: ["config", "dataSource", "displayedButtons"], outputs: ["actionClick"] }, { kind: "component", type: CardsComponent, selector: "spa-cards", inputs: ["config", "dataSource", "displayedButtons", "smallScreen"], outputs: ["actionClick", "columnClick", "showBannerEvent"] }, { kind: "component", type: GroupsComponent, selector: "spa-groups", inputs: ["config", "dataSource", "displayedButtons"], outputs: ["actionClick"] }, { kind: "pipe", type: CamelToWordsPipe, name: "camelToWords" }] }); }
|
|
14105
14394
|
}
|
|
14106
14395
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: TableComponent, decorators: [{
|
|
14107
14396
|
type: Component,
|
|
14108
14397
|
args: [{ selector: 'spa-table', standalone: false, template: "\r\n<ng-container *ngIf=\"hasFormAccess\">\r\n\r\n <!-- Search -->\r\n <spa-search\r\n *ngIf=\"config.searchConfig\" [config]=\"config.searchConfig\" [smallScreen]=\"smallScreen\" [tableDataSource]=\"tableDataSource\" style=\"margin-bottom: 20px;\" (searchClick)=\"searchClicked($event)\">\r\n </spa-search>\r\n\r\n <!-- Header -->\r\n <app-table-header\r\n [config]=\"config\" [data]=\"dataSource\" [tableDataSource]=\"tableDataSource\" [tileConfig]=\"config.tileConfig\" [tileData]=\"tileData\" [tileReload]=\"tileReload\" [lastSearch]=\"lastSearch\" [smallScreen]=\"smallScreen\"\r\n [showFilterButton]=\"showFilterButton\" (createClick)=\"newModel()\" (customClick)=\"customModel($event,null)\"\r\n (refreshClick)=\"refreshClicked()\" (tileClick)=\"tileClicked($event)\" (tileUnClick)=\"tileUnClicked($event)\">\r\n </app-table-header>\r\n\r\n\r\n <!-- Table -->\r\n <div *ngIf=\"!config.viewType || config?.viewType === 'table'\">\r\n\r\n <p *ngIf=\"!config\"><em>Configure Table</em></p>\r\n <p *ngIf=\"!dataSource\"><em>Loading...</em></p>\r\n\r\n <div *ngIf=\"dataSource && (!smallScreen || (smallScreen && dataSource?.length > 0))\">\r\n\r\n <table mat-table [dataSource]=\"tableDataSource\" [ngClass]=\"elevation\">\r\n\r\n <ng-container *ngFor=\"let column of config.columns\" [matColumnDef]=\"column.name\">\r\n <th mat-header-cell *matHeaderCellDef >{{ column.alias ?? column.name | camelToWords }}</th>\r\n <td mat-cell *matCellDef=\"let row;\" class=\"right-padding\" >\r\n\r\n <!-- Rows -->\r\n <app-table-row [column]=\"column\" [row]=\"row\" [config]=\"config\" [smallScreen]=\"smallScreen\"\r\n (actionClick)=\"actionClicked(column.name, row)\" (columnClick)=\"columnClicked(column, row)\" (showBannerEvent)=\"showBanner($event)\">\r\n </app-table-row>\r\n\r\n </td>\r\n </ng-container>\r\n\r\n <ng-container matColumnDef=\"action\">\r\n <th mat-header-cell *matHeaderCellDef> Action </th>\r\n <td mat-cell *matCellDef=\"let row\" [ngStyle]=\"{width:false ? '20px' : actionsWidth}\">\r\n <div class=\"action-buttons-container\">\r\n\r\n <!-- Actions -->\r\n <app-table-action\r\n [displayedButtons]=\"displayedButtons\" [config]=\"config\" [smallScreen]=\"smallScreen\" [row]=\"row\" (actionClick)=\"actionClicked($event.name, $event.row)\">\r\n </app-table-action>\r\n\r\n </div>\r\n </td>\r\n </ng-container>\r\n\r\n\r\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\r\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\" [ngClass]=\"{'make-gray': (config.greyOut && config.greyOut(row)) || row.pendingApproval}\"></tr>\r\n </table>\r\n\r\n </div>\r\n\r\n <!-- Changed: Removed *ngIf condition to keep paginator always in DOM and maintain ViewChild reference -->\r\n <!-- Changed: Added CSS class binding to hide when no data instead of conditional rendering -->\r\n <mat-paginator \r\n #tablePaginator \r\n [pageSizeOptions]=\"config.pageSizes ?? [10, 20, 50]\" \r\n [ngClass]=\"{'paginator-hidden': !dataSource || (smallScreen && dataSource?.length === 0)}\"\r\n showFirstLastButtons>\r\n </mat-paginator>\r\n\r\n </div>\r\n \r\n <!-- Capsules -->\r\n <spa-capsules *ngIf=\"config?.viewType === 'capsule'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n (actionClick)=\"actionClicked($event.name, $event.row)\">\r\n </spa-capsules>\r\n\r\n\r\n <!-- Cards -->\r\n <spa-cards *ngIf=\"config?.viewType === 'card'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n [smallScreen]=\"smallScreen\"\r\n (actionClick)=\"actionClicked($event.name, $event.row)\"\r\n (columnClick)=\"columnClicked($event.column, $event.row)\"\r\n (showBannerEvent)=\"showBanner($event)\">\r\n </spa-cards>\r\n\r\n <!-- Groups - Added: New grouped view type -->\r\n <spa-groups *ngIf=\"config?.viewType === 'grouped'\"\r\n [config]=\"config\"\r\n [dataSource]=\"dataSource\"\r\n [displayedButtons]=\"displayedButtons\"\r\n (actionClick)=\"actionClicked($event.name, $event.row, $event.group, $event.button)\">\r\n </spa-groups>\r\n\r\n\r\n <div class=\"tin-center\">\r\n <p *ngIf=\"dataSource?.length == 0\"><em>{{config.noDataMessage ?? 'No Data'}}</em></p>\r\n </div>\r\n\r\n</ng-container>\r\n\r\n\r\n<ng-container *ngIf=\"!hasFormAccess\">\r\n <div class=\"tin-center\">\r\n <p><em>Access Restricted</em></p>\r\n </div>\r\n</ng-container>\r\n\r\n", styles: [".top{display:flex;flex-direction:row;flex-wrap:wrap;justify-content:space-between;align-items:center;margin-bottom:10px;margin-top:10px}.mat-mini-fab{width:32px;height:32px}.mat-mini-fab mat-icon{font-size:16px;margin-top:-3px}.mat-icon-button{width:32px;height:32px}.mat-icon-button mat-icon{font-size:20px;margin-top:-7px}.col-icon{margin-left:10px}.title{margin-top:10px;font-size:larger;font-weight:300}.make-gray{background-color:#f5f5f5}.right-padding{padding-right:10px}.action-buttons-container{display:flex;justify-content:flex-end;align-items:center}.refreshIcon{font-size:22px!important;margin-top:-7px!important}.dialog-container{display:flex;flex-direction:column;height:100%}.dialog-content{flex:1;overflow:hidden;display:flex;flex-direction:column}.dialog-scroll-content{flex:1;overflow-y:auto;max-height:none!important;display:flex;flex-direction:column}.dialog-scroll-content>.tin-input{flex:1;display:flex;flex-direction:column}.dialog-scroll-content>.tin-input>spa-tabs-internal{flex:1;display:flex;flex-direction:column}mat-dialog-actions{flex-shrink:0;justify-content:flex-start}.paginator-hidden{display:none!important}\n"] }]
|
|
14109
|
-
}], ctorParameters: () => [{ type: DataServiceLib }, { type: MessageService }, { type: i1$3.BreakpointObserver }, { type: i1.MatDialog }, { type: ButtonService }, { type: DialogService }, { type: TableConfigService }, { type: ConditionService }, { type: AuthService }], propDecorators: { tablePaginator: [{
|
|
14398
|
+
}], ctorParameters: () => [{ type: DataServiceLib }, { type: MessageService }, { type: i1$3.BreakpointObserver }, { type: i1.MatDialog }, { type: ButtonService }, { type: DialogService }, { type: TableConfigService }, { type: ConditionService }, { type: AuthService }, { type: SignalRService }], propDecorators: { tablePaginator: [{
|
|
14110
14399
|
type: ViewChild,
|
|
14111
14400
|
args: ['tablePaginator', { static: false }]
|
|
14112
14401
|
}], data: [{
|
|
@@ -16437,6 +16726,7 @@ class LoginComponent {
|
|
|
16437
16726
|
}
|
|
16438
16727
|
// Changed: Auto-redirect only if session is genuinely valid (non-expired token)
|
|
16439
16728
|
if (this.authService.hasValidSession()) {
|
|
16729
|
+
this.notifications(); // Changed: Establish SignalR connections on session restore (not just fresh login)
|
|
16440
16730
|
this.router.navigate([this.redirectPath]);
|
|
16441
16731
|
return;
|
|
16442
16732
|
}
|
|
@@ -16446,6 +16736,7 @@ class LoginComponent {
|
|
|
16446
16736
|
this.authService.silentRefresh().then((success) => {
|
|
16447
16737
|
this.isProcessing = false;
|
|
16448
16738
|
if (success) {
|
|
16739
|
+
this.notifications(); // Changed: Establish SignalR connections after silent refresh
|
|
16449
16740
|
this.router.navigate([this.redirectPath]);
|
|
16450
16741
|
}
|
|
16451
16742
|
// If refresh fails, stay on login page — user must re-enter credentials
|
|
@@ -16554,11 +16845,14 @@ class LoginComponent {
|
|
|
16554
16845
|
notifications() {
|
|
16555
16846
|
if (this.appConfig.multitenant) {
|
|
16556
16847
|
this.notificationsService.loadNotifications();
|
|
16557
|
-
// Changed: Start SignalR
|
|
16558
|
-
const
|
|
16848
|
+
// Changed: Start SignalR connections for real-time notification count and entity change updates
|
|
16849
|
+
const notificationHubUrl = this.httpService.apiUrl.replace(/\/api\/$/, '/hubs/notification');
|
|
16850
|
+
const dataHubUrl = this.httpService.apiUrl.replace(/\/api\/$/, '/hubs/data'); // Changed: Data hub for real-time table updates
|
|
16559
16851
|
this.storageService.get(Constants.AUTH_TOKEN).then((token) => {
|
|
16560
|
-
if (token)
|
|
16561
|
-
this.signalRService.startConnection(
|
|
16852
|
+
if (token) {
|
|
16853
|
+
this.signalRService.startConnection(notificationHubUrl, token);
|
|
16854
|
+
this.signalRService.startDataConnection(dataHubUrl, token); // Changed: Connect to data hub
|
|
16855
|
+
}
|
|
16562
16856
|
});
|
|
16563
16857
|
}
|
|
16564
16858
|
}
|
|
@@ -18157,7 +18451,9 @@ class PurchasingService {
|
|
|
18157
18451
|
{ name: 'delete', dialog: true, action: { url: 'purchaseorders?action=delete', method: 'post' } }
|
|
18158
18452
|
],
|
|
18159
18453
|
loadAction: { url: 'purchaseorders/all/x' },
|
|
18160
|
-
formConfig: this.purchaseOrderFormConfig
|
|
18454
|
+
formConfig: this.purchaseOrderFormConfig,
|
|
18455
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
18456
|
+
entityName: 'PurchaseOrder'
|
|
18161
18457
|
};
|
|
18162
18458
|
//--------------------------Inventory Receipts-------------------------
|
|
18163
18459
|
this.inventoryReceiptItemFormConfig = {
|
|
@@ -18311,7 +18607,9 @@ class PurchasingService {
|
|
|
18311
18607
|
{ name: 'delete', dialog: true, icon: { name: 'delete_forever', color: 'red' }, action: { url: 'inventoryreceipts?action=delete', method: 'post' }, confirm: { message: 'CAUTION: Deleting this receipt will reverse all inventory additions, any sales of this inventory, and all related accounting transactions. This action cannot be undone. Are you sure you want to proceed?' } },
|
|
18312
18608
|
],
|
|
18313
18609
|
loadAction: { url: 'inventoryreceipts/all/x' },
|
|
18314
|
-
formConfig: this.inventoryReceiptFormConfig
|
|
18610
|
+
formConfig: this.inventoryReceiptFormConfig,
|
|
18611
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
18612
|
+
entityName: 'InventoryReceipt'
|
|
18315
18613
|
};
|
|
18316
18614
|
//--------------------------Supplier Payments-------------------------
|
|
18317
18615
|
// Changed: Supplier payment form for recording payments against credit purchase receipts
|
|
@@ -18511,7 +18809,8 @@ class TransactionsComponent {
|
|
|
18511
18809
|
this.accountingService = inject(AccountingService);
|
|
18512
18810
|
this.pageConfig = {
|
|
18513
18811
|
title: 'Transactions',
|
|
18514
|
-
tableConfig: this.accountingService.transactionsTableConfig
|
|
18812
|
+
tableConfig: this.accountingService.transactionsTableConfig,
|
|
18813
|
+
searchTableConfig: this.accountingService.transactionSearchTableConfig // Changed: Enable search mode with date range, description, account filters
|
|
18515
18814
|
};
|
|
18516
18815
|
}
|
|
18517
18816
|
ngOnInit() {
|
|
@@ -18812,7 +19111,9 @@ class SalesService {
|
|
|
18812
19111
|
this.salesOrderDeliverButton
|
|
18813
19112
|
],
|
|
18814
19113
|
loadAction: { url: 'salesorders/all/x' },
|
|
18815
|
-
formConfig: this.salesOrderFormConfig
|
|
19114
|
+
formConfig: this.salesOrderFormConfig,
|
|
19115
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
19116
|
+
entityName: 'SalesOrder'
|
|
18816
19117
|
};
|
|
18817
19118
|
//--------------------------Sale Items-------------------------
|
|
18818
19119
|
this.saleItemFormConfig = {
|
|
@@ -18994,7 +19295,9 @@ class SalesService {
|
|
|
18994
19295
|
this.saleVoidButton
|
|
18995
19296
|
],
|
|
18996
19297
|
loadAction: { url: 'sales/all/x' },
|
|
18997
|
-
formConfig: this.saleFormConfig
|
|
19298
|
+
formConfig: this.saleFormConfig,
|
|
19299
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
19300
|
+
entityName: 'Sale'
|
|
18998
19301
|
};
|
|
18999
19302
|
}
|
|
19000
19303
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: SalesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
@@ -19289,7 +19592,9 @@ class ProductionService {
|
|
|
19289
19592
|
{ name: 'delete', dialog: true, action: { url: 'productionrecipes?action=delete', method: 'post' } }
|
|
19290
19593
|
],
|
|
19291
19594
|
loadAction: { url: 'productionrecipes/all/x' },
|
|
19292
|
-
formConfig: this.recipeFormConfig
|
|
19595
|
+
formConfig: this.recipeFormConfig,
|
|
19596
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
19597
|
+
entityName: 'ProductionRecipe'
|
|
19293
19598
|
};
|
|
19294
19599
|
// ==================== PRODUCTION ORDERS ====================
|
|
19295
19600
|
this.orderItemFormConfig = {
|
|
@@ -19409,7 +19714,9 @@ class ProductionService {
|
|
|
19409
19714
|
{ name: 'delete', dialog: true, action: { url: 'productionorders?action=delete', method: 'post' }, visible: (x) => x.statusName === 'Draft' }
|
|
19410
19715
|
],
|
|
19411
19716
|
loadAction: { url: 'productionorders/all/x' },
|
|
19412
|
-
formConfig: this.orderFormConfig
|
|
19717
|
+
formConfig: this.orderFormConfig,
|
|
19718
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
19719
|
+
entityName: 'ProductionOrder'
|
|
19413
19720
|
};
|
|
19414
19721
|
}
|
|
19415
19722
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: ProductionService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
@@ -19816,6 +20123,8 @@ class PayrollService {
|
|
|
19816
20123
|
],
|
|
19817
20124
|
loadAction: { url: 'salarystructures/all/x' },
|
|
19818
20125
|
formConfig: this.salaryStructureFormConfig,
|
|
20126
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
20127
|
+
entityName: 'SalaryStructure'
|
|
19819
20128
|
};
|
|
19820
20129
|
//--------------------------Statutory Deduction Bands (child of StatutoryDeductionType)-------------------------
|
|
19821
20130
|
this.statutoryDeductionBandFormConfig = {
|
|
@@ -19893,6 +20202,8 @@ class PayrollService {
|
|
|
19893
20202
|
],
|
|
19894
20203
|
loadAction: { url: 'statutorydeductiontypes/all/x' },
|
|
19895
20204
|
formConfig: this.statutoryDeductionTypeFormConfig,
|
|
20205
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
20206
|
+
entityName: 'StatutoryDeductionType'
|
|
19896
20207
|
};
|
|
19897
20208
|
//--------------------------Payslip Lines (child of Payslip)-------------------------
|
|
19898
20209
|
this.payslipLineFormConfig = {
|
|
@@ -20058,6 +20369,8 @@ class PayrollService {
|
|
|
20058
20369
|
],
|
|
20059
20370
|
loadAction: { url: 'commissionconfigs/all/x' },
|
|
20060
20371
|
formConfig: this.commissionConfigFormConfig,
|
|
20372
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
20373
|
+
entityName: 'CommissionConfig'
|
|
20061
20374
|
};
|
|
20062
20375
|
// Employee commission configs child table
|
|
20063
20376
|
this.employeeCommissionConfigsTableConfig = {
|
|
@@ -20117,6 +20430,8 @@ class PayrollService {
|
|
|
20117
20430
|
],
|
|
20118
20431
|
loadAction: { url: 'commissionentries/all/x' },
|
|
20119
20432
|
formConfig: this.commissionEntryFormConfig,
|
|
20433
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
20434
|
+
entityName: 'CommissionEntry'
|
|
20120
20435
|
};
|
|
20121
20436
|
// Employee commission entries child table
|
|
20122
20437
|
this.employeeCommissionEntriesTableConfig = {
|
|
@@ -20171,6 +20486,8 @@ class PayrollService {
|
|
|
20171
20486
|
],
|
|
20172
20487
|
loadAction: { url: 'salaryadvances/all/x' },
|
|
20173
20488
|
formConfig: this.salaryAdvanceFormConfig,
|
|
20489
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
20490
|
+
entityName: 'SalaryAdvance'
|
|
20174
20491
|
};
|
|
20175
20492
|
// Employee salary advances child table
|
|
20176
20493
|
this.employeeSalaryAdvancesTableConfig = {
|
|
@@ -20226,6 +20543,8 @@ class PayrollService {
|
|
|
20226
20543
|
],
|
|
20227
20544
|
loadAction: { url: 'overtimeentries/all/x' },
|
|
20228
20545
|
formConfig: this.overtimeEntryFormConfig,
|
|
20546
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
20547
|
+
entityName: 'OvertimeEntry'
|
|
20229
20548
|
};
|
|
20230
20549
|
// Employee overtime entries child table
|
|
20231
20550
|
this.employeeOvertimeHistoryTableConfig = {
|
|
@@ -20295,6 +20614,8 @@ class PayrollService {
|
|
|
20295
20614
|
],
|
|
20296
20615
|
loadAction: { url: 'payrollruns/all/x' },
|
|
20297
20616
|
formConfig: this.payrollRunFormConfig,
|
|
20617
|
+
// realTime: true, // Disabled: testing realtime on transactions table only
|
|
20618
|
+
entityName: 'PayrollRun'
|
|
20298
20619
|
};
|
|
20299
20620
|
}
|
|
20300
20621
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: PayrollService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
@@ -20534,7 +20855,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
|
|
|
20534
20855
|
}]
|
|
20535
20856
|
}] });
|
|
20536
20857
|
|
|
20537
|
-
// Accounting module dashboard
|
|
20858
|
+
// Accounting module dashboard — pure financial/account performance (invoice-specific moved to invoicing)
|
|
20538
20859
|
class AccountingDashboardComponent {
|
|
20539
20860
|
constructor() {
|
|
20540
20861
|
this.summaryTiles = {
|
|
@@ -20542,45 +20863,56 @@ class AccountingDashboardComponent {
|
|
|
20542
20863
|
{ name: 'revenue', alias: 'Revenue (MTD)', color: '#4caf50', icon: 'trending_up', style: 'icon', info: 'MTD revenue' },
|
|
20543
20864
|
{ name: 'expenses', alias: 'Expenses (MTD)', color: '#f44336', icon: 'trending_down', style: 'icon', info: 'MTD expenses' },
|
|
20544
20865
|
{ name: 'netProfit', alias: 'Net Profit (MTD)', color: '#2196f3', icon: 'account_balance', style: 'icon', info: 'MTD profit' },
|
|
20545
|
-
{ name: '
|
|
20546
|
-
{ name: '
|
|
20547
|
-
{ name: '
|
|
20866
|
+
{ name: 'cashBalance', alias: 'Cash & Bank', color: '#ff9800', icon: 'account_balance_wallet', style: 'icon', info: 'Cash + bank total' }, // Changed: Replaced outstandingAR
|
|
20867
|
+
{ name: 'totalLiabilities', alias: 'Liabilities', color: '#9c27b0', icon: 'credit_card', style: 'icon', info: 'Total liabilities' }, // Changed: Replaced outstandingAP
|
|
20868
|
+
{ name: 'transactionsMTD', alias: 'Transactions', color: '#607d8b', icon: 'swap_horiz', style: 'icon', info: 'Posted this period' }, // Changed: Replaced overdueInvoices
|
|
20548
20869
|
],
|
|
20549
|
-
loadAction: { url: 'accounts/dashboard-summary/x' },
|
|
20870
|
+
loadAction: { url: 'accounts/dashboard-summary/x' },
|
|
20550
20871
|
loadInit: true
|
|
20551
20872
|
};
|
|
20552
|
-
// Changed:
|
|
20873
|
+
// Changed: Replaced collectionRate/invoiceStatusSplit with profitMargin/expenseBreakdown
|
|
20553
20874
|
this.chartTiles = {
|
|
20554
20875
|
tiles: [
|
|
20555
|
-
{ name: '
|
|
20556
|
-
{ name: 'revenueTrendSpark', alias: 'Revenue Trend', color: '#2196f3', chart: { type: 'line', color: '#2196f3', height: 100, dataField: 'revenueTrendSpark' }, footer: 'Last 12 months', footerIcon: 'show_chart' },
|
|
20557
|
-
{ name: '
|
|
20558
|
-
{ name: 'expenseTrendSpark', alias: 'Expense Trend', color: '#f44336', chart: { type: 'bar', colors: ['#f44336', '#ef5350', '#e57373', '#ef9a9a', '#ffcdd2', '#f44336'], height: 100, dataField: 'expenseTrendSpark' }, footer: 'Last 6 months', footerIcon: 'trending_down' },
|
|
20876
|
+
{ name: 'profitMargin', alias: 'Profit Margin', color: '#4caf50', chart: { type: 'doughnut', gaugeColor: '#4caf50', height: 130, dataField: 'profitMargin' }, footer: 'Net profit / revenue', footerIcon: 'pie_chart' }, // Changed: Replaced collectionRate
|
|
20877
|
+
{ name: 'revenueTrendSpark', alias: 'Revenue Trend', color: '#2196f3', chart: { type: 'line', color: '#2196f3', height: 100, dataField: 'revenueTrendSpark' }, footer: 'Last 12 months', footerIcon: 'show_chart' },
|
|
20878
|
+
{ name: 'expenseBreakdown', alias: 'Expense Breakdown', color: '#ff9800', chart: { type: 'pie', colors: ['#f44336', '#ff5722', '#ff9800', '#ffc107', '#ffeb3b', '#9e9e9e'], height: 130, dataField: 'expenseBreakdown' }, footer: 'Top 5 + Other', footerIcon: 'donut_large' }, // Changed: Replaced invoiceStatusSplit
|
|
20879
|
+
{ name: 'expenseTrendSpark', alias: 'Expense Trend', color: '#f44336', chart: { type: 'bar', colors: ['#f44336', '#ef5350', '#e57373', '#ef9a9a', '#ffcdd2', '#f44336'], height: 100, dataField: 'expenseTrendSpark' }, footer: 'Last 6 months', footerIcon: 'trending_down' },
|
|
20559
20880
|
],
|
|
20560
|
-
loadAction: { url: 'accounts/dashboard-chart-tiles/x' },
|
|
20881
|
+
loadAction: { url: 'accounts/dashboard-chart-tiles/x' },
|
|
20561
20882
|
loadInit: true
|
|
20562
20883
|
};
|
|
20884
|
+
// Changed: Replaced arAging/invoiceStatus with cashFlow/transactionVolume
|
|
20563
20885
|
this.chartConfig = {
|
|
20564
20886
|
charts: [
|
|
20565
|
-
{ name: 'revenueTrend', title: 'Revenue vs Expenses Trend', type: 'line', height: '300px', showPoints: true, tension: 0.4, colors: ['#4caf50', '#f44336'], showLegend: true },
|
|
20566
|
-
{ name: '
|
|
20887
|
+
{ name: 'revenueTrend', title: 'Revenue vs Expenses Trend', type: 'line', height: '300px', showPoints: true, tension: 0.4, colors: ['#4caf50', '#f44336'], showLegend: true },
|
|
20888
|
+
{ name: 'cashFlow', title: 'Monthly Cash Flow', type: 'bar', height: '300px', colors: ['#4caf50', '#f44336'], showLegend: true }, // Changed: Replaced arAging
|
|
20567
20889
|
{ name: 'accountBalances', title: 'Account Balances by Type', type: 'bar', height: '300px', colors: ['#2196f3', '#f44336', '#4caf50', '#ff9800', '#9c27b0'] },
|
|
20568
|
-
{ name: '
|
|
20890
|
+
{ name: 'transactionVolume', title: 'Monthly Transaction Volume', type: 'bar', height: '300px', colors: ['#7c4dff'] }, // Changed: Replaced invoiceStatus
|
|
20569
20891
|
],
|
|
20570
|
-
loadAction: { url: 'accounts/dashboard-charts/x' },
|
|
20892
|
+
loadAction: { url: 'accounts/dashboard-charts/x' },
|
|
20571
20893
|
loadInit: true,
|
|
20572
20894
|
columns: 2
|
|
20573
20895
|
};
|
|
20896
|
+
// Changed: New cash/bank running balance line chart with separate data source
|
|
20897
|
+
this.cashBankChartConfig = {
|
|
20898
|
+
charts: [
|
|
20899
|
+
{ name: 'cashBankBalances', title: 'Cash & Bank Balances (30 Days)', type: 'line', height: '500px', showPoints: true, tension: 0.4, showLegend: true }, // Changed: Increased height for more granular values
|
|
20900
|
+
],
|
|
20901
|
+
loadAction: { url: 'accounts/dashboard-cash-balances/x' },
|
|
20902
|
+
loadInit: true,
|
|
20903
|
+
columns: 1
|
|
20904
|
+
};
|
|
20574
20905
|
}
|
|
20575
20906
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.14", ngImport: i0, type: AccountingDashboardComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
20576
20907
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.14", type: AccountingDashboardComponent, isStandalone: false, selector: "spa-accounting-dashboard", ngImport: i0, template: `
|
|
20577
20908
|
<div class="dashboard-container">
|
|
20578
20909
|
<h4 class="dashboard-title"><mat-icon>account_balance</mat-icon> Accounting Dashboard</h4>
|
|
20579
20910
|
<spa-tiles [config]="summaryTiles"></spa-tiles>
|
|
20580
|
-
<!-- Changed: Chart tiles for mini financial indicators -->
|
|
20581
20911
|
<div style="margin-top: 16px;"></div>
|
|
20582
20912
|
<spa-tiles [config]="chartTiles"></spa-tiles>
|
|
20583
20913
|
<spa-charts [config]="chartConfig"></spa-charts>
|
|
20914
|
+
<!-- Changed: Separate cash/bank balance chart with own data source -->
|
|
20915
|
+
<spa-charts [config]="cashBankChartConfig"></spa-charts>
|
|
20584
20916
|
</div>
|
|
20585
20917
|
`, isInline: true, styles: [".dashboard-container{padding:16px}.dashboard-title{display:flex;align-items:center;gap:8px;margin-bottom:16px;color:#333;font-weight:500}\n"], dependencies: [{ kind: "component", type: i4$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: TilesComponent, selector: "spa-tiles", inputs: ["config", "lastSearch", "data", "reload"], outputs: ["tileActionSelected", "tileClick", "tileUnClick"] }, { kind: "component", type: ChartsComponent, selector: "spa-charts", inputs: ["config", "data", "reload"] }] }); }
|
|
20586
20918
|
}
|
|
@@ -20590,10 +20922,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.14", ngImpo
|
|
|
20590
20922
|
<div class="dashboard-container">
|
|
20591
20923
|
<h4 class="dashboard-title"><mat-icon>account_balance</mat-icon> Accounting Dashboard</h4>
|
|
20592
20924
|
<spa-tiles [config]="summaryTiles"></spa-tiles>
|
|
20593
|
-
<!-- Changed: Chart tiles for mini financial indicators -->
|
|
20594
20925
|
<div style="margin-top: 16px;"></div>
|
|
20595
20926
|
<spa-tiles [config]="chartTiles"></spa-tiles>
|
|
20596
20927
|
<spa-charts [config]="chartConfig"></spa-charts>
|
|
20928
|
+
<!-- Changed: Separate cash/bank balance chart with own data source -->
|
|
20929
|
+
<spa-charts [config]="cashBankChartConfig"></spa-charts>
|
|
20597
20930
|
</div>
|
|
20598
20931
|
`, standalone: false, styles: [".dashboard-container{padding:16px}.dashboard-title{display:flex;align-items:center;gap:8px;margin-bottom:16px;color:#333;font-weight:500}\n"] }]
|
|
20599
20932
|
}] });
|
|
@@ -20731,8 +21064,8 @@ class OverviewDashboardComponent {
|
|
|
20731
21064
|
{ name: 'expenses', alias: 'Expenses (MTD)', color: '#f44336', icon: 'trending_down', style: 'icon', info: 'MTD expenses' },
|
|
20732
21065
|
{ name: 'netProfit', alias: 'Net Profit (MTD)', color: '#2196f3', icon: 'account_balance', style: 'icon', info: 'MTD profit' },
|
|
20733
21066
|
{ name: 'stockValue', alias: 'Stock Value', color: '#ff9800', icon: 'inventory_2', style: 'icon', info: 'Inventory value' },
|
|
20734
|
-
{ name: '
|
|
20735
|
-
{ name: '
|
|
21067
|
+
{ name: 'cashBalance', alias: 'Cash & Bank', color: '#9c27b0', icon: 'account_balance_wallet', style: 'icon', info: 'Cash + bank total' }, // Changed: Replaced outstandingAR
|
|
21068
|
+
{ name: 'totalLiabilities', alias: 'Liabilities', color: '#e91e63', icon: 'credit_card', style: 'icon', info: 'Total liabilities' }, // Changed: Replaced outstandingAP
|
|
20736
21069
|
],
|
|
20737
21070
|
loadAction: { url: 'dashboard/overview/summary' },
|
|
20738
21071
|
loadInit: true
|
|
@@ -20824,6 +21157,7 @@ class InvoiceDashboardComponent {
|
|
|
20824
21157
|
{ name: 'agingBreakdown', title: 'AR Aging Breakdown', type: 'bar', height: '300px', colors: ['#4caf50', '#ff9800', '#ff5722', '#f44336', '#b71c1c'] },
|
|
20825
21158
|
{ name: 'topCustomers', title: 'Top Customers by Outstanding', type: 'bar', height: '300px', colors: ['#1565c0', '#1976d2', '#1e88e5', '#2196f3', '#42a5f5'] },
|
|
20826
21159
|
{ name: 'paymentTrend', title: 'Payment Collection Trend', type: 'line', height: '300px', showPoints: true, tension: 0.4, colors: ['#4caf50'], showLegend: true },
|
|
21160
|
+
{ name: 'collectionPerformance', title: 'Collection Performance (12 Months)', type: 'line', height: '300px', showPoints: true, tension: 0.4, colors: ['#f57c00', '#4caf50'], showLegend: true }, // Changed: Avg days to pay + on-time rate trend
|
|
20827
21161
|
],
|
|
20828
21162
|
loadAction: { url: 'invoices/dashboard-charts/x' },
|
|
20829
21163
|
loadInit: true,
|