@franzzemen/brokenstock-shell 0.0.2 → 0.0.4
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.
|
@@ -23,6 +23,8 @@ import * as i4 from '@angular/material/input';
|
|
|
23
23
|
import { MatInput, MatInputModule } from '@angular/material/input';
|
|
24
24
|
import * as i6 from '@angular/material/button';
|
|
25
25
|
import { MatButtonModule } from '@angular/material/button';
|
|
26
|
+
import * as i7 from '@angular/material/checkbox';
|
|
27
|
+
import { MatCheckboxModule } from '@angular/material/checkbox';
|
|
26
28
|
import * as i1$2 from '@angular/material/dialog';
|
|
27
29
|
import { MAT_DIALOG_DATA, MatDialogRef, MatDialogModule } from '@angular/material/dialog';
|
|
28
30
|
|
|
@@ -45,8 +47,11 @@ function provideShellConfig(config) {
|
|
|
45
47
|
}
|
|
46
48
|
|
|
47
49
|
class ThinkingService {
|
|
48
|
-
|
|
49
|
-
|
|
50
|
+
constructor() {
|
|
51
|
+
this.#activeCount = signal(0, ...(ngDevMode ? [{ debugName: "#activeCount" }] : /* istanbul ignore next */ []));
|
|
52
|
+
this.isThinking = computed(() => this.#activeCount() > 0, ...(ngDevMode ? [{ debugName: "isThinking" }] : /* istanbul ignore next */ []));
|
|
53
|
+
}
|
|
54
|
+
#activeCount;
|
|
50
55
|
startThinking() {
|
|
51
56
|
this.#activeCount.update(c => c + 1);
|
|
52
57
|
}
|
|
@@ -56,8 +61,8 @@ class ThinkingService {
|
|
|
56
61
|
reset() {
|
|
57
62
|
this.#activeCount.set(0);
|
|
58
63
|
}
|
|
59
|
-
static
|
|
60
|
-
static
|
|
64
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ThinkingService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
65
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ThinkingService, providedIn: 'root' }); }
|
|
61
66
|
}
|
|
62
67
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ThinkingService, decorators: [{
|
|
63
68
|
type: Injectable,
|
|
@@ -65,17 +70,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
65
70
|
}] });
|
|
66
71
|
|
|
67
72
|
class AuthenticationService {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
73
|
+
constructor() {
|
|
74
|
+
this.authenticated = signal(false, ...(ngDevMode ? [{ debugName: "authenticated" }] : /* istanbul ignore next */ []));
|
|
75
|
+
this.authenticating = signal(false, ...(ngDevMode ? [{ debugName: "authenticating" }] : /* istanbul ignore next */ []));
|
|
76
|
+
this.userSession = signal(undefined, ...(ngDevMode ? [{ debugName: "userSession" }] : /* istanbul ignore next */ []));
|
|
77
|
+
this.effectivePermissions = signal({}, ...(ngDevMode ? [{ debugName: "effectivePermissions" }] : /* istanbul ignore next */ []));
|
|
78
|
+
this.conflictSessions = signal(undefined, ...(ngDevMode ? [{ debugName: "conflictSessions" }] : /* istanbul ignore next */ []));
|
|
79
|
+
this.#refreshing = null;
|
|
80
|
+
this.#auth = 'Bearer ..';
|
|
81
|
+
this.#httpClient = inject(HttpClient);
|
|
82
|
+
this.#thinkingService = inject(ThinkingService);
|
|
83
|
+
this.#router = inject(Router);
|
|
84
|
+
this.#authUrls = inject(SHELL_AUTH_URLS);
|
|
85
|
+
}
|
|
86
|
+
#refreshing;
|
|
87
|
+
#auth;
|
|
88
|
+
#httpClient;
|
|
89
|
+
#thinkingService;
|
|
90
|
+
#router;
|
|
91
|
+
#authUrls;
|
|
79
92
|
get auth() {
|
|
80
93
|
return this.#auth;
|
|
81
94
|
}
|
|
@@ -211,8 +224,8 @@ class AuthenticationService {
|
|
|
211
224
|
this.#auth = 'Bearer ..';
|
|
212
225
|
this.#router.navigate(['/login']).catch(console.error);
|
|
213
226
|
}
|
|
214
|
-
static
|
|
215
|
-
static
|
|
227
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: AuthenticationService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
228
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: AuthenticationService, providedIn: 'root' }); }
|
|
216
229
|
}
|
|
217
230
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: AuthenticationService, decorators: [{
|
|
218
231
|
type: Injectable,
|
|
@@ -267,15 +280,17 @@ const authInterceptor = (req, next) => {
|
|
|
267
280
|
};
|
|
268
281
|
|
|
269
282
|
class RegexValidatorDirective {
|
|
270
|
-
|
|
283
|
+
constructor() {
|
|
284
|
+
this.regex = input(/^[A-Z0-9._%+-@!?]{4,64}$/i, ...(ngDevMode ? [{ debugName: "regex" }] : /* istanbul ignore next */ []));
|
|
285
|
+
}
|
|
271
286
|
validate(control) {
|
|
272
287
|
if (!control.value || !this.regex().test(control.value)) {
|
|
273
288
|
return { regexValidator: { value: control.value } };
|
|
274
289
|
}
|
|
275
290
|
return null;
|
|
276
291
|
}
|
|
277
|
-
static
|
|
278
|
-
static
|
|
292
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: RegexValidatorDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive }); }
|
|
293
|
+
static { this.ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.2.7", type: RegexValidatorDirective, isStandalone: true, selector: "[regexValidator]", inputs: { regex: { classPropertyName: "regex", publicName: "regex", isSignal: true, isRequired: false, transformFunction: null } }, providers: [{ provide: NG_VALIDATORS, useExisting: RegexValidatorDirective, multi: true }], ngImport: i0 }); }
|
|
279
294
|
}
|
|
280
295
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: RegexValidatorDirective, decorators: [{
|
|
281
296
|
type: Directive,
|
|
@@ -286,10 +301,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
286
301
|
}], propDecorators: { regex: [{ type: i0.Input, args: [{ isSignal: true, alias: "regex", required: false }] }] } });
|
|
287
302
|
|
|
288
303
|
class ThemeService {
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
304
|
+
constructor() {
|
|
305
|
+
this.mode = signal('dark', ...(ngDevMode ? [{ debugName: "mode" }] : /* istanbul ignore next */ []));
|
|
306
|
+
this.isDark = computed(() => this.mode() === 'dark', ...(ngDevMode ? [{ debugName: "isDark" }] : /* istanbul ignore next */ []));
|
|
307
|
+
}
|
|
308
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ThemeService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
309
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ThemeService, providedIn: 'root' }); }
|
|
293
310
|
}
|
|
294
311
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ThemeService, decorators: [{
|
|
295
312
|
type: Injectable,
|
|
@@ -297,12 +314,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
297
314
|
}] });
|
|
298
315
|
|
|
299
316
|
class TerminalFocusService {
|
|
300
|
-
|
|
317
|
+
constructor() {
|
|
318
|
+
this.focusRequested = signal(0, ...(ngDevMode ? [{ debugName: "focusRequested" }] : /* istanbul ignore next */ []));
|
|
319
|
+
}
|
|
301
320
|
requestFocus() {
|
|
302
321
|
this.focusRequested.update(v => v + 1);
|
|
303
322
|
}
|
|
304
|
-
static
|
|
305
|
-
static
|
|
323
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: TerminalFocusService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
324
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: TerminalFocusService, providedIn: 'root' }); }
|
|
306
325
|
}
|
|
307
326
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: TerminalFocusService, decorators: [{
|
|
308
327
|
type: Injectable,
|
|
@@ -310,22 +329,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
310
329
|
}] });
|
|
311
330
|
|
|
312
331
|
class KeyboardShortcutService {
|
|
313
|
-
#groups
|
|
314
|
-
#activeGroupId
|
|
315
|
-
#document
|
|
316
|
-
#zone
|
|
317
|
-
#focusService
|
|
318
|
-
helpVisible = signal(false, ...(ngDevMode ? [{ debugName: "helpVisible" }] : /* istanbul ignore next */ []));
|
|
319
|
-
activeShortcuts = computed(() => {
|
|
320
|
-
const groupId = this.#activeGroupId();
|
|
321
|
-
if (!groupId)
|
|
322
|
-
return null;
|
|
323
|
-
const shortcuts = this.#groups.get(groupId);
|
|
324
|
-
if (!shortcuts)
|
|
325
|
-
return null;
|
|
326
|
-
return { groupId, shortcuts };
|
|
327
|
-
}, ...(ngDevMode ? [{ debugName: "activeShortcuts" }] : /* istanbul ignore next */ []));
|
|
332
|
+
#groups;
|
|
333
|
+
#activeGroupId;
|
|
334
|
+
#document;
|
|
335
|
+
#zone;
|
|
336
|
+
#focusService;
|
|
328
337
|
constructor() {
|
|
338
|
+
this.#groups = new Map();
|
|
339
|
+
this.#activeGroupId = signal(null, ...(ngDevMode ? [{ debugName: "#activeGroupId" }] : /* istanbul ignore next */ []));
|
|
340
|
+
this.#document = inject(DOCUMENT);
|
|
341
|
+
this.#zone = inject(NgZone);
|
|
342
|
+
this.#focusService = inject(TerminalFocusService);
|
|
343
|
+
this.helpVisible = signal(false, ...(ngDevMode ? [{ debugName: "helpVisible" }] : /* istanbul ignore next */ []));
|
|
344
|
+
this.activeShortcuts = computed(() => {
|
|
345
|
+
const groupId = this.#activeGroupId();
|
|
346
|
+
if (!groupId)
|
|
347
|
+
return null;
|
|
348
|
+
const shortcuts = this.#groups.get(groupId);
|
|
349
|
+
if (!shortcuts)
|
|
350
|
+
return null;
|
|
351
|
+
return { groupId, shortcuts };
|
|
352
|
+
}, ...(ngDevMode ? [{ debugName: "activeShortcuts" }] : /* istanbul ignore next */ []));
|
|
329
353
|
this.#zone.runOutsideAngular(() => {
|
|
330
354
|
this.#document.addEventListener('keydown', (event) => {
|
|
331
355
|
this.#handleKeydown(event);
|
|
@@ -380,8 +404,8 @@ class KeyboardShortcutService {
|
|
|
380
404
|
}
|
|
381
405
|
return false;
|
|
382
406
|
}
|
|
383
|
-
static
|
|
384
|
-
static
|
|
407
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KeyboardShortcutService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
408
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KeyboardShortcutService, providedIn: 'root' }); }
|
|
385
409
|
}
|
|
386
410
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: KeyboardShortcutService, decorators: [{
|
|
387
411
|
type: Injectable,
|
|
@@ -389,8 +413,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
389
413
|
}], ctorParameters: () => [] });
|
|
390
414
|
|
|
391
415
|
class CommandRegistryService {
|
|
392
|
-
commands = new Map();
|
|
393
416
|
constructor() {
|
|
417
|
+
this.commands = new Map();
|
|
394
418
|
const appCommands = inject(SHELL_COMMANDS, { optional: true }) ?? [];
|
|
395
419
|
for (const cmd of appCommands) {
|
|
396
420
|
this.register(cmd);
|
|
@@ -421,8 +445,8 @@ class CommandRegistryService {
|
|
|
421
445
|
.filter(name => name.startsWith(prefix) && name !== prefix)
|
|
422
446
|
.sort();
|
|
423
447
|
}
|
|
424
|
-
static
|
|
425
|
-
static
|
|
448
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: CommandRegistryService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
449
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: CommandRegistryService, providedIn: 'root' }); }
|
|
426
450
|
}
|
|
427
451
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: CommandRegistryService, decorators: [{
|
|
428
452
|
type: Injectable,
|
|
@@ -446,22 +470,22 @@ const HELP_USAGE = 'help [command]\n\n' +
|
|
|
446
470
|
|
|
447
471
|
const CommandInputSchema = z.string().trim().min(1, 'Command cannot be empty');
|
|
448
472
|
class CommandService {
|
|
449
|
-
history = signal([], ...(ngDevMode ? [{ debugName: "history" }] : /* istanbul ignore next */ []));
|
|
450
|
-
currentInput = signal('', ...(ngDevMode ? [{ debugName: "currentInput" }] : /* istanbul ignore next */ []));
|
|
451
|
-
isProcessing = signal(false, ...(ngDevMode ? [{ debugName: "isProcessing" }] : /* istanbul ignore next */ []));
|
|
452
|
-
authService = inject(AuthenticationService);
|
|
453
|
-
registry = inject(CommandRegistryService);
|
|
454
473
|
constructor() {
|
|
474
|
+
this.history = signal([], ...(ngDevMode ? [{ debugName: "history" }] : /* istanbul ignore next */ []));
|
|
475
|
+
this.currentInput = signal('', ...(ngDevMode ? [{ debugName: "currentInput" }] : /* istanbul ignore next */ []));
|
|
476
|
+
this.isProcessing = signal(false, ...(ngDevMode ? [{ debugName: "isProcessing" }] : /* istanbul ignore next */ []));
|
|
477
|
+
this.authService = inject(AuthenticationService);
|
|
478
|
+
this.registry = inject(CommandRegistryService);
|
|
479
|
+
this.lastResult = computed(() => {
|
|
480
|
+
const h = this.history();
|
|
481
|
+
return h.length > 0 ? h[h.length - 1].result : null;
|
|
482
|
+
}, ...(ngDevMode ? [{ debugName: "lastResult" }] : /* istanbul ignore next */ []));
|
|
455
483
|
effect(() => {
|
|
456
484
|
if (!this.authService.authenticated()) {
|
|
457
485
|
this.history.set([]);
|
|
458
486
|
}
|
|
459
487
|
});
|
|
460
488
|
}
|
|
461
|
-
lastResult = computed(() => {
|
|
462
|
-
const h = this.history();
|
|
463
|
-
return h.length > 0 ? h[h.length - 1].result : null;
|
|
464
|
-
}, ...(ngDevMode ? [{ debugName: "lastResult" }] : /* istanbul ignore next */ []));
|
|
465
489
|
echoCommand(input) {
|
|
466
490
|
if (this.#coalesce(input))
|
|
467
491
|
return;
|
|
@@ -585,8 +609,8 @@ class CommandService {
|
|
|
585
609
|
return { success: false, message: `Unknown command: ${name}`, timestamp: new Date() };
|
|
586
610
|
return { success: true, message: def.usage, timestamp: new Date() };
|
|
587
611
|
}
|
|
588
|
-
static
|
|
589
|
-
static
|
|
612
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: CommandService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
613
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: CommandService, providedIn: 'root' }); }
|
|
590
614
|
}
|
|
591
615
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: CommandService, decorators: [{
|
|
592
616
|
type: Injectable,
|
|
@@ -594,22 +618,27 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
594
618
|
}], ctorParameters: () => [] });
|
|
595
619
|
|
|
596
620
|
class StatusBar {
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
621
|
+
constructor() {
|
|
622
|
+
this.#authService = inject(AuthenticationService);
|
|
623
|
+
this.#focusService = inject(TerminalFocusService);
|
|
624
|
+
this.#commandService = inject(CommandService);
|
|
625
|
+
this.isAuthenticated = this.#authService.authenticated;
|
|
626
|
+
this.loginStatus = computed(() => this.#authService.authenticating()
|
|
627
|
+
? 'Authenticating...'
|
|
628
|
+
: this.#authService.authenticated()
|
|
629
|
+
? 'Logged in'
|
|
630
|
+
: 'Not logged in', ...(ngDevMode ? [{ debugName: "loginStatus" }] : /* istanbul ignore next */ []));
|
|
631
|
+
}
|
|
632
|
+
#authService;
|
|
633
|
+
#focusService;
|
|
634
|
+
#commandService;
|
|
606
635
|
logout() {
|
|
607
636
|
this.#authService.logout();
|
|
608
637
|
this.#commandService.echoCommand('logout');
|
|
609
638
|
this.#focusService.requestFocus();
|
|
610
639
|
}
|
|
611
|
-
static
|
|
612
|
-
static
|
|
640
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: StatusBar, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
641
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: StatusBar, isStandalone: true, selector: "shell-status-bar", ngImport: i0, template: "<div class=\"status-bar\">\n <div class=\"status-item\">\n <span class=\"status-label text-secondary-info\">Status:</span>\n @if (isAuthenticated()) {\n <a class=\"status-value text-interactive logout-link\" (click)=\"logout()\">Log Out</a>\n } @else {\n <span class=\"status-value text-loss\">{{ loginStatus() }}</span>\n }\n </div>\n @if (isAuthenticated()) {\n <ng-content />\n }\n</div>\n", styles: [".status-bar{display:flex;align-items:center;gap:24px;padding:0 16px;height:100%;background-color:var(--color-surface);border-bottom:1px solid var(--color-surface-border);font-size:.8rem}.status-item{display:flex;align-items:baseline;gap:6px}.status-label{font-weight:500;text-transform:uppercase;letter-spacing:.05em;font-size:.7rem}.logout-link{cursor:pointer;text-decoration:underline}.logout-link:hover{opacity:.8}\n"] }); }
|
|
613
642
|
}
|
|
614
643
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: StatusBar, decorators: [{
|
|
615
644
|
type: Component,
|
|
@@ -617,12 +646,18 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
617
646
|
}] });
|
|
618
647
|
|
|
619
648
|
class SideMenu {
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
649
|
+
constructor() {
|
|
650
|
+
this.#focusService = inject(TerminalFocusService);
|
|
651
|
+
this.#commandService = inject(CommandService);
|
|
652
|
+
this.#shortcutService = inject(KeyboardShortcutService);
|
|
653
|
+
this.hasShortcuts = this.#shortcutService.activeShortcuts;
|
|
654
|
+
this.#allMenuItems = inject(SHELL_MENU_ITEMS, { optional: true }) ?? [];
|
|
655
|
+
this.menuItems = computed(() => this.#allMenuItems.filter(item => !item.visible || item.visible()), ...(ngDevMode ? [{ debugName: "menuItems" }] : /* istanbul ignore next */ []));
|
|
656
|
+
}
|
|
657
|
+
#focusService;
|
|
658
|
+
#commandService;
|
|
659
|
+
#shortcutService;
|
|
660
|
+
#allMenuItems;
|
|
626
661
|
onMenuClick(item) {
|
|
627
662
|
if (item.command) {
|
|
628
663
|
this.#commandService.echoCommand(item.command);
|
|
@@ -632,8 +667,8 @@ class SideMenu {
|
|
|
632
667
|
toggleHelp() {
|
|
633
668
|
this.#shortcutService.toggleHelp();
|
|
634
669
|
}
|
|
635
|
-
static
|
|
636
|
-
static
|
|
670
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SideMenu, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
671
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: SideMenu, isStandalone: true, selector: "shell-side-menu", ngImport: i0, template: "<nav class=\"side-menu\">\n @for (item of menuItems(); track item.route) {\n <a\n class=\"menu-item\"\n [routerLink]=\"item.route\"\n routerLinkActive=\"active\"\n [matTooltip]=\"item.label\"\n matTooltipPosition=\"right\"\n (click)=\"onMenuClick(item)\"\n >\n <mat-icon>{{ item.icon }}</mat-icon>\n </a>\n }\n <div class=\"menu-spacer\"></div>\n @if (hasShortcuts()) {\n <button\n class=\"help-button\"\n matTooltip=\"Keyboard shortcuts\"\n matTooltipPosition=\"right\"\n (click)=\"toggleHelp()\"\n >\n <span class=\"help-modifier\">Alt+</span><span class=\"help-key\">?</span>\n </button>\n }\n</nav>\n", styles: [".side-menu{display:flex;flex-direction:column;align-items:center;padding-top:8px;gap:4px;height:100%;background-color:var(--color-surface);border-right:1px solid var(--color-surface-border)}.menu-item{display:flex;align-items:center;justify-content:center;width:40px;height:40px;border-radius:8px;color:var(--color-secondary-info);text-decoration:none;transition:background-color .15s,color .15s}.menu-item:hover,.menu-item.active{background-color:var(--color-surface-light);color:var(--color-interactive)}.menu-spacer{flex:1}.help-button{margin-bottom:8px;padding:4px 6px;border:1px solid var(--color-surface-border);border-radius:6px;background:none;font-size:.7rem;font-family:Roboto Mono,monospace;cursor:pointer;color:var(--color-interactive);transition:background-color .15s}.help-button:hover{background-color:var(--color-surface-light)}.help-modifier{opacity:.6}.help-key{font-weight:700}\n"], dependencies: [{ kind: "directive", type: RouterLink, selector: "[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "state", "info", "relativeTo", "preserveFragment", "skipLocationChange", "replaceUrl", "routerLink"] }, { kind: "directive", type: RouterLinkActive, selector: "[routerLinkActive]", inputs: ["routerLinkActiveOptions", "ariaCurrentWhenActive", "routerLinkActive"], outputs: ["isActiveChange"], exportAs: ["routerLinkActive"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "ngmodule", type: MatTooltipModule }, { kind: "directive", type: i2.MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }] }); }
|
|
637
672
|
}
|
|
638
673
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: SideMenu, decorators: [{
|
|
639
674
|
type: Component,
|
|
@@ -641,11 +676,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
641
676
|
}] });
|
|
642
677
|
|
|
643
678
|
class MainContent {
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
679
|
+
constructor() {
|
|
680
|
+
this.#thinkingService = inject(ThinkingService);
|
|
681
|
+
this.#shortcutService = inject(KeyboardShortcutService);
|
|
682
|
+
this.isThinking = this.#thinkingService.isThinking;
|
|
683
|
+
this.shortcutHelpVisible = this.#shortcutService.helpVisible;
|
|
684
|
+
this.activeShortcuts = this.#shortcutService.activeShortcuts;
|
|
685
|
+
}
|
|
686
|
+
#thinkingService;
|
|
687
|
+
#shortcutService;
|
|
649
688
|
formatKey(key) {
|
|
650
689
|
const keyMap = {
|
|
651
690
|
ArrowUp: '↑', ArrowDown: '↓', ArrowLeft: '←', ArrowRight: '→',
|
|
@@ -656,8 +695,8 @@ class MainContent {
|
|
|
656
695
|
closeShortcutHelp() {
|
|
657
696
|
this.#shortcutService.helpVisible.set(false);
|
|
658
697
|
}
|
|
659
|
-
static
|
|
660
|
-
static
|
|
698
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MainContent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
699
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: MainContent, isStandalone: true, selector: "shell-main-content", ngImport: i0, template: "<div class=\"main-content\">\n <div class=\"content-area\">\n <router-outlet />\n </div>\n @if (shortcutHelpVisible() && activeShortcuts()) {\n <div class=\"shortcut-overlay\" (click)=\"closeShortcutHelp()\">\n <div class=\"shortcut-panel\" (click)=\"$event.stopPropagation()\">\n <div class=\"shortcut-title text-secondary-info\">{{ activeShortcuts()!.groupId }} shortcuts</div>\n @for (s of activeShortcuts()!.shortcuts; track s.key) {\n <div class=\"shortcut-row\">\n <kbd class=\"shortcut-key\">Alt+{{ formatKey(s.key) }}</kbd>\n <span class=\"shortcut-desc text-text-primary\">{{ s.description }}</span>\n </div>\n }\n <div class=\"shortcut-row shortcut-dismiss\">\n <kbd class=\"shortcut-key\">Alt+?</kbd>\n <span class=\"shortcut-desc text-secondary-info\">or</span>\n <kbd class=\"shortcut-key\">Esc</kbd>\n <span class=\"shortcut-desc text-secondary-info\">dismiss</span>\n </div>\n </div>\n </div>\n }\n @if (isThinking()) {\n <div class=\"thinking-overlay\">\n <mat-spinner diameter=\"48\" />\n </div>\n }\n</div>\n", styles: [".main-content{position:relative;height:100%;overflow:hidden}.content-area{height:100%;overflow-y:auto;padding:16px}.shortcut-overlay{position:absolute;inset:0;z-index:15;display:flex;align-items:center;justify-content:center;background-color:#0a0e1480}.shortcut-panel{background-color:var(--color-terminal-bg);border:1px solid var(--color-surface-border);border-radius:6px;padding:14px 18px;font-size:.8rem;box-shadow:0 4px 16px #00000080;min-width:220px}.shortcut-title{font-size:.7rem;text-transform:uppercase;letter-spacing:.05em;margin-bottom:8px;font-weight:500}.shortcut-row{display:flex;align-items:center;gap:10px;padding:3px 0}.shortcut-row.shortcut-dismiss{margin-top:6px;border-top:1px solid var(--color-surface-border);padding-top:8px}.shortcut-key{font-family:Roboto Mono,monospace;font-size:.75rem;background-color:#ffffff14;border:1px solid var(--color-surface-border);border-radius:3px;padding:1px 6px;min-width:70px;text-align:center}.shortcut-desc{font-size:.78rem}.thinking-overlay{position:absolute;inset:0;z-index:20;background-color:#0a0e14b3;display:flex;align-items:center;justify-content:center;pointer-events:all;cursor:wait}\n"], dependencies: [{ kind: "directive", type: RouterOutlet, selector: "router-outlet", inputs: ["name", "routerOutletData"], outputs: ["activate", "deactivate", "attach", "detach"], exportAs: ["outlet"] }, { kind: "ngmodule", type: MatProgressSpinnerModule }, { kind: "component", type: i1$1.MatProgressSpinner, selector: "mat-progress-spinner, mat-spinner", inputs: ["color", "mode", "value", "diameter", "strokeWidth"], exportAs: ["matProgressSpinner"] }] }); }
|
|
661
700
|
}
|
|
662
701
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: MainContent, decorators: [{
|
|
663
702
|
type: Component,
|
|
@@ -665,25 +704,25 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
665
704
|
}] });
|
|
666
705
|
|
|
667
706
|
class CommandTerminal {
|
|
668
|
-
commandService = inject(CommandService);
|
|
669
|
-
registry = inject(CommandRegistryService);
|
|
670
|
-
authService = inject(AuthenticationService);
|
|
671
|
-
terminalFocusService = inject(TerminalFocusService);
|
|
672
|
-
history = computed(() => [...this.commandService.history()].reverse(), ...(ngDevMode ? [{ debugName: "history" }] : /* istanbul ignore next */ []));
|
|
673
|
-
currentInput = this.commandService.currentInput;
|
|
674
|
-
isProcessing = this.commandService.isProcessing;
|
|
675
|
-
inputEl = viewChild('terminalInput', ...(ngDevMode ? [{ debugName: "inputEl" }] : /* istanbul ignore next */ []));
|
|
676
|
-
tabCycleIndex = -1;
|
|
677
|
-
lastTabPrefix = '';
|
|
678
|
-
ghostText = computed(() => {
|
|
679
|
-
const input = this.currentInput().trim();
|
|
680
|
-
if (!input || input.includes(' '))
|
|
681
|
-
return '';
|
|
682
|
-
const prefix = input.toLowerCase();
|
|
683
|
-
const suggestions = this.registry.getSuggestions(prefix, this.authService.authenticated());
|
|
684
|
-
return suggestions.length > 0 ? suggestions[0] : '';
|
|
685
|
-
}, ...(ngDevMode ? [{ debugName: "ghostText" }] : /* istanbul ignore next */ []));
|
|
686
707
|
constructor() {
|
|
708
|
+
this.commandService = inject(CommandService);
|
|
709
|
+
this.registry = inject(CommandRegistryService);
|
|
710
|
+
this.authService = inject(AuthenticationService);
|
|
711
|
+
this.terminalFocusService = inject(TerminalFocusService);
|
|
712
|
+
this.history = computed(() => [...this.commandService.history()].reverse(), ...(ngDevMode ? [{ debugName: "history" }] : /* istanbul ignore next */ []));
|
|
713
|
+
this.currentInput = this.commandService.currentInput;
|
|
714
|
+
this.isProcessing = this.commandService.isProcessing;
|
|
715
|
+
this.inputEl = viewChild('terminalInput', ...(ngDevMode ? [{ debugName: "inputEl" }] : /* istanbul ignore next */ []));
|
|
716
|
+
this.tabCycleIndex = -1;
|
|
717
|
+
this.lastTabPrefix = '';
|
|
718
|
+
this.ghostText = computed(() => {
|
|
719
|
+
const input = this.currentInput().trim();
|
|
720
|
+
if (!input || input.includes(' '))
|
|
721
|
+
return '';
|
|
722
|
+
const prefix = input.toLowerCase();
|
|
723
|
+
const suggestions = this.registry.getSuggestions(prefix, this.authService.authenticated());
|
|
724
|
+
return suggestions.length > 0 ? suggestions[0] : '';
|
|
725
|
+
}, ...(ngDevMode ? [{ debugName: "ghostText" }] : /* istanbul ignore next */ []));
|
|
687
726
|
afterNextRender(() => this.focusInput());
|
|
688
727
|
effect(() => {
|
|
689
728
|
if (!this.isProcessing()) {
|
|
@@ -748,8 +787,8 @@ class CommandTerminal {
|
|
|
748
787
|
focusInput() {
|
|
749
788
|
this.inputEl()?.nativeElement.focus();
|
|
750
789
|
}
|
|
751
|
-
static
|
|
752
|
-
static
|
|
790
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: CommandTerminal, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
791
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: CommandTerminal, isStandalone: true, selector: "shell-command-terminal", viewQueries: [{ propertyName: "inputEl", first: true, predicate: ["terminalInput"], descendants: true, isSignal: true }], ngImport: i0, template: "<div class=\"terminal\">\n <div class=\"terminal-input-row\">\n <span class=\"prompt\">$</span>\n <div class=\"input-wrapper\">\n @if (ghostText()) {\n <input\n class=\"ghost-input\"\n type=\"text\"\n [value]=\"ghostText()\"\n disabled\n tabindex=\"-1\"\n aria-hidden=\"true\"\n />\n }\n <input\n #terminalInput\n class=\"terminal-input\"\n type=\"text\"\n [ngModel]=\"currentInput()\"\n (ngModelChange)=\"onInputChange($event)\"\n (keydown.enter)=\"onSubmit()\"\n (keydown.tab)=\"onTab($any($event))\"\n placeholder=\"Type a command...\"\n [disabled]=\"isProcessing()\"\n autocomplete=\"off\"\n spellcheck=\"false\"\n />\n </div>\n </div>\n <div class=\"terminal-output\">\n @for (entry of history(); track entry.result.timestamp) {\n @if (entry.input) {\n <div class=\"terminal-line\">\n <span class=\"prompt\">$</span>\n <span class=\"command-text\">{{ entry.input }}@if ((entry.repeatCount ?? 1) > 1) { <span class=\"repeat-count\">(\u00D7{{ entry.repeatCount }})</span>}</span>\n </div>\n }\n @if (entry.result.message) {\n <div class=\"terminal-line\" [class]=\"getSeverityClass(entry.result)\">{{ entry.result.message }}</div>\n }\n }\n </div>\n</div>\n", styles: [".terminal{display:flex;flex-direction:column;height:100%;background-color:var(--color-terminal-bg);border-top:1px solid var(--color-surface-border);font-family:Roboto Mono,Courier New,monospace;font-size:.85rem}.terminal-output{flex:1;overflow-y:auto;padding:8px 12px;display:flex;flex-direction:column}.terminal-line{line-height:1.6;color:var(--color-text-primary);white-space:pre-wrap}.terminal-line.error{color:var(--color-loss)}.terminal-line.warning{color:var(--color-warning)}.terminal-line.info{color:var(--color-info)}.prompt{color:var(--color-terminal-prompt);margin-right:8px;font-weight:700}.command-text{color:var(--color-terminal-text)}.repeat-count{color:var(--color-secondary-info);opacity:.6;margin-left:4px}.terminal-input-row{display:flex;align-items:center;padding:8px 12px;border-bottom:1px solid var(--color-surface-border)}.input-wrapper{flex:1;display:grid}.ghost-input,.terminal-input{grid-area:1 / 1;font-family:inherit;font-size:inherit;line-height:normal;margin:0;padding:0;border:none;background:transparent;outline:none;-webkit-appearance:none;appearance:none;width:100%}.ghost-input{color:var(--color-secondary-info);opacity:.3;pointer-events:none}.terminal-input{color:var(--color-terminal-text);caret-color:var(--color-terminal-prompt)}.terminal-input::placeholder{color:var(--color-secondary-info);opacity:.5}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }] }); }
|
|
753
792
|
}
|
|
754
793
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: CommandTerminal, decorators: [{
|
|
755
794
|
type: Component,
|
|
@@ -760,23 +799,30 @@ const MIN_TERMINAL_HEIGHT = 80;
|
|
|
760
799
|
const MAX_TERMINAL_RATIO = 0.6;
|
|
761
800
|
const DEFAULT_TERMINAL_HEIGHT = 160;
|
|
762
801
|
class Shell {
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
this
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
802
|
+
constructor() {
|
|
803
|
+
this.#thinkingService = inject(ThinkingService);
|
|
804
|
+
this.isThinking = this.#thinkingService.isThinking;
|
|
805
|
+
this.terminalHeight = signal(`${DEFAULT_TERMINAL_HEIGHT}px`, ...(ngDevMode ? [{ debugName: "terminalHeight" }] : /* istanbul ignore next */ []));
|
|
806
|
+
this.isDragging = signal(false, ...(ngDevMode ? [{ debugName: "isDragging" }] : /* istanbul ignore next */ []));
|
|
807
|
+
this.#startY = 0;
|
|
808
|
+
this.#startHeight = DEFAULT_TERMINAL_HEIGHT;
|
|
809
|
+
this.#onMouseMove = (event) => {
|
|
810
|
+
const deltaY = event.clientY - this.#startY;
|
|
811
|
+
const maxHeight = Math.floor(window.innerHeight * MAX_TERMINAL_RATIO);
|
|
812
|
+
const newHeight = Math.min(maxHeight, Math.max(MIN_TERMINAL_HEIGHT, this.#startHeight - deltaY));
|
|
813
|
+
this.terminalHeight.set(`${newHeight}px`);
|
|
814
|
+
};
|
|
815
|
+
this.#onMouseUp = () => {
|
|
816
|
+
this.isDragging.set(false);
|
|
817
|
+
document.removeEventListener('mousemove', this.#onMouseMove);
|
|
818
|
+
document.removeEventListener('mouseup', this.#onMouseUp);
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
#thinkingService;
|
|
822
|
+
#startY;
|
|
823
|
+
#startHeight;
|
|
824
|
+
#onMouseMove;
|
|
825
|
+
#onMouseUp;
|
|
780
826
|
onResizeStart(event) {
|
|
781
827
|
event.preventDefault();
|
|
782
828
|
this.#startY = event.clientY;
|
|
@@ -785,29 +831,30 @@ class Shell {
|
|
|
785
831
|
document.addEventListener('mousemove', this.#onMouseMove);
|
|
786
832
|
document.addEventListener('mouseup', this.#onMouseUp);
|
|
787
833
|
}
|
|
788
|
-
static
|
|
789
|
-
static
|
|
834
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: Shell, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
835
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "21.2.7", type: Shell, isStandalone: true, selector: "shell-root", ngImport: i0, template: "<div class=\"shell\" [style.--terminal-height]=\"terminalHeight()\" [class.is-dragging]=\"isDragging()\">\n <shell-status-bar class=\"shell-status\" [class.disabled-zone]=\"isThinking()\">\n <ng-content />\n </shell-status-bar>\n <shell-side-menu class=\"shell-menu\" [class.disabled-zone]=\"isThinking()\" />\n <shell-main-content class=\"shell-main\" />\n <div class=\"shell-resize\" [class.dragging]=\"isDragging()\" (mousedown)=\"onResizeStart($event)\"></div>\n <shell-command-terminal class=\"shell-terminal\" [class.disabled-zone]=\"isThinking()\" />\n</div>\n", styles: [".shell{display:grid;grid-template-areas:\"status status\" \"menu main\" \"resize resize\" \"terminal terminal\";grid-template-columns:56px 1fr;grid-template-rows:48px 1fr 4px var(--terminal-height, 160px);height:100vh;width:100vw;overflow:hidden;background-color:var(--color-surface-dark)}.shell-status{grid-area:status}.shell-menu{grid-area:menu}.shell-main{grid-area:main;overflow:hidden}.shell-resize{grid-area:resize;cursor:row-resize;background-color:var(--color-surface-border);transition:background-color .15s ease}.shell-resize:hover,.shell-resize.dragging{background-color:var(--color-interactive)}.shell-terminal{grid-area:terminal}.shell.is-dragging{user-select:none;-webkit-user-select:none}.disabled-zone{pointer-events:none;opacity:.4;transition:opacity .2s ease}\n"], dependencies: [{ kind: "component", type: StatusBar, selector: "shell-status-bar" }, { kind: "component", type: SideMenu, selector: "shell-side-menu" }, { kind: "component", type: MainContent, selector: "shell-main-content" }, { kind: "component", type: CommandTerminal, selector: "shell-command-terminal" }] }); }
|
|
790
836
|
}
|
|
791
837
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: Shell, decorators: [{
|
|
792
838
|
type: Component,
|
|
793
|
-
args: [{ selector: 'shell-root', imports: [StatusBar, SideMenu, MainContent, CommandTerminal], template: "<div class=\"shell\" [style.--terminal-height]=\"terminalHeight()\" [class.is-dragging]=\"isDragging()\">\n <shell-status-bar class=\"shell-status\" [class.disabled-zone]=\"isThinking()\" />\n <shell-side-menu class=\"shell-menu\" [class.disabled-zone]=\"isThinking()\" />\n <shell-main-content class=\"shell-main\" />\n <div class=\"shell-resize\" [class.dragging]=\"isDragging()\" (mousedown)=\"onResizeStart($event)\"></div>\n <shell-command-terminal class=\"shell-terminal\" [class.disabled-zone]=\"isThinking()\" />\n</div>\n", styles: [".shell{display:grid;grid-template-areas:\"status status\" \"menu main\" \"resize resize\" \"terminal terminal\";grid-template-columns:56px 1fr;grid-template-rows:48px 1fr 4px var(--terminal-height, 160px);height:100vh;width:100vw;overflow:hidden;background-color:var(--color-surface-dark)}.shell-status{grid-area:status}.shell-menu{grid-area:menu}.shell-main{grid-area:main;overflow:hidden}.shell-resize{grid-area:resize;cursor:row-resize;background-color:var(--color-surface-border);transition:background-color .15s ease}.shell-resize:hover,.shell-resize.dragging{background-color:var(--color-interactive)}.shell-terminal{grid-area:terminal}.shell.is-dragging{user-select:none;-webkit-user-select:none}.disabled-zone{pointer-events:none;opacity:.4;transition:opacity .2s ease}\n"] }]
|
|
839
|
+
args: [{ selector: 'shell-root', imports: [StatusBar, SideMenu, MainContent, CommandTerminal], template: "<div class=\"shell\" [style.--terminal-height]=\"terminalHeight()\" [class.is-dragging]=\"isDragging()\">\n <shell-status-bar class=\"shell-status\" [class.disabled-zone]=\"isThinking()\">\n <ng-content />\n </shell-status-bar>\n <shell-side-menu class=\"shell-menu\" [class.disabled-zone]=\"isThinking()\" />\n <shell-main-content class=\"shell-main\" />\n <div class=\"shell-resize\" [class.dragging]=\"isDragging()\" (mousedown)=\"onResizeStart($event)\"></div>\n <shell-command-terminal class=\"shell-terminal\" [class.disabled-zone]=\"isThinking()\" />\n</div>\n", styles: [".shell{display:grid;grid-template-areas:\"status status\" \"menu main\" \"resize resize\" \"terminal terminal\";grid-template-columns:56px 1fr;grid-template-rows:48px 1fr 4px var(--terminal-height, 160px);height:100vh;width:100vw;overflow:hidden;background-color:var(--color-surface-dark)}.shell-status{grid-area:status}.shell-menu{grid-area:menu}.shell-main{grid-area:main;overflow:hidden}.shell-resize{grid-area:resize;cursor:row-resize;background-color:var(--color-surface-border);transition:background-color .15s ease}.shell-resize:hover,.shell-resize.dragging{background-color:var(--color-interactive)}.shell-terminal{grid-area:terminal}.shell.is-dragging{user-select:none;-webkit-user-select:none}.disabled-zone{pointer-events:none;opacity:.4;transition:opacity .2s ease}\n"] }]
|
|
794
840
|
}] });
|
|
795
841
|
|
|
796
842
|
class Login {
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
model = { username: '', password: '' };
|
|
800
|
-
submitted = false;
|
|
801
|
-
hide = signal(true, ...(ngDevMode ? [{ debugName: "hide" }] : /* istanbul ignore next */ []));
|
|
802
|
-
errors = [];
|
|
803
|
-
USERNAME_REGEX = USERNAME_REGEX;
|
|
804
|
-
PASSWORD_REGEX = PASSWORD_REGEX;
|
|
805
|
-
appName = inject(SHELL_APP_NAME, { optional: true }) ?? 'Application';
|
|
806
|
-
#commandService = inject(CommandService);
|
|
807
|
-
#terminalFocusService = inject(TerminalFocusService);
|
|
843
|
+
#commandService;
|
|
844
|
+
#terminalFocusService;
|
|
808
845
|
constructor(authenticationService, router) {
|
|
809
846
|
this.authenticationService = authenticationService;
|
|
810
847
|
this.router = router;
|
|
848
|
+
this.model = { username: '', password: '' };
|
|
849
|
+
this.submitted = false;
|
|
850
|
+
this.hide = signal(true, ...(ngDevMode ? [{ debugName: "hide" }] : /* istanbul ignore next */ []));
|
|
851
|
+
this.takeover = signal(true, ...(ngDevMode ? [{ debugName: "takeover" }] : /* istanbul ignore next */ []));
|
|
852
|
+
this.errors = [];
|
|
853
|
+
this.USERNAME_REGEX = USERNAME_REGEX;
|
|
854
|
+
this.PASSWORD_REGEX = PASSWORD_REGEX;
|
|
855
|
+
this.appName = inject(SHELL_APP_NAME, { optional: true }) ?? 'Application';
|
|
856
|
+
this.#commandService = inject(CommandService);
|
|
857
|
+
this.#terminalFocusService = inject(TerminalFocusService);
|
|
811
858
|
}
|
|
812
859
|
onAutofill(event, inputEl) {
|
|
813
860
|
if (event.isAutofilled) {
|
|
@@ -827,7 +874,7 @@ class Login {
|
|
|
827
874
|
this.submitted = true;
|
|
828
875
|
const result = validateCredentials(this.model);
|
|
829
876
|
if (result === true) {
|
|
830
|
-
this.#doLogin(
|
|
877
|
+
this.#doLogin(this.takeover());
|
|
831
878
|
}
|
|
832
879
|
else {
|
|
833
880
|
for (let ndx = 0; ndx < result.length; ndx++) {
|
|
@@ -864,8 +911,8 @@ class Login {
|
|
|
864
911
|
this.submitted = false;
|
|
865
912
|
});
|
|
866
913
|
}
|
|
867
|
-
static
|
|
868
|
-
static
|
|
914
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: Login, deps: [{ token: AuthenticationService }, { token: i2$1.Router }], target: i0.ɵɵFactoryTarget.Component }); }
|
|
915
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: Login, isStandalone: true, selector: "shell-login", ngImport: i0, template: "@let usernameRegex = USERNAME_REGEX;\n@let passwordRegex = PASSWORD_REGEX;\n<div class=\"login-container\">\n <div class=\"login-header\">\n <h2 class=\"text-text-primary\">{{ appName }}</h2>\n <p class=\"text-secondary-info\">Sign in to continue</p>\n </div>\n <form #loginForm=\"ngForm\" (ngSubmit)=\"onSubmit($event)\" class=\"login-form\">\n <mat-form-field appearance=\"outline\" class=\"login-field\">\n <mat-label>Username</mat-label>\n <input\n #usernameInput\n matInput\n placeholder=\"Enter username\"\n [(ngModel)]=\"model.username\"\n name=\"username\"\n [disabled]=\"submitted\"\n required\n regexValidator\n [regex]=\"usernameRegex\"\n (cdkAutofill)=\"onAutofill($event, usernameInput)\"\n />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"login-field\">\n <mat-label>Password</mat-label>\n <input\n #passwordInput\n matInput\n placeholder=\"Enter password\"\n [type]=\"hide() ? 'password' : 'text'\"\n [(ngModel)]=\"model.password\"\n name=\"password\"\n [disabled]=\"submitted\"\n regexValidator\n [regex]=\"passwordRegex\"\n (cdkAutofill)=\"onAutofill($event, passwordInput)\"\n />\n <button\n mat-icon-button\n matSuffix\n type=\"button\"\n (click)=\"clickEvent($event)\"\n [attr.aria-label]=\"'Hide password'\"\n [attr.aria-pressed]=\"hide()\"\n >\n <mat-icon>{{ hide() ? 'visibility_off' : 'visibility' }}</mat-icon>\n </button>\n </mat-form-field>\n <mat-checkbox\n class=\"login-takeover\"\n name=\"takeover\"\n [checked]=\"takeover()\"\n (change)=\"takeover.set($event.checked)\"\n [disabled]=\"submitted\"\n >\n Takeover session if logged in elsewhere\n </mat-checkbox>\n <button mat-flat-button type=\"submit\" [disabled]=\"submitted\" class=\"login-button\">\n Login\n </button>\n </form>\n @if (errors.length > 0) {\n <div class=\"login-errors\">\n @for (error of errors; track error.ndx) {\n <div class=\"login-error text-loss\">{{ error.message }}</div>\n }\n </div>\n }\n @if (authenticationService.conflictSessions(); as sessions) {\n <div class=\"login-conflict\">\n @for (session of sessions; track $index) {\n <p class=\"text-secondary-info\">\n Already logged in from <strong>{{ session.appContext }}</strong>\n since {{ session.startEpoch | date:'short' }}.\n </p>\n }\n <p class=\"text-secondary-info\">Log in here and end that session?</p>\n <div class=\"login-conflict-actions\">\n <button mat-stroked-button type=\"button\" (click)=\"onCancelConflict()\">Cancel</button>\n <button mat-flat-button type=\"button\" (click)=\"onTakeOver()\">Take Over</button>\n </div>\n </div>\n }\n</div>\n", styles: [".login-container{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;text-align:center}.login-header{margin-bottom:32px}.login-header h2{font-size:1.5rem;font-weight:300;margin-bottom:8px}.login-form{display:flex;flex-direction:column;align-items:center;gap:8px;width:320px}.login-field{width:100%;text-align:left}.login-takeover{align-self:flex-start;margin-top:4px}.login-button{margin-top:8px;width:100%}.login-errors{margin-top:16px;max-width:320px}.login-conflict{margin-top:16px;max-width:320px;padding:12px 16px;border-radius:4px;background-color:var(--color-surface-light);font-size:.85rem;text-align:left}.login-conflict p{margin:0 0 8px}.login-conflict-actions{display:flex;gap:8px;margin-top:12px;justify-content:flex-end}.login-error{padding:8px 12px;margin-bottom:4px;font-size:.85rem;border-radius:4px;background-color:var(--color-surface-light)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i3.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i3.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i3.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i3.RequiredValidator, selector: ":not([type=checkbox])[required][formControlName],:not([type=checkbox])[required][formControl],:not([type=checkbox])[required][ngModel]", inputs: ["required"] }, { kind: "directive", type: i3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: i3.NgForm, selector: "form:not([ngNoForm]):not([formGroup]):not([formArray]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "ngmodule", type: MatInputModule }, { kind: "directive", type: i4.MatSuffix, selector: "[matSuffix], [matIconSuffix], [matTextSuffix]", inputs: ["matTextSuffix"] }, { kind: "directive", type: i5.CdkAutofill, selector: "[cdkAutofill]", outputs: ["cdkAutofill"] }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: i6.MatIconButton, selector: "button[mat-icon-button], a[mat-icon-button], button[matIconButton], a[matIconButton]", exportAs: ["matButton", "matAnchor"] }, { kind: "ngmodule", type: MatCheckboxModule }, { kind: "component", type: i7.MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "ngmodule", type: MatIconModule }, { kind: "component", type: i1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "directive", type: RegexValidatorDirective, selector: "[regexValidator]", inputs: ["regex"] }, { kind: "ngmodule", type: TextFieldModule }, { kind: "pipe", type: DatePipe, name: "date" }] }); }
|
|
869
916
|
}
|
|
870
917
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: Login, decorators: [{
|
|
871
918
|
type: Component,
|
|
@@ -876,18 +923,21 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImpor
|
|
|
876
923
|
MatInput,
|
|
877
924
|
MatInputModule,
|
|
878
925
|
MatButtonModule,
|
|
926
|
+
MatCheckboxModule,
|
|
879
927
|
MatIconModule,
|
|
880
928
|
RegexValidatorDirective,
|
|
881
929
|
TextFieldModule,
|
|
882
930
|
DatePipe,
|
|
883
|
-
], template: "@let usernameRegex = USERNAME_REGEX;\n@let passwordRegex = PASSWORD_REGEX;\n<div class=\"login-container\">\n <div class=\"login-header\">\n <h2 class=\"text-text-primary\">{{ appName }}</h2>\n <p class=\"text-secondary-info\">Sign in to continue</p>\n </div>\n <form #loginForm=\"ngForm\" (ngSubmit)=\"onSubmit($event)\" class=\"login-form\">\n <mat-form-field appearance=\"outline\" class=\"login-field\">\n <mat-label>Username</mat-label>\n <input\n #usernameInput\n matInput\n placeholder=\"Enter username\"\n [(ngModel)]=\"model.username\"\n name=\"username\"\n [disabled]=\"submitted\"\n required\n regexValidator\n [regex]=\"usernameRegex\"\n (cdkAutofill)=\"onAutofill($event, usernameInput)\"\n />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"login-field\">\n <mat-label>Password</mat-label>\n <input\n #passwordInput\n matInput\n placeholder=\"Enter password\"\n [type]=\"hide() ? 'password' : 'text'\"\n [(ngModel)]=\"model.password\"\n name=\"password\"\n [disabled]=\"submitted\"\n regexValidator\n [regex]=\"passwordRegex\"\n (cdkAutofill)=\"onAutofill($event, passwordInput)\"\n />\n <button\n mat-icon-button\n matSuffix\n type=\"button\"\n (click)=\"clickEvent($event)\"\n [attr.aria-label]=\"'Hide password'\"\n [attr.aria-pressed]=\"hide()\"\n >\n <mat-icon>{{ hide() ? 'visibility_off' : 'visibility' }}</mat-icon>\n </button>\n </mat-form-field>\n <button mat-flat-button type=\"submit\" [disabled]=\"submitted\" class=\"login-button\">\n Login\n </button>\n </form>\n @if (errors.length > 0) {\n <div class=\"login-errors\">\n @for (error of errors; track error.ndx) {\n <div class=\"login-error text-loss\">{{ error.message }}</div>\n }\n </div>\n }\n @if (authenticationService.conflictSessions(); as sessions) {\n <div class=\"login-conflict\">\n @for (session of sessions; track $index) {\n <p class=\"text-secondary-info\">\n Already logged in from <strong>{{ session.appContext }}</strong>\n since {{ session.startEpoch | date:'short' }}.\n </p>\n }\n <p class=\"text-secondary-info\">Log in here and end that session?</p>\n <div class=\"login-conflict-actions\">\n <button mat-stroked-button type=\"button\" (click)=\"onCancelConflict()\">Cancel</button>\n <button mat-flat-button type=\"button\" (click)=\"onTakeOver()\">Take Over</button>\n </div>\n </div>\n }\n</div>\n", styles: [".login-container{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;text-align:center}.login-header{margin-bottom:32px}.login-header h2{font-size:1.5rem;font-weight:300;margin-bottom:8px}.login-form{display:flex;flex-direction:column;align-items:center;gap:8px;width:320px}.login-field{width:100%;text-align:left}.login-button{margin-top:8px;width:100%}.login-errors{margin-top:16px;max-width:320px}.login-conflict{margin-top:16px;max-width:320px;padding:12px 16px;border-radius:4px;background-color:var(--color-surface-light);font-size:.85rem;text-align:left}.login-conflict p{margin:0 0 8px}.login-conflict-actions{display:flex;gap:8px;margin-top:12px;justify-content:flex-end}.login-error{padding:8px 12px;margin-bottom:4px;font-size:.85rem;border-radius:4px;background-color:var(--color-surface-light)}\n"] }]
|
|
931
|
+
], template: "@let usernameRegex = USERNAME_REGEX;\n@let passwordRegex = PASSWORD_REGEX;\n<div class=\"login-container\">\n <div class=\"login-header\">\n <h2 class=\"text-text-primary\">{{ appName }}</h2>\n <p class=\"text-secondary-info\">Sign in to continue</p>\n </div>\n <form #loginForm=\"ngForm\" (ngSubmit)=\"onSubmit($event)\" class=\"login-form\">\n <mat-form-field appearance=\"outline\" class=\"login-field\">\n <mat-label>Username</mat-label>\n <input\n #usernameInput\n matInput\n placeholder=\"Enter username\"\n [(ngModel)]=\"model.username\"\n name=\"username\"\n [disabled]=\"submitted\"\n required\n regexValidator\n [regex]=\"usernameRegex\"\n (cdkAutofill)=\"onAutofill($event, usernameInput)\"\n />\n </mat-form-field>\n <mat-form-field appearance=\"outline\" class=\"login-field\">\n <mat-label>Password</mat-label>\n <input\n #passwordInput\n matInput\n placeholder=\"Enter password\"\n [type]=\"hide() ? 'password' : 'text'\"\n [(ngModel)]=\"model.password\"\n name=\"password\"\n [disabled]=\"submitted\"\n regexValidator\n [regex]=\"passwordRegex\"\n (cdkAutofill)=\"onAutofill($event, passwordInput)\"\n />\n <button\n mat-icon-button\n matSuffix\n type=\"button\"\n (click)=\"clickEvent($event)\"\n [attr.aria-label]=\"'Hide password'\"\n [attr.aria-pressed]=\"hide()\"\n >\n <mat-icon>{{ hide() ? 'visibility_off' : 'visibility' }}</mat-icon>\n </button>\n </mat-form-field>\n <mat-checkbox\n class=\"login-takeover\"\n name=\"takeover\"\n [checked]=\"takeover()\"\n (change)=\"takeover.set($event.checked)\"\n [disabled]=\"submitted\"\n >\n Takeover session if logged in elsewhere\n </mat-checkbox>\n <button mat-flat-button type=\"submit\" [disabled]=\"submitted\" class=\"login-button\">\n Login\n </button>\n </form>\n @if (errors.length > 0) {\n <div class=\"login-errors\">\n @for (error of errors; track error.ndx) {\n <div class=\"login-error text-loss\">{{ error.message }}</div>\n }\n </div>\n }\n @if (authenticationService.conflictSessions(); as sessions) {\n <div class=\"login-conflict\">\n @for (session of sessions; track $index) {\n <p class=\"text-secondary-info\">\n Already logged in from <strong>{{ session.appContext }}</strong>\n since {{ session.startEpoch | date:'short' }}.\n </p>\n }\n <p class=\"text-secondary-info\">Log in here and end that session?</p>\n <div class=\"login-conflict-actions\">\n <button mat-stroked-button type=\"button\" (click)=\"onCancelConflict()\">Cancel</button>\n <button mat-flat-button type=\"button\" (click)=\"onTakeOver()\">Take Over</button>\n </div>\n </div>\n }\n</div>\n", styles: [".login-container{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100%;text-align:center}.login-header{margin-bottom:32px}.login-header h2{font-size:1.5rem;font-weight:300;margin-bottom:8px}.login-form{display:flex;flex-direction:column;align-items:center;gap:8px;width:320px}.login-field{width:100%;text-align:left}.login-takeover{align-self:flex-start;margin-top:4px}.login-button{margin-top:8px;width:100%}.login-errors{margin-top:16px;max-width:320px}.login-conflict{margin-top:16px;max-width:320px;padding:12px 16px;border-radius:4px;background-color:var(--color-surface-light);font-size:.85rem;text-align:left}.login-conflict p{margin:0 0 8px}.login-conflict-actions{display:flex;gap:8px;margin-top:12px;justify-content:flex-end}.login-error{padding:8px 12px;margin-bottom:4px;font-size:.85rem;border-radius:4px;background-color:var(--color-surface-light)}\n"] }]
|
|
884
932
|
}], ctorParameters: () => [{ type: AuthenticationService }, { type: i2$1.Router }] });
|
|
885
933
|
|
|
886
934
|
class ConfirmDialog {
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
935
|
+
constructor() {
|
|
936
|
+
this.data = inject(MAT_DIALOG_DATA);
|
|
937
|
+
this.dialogRef = inject((MatDialogRef));
|
|
938
|
+
}
|
|
939
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ConfirmDialog, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
940
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.7", type: ConfirmDialog, isStandalone: true, selector: "shell-confirm-dialog", ngImport: i0, template: `
|
|
891
941
|
<h2 mat-dialog-title>{{ data.title }}</h2>
|
|
892
942
|
<mat-dialog-content>
|
|
893
943
|
<p>{{ data.message }}</p>
|
|
@@ -899,7 +949,7 @@ class ConfirmDialog {
|
|
|
899
949
|
<button mat-button (click)="dialogRef.close(false)">{{ data.cancelLabel ?? 'Cancel' }}</button>
|
|
900
950
|
<button mat-flat-button color="warn" (click)="dialogRef.close(true)">{{ data.confirmLabel ?? 'Confirm' }}</button>
|
|
901
951
|
</mat-dialog-actions>
|
|
902
|
-
`, isInline: true, styles: [":host{display:block}.warning-message{color:var(--color-warning);margin-top:8px}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1$2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }] });
|
|
952
|
+
`, isInline: true, styles: [":host{display:block}.warning-message{color:var(--color-warning);margin-top:8px}\n"], dependencies: [{ kind: "ngmodule", type: MatDialogModule }, { kind: "directive", type: i1$2.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: i1$2.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "directive", type: i1$2.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "ngmodule", type: MatButtonModule }, { kind: "component", type: i6.MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }] }); }
|
|
903
953
|
}
|
|
904
954
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.7", ngImport: i0, type: ConfirmDialog, decorators: [{
|
|
905
955
|
type: Component,
|