@devhouse.int/angular-reusable-components 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/index.d.ts ADDED
@@ -0,0 +1,2799 @@
1
+ import * as i0 from '@angular/core';
2
+ import { OnInit, OnChanges, OnDestroy, ChangeDetectorRef, EventEmitter, TemplateRef, SimpleChanges, AfterContentInit, InjectionToken, Provider, AfterViewInit, ElementRef, DestroyRef, NgZone, ViewContainerRef, DoCheck } from '@angular/core';
3
+ import { DxFormComponent, DxListComponent, DxDataGridComponent as DxDataGridComponent$1 } from 'devextreme-angular';
4
+ import * as rxjs from 'rxjs';
5
+ import { Observable } from 'rxjs';
6
+ import * as _devhouse_int_angular_reusable_components from '@devhouse.int/angular-reusable-components';
7
+ import { ActivatedRoute, Router } from '@angular/router';
8
+ import { Guid } from 'devextreme/common';
9
+ import * as _angular_forms from '@angular/forms';
10
+ import { ControlValueAccessor } from '@angular/forms';
11
+ import { Location } from '@angular/common';
12
+ import { DxDataGridTypes, DxDataGridComponent } from 'devextreme-angular/ui/data-grid';
13
+ import { HttpClient } from '@angular/common/http';
14
+ import { DxFileManagerComponent, DxFileManagerTypes } from 'devextreme-angular/ui/file-manager';
15
+ import RemoteFileSystemProvider from 'devextreme/file_management/remote_provider';
16
+ import { DataSource } from 'devextreme/common/data';
17
+ import { SafeHtml } from '@angular/platform-browser';
18
+
19
+ declare class AppBorderWrapperComponent {
20
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppBorderWrapperComponent, never>;
21
+ static ɵcmp: i0.ɵɵComponentDeclaration<AppBorderWrapperComponent, "app-border-wrapper", never, {}, {}, never, ["*"], true, never>;
22
+ }
23
+
24
+ declare class SmartLookupHostService {
25
+ private _saved;
26
+ private _error;
27
+ readonly saved$: rxjs.Observable<any>;
28
+ readonly error$: rxjs.Observable<string>;
29
+ notifySaved(item: any): void;
30
+ notifyError(message: string): void;
31
+ static ɵfac: i0.ɵɵFactoryDeclaration<SmartLookupHostService, never>;
32
+ static ɵprov: i0.ɵɵInjectableDeclaration<SmartLookupHostService>;
33
+ }
34
+
35
+ type LoadFn<TItem> = () => Promise<TItem[]>;
36
+ type CreateFn<TCreate, TCreated> = (payload: TCreate) => Promise<TCreated>;
37
+ declare class AppSmartLookupComponent<TItem extends Record<string, any>, TCreate extends Record<string, any>> implements OnInit, OnChanges, OnDestroy {
38
+ private cdr;
39
+ private hostService;
40
+ private _hostSub;
41
+ constructor(cdr: ChangeDetectorRef, hostService: SmartLookupHostService);
42
+ label: string;
43
+ placeholder: string;
44
+ readOnly: boolean;
45
+ disabled: boolean;
46
+ valueExpr: string;
47
+ displayExpr: string | ((item: any) => string);
48
+ /** Set this when displayExpr is a function so the SelectBox can still search by a field. */
49
+ searchExpr: string | null;
50
+ value: any;
51
+ valueChange: EventEmitter<any>;
52
+ loadFn: LoadFn<TItem>;
53
+ createFn?: CreateFn<TCreate, TItem>;
54
+ createMode: 'form' | 'content';
55
+ allowAdd: boolean;
56
+ addButtonHint: string;
57
+ createPopupTitle: string;
58
+ cancelText: string;
59
+ saveText: string;
60
+ createFormItems: any[];
61
+ createInitialModel: Partial<TCreate>;
62
+ popupWidth: string | number;
63
+ popupHeight: string | number;
64
+ /**
65
+ * Lets the user resize the create popup by dragging its edges.
66
+ * dxPopup defaults `resizeEnabled` to false, so without this the popup is
67
+ * locked to `popupWidth`/`popupHeight` — which is unusable for `createMode="content"`
68
+ * hosts that project a whole grid screen (e.g. the timezones screen on the
69
+ * Countries form). Enabled by default; opt out per host if a fixed size is required.
70
+ */
71
+ popupResizeEnabled: boolean;
72
+ popupMinWidth: string | number;
73
+ popupMinHeight: string | number;
74
+ popupMaxWidth: string | number;
75
+ popupMaxHeight: string | number;
76
+ created: EventEmitter<TItem>;
77
+ contentTemplate?: TemplateRef<any>;
78
+ createFormRef?: DxFormComponent;
79
+ items: TItem[];
80
+ isLoading: boolean;
81
+ popupVisible: boolean;
82
+ saving: boolean;
83
+ createModel: TCreate;
84
+ createError: string | null;
85
+ ngOnChanges(changes: SimpleChanges): void;
86
+ ngOnInit(): Promise<void>;
87
+ ngOnDestroy(): void;
88
+ reload(): Promise<void>;
89
+ onValueChanged(e: any): void;
90
+ openCreatePopup(): void;
91
+ closeCreatePopup(): void;
92
+ private isFormValid;
93
+ saveNew(): Promise<void>;
94
+ onExternalSaved(createdItem: any): Promise<void>;
95
+ onExternalError(message: string): void;
96
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppSmartLookupComponent<any, any>, never>;
97
+ static ɵcmp: i0.ɵɵComponentDeclaration<AppSmartLookupComponent<any, any>, "app-smart-lookup", never, { "label": { "alias": "label"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "valueExpr": { "alias": "valueExpr"; "required": false; }; "displayExpr": { "alias": "displayExpr"; "required": false; }; "searchExpr": { "alias": "searchExpr"; "required": false; }; "value": { "alias": "value"; "required": false; }; "loadFn": { "alias": "loadFn"; "required": true; }; "createFn": { "alias": "createFn"; "required": false; }; "createMode": { "alias": "createMode"; "required": false; }; "allowAdd": { "alias": "allowAdd"; "required": false; }; "addButtonHint": { "alias": "addButtonHint"; "required": false; }; "createPopupTitle": { "alias": "createPopupTitle"; "required": false; }; "cancelText": { "alias": "cancelText"; "required": false; }; "saveText": { "alias": "saveText"; "required": false; }; "createFormItems": { "alias": "createFormItems"; "required": false; }; "createInitialModel": { "alias": "createInitialModel"; "required": false; }; "popupWidth": { "alias": "popupWidth"; "required": false; }; "popupHeight": { "alias": "popupHeight"; "required": false; }; "popupResizeEnabled": { "alias": "popupResizeEnabled"; "required": false; }; "popupMinWidth": { "alias": "popupMinWidth"; "required": false; }; "popupMinHeight": { "alias": "popupMinHeight"; "required": false; }; "popupMaxWidth": { "alias": "popupMaxWidth"; "required": false; }; "popupMaxHeight": { "alias": "popupMaxHeight"; "required": false; }; }, { "valueChange": "valueChange"; "created": "created"; }, ["contentTemplate"], never, true, never>;
98
+ }
99
+
100
+ type AppToolbarItemLocation = 'before' | 'after' | 'center';
101
+ declare class AppToolbarComponent implements AfterContentInit {
102
+ containerClass: string;
103
+ private readonly projectedItems;
104
+ items: AppToolbarItemComponent[];
105
+ ngAfterContentInit(): void;
106
+ get beforeItems(): AppToolbarItemComponent[];
107
+ get centerItems(): AppToolbarItemComponent[];
108
+ get afterItems(): AppToolbarItemComponent[];
109
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppToolbarComponent, never>;
110
+ static ɵcmp: i0.ɵɵComponentDeclaration<AppToolbarComponent, "app-toolbar", never, { "containerClass": { "alias": "containerClass"; "required": false; }; }, {}, ["projectedItems"], never, true, never>;
111
+ }
112
+
113
+ declare class AppToolbarItemComponent {
114
+ location: AppToolbarItemLocation;
115
+ widget?: string;
116
+ options: any;
117
+ projectedTemplate?: TemplateRef<unknown>;
118
+ /**
119
+ * CSS class(es) applied to the button via `options.cssClass` (or `options.class`)
120
+ * — style it in your own component SCSS exactly like a normal button.
121
+ */
122
+ get buttonCssClass(): string;
123
+ itemTemplate: TemplateRef<unknown>;
124
+ onButtonClick: (e: any) => void;
125
+ onSelectValueChanged: (e: any) => void;
126
+ onSelectCustomItemCreating: (e: any) => void;
127
+ onDropDownItemClick: (e: any) => void;
128
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppToolbarItemComponent, never>;
129
+ static ɵcmp: i0.ɵɵComponentDeclaration<AppToolbarItemComponent, "app-toolbar-item", never, { "location": { "alias": "location"; "required": false; }; "widget": { "alias": "widget"; "required": false; }; "options": { "alias": "options"; "required": false; }; }, {}, ["projectedTemplate"], ["*"], true, never>;
130
+ }
131
+
132
+ declare class DxDateBoxRangeComponent {
133
+ label: string;
134
+ fromDate: Date | null;
135
+ toDate: Date | null;
136
+ onDateChange(): void;
137
+ static ɵfac: i0.ɵɵFactoryDeclaration<DxDateBoxRangeComponent, never>;
138
+ static ɵcmp: i0.ɵɵComponentDeclaration<DxDateBoxRangeComponent, "app-dx-date-box-range", never, { "label": { "alias": "label"; "required": false; }; "fromDate": { "alias": "fromDate"; "required": false; }; "toDate": { "alias": "toDate"; "required": false; }; }, {}, never, never, true, never>;
139
+ }
140
+
141
+ interface FormNavigatorPermissions {
142
+ canInsert?: boolean;
143
+ canUpdate?: boolean;
144
+ canOpen?: boolean;
145
+ canDelete?: boolean;
146
+ canPrint?: boolean;
147
+ canExecute?: boolean;
148
+ canExport?: boolean;
149
+ canImport?: boolean;
150
+ canQuery?: boolean;
151
+ canPrintreport?: boolean;
152
+ canDesignreport?: boolean;
153
+ canAssign?: boolean;
154
+ canShare?: boolean;
155
+ canBrowse?: boolean;
156
+ canLogin?: boolean;
157
+ }
158
+ interface FormNavigatorMessages {
159
+ Load_Data_ERROR: string;
160
+ NOT_FOUND: string;
161
+ NO_PERMISSION: string;
162
+ SAVE_ERROR: string;
163
+ SAVE_SUCCESS: string;
164
+ DELETE_ERROR: string;
165
+ DUPLICATE_ERROR: string;
166
+ DUPLICATE_SUCCESS: string;
167
+ VALIDATION_REQUIRED: string;
168
+ }
169
+ interface FormNavigatorAdapter {
170
+ permissions$: Observable<FormNavigatorPermissions | null>;
171
+ loadPermissions(): void;
172
+ translate(key: string, fallback: string): string;
173
+ /** Optional UI language hint for host components that need localized sample content. */
174
+ isArabic?(): boolean;
175
+ messages: Readonly<FormNavigatorMessages>;
176
+ notify(type: 'success' | 'error' | 'info' | 'warning', message: string): void;
177
+ confirm(type: 'delete' | 'duplicate' | 'unsaved'): Promise<boolean>;
178
+ beginRecordLoad(): number;
179
+ waitForLookups(loadId: number): Promise<void>;
180
+ isRecordLoadActive(loadId: number): boolean;
181
+ /**
182
+ * Optional: lets a lookup editor register an in-flight value resolution with the record
183
+ * load so the host can wait for lookups to settle. Returns a completion callback.
184
+ */
185
+ trackLookup?(): (() => void) | null;
186
+ showLoading(message: string): void;
187
+ hideLoading(): void;
188
+ }
189
+ declare const FORM_NAVIGATOR_ADAPTER: InjectionToken<FormNavigatorAdapter>;
190
+
191
+ interface InfoUserProvider {
192
+ getById(id: unknown): Observable<unknown> | Promise<unknown>;
193
+ }
194
+ declare const INFO_USER_PROVIDER: InjectionToken<InfoUserProvider>;
195
+
196
+ interface InfoDTO {
197
+ label?: string;
198
+ userName?: string;
199
+ date?: any;
200
+ }
201
+ declare class InfoPopupComponent implements OnInit {
202
+ private userService;
203
+ private cdr;
204
+ showInfo: boolean;
205
+ showSecuredInfo: boolean;
206
+ rowId: any;
207
+ tableName: string;
208
+ infoList: InfoDTO[];
209
+ popupTitle: string;
210
+ popupWidth: number | string;
211
+ popupHeight: number | string;
212
+ popupMaxWidth: number | string;
213
+ popupMaxHeight: number | string;
214
+ popupMinWidth: number;
215
+ popupMinHeight: number;
216
+ isPopupFullScreen: boolean;
217
+ private layoutInitialized;
218
+ set currentObject(dto: any);
219
+ creatorIdUserName: string;
220
+ LastModifierIdUserName: string;
221
+ constructor(userService: InfoUserProvider, cdr: ChangeDetectorRef);
222
+ ngOnInit(): void;
223
+ onWindowResize(): void;
224
+ getUserNameById(id: any): Promise<string>;
225
+ open(): void;
226
+ close(): void;
227
+ onPopupHiding(): void;
228
+ trackByLabel(index: number, item: InfoDTO): string;
229
+ private resolveRowId;
230
+ private buildInfoList;
231
+ private ensureLayoutReady;
232
+ private updatePopupLayout;
233
+ static ɵfac: i0.ɵɵFactoryDeclaration<InfoPopupComponent, never>;
234
+ static ɵcmp: i0.ɵɵComponentDeclaration<InfoPopupComponent, "app-info-popup", never, { "currentObject": { "alias": "currentObject"; "required": false; }; }, {}, never, never, true, never>;
235
+ }
236
+
237
+ interface LookupGridProvider {
238
+ getSysLookup(id: any): Observable<any>;
239
+ createDataSource(...args: any[]): Promise<any>;
240
+ toCamelCase(value: string): string;
241
+ createGridColumns(...args: any[]): any[];
242
+ }
243
+ declare const LOOKUP_GRID_PROVIDER: InjectionToken<LookupGridProvider>;
244
+ declare enum LookupValueType {
245
+ String = 1,
246
+ Int32 = 2,
247
+ Int16 = 3,
248
+ Int64 = 4,
249
+ Boolean = 5,
250
+ Byte = 6,
251
+ Char = 7,
252
+ Guid = 8,
253
+ DateTime = 9,
254
+ Decimal = 10,
255
+ Double = 11,
256
+ Array = 12
257
+ }
258
+ declare const LINQ_SELECT_COMMAND_TYPE = 2;
259
+ declare function lookupValueToArray(value: any, valueType?: number): any[];
260
+
261
+ interface ReusableComponentsConfig {
262
+ apiUrl?: string;
263
+ /** Optional app-wide translation hook. Components fall back to the supplied text. */
264
+ translate?: (key: string, fallback: string) => string;
265
+ /** Optional culture hint used only when content has no language-specific text. */
266
+ isArabic?: () => boolean;
267
+ }
268
+ declare const REUSABLE_COMPONENTS_CONFIG: InjectionToken<ReusableComponentsConfig>;
269
+ declare function provideReusableComponents(config: ReusableComponentsConfig): Provider;
270
+
271
+ type SysLookupNavigationDto = any;
272
+ declare class LookupDynamicGridComponent implements OnInit, OnChanges {
273
+ private sysLookupService;
274
+ private config?;
275
+ selectedValue: any[];
276
+ columns: any[];
277
+ summary: any;
278
+ remoteOperations: boolean;
279
+ keyField: string;
280
+ returnField: string;
281
+ gridDataSource: any;
282
+ isMultiSelectMode: 'single' | 'multiple';
283
+ relativeWidth: boolean;
284
+ summaryColumn: string | null;
285
+ navigationActions: SysLookupNavigationDto[];
286
+ focusedValue: any;
287
+ private _focusAppliedOnce;
288
+ isMultiSelect: boolean;
289
+ lookupId: string;
290
+ value: any;
291
+ valueChange: EventEmitter<any>;
292
+ rowDataSelected: EventEmitter<any>;
293
+ gridTitle?: string;
294
+ gridTitleChange: EventEmitter<string>;
295
+ exporting: EventEmitter<DxDataGridTypes.ExportingEvent>;
296
+ applyFilterOnEnter: boolean;
297
+ dateFormat: string;
298
+ /** Opt-in: pick the English column fields/titles when the UI is English. Default false keeps Arabic-only. */
299
+ languageAware: boolean;
300
+ lookupParameterSource: string | number | null;
301
+ lookupParameters: string | null;
302
+ selectParametersCallback?: () => Record<string, any>;
303
+ dataGrid?: DxDataGridComponent;
304
+ private _initialized;
305
+ private _dateColumnsResolved;
306
+ constructor(sysLookupService: LookupGridProvider, config?: ReusableComponentsConfig);
307
+ onEditorPreparing(e: any): void;
308
+ ngOnInit(): Promise<void>;
309
+ ngOnChanges(changes: SimpleChanges): Promise<void>;
310
+ private initGrid;
311
+ onSelectionChanged(_: any): void;
312
+ refreshGrid(): Promise<void>;
313
+ clearSelection(): void;
314
+ onExporting(e: DxDataGridTypes.ExportingEvent): void;
315
+ private prepareProperties;
316
+ onContentReady(): Promise<void>;
317
+ private resolveDateColumns;
318
+ private focusByValue;
319
+ private focusAndNavigateWhenReady;
320
+ private resetToFirstPage;
321
+ getNavigationActionForField(dataField: string): SysLookupNavigationDto | null;
322
+ openNavigationAction(action: SysLookupNavigationDto | null, rowData: any): void;
323
+ static ɵfac: i0.ɵɵFactoryDeclaration<LookupDynamicGridComponent, [null, { optional: true; }]>;
324
+ static ɵcmp: i0.ɵɵComponentDeclaration<LookupDynamicGridComponent, "app-lookup-dynamic-grid", never, { "focusedValue": { "alias": "focusedValue"; "required": false; }; "isMultiSelect": { "alias": "isMultiSelect"; "required": false; }; "lookupId": { "alias": "lookupId"; "required": false; }; "value": { "alias": "value"; "required": false; }; "gridTitle": { "alias": "gridTitle"; "required": false; }; "applyFilterOnEnter": { "alias": "applyFilterOnEnter"; "required": false; }; "dateFormat": { "alias": "dateFormat"; "required": false; }; "languageAware": { "alias": "languageAware"; "required": false; }; "lookupParameterSource": { "alias": "lookupParameterSource"; "required": false; }; "lookupParameters": { "alias": "lookupParameters"; "required": false; }; "selectParametersCallback": { "alias": "selectParametersCallback"; "required": false; }; }, { "valueChange": "valueChange"; "rowDataSelected": "rowDataSelected"; "gridTitleChange": "gridTitleChange"; "exporting": "exporting"; }, never, never, true, never>;
325
+ }
326
+
327
+ /**
328
+ * Faithful port of Flexora's original lookup popup: a thin shell around
329
+ * LookupDynamicGridComponent, which supplies the full search experience
330
+ * (search panel, filter row, metadata-driven columns/widths, paging,
331
+ * focused-value navigation, double-click selection). An earlier library
332
+ * rewrite replaced this with a bare dx-data-grid fed by LOOKUP_DATA_PROVIDER
333
+ * — losing the filter row, the metadata column widths, and the full-width
334
+ * layout — which is why the popup suddenly looked degraded on every screen.
335
+ */
336
+ declare class LookupPopupComponent {
337
+ private cdr;
338
+ lookupId: any;
339
+ selectParameters: any;
340
+ popupVisible: boolean;
341
+ selectedValue: any;
342
+ selectedRowData: any;
343
+ popupTitle: string;
344
+ lookupPopupVisibleChange: EventEmitter<boolean>;
345
+ selectedValueChanged: EventEmitter<boolean>;
346
+ /** Forwarded to the popup grid: pick English columns/titles when the UI is English.
347
+ * Set by the host (e.g. app-lookup-edit); default false = legacy Arabic behavior. */
348
+ languageAware: boolean;
349
+ focusedValue?: any;
350
+ getResultCallback: (result: any) => void;
351
+ lookupParameterSource: string | number | null;
352
+ lookupParameters: string | null;
353
+ selectParametersCallback?: () => Record<string, any>;
354
+ closeButtonOptions: Record<string, unknown>;
355
+ showButtonOptions: Record<string, unknown>;
356
+ dynamicGrid: LookupDynamicGridComponent;
357
+ constructor(cdr: ChangeDetectorRef);
358
+ openLookupPopup(lookupId: Guid, getResultCallback: (result: any) => void, lookupParameterSource?: string | number | null, lookupParameters?: string | null, selectParametersCallback?: () => Record<string, any>, valueToFocus?: any): void;
359
+ closePopup(): void;
360
+ onPopupShown(): void;
361
+ onShowClick(): void;
362
+ static ɵfac: i0.ɵɵFactoryDeclaration<LookupPopupComponent, never>;
363
+ static ɵcmp: i0.ɵɵComponentDeclaration<LookupPopupComponent, "lookup-popup, app-lookup-popup", never, {}, { "lookupPopupVisibleChange": "lookupPopupVisibleChange"; "selectedValueChanged": "selectedValueChanged"; }, never, never, true, never>;
364
+ }
365
+
366
+ declare enum FormModeEnum {
367
+ Edit = 1,
368
+ Insert = 2
369
+ }
370
+ type FormNavigatorCommand = 'first' | 'previous' | 'next' | 'last' | 'new' | 'save' | 'delete' | 'search' | 'duplicate' | 'cancel' | 'refresh' | 'info' | 'print';
371
+ type ReportModelsDto = any;
372
+ declare class FormNavigatorComponent<T = any> implements OnInit, OnDestroy, AfterViewInit {
373
+ private cdr;
374
+ private activatedRoute;
375
+ private router;
376
+ private location;
377
+ private sidebarObserver;
378
+ private resizeObserver;
379
+ private directionObserver;
380
+ private readonly renderer;
381
+ private readonly ngZone;
382
+ private readonly elementRef;
383
+ lookupID: Guid;
384
+ currentObject: T | null;
385
+ /** Physical DB table name shown in the info popup (fallback when the loaded
386
+ * record isn't stamped with `__tableName` by the data service). */
387
+ tableName?: string;
388
+ getByIndexCallback?: (index: number) => Promise<{
389
+ item: T;
390
+ tableName?: string;
391
+ } | null>;
392
+ getByKeyCallback?: (key: string) => Promise<{
393
+ item: T;
394
+ index?: number;
395
+ tableName?: string;
396
+ } | null>;
397
+ getCountCallback?: () => Promise<number>;
398
+ insertCallback?: (data: T) => Promise<T>;
399
+ updateCallback?: (id: any, data: T) => Promise<T | void>;
400
+ removeCallback?: (id: any) => Promise<void>;
401
+ duplicateCallback?: (item: T) => Promise<T>;
402
+ refreshCallback?: (id: any) => Promise<T>;
403
+ onLoadDataSuccess?: (data: T) => void | Promise<void>;
404
+ onLoadDataFailure?: (error: any) => void;
405
+ onLoadDataComplete?: () => void;
406
+ onInsertSuccess?: (data: T) => void;
407
+ onInsertFailure?: (error: any) => void;
408
+ onInsertComplete?: () => void;
409
+ onUpdateSuccess?: (data: T) => void;
410
+ onUpdateFailure?: (error: any) => void;
411
+ onUpdateComplete?: () => void;
412
+ onDeleteSuccess?: () => void;
413
+ onDeleteFailure?: (error: any) => void;
414
+ onDeleteComplete?: () => void;
415
+ onDuplicateFailure?: (error: any) => void;
416
+ onDuplicateComplete?: () => void;
417
+ onSaveSuccess?: () => void;
418
+ onSaveFailure?: (error: any) => void;
419
+ onSaveCompleted?: () => void;
420
+ onCancelSuccess?: () => void;
421
+ onNew?: () => void;
422
+ onFormModeChanged?: (lastFormMode: FormModeEnum, newFormMode: FormModeEnum) => void;
423
+ onDataChanged?: (data: T) => void;
424
+ lookupParameterSource: string | number | null;
425
+ lookupParameters: string | null;
426
+ selectParametersCallback?: () => Record<string, any>;
427
+ onRefreshSuccess?: (fresh: any) => void | Promise<void>;
428
+ onRefreshFailure?: (error: any) => void;
429
+ allowSearch: boolean;
430
+ allowPrint: boolean;
431
+ allowDuplicate: boolean;
432
+ allowDelete: boolean;
433
+ allowUpdate: boolean;
434
+ allowInsert: boolean;
435
+ allowNavigate: boolean;
436
+ /** Host resolved a workflow or business rule that locks editing for this record. */
437
+ editingLocked: boolean;
438
+ /** Host resolved a workflow or business rule that locks deletion for this record. */
439
+ deleteLocked: boolean;
440
+ /** Set false to disable the Alt+key keyboard shortcuts on this navigator. */
441
+ shortcutsEnabled: boolean;
442
+ allowSubscribe: boolean;
443
+ onPrint: EventEmitter<void>;
444
+ lookupPopupComponent: LookupPopupComponent;
445
+ infoPopupComponent: InfoPopupComponent;
446
+ toolbarRef: ElementRef<HTMLElement>;
447
+ formGroup?: _angular_forms.FormGroup;
448
+ validateBeforeSave?: () => boolean | Promise<boolean>;
449
+ confirmBeforeSave?: () => Promise<boolean>;
450
+ codeFieldName: any;
451
+ idFieldName: any;
452
+ reportModels: ReportModelsDto[];
453
+ isSaving: boolean;
454
+ isDuplicating: boolean;
455
+ isLoading: boolean;
456
+ private cleanSnapshot;
457
+ count: number;
458
+ index: number;
459
+ code: string | null;
460
+ formMode: FormModeEnum;
461
+ isFormDirty: boolean;
462
+ isRefreshing: boolean;
463
+ suppressDirty: boolean;
464
+ isNavigating: boolean;
465
+ private navigationSequence;
466
+ isBtnFirstDisabled: boolean;
467
+ isBtnPreviousDisabled: boolean;
468
+ isBtnNextDisabled: boolean;
469
+ isBtnLastDisabled: boolean;
470
+ isBtnNewDisabled: boolean;
471
+ isBtnDeleteDisabled: boolean;
472
+ isBtnDuplicateDisabled: boolean;
473
+ isBtnInfoDisabled: boolean;
474
+ isBtnCancelDisabled: boolean;
475
+ isBtnPrintDisabled: boolean;
476
+ isBtnRefreshDisabled: boolean;
477
+ direction: 'rtl' | 'ltr';
478
+ icons: {
479
+ first: string;
480
+ prev: string;
481
+ next: string;
482
+ last: string;
483
+ };
484
+ private readonly shortcuts;
485
+ toolbarItems: ({
486
+ location: string;
487
+ template: string;
488
+ cssClass: string;
489
+ } | {
490
+ location: string;
491
+ template: string;
492
+ cssClass?: undefined;
493
+ })[];
494
+ protected readonly adapter: FormNavigatorAdapter;
495
+ protected readonly destroyRef: DestroyRef;
496
+ pagePermissions?: FormNavigatorPermissions;
497
+ readonly permissionsReady$: rxjs.Observable<FormNavigatorPermissions>;
498
+ constructor(cdr: ChangeDetectorRef, activatedRoute: ActivatedRoute, router: Router, location: Location);
499
+ get messages(): Readonly<FormNavigatorMessages>;
500
+ protected notifySuccess(message: string): void;
501
+ protected notifyError(message: string): void;
502
+ protected notifyInfo(message: string): void;
503
+ protected notifyWarning(message: string): void;
504
+ protected confirmDelete(): Promise<boolean>;
505
+ protected confirmDuplicate(): Promise<boolean>;
506
+ protected confirmUnsavedChanges(): Promise<boolean>;
507
+ private updateQueryParams;
508
+ get isEditMode(): boolean;
509
+ get currentRecordId(): string | undefined;
510
+ /** Auto-detect: show status-change subscription option only when the record has a status_id field.
511
+ * Case-insensitive so it catches status_id, status_Id, Status_Id, etc. */
512
+ get hasStatusField(): boolean;
513
+ get modeResolved(): boolean;
514
+ get canSave(): boolean;
515
+ get canDelete(): boolean;
516
+ ngOnInit(): Promise<void>;
517
+ ngAfterViewInit(): void;
518
+ ngOnDestroy(): void;
519
+ /**
520
+ * Setup observers to track sidebar toggle and window resize
521
+ */
522
+ private setupPositionTracking;
523
+ /**
524
+ * Cleanup observers on destroy
525
+ */
526
+ private cleanupPositionTracking;
527
+ /**
528
+ * Handle window resize
529
+ */
530
+ private onWindowResize;
531
+ /**
532
+ * Update the position of the form navigator based on content area
533
+ */
534
+ private updatePosition;
535
+ private loadInitialCount;
536
+ private setupDirection;
537
+ /**
538
+ * Setup observer to track direction (RTL/LTR) changes on body element
539
+ */
540
+ private setupDirectionObserver;
541
+ /**
542
+ * Cleanup direction observer
543
+ */
544
+ private cleanupDirectionObserver;
545
+ codeValueChanged: (e: any) => void;
546
+ private handleRouteParams;
547
+ navigateTo(index: number, code?: string | null): Promise<void>;
548
+ private loadByCode;
549
+ private loadByIndex;
550
+ first(): void;
551
+ prev(): void;
552
+ next(): void;
553
+ last(): void;
554
+ triggerNew(): Promise<void>;
555
+ triggerSave(): Promise<void>;
556
+ private handleInsert;
557
+ private handleUpdate;
558
+ triggerDelete(): Promise<void>;
559
+ triggerDuplicate(): Promise<void>;
560
+ triggerCancel(): void;
561
+ triggerRefresh(): Promise<void>;
562
+ private refreshCount;
563
+ hasRealUnsavedChanges(): boolean;
564
+ captureCleanSnapshot(): void;
565
+ private normalizeSnapshot;
566
+ private sortObject;
567
+ private waitForUiFrame;
568
+ private finishProgrammaticChange;
569
+ /**
570
+ * يشغّل عمليةً برمجية تُبدّل بيانات النموذج من المضيف (ترحيل / عكس / حفظ مخصّص من زر خاص…)
571
+ * بحيث لا تُوسم كتعديل مستخدم غير محفوظ. يطبّق نفس بركت التغيير البرمجي الذي يستخدمه
572
+ * المتصفّح داخليًا في التحميل و«جديد»: يكبت الـ dirty أثناء التبديل، ثم ينتظر إطار الواجهة
573
+ * ويعيد التقاط الحالة النظيفة — فتصير النتيجة المحفوظة هي خطَّ الأساس ولا يظهر تحذير
574
+ * «تغييرات غير محفوظة» عند المغادرة.
575
+ *
576
+ * حلٌّ عام: أي شاشة فيها عملية حفظ برمجية (ترحيل/عكس/…) تستدعيه بدل تكرار المعالجة في كل
577
+ * مكوّن على حدة.
578
+ */
579
+ runProgrammaticChange(mutate: () => void | Promise<void>): Promise<void>;
580
+ markFormDirty(): void;
581
+ updateButtonStates(): void;
582
+ updateUrl(clear?: boolean, code?: string | null): void;
583
+ private removeSearchParams;
584
+ triggerOpenPopup(): void;
585
+ handlePopupResult(result: any): Promise<void>;
586
+ private _lastLoadedTableName;
587
+ private stampTableName;
588
+ triggerInfo(): void;
589
+ triggerPrint(): void;
590
+ getShortcut(command: FormNavigatorCommand): string;
591
+ handleKeyboardEvent(event: KeyboardEvent): void;
592
+ canExecuteCommand(command: FormNavigatorCommand): boolean;
593
+ private resolveShortcutCommand;
594
+ private resolveEventCode;
595
+ private getDirectionalCommandForDisplay;
596
+ private formatShortcutCode;
597
+ private getLogicalDirection;
598
+ private runPreSaveValidation;
599
+ private focusFirstInvalidControl;
600
+ isPrintDisabled: boolean;
601
+ private computeIsPrintDisabled;
602
+ onPrintOptionClick(e: any): void;
603
+ static ɵfac: i0.ɵɵFactoryDeclaration<FormNavigatorComponent<any>, never>;
604
+ static ɵcmp: i0.ɵɵComponentDeclaration<FormNavigatorComponent<any>, "app-form-navigator", never, { "lookupID": { "alias": "lookupID"; "required": false; }; "currentObject": { "alias": "currentObject"; "required": false; }; "tableName": { "alias": "tableName"; "required": false; }; "getByIndexCallback": { "alias": "getByIndexCallback"; "required": false; }; "getByKeyCallback": { "alias": "getByKeyCallback"; "required": false; }; "getCountCallback": { "alias": "getCountCallback"; "required": false; }; "insertCallback": { "alias": "insertCallback"; "required": false; }; "updateCallback": { "alias": "updateCallback"; "required": false; }; "removeCallback": { "alias": "removeCallback"; "required": false; }; "duplicateCallback": { "alias": "duplicateCallback"; "required": false; }; "refreshCallback": { "alias": "refreshCallback"; "required": false; }; "onLoadDataSuccess": { "alias": "onLoadDataSuccess"; "required": false; }; "onLoadDataFailure": { "alias": "onLoadDataFailure"; "required": false; }; "onLoadDataComplete": { "alias": "onLoadDataComplete"; "required": false; }; "onInsertSuccess": { "alias": "onInsertSuccess"; "required": false; }; "onInsertFailure": { "alias": "onInsertFailure"; "required": false; }; "onInsertComplete": { "alias": "onInsertComplete"; "required": false; }; "onUpdateSuccess": { "alias": "onUpdateSuccess"; "required": false; }; "onUpdateFailure": { "alias": "onUpdateFailure"; "required": false; }; "onUpdateComplete": { "alias": "onUpdateComplete"; "required": false; }; "onDeleteSuccess": { "alias": "onDeleteSuccess"; "required": false; }; "onDeleteFailure": { "alias": "onDeleteFailure"; "required": false; }; "onDeleteComplete": { "alias": "onDeleteComplete"; "required": false; }; "onDuplicateFailure": { "alias": "onDuplicateFailure"; "required": false; }; "onDuplicateComplete": { "alias": "onDuplicateComplete"; "required": false; }; "onSaveSuccess": { "alias": "onSaveSuccess"; "required": false; }; "onSaveFailure": { "alias": "onSaveFailure"; "required": false; }; "onSaveCompleted": { "alias": "onSaveCompleted"; "required": false; }; "onCancelSuccess": { "alias": "onCancelSuccess"; "required": false; }; "onNew": { "alias": "onNew"; "required": false; }; "onFormModeChanged": { "alias": "onFormModeChanged"; "required": false; }; "onDataChanged": { "alias": "onDataChanged"; "required": false; }; "lookupParameterSource": { "alias": "lookupParameterSource"; "required": false; }; "lookupParameters": { "alias": "lookupParameters"; "required": false; }; "selectParametersCallback": { "alias": "selectParametersCallback"; "required": false; }; "onRefreshSuccess": { "alias": "onRefreshSuccess"; "required": false; }; "onRefreshFailure": { "alias": "onRefreshFailure"; "required": false; }; "allowSearch": { "alias": "allowSearch"; "required": false; }; "allowPrint": { "alias": "allowPrint"; "required": false; }; "allowDuplicate": { "alias": "allowDuplicate"; "required": false; }; "allowDelete": { "alias": "allowDelete"; "required": false; }; "allowUpdate": { "alias": "allowUpdate"; "required": false; }; "allowInsert": { "alias": "allowInsert"; "required": false; }; "allowNavigate": { "alias": "allowNavigate"; "required": false; }; "editingLocked": { "alias": "editingLocked"; "required": false; }; "deleteLocked": { "alias": "deleteLocked"; "required": false; }; "shortcutsEnabled": { "alias": "shortcutsEnabled"; "required": false; }; "allowSubscribe": { "alias": "allowSubscribe"; "required": false; }; "formGroup": { "alias": "formGroup"; "required": false; }; "validateBeforeSave": { "alias": "validateBeforeSave"; "required": false; }; "confirmBeforeSave": { "alias": "confirmBeforeSave"; "required": false; }; "codeFieldName": { "alias": "codeFieldName"; "required": false; }; "idFieldName": { "alias": "idFieldName"; "required": false; }; "reportModels": { "alias": "reportModels"; "required": false; }; "isLoading": { "alias": "isLoading"; "required": false; }; }, { "onPrint": "onPrint"; }, never, never, true, never>;
605
+ }
606
+
607
+ declare class EditFormButtonsComponent<T = any> implements OnInit {
608
+ private cdr;
609
+ private activatedRoute;
610
+ private router;
611
+ private route;
612
+ private readonly adapter;
613
+ constructor(cdr: ChangeDetectorRef, activatedRoute: ActivatedRoute, router: Router, route: ActivatedRoute);
614
+ get messages(): Readonly<_devhouse_int_angular_reusable_components.FormNavigatorMessages>;
615
+ private notifyError;
616
+ private notifyWarning;
617
+ toolbarItems: {
618
+ location: string;
619
+ template: string;
620
+ }[];
621
+ saveText: string;
622
+ closeText: string;
623
+ saveAndReturnText: string;
624
+ saveIcon: string;
625
+ closeIcon: string;
626
+ saveAndReturnIcon: string;
627
+ currentObject: T | null;
628
+ idFieldName: any;
629
+ getById?: (id: Guid) => Promise<{
630
+ item: T;
631
+ } | null>;
632
+ onNew?: () => void;
633
+ onDataChanged?: (data: T) => void;
634
+ onFormModeChanged?: (lastFormMode: FormModeEnum, newFormMode: FormModeEnum) => void;
635
+ onLoadDataSuccess?: (data: T) => void;
636
+ onLoadDataFailure?: (error: any) => void;
637
+ onLoadDataComplete?: () => void;
638
+ insertCallback?: (data: T) => Promise<T>;
639
+ onInsertSuccess?: (data: T) => void;
640
+ onInsertFailure?: (error: any) => void;
641
+ onInsertComplete?: () => void;
642
+ updateCallback?: (id: any, data: T) => Promise<T>;
643
+ onUpdateSuccess?: (data: T) => void;
644
+ onUpdateFailure?: (error: any) => void;
645
+ onUpdateComplete?: () => void;
646
+ onSaveSuccess?: () => void;
647
+ onSaveFailure?: (error: any) => void;
648
+ onSaveCompleted?: () => void;
649
+ /**
650
+ * Workflow allow_edit lock. While true both save buttons are disabled and runSave()
651
+ * refuses, so the user sees the lock before the round-trip.
652
+ */
653
+ editingLocked: boolean;
654
+ /** Runs after validation passed; resolving false cancels the save silently. */
655
+ confirmBeforeSave?: () => Promise<boolean>;
656
+ /**
657
+ * Pre-save validation gate (same contract as FormNavigator). Returns false when the
658
+ * form is invalid; the host shows its own inline field messages, so we just stop
659
+ * silently — no error toast. Runs BEFORE insert/update, so a validation failure never
660
+ * reaches the save path (and never produces the generic "Validation failed" rejection).
661
+ */
662
+ validateBeforeSave?: () => Promise<boolean>;
663
+ embedded: boolean;
664
+ embeddedMode: 'new' | 'edit';
665
+ embeddedId: string | null;
666
+ saved: EventEmitter<void>;
667
+ closed: EventEmitter<void>;
668
+ isSaving: boolean;
669
+ formMode: FormModeEnum;
670
+ id: any;
671
+ ngOnInit(): Promise<void>;
672
+ private applyFormMode;
673
+ /**
674
+ * Keeps the URL in step with the record in route mode (so a refresh reopens the same
675
+ * one). Embedded there is no URL of ours to keep in step, and writing `id`/`mode` onto
676
+ * the grid's URL would be wrong.
677
+ */
678
+ private syncQueryParams;
679
+ getObjectById(): Promise<void>;
680
+ triggerNew(): void;
681
+ triggerClose(): void;
682
+ /** Host contract: the popup's own close button routes through the normal close path. */
683
+ requestClose(): void;
684
+ /**
685
+ * Tells the tab that opened this one to refresh its grid. Embedded there is no opener —
686
+ * the host is listening to `saved` instead, in the same document.
687
+ */
688
+ private notifyOpenerSaved;
689
+ triggerSaveAndReturn(): Promise<void>;
690
+ triggerSave(): Promise<void>;
691
+ /**
692
+ * Pull the human-readable text out of whatever the save path rejected with: the
693
+ * ErrorInterceptor rethrows an `Error` carrying the backend message, but a plain string
694
+ * is possible too, so both shapes are handled before falling back.
695
+ */
696
+ private notifySaveError;
697
+ /**
698
+ * One save attempt, from the click until the load panel comes back down.
699
+ *
700
+ * 1. `panelRaised` is a LOCAL of this invocation, so every run releases exactly the raise
701
+ * it took (a shared field made overlapping runs leave the panel up forever).
702
+ * 2. `isSaving` is set BEFORE the first `await`, so a second click during an in-flight
703
+ * save is dropped instead of posting the same record twice.
704
+ */
705
+ private runSave;
706
+ /**
707
+ * Pre-save validation gate (mirrors FormNavigator). Failure is silent on purpose — the
708
+ * form already shows inline field messages, so no error toast is needed and the save path
709
+ * (insert/update) is never reached.
710
+ */
711
+ private passesPreSaveValidation;
712
+ private handleInsert;
713
+ private handleUpdate;
714
+ /** Currently unused (no caller in the app), kept working in both modes. */
715
+ setEditMode(id: string): void;
716
+ static ɵfac: i0.ɵɵFactoryDeclaration<EditFormButtonsComponent<any>, never>;
717
+ static ɵcmp: i0.ɵɵComponentDeclaration<EditFormButtonsComponent<any>, "app-edit-form-buttons", never, { "saveText": { "alias": "saveText"; "required": false; }; "closeText": { "alias": "closeText"; "required": false; }; "saveAndReturnText": { "alias": "saveAndReturnText"; "required": false; }; "saveIcon": { "alias": "saveIcon"; "required": false; }; "closeIcon": { "alias": "closeIcon"; "required": false; }; "saveAndReturnIcon": { "alias": "saveAndReturnIcon"; "required": false; }; "currentObject": { "alias": "currentObject"; "required": false; }; "idFieldName": { "alias": "idFieldName"; "required": false; }; "getById": { "alias": "getById"; "required": false; }; "onNew": { "alias": "onNew"; "required": false; }; "onDataChanged": { "alias": "onDataChanged"; "required": false; }; "onFormModeChanged": { "alias": "onFormModeChanged"; "required": false; }; "onLoadDataSuccess": { "alias": "onLoadDataSuccess"; "required": false; }; "onLoadDataFailure": { "alias": "onLoadDataFailure"; "required": false; }; "onLoadDataComplete": { "alias": "onLoadDataComplete"; "required": false; }; "insertCallback": { "alias": "insertCallback"; "required": false; }; "onInsertSuccess": { "alias": "onInsertSuccess"; "required": false; }; "onInsertFailure": { "alias": "onInsertFailure"; "required": false; }; "onInsertComplete": { "alias": "onInsertComplete"; "required": false; }; "updateCallback": { "alias": "updateCallback"; "required": false; }; "onUpdateSuccess": { "alias": "onUpdateSuccess"; "required": false; }; "onUpdateFailure": { "alias": "onUpdateFailure"; "required": false; }; "onUpdateComplete": { "alias": "onUpdateComplete"; "required": false; }; "onSaveSuccess": { "alias": "onSaveSuccess"; "required": false; }; "onSaveFailure": { "alias": "onSaveFailure"; "required": false; }; "onSaveCompleted": { "alias": "onSaveCompleted"; "required": false; }; "editingLocked": { "alias": "editingLocked"; "required": false; }; "confirmBeforeSave": { "alias": "confirmBeforeSave"; "required": false; }; "validateBeforeSave": { "alias": "validateBeforeSave"; "required": false; }; "embedded": { "alias": "embedded"; "required": false; }; "embeddedMode": { "alias": "embeddedMode"; "required": false; }; "embeddedId": { "alias": "embeddedId"; "required": false; }; }, { "saved": "saved"; "closed": "closed"; }, never, never, true, never>;
718
+ }
719
+ declare enum TriggerSaveModeEnum {
720
+ Save = 1,
721
+ SaveAndReturn = 2
722
+ }
723
+
724
+ /**
725
+ * Contract a *form screen* implements so it can be hosted inside a popup on top of the grid
726
+ * it belongs to, instead of being opened at its own `…/form` route in a second browser tab.
727
+ *
728
+ * Why a contract and not a base class: the form screens have nothing else in common — some
729
+ * are metadata-driven (DynamicForm/DynamicFormAccordion), some are hand-written
730
+ * (AddBranch, DashboardForm) — and they already extend different bases. All the host needs
731
+ * is to hand over three parameters and be told when the screen is finished.
732
+ *
733
+ * Anything that does NOT implement this stays on the old behaviour: DynamicGridComponent
734
+ * checks with `isEmbeddedFormHost()` before creating the component and falls back to
735
+ * `window.open` when the check fails, so an unconverted screen keeps working untouched.
736
+ */
737
+ interface EmbeddedFormHost {
738
+ /** True while hosted in a popup. Route mode must behave exactly as it did before. */
739
+ embedded: boolean;
740
+ embeddedMode: 'new' | 'edit';
741
+ embeddedId: string | null;
742
+ /**
743
+ * The `sys_job` id of the FORM (`…/form` has a job row of its own, separate from the
744
+ * grid's). Metadata-driven screens resolve their `dynamic_form` from it; screens that
745
+ * do not use it leave the property out.
746
+ */
747
+ embeddedJobId?: string | null;
748
+ /** Raised after every successful save, so the host can consider its list stale. */
749
+ saved?: EventEmitter<void>;
750
+ /** Raised when the screen is finished — the host closes the popup. */
751
+ closed: EventEmitter<void>;
752
+ /**
753
+ * The host calls this for the popup's own close button, so closing from outside goes
754
+ * through the screen's normal close path (including any unsaved-changes prompt it has)
755
+ * instead of pulling the component out from underneath it.
756
+ */
757
+ requestClose(): void | Promise<void>;
758
+ }
759
+ declare function isEmbeddedFormHost(value: unknown): value is EmbeddedFormHost;
760
+
761
+ /**
762
+ * Opt-in full-screen toggle for a hand-written edit popup:
763
+ *
764
+ * <dx-popup appPopupFullScreen [(visible)]="…" …>
765
+ *
766
+ * For the screens whose add/edit form is their own <dx-popup> (not the grid's popup edit
767
+ * form — that one is covered by AppPopupEditFullScreenDirective). Opt-in, not a
768
+ * `dx-popup` selector, on purpose: confirmation, lookup and attachment popups must not get it.
769
+ *
770
+ * - The button goes in the title bar, APPENDED to whatever toolbar items the popup already
771
+ * has (these screens keep Save/Cancel inside their content, so nothing is replaced).
772
+ * - Every opening starts at the normal size; drag/resize are off while full screen and are
773
+ * restored to the screen's own values afterwards.
774
+ */
775
+ declare class AppPopupFullScreenDirective implements OnInit {
776
+ private readonly popup;
777
+ private readonly config;
778
+ private readonly t;
779
+ private readonly toggle;
780
+ private instance;
781
+ private originalsCaptured;
782
+ private originalDrag?;
783
+ private originalResize?;
784
+ ngOnInit(): void;
785
+ private onShowing;
786
+ private apply;
787
+ static ɵfac: i0.ɵɵFactoryDeclaration<AppPopupFullScreenDirective, never>;
788
+ static ɵdir: i0.ɵɵDirectiveDeclaration<AppPopupFullScreenDirective, "dx-popup[appPopupFullScreen]", never, {}, {}, never, never, true, never>;
789
+ }
790
+
791
+ /**
792
+ * Full-screen toggle for the popup that hosts an embedded add/edit form (see
793
+ * EmbeddedFormHost). One class for every host so the button, its icon/hint and the
794
+ * reset-on-close rule cannot drift between screens.
795
+ *
796
+ * Template (inside the host's <dx-popup>):
797
+ * [fullScreen]="fullScreen.active"
798
+ * <dxi-popup-toolbar-item toolbar="top" location="after" widget="dxButton"
799
+ * [options]="fullScreen.buttonOptions"></dxi-popup-toolbar-item>
800
+ *
801
+ * `buttonOptions` is a STORED object, rebuilt only when the state flips: a new options
802
+ * reference on every change-detection pass makes DevExtreme re-create the button each time.
803
+ */
804
+ declare class PopupFullScreenToggle {
805
+ private readonly t;
806
+ private readonly onChange?;
807
+ active: boolean;
808
+ buttonOptions: Record<string, unknown>;
809
+ constructor(t: (key: string, fallback?: string) => string, onChange?: () => void);
810
+ set(value: boolean): void;
811
+ /** Call from the popup's onHidden so every opening starts at the normal size. */
812
+ reset(): void;
813
+ private build;
814
+ }
815
+
816
+ /** سطر تحليل متاح للإشارة إليه داخل المعادلة. */
817
+ interface EquationLine {
818
+ line_No: number;
819
+ label: string;
820
+ }
821
+ /** رمز واحد داخل المعادلة (مرجع سطر / عامل). */
822
+ type Token = {
823
+ kind: 'ref';
824
+ lineNo: number;
825
+ } | {
826
+ kind: 'op';
827
+ value: '+' | '-' | '*' | '/';
828
+ };
829
+ /**
830
+ * محرّر معادلات لسطور التحليل المالي (نوع السطر = FORMULA / SUBTOTAL).
831
+ *
832
+ * يبني المعادلة كقائمة رموز (Tokens) مرتبة بدل نص حر، فيمنع بنيوياً أي إدخال
833
+ * غير صالح. المخرَج مقيَّد **تماماً** بقواعد الـ backend
834
+ * (`FinancialAnalysisLineService.ValidFormulaPattern`):
835
+ * `^\s*-?\s*\[\d+\]\s*([+\-*\/]\s*\[\d+\]\s*)*$`
836
+ * أي: إشارة سالبة اختيارية في البداية، ثم مرجع سطر `[n]`، ثم صفر أو أكثر من
837
+ * (عامل `+ - * /` ثم مرجع `[n]`). **لا أقواس ولا أرقام ثابتة** — المُعامَلات
838
+ * دائماً مراجع سطور، وإلا رفض الـ backend المعادلة.
839
+ */
840
+ declare class EquationEditorComponent implements OnChanges {
841
+ /** Optional host translation function; falls back to the supplied text. */
842
+ translate: (key: string, fallback: string) => string;
843
+ protected t(key: string, fallback: string): string;
844
+ /** السطور المتاحة للإشارة إليها (تُمرَّر محدَّثة عند كل فتح). */
845
+ lines: EquationLine[];
846
+ /** رقم السطر الحالي — يُستبعد من قائمة الاختيار لمنع الإشارة الذاتية. */
847
+ currentLineNo: number | null;
848
+ /** المعادلة الحالية (لوضع التعديل). */
849
+ value: string | null;
850
+ /** إظهار الضرب/القسمة (× ÷) بجانب الجمع/الطرح. */
851
+ allowMultiplyDivide: boolean;
852
+ /** إظهار/إخفاء البوب أب. */
853
+ visible: boolean;
854
+ /** يُطلق عند الحفظ حاملاً نص المعادلة `[1]+[2]`. */
855
+ save: EventEmitter<string>;
856
+ /** يُطلق عند الإلغاء/الإغلاق. */
857
+ closed: EventEmitter<void>;
858
+ lineList?: DxListComponent;
859
+ tokens: Token[];
860
+ /**
861
+ * Keep the dxList data source reference stable between change-detection passes.
862
+ * Returning `lines.filter(...)` from a template-bound getter makes DevExtreme
863
+ * replace/re-render its items while a pointer interaction is in progress,
864
+ * which can prevent `onItemClick` from being raised.
865
+ */
866
+ pickableLines: EquationLine[];
867
+ /** بعد ظهور البوب أب فعلاً: أعِد رسم القائمة لتصحيح أبعاد التمرير/النقر
868
+ * (القائمة تُنشأ أحياناً قبل قياس البوب أب فيتعطّل التمرير والاختيار). */
869
+ onPopupShown(): void;
870
+ ngOnChanges(changes: SimpleChanges): void;
871
+ private get lastKind();
872
+ /** يُسمح بمُعامَل (مرجع سطر) بعد: البداية أو عامل. */
873
+ get allowsOperand(): boolean;
874
+ /** يُسمح بعامل بعد: مرجع سطر. الاستثناء: سالب واحد في البداية فقط. */
875
+ get allowsOperator(): boolean;
876
+ /** هل يُسمح بهذا العامل تحديداً الآن؟ (يشمل السالب الأوّلي). */
877
+ canAddOp(value: '+' | '-' | '*' | '/'): boolean;
878
+ addRef(lineNo: number): void;
879
+ addOp(value: '+' | '-' | '*' | '/'): void;
880
+ backspace(): void;
881
+ clearAll(): void;
882
+ /** نص الرمز كما يظهر في شريط المعادلة. */
883
+ tokenChip(t: Token): string;
884
+ opSymbol(v: string): string;
885
+ /** معاينة مقروءة (بأسماء السطور بدل `[n]`). */
886
+ get preview(): string;
887
+ get hasReference(): boolean;
888
+ /** صحيحة عندما: بها مرجع واحد على الأقل وتنتهي بمرجع (لا عامل معلّق). */
889
+ get isValid(): boolean;
890
+ get validationMessage(): string;
891
+ private serialize;
892
+ private parse;
893
+ onSave(): void;
894
+ onCancel(): void;
895
+ onPopupHiding(): void;
896
+ static ɵfac: i0.ɵɵFactoryDeclaration<EquationEditorComponent, never>;
897
+ static ɵcmp: i0.ɵɵComponentDeclaration<EquationEditorComponent, "app-equation-editor", never, { "translate": { "alias": "translate"; "required": false; }; "lines": { "alias": "lines"; "required": false; }; "currentLineNo": { "alias": "currentLineNo"; "required": false; }; "value": { "alias": "value"; "required": false; }; "allowMultiplyDivide": { "alias": "allowMultiplyDivide"; "required": false; }; "visible": { "alias": "visible"; "required": false; }; }, { "save": "save"; "closed": "closed"; }, never, never, true, never>;
898
+ }
899
+
900
+ declare class FileEditComponent implements ControlValueAccessor {
901
+ private http;
902
+ private readonly libraryConfig;
903
+ fileName: string | null;
904
+ uploading: boolean;
905
+ importing: boolean;
906
+ /** Host translation hook (REUSABLE_COMPONENTS_CONFIG.translate); falls back to the supplied text. */
907
+ private t;
908
+ errorMessage: string | null;
909
+ successMessage: string | null;
910
+ /** القراءة فقط — تمنع أي تفاعل (رفع/مسح/تنزيل) */
911
+ readOnly: boolean;
912
+ /** قائمة الامتدادات المسموحة للاختيار في نافذة الملفات (المرشح الحقيقي على الخادم) */
913
+ accept: string;
914
+ /** الحد الأقصى لحجم الملف بالبايت (اختياري) */
915
+ maxFileSizeBytes?: number;
916
+ /** معرف السجل الحالي (formData.id) — null يعني سجل جديد غير محفوظ بعد */
917
+ recordId: string | null;
918
+ /** المسار الأساسي للكيان في الـ API، مثل 'bank-statement' (بدون /@id) */
919
+ apiEntityPath: string;
920
+ /** Optional per-instance override; otherwise uses REUSABLE_COMPONENTS_CONFIG. */
921
+ apiBaseUrl: string;
922
+ Changed: EventEmitter<void>;
923
+ Upload: EventEmitter<void>;
924
+ Clear: EventEmitter<void>;
925
+ Imported: EventEmitter<number>;
926
+ /**
927
+ * اسم حقل شقيق يملؤه الخادم في رده على الرفع (من `lookup_parameters`).
928
+ * لو رد الرفع احتوى مفتاحًا بنفس الاسم، تُبَثّ قيمته ليكتبها النموذج في الحقل.
929
+ * مثال: مصدر الاستيراد الذي يشتقه الخادم من الملف نفسه.
930
+ *
931
+ * ويعمل كذلك كبوابة لزر «استيراد الأسطر»: وجود حقل مصدر استيراد هو بعينه معنى
932
+ * «هذا الملف هو ما نقرأه». الشاشات التي ترفع الملف كمستند إثبات فقط — مثل مرفق
933
+ * كشف الحساب في التسوية البنكية — لا تُعرّفه، فيختفي الزر بدل أن يَعِد بقراءة
934
+ * ملف لا يُقرأ أصلًا (الأسطر هناك تأتي من كشف الحساب المرتبط).
935
+ */
936
+ syncFieldName: string | null;
937
+ contextFieldNames: string[];
938
+ contextValues: Record<string, any> | null;
939
+ /** القيمة التي أعادها الخادم للحقل الشقيق بعد رفع ناجح */
940
+ SyncFieldValue: EventEmitter<any>;
941
+ private onChange;
942
+ private onTouched;
943
+ constructor(http: HttpClient, libraryConfig: ReusableComponentsConfig | null);
944
+ get canInteract(): boolean;
945
+ get canUpload(): boolean;
946
+ private get apiUrl();
947
+ private get importResourceUrl();
948
+ private get importFileUrl();
949
+ private get importFileAndLinesUrl();
950
+ private get importLinesUrl();
951
+ writeValue(value: string | null): void;
952
+ registerOnChange(fn: any): void;
953
+ registerOnTouched(fn: any): void;
954
+ setDisabledState?(isDisabled: boolean): void;
955
+ onFileSelected(event: Event): Promise<void>;
956
+ downloadFile(): Promise<void>;
957
+ importLines(): Promise<void>;
958
+ private contextEntries;
959
+ private contextBody;
960
+ clearFile(): Promise<void>;
961
+ static ɵfac: i0.ɵɵFactoryDeclaration<FileEditComponent, [null, { optional: true; }]>;
962
+ static ɵcmp: i0.ɵɵComponentDeclaration<FileEditComponent, "app-file-edit", never, { "readOnly": { "alias": "readOnly"; "required": false; }; "accept": { "alias": "accept"; "required": false; }; "maxFileSizeBytes": { "alias": "maxFileSizeBytes"; "required": false; }; "recordId": { "alias": "recordId"; "required": false; }; "apiEntityPath": { "alias": "apiEntityPath"; "required": false; }; "apiBaseUrl": { "alias": "apiBaseUrl"; "required": false; }; "syncFieldName": { "alias": "syncFieldName"; "required": false; }; "contextFieldNames": { "alias": "contextFieldNames"; "required": false; }; "contextValues": { "alias": "contextValues"; "required": false; }; }, { "Changed": "Changed"; "Upload": "Upload"; "Clear": "Clear"; "Imported": "Imported"; "SyncFieldValue": "SyncFieldValue"; }, never, never, true, never>;
963
+ }
964
+
965
+ /**
966
+ * Host-supplied backend for the file manager component (attachments per
967
+ * entity: folders, files, links, tags). The host adapter typically wraps its
968
+ * file-manager API service, its attachment-tags lookup, and its tenant
969
+ * identity headers.
970
+ */
971
+ interface FileManagerProvider {
972
+ /**
973
+ * Endpoint URL for DevExtreme's `RemoteFileSystemProvider`
974
+ * (the file-system command endpoint scoped to source + entity).
975
+ */
976
+ getFileSystemEndpoint(attachmentSourceId: any, entityKey: string): string;
977
+ /**
978
+ * Extra headers for the RemoteFileSystemProvider's own AJAX transport. This
979
+ * method is called before each request, so hosts can supply a refreshed bearer
980
+ * token together with tenant identity headers.
981
+ * It bypasses Angular's HttpClient interceptors, so identity headers
982
+ * (e.g. X-Tenant-Domain) must be supplied here explicitly.
983
+ */
984
+ fileSystemRequestHeaders(): Record<string, string>;
985
+ /**
986
+ * DataSource/CustomStore for the attachment-tags tag box ({ id, name_Ar }).
987
+ * May return the store directly or a promise of it (the component awaits it).
988
+ */
989
+ createTagsStore(): any;
990
+ addURL(data: {
991
+ name: string;
992
+ attachmentTypeId: any;
993
+ attachmentSourceID: any;
994
+ entityKey: any;
995
+ url: string;
996
+ issueDate?: Date | null;
997
+ expireDate?: Date | null;
998
+ attachmentCode?: string | null;
999
+ tags?: string[];
1000
+ }): Observable<unknown>;
1001
+ uploadManual(formData: FormData, attachmentSourceId: any, entityKey: string, issueDate?: string | null, expireDate?: string | null, attachmentCode?: string | null, tags?: string[], currentDirectoryKey?: string, currentDirectoryName?: string, fileName?: string, fileSize?: number): Observable<any>;
1002
+ updateFileMetadataWithFile(key: string, name: string, attachmentSourceId: any, entityKey: string, newFile?: File, url?: string | null, issueDate?: string | null, expireDate?: string | null, attachmentCode?: string | null, tags?: string[], isLink?: boolean): Observable<any>;
1003
+ /**
1004
+ * Optional: called when an upload or delete may have changed the used storage (or the
1005
+ * quota was hit), so the host can refresh a storage banner/meter.
1006
+ */
1007
+ onStorageChanged?(): void;
1008
+ downloadFile(fileId: string): Observable<Blob>;
1009
+ getAttachmentTags(attachmentId: string): Observable<any[]>;
1010
+ setAttachmentTagsById(attachmentId: string, tags: string[]): Observable<unknown>;
1011
+ }
1012
+ declare const FILE_MANAGER_PROVIDER: InjectionToken<FileManagerProvider>;
1013
+
1014
+ type FMItem = {
1015
+ name?: string;
1016
+ isDirectory?: boolean;
1017
+ key?: string;
1018
+ dataItem?: any;
1019
+ };
1020
+ declare class FileManagerComponent implements OnChanges, OnInit {
1021
+ private fileProvider;
1022
+ private ngZone;
1023
+ private cdr;
1024
+ attachmentSourceId: Guid;
1025
+ entityKey: Guid | undefined | string;
1026
+ IsEnabled: boolean;
1027
+ AllowAdd: boolean;
1028
+ AllowModify: boolean;
1029
+ AllowDelete: boolean;
1030
+ fileManager: DxFileManagerComponent;
1031
+ fileInput: ElementRef<HTMLInputElement>;
1032
+ private readonly adapter;
1033
+ protected readonly t: (key: string, fallback: string) => string;
1034
+ /** Bilingual lookup rows: show the UI language, falling back to the other one. */
1035
+ private pickLocalized;
1036
+ /** name_Ar / name_En by the active language (was hard-wired to name_Ar). */
1037
+ readonly localizedNameExpr: (item: any) => string;
1038
+ readonly nameExpr: (item: any) => string;
1039
+ /** A function displayExpr gives the DataSource no field to search: name the UI-language column. */
1040
+ get nameSearchExpr(): string;
1041
+ /** Tell the host that used storage may have changed (upload / delete / quota hit). */
1042
+ notifyStorageChanged(): void;
1043
+ linkForm: {
1044
+ linkName: string;
1045
+ linkUrl: string;
1046
+ attachmentCode: string;
1047
+ linkIssueDate: Date | null;
1048
+ linkExpireDate: Date | null;
1049
+ };
1050
+ fileForm: {
1051
+ attachmentCode: string;
1052
+ selectedTags: string[];
1053
+ fileIssueDate: Date | null;
1054
+ fileExpireDate: Date | null;
1055
+ };
1056
+ isDirectory: boolean;
1057
+ isInDirectory: boolean;
1058
+ isSingleItemSelected: boolean;
1059
+ isDownloadDisabled: boolean;
1060
+ linkpopupVisible: boolean;
1061
+ filepopupVisible: boolean;
1062
+ selectedFile: File | null;
1063
+ formatter: any;
1064
+ manualSelectedFile: File | null;
1065
+ attachmentCode: string | null;
1066
+ dsAttachmentTags: any;
1067
+ selectedTags: any[];
1068
+ focusedItemTags: any[];
1069
+ remoteProvider: RemoteFileSystemProvider;
1070
+ imageItemToDisplay: DxFileManagerTypes.SelectedFileOpenedEvent["file"];
1071
+ showTagBox: boolean;
1072
+ focusedItem: FMItem | null;
1073
+ savingTags: boolean;
1074
+ constructor(fileProvider: FileManagerProvider, ngZone: NgZone, cdr: ChangeDetectorRef);
1075
+ editMode: boolean;
1076
+ editModel: {
1077
+ key?: string;
1078
+ id?: string;
1079
+ name?: string | null;
1080
+ url?: string | null;
1081
+ attachmentCode?: string | null;
1082
+ tags?: string[];
1083
+ issueDate?: Date | null;
1084
+ expireDate?: Date | null;
1085
+ isLink?: boolean;
1086
+ };
1087
+ ngOnChanges(changes: SimpleChanges): void;
1088
+ ngOnInit(): Promise<void>;
1089
+ private loadAllTags;
1090
+ private loadTagForSelected;
1091
+ private initRemoteProvider;
1092
+ openSelectedItem(e: any): void;
1093
+ normalizeUrl(url: string | null | undefined): string;
1094
+ private openLinkPopup;
1095
+ private openFilePopup;
1096
+ private resetEditModel;
1097
+ showInfo(): void;
1098
+ showFileInfo(): void;
1099
+ newFileMenuOptions: {
1100
+ items: {
1101
+ id: string;
1102
+ text: string;
1103
+ icon: string;
1104
+ }[];
1105
+ onItemClick: (e: any) => void;
1106
+ };
1107
+ isReplacingFile: boolean;
1108
+ replacementFile: File | null;
1109
+ onFileSelected(event: any): void;
1110
+ triggerUpload(): void;
1111
+ addLink(): void;
1112
+ uploadManualFile(): void;
1113
+ /**
1114
+ * Turns DevExtreme's FileSystemErrorCode into a sentence the user can act on.
1115
+ *
1116
+ * The server cannot localize these itself: this path returns through the file-manager command
1117
+ * result, never through the API exception middleware, so `errorText` carries only the raw
1118
+ * values (pipe-separated) and the wording belongs here.
1119
+ */
1120
+ private describeUploadError;
1121
+ /** Replaces {0}, {1}… with the given values (the same placeholders the server message uses). */
1122
+ private fmt;
1123
+ private resetFileInput;
1124
+ resetFileForm(): void;
1125
+ onContextMenuShowing(e: any): void;
1126
+ onSelectionChanged(e: any): void;
1127
+ onCurrentDirectoryChanged(e: any): void;
1128
+ displayImagePopup(e: any): void;
1129
+ openUrl(url: string): void;
1130
+ truncateUrl(url: string): string;
1131
+ download(id: string, fileName: string): void;
1132
+ formatDateOnly(value: any): string;
1133
+ editRow(rowData: any): void;
1134
+ private parseDate;
1135
+ saveEdit(): Promise<void>;
1136
+ closeEdit(): void;
1137
+ editSelected: () => void;
1138
+ onCustomTagCreating(e: any): void;
1139
+ onFocusedItemChanged(e: DxFileManagerTypes.FocusedItemChangedEvent): Promise<void>;
1140
+ hideTagBox(): void;
1141
+ onTagsChanged(e: any): void;
1142
+ saveFocusedItemTags(): Promise<void>;
1143
+ cancelTagChanges(): void;
1144
+ hideParentDirRow(): void;
1145
+ static ɵfac: i0.ɵɵFactoryDeclaration<FileManagerComponent, never>;
1146
+ static ɵcmp: i0.ɵɵComponentDeclaration<FileManagerComponent, "app-file-manager", never, { "attachmentSourceId": { "alias": "attachmentSourceId"; "required": false; }; "entityKey": { "alias": "entityKey"; "required": false; }; "IsEnabled": { "alias": "IsEnabled"; "required": false; }; "AllowAdd": { "alias": "AllowAdd"; "required": false; }; "AllowModify": { "alias": "AllowModify"; "required": false; }; "AllowDelete": { "alias": "AllowDelete"; "required": false; }; }, {}, never, never, true, never>;
1147
+ }
1148
+
1149
+ declare class DxFormItemsOutletDirective implements OnChanges {
1150
+ private readonly viewContainerRef;
1151
+ template: TemplateRef<unknown> | null;
1152
+ constructor(viewContainerRef: ViewContainerRef);
1153
+ ngOnChanges(_changes: SimpleChanges): void;
1154
+ static ɵfac: i0.ɵɵFactoryDeclaration<DxFormItemsOutletDirective, never>;
1155
+ static ɵdir: i0.ɵɵDirectiveDeclaration<DxFormItemsOutletDirective, "[appDxFormItemsOutlet]", never, { "template": { "alias": "appDxFormItemsOutlet"; "required": false; }; }, {}, never, never, true, never>;
1156
+ }
1157
+
1158
+ /**
1159
+ * Shared «من / إلى» (From / To) range validation.
1160
+ *
1161
+ * One rule, one message, one way of drawing the error — used by the dynamic query
1162
+ * screens (dynamic-query / -tab / -accordion) and by the shared filter panel that the
1163
+ * dynamic grid's search filters render into. Every caller used to carry its own copy of
1164
+ * «compare the two ends», and the copies had drifted: numbers and dates only, text ranges
1165
+ * skipped, time ranges compared as full timestamps, a toast instead of an inline error.
1166
+ *
1167
+ * The rule: when BOTH ends have a value and «إلى» is before «من», both editors are marked
1168
+ * invalid with the same message. An empty end means an open range — never an error.
1169
+ */
1170
+ type RangeKind = 'number' | 'date' | 'datetime' | 'time' | 'text';
1171
+
1172
+ /**
1173
+ * Marks a filter item as one end of a «من / إلى» pair. Put it on the item's `editorOptions`
1174
+ * (both ends share the same `key`); the panel then validates the pair on every change and
1175
+ * blocks «عرض» while «إلى» is before «من» — with the error drawn under both editors.
1176
+ */
1177
+ interface FilterRangePair {
1178
+ key: string;
1179
+ role: 'from' | 'to';
1180
+ kind: RangeKind;
1181
+ /** Caption of the range, prefixed to the message («تاريخ الإصدار: …»). */
1182
+ caption?: string | null;
1183
+ }
1184
+ /** One applied filter as shown in the count badge and the collapsed-state chips. */
1185
+ interface AppliedFilter {
1186
+ key: string;
1187
+ label: string;
1188
+ /** Empty when the value is an id (GUID) or a boolean — the label alone is shown. */
1189
+ display: string;
1190
+ }
1191
+ declare class FilterPanelComponent implements OnChanges {
1192
+ title: string;
1193
+ validationGroup?: string;
1194
+ headerIcon: string;
1195
+ applyButtonDisabled: boolean;
1196
+ applyButtonText: string;
1197
+ applyButtonIcon: string;
1198
+ /**
1199
+ * يُظهر «مسح الفلاتر» بعد أول «عرض» حتى لو لم يُملأ أي فلتر (سلوك شاشة قيود اليومية).
1200
+ * الافتراضي false: الزرّ يظهر فقط حين يكون هناك فلتر مُطبَّق بقيمة، كما كان.
1201
+ */
1202
+ showClearAfterApply: boolean;
1203
+ /** رُفع بعد أول «عرض». */
1204
+ hasApplied: boolean;
1205
+ clearButtonText: string;
1206
+ removeFilterText: string;
1207
+ /** Localized «إلى must not be before من» message; defaults to the shared Arabic text. */
1208
+ rangeMessage: string;
1209
+ /**
1210
+ * Snapshot of the filters that were in effect when «عرض» was last pressed. It is
1211
+ * read from `formData` AT APPLY TIME — editing a field without pressing apply does
1212
+ * not change the count or the chips (same decision as the posting-rules filter bar).
1213
+ */
1214
+ appliedFilters: AppliedFilter[];
1215
+ private formInstance;
1216
+ /** Editor instances by dataField (only the editors that can be a range end register). */
1217
+ private readonly editors;
1218
+ formData: Record<string, unknown>;
1219
+ items: any[];
1220
+ colCountDesktop: number;
1221
+ colCountMobile: number;
1222
+ labelLocationDesktop: 'left' | 'right' | 'top';
1223
+ labelLocationMobile: 'left' | 'right' | 'top';
1224
+ showColonAfterLabel: boolean;
1225
+ mobileBreakpoint: number;
1226
+ forceMobile: boolean | null;
1227
+ collapsed: boolean | null;
1228
+ autoCollapseByRequired: boolean;
1229
+ onApplyFilter: EventEmitter<void>;
1230
+ onFieldDataChanged: EventEmitter<any>;
1231
+ formInitialized: EventEmitter<any>;
1232
+ isMobile: boolean;
1233
+ private initialCollapsedApplied;
1234
+ /**
1235
+ * What dx-form actually renders. Equals `items` (same reference) unless an item carries
1236
+ * `startNewRow: true`; then empty items fill the rest of the current row so it starts a
1237
+ * new one. dxForm has no "new row" option and silently DROPS a colSpan that overflows
1238
+ * the row (form.layout_manager `_prepareItemsWithMerging`), so padding is the only way.
1239
+ * Done here, not by the host, because only the panel knows the colCount in effect
1240
+ * (desktop vs mobile). Kept as a field, never a getter: a fresh array on every change
1241
+ * detection would make dx-form rebuild its editors.
1242
+ */
1243
+ layoutItems: any[];
1244
+ get colCount(): number;
1245
+ ngOnChanges(changes: SimpleChanges): void;
1246
+ private refreshLayoutItems;
1247
+ /** Top-level items only; hidden items take no cell so they don't count toward the row. */
1248
+ private padRowBreaks;
1249
+ constructor();
1250
+ ngOnDestroy(): void;
1251
+ ngAfterContentInit(): void;
1252
+ private onResize;
1253
+ private syncIsMobile;
1254
+ private applyInitialCollapsedFromItems;
1255
+ private hasRequiredInItems;
1256
+ toggleCollapse(): void;
1257
+ onApplyClick(e?: any): void;
1258
+ /** Clears every field, then applies immediately so the grid reflects the reset. */
1259
+ onClearClick(e?: any): void;
1260
+ /** Removes ONE applied filter (chip ×) and re-applies. */
1261
+ removeAppliedFilter(f: AppliedFilter): void;
1262
+ private clearField;
1263
+ private snapshotAppliedFilters;
1264
+ private hasValue;
1265
+ /** Label = the form item's caption for that dataField; falls back to the key. */
1266
+ private labelFor;
1267
+ private findItem;
1268
+ /** Human text for the chip; ids (GUIDs) are not shown — the label alone is the message. */
1269
+ private displayFor;
1270
+ onToggleClick(e?: MouseEvent): void;
1271
+ onFormFieldDataChanged(e: any): void;
1272
+ /** Called from the editor templates so a range end can be marked without focus. */
1273
+ registerEditor(dataField: string, instance: any): void;
1274
+ /**
1275
+ * Validates every tagged From/To pair and draws the result on both ends.
1276
+ * Returns false (and «عرض» does nothing) while any pair is reversed.
1277
+ */
1278
+ validateRangePairs(): boolean;
1279
+ private validateRangeOf;
1280
+ private validatePairOf;
1281
+ /** Template editors register themselves; native `editorType` editors come from the form. */
1282
+ private editorOf;
1283
+ /**
1284
+ * Every From/To pair in the panel:
1285
+ * 1. items tagged explicitly with `editorOptions.rangePair` (the dynamic grid does this);
1286
+ * 2. otherwise detected by NAME + EDITOR — a text/number/date item whose dataField has a
1287
+ * `from` word and whose `to` partner (see rangePartnerFieldName) is an item of the same
1288
+ * editor kind. That is what makes every static screen using the panel validated with no
1289
+ * per-screen code: `dateFrom`/`dateTo`, `fromDate`/`toDate`, `journal_Date_From`/`_To`…
1290
+ * Lookups/select boxes never pair (من صندوق / إلى صندوق is not a range).
1291
+ */
1292
+ private rangeItems;
1293
+ private editorKindOf;
1294
+ onFormInitialized(e: any): void;
1295
+ static ɵfac: i0.ɵɵFactoryDeclaration<FilterPanelComponent, never>;
1296
+ static ɵcmp: i0.ɵɵComponentDeclaration<FilterPanelComponent, "app-filter-panel", never, { "title": { "alias": "title"; "required": false; }; "validationGroup": { "alias": "validationGroup"; "required": false; }; "applyButtonDisabled": { "alias": "applyButtonDisabled"; "required": false; }; "applyButtonText": { "alias": "applyButtonText"; "required": false; }; "applyButtonIcon": { "alias": "applyButtonIcon"; "required": false; }; "showClearAfterApply": { "alias": "showClearAfterApply"; "required": false; }; "clearButtonText": { "alias": "clearButtonText"; "required": false; }; "removeFilterText": { "alias": "removeFilterText"; "required": false; }; "rangeMessage": { "alias": "rangeMessage"; "required": false; }; "formData": { "alias": "formData"; "required": false; }; "items": { "alias": "items"; "required": false; }; "colCountDesktop": { "alias": "colCountDesktop"; "required": false; }; "colCountMobile": { "alias": "colCountMobile"; "required": false; }; "labelLocationDesktop": { "alias": "labelLocationDesktop"; "required": false; }; "labelLocationMobile": { "alias": "labelLocationMobile"; "required": false; }; "showColonAfterLabel": { "alias": "showColonAfterLabel"; "required": false; }; "mobileBreakpoint": { "alias": "mobileBreakpoint"; "required": false; }; "forceMobile": { "alias": "forceMobile"; "required": false; }; "collapsed": { "alias": "collapsed"; "required": false; }; "autoCollapseByRequired": { "alias": "autoCollapseByRequired"; "required": false; }; }, { "onApplyFilter": "onApplyFilter"; "onFieldDataChanged": "onFieldDataChanged"; "formInitialized": "formInitialized"; }, never, ["*"], true, never>;
1297
+ }
1298
+
1299
+ interface FinancialDimensionValuesProvider {
1300
+ dimensionLookupId: any;
1301
+ dimensionValueLookupId: any;
1302
+ fieldDataParameterSource: string | number;
1303
+ loadValues(options: any): Observable<any>;
1304
+ loadDimensions(options: any): Observable<any>;
1305
+ }
1306
+ declare const FINANCIAL_DIMENSION_VALUES_PROVIDER: InjectionToken<FinancialDimensionValuesProvider>;
1307
+
1308
+ interface FinancialDimensionValueRow {
1309
+ dimensionId: string;
1310
+ dimensionName: string;
1311
+ dimensionNameEn?: string;
1312
+ dimensionValueId: string;
1313
+ dimensionValueName: string;
1314
+ dimensionValueNameEn?: string;
1315
+ }
1316
+ declare class FinancialDimensionValuesComponent implements OnInit {
1317
+ private cdr;
1318
+ private sysLookupService;
1319
+ private provider;
1320
+ private readonly navigatorAdapter;
1321
+ private readonly config;
1322
+ private get useArabic();
1323
+ readonly nameExpr: (item: any) => string;
1324
+ get nameSearchExpr(): string;
1325
+ /** Emits comma-separated value IDs whenever rows change. */
1326
+ value: string | null | undefined;
1327
+ valueChange: EventEmitter<any>;
1328
+ valueType: LookupValueType | number;
1329
+ caption: string;
1330
+ text: string | null | undefined;
1331
+ name: string;
1332
+ fieldName: string;
1333
+ gridId?: string;
1334
+ dsFinancialDimensions: DataSource | null;
1335
+ dsFinancialDimensionValues: DataSource | null;
1336
+ rows: FinancialDimensionValueRow[];
1337
+ selectedDimensionId: string | null;
1338
+ selectedValueId: string | null;
1339
+ selectedDimensionItem: any;
1340
+ selectedValueItem: any;
1341
+ constructor(cdr: ChangeDetectorRef, sysLookupService: LookupGridProvider, provider: FinancialDimensionValuesProvider);
1342
+ ngOnInit(): Promise<void>;
1343
+ onDimensionChange(dimensionId: string | null): void;
1344
+ onDimensionSelectionChanged(e: any): void;
1345
+ onValueSelectionChanged(e: any): void;
1346
+ get canAdd(): boolean;
1347
+ onAdd(): void;
1348
+ onDelete(row: FinancialDimensionValueRow): Promise<void>;
1349
+ private resetSelection;
1350
+ private emitChange;
1351
+ getReportDisplayText(culture: string): string;
1352
+ /**
1353
+ * Drops every chosen pair. Needed because the control's state lives in `rows`, so the generic
1354
+ * "control.value = null" reset used for plain editors would leave the grid populated while
1355
+ * reporting an empty condition.
1356
+ */
1357
+ clear(): void;
1358
+ setSelectedValueIds(joinedValueIds: string | null | undefined): Promise<void>;
1359
+ /** DevExtreme filter expression matching any of the given ids. */
1360
+ private buildIdFilter;
1361
+ static ɵfac: i0.ɵɵFactoryDeclaration<FinancialDimensionValuesComponent, never>;
1362
+ static ɵcmp: i0.ɵɵComponentDeclaration<FinancialDimensionValuesComponent, "app-financial-dimension-values", never, { "value": { "alias": "value"; "required": false; }; "valueType": { "alias": "valueType"; "required": false; }; "caption": { "alias": "caption"; "required": false; }; "text": { "alias": "text"; "required": false; }; "name": { "alias": "name"; "required": false; }; "fieldName": { "alias": "fieldName"; "required": false; }; "gridId": { "alias": "gridId"; "required": false; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
1363
+ }
1364
+
1365
+ interface FinancialDimensionValueVm {
1366
+ id: string;
1367
+ code: string;
1368
+ name_Ar: string;
1369
+ name_En?: string;
1370
+ }
1371
+ interface FinancialDimensionVm {
1372
+ id: string;
1373
+ code: string;
1374
+ name_Ar: string;
1375
+ name_En?: string;
1376
+ position?: number;
1377
+ is_Required?: boolean;
1378
+ values: FinancialDimensionValueVm[];
1379
+ }
1380
+ type DimensionSelectionsMap = Record<string, string | null>;
1381
+ interface FinancialDimensionsProvider {
1382
+ getDimensionsByAccount(accountId: string, combinationId?: string | null): Promise<FinancialDimensionVm[]>;
1383
+ getAllDimensions(): Promise<FinancialDimensionVm[]>;
1384
+ getCombinationSelections(dimensions: FinancialDimensionVm[], combinationId: string): Promise<DimensionSelectionsMap>;
1385
+ buildPayload(dimensions: FinancialDimensionVm[], selections: DimensionSelectionsMap, accountId: string): any;
1386
+ createOrGetCombination(payload: any): Promise<{
1387
+ id: string;
1388
+ display_Value: string;
1389
+ }>;
1390
+ }
1391
+ declare const FINANCIAL_DIMENSIONS_PROVIDER: InjectionToken<FinancialDimensionsProvider>;
1392
+
1393
+ /**
1394
+ * Picks (or creates) a financial-dimension combination for one main account and hands back its
1395
+ * id + display value. Stateless towards its host: it neither knows the grid nor the row — the
1396
+ * host decides where the result goes (toolbar → focused row, edit form → the row being edited).
1397
+ */
1398
+ declare class FinancialDimensionsPopupComponent {
1399
+ private financialDimensionsFacadeService;
1400
+ private cdr;
1401
+ visible: boolean;
1402
+ visibleChange: EventEmitter<boolean>;
1403
+ mainAccountId: string | null;
1404
+ existingCombinationId: string | null;
1405
+ reportMode: boolean;
1406
+ /**
1407
+ * SCR-09 — optional "locked" toggle, opt-in and off by default so the two other
1408
+ * consumers of this shared popup (financial-transactions-form, opening-balance-form)
1409
+ * are unaffected. A caller that needs it (accrual-schemes) sets `showLockToggle` and
1410
+ * owns the permission gate via `lockToggleDisabled` — this component has no notion
1411
+ * of permissions, only of whether the switch may be touched right now.
1412
+ */
1413
+ showLockToggle: boolean;
1414
+ locked: boolean;
1415
+ lockedChange: EventEmitter<boolean>;
1416
+ lockToggleDisabled: boolean;
1417
+ saved: EventEmitter<{
1418
+ combinationId: string;
1419
+ displayValue: string;
1420
+ selections?: DimensionSelectionsMap;
1421
+ locked?: boolean;
1422
+ }>;
1423
+ /** The user asked to drop the row's dimensions (only offered when one is already set). */
1424
+ cleared: EventEmitter<void>;
1425
+ dimensions: FinancialDimensionVm[];
1426
+ selections: DimensionSelectionsMap;
1427
+ isSaving: boolean;
1428
+ isLoading: boolean;
1429
+ validationError: string;
1430
+ invalidDimensionIds: Set<string>;
1431
+ private readonly config;
1432
+ private readonly adapter;
1433
+ private t;
1434
+ constructor(financialDimensionsFacadeService: FinancialDimensionsProvider, cdr: ChangeDetectorRef);
1435
+ get isArabic(): boolean;
1436
+ /** Language-aware label with a fallback to the other side, so a row filled on one side only
1437
+ * never renders blank. */
1438
+ label(item: {
1439
+ name_Ar?: string;
1440
+ name_En?: string;
1441
+ } | null | undefined): string;
1442
+ /** dxSelectBox displayExpr — bound as a function so it follows the UI language. */
1443
+ readonly valueDisplayExpr: (item: any) => string;
1444
+ get canClear(): boolean;
1445
+ onShowing(): void;
1446
+ onShown(): Promise<void>;
1447
+ onSave(): Promise<void>;
1448
+ onClear(): void;
1449
+ onSelectionChanged(dimensionId: string, value: string | null): void;
1450
+ onHiding(): void;
1451
+ private close;
1452
+ static ɵfac: i0.ɵɵFactoryDeclaration<FinancialDimensionsPopupComponent, never>;
1453
+ static ɵcmp: i0.ɵɵComponentDeclaration<FinancialDimensionsPopupComponent, "app-financial-dimensions-popup", never, { "visible": { "alias": "visible"; "required": false; }; "mainAccountId": { "alias": "mainAccountId"; "required": false; }; "existingCombinationId": { "alias": "existingCombinationId"; "required": false; }; "reportMode": { "alias": "reportMode"; "required": false; }; "showLockToggle": { "alias": "showLockToggle"; "required": false; }; "locked": { "alias": "locked"; "required": false; }; "lockToggleDisabled": { "alias": "lockToggleDisabled"; "required": false; }; }, { "visibleChange": "visibleChange"; "lockedChange": "lockedChange"; "saved": "saved"; "cleared": "cleared"; }, never, never, true, never>;
1454
+ }
1455
+
1456
+ /**
1457
+ * Icon name supported by {@link FnIconComponent}.
1458
+ * Mirrors the FormNavigator toolbar actions.
1459
+ */
1460
+ type FnIconName = 'first' | 'prev' | 'next' | 'last' | 'new' | 'save' | 'delete' | 'search' | 'duplicate' | 'cancel' | 'refresh' | 'info' | 'print' | 'bell' | 'bell-outline';
1461
+ /** Semantic accent. Drives which theme token tints the soft-3D gradient. */
1462
+ type FnIconAccent = 'primary' | 'success' | 'danger' | 'warning' | 'neutral';
1463
+ /**
1464
+ * Soft-3D, theme-tinted icon used by the FormNavigator toolbar.
1465
+ *
1466
+ * Rendering technique (all in SCSS, zero runtime cost):
1467
+ * - the glyph silhouette is a CSS `mask` (a data-URI SVG, one per `name`);
1468
+ * - the visible fill is a vertical `linear-gradient` built from the active
1469
+ * theme tokens (`--color-primary` / `--color-success` / `--color-danger`),
1470
+ * so it recolors automatically with every preset and with dark mode;
1471
+ * - depth comes from a top highlight + bottom drop-shadow.
1472
+ *
1473
+ * Because the colors are derived from CSS variables, nothing here needs to know
1474
+ * about the current preset — switching `data-app-theme` or `.dark` just works.
1475
+ */
1476
+ declare class FnIconComponent {
1477
+ /** Which glyph to render. */
1478
+ name: FnIconName;
1479
+ /** Semantic tint. Defaults to the brand primary. */
1480
+ accent: FnIconAccent;
1481
+ /**
1482
+ * When true the glyph is horizontally mirrored under `[dir="rtl"]`.
1483
+ * Used by the navigation arrows (first/prev/next/last) so they keep pointing
1484
+ * toward the logical start/end in right-to-left layouts.
1485
+ */
1486
+ directional: boolean;
1487
+ static ɵfac: i0.ɵɵFactoryDeclaration<FnIconComponent, never>;
1488
+ static ɵcmp: i0.ɵɵComponentDeclaration<FnIconComponent, "app-fn-icon", never, { "name": { "alias": "name"; "required": true; }; "accent": { "alias": "accent"; "required": false; }; "directional": { "alias": "directional"; "required": false; }; }, {}, never, never, true, never>;
1489
+ }
1490
+
1491
+ declare class GridLookupComponent implements OnInit, OnChanges {
1492
+ private sysLookupService;
1493
+ private cdr;
1494
+ private readonly libraryConfig;
1495
+ columns: any[];
1496
+ remoteOperations: boolean;
1497
+ valueExpr: any;
1498
+ displayExpr: any;
1499
+ gridDataSource: any;
1500
+ selectedValue: any[];
1501
+ isMultiSelectMode: 'none' | 'single' | 'multiple';
1502
+ selectedItems: any[];
1503
+ lookupId: Guid;
1504
+ width: number | string;
1505
+ lookupParameterSource: string | number | null;
1506
+ lookupParameters: string | null;
1507
+ selectParametersCallback?: () => Record<string, any>;
1508
+ caption: string;
1509
+ fieldName: string;
1510
+ gridId: string;
1511
+ name: string;
1512
+ text: string | null;
1513
+ valueType: LookupValueType | number;
1514
+ isMultiSelect: boolean;
1515
+ isCode: boolean;
1516
+ useCommaSeparatedValues: boolean;
1517
+ value: any | string | Guid | null | undefined;
1518
+ valueChange: EventEmitter<any>;
1519
+ readOnly: boolean;
1520
+ disabled: boolean;
1521
+ /**
1522
+ * ارتفاع القائمة المنسدلة (اختياري). بدونه تأخذ DropDownBox المساحة المتبقية تحت الحقل،
1523
+ * فحقلٌ قرب أسفل الشاشة (داخل نافذة مثلاً) تنكمش شبكته إلى صفر صفوف. مع قيمة ثابتة
1524
+ * تنقلب القائمة فوق الحقل عند الحاجة والشبكة تملؤها.
1525
+ */
1526
+ dropDownHeight: number | string | null;
1527
+ dropDownWidth: number | string;
1528
+ get dropDownOptions(): Record<string, any>;
1529
+ private _dropDownOptionsKey;
1530
+ private _dropDownOptions;
1531
+ dataGrid: DxDataGridComponent$1;
1532
+ dropDownRef: any;
1533
+ id: string;
1534
+ code: string;
1535
+ required: boolean;
1536
+ requiredMessage: string;
1537
+ validationGroup: string;
1538
+ constructor(sysLookupService: LookupGridProvider, cdr: ChangeDetectorRef, libraryConfig: ReusableComponentsConfig | null);
1539
+ /**
1540
+ * "Search on Enter" for the inner grid's filter row. This component doesn't import
1541
+ * AppGridDefaultsDirective (it would impose all the grid defaults on the compact dropdown grid),
1542
+ * so we wire the shared editor-deferral directly. The Arabic-aware matching itself is handled
1543
+ * server-side via the sys-lookup data source.
1544
+ */
1545
+ onEditorPreparing(e: any): void;
1546
+ ngOnInit(): Promise<void>;
1547
+ onDropDownOpened(): void;
1548
+ ngOnChanges(changes: SimpleChanges): Promise<void>;
1549
+ onValueChanged(e: any): void;
1550
+ clearFocusedRowInGrid(): void;
1551
+ onSelectionChanged(event: any): void;
1552
+ getSelectedDisplayTexts(): string[];
1553
+ prepareProperties(): Promise<void>;
1554
+ requiredValidationCallback: (e: any) => boolean;
1555
+ static ɵfac: i0.ɵɵFactoryDeclaration<GridLookupComponent, [null, null, { optional: true; }]>;
1556
+ static ɵcmp: i0.ɵɵComponentDeclaration<GridLookupComponent, "app-grid-lookup", never, { "lookupId": { "alias": "lookupId"; "required": false; }; "width": { "alias": "width"; "required": false; }; "lookupParameterSource": { "alias": "lookupParameterSource"; "required": false; }; "lookupParameters": { "alias": "lookupParameters"; "required": false; }; "selectParametersCallback": { "alias": "selectParametersCallback"; "required": false; }; "caption": { "alias": "caption"; "required": false; }; "fieldName": { "alias": "fieldName"; "required": false; }; "gridId": { "alias": "gridId"; "required": false; }; "name": { "alias": "name"; "required": false; }; "valueType": { "alias": "valueType"; "required": false; }; "isMultiSelect": { "alias": "isMultiSelect"; "required": false; }; "isCode": { "alias": "isCode"; "required": false; }; "useCommaSeparatedValues": { "alias": "useCommaSeparatedValues"; "required": false; }; "value": { "alias": "value"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "dropDownHeight": { "alias": "dropDownHeight"; "required": false; }; "dropDownWidth": { "alias": "dropDownWidth"; "required": false; }; "required": { "alias": "required"; "required": false; }; "requiredMessage": { "alias": "requiredMessage"; "required": false; }; "validationGroup": { "alias": "validationGroup"; "required": false; }; }, { "valueChange": "valueChange"; }, never, never, true, never>;
1557
+ }
1558
+
1559
+ interface GroupingLevelValue {
1560
+ groupingFieldName?: string;
1561
+ isNewPage?: boolean;
1562
+ [key: string]: any;
1563
+ }
1564
+ declare class GroupingLevelComponent {
1565
+ group: GroupingLevelValue;
1566
+ groupsData: any[];
1567
+ allGroups: GroupingLevelValue[];
1568
+ label?: string;
1569
+ groupingChanged: EventEmitter<string>;
1570
+ newPageChanged: EventEmitter<boolean>;
1571
+ private readonly cdr;
1572
+ private readonly adapter;
1573
+ onGroupingChanged(e: any): void;
1574
+ onNewPageChanged(e: any): void;
1575
+ getDisplayText: (item: any) => string;
1576
+ static ɵfac: i0.ɵɵFactoryDeclaration<GroupingLevelComponent, never>;
1577
+ static ɵcmp: i0.ɵɵComponentDeclaration<GroupingLevelComponent, "app-grouping-level", never, { "group": { "alias": "group"; "required": false; }; "groupsData": { "alias": "groupsData"; "required": false; }; "allGroups": { "alias": "allGroups"; "required": false; }; "label": { "alias": "label"; "required": false; }; }, { "groupingChanged": "groupingChanged"; "newPageChanged": "newPageChanged"; }, never, never, true, never>;
1578
+ }
1579
+
1580
+ declare class ImageEditComponent implements ControlValueAccessor {
1581
+ /**
1582
+ * Formats a canvas cannot re-encode without destroying the file: SVG would be rasterised and
1583
+ * lose its scalability, GIF would lose every frame but the first. They are passed through at
1584
+ * their original size instead.
1585
+ */
1586
+ private static readonly PASSTHROUGH_TYPES;
1587
+ imageSrc: string | null;
1588
+ /** True while the picked file is being read and downscaled — before any HTTP call happens. */
1589
+ processing: boolean;
1590
+ /** Set when a file is refused (too large, or not a readable image). */
1591
+ errorMessage: string | null;
1592
+ width: number;
1593
+ height: number;
1594
+ /** ✅ القراءة فقط — تمنع أي تفاعل (رفع/مسح/تغيير) */
1595
+ readOnly: boolean;
1596
+ attachmentsRelativePath: string;
1597
+ imageType: number;
1598
+ /**
1599
+ * Longest edge, in pixels, the picture is downscaled to before it is emitted.
1600
+ *
1601
+ * A phone photo is 3000-4000px wide and several megabytes; base64 adds another third, and the
1602
+ * whole thing travels inside the entity's own save request over the user's UPLOAD link — which
1603
+ * is what made saving take seconds regardless of the storage provider. Nothing in the app
1604
+ * displays an image larger than a few hundred pixels, so 1600 is already generous.
1605
+ *
1606
+ * Set to 0 to keep the original resolution.
1607
+ */
1608
+ maxDimension: number;
1609
+ /** JPEG quality used when re-encoding. 0.85 is visually lossless at these sizes. */
1610
+ quality: number;
1611
+ /**
1612
+ * Refuse a file larger than this before reading it at all. The server enforces its own limit
1613
+ * from AttachmentSettings.FileSize; this only avoids spending seconds reading a file that would
1614
+ * be rejected anyway — or exceeding the request body limit, which surfaces as a bare 413.
1615
+ * Set to 0 to disable.
1616
+ */
1617
+ maxFileSizeMb: number;
1618
+ base64: string;
1619
+ base64Change: EventEmitter<string>;
1620
+ fileName: string;
1621
+ fileNameChange: EventEmitter<string>;
1622
+ Changed: EventEmitter<void>;
1623
+ Upload: EventEmitter<void>;
1624
+ Clear: EventEmitter<void>;
1625
+ /** Emitted with a human-readable reason when a picked file is refused. */
1626
+ Rejected: EventEmitter<string>;
1627
+ get iconHeight(): number;
1628
+ get imageHeight(): number;
1629
+ get fontSize(): number;
1630
+ private onChange;
1631
+ private onTouched;
1632
+ writeValue(value: string | null): void;
1633
+ /** True for values the browser can already use unchanged (http/https/data URLs). */
1634
+ private isAbsolute;
1635
+ registerOnChange(fn: any): void;
1636
+ registerOnTouched(fn: any): void;
1637
+ /** ✅ احترام disabled من الـ FormControl إن وُجد */
1638
+ setDisabledState?(isDisabled: boolean): void;
1639
+ /** رفع ملف جديد */
1640
+ onFileSelected(event: Event): Promise<void>;
1641
+ /**
1642
+ * Writes the picked image out in the shape the configured storage mode expects. All three modes
1643
+ * behave exactly as before — only the bytes are smaller.
1644
+ */
1645
+ private applyPickedImage;
1646
+ private reject;
1647
+ private readAsDataUrl;
1648
+ /**
1649
+ * Draws the picture onto a canvas at a bounded size and re-encodes it.
1650
+ *
1651
+ * Output format is decided rather than inherited:
1652
+ * <ul>
1653
+ * <li>BinaryImage mode always yields PNG, because reading that mode back builds a
1654
+ * <code>data:image/png;base64,</code> URL — emitting JPEG there would leave the column
1655
+ * and its declared type disagreeing.</li>
1656
+ * <li>Otherwise JPEG, unless the picture actually uses transparency, which JPEG cannot
1657
+ * represent and would turn into a black background.</li>
1658
+ * </ul>
1659
+ */
1660
+ private downscale;
1661
+ /** Scans the alpha channel of the already-downscaled canvas; stops at the first transparent pixel. */
1662
+ private hasTransparency;
1663
+ /**
1664
+ * Re-encoding changes the format, so the name must follow. A file called <code>logo.png</code>
1665
+ * holding JPEG bytes would be stored under a misleading key and could be turned away by the
1666
+ * AllowedExtensions allow-list for a type it is not.
1667
+ */
1668
+ private withExtension;
1669
+ /** مسح الصورة (يحترم readOnly) */
1670
+ clearImage(): void;
1671
+ /**
1672
+ * The stored path resolved to a URL the browser could not load (e.g. a key copied from
1673
+ * another tenant's storage — the file does not exist here → 404). Fall back to the «No image»
1674
+ * placeholder instead of leaving a broken-image icon. Display-only: the bound value is left
1675
+ * untouched so a real save/clear still reflects the user's own action.
1676
+ */
1677
+ onImageError(): void;
1678
+ /** مسح داخلي لا يراعي readOnly — يُستخدم داخليًا للـ writeValue(undefined) */
1679
+ private clearImageInternal;
1680
+ getBase64(byteArray: number[]): string;
1681
+ static ɵfac: i0.ɵɵFactoryDeclaration<ImageEditComponent, never>;
1682
+ static ɵcmp: i0.ɵɵComponentDeclaration<ImageEditComponent, "app-image-edit", never, { "width": { "alias": "width"; "required": false; }; "height": { "alias": "height"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; "attachmentsRelativePath": { "alias": "attachmentsRelativePath"; "required": false; }; "imageType": { "alias": "imageType"; "required": false; }; "maxDimension": { "alias": "maxDimension"; "required": false; }; "quality": { "alias": "quality"; "required": false; }; "maxFileSizeMb": { "alias": "maxFileSizeMb"; "required": false; }; "base64": { "alias": "base64"; "required": false; }; "fileName": { "alias": "fileName"; "required": false; }; }, { "base64Change": "base64Change"; "fileNameChange": "fileNameChange"; "Changed": "Changed"; "Upload": "Upload"; "Clear": "Clear"; "Rejected": "Rejected"; }, never, never, true, never>;
1683
+ }
1684
+
1685
+ /** Host-owned data and culture boundary for the journal entry viewer. */
1686
+ interface JournalEntryViewerProvider {
1687
+ getWithLines(entryId: string): Promise<any>;
1688
+ isArabic(): boolean;
1689
+ }
1690
+ declare const JOURNAL_ENTRY_VIEWER_PROVIDER: InjectionToken<JournalEntryViewerProvider>;
1691
+
1692
+ interface ViewerRow {
1693
+ id: string;
1694
+ entry_Id: string;
1695
+ entry_No: string;
1696
+ entry_Kind: string;
1697
+ journal_Name: string;
1698
+ line_No: number;
1699
+ main_Account_No: string;
1700
+ main_Account_Name: string;
1701
+ line_Nature_Name: string;
1702
+ line_Text: string;
1703
+ debit: number;
1704
+ credit: number;
1705
+ }
1706
+ declare class JournalEntryViewerComponent implements OnChanges, DoCheck {
1707
+ private subledgerEntryService;
1708
+ entryId: string | null | undefined;
1709
+ /** Host route used when a user opens an entry from the viewer. */
1710
+ entryRoute: string;
1711
+ gridHeight: number | string;
1712
+ /** عدد سطور الصفحة في شبكة القيد. القيود الكبيرة (تشغيل إهلاك بسطرين لكل أصل) تحتاج ترقيماً. */
1713
+ pageSize: number;
1714
+ set emptyText(value: string | null | undefined);
1715
+ get emptyText(): string | null;
1716
+ private _emptyText;
1717
+ loaded: EventEmitter<{
1718
+ transactionValue: number;
1719
+ netEffect: number;
1720
+ hasReversal: boolean;
1721
+ }>;
1722
+ isLoading: boolean;
1723
+ /** فشل تحميل قيد بعينه لا يمنع عرض الباقي — تُذكر أرقام المتعذّرة فقط. */
1724
+ failedCount: number;
1725
+ /**
1726
+ * تُحفظ الـDTOs كما وصلت، والتحويل إلى صفوف يتم حسب اللغة الحالية وقت العرض.
1727
+ * لو ثُبِّتت اللغة وقت التحميل لظلّت أسماء اليومية والحسابات بلغتها القديمة بعد
1728
+ * تبديل لغة الواجهة والشاشة مفتوحة.
1729
+ */
1730
+ private loadedEntries;
1731
+ constructor(subledgerEntryService: JournalEntryViewerProvider);
1732
+ get isArabic(): boolean;
1733
+ /**
1734
+ * الصفوف والملخّص **خصائص لا getters**، تُبنى مرّة بعد وصول القيود.
1735
+ *
1736
+ * كـgetters كانت كل قراءة تُنشئ مصفوفة جديدة، فتقرأ DevExtreme مرجعًا مختلفًا في كل
1737
+ * دورة كشف تغيير وتفهم أن مصدر البيانات تبدّل فتبدأ تحميلًا جديدًا — فيعيد Angular
1738
+ * القراءة، وتدخل الشبكة دورة تحميل لا تنتهي رغم أن الطلبات ترجع 200.
1739
+ */
1740
+ rows: ViewerRow[];
1741
+ summary: {
1742
+ entry_Id: string;
1743
+ entry_No: string;
1744
+ kind: string;
1745
+ isReversed: boolean;
1746
+ }[];
1747
+ /**
1748
+ * اللغة التي بُنيت بها الصفوف. تثبيت الصفوف يعني أن تبديل اللغة والشاشة مفتوحة لا
1749
+ * يُحدِّث أسماء اليومية والحسابات، فتُعاد البناء عند تغيّرها — مقارنة قيمة منطقية
1750
+ * واحدة في كل دورة، بلا إنشاء مصفوفات.
1751
+ */
1752
+ private builtForArabic;
1753
+ ngDoCheck(): void;
1754
+ private rebuildView;
1755
+ /** قيمة الحركة = مجموع مدين القيود الأصلية، من إجمالي الخادم لا بإعادة الجمع. */
1756
+ get transactionValue(): number;
1757
+ /** الأصلي ناقص العكسي — يصير صفرًا بعد العكس، ومحسوب لا مكتوب. */
1758
+ get netEffect(): number;
1759
+ get hasReversal(): boolean;
1760
+ ngOnChanges(changes: SimpleChanges): void;
1761
+ /** يفتح القيد في شاشة القيود اليومية في تبويب جديد — نفس رابط كشف الحساب. */
1762
+ openEntry(entryId: string | null | undefined): void;
1763
+ /** تعيد التحميل بعد عملية غيّرت القيود (ترحيل أو عكس). */
1764
+ reload(): Promise<void>;
1765
+ private load;
1766
+ private fetch;
1767
+ private emitTotals;
1768
+ /** «أصلي — معكوس» / «قيد عكسي — مرحّل»: النوع والحالة وجهان لوصف واحد. */
1769
+ private describe;
1770
+ static ɵfac: i0.ɵɵFactoryDeclaration<JournalEntryViewerComponent, never>;
1771
+ static ɵcmp: i0.ɵɵComponentDeclaration<JournalEntryViewerComponent, "app-journal-entry-viewer", never, { "entryId": { "alias": "entryId"; "required": false; }; "entryRoute": { "alias": "entryRoute"; "required": false; }; "gridHeight": { "alias": "gridHeight"; "required": false; }; "pageSize": { "alias": "pageSize"; "required": false; }; "emptyText": { "alias": "emptyText"; "required": false; }; }, { "loaded": "loaded"; }, never, never, true, never>;
1772
+ }
1773
+
1774
+ /** Lookup keys are intentionally open-ended for legacy and composite-key APIs. */
1775
+ type LookupKey = any;
1776
+ interface LookupColumn {
1777
+ dataField: string;
1778
+ caption: string;
1779
+ width?: number | string;
1780
+ }
1781
+ interface LookupContext {
1782
+ lookupId: Guid | string | number | null;
1783
+ parameters?: Readonly<Record<string, unknown>>;
1784
+ lookupParameterSource?: string | number | null;
1785
+ lookupParameters?: string | null;
1786
+ }
1787
+ interface LookupItem<TRow extends Record<string, unknown> = Record<string, unknown>> {
1788
+ id: LookupKey;
1789
+ value: LookupKey;
1790
+ label: string;
1791
+ rowData: TRow;
1792
+ }
1793
+ interface LookupSearchResult<TRow extends Record<string, unknown> = Record<string, unknown>> {
1794
+ items: readonly LookupItem<TRow>[];
1795
+ columns?: readonly LookupColumn[];
1796
+ title?: string;
1797
+ }
1798
+
1799
+ type LookupAsync<T> = Promise<T> | Observable<T> | T;
1800
+ interface LookupDataProvider {
1801
+ resolve(context: LookupContext, key: LookupKey): LookupAsync<LookupItem | null>;
1802
+ search(context: LookupContext, query: string): LookupAsync<LookupSearchResult>;
1803
+ }
1804
+ declare const LOOKUP_DATA_PROVIDER: InjectionToken<LookupDataProvider>;
1805
+ declare function provideLookup(provider: LookupDataProvider): Provider;
1806
+
1807
+ declare class LookupEditComponent implements OnChanges, AfterViewInit {
1808
+ private readonly provider;
1809
+ lookupId: Guid | string | number | null;
1810
+ parameters?: Readonly<Record<string, unknown>>;
1811
+ selectParameters?: Readonly<Record<string, unknown>> | null;
1812
+ selectParametersCallback?: () => Record<string, unknown>;
1813
+ lookupParameterSource: string | number | null;
1814
+ lookupParameters: string | null;
1815
+ caption: string;
1816
+ fieldName: string;
1817
+ gridId: string;
1818
+ name: string;
1819
+ valueType: unknown;
1820
+ width: number | string;
1821
+ placeholder: string;
1822
+ idValue: LookupKey;
1823
+ readOnly: boolean;
1824
+ allowManualInput: boolean;
1825
+ required: boolean;
1826
+ languageAware: boolean;
1827
+ editorWidth: number | string;
1828
+ idValueChange: EventEmitter<any>;
1829
+ /** Fired when an item is picked from the popup: the id plus the full row. */
1830
+ resultSelected: EventEmitter<LookupItem<Record<string, unknown>>>;
1831
+ labelChange: EventEmitter<string>;
1832
+ lookupError: EventEmitter<unknown>;
1833
+ value: any;
1834
+ label: string;
1835
+ loading: boolean;
1836
+ selectedRowData: any;
1837
+ /** Navigation actions of the sys_lookup metadata (optional: needs LOOKUP_GRID_PROVIDER). */
1838
+ navigationActions: any[];
1839
+ /** Set while a resolution this component started is pending, so the echoed [idValue] isn't resolved twice. */
1840
+ triggerFlag: boolean;
1841
+ private textFieldNameAr;
1842
+ private textFieldNameEn;
1843
+ private readonly adapter;
1844
+ private readonly gridProvider;
1845
+ private readonly hostConfig;
1846
+ private readonly cdr;
1847
+ validationMessage: string | null;
1848
+ private requestVersion;
1849
+ /**
1850
+ * MUST be a stable class field, never an inline object in the template.
1851
+ * An inline `[options]="{ ..., onClick: openPopup.bind(this) }"` creates a
1852
+ * new object (and a new onClick reference) on every change-detection cycle;
1853
+ * DevExtreme then re-renders the action button each cycle, so the DOM node
1854
+ * under the pointer is replaced between pointerdown and pointerup and
1855
+ * dxclick never fires — the search button looks enabled but is dead.
1856
+ */
1857
+ searchButtonOptions: Record<string, unknown>;
1858
+ /** «Open in a new tab» button shown after the label when the lookup declares a navigation action. */
1859
+ openDetailsButton: Record<string, unknown>;
1860
+ get defaultNavigationAction(): any | null;
1861
+ private syncOpenButton;
1862
+ private translate;
1863
+ private get uiIsArabic();
1864
+ validateRequired: () => boolean;
1865
+ get requiredMessage(): string;
1866
+ lookupPopupComponent: LookupPopupComponent;
1867
+ valueTextBox?: {
1868
+ instance?: {
1869
+ element(): HTMLElement;
1870
+ focus(): void;
1871
+ option(name: string, value: unknown): void;
1872
+ };
1873
+ };
1874
+ get edtLookupLabel(): string;
1875
+ /** Read the report label without changing the selected ID or editor text. */
1876
+ getReportDisplayText(culture: string): string;
1877
+ /**
1878
+ * Programmatic read-only switch. `ngOnChanges` only fires for template bindings, so a
1879
+ * host that flips `readOnly` on the instance directly must go through here to keep the
1880
+ * search button in step with the editor.
1881
+ */
1882
+ setReadOnly(value: boolean): void;
1883
+ set edtLookupLabel(value: string);
1884
+ constructor(provider: LookupDataProvider);
1885
+ ngOnChanges(changes: SimpleChanges): void;
1886
+ ngAfterViewInit(): void;
1887
+ private loadNavigationActions;
1888
+ openLookupNavigation(action: any | null): void;
1889
+ /**
1890
+ * Opens the full lookup popup (LookupDynamicGridComponent inside):
1891
+ * search panel, filter row, metadata-driven columns/widths, paging and
1892
+ * focused-value navigation — same experience as the original component.
1893
+ */
1894
+ openPopup(): void;
1895
+ /** Merges the three parameter inputs into the single callback the grid expects. */
1896
+ private get effectiveSelectParametersCallback();
1897
+ private handlePopupResult;
1898
+ onValueChanged(event: {
1899
+ event?: Event;
1900
+ value?: LookupKey;
1901
+ component?: any;
1902
+ }): void;
1903
+ handleLookupTrigger(value?: LookupKey, emitValueChange?: boolean, userTriggered?: boolean): void;
1904
+ markInvalid(message?: string): void;
1905
+ clearInvalid(): void;
1906
+ focus(): void;
1907
+ private resolve;
1908
+ private applyItem;
1909
+ private handleNotFound;
1910
+ private clear;
1911
+ private get context();
1912
+ private unwrap;
1913
+ static ɵfac: i0.ɵɵFactoryDeclaration<LookupEditComponent, never>;
1914
+ static ɵcmp: i0.ɵɵComponentDeclaration<LookupEditComponent, "lookup-edit, app-lookup-edit", never, { "lookupId": { "alias": "lookupId"; "required": true; }; "parameters": { "alias": "parameters"; "required": false; }; "selectParameters": { "alias": "selectParameters"; "required": false; }; "selectParametersCallback": { "alias": "selectParametersCallback"; "required": false; }; "lookupParameterSource": { "alias": "lookupParameterSource"; "required": false; }; "lookupParameters": { "alias": "lookupParameters"; "required": false; }; "caption": { "alias": "caption"; "required": false; }; "fieldName": { "alias": "fieldName"; "required": false; }; "gridId": { "alias": "gridId"; "required": false; }; "name": { "alias": "name"; "required": false; }; "valueType": { "alias": "valueType"; "required": false; }; "width": { "alias": "width"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "idValue": { "alias": "idValue"; "required": false; }; "readOnly": { "alias": "readOnly"; "required": false; }; "allowManualInput": { "alias": "allowManualInput"; "required": false; }; "required": { "alias": "required"; "required": false; }; "languageAware": { "alias": "languageAware"; "required": false; }; "editorWidth": { "alias": "editorWidth"; "required": false; }; }, { "idValueChange": "idValueChange"; "resultSelected": "resultSelected"; "labelChange": "labelChange"; "lookupError": "lookupError"; }, never, never, true, never>;
1915
+ }
1916
+
1917
+ declare class MapLocationPickerComponent implements OnInit, OnDestroy {
1918
+ value: string | null | undefined;
1919
+ valueChange: EventEmitter<string>;
1920
+ coordinates: string | null | undefined;
1921
+ coordinatesChange: EventEmitter<string>;
1922
+ placeName: string | null | undefined;
1923
+ placeNameChange: EventEmitter<string>;
1924
+ displayField: 'coordinates' | 'placeName';
1925
+ dataToSend: 'coordinates' | 'placeName' | 'both';
1926
+ /** When no coordinates are saved, geocode this query (e.g. country name) to center the map */
1927
+ defaultSearchQuery?: string | null;
1928
+ /**
1929
+ * When true AND defaultSearchQuery resolves to an area, lock the map to that
1930
+ * area's bounds (pan + zoom + marker placement) so the user can't pick a point
1931
+ * outside it — e.g. restricting an address pin to the selected country. Opt-in:
1932
+ * defaults to false, so existing usages of this component are unaffected.
1933
+ */
1934
+ restrictToSearchArea: boolean;
1935
+ coordinatesSelected: EventEmitter<string>;
1936
+ placeNameSelected: EventEmitter<string>;
1937
+ locationSelected: EventEmitter<string | {
1938
+ coordinates: string;
1939
+ placeName: string;
1940
+ }>;
1941
+ mapPopupVisible: boolean;
1942
+ private L?;
1943
+ private map?;
1944
+ private marker?;
1945
+ private restrictBounds?;
1946
+ private static iconsInitialized;
1947
+ mapButtonOptions: any;
1948
+ ngOnInit(): void;
1949
+ ngOnDestroy(): void;
1950
+ private initializeValue;
1951
+ openPopup(): void;
1952
+ onMapPopupShown(): Promise<void>;
1953
+ saveSelectedLocation(): void;
1954
+ onMapPopupHiding(): void;
1955
+ onTextChanged(e: any): void;
1956
+ private updateCoordinatesAndFetchPlaceName;
1957
+ private fetchPlaceName;
1958
+ private extractPlaceName;
1959
+ private emitLocationSelected;
1960
+ private disposeMap;
1961
+ private ensureLeafletLoaded;
1962
+ private ensureLeafletIcons;
1963
+ static ɵfac: i0.ɵɵFactoryDeclaration<MapLocationPickerComponent, never>;
1964
+ static ɵcmp: i0.ɵɵComponentDeclaration<MapLocationPickerComponent, "app-map-location-picker", never, { "value": { "alias": "value"; "required": false; }; "coordinates": { "alias": "coordinates"; "required": false; }; "placeName": { "alias": "placeName"; "required": false; }; "displayField": { "alias": "displayField"; "required": false; }; "dataToSend": { "alias": "dataToSend"; "required": false; }; "defaultSearchQuery": { "alias": "defaultSearchQuery"; "required": false; }; "restrictToSearchArea": { "alias": "restrictToSearchArea"; "required": false; }; }, { "valueChange": "valueChange"; "coordinatesChange": "coordinatesChange"; "placeNameChange": "placeNameChange"; "coordinatesSelected": "coordinatesSelected"; "placeNameSelected": "placeNameSelected"; "locationSelected": "locationSelected"; }, never, never, true, never>;
1965
+ }
1966
+
1967
+ interface MessageContentPopupData {
1968
+ title?: string | null;
1969
+ subject?: string | null;
1970
+ body?: string | null;
1971
+ isHtml?: boolean | null;
1972
+ }
1973
+ /**
1974
+ * Generic viewer for a subject + body (HTML or plain text) shown in a modal.
1975
+ * Kept out of DynamicGridComponent so the grid stays free of message-specific
1976
+ * presentation concerns; any caller opens it via the public `open()` method.
1977
+ */
1978
+ declare class MessageContentPopupComponent {
1979
+ private readonly sanitizer;
1980
+ private readonly cdr;
1981
+ defaultTitle: string;
1982
+ defaultSubject: string;
1983
+ subjectLabel: string;
1984
+ bodyLabel: string;
1985
+ visible: boolean;
1986
+ title: string;
1987
+ subject: string;
1988
+ bodyText: string;
1989
+ safeBody: SafeHtml;
1990
+ isHtml: boolean;
1991
+ open(data: MessageContentPopupData): void;
1992
+ close(): void;
1993
+ static ɵfac: i0.ɵɵFactoryDeclaration<MessageContentPopupComponent, never>;
1994
+ static ɵcmp: i0.ɵɵComponentDeclaration<MessageContentPopupComponent, "app-message-content-popup", never, { "defaultTitle": { "alias": "defaultTitle"; "required": false; }; "defaultSubject": { "alias": "defaultSubject"; "required": false; }; "subjectLabel": { "alias": "subjectLabel"; "required": false; }; "bodyLabel": { "alias": "bodyLabel"; "required": false; }; }, {}, never, never, true, never>;
1995
+ }
1996
+
1997
+ declare enum PermissionType {
1998
+ Allowed = "allowed",
1999
+ Denied = "denied"
2000
+ }
2001
+ interface PermissionItem {
2002
+ id: number;
2003
+ name_Ar: string;
2004
+ name_En: string;
2005
+ display_Order?: number;
2006
+ is_Disabled: boolean;
2007
+ allow_Rule_Id: number;
2008
+ deny_Rule_Id: number;
2009
+ }
2010
+ interface SecurityRuleItem {
2011
+ id: Number;
2012
+ security_Rule_Ar: string | null;
2013
+ security_Rule_En: string | null;
2014
+ }
2015
+
2016
+ type RuleChangeEvent = {
2017
+ permissionId: number;
2018
+ kind: 'allow' | 'deny';
2019
+ ruleId: number | null;
2020
+ };
2021
+ declare class PermissionSelectorItemComponent {
2022
+ private readonly config;
2023
+ readonly securityRuleExpr: (item: SecurityRuleItem | null) => string;
2024
+ readonly securityRuleSearchExpr: () => string;
2025
+ /** ثابت لقراءة enum داخل القالب */
2026
+ PermissionType: typeof PermissionType;
2027
+ private readonly ALL_RULE_ID;
2028
+ permissionId: number;
2029
+ permissionName: string;
2030
+ type: PermissionType;
2031
+ /** هل هذا الـ permission مختار؟ */
2032
+ selected: boolean;
2033
+ /** هل هذا الـ permission معطّل (متضارب مع الجهة الأخرى)؟ */
2034
+ disabled: boolean;
2035
+ /** قائمة قواعد الأمان */
2036
+ securityRules: SecurityRuleItem[];
2037
+ /** القيم الحالية للقواعد لهذا الـ permission */
2038
+ allowRuleId: number | null;
2039
+ denyRuleId: number | null;
2040
+ /** تغيّر حالة الـ checkbox */
2041
+ toggle: EventEmitter<{
2042
+ permissionId: number;
2043
+ selected: boolean;
2044
+ }>;
2045
+ /** تغيّر القاعدة */
2046
+ ruleChanged: EventEmitter<RuleChangeEvent>;
2047
+ onToggle(ev: Event): void;
2048
+ onRuleChanged(kind: 'allow' | 'deny', value: any): void;
2049
+ static ɵfac: i0.ɵɵFactoryDeclaration<PermissionSelectorItemComponent, never>;
2050
+ static ɵcmp: i0.ɵɵComponentDeclaration<PermissionSelectorItemComponent, "app-permission-selector-item", never, { "permissionId": { "alias": "permissionId"; "required": false; }; "permissionName": { "alias": "permissionName"; "required": false; }; "type": { "alias": "type"; "required": false; }; "selected": { "alias": "selected"; "required": false; }; "disabled": { "alias": "disabled"; "required": false; }; "securityRules": { "alias": "securityRules"; "required": false; }; "allowRuleId": { "alias": "allowRuleId"; "required": false; }; "denyRuleId": { "alias": "denyRuleId"; "required": false; }; }, { "toggle": "toggle"; "ruleChanged": "ruleChanged"; }, never, never, true, never>;
2051
+ }
2052
+
2053
+ /** One field-level change entry — mirror of Flexora's `RecordChangeEntry`. */
2054
+ interface RecordChangeEntry {
2055
+ column_Name: string;
2056
+ old_Value?: string | null;
2057
+ new_Value?: string | null;
2058
+ changed_On: string;
2059
+ changed_By?: string | null;
2060
+ }
2061
+ /** Full change log of one record — mirror of Flexora's `RecordChangeLogResult`. */
2062
+ interface RecordChangeLogResult {
2063
+ table_Name: string;
2064
+ record_Id: string;
2065
+ created_By?: string | null;
2066
+ created_On?: string | null;
2067
+ modified_By?: string | null;
2068
+ modified_On?: string | null;
2069
+ changes: RecordChangeEntry[];
2070
+ }
2071
+ /**
2072
+ * Host-supplied loader for the record change log popup. Shaped to match
2073
+ * Flexora's `RecordChangeLogService` structurally so the host can wire it with
2074
+ * `{ provide: RECORD_CHANGE_LOG_PROVIDER, useExisting: RecordChangeLogService }`.
2075
+ */
2076
+ interface RecordChangeLogProvider {
2077
+ getLog(tableName: string, recordId: string): Observable<RecordChangeLogResult>;
2078
+ }
2079
+ declare const RECORD_CHANGE_LOG_PROVIDER: InjectionToken<RecordChangeLogProvider>;
2080
+
2081
+ declare class RecordChangeLogPopupComponent {
2082
+ private provider;
2083
+ visible: boolean;
2084
+ loading: boolean;
2085
+ displayId: string;
2086
+ result: RecordChangeLogResult | null;
2087
+ constructor(provider: RecordChangeLogProvider);
2088
+ get changes(): RecordChangeEntry[];
2089
+ /**
2090
+ * @param tableName اسم جدول السجل (مثل cash_transfer)
2091
+ * @param recordId معرف السجل (id)
2092
+ * @param displayId معرف معروض في العنوان (الكود مثلًا) — اختياري
2093
+ */
2094
+ open(tableName: string, recordId: string, displayId?: string): Promise<void>;
2095
+ close(): void;
2096
+ static ɵfac: i0.ɵɵFactoryDeclaration<RecordChangeLogPopupComponent, never>;
2097
+ static ɵcmp: i0.ɵɵComponentDeclaration<RecordChangeLogPopupComponent, "app-record-change-log-popup", never, {}, {}, never, never, true, never>;
2098
+ }
2099
+
2100
+ declare class PermissionSelectorComponent implements OnChanges {
2101
+ private cd;
2102
+ allowByPerm: any;
2103
+ denyByPerm: any;
2104
+ PermissionType: typeof PermissionType;
2105
+ constructor(cd: ChangeDetectorRef);
2106
+ /**
2107
+ * Layout mode for permission items.
2108
+ * - 'list': normal stacked list
2109
+ * - 'grid': responsive grid (better when there are many permissions)
2110
+ */
2111
+ layout: 'list' | 'grid';
2112
+ /** Minimum width for a grid item (px) when layout='grid' */
2113
+ gridMinItemWidth: number;
2114
+ type: PermissionType;
2115
+ permissions: PermissionItem[];
2116
+ userPermissionIds: number[];
2117
+ permissionsChanged: EventEmitter<number[]>;
2118
+ conflictingPermissionIds: number[];
2119
+ permissionsList: any[];
2120
+ userPermissions: Array<{
2121
+ permission_Id: number;
2122
+ allow_Rule_Id: number | null;
2123
+ deny_Rule_Id: number | null;
2124
+ }>;
2125
+ securityRules: SecurityRuleItem[];
2126
+ ruleChanged: EventEmitter<RuleChangeEvent>;
2127
+ ngOnChanges(changes: SimpleChanges): void;
2128
+ private updatePermissionsList;
2129
+ trackByPermissionId(index: number, item: PermissionItem): number;
2130
+ isSelected: (id: number) => boolean;
2131
+ isDisabled: (id: number) => boolean;
2132
+ getRuleId(id: number, kind: 'allow' | 'deny'): number | null;
2133
+ onToggleItem(e: {
2134
+ permissionId: number;
2135
+ selected: boolean;
2136
+ }): void;
2137
+ onRuleChangedFromItem(e: RuleChangeEvent): void;
2138
+ static ɵfac: i0.ɵɵFactoryDeclaration<PermissionSelectorComponent, never>;
2139
+ static ɵcmp: i0.ɵɵComponentDeclaration<PermissionSelectorComponent, "app-permission-selector", never, { "layout": { "alias": "layout"; "required": false; }; "gridMinItemWidth": { "alias": "gridMinItemWidth"; "required": false; }; "type": { "alias": "type"; "required": false; }; "permissions": { "alias": "permissions"; "required": false; }; "userPermissionIds": { "alias": "userPermissionIds"; "required": false; }; "conflictingPermissionIds": { "alias": "conflictingPermissionIds"; "required": false; }; "userPermissions": { "alias": "userPermissions"; "required": false; }; "securityRules": { "alias": "securityRules"; "required": false; }; }, { "permissionsChanged": "permissionsChanged"; "ruleChanged": "ruleChanged"; }, never, never, true, never>;
2140
+ }
2141
+
2142
+ declare class QueryActionsToolbarComponent {
2143
+ runDisabled: boolean;
2144
+ clearDisabled: boolean;
2145
+ printDisabled: boolean;
2146
+ saveDisabled: boolean;
2147
+ /** شاشة بلا «حفظ تقرير» (مثل قائمة التدفقات النقدية) تُخفي الزرّ بدل أن تتركه معطَّلاً دائماً. */
2148
+ showSave: boolean;
2149
+ run: EventEmitter<void>;
2150
+ clear: EventEmitter<void>;
2151
+ print: EventEmitter<void>;
2152
+ save: EventEmitter<void>;
2153
+ onRunClick: () => void;
2154
+ onClearClick: () => void;
2155
+ onPrintClick: () => void;
2156
+ onSaveClick: () => void;
2157
+ static ɵfac: i0.ɵɵFactoryDeclaration<QueryActionsToolbarComponent, never>;
2158
+ static ɵcmp: i0.ɵɵComponentDeclaration<QueryActionsToolbarComponent, "app-query-actions-toolbar", never, { "runDisabled": { "alias": "runDisabled"; "required": false; }; "clearDisabled": { "alias": "clearDisabled"; "required": false; }; "printDisabled": { "alias": "printDisabled"; "required": false; }; "saveDisabled": { "alias": "saveDisabled"; "required": false; }; "showSave": { "alias": "showSave"; "required": false; }; }, { "run": "run"; "clear": "clear"; "print": "print"; "save": "save"; }, never, never, true, never>;
2159
+ }
2160
+
2161
+ interface BarRect {
2162
+ x: number;
2163
+ width: number;
2164
+ }
2165
+ interface Code128Drawing {
2166
+ /** Bars only, in module units from the left edge (quiet zones included in `totalWidth`). */
2167
+ bars: BarRect[];
2168
+ totalWidth: number;
2169
+ }
2170
+
2171
+ /**
2172
+ * Live preview of a retail receipt template (قوالب الإيصالات — §2 «معاينة الإيصال»).
2173
+ *
2174
+ * Reads the template straight from the form's data object, which every accordion section
2175
+ * shares by reference, so it redraws on each edit with no event wiring.
2176
+ *
2177
+ * What it models, and why:
2178
+ * - Thermal printers print a fixed number of characters per line, set by the paper width.
2179
+ * The paper is drawn that many characters wide (`ch` units, app font — a monospace font
2180
+ * has no proper Arabic glyphs), and header/footer lines longer than that count are cut —
2181
+ * exactly what the printer will do (§4.2) — and flagged.
2182
+ * - The sale itself is fixed sample data (the template has no transaction behind it).
2183
+ * - A chosen advanced report replaces the whole layout (§5.7), so the preview is dimmed
2184
+ * under a notice rather than pretending to show what will print.
2185
+ */
2186
+ type ReceiptLang = 'ar' | 'en';
2187
+ interface SampleLine {
2188
+ name: string;
2189
+ amount: string;
2190
+ }
2191
+ declare class ReceiptPreviewComponent {
2192
+ private config;
2193
+ constructor(config: ReusableComponentsConfig | null);
2194
+ /** The template being edited (the form's shared data object). */
2195
+ values: Record<string, any> | null | undefined;
2196
+ private get v();
2197
+ get paperMm(): number;
2198
+ get charsPerLine(): number;
2199
+ get copies(): number;
2200
+ get hasReport(): boolean;
2201
+ get logoPath(): string | null;
2202
+ /** Switches default to on — the table default — when a new record has not set them yet. */
2203
+ private flag;
2204
+ get showTax(): boolean;
2205
+ get showQr(): boolean;
2206
+ get showLoyalty(): boolean;
2207
+ get showBarcode(): boolean;
2208
+ /**
2209
+ * The receipt prints in one language (§6.2) and the template carries no language field,
2210
+ * so it is read from its own texts: Arabic letters ⇒ Arabic; only Latin ⇒ English;
2211
+ * no text yet ⇒ the user's interface language.
2212
+ */
2213
+ get lang(): ReceiptLang;
2214
+ get dir(): 'rtl' | 'ltr';
2215
+ get sample(): {
2216
+ receiptLabel: string;
2217
+ cashierLabel: string;
2218
+ cashier: string;
2219
+ lines: SampleLine[];
2220
+ totals: SampleLine[];
2221
+ tax: SampleLine[];
2222
+ due: SampleLine;
2223
+ payment: string;
2224
+ loyalty: string[];
2225
+ qr: string;
2226
+ copyOf: (n: number, of: number) => string;
2227
+ logo: string;
2228
+ };
2229
+ readonly receiptNo = "T01-004921";
2230
+ readonly saleDate = "2026-08-06";
2231
+ readonly saleTime = "19:42";
2232
+ /** Real Code 128 of the sample receipt number — scannable. Computed once: the number is fixed. */
2233
+ readonly barcode: Code128Drawing;
2234
+ /** QR-shaped placeholder; the real QR holds e-invoice data that exists only after a sale. */
2235
+ readonly qr: {
2236
+ size: number;
2237
+ dark: [number, number][];
2238
+ };
2239
+ get separator(): string;
2240
+ get headerLines(): {
2241
+ text: string;
2242
+ cut: boolean;
2243
+ }[];
2244
+ get footerLines(): {
2245
+ text: string;
2246
+ cut: boolean;
2247
+ }[];
2248
+ get cutCount(): number;
2249
+ get copyLabels(): string[];
2250
+ private cutLines;
2251
+ static ɵfac: i0.ɵɵFactoryDeclaration<ReceiptPreviewComponent, [{ optional: true; }]>;
2252
+ static ɵcmp: i0.ɵɵComponentDeclaration<ReceiptPreviewComponent, "app-receipt-preview", never, { "values": { "alias": "values"; "required": false; }; }, {}, never, never, true, never>;
2253
+ }
2254
+
2255
+ /**
2256
+ * أزرار سير عمل «التقارير المحفوظة»: اعتماد · إلغاء الاعتماد · أرشفة ·
2257
+ * إلغاء الأرشيف.
2258
+ *
2259
+ * تشترك فيه خمس شاشات (استخراج القوائم المالية · التحليل المالي · أرصدة
2260
+ * الحسابات · كشف الحساب · ميزان المراجعة). الأزرار **ثابتة ومرئية دائماً**
2261
+ * وتُعطَّل حين لا تنطبق على حالة الصفوف المحدَّدة — بدل شريط سير العمل
2262
+ * الديناميكي الذي كان يظهر ويختفي.
2263
+ *
2264
+ * ⚠ يُوضع **داخل** `*dxTemplate` الخاصّ بشريط أدوات الشبكة لا بدلاً منه:
2265
+ * DevExtreme يحلّ اسم القالب من الشبكة نفسها عبر `toolbarCustomItems`.
2266
+ *
2267
+ * قواعد التعطيل تسكن هنا لأنها **دالة خالصة** من الحالة والصلاحية، ومتطابقة
2268
+ * في الخمس شاشات. والتعطيل **للوضوح لا للحماية**: الخادم يتحقّق من صلاحية
2269
+ * الانتقال على نقطة `bulk-apply-workflow` نفسها.
2270
+ */
2271
+ declare class ReportWorkflowActionsComponent {
2272
+ /** حالة الصفوف المحدَّدة، أو `null` لو اختلفت أو لا تحديد. */
2273
+ statusId: string | null;
2274
+ /** صلاحية «اعتماد» (sys_permission 21) على وظيفة الشاشة. */
2275
+ canApprove: boolean;
2276
+ /** تحديد صالح: صفّ واحد على الأقل وكلها بنفس الحالة. */
2277
+ hasSelection: boolean;
2278
+ /** مُخرَج واحد يحمل معرّف الإجراء — الشاشة تعامل الأربعة بنفس المسار. */
2279
+ action: EventEmitter<string>;
2280
+ /**
2281
+ * معرّفات الحالات والإجراءات تخصّ دورة عمل المستأجر فلا قيم افتراضية لها هنا — الشاشة
2282
+ * المستضيفة تمرّرها (في Flexora: `FinancialReportStatusEnum` / `FinancialReportWorkflowActionEnum`).
2283
+ * معرّف غير مُمرَّر يعطّل الزرّ المقابل بدل أن يطابق حالة فارغة أو يُرسل معرّفاً خاطئاً.
2284
+ */
2285
+ draftStatusId: string | null;
2286
+ approvedStatusId: string | null;
2287
+ archivedStatusId: string | null;
2288
+ approveActionId: string | null;
2289
+ unapproveActionId: string | null;
2290
+ archiveActionId: string | null;
2291
+ unarchiveActionId: string | null;
2292
+ private get enabled();
2293
+ private matches;
2294
+ get canApproveNow(): boolean;
2295
+ get canUnapproveNow(): boolean;
2296
+ get canArchiveNow(): boolean;
2297
+ get canUnarchiveNow(): boolean;
2298
+ /**
2299
+ * سبب التعطيل — يُعرض تلميحاً على الزرار المعطَّل بدل تكرار اسمه.
2300
+ * الترتيب: الصلاحية أولاً (حاجز ثابت) ثم التحديد ثم الحالة.
2301
+ * الترجمة في القالب عبر `localize` بالمفتاح والافتراض معاً.
2302
+ */
2303
+ get disabledReasonKey(): string;
2304
+ get disabledReasonDefault(): string;
2305
+ emit(actionId: string | null): void;
2306
+ static ɵfac: i0.ɵɵFactoryDeclaration<ReportWorkflowActionsComponent, never>;
2307
+ static ɵcmp: i0.ɵɵComponentDeclaration<ReportWorkflowActionsComponent, "app-report-workflow-actions", never, { "statusId": { "alias": "statusId"; "required": false; }; "canApprove": { "alias": "canApprove"; "required": false; }; "hasSelection": { "alias": "hasSelection"; "required": false; }; "draftStatusId": { "alias": "draftStatusId"; "required": false; }; "approvedStatusId": { "alias": "approvedStatusId"; "required": false; }; "archivedStatusId": { "alias": "archivedStatusId"; "required": false; }; "approveActionId": { "alias": "approveActionId"; "required": false; }; "unapproveActionId": { "alias": "unapproveActionId"; "required": false; }; "archiveActionId": { "alias": "archiveActionId"; "required": false; }; "unarchiveActionId": { "alias": "unarchiveActionId"; "required": false; }; }, { "action": "action"; }, never, never, true, never>;
2308
+ }
2309
+
2310
+ /** سطر معلومة يُعرض فوق تاريخ العكس (مثلاً: عدد الأصول، رقم القيد الأصلي). */
2311
+ interface ReversalDetailItem {
2312
+ label: string;
2313
+ value: string | number | null | undefined;
2314
+ }
2315
+ /** ما يُرسَل عند التأكيد حين تُستخدم الخيارات الإضافية (السبب). */
2316
+ interface ReversalConfirmation {
2317
+ date: Date;
2318
+ reason: string;
2319
+ }
2320
+ declare class ReversalDatePopupComponent {
2321
+ private config;
2322
+ constructor(config: ReusableComponentsConfig | null);
2323
+ private readonly t;
2324
+ set visible(value: boolean);
2325
+ /** Disables the confirm button while the host is performing the reversal. */
2326
+ set busy(value: boolean);
2327
+ /**
2328
+ * التاريخ المقترح عند الفتح (الافتراضي: اليوم). عكس الإهلاك يمرّر تاريخ التشغيل الأصلي.
2329
+ * يُطبَّق عند الفتح، وكذلك إن وصل بعد الفتح (ترتيب إسناد المدخلات غير مضمون).
2330
+ */
2331
+ set initialDate(value: Date | string | null | undefined);
2332
+ /** أقدم تاريخ مسموح (تاريخ المستند الأصلي) — الخادم يتحقّق منه أيضاً. */
2333
+ minDate: Date | string | null | undefined;
2334
+ /** معلومات تُعرض فوق التاريخ (SRS الإهلاك §5.2: عدد الأصول، الإجمالي، رقم القيد، التاريخ). */
2335
+ details: ReversalDetailItem[] | null;
2336
+ /** نص تحذير يظهر فوق التاريخ. */
2337
+ warning: string | null;
2338
+ /** يُظهر حقل «سبب العكس». */
2339
+ showReason: boolean;
2340
+ /** السبب إلزامي: زر التأكيد معطَّل حتى يُكتب. */
2341
+ set reasonRequired(value: boolean);
2342
+ visibleChange: EventEmitter<boolean>;
2343
+ /** The chosen accounting date. Raised only when the user confirms. */
2344
+ confirmed: EventEmitter<Date>;
2345
+ /** نفس لحظة confirmed لكن مع السبب — للشاشات التي تستخدم showReason. */
2346
+ confirmedWithReason: EventEmitter<ReversalConfirmation>;
2347
+ isVisible: boolean;
2348
+ isBusy: boolean;
2349
+ isReasonRequired: boolean;
2350
+ reversalDate: Date;
2351
+ reason: string;
2352
+ private defaultDate;
2353
+ confirmButtonOptions: Record<string, unknown>;
2354
+ readonly cancelButtonOptions: {
2355
+ text: string;
2356
+ stylingMode: string;
2357
+ onClick: () => void;
2358
+ };
2359
+ private get missingReason();
2360
+ private refreshConfirmButton;
2361
+ onReasonChanged(value: string | null | undefined): void;
2362
+ onVisibleChange(value: boolean): void;
2363
+ confirm(): void;
2364
+ close(): void;
2365
+ static ɵfac: i0.ɵɵFactoryDeclaration<ReversalDatePopupComponent, [{ optional: true; }]>;
2366
+ static ɵcmp: i0.ɵɵComponentDeclaration<ReversalDatePopupComponent, "app-reversal-date-popup", never, { "visible": { "alias": "visible"; "required": false; }; "busy": { "alias": "busy"; "required": false; }; "initialDate": { "alias": "initialDate"; "required": false; }; "minDate": { "alias": "minDate"; "required": false; }; "details": { "alias": "details"; "required": false; }; "warning": { "alias": "warning"; "required": false; }; "showReason": { "alias": "showReason"; "required": false; }; "reasonRequired": { "alias": "reasonRequired"; "required": false; }; }, { "visibleChange": "visibleChange"; "confirmed": "confirmed"; "confirmedWithReason": "confirmedWithReason"; }, never, never, true, never>;
2367
+ }
2368
+
2369
+ /** Presentational action bar for save-only forms. */
2370
+ declare class SaveOnlyButtonsComponent {
2371
+ saving: boolean;
2372
+ /** Defaults to true to preserve always-enabled behavior for hosts without change tracking. */
2373
+ hasChanges: boolean;
2374
+ /** Save button text; falls back to the localized "حفظ" when null. */
2375
+ saveText: string | null;
2376
+ showRestore: boolean;
2377
+ /** Restore button text; falls back to the localized default when null. */
2378
+ restoreText: string | null;
2379
+ save: EventEmitter<void>;
2380
+ restore: EventEmitter<void>;
2381
+ static ɵfac: i0.ɵɵFactoryDeclaration<SaveOnlyButtonsComponent, never>;
2382
+ static ɵcmp: i0.ɵɵComponentDeclaration<SaveOnlyButtonsComponent, "app-save-only-buttons", never, { "saving": { "alias": "saving"; "required": false; }; "hasChanges": { "alias": "hasChanges"; "required": false; }; "saveText": { "alias": "saveText"; "required": false; }; "showRestore": { "alias": "showRestore"; "required": false; }; "restoreText": { "alias": "restoreText"; "required": false; }; }, { "save": "save"; "restore": "restore"; }, never, never, true, never>;
2383
+ }
2384
+
2385
+ declare class SelectBoxWithLinkComponent implements ControlValueAccessor, OnInit {
2386
+ private readonly router;
2387
+ dataSource: any;
2388
+ displayExpr: string | ((item: unknown) => string);
2389
+ valueExpr: string;
2390
+ searchEnabled: boolean;
2391
+ showClearButton: boolean;
2392
+ placeholder: string;
2393
+ linkRoute: string;
2394
+ linkHint: string;
2395
+ linkIcon: string;
2396
+ value: unknown;
2397
+ disabled: boolean;
2398
+ buttons: any[];
2399
+ private onChange;
2400
+ private onTouched;
2401
+ ngOnInit(): void;
2402
+ writeValue(value: unknown): void;
2403
+ registerOnChange(fn: (value: unknown) => void): void;
2404
+ registerOnTouched(fn: () => void): void;
2405
+ setDisabledState(isDisabled: boolean): void;
2406
+ onValueChanged(event: {
2407
+ value?: unknown;
2408
+ }): void;
2409
+ openLinkScreen: () => void;
2410
+ static ɵfac: i0.ɵɵFactoryDeclaration<SelectBoxWithLinkComponent, never>;
2411
+ static ɵcmp: i0.ɵɵComponentDeclaration<SelectBoxWithLinkComponent, "app-select-box-with-link", never, { "dataSource": { "alias": "dataSource"; "required": false; }; "displayExpr": { "alias": "displayExpr"; "required": false; }; "valueExpr": { "alias": "valueExpr"; "required": false; }; "searchEnabled": { "alias": "searchEnabled"; "required": false; }; "showClearButton": { "alias": "showClearButton"; "required": false; }; "placeholder": { "alias": "placeholder"; "required": false; }; "linkRoute": { "alias": "linkRoute"; "required": false; }; "linkHint": { "alias": "linkHint"; "required": false; }; "linkIcon": { "alias": "linkIcon"; "required": false; }; }, {}, never, never, true, never>;
2412
+ }
2413
+
2414
+ interface SubscriptionPrefs {
2415
+ notifyOnUpdate: boolean;
2416
+ notifyOnStatusChange: boolean;
2417
+ notifyOnDelete: boolean;
2418
+ channelInApp: boolean;
2419
+ channelEmail: boolean;
2420
+ channelWhatsapp: boolean;
2421
+ channelSms: boolean;
2422
+ }
2423
+ interface RecordSubscriptionItem {
2424
+ record_Id: string;
2425
+ notify_On_Update: boolean;
2426
+ notify_On_Status_Change: boolean;
2427
+ notify_On_Delete: boolean;
2428
+ channel_In_App: boolean;
2429
+ channel_Email: boolean;
2430
+ channel_Whatsapp: boolean;
2431
+ channel_Sms: boolean;
2432
+ }
2433
+ interface RecordSubscriptionProvider {
2434
+ isSubscribed(recordId: string): Observable<boolean>;
2435
+ getMine(): Observable<RecordSubscriptionItem[]>;
2436
+ subscribe(recordId: string, prefs: SubscriptionPrefs): Observable<unknown>;
2437
+ unsubscribe(recordId: string): Observable<unknown>;
2438
+ }
2439
+ declare const RECORD_SUBSCRIPTION_PROVIDER: InjectionToken<RecordSubscriptionProvider>;
2440
+
2441
+ declare class SubscribeButtonComponent implements OnChanges {
2442
+ recordId: string;
2443
+ /** Hide the "تغيير الحالة" checkbox when the entity has no status workflow */
2444
+ showStatusChange: boolean;
2445
+ isSubscribed: boolean;
2446
+ loading: boolean;
2447
+ showPopup: boolean;
2448
+ popupLoading: boolean;
2449
+ validationError: string | null;
2450
+ prefs: SubscriptionPrefs;
2451
+ private readonly svc;
2452
+ private readonly cdr;
2453
+ ngOnChanges(changes: SimpleChanges): void;
2454
+ private refresh;
2455
+ onBellClick(): void;
2456
+ onConfirmSubscribe(): void;
2457
+ onUnsubscribe(): void;
2458
+ triggerOpen(recordId: string): void;
2459
+ static ɵfac: i0.ɵɵFactoryDeclaration<SubscribeButtonComponent, never>;
2460
+ static ɵcmp: i0.ɵɵComponentDeclaration<SubscribeButtonComponent, "app-subscribe-button", never, { "recordId": { "alias": "recordId"; "required": false; }; "showStatusChange": { "alias": "showStatusChange"; "required": false; }; }, {}, never, never, true, never>;
2461
+ }
2462
+
2463
+ /** Mirror of Flexora's `AvailableTransitionDto` (structural — any compatible shape works). */
2464
+ interface WorkflowAvailableTransition {
2465
+ id: string;
2466
+ transition_Name_Ar: string;
2467
+ transition_Name_En?: string | null;
2468
+ transition_Type_Id: string;
2469
+ transition_Type_Code?: string | null;
2470
+ to_State_Id: string;
2471
+ to_State_Name_Ar?: string | null;
2472
+ to_State_Name_En?: string | null;
2473
+ require_Note: boolean;
2474
+ allow_From_Notification: boolean;
2475
+ icon?: string | null;
2476
+ can_Execute: boolean;
2477
+ disabled_Reason_Key?: string | null;
2478
+ }
2479
+ /** Mirror of Flexora's `WorkflowStateChainDto`. */
2480
+ interface WorkflowStateChain {
2481
+ state_Id: string;
2482
+ state_Name_Ar?: string | null;
2483
+ state_Name_En?: string | null;
2484
+ state_Type_Code?: string | null;
2485
+ display_Order?: number | null;
2486
+ is_Current: boolean;
2487
+ is_Passed: boolean;
2488
+ }
2489
+ /** Mirror of Flexora's `WorkflowInstanceResultDto`. */
2490
+ interface WorkflowInstanceResult {
2491
+ instance_Id: string;
2492
+ current_State_Id: string;
2493
+ current_State_Name_Ar?: string | null;
2494
+ current_State_Name_En?: string | null;
2495
+ current_State_Type_Code?: string | null;
2496
+ instance_Status_Id: string;
2497
+ state_Entered_On: string;
2498
+ due_On?: string | null;
2499
+ escalation_Level: number;
2500
+ completed_On?: string | null;
2501
+ /** حالة المستند نفسه (لا الدورة) — تغني الشاشة عن إعادة جلب المستند بعد الإجراء */
2502
+ document_Status_Id?: string | null;
2503
+ /** لا يوجد مسؤول مُسنَد للخطوة الحالية. */
2504
+ no_Responsible?: boolean;
2505
+ available_Transitions: WorkflowAvailableTransition[];
2506
+ states: WorkflowStateChain[];
2507
+ }
2508
+ /** Mirror of Flexora's `DocumentWorkflowContextDto`. */
2509
+ interface WorkflowDocumentContext {
2510
+ instance: WorkflowInstanceResult | null;
2511
+ can_Start?: boolean;
2512
+ document_Status_Name_Ar?: string | null;
2513
+ document_Status_Name_En?: string | null;
2514
+ }
2515
+ /** Mirror of Flexora's `ApplyTransitionInput`. */
2516
+ interface WorkflowApplyTransitionInput {
2517
+ transition_Id: string;
2518
+ notes?: string | null;
2519
+ expected_State_Id: string;
2520
+ }
2521
+ interface WorkflowUpdatedNotification {
2522
+ documentTypeId: string;
2523
+ documentId: string;
2524
+ }
2525
+ /**
2526
+ * Host-supplied services for the workflow actions bar (workflow v2 —
2527
+ * document context + transitions). The host adapter typically wraps its
2528
+ * workflow-instance API service, its cross-tab update channel, and its
2529
+ * language service.
2530
+ */
2531
+ interface WorkflowActionsProvider {
2532
+ /** Everything the bar needs in one call (always 200 — no 404). */
2533
+ getDocumentContext(documentTypeId: string, documentId: string): Observable<WorkflowDocumentContext>;
2534
+ applyTransition(instanceId: string, input: WorkflowApplyTransitionInput): Observable<WorkflowInstanceResult>;
2535
+ /** Fired when a workflow changed elsewhere (other tab/screen) so the bar reloads. */
2536
+ workflowUpdates$: Observable<WorkflowUpdatedNotification>;
2537
+ /** Whether the UI language is Arabic (drives Ar/En name selection). */
2538
+ isArabic(): boolean;
2539
+ /** Optional: light "does this document type have an active cycle?" probe (drives the loading hint). */
2540
+ hasActiveWorkflow?(documentTypeId: string): Observable<boolean>;
2541
+ /** Optional: bulk mode (grid selection) — required only when `documentIds` is used. */
2542
+ bulkApplyTransition?(input: {
2543
+ items: {
2544
+ instance_Id: string;
2545
+ transition_Id: string;
2546
+ expected_State_Id: string;
2547
+ }[];
2548
+ notes?: string | null;
2549
+ }): Observable<{
2550
+ succeeded: number;
2551
+ failed: number;
2552
+ errors: {
2553
+ instance_Id: string;
2554
+ error_Key: string;
2555
+ message?: string | null;
2556
+ }[];
2557
+ }>;
2558
+ /** Optional: translate a server error key to localized text (bulk error reasons). */
2559
+ translate?(key: string): string | null | undefined;
2560
+ }
2561
+ declare const WORKFLOW_ACTIONS_PROVIDER: InjectionToken<WorkflowActionsProvider>;
2562
+ /** Row-level button color per transition type (APPROVE/REJECT/ESCALATE/default). */
2563
+ declare function workflowTransitionColor(code?: string | null): {
2564
+ row: string;
2565
+ bulk: string;
2566
+ };
2567
+ declare function workflowTransitionButtonClass(code?: string | null): string;
2568
+ /** DevExtreme `type` for the confirm / bulk buttons = the transition's consequence. */
2569
+ declare function workflowTransitionDxType(code?: string | null): 'success' | 'danger' | 'warning' | 'default';
2570
+
2571
+ /** Bulk mode: a transition executable on every selected document. */
2572
+ interface BulkTransition {
2573
+ /** Representative row (first document's) — label, tone and icon come from it. */
2574
+ transition: WorkflowAvailableTransition;
2575
+ requireNote: boolean;
2576
+ /** Each document's own transition row: the same label is a different row per state. */
2577
+ byDocument: Map<string, WorkflowAvailableTransition>;
2578
+ }
2579
+ declare class WorkflowActionsComponent implements OnChanges, OnDestroy {
2580
+ private wfProvider;
2581
+ private adapter;
2582
+ documentTypeId: string | null;
2583
+ documentId: string | null;
2584
+ documentNumber: string | null;
2585
+ /**
2586
+ * هل لنوع المستند دورة فعّالة في الكيان الحالي؟ الشاشات الديناميكية تمرّرها من
2587
+ * تعريف الشاشة (has_Active_Workflow). غير مُمرَّرة (شاشة استاتيك) ⟵ تُسأل الخدمة
2588
+ * بطلب خفيف واحد لكل نوع، بالتوازي مع context. تحدد مؤشر التحميل فقط؛ رد context
2589
+ * يبقى هو الحاكم لما يُعرض بعده.
2590
+ */
2591
+ hasWorkflow: boolean | null;
2592
+ /** إظهار «جارٍ تحميل دورة العمل…» أثناء loading. */
2593
+ showLoadingHint: boolean;
2594
+ containerClass: string;
2595
+ /**
2596
+ * Bulk mode — pass the grid's selected ids here instead of `documentId`. The component
2597
+ * then offers only the transitions executable on **every** selected document and runs
2598
+ * them through bulk-apply-transition. `null` (the default) keeps the single-document
2599
+ * mode every existing screen uses, untouched.
2600
+ */
2601
+ documentIds: string[] | null;
2602
+ /** Bulk mode only: raised after a run that changed at least one document. */
2603
+ bulkCompleted: EventEmitter<void>;
2604
+ get isBulkMode(): boolean;
2605
+ get documentDisplayValue(): string;
2606
+ changed: EventEmitter<WorkflowInstanceResult>;
2607
+ statusChanged: EventEmitter<string>;
2608
+ loading: boolean;
2609
+ instance: WorkflowInstanceResult | null;
2610
+ transitions: WorkflowAvailableTransition[];
2611
+ documentStatusName: string;
2612
+ confirmVisible: boolean;
2613
+ pendingTransition: WorkflowAvailableTransition | null;
2614
+ noteText: string;
2615
+ executing: boolean;
2616
+ bulkLoading: boolean;
2617
+ bulkTransitions: BulkTransition[];
2618
+ pendingBulk: BulkTransition | null;
2619
+ private bulkDocs;
2620
+ /**
2621
+ * How many selected documents have no workflow cycle (e.g. a «مرحّل» record that never
2622
+ * entered the cycle). Such a document has no actions, so it alone empties the shared
2623
+ * list — the message says so instead of a bare «no common action».
2624
+ */
2625
+ get bulkWithoutCycleCount(): number;
2626
+ private bulkLoadSeq;
2627
+ private loadPromise;
2628
+ private activeLoadKey;
2629
+ private lastLoadedKey;
2630
+ private reloadRequested;
2631
+ private readonly workflowUpdateSubscription;
2632
+ constructor(wfProvider: WorkflowActionsProvider, adapter: FormNavigatorAdapter);
2633
+ get isAr(): boolean;
2634
+ ngOnChanges(changes: SimpleChanges): Promise<void>;
2635
+ ngOnDestroy(): void;
2636
+ refresh(): Promise<void>;
2637
+ private load;
2638
+ private loadContext;
2639
+ /** معروفة من الشاشة ⟵ فورًا؛ وإلا لا مؤشر حتى يصل الرد الخفيف (لا ننتظره قبل context). */
2640
+ private resolveLoadingHint;
2641
+ onTransitionClick(tr: WorkflowAvailableTransition): void;
2642
+ get noteRequired(): boolean;
2643
+ get canConfirm(): boolean;
2644
+ confirmExecute(): Promise<void>;
2645
+ cancelConfirm(): void;
2646
+ onBulkTransitionClick(bulk: BulkTransition): void;
2647
+ /**
2648
+ * Reads each selected document's context (the same call the single mode makes, so a
2649
+ * draft's cycle starts lazily exactly as opening it would) and keeps the transitions
2650
+ * executable on all of them.
2651
+ */
2652
+ private loadBulk;
2653
+ /**
2654
+ * Transitions executable on every selected document. Matched by name because the same
2655
+ * label is a different transition row per state («إلغاء» leaves both «مسودة» and «معتمد»).
2656
+ * A document with no running cycle makes the intersection empty.
2657
+ */
2658
+ private commonTransitions;
2659
+ private confirmBulk;
2660
+ /**
2661
+ * bulk-apply-transition reports each failure as the exception's type name and raw
2662
+ * Message — for a business exception both are the localization key, not the text the
2663
+ * single path shows (that one is localized by ApiExceptionMiddleware).
2664
+ */
2665
+ private bulkErrorText;
2666
+ private emitAfterChange;
2667
+ get isCompleted(): boolean;
2668
+ get stateName(): string;
2669
+ get chainStates(): WorkflowStateChain[];
2670
+ get pathStates(): WorkflowStateChain[];
2671
+ chainStateName(s: WorkflowStateChain): string;
2672
+ /**
2673
+ * ثلاث حالات بصرية لا اثنتان:
2674
+ * الحالية → بارزة (زرقاء بإطار)
2675
+ * مرّ بها → مؤكَّدة لكن هادئة (خضراء باهتة)
2676
+ * لم يصلها → باهتة
2677
+ * و «مرّ بها» يحسبها الخادم من سجل الحركة، فالرجوع للخلف يُطفئ ما بعده.
2678
+ */
2679
+ chainStateClass(s: WorkflowStateChain): string;
2680
+ transitionName(tr: WorkflowAvailableTransition): string;
2681
+ transitionButtonClass(tr: WorkflowAvailableTransition): string;
2682
+ /** DevExtreme `type` of the confirm button = the pending transition's consequence. */
2683
+ get pendingTransitionType(): 'success' | 'danger' | 'warning' | 'default';
2684
+ /**
2685
+ * مفتاح سبب التعطيل كما أرسله الخادم — نفس مفتاح الاستثناء الذي يردّه عند
2686
+ * محاولة التجاوز، فلا تفترق رسالة التلميح عن رسالة الرفض.
2687
+ */
2688
+ transitionDisabledKey(tr: WorkflowAvailableTransition): string;
2689
+ /**
2690
+ * The API's `{ error: { message, details } }` body. ErrorInterceptor re-throws non-GET
2691
+ * failures as a plain `Error` (message = the server text) and keeps the HttpErrorResponse
2692
+ * on `.original`; GET failures and throttled ones arrive as the raw HttpErrorResponse.
2693
+ * Reading only `err.error.error` missed the first shape, so every rejected transition
2694
+ * showed the generic text instead of the server's reason.
2695
+ */
2696
+ private errorBody;
2697
+ private extractError;
2698
+ static ɵfac: i0.ɵɵFactoryDeclaration<WorkflowActionsComponent, never>;
2699
+ static ɵcmp: i0.ɵɵComponentDeclaration<WorkflowActionsComponent, "app-workflow-actions", never, { "documentTypeId": { "alias": "documentTypeId"; "required": false; }; "documentId": { "alias": "documentId"; "required": false; }; "documentNumber": { "alias": "documentNumber"; "required": false; }; "hasWorkflow": { "alias": "hasWorkflow"; "required": false; }; "containerClass": { "alias": "containerClass"; "required": false; }; "documentIds": { "alias": "documentIds"; "required": false; }; }, { "bulkCompleted": "bulkCompleted"; "changed": "changed"; "statusChanged": "statusChanged"; }, never, never, true, never>;
2700
+ }
2701
+
2702
+ /**
2703
+ * نافذة تأكيد تنفيذ انتقال دورة عمل — مشتركة بين شريط الدورة على المستند
2704
+ * (workflow-actions) و«اعتماداتي» (فردي وجماعي)، فيبقى الشكل والسلوك واحدًا.
2705
+ *
2706
+ * الشكل: زر التنفيذ بلون نتيجة الانتقال (Tint) و«لا» نصّي بجانبه،
2707
+ * متجاوران في نهاية السطر (يسار في العربي).
2708
+ */
2709
+ declare class WorkflowConfirmDialogComponent {
2710
+ visible: boolean;
2711
+ visibleChange: EventEmitter<boolean>;
2712
+ /** عنوان بديل (مثل «تنفيذ جماعي»)؛ الافتراضي «تأكيد الإجراء». */
2713
+ title?: string | null;
2714
+ /** اسم الانتقال المعروض. */
2715
+ actionName: string;
2716
+ /** رمز نوع الانتقال (APPROVE / REJECT / …) — يحدد لون زر التنفيذ. */
2717
+ transitionTypeCode?: string | null;
2718
+ /** رقم المستند في التنفيذ الفردي. */
2719
+ documentNumber?: string | null;
2720
+ /** عدد العناصر في التنفيذ الجماعي (يُقدَّم على documentNumber إن وُجد). */
2721
+ itemsCount?: number | null;
2722
+ noteRequired: boolean;
2723
+ note: string;
2724
+ noteChange: EventEmitter<string>;
2725
+ executing: boolean;
2726
+ confirmed: EventEmitter<void>;
2727
+ cancelled: EventEmitter<void>;
2728
+ get isBulk(): boolean;
2729
+ get buttonType(): 'success' | 'danger' | 'warning' | 'default';
2730
+ get canConfirm(): boolean;
2731
+ onVisibleChange(value: boolean): void;
2732
+ onNoteChange(value: string): void;
2733
+ confirm(): void;
2734
+ cancel(): void;
2735
+ static ɵfac: i0.ɵɵFactoryDeclaration<WorkflowConfirmDialogComponent, never>;
2736
+ static ɵcmp: i0.ɵɵComponentDeclaration<WorkflowConfirmDialogComponent, "app-workflow-confirm-dialog", never, { "visible": { "alias": "visible"; "required": false; }; "title": { "alias": "title"; "required": false; }; "actionName": { "alias": "actionName"; "required": false; }; "transitionTypeCode": { "alias": "transitionTypeCode"; "required": false; }; "documentNumber": { "alias": "documentNumber"; "required": false; }; "itemsCount": { "alias": "itemsCount"; "required": false; }; "noteRequired": { "alias": "noteRequired"; "required": false; }; "note": { "alias": "note"; "required": false; }; "executing": { "alias": "executing"; "required": false; }; }, { "visibleChange": "visibleChange"; "noteChange": "noteChange"; "confirmed": "confirmed"; "cancelled": "cancelled"; }, never, never, true, never>;
2737
+ }
2738
+
2739
+ /**
2740
+ * Host-supplied services for the workflow toolbar.
2741
+ *
2742
+ * Shaped to match Flexora's `WorkflowActionService` structurally so the host
2743
+ * can wire it with `{ provide: WORKFLOW_TOOLBAR_PROVIDER, useExisting: WorkflowActionService }`.
2744
+ * Other hosts implement the two methods however they load/map their workflow actions.
2745
+ */
2746
+ interface WorkflowToolbarProvider {
2747
+ /** Available actions for (workflowId, statusId). */
2748
+ getAvailableWorkflowActions(workflowId: any, statusId: any): Observable<any[]>;
2749
+ /**
2750
+ * Maps raw action DTOs to toolbar items ({ text, iconClass, btnClass, hint,
2751
+ * onClick, disabled?, visible? }). The callback executes one action.
2752
+ */
2753
+ mapWorkflowActionsItems(actions: any[], applyWorkflowCallback: (actionId: any) => Promise<void>): any[];
2754
+ }
2755
+ declare const WORKFLOW_TOOLBAR_PROVIDER: InjectionToken<WorkflowToolbarProvider>;
2756
+
2757
+ interface WorkflowToolbarItem {
2758
+ text: string;
2759
+ iconClass?: string;
2760
+ btnClass?: string;
2761
+ hint?: string;
2762
+ onClick?: () => void;
2763
+ disabled?: boolean;
2764
+ visible?: boolean;
2765
+ }
2766
+ declare class WorkflowToolbarComponent implements OnChanges {
2767
+ private workflowProvider;
2768
+ private adapter;
2769
+ containerClass: string;
2770
+ showEmpty: boolean;
2771
+ compact: boolean;
2772
+ workflowId?: Guid | null;
2773
+ statusId?: Guid | null;
2774
+ documentId?: Guid | null;
2775
+ applyWorkflowCallback?: (actionId: Guid, documentId: Guid | null) => Promise<any[]>;
2776
+ /**
2777
+ * Optional hook run AFTER a workflow action succeeds. The host (screen) uses
2778
+ * it to refresh its grid and return the affected record's NEW status id; the
2779
+ * toolbar then reloads its own buttons for that new status. This centralizes
2780
+ * the "reload the buttons after any action" behaviour here instead of each
2781
+ * screen re-implementing it. When not provided, the toolbar falls back to
2782
+ * mapping the actions returned by applyWorkflowCallback (single-record flows).
2783
+ */
2784
+ resolveStatusAfterApply?: () => Promise<Guid | null | undefined>;
2785
+ toolbarItems: WorkflowToolbarItem[];
2786
+ constructor(workflowProvider: WorkflowToolbarProvider, adapter: FormNavigatorAdapter);
2787
+ get visibleItems(): WorkflowToolbarItem[];
2788
+ ngOnChanges(changes: SimpleChanges): Promise<void>;
2789
+ private loadWorkflowActions;
2790
+ private mapWorkflowActionsItems;
2791
+ applyWorkflow(actionId: Guid): Promise<void>;
2792
+ onItemClick(item: WorkflowToolbarItem): void;
2793
+ trackByFn(index: number, item: WorkflowToolbarItem): string;
2794
+ static ɵfac: i0.ɵɵFactoryDeclaration<WorkflowToolbarComponent, never>;
2795
+ static ɵcmp: i0.ɵɵComponentDeclaration<WorkflowToolbarComponent, "app-workflow-toolbar", never, { "containerClass": { "alias": "containerClass"; "required": false; }; "showEmpty": { "alias": "showEmpty"; "required": false; }; "compact": { "alias": "compact"; "required": false; }; "workflowId": { "alias": "workflowId"; "required": false; }; "statusId": { "alias": "statusId"; "required": false; }; "documentId": { "alias": "documentId"; "required": false; }; "applyWorkflowCallback": { "alias": "applyWorkflowCallback"; "required": false; }; "resolveStatusAfterApply": { "alias": "resolveStatusAfterApply"; "required": false; }; }, {}, never, never, true, never>;
2796
+ }
2797
+
2798
+ export { AppBorderWrapperComponent, AppPopupFullScreenDirective, AppSmartLookupComponent, AppToolbarComponent, AppToolbarItemComponent, DxDateBoxRangeComponent, DxFormItemsOutletDirective, EditFormButtonsComponent, EquationEditorComponent, FILE_MANAGER_PROVIDER, FINANCIAL_DIMENSIONS_PROVIDER, FINANCIAL_DIMENSION_VALUES_PROVIDER, FORM_NAVIGATOR_ADAPTER, FileEditComponent, FileManagerComponent, FilterPanelComponent, FinancialDimensionValuesComponent, FinancialDimensionsPopupComponent, FnIconComponent, FormModeEnum, FormNavigatorComponent, GridLookupComponent, GroupingLevelComponent, INFO_USER_PROVIDER, ImageEditComponent, InfoPopupComponent, JOURNAL_ENTRY_VIEWER_PROVIDER, JournalEntryViewerComponent, LINQ_SELECT_COMMAND_TYPE, LOOKUP_DATA_PROVIDER, LOOKUP_GRID_PROVIDER, LookupDynamicGridComponent, LookupEditComponent, LookupPopupComponent, LookupValueType, MapLocationPickerComponent, MessageContentPopupComponent, PermissionSelectorComponent, PermissionSelectorItemComponent, PermissionType, PopupFullScreenToggle, QueryActionsToolbarComponent, RECORD_CHANGE_LOG_PROVIDER, RECORD_SUBSCRIPTION_PROVIDER, REUSABLE_COMPONENTS_CONFIG, ReceiptPreviewComponent, RecordChangeLogPopupComponent, ReportWorkflowActionsComponent, ReversalDatePopupComponent, SaveOnlyButtonsComponent, SelectBoxWithLinkComponent, SmartLookupHostService, SubscribeButtonComponent, TriggerSaveModeEnum, WORKFLOW_ACTIONS_PROVIDER, WORKFLOW_TOOLBAR_PROVIDER, WorkflowActionsComponent, WorkflowConfirmDialogComponent, WorkflowToolbarComponent, isEmbeddedFormHost, lookupValueToArray, provideLookup, provideReusableComponents, workflowTransitionButtonClass, workflowTransitionColor, workflowTransitionDxType };
2799
+ export type { AppToolbarItemLocation, AppliedFilter, CreateFn, DimensionSelectionsMap, EmbeddedFormHost, EquationLine, FileManagerProvider, FilterRangePair, FinancialDimensionValueRow, FinancialDimensionValueVm, FinancialDimensionValuesProvider, FinancialDimensionVm, FinancialDimensionsProvider, FnIconAccent, FnIconName, FormNavigatorAdapter, FormNavigatorMessages, FormNavigatorPermissions, GroupingLevelValue, InfoUserProvider, JournalEntryViewerProvider, LoadFn, LookupAsync, LookupColumn, LookupContext, LookupDataProvider, LookupGridProvider, LookupItem, LookupKey, LookupSearchResult, MessageContentPopupData, PermissionItem, RecordChangeEntry, RecordChangeLogProvider, RecordChangeLogResult, RecordSubscriptionItem, RecordSubscriptionProvider, ReusableComponentsConfig, ReversalConfirmation, ReversalDetailItem, RuleChangeEvent, SecurityRuleItem, SubscriptionPrefs, WorkflowActionsProvider, WorkflowApplyTransitionInput, WorkflowAvailableTransition, WorkflowDocumentContext, WorkflowInstanceResult, WorkflowStateChain, WorkflowToolbarItem, WorkflowToolbarProvider, WorkflowUpdatedNotification };