mesauth-angular 1.5.5 → 1.6.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/README.md +12 -1
- package/fesm2022/mesauth-angular.mjs +211 -20
- package/fesm2022/mesauth-angular.mjs.map +1 -1
- package/index.d.ts +28 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -4,12 +4,23 @@ Angular helper library to connect to a backend API and SignalR hub to surface th
|
|
|
4
4
|
|
|
5
5
|
## Changelog
|
|
6
6
|
|
|
7
|
+
### v1.6.0 (2026-03-28) - **Approval Module Enhancements**
|
|
8
|
+
- **`[templateId]` locks routing UI**: When bound, the routing mode toggle and template dropdown are hidden — the template name is shown as read-only. Role-based steps auto-load candidate pickers from `GET /approval/roles/preview`; the requester selects one user per step before submitting. Pass as number binding: `[templateId]="6"`.
|
|
9
|
+
- **`(approvalSubmitting)` output** *(corrected from single-t typo)*: Fires before content capture starts. Use it to hide edit controls (`*ngIf="!isSubmitting"`) so they are excluded from the approval snapshot. Angular CD runs after the emit so DOM updates are captured.
|
|
10
|
+
- **Automatic theme support**: `<ma-arv-container>` applies `ThemeService` internally — adapts to the app's light/dark theme via `@HostBinding('class')` with no extra setup.
|
|
11
|
+
- **`previewRole(orgCode, level)`** added to `MaApprovalService`: Fetch candidate users for a role-based approval step.
|
|
12
|
+
- **Callback security**: MesAuth.Api sends `X-APP-ID` + `X-APP-KEY` headers on every callback POST using its own app credentials. Protect callback endpoints with `[MesAuth]` from `MesAuth.Authorizer`.
|
|
13
|
+
|
|
7
14
|
### v1.5.0 (2026-03-24) - **Approval Module**
|
|
8
15
|
- **New `<ma-approval-panel>` component**: Slide-out sidebar with 3 tabs (Processing / Approved / Rejected). Shows all pending approvals requiring action, and recent approved/rejected items. Listens to `approvalEvents$` for real-time refresh via SignalR.
|
|
9
16
|
- **New `<ma-arv-container>` component**: Content capture container for submitting documents for approval. Captures projected `<ng-content>` as a self-contained HTML document by inlining all computed styles, replacing canvas elements with images, and stripping Angular/script artifacts. Supports ad-hoc step builder and template selector.
|
|
10
|
-
-
|
|
17
|
+
- **`[templateId]` locks routing UI**: When bound, the routing mode toggle and template dropdown are hidden — the template name is shown as read-only. Role-based steps auto-load candidate pickers from `GET /approval/roles/preview`; the requester selects one user per step before submitting. Pass as number binding: `[templateId]="6"`.
|
|
18
|
+
- **`(approvalSubmitting)` output** *(corrected from single-t typo)*: Fires before content capture starts. Use it to hide edit controls (`*ngIf="!isSubmitting"`) so they are excluded from the approval snapshot. Angular CD runs after the emit so DOM updates are captured.
|
|
19
|
+
- **Automatic theme support**: Applies `ThemeService` internally — adapts to the app's light/dark theme via `@HostBinding('class')` with no extra setup.
|
|
20
|
+
- **New `MaApprovalService`**: Service for all approval API calls — `getPendingApprovals()`, `getMyRequests()`, `getDashboard()`, `approve()`, `reject()`, `delegate()`, `getTemplates()`, `createApproval()`, `previewRole(orgCode, level)`, etc. Manual init pattern (same as `MesAuthService`).
|
|
11
21
|
- **Approval icon in `ma-user-profile`**: Clipboard/checkmark icon button added between notification bell and avatar. Shows pending count badge. Emits `approvalClick` output for panel toggle.
|
|
12
22
|
- **`approvalEvents$` observable in `MesAuthService`**: Real-time SignalR events (`ApprovalCompleted`, `ApprovalStepChanged`) exposed as an observable stream.
|
|
23
|
+
- **Callback security**: MesAuth.Api sends `X-APP-ID` + `X-APP-KEY` headers on every callback POST using its own app credentials. Protect callback endpoints with `[MesAuth]` from `MesAuth.Authorizer`.
|
|
13
24
|
- **New exports**: `MaApprovalService`, `MaApprovalPanelComponent`, `MaArvContainerComponent`, and all approval model interfaces/enums.
|
|
14
25
|
|
|
15
26
|
### v1.4.0 (2026-03-20) - **Remove Unused Route Registration API**
|
|
@@ -3,7 +3,7 @@ import { InjectionToken, makeEnvironmentProviders, provideAppInitializer, inject
|
|
|
3
3
|
import * as i4 from '@angular/common/http';
|
|
4
4
|
import { HttpClient } from '@angular/common/http';
|
|
5
5
|
import { HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
|
|
6
|
-
import { BehaviorSubject, Subject, EMPTY, of, timer, throwError } from 'rxjs';
|
|
6
|
+
import { BehaviorSubject, Subject, EMPTY, of, timer, throwError, forkJoin } from 'rxjs';
|
|
7
7
|
import { tap, catchError, switchMap, takeUntil } from 'rxjs/operators';
|
|
8
8
|
import * as i2 from '@angular/router';
|
|
9
9
|
import { Router } from '@angular/router';
|
|
@@ -1253,7 +1253,7 @@ class NotificationPanelComponent {
|
|
|
1253
1253
|
</div>
|
|
1254
1254
|
<div class="modal-body" *ngIf="!selectedNotificationUrl" [innerHTML]="selectedNotificationHtml"></div>
|
|
1255
1255
|
<div class="modal-body modal-body-iframe" *ngIf="selectedNotificationUrl">
|
|
1256
|
-
<iframe [src]="selectedNotificationUrl" sandbox="allow-same-origin" class="notification-iframe"></iframe>
|
|
1256
|
+
<iframe [src]="selectedNotificationUrl" sandbox="allow-same-origin allow-scripts" class="notification-iframe"></iframe>
|
|
1257
1257
|
</div>
|
|
1258
1258
|
<div class="modal-footer">
|
|
1259
1259
|
<button class="action-btn" (click)="closeDetails()">Close</button>
|
|
@@ -1415,7 +1415,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
1415
1415
|
</div>
|
|
1416
1416
|
<div class="modal-body" *ngIf="!selectedNotificationUrl" [innerHTML]="selectedNotificationHtml"></div>
|
|
1417
1417
|
<div class="modal-body modal-body-iframe" *ngIf="selectedNotificationUrl">
|
|
1418
|
-
<iframe [src]="selectedNotificationUrl" sandbox="allow-same-origin" class="notification-iframe"></iframe>
|
|
1418
|
+
<iframe [src]="selectedNotificationUrl" sandbox="allow-same-origin allow-scripts" class="notification-iframe"></iframe>
|
|
1419
1419
|
</div>
|
|
1420
1420
|
<div class="modal-footer">
|
|
1421
1421
|
<button class="action-btn" (click)="closeDetails()">Close</button>
|
|
@@ -1508,6 +1508,9 @@ class MaApprovalService {
|
|
|
1508
1508
|
deleteTemplate(id) {
|
|
1509
1509
|
return this.http.delete(`${this.apiBase}/approval/templates/${id}`, this.opts);
|
|
1510
1510
|
}
|
|
1511
|
+
previewRole(orgCode, level) {
|
|
1512
|
+
return this.http.get(`${this.apiBase}/approval/roles/preview?orgCode=${encodeURIComponent(orgCode)}&level=${encodeURIComponent(level)}`, this.opts);
|
|
1513
|
+
}
|
|
1511
1514
|
// ====================== Create (used by ma-arv-container) ======================
|
|
1512
1515
|
createApproval(request) {
|
|
1513
1516
|
return this.http.post(`${this.apiBase}/approval/documents`, request, this.opts);
|
|
@@ -2016,12 +2019,18 @@ class MaArvContainerComponent {
|
|
|
2016
2019
|
callbackUrl;
|
|
2017
2020
|
deadlineHours;
|
|
2018
2021
|
approvalSubmitted = new EventEmitter();
|
|
2019
|
-
|
|
2022
|
+
approvalSubmitting = new EventEmitter();
|
|
2020
2023
|
cancelled = new EventEmitter();
|
|
2021
2024
|
contentBody;
|
|
2022
2025
|
routingMode = 'template';
|
|
2023
2026
|
templates = [];
|
|
2024
2027
|
selectedTemplateId = null;
|
|
2028
|
+
selectedTemplate = null;
|
|
2029
|
+
loadingTemplate = false;
|
|
2030
|
+
// Per-step role candidates and selected user
|
|
2031
|
+
stepCandidates = [];
|
|
2032
|
+
stepLoadingCandidates = [];
|
|
2033
|
+
stepSelectedUsers = [];
|
|
2025
2034
|
adHocSteps = [];
|
|
2026
2035
|
referenceUserIds = [];
|
|
2027
2036
|
refSearchQuery = '';
|
|
@@ -2032,11 +2041,17 @@ class MaArvContainerComponent {
|
|
|
2032
2041
|
isSubmitted = false;
|
|
2033
2042
|
errorMessage = '';
|
|
2034
2043
|
userLabelMap = {};
|
|
2044
|
+
get themeClass() { return `theme-${this.currentTheme}`; }
|
|
2045
|
+
currentTheme = 'light';
|
|
2035
2046
|
destroy$ = new Subject();
|
|
2036
2047
|
mesAuth = inject(MesAuthService);
|
|
2048
|
+
themeService = inject(ThemeService);
|
|
2037
2049
|
approvalSvc = null;
|
|
2038
2050
|
http = inject(HttpClient);
|
|
2039
2051
|
ngOnInit() {
|
|
2052
|
+
this.themeService.currentTheme$
|
|
2053
|
+
.pipe(takeUntil(this.destroy$))
|
|
2054
|
+
.subscribe(t => this.currentTheme = t);
|
|
2040
2055
|
const config = this.mesAuth.getConfig();
|
|
2041
2056
|
if (config) {
|
|
2042
2057
|
this.approvalSvc = new MaApprovalService();
|
|
@@ -2051,13 +2066,63 @@ class MaArvContainerComponent {
|
|
|
2051
2066
|
}
|
|
2052
2067
|
loadTemplates() {
|
|
2053
2068
|
this.approvalSvc.getTemplates().pipe(takeUntil(this.destroy$)).subscribe({
|
|
2054
|
-
next: (t) =>
|
|
2069
|
+
next: (t) => {
|
|
2070
|
+
this.templates = t;
|
|
2071
|
+
if (this.templateId != null && this.selectedTemplateId == null) {
|
|
2072
|
+
this.selectedTemplateId = this.templateId;
|
|
2073
|
+
this.loadTemplateDetail(this.templateId);
|
|
2074
|
+
}
|
|
2075
|
+
},
|
|
2055
2076
|
error: () => { }
|
|
2056
2077
|
});
|
|
2057
2078
|
}
|
|
2079
|
+
loadTemplateDetail(id) {
|
|
2080
|
+
this.loadingTemplate = true;
|
|
2081
|
+
this.selectedTemplate = null;
|
|
2082
|
+
this.stepCandidates = [];
|
|
2083
|
+
this.stepLoadingCandidates = [];
|
|
2084
|
+
this.stepSelectedUsers = [];
|
|
2085
|
+
this.approvalSvc.getTemplate(id).pipe(takeUntil(this.destroy$)).subscribe({
|
|
2086
|
+
next: (t) => {
|
|
2087
|
+
this.selectedTemplate = t;
|
|
2088
|
+
this.loadingTemplate = false;
|
|
2089
|
+
this.loadStepCandidates(t.steps);
|
|
2090
|
+
},
|
|
2091
|
+
error: () => { this.loadingTemplate = false; }
|
|
2092
|
+
});
|
|
2093
|
+
}
|
|
2094
|
+
loadStepCandidates(steps) {
|
|
2095
|
+
this.stepCandidates = steps.map(() => []);
|
|
2096
|
+
this.stepLoadingCandidates = steps.map(() => false);
|
|
2097
|
+
this.stepSelectedUsers = steps.map(() => '');
|
|
2098
|
+
steps.forEach((step, i) => {
|
|
2099
|
+
if (!step.roles || step.roles.length === 0)
|
|
2100
|
+
return;
|
|
2101
|
+
this.stepLoadingCandidates[i] = true;
|
|
2102
|
+
const calls = step.roles.map(r => this.approvalSvc.previewRole(r.orgCode, r.positionLevel));
|
|
2103
|
+
forkJoin(calls.length > 0 ? calls : [of([])])
|
|
2104
|
+
.pipe(takeUntil(this.destroy$))
|
|
2105
|
+
.subscribe({
|
|
2106
|
+
next: results => {
|
|
2107
|
+
const merged = new Map();
|
|
2108
|
+
results.forEach(list => list.forEach(u => merged.set(u.userId, u)));
|
|
2109
|
+
this.stepCandidates[i] = Array.from(merged.values());
|
|
2110
|
+
this.stepLoadingCandidates[i] = false;
|
|
2111
|
+
},
|
|
2112
|
+
error: () => { this.stepLoadingCandidates[i] = false; }
|
|
2113
|
+
});
|
|
2114
|
+
});
|
|
2115
|
+
}
|
|
2116
|
+
onStepUserChange(stepIndex, event) {
|
|
2117
|
+
this.stepSelectedUsers[stepIndex] = event.target.value;
|
|
2118
|
+
}
|
|
2058
2119
|
onTemplateChange(event) {
|
|
2059
2120
|
const val = event.target.value;
|
|
2060
2121
|
this.selectedTemplateId = val ? parseInt(val, 10) : null;
|
|
2122
|
+
this.selectedTemplate = null;
|
|
2123
|
+
if (this.selectedTemplateId) {
|
|
2124
|
+
this.loadTemplateDetail(this.selectedTemplateId);
|
|
2125
|
+
}
|
|
2061
2126
|
}
|
|
2062
2127
|
addStep() {
|
|
2063
2128
|
const order = this.adHocSteps.length + 1;
|
|
@@ -2138,6 +2203,8 @@ class MaArvContainerComponent {
|
|
|
2138
2203
|
.catch(() => []);
|
|
2139
2204
|
}
|
|
2140
2205
|
async submit() {
|
|
2206
|
+
if (this.submitting)
|
|
2207
|
+
return;
|
|
2141
2208
|
this.errorMessage = '';
|
|
2142
2209
|
if (!this.approvalSvc) {
|
|
2143
2210
|
this.errorMessage = 'Approval service not initialized. Ensure provideMesAuth() is configured.';
|
|
@@ -2159,10 +2226,21 @@ class MaArvContainerComponent {
|
|
|
2159
2226
|
this.errorMessage = 'Please add at least one approval step.';
|
|
2160
2227
|
return;
|
|
2161
2228
|
}
|
|
2162
|
-
|
|
2163
|
-
if (this.
|
|
2164
|
-
this.
|
|
2229
|
+
// Validate role-based steps have a selected approver
|
|
2230
|
+
if (this.routingMode === 'template' && this.selectedTemplate) {
|
|
2231
|
+
for (let i = 0; i < this.selectedTemplate.steps.length; i++) {
|
|
2232
|
+
const step = this.selectedTemplate.steps[i];
|
|
2233
|
+
if (step.roles?.length > 0 && !this.stepSelectedUsers[i]) {
|
|
2234
|
+
this.errorMessage = `Please select an approver for step "${step.stepName}".`;
|
|
2235
|
+
return;
|
|
2236
|
+
}
|
|
2237
|
+
}
|
|
2165
2238
|
}
|
|
2239
|
+
// Emit before capture so parent can hide edit controls (inputs, buttons)
|
|
2240
|
+
// then wait one tick for Angular CD to update the DOM before snapshotting
|
|
2241
|
+
this.approvalSubmitting.emit();
|
|
2242
|
+
await new Promise(resolve => setTimeout(resolve));
|
|
2243
|
+
this.submitting = true;
|
|
2166
2244
|
try {
|
|
2167
2245
|
const contentHtml = await this.captureContent();
|
|
2168
2246
|
const thumbnailBase64 = await this.captureThumbnail().catch(() => undefined);
|
|
@@ -2178,6 +2256,20 @@ class MaArvContainerComponent {
|
|
|
2178
2256
|
};
|
|
2179
2257
|
if (this.routingMode === 'template') {
|
|
2180
2258
|
request.templateId = this.selectedTemplateId ?? this.templateId;
|
|
2259
|
+
// If template has role-based steps with selected approvers, pass explicit steps
|
|
2260
|
+
if (this.selectedTemplate) {
|
|
2261
|
+
const hasRoleSteps = this.selectedTemplate.steps.some(s => s.roles?.length > 0);
|
|
2262
|
+
if (hasRoleSteps) {
|
|
2263
|
+
request.steps = this.selectedTemplate.steps.map((s, i) => ({
|
|
2264
|
+
stepOrder: s.stepOrder,
|
|
2265
|
+
stepName: s.stepName,
|
|
2266
|
+
mode: s.mode,
|
|
2267
|
+
approverUserIds: s.roles?.length > 0
|
|
2268
|
+
? (this.stepSelectedUsers[i] ? [this.stepSelectedUsers[i]] : s.assigneeUserIds)
|
|
2269
|
+
: s.assigneeUserIds
|
|
2270
|
+
}));
|
|
2271
|
+
}
|
|
2272
|
+
}
|
|
2181
2273
|
}
|
|
2182
2274
|
else {
|
|
2183
2275
|
request.steps = this.adHocSteps.map((s, i) => ({
|
|
@@ -2328,7 +2420,7 @@ ${clone.outerHTML}
|
|
|
2328
2420
|
];
|
|
2329
2421
|
}
|
|
2330
2422
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: MaArvContainerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2331
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: MaArvContainerComponent, isStandalone: true, selector: "ma-arv-container", inputs: { title: "title", description: "description", referenceId: "referenceId", templateId: "templateId", callbackUrl: "callbackUrl", deadlineHours: "deadlineHours" }, outputs: { approvalSubmitted: "approvalSubmitted",
|
|
2423
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "20.3.18", type: MaArvContainerComponent, isStandalone: true, selector: "ma-arv-container", inputs: { title: "title", description: "description", referenceId: "referenceId", templateId: "templateId", callbackUrl: "callbackUrl", deadlineHours: "deadlineHours" }, outputs: { approvalSubmitted: "approvalSubmitted", approvalSubmitting: "approvalSubmitting", cancelled: "cancelled" }, host: { properties: { "class": "this.themeClass" } }, viewQueries: [{ propertyName: "contentBody", first: true, predicate: ["contentBody"], descendants: true, static: true }], ngImport: i0, template: `
|
|
2332
2424
|
<div class="arv-container">
|
|
2333
2425
|
<!-- Content Area -->
|
|
2334
2426
|
<div class="arv-content-body" #contentBody>
|
|
@@ -2343,7 +2435,8 @@ ${clone.outerHTML}
|
|
|
2343
2435
|
<div class="arv-routing">
|
|
2344
2436
|
<div class="arv-routing-header">
|
|
2345
2437
|
<h4 class="arv-section-title">Approval Routing</h4>
|
|
2346
|
-
|
|
2438
|
+
<!-- Show routing toggle only when templateId is NOT locked -->
|
|
2439
|
+
<div *ngIf="!templateId" class="arv-routing-mode">
|
|
2347
2440
|
<label class="arv-radio">
|
|
2348
2441
|
<input type="radio" name="routingMode" value="template" [checked]="routingMode === 'template'" (change)="routingMode = 'template'"> Use Template
|
|
2349
2442
|
</label>
|
|
@@ -2353,15 +2446,62 @@ ${clone.outerHTML}
|
|
|
2353
2446
|
</div>
|
|
2354
2447
|
</div>
|
|
2355
2448
|
|
|
2356
|
-
<!--
|
|
2357
|
-
<div *ngIf="routingMode === 'template'" class="arv-template-select">
|
|
2449
|
+
<!-- Locked template: show name only, no selector -->
|
|
2450
|
+
<div *ngIf="templateId && routingMode === 'template'" class="arv-template-select">
|
|
2451
|
+
<div *ngIf="loadingTemplate" class="arv-template-loading">Loading template...</div>
|
|
2452
|
+
<div *ngIf="selectedTemplate && !loadingTemplate" class="arv-locked-template">
|
|
2453
|
+
<span class="arv-locked-label">Template</span>
|
|
2454
|
+
<span class="arv-locked-name">{{ selectedTemplate.name }}</span>
|
|
2455
|
+
</div>
|
|
2456
|
+
</div>
|
|
2457
|
+
|
|
2458
|
+
<!-- Free template selector (no locked templateId) -->
|
|
2459
|
+
<div *ngIf="!templateId && routingMode === 'template'" class="arv-template-select">
|
|
2358
2460
|
<label class="arv-label">Select Template</label>
|
|
2359
2461
|
<select class="arv-select" (change)="onTemplateChange($event)">
|
|
2360
2462
|
<option value="">-- Select a template --</option>
|
|
2361
|
-
<option *ngFor="let t of templates" [value]="t.id">{{ t.name }}</option>
|
|
2463
|
+
<option *ngFor="let t of templates" [value]="t.id" [selected]="t.id === selectedTemplateId">{{ t.name }}</option>
|
|
2362
2464
|
</select>
|
|
2363
2465
|
</div>
|
|
2364
2466
|
|
|
2467
|
+
<!-- Step pickers (shared for both locked and free template) -->
|
|
2468
|
+
<div *ngIf="routingMode === 'template'" class="arv-template-select">
|
|
2469
|
+
<div *ngIf="!loadingTemplate && selectedTemplate" class="arv-template-steps">
|
|
2470
|
+
<div class="arv-step-card" *ngFor="let s of selectedTemplate.steps; let i = index">
|
|
2471
|
+
<div class="arv-step-card-header">
|
|
2472
|
+
<span class="arv-step-preview-num">Step {{ s.stepOrder }}</span>
|
|
2473
|
+
<span class="arv-step-preview-name">{{ s.stepName }}</span>
|
|
2474
|
+
<span *ngIf="s.roles && s.roles.length > 0" class="arv-step-role-badge">
|
|
2475
|
+
{{ s.roles[0].positionLevel }}{{ s.roles[0].orgName ? ' · ' + s.roles[0].orgName : '' }}
|
|
2476
|
+
</span>
|
|
2477
|
+
</div>
|
|
2478
|
+
<!-- Role-based step: show approver picker -->
|
|
2479
|
+
<div *ngIf="s.roles && s.roles.length > 0" class="arv-step-picker">
|
|
2480
|
+
<div *ngIf="stepLoadingCandidates[i]" class="arv-template-loading">Loading candidates...</div>
|
|
2481
|
+
<select *ngIf="!stepLoadingCandidates[i]" class="arv-select arv-select-sm"
|
|
2482
|
+
(change)="onStepUserChange(i, $event)">
|
|
2483
|
+
<option value="">-- Select approver --</option>
|
|
2484
|
+
<option *ngFor="let u of stepCandidates[i]" [value]="u.userId"
|
|
2485
|
+
[selected]="u.userId === stepSelectedUsers[i]">
|
|
2486
|
+
{{ u.fullName || u.userId }}{{ u.department ? ' · ' + u.department : '' }}{{ u.position ? ' (' + u.position + ')' : '' }}
|
|
2487
|
+
</option>
|
|
2488
|
+
</select>
|
|
2489
|
+
<div *ngIf="!stepLoadingCandidates[i] && stepCandidates[i]?.length === 0" class="arv-template-loading">
|
|
2490
|
+
No candidates found for this role.
|
|
2491
|
+
</div>
|
|
2492
|
+
</div>
|
|
2493
|
+
<!-- Fixed-user step -->
|
|
2494
|
+
<div *ngIf="!s.roles || s.roles.length === 0" class="arv-step-fixed">
|
|
2495
|
+
{{ s.assigneeUserIds.length }} pre-configured approver(s)
|
|
2496
|
+
</div>
|
|
2497
|
+
</div>
|
|
2498
|
+
<div *ngIf="selectedTemplate.referenceUserIds.length > 0" class="arv-step-preview arv-step-preview-cc">
|
|
2499
|
+
<span class="arv-step-preview-num">CC</span>
|
|
2500
|
+
<span class="arv-step-preview-name">{{ selectedTemplate.referenceUserIds.length }} reference user(s) from template</span>
|
|
2501
|
+
</div>
|
|
2502
|
+
</div>
|
|
2503
|
+
</div>
|
|
2504
|
+
|
|
2365
2505
|
<!-- Ad-hoc steps -->
|
|
2366
2506
|
<div *ngIf="routingMode === 'adhoc'" class="arv-steps">
|
|
2367
2507
|
<div class="arv-step" *ngFor="let step of adHocSteps; let i = index">
|
|
@@ -2443,7 +2583,7 @@ ${clone.outerHTML}
|
|
|
2443
2583
|
<p>Submitted for approval successfully.</p>
|
|
2444
2584
|
</div>
|
|
2445
2585
|
</div>
|
|
2446
|
-
`, isInline: true, styles: [":host{display:block;--arv-primary: #90caf9;--arv-primary-hover: #64b5f6;--arv-success: #66bb6a;--arv-danger: #ef5350;--arv-text: #e0e0e0;--arv-text-muted: #9e9e9e;--arv-bg: #1e1e2e;--arv-bg2: #27273a;--arv-border: #383850;--arv-radius: 8px}:host(.theme-light){--arv-primary: #1565c0;--arv-primary-hover: #0d47a1;--arv-success: #2e7d32;--arv-danger: #c62828;--arv-text: #212121;--arv-text-muted: #616161;--arv-bg: #ffffff;--arv-bg2: #f5f5f5;--arv-border: #e0e0e0}.arv-container{display:flex;flex-direction:column;height:100%}.arv-content-body{flex:1;overflow:auto}.arv-footer{border-top:1px solid var(--arv-border);background:var(--arv-bg2)}.arv-footer-inner{padding:16px;display:flex;flex-direction:column;gap:14px}.arv-section-title{margin:0 0 8px;font-size:13px;font-weight:700;color:var(--arv-primary);text-transform:uppercase;letter-spacing:.5px}.arv-routing-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}.arv-routing-mode{display:flex;gap:12px}.arv-radio{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--arv-text);cursor:pointer}.arv-label{font-size:12px;color:var(--arv-text-muted);display:block;margin-bottom:4px}.arv-select{width:100%;padding:8px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input{padding:7px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input-sm{width:100%;margin-top:4px}.arv-steps{display:flex;flex-direction:column;gap:10px}.arv-step{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);padding:10px}.arv-step-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.arv-step-num{font-size:12px;font-weight:700;color:var(--arv-primary);min-width:44px}.arv-approver-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.arv-tag{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:#90caf91f;border:1px solid rgba(144,202,249,.3);border-radius:12px;font-size:12px;color:var(--arv-primary)}.arv-tag-remove{background:none;border:none;cursor:pointer;color:var(--arv-text-muted);font-size:11px;padding:0 2px;line-height:1}.arv-tag-remove:hover{color:var(--arv-danger)}.arv-user-search{position:relative}.arv-search-results{position:absolute;left:0;right:0;z-index:100;background:var(--arv-bg2);border:1px solid var(--arv-border);border-radius:var(--arv-radius);max-height:150px;overflow-y:auto}.arv-search-item{padding:8px 12px;cursor:pointer;font-size:13px;color:var(--arv-text)}.arv-search-item:hover{background:var(--arv-bg)}.arv-hint{font-size:12px;color:var(--arv-text-muted);margin:0 0 8px}.arv-btn-icon{background:none;border:none;cursor:pointer;padding:2px;border-radius:4px;display:inline-flex;align-items:center;justify-content:center}.arv-btn-danger{color:var(--arv-danger)}.arv-btn-danger:hover{background:#ef53501a}.arv-actions{display:flex;justify-content:flex-end;gap:10px}.arv-btn{padding:9px 18px;border-radius:var(--arv-radius);font-size:13px;font-weight:600;cursor:pointer;border:none;transition:background .15s}.arv-btn-primary{background:var(--arv-primary);color:#fff}.arv-btn-primary:hover:not(:disabled){background:var(--arv-primary-hover)}.arv-btn-primary:disabled{opacity:.6;cursor:not-allowed}.arv-btn-secondary{background:transparent;border:1px solid var(--arv-border);color:var(--arv-text-muted)}.arv-btn-secondary:hover{color:var(--arv-text);border-color:var(--arv-text-muted)}.arv-btn-outline{background:transparent;border:1px dashed var(--arv-border);color:var(--arv-text-muted);font-size:12px;padding:6px 12px}.arv-btn-outline:hover{border-color:var(--arv-primary);color:var(--arv-primary)}.arv-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:arv-spin .6s linear infinite;margin-right:6px}@keyframes arv-spin{to{transform:rotate(360deg)}}.arv-error{padding:8px 12px;background:#ef53501a;border:1px solid rgba(239,83,80,.3);border-radius:var(--arv-radius);font-size:13px;color:var(--arv-danger)}.arv-success{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;gap:12px;text-align:center}.arv-success p{color:var(--arv-success);font-size:15px;font-weight:600;margin:0}.arv-references{border-top:1px solid var(--arv-border);padding-top:12px}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
|
|
2586
|
+
`, isInline: true, styles: [":host{display:block;--arv-primary: #90caf9;--arv-primary-hover: #64b5f6;--arv-success: #66bb6a;--arv-danger: #ef5350;--arv-text: #e0e0e0;--arv-text-muted: #9e9e9e;--arv-bg: #1e1e2e;--arv-bg2: #27273a;--arv-border: #383850;--arv-radius: 8px}:host(.theme-light){--arv-primary: #1565c0;--arv-primary-hover: #0d47a1;--arv-success: #2e7d32;--arv-danger: #c62828;--arv-text: #212121;--arv-text-muted: #616161;--arv-bg: #ffffff;--arv-bg2: #f5f5f5;--arv-border: #e0e0e0}.arv-container{display:flex;flex-direction:column;height:100%}.arv-content-body{flex:1;overflow:auto}.arv-footer{border-top:1px solid var(--arv-border);background:var(--arv-bg2)}.arv-footer-inner{padding:16px;display:flex;flex-direction:column;gap:14px}.arv-section-title{margin:0 0 8px;font-size:13px;font-weight:700;color:var(--arv-primary);text-transform:uppercase;letter-spacing:.5px}.arv-routing-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}.arv-routing-mode{display:flex;gap:12px}.arv-radio{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--arv-text);cursor:pointer}.arv-label{font-size:12px;color:var(--arv-text-muted);display:block;margin-bottom:4px}.arv-select{width:100%;padding:8px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input{padding:7px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input-sm{width:100%;margin-top:4px}.arv-steps{display:flex;flex-direction:column;gap:10px}.arv-step{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);padding:10px}.arv-step-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.arv-step-num{font-size:12px;font-weight:700;color:var(--arv-primary);min-width:44px}.arv-approver-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.arv-tag{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:#90caf91f;border:1px solid rgba(144,202,249,.3);border-radius:12px;font-size:12px;color:var(--arv-primary)}.arv-tag-remove{background:none;border:none;cursor:pointer;color:var(--arv-text-muted);font-size:11px;padding:0 2px;line-height:1}.arv-tag-remove:hover{color:var(--arv-danger)}.arv-user-search{position:relative}.arv-search-results{position:absolute;left:0;right:0;z-index:100;background:var(--arv-bg2);border:1px solid var(--arv-border);border-radius:var(--arv-radius);max-height:150px;overflow-y:auto}.arv-search-item{padding:8px 12px;cursor:pointer;font-size:13px;color:var(--arv-text)}.arv-search-item:hover{background:var(--arv-bg)}.arv-hint{font-size:12px;color:var(--arv-text-muted);margin:0 0 8px}.arv-btn-icon{background:none;border:none;cursor:pointer;padding:2px;border-radius:4px;display:inline-flex;align-items:center;justify-content:center}.arv-btn-danger{color:var(--arv-danger)}.arv-btn-danger:hover{background:#ef53501a}.arv-actions{display:flex;justify-content:flex-end;gap:10px}.arv-btn{padding:9px 18px;border-radius:var(--arv-radius);font-size:13px;font-weight:600;cursor:pointer;border:none;transition:background .15s}.arv-btn-primary{background:var(--arv-primary);color:#fff}.arv-btn-primary:hover:not(:disabled){background:var(--arv-primary-hover)}.arv-btn-primary:disabled{opacity:.6;cursor:not-allowed}.arv-btn-secondary{background:transparent;border:1px solid var(--arv-border);color:var(--arv-text-muted)}.arv-btn-secondary:hover{color:var(--arv-text);border-color:var(--arv-text-muted)}.arv-btn-outline{background:transparent;border:1px dashed var(--arv-border);color:var(--arv-text-muted);font-size:12px;padding:6px 12px}.arv-btn-outline:hover{border-color:var(--arv-primary);color:var(--arv-primary)}.arv-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:arv-spin .6s linear infinite;margin-right:6px}@keyframes arv-spin{to{transform:rotate(360deg)}}.arv-error{padding:8px 12px;background:#ef53501a;border:1px solid rgba(239,83,80,.3);border-radius:var(--arv-radius);font-size:13px;color:var(--arv-danger)}.arv-success{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;gap:12px;text-align:center}.arv-success p{color:var(--arv-success);font-size:15px;font-weight:600;margin:0}.arv-references{border-top:1px solid var(--arv-border);padding-top:12px}.arv-template-loading{font-size:12px;color:var(--arv-text-muted);margin-top:8px;padding:4px 0}.arv-template-steps{margin-top:8px;display:flex;flex-direction:column;gap:6px}.arv-step-card{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);overflow:hidden}.arv-step-card-header{display:flex;align-items:center;gap:8px;padding:7px 10px;background:#00000008;border-bottom:1px solid var(--arv-border);flex-wrap:wrap}.arv-step-preview{display:flex;align-items:center;gap:8px;padding:5px 8px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:4px;font-size:12px}.arv-step-preview-num{font-weight:700;color:var(--arv-primary);min-width:44px;flex-shrink:0;font-size:12px}.arv-step-preview-name{flex:1;color:var(--arv-text);font-size:12px;font-weight:600}.arv-step-role-badge{font-size:11px;color:var(--arv-text-muted);background:#90caf91a;border:1px solid rgba(144,202,249,.25);border-radius:10px;padding:1px 7px}.arv-step-preview-cc .arv-step-preview-num{color:var(--arv-text-muted)}.arv-locked-template{display:flex;align-items:center;gap:8px;padding:7px 10px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);margin-top:6px}.arv-locked-label{font-size:11px;color:var(--arv-text-muted);text-transform:uppercase;letter-spacing:.5px;flex-shrink:0}.arv-locked-name{font-size:13px;font-weight:600;color:var(--arv-text)}.arv-step-picker{padding:8px 10px}.arv-select-sm{font-size:12px;padding:6px 8px}.arv-step-fixed{padding:6px 10px;font-size:12px;color:var(--arv-text-muted)}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: NgFor, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
|
|
2447
2587
|
}
|
|
2448
2588
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImport: i0, type: MaArvContainerComponent, decorators: [{
|
|
2449
2589
|
type: Component,
|
|
@@ -2462,7 +2602,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
2462
2602
|
<div class="arv-routing">
|
|
2463
2603
|
<div class="arv-routing-header">
|
|
2464
2604
|
<h4 class="arv-section-title">Approval Routing</h4>
|
|
2465
|
-
|
|
2605
|
+
<!-- Show routing toggle only when templateId is NOT locked -->
|
|
2606
|
+
<div *ngIf="!templateId" class="arv-routing-mode">
|
|
2466
2607
|
<label class="arv-radio">
|
|
2467
2608
|
<input type="radio" name="routingMode" value="template" [checked]="routingMode === 'template'" (change)="routingMode = 'template'"> Use Template
|
|
2468
2609
|
</label>
|
|
@@ -2472,15 +2613,62 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
2472
2613
|
</div>
|
|
2473
2614
|
</div>
|
|
2474
2615
|
|
|
2475
|
-
<!--
|
|
2476
|
-
<div *ngIf="routingMode === 'template'" class="arv-template-select">
|
|
2616
|
+
<!-- Locked template: show name only, no selector -->
|
|
2617
|
+
<div *ngIf="templateId && routingMode === 'template'" class="arv-template-select">
|
|
2618
|
+
<div *ngIf="loadingTemplate" class="arv-template-loading">Loading template...</div>
|
|
2619
|
+
<div *ngIf="selectedTemplate && !loadingTemplate" class="arv-locked-template">
|
|
2620
|
+
<span class="arv-locked-label">Template</span>
|
|
2621
|
+
<span class="arv-locked-name">{{ selectedTemplate.name }}</span>
|
|
2622
|
+
</div>
|
|
2623
|
+
</div>
|
|
2624
|
+
|
|
2625
|
+
<!-- Free template selector (no locked templateId) -->
|
|
2626
|
+
<div *ngIf="!templateId && routingMode === 'template'" class="arv-template-select">
|
|
2477
2627
|
<label class="arv-label">Select Template</label>
|
|
2478
2628
|
<select class="arv-select" (change)="onTemplateChange($event)">
|
|
2479
2629
|
<option value="">-- Select a template --</option>
|
|
2480
|
-
<option *ngFor="let t of templates" [value]="t.id">{{ t.name }}</option>
|
|
2630
|
+
<option *ngFor="let t of templates" [value]="t.id" [selected]="t.id === selectedTemplateId">{{ t.name }}</option>
|
|
2481
2631
|
</select>
|
|
2482
2632
|
</div>
|
|
2483
2633
|
|
|
2634
|
+
<!-- Step pickers (shared for both locked and free template) -->
|
|
2635
|
+
<div *ngIf="routingMode === 'template'" class="arv-template-select">
|
|
2636
|
+
<div *ngIf="!loadingTemplate && selectedTemplate" class="arv-template-steps">
|
|
2637
|
+
<div class="arv-step-card" *ngFor="let s of selectedTemplate.steps; let i = index">
|
|
2638
|
+
<div class="arv-step-card-header">
|
|
2639
|
+
<span class="arv-step-preview-num">Step {{ s.stepOrder }}</span>
|
|
2640
|
+
<span class="arv-step-preview-name">{{ s.stepName }}</span>
|
|
2641
|
+
<span *ngIf="s.roles && s.roles.length > 0" class="arv-step-role-badge">
|
|
2642
|
+
{{ s.roles[0].positionLevel }}{{ s.roles[0].orgName ? ' · ' + s.roles[0].orgName : '' }}
|
|
2643
|
+
</span>
|
|
2644
|
+
</div>
|
|
2645
|
+
<!-- Role-based step: show approver picker -->
|
|
2646
|
+
<div *ngIf="s.roles && s.roles.length > 0" class="arv-step-picker">
|
|
2647
|
+
<div *ngIf="stepLoadingCandidates[i]" class="arv-template-loading">Loading candidates...</div>
|
|
2648
|
+
<select *ngIf="!stepLoadingCandidates[i]" class="arv-select arv-select-sm"
|
|
2649
|
+
(change)="onStepUserChange(i, $event)">
|
|
2650
|
+
<option value="">-- Select approver --</option>
|
|
2651
|
+
<option *ngFor="let u of stepCandidates[i]" [value]="u.userId"
|
|
2652
|
+
[selected]="u.userId === stepSelectedUsers[i]">
|
|
2653
|
+
{{ u.fullName || u.userId }}{{ u.department ? ' · ' + u.department : '' }}{{ u.position ? ' (' + u.position + ')' : '' }}
|
|
2654
|
+
</option>
|
|
2655
|
+
</select>
|
|
2656
|
+
<div *ngIf="!stepLoadingCandidates[i] && stepCandidates[i]?.length === 0" class="arv-template-loading">
|
|
2657
|
+
No candidates found for this role.
|
|
2658
|
+
</div>
|
|
2659
|
+
</div>
|
|
2660
|
+
<!-- Fixed-user step -->
|
|
2661
|
+
<div *ngIf="!s.roles || s.roles.length === 0" class="arv-step-fixed">
|
|
2662
|
+
{{ s.assigneeUserIds.length }} pre-configured approver(s)
|
|
2663
|
+
</div>
|
|
2664
|
+
</div>
|
|
2665
|
+
<div *ngIf="selectedTemplate.referenceUserIds.length > 0" class="arv-step-preview arv-step-preview-cc">
|
|
2666
|
+
<span class="arv-step-preview-num">CC</span>
|
|
2667
|
+
<span class="arv-step-preview-name">{{ selectedTemplate.referenceUserIds.length }} reference user(s) from template</span>
|
|
2668
|
+
</div>
|
|
2669
|
+
</div>
|
|
2670
|
+
</div>
|
|
2671
|
+
|
|
2484
2672
|
<!-- Ad-hoc steps -->
|
|
2485
2673
|
<div *ngIf="routingMode === 'adhoc'" class="arv-steps">
|
|
2486
2674
|
<div class="arv-step" *ngFor="let step of adHocSteps; let i = index">
|
|
@@ -2562,7 +2750,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
2562
2750
|
<p>Submitted for approval successfully.</p>
|
|
2563
2751
|
</div>
|
|
2564
2752
|
</div>
|
|
2565
|
-
`, styles: [":host{display:block;--arv-primary: #90caf9;--arv-primary-hover: #64b5f6;--arv-success: #66bb6a;--arv-danger: #ef5350;--arv-text: #e0e0e0;--arv-text-muted: #9e9e9e;--arv-bg: #1e1e2e;--arv-bg2: #27273a;--arv-border: #383850;--arv-radius: 8px}:host(.theme-light){--arv-primary: #1565c0;--arv-primary-hover: #0d47a1;--arv-success: #2e7d32;--arv-danger: #c62828;--arv-text: #212121;--arv-text-muted: #616161;--arv-bg: #ffffff;--arv-bg2: #f5f5f5;--arv-border: #e0e0e0}.arv-container{display:flex;flex-direction:column;height:100%}.arv-content-body{flex:1;overflow:auto}.arv-footer{border-top:1px solid var(--arv-border);background:var(--arv-bg2)}.arv-footer-inner{padding:16px;display:flex;flex-direction:column;gap:14px}.arv-section-title{margin:0 0 8px;font-size:13px;font-weight:700;color:var(--arv-primary);text-transform:uppercase;letter-spacing:.5px}.arv-routing-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}.arv-routing-mode{display:flex;gap:12px}.arv-radio{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--arv-text);cursor:pointer}.arv-label{font-size:12px;color:var(--arv-text-muted);display:block;margin-bottom:4px}.arv-select{width:100%;padding:8px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input{padding:7px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input-sm{width:100%;margin-top:4px}.arv-steps{display:flex;flex-direction:column;gap:10px}.arv-step{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);padding:10px}.arv-step-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.arv-step-num{font-size:12px;font-weight:700;color:var(--arv-primary);min-width:44px}.arv-approver-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.arv-tag{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:#90caf91f;border:1px solid rgba(144,202,249,.3);border-radius:12px;font-size:12px;color:var(--arv-primary)}.arv-tag-remove{background:none;border:none;cursor:pointer;color:var(--arv-text-muted);font-size:11px;padding:0 2px;line-height:1}.arv-tag-remove:hover{color:var(--arv-danger)}.arv-user-search{position:relative}.arv-search-results{position:absolute;left:0;right:0;z-index:100;background:var(--arv-bg2);border:1px solid var(--arv-border);border-radius:var(--arv-radius);max-height:150px;overflow-y:auto}.arv-search-item{padding:8px 12px;cursor:pointer;font-size:13px;color:var(--arv-text)}.arv-search-item:hover{background:var(--arv-bg)}.arv-hint{font-size:12px;color:var(--arv-text-muted);margin:0 0 8px}.arv-btn-icon{background:none;border:none;cursor:pointer;padding:2px;border-radius:4px;display:inline-flex;align-items:center;justify-content:center}.arv-btn-danger{color:var(--arv-danger)}.arv-btn-danger:hover{background:#ef53501a}.arv-actions{display:flex;justify-content:flex-end;gap:10px}.arv-btn{padding:9px 18px;border-radius:var(--arv-radius);font-size:13px;font-weight:600;cursor:pointer;border:none;transition:background .15s}.arv-btn-primary{background:var(--arv-primary);color:#fff}.arv-btn-primary:hover:not(:disabled){background:var(--arv-primary-hover)}.arv-btn-primary:disabled{opacity:.6;cursor:not-allowed}.arv-btn-secondary{background:transparent;border:1px solid var(--arv-border);color:var(--arv-text-muted)}.arv-btn-secondary:hover{color:var(--arv-text);border-color:var(--arv-text-muted)}.arv-btn-outline{background:transparent;border:1px dashed var(--arv-border);color:var(--arv-text-muted);font-size:12px;padding:6px 12px}.arv-btn-outline:hover{border-color:var(--arv-primary);color:var(--arv-primary)}.arv-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:arv-spin .6s linear infinite;margin-right:6px}@keyframes arv-spin{to{transform:rotate(360deg)}}.arv-error{padding:8px 12px;background:#ef53501a;border:1px solid rgba(239,83,80,.3);border-radius:var(--arv-radius);font-size:13px;color:var(--arv-danger)}.arv-success{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;gap:12px;text-align:center}.arv-success p{color:var(--arv-success);font-size:15px;font-weight:600;margin:0}.arv-references{border-top:1px solid var(--arv-border);padding-top:12px}\n"] }]
|
|
2753
|
+
`, styles: [":host{display:block;--arv-primary: #90caf9;--arv-primary-hover: #64b5f6;--arv-success: #66bb6a;--arv-danger: #ef5350;--arv-text: #e0e0e0;--arv-text-muted: #9e9e9e;--arv-bg: #1e1e2e;--arv-bg2: #27273a;--arv-border: #383850;--arv-radius: 8px}:host(.theme-light){--arv-primary: #1565c0;--arv-primary-hover: #0d47a1;--arv-success: #2e7d32;--arv-danger: #c62828;--arv-text: #212121;--arv-text-muted: #616161;--arv-bg: #ffffff;--arv-bg2: #f5f5f5;--arv-border: #e0e0e0}.arv-container{display:flex;flex-direction:column;height:100%}.arv-content-body{flex:1;overflow:auto}.arv-footer{border-top:1px solid var(--arv-border);background:var(--arv-bg2)}.arv-footer-inner{padding:16px;display:flex;flex-direction:column;gap:14px}.arv-section-title{margin:0 0 8px;font-size:13px;font-weight:700;color:var(--arv-primary);text-transform:uppercase;letter-spacing:.5px}.arv-routing-header{display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:8px}.arv-routing-mode{display:flex;gap:12px}.arv-radio{display:flex;align-items:center;gap:6px;font-size:13px;color:var(--arv-text);cursor:pointer}.arv-label{font-size:12px;color:var(--arv-text-muted);display:block;margin-bottom:4px}.arv-select{width:100%;padding:8px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input{padding:7px 10px;border:1px solid var(--arv-border);border-radius:var(--arv-radius);background:var(--arv-bg);color:var(--arv-text);font-size:13px}.arv-input-sm{width:100%;margin-top:4px}.arv-steps{display:flex;flex-direction:column;gap:10px}.arv-step{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);padding:10px}.arv-step-header{display:flex;align-items:center;gap:8px;margin-bottom:8px}.arv-step-num{font-size:12px;font-weight:700;color:var(--arv-primary);min-width:44px}.arv-approver-tags{display:flex;flex-wrap:wrap;gap:6px;margin-bottom:6px}.arv-tag{display:inline-flex;align-items:center;gap:4px;padding:3px 8px;background:#90caf91f;border:1px solid rgba(144,202,249,.3);border-radius:12px;font-size:12px;color:var(--arv-primary)}.arv-tag-remove{background:none;border:none;cursor:pointer;color:var(--arv-text-muted);font-size:11px;padding:0 2px;line-height:1}.arv-tag-remove:hover{color:var(--arv-danger)}.arv-user-search{position:relative}.arv-search-results{position:absolute;left:0;right:0;z-index:100;background:var(--arv-bg2);border:1px solid var(--arv-border);border-radius:var(--arv-radius);max-height:150px;overflow-y:auto}.arv-search-item{padding:8px 12px;cursor:pointer;font-size:13px;color:var(--arv-text)}.arv-search-item:hover{background:var(--arv-bg)}.arv-hint{font-size:12px;color:var(--arv-text-muted);margin:0 0 8px}.arv-btn-icon{background:none;border:none;cursor:pointer;padding:2px;border-radius:4px;display:inline-flex;align-items:center;justify-content:center}.arv-btn-danger{color:var(--arv-danger)}.arv-btn-danger:hover{background:#ef53501a}.arv-actions{display:flex;justify-content:flex-end;gap:10px}.arv-btn{padding:9px 18px;border-radius:var(--arv-radius);font-size:13px;font-weight:600;cursor:pointer;border:none;transition:background .15s}.arv-btn-primary{background:var(--arv-primary);color:#fff}.arv-btn-primary:hover:not(:disabled){background:var(--arv-primary-hover)}.arv-btn-primary:disabled{opacity:.6;cursor:not-allowed}.arv-btn-secondary{background:transparent;border:1px solid var(--arv-border);color:var(--arv-text-muted)}.arv-btn-secondary:hover{color:var(--arv-text);border-color:var(--arv-text-muted)}.arv-btn-outline{background:transparent;border:1px dashed var(--arv-border);color:var(--arv-text-muted);font-size:12px;padding:6px 12px}.arv-btn-outline:hover{border-color:var(--arv-primary);color:var(--arv-primary)}.arv-spinner{display:inline-block;width:14px;height:14px;border:2px solid rgba(255,255,255,.3);border-top-color:#fff;border-radius:50%;animation:arv-spin .6s linear infinite;margin-right:6px}@keyframes arv-spin{to{transform:rotate(360deg)}}.arv-error{padding:8px 12px;background:#ef53501a;border:1px solid rgba(239,83,80,.3);border-radius:var(--arv-radius);font-size:13px;color:var(--arv-danger)}.arv-success{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:32px;gap:12px;text-align:center}.arv-success p{color:var(--arv-success);font-size:15px;font-weight:600;margin:0}.arv-references{border-top:1px solid var(--arv-border);padding-top:12px}.arv-template-loading{font-size:12px;color:var(--arv-text-muted);margin-top:8px;padding:4px 0}.arv-template-steps{margin-top:8px;display:flex;flex-direction:column;gap:6px}.arv-step-card{background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);overflow:hidden}.arv-step-card-header{display:flex;align-items:center;gap:8px;padding:7px 10px;background:#00000008;border-bottom:1px solid var(--arv-border);flex-wrap:wrap}.arv-step-preview{display:flex;align-items:center;gap:8px;padding:5px 8px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:4px;font-size:12px}.arv-step-preview-num{font-weight:700;color:var(--arv-primary);min-width:44px;flex-shrink:0;font-size:12px}.arv-step-preview-name{flex:1;color:var(--arv-text);font-size:12px;font-weight:600}.arv-step-role-badge{font-size:11px;color:var(--arv-text-muted);background:#90caf91a;border:1px solid rgba(144,202,249,.25);border-radius:10px;padding:1px 7px}.arv-step-preview-cc .arv-step-preview-num{color:var(--arv-text-muted)}.arv-locked-template{display:flex;align-items:center;gap:8px;padding:7px 10px;background:var(--arv-bg);border:1px solid var(--arv-border);border-radius:var(--arv-radius);margin-top:6px}.arv-locked-label{font-size:11px;color:var(--arv-text-muted);text-transform:uppercase;letter-spacing:.5px;flex-shrink:0}.arv-locked-name{font-size:13px;font-weight:600;color:var(--arv-text)}.arv-step-picker{padding:8px 10px}.arv-select-sm{font-size:12px;padding:6px 8px}.arv-step-fixed{padding:6px 10px;font-size:12px;color:var(--arv-text-muted)}\n"] }]
|
|
2566
2754
|
}], propDecorators: { title: [{
|
|
2567
2755
|
type: Input
|
|
2568
2756
|
}], description: [{
|
|
@@ -2577,13 +2765,16 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "20.3.18", ngImpo
|
|
|
2577
2765
|
type: Input
|
|
2578
2766
|
}], approvalSubmitted: [{
|
|
2579
2767
|
type: Output
|
|
2580
|
-
}],
|
|
2768
|
+
}], approvalSubmitting: [{
|
|
2581
2769
|
type: Output
|
|
2582
2770
|
}], cancelled: [{
|
|
2583
2771
|
type: Output
|
|
2584
2772
|
}], contentBody: [{
|
|
2585
2773
|
type: ViewChild,
|
|
2586
2774
|
args: ['contentBody', { static: true }]
|
|
2775
|
+
}], themeClass: [{
|
|
2776
|
+
type: HostBinding,
|
|
2777
|
+
args: ['class']
|
|
2587
2778
|
}] } });
|
|
2588
2779
|
|
|
2589
2780
|
/**
|