ngx-dev-toolbar 1.0.4 → 2.0.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/components/icons/bolt-icon.component.d.ts +6 -0
- package/components/icons/filter-icon.component.d.ts +6 -0
- package/components/icons/icon.models.d.ts +1 -1
- package/components/icons/lock-icon.component.d.ts +6 -0
- package/components/select/select.component.d.ts +1 -1
- package/components/window/window.component.d.ts +1 -1
- package/dev-toolbar-state.service.d.ts +1 -1
- package/dev-toolbar.component.d.ts +3 -2
- package/fesm2022/ngx-dev-toolbar.mjs +2074 -139
- package/fesm2022/ngx-dev-toolbar.mjs.map +1 -1
- package/index.d.ts +10 -0
- package/models/dev-toolbar-config.interface.d.ts +31 -0
- package/package.json +2 -2
- package/tools/app-features-tool/app-features-internal.service.d.ts +102 -0
- package/tools/app-features-tool/app-features-tool.component.d.ts +61 -0
- package/tools/app-features-tool/app-features.models.d.ts +109 -0
- package/tools/app-features-tool/app-features.service.d.ts +151 -0
- package/tools/feature-flags-tool/feature-flags-internal.service.d.ts +15 -0
- package/tools/language-tool/language-internal.service.d.ts +10 -0
- package/tools/permissions-tool/permissions-internal.service.d.ts +34 -0
- package/tools/permissions-tool/permissions-tool.component.d.ts +27 -0
- package/tools/permissions-tool/permissions.models.d.ts +34 -0
- package/tools/permissions-tool/permissions.service.d.ts +87 -0
- package/tools/presets-tool/presets-internal.service.d.ts +57 -0
- package/tools/presets-tool/presets-tool.component.d.ts +33 -0
- package/tools/presets-tool/presets.models.d.ts +24 -0
- package/tools/presets-tool/presets.service.d.ts +51 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { signal, computed, Injectable, Component, ChangeDetectionStrategy, input, inject, ElementRef, output, ViewChild, ContentChild, model, DestroyRef
|
|
2
|
+
import { signal, computed, Injectable, Component, ChangeDetectionStrategy, input, inject, ElementRef, output, ViewEncapsulation, ViewChild, ContentChild, model, DestroyRef } from '@angular/core';
|
|
3
3
|
import { trigger, state, style, transition, animate } from '@angular/animations';
|
|
4
4
|
import * as i1 from '@angular/cdk/overlay';
|
|
5
5
|
import { CdkConnectedOverlay, OverlayModule } from '@angular/cdk/overlay';
|
|
@@ -158,6 +158,55 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
158
158
|
}]
|
|
159
159
|
}] });
|
|
160
160
|
|
|
161
|
+
class BoltIconComponent {
|
|
162
|
+
constructor() {
|
|
163
|
+
this.fill = input('#FFFF');
|
|
164
|
+
}
|
|
165
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: BoltIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
166
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.0.5", type: BoltIconComponent, isStandalone: true, selector: "ndt-bolt-icon", inputs: { fill: { classPropertyName: "fill", publicName: "fill", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
167
|
+
<svg
|
|
168
|
+
[attr.fill]="fill()"
|
|
169
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
170
|
+
width="24"
|
|
171
|
+
height="24"
|
|
172
|
+
viewBox="0 0 256 256"
|
|
173
|
+
>
|
|
174
|
+
<path
|
|
175
|
+
d="M160,16,144,96H208l-96,144,16-80H64Z"
|
|
176
|
+
opacity="0.2"
|
|
177
|
+
></path>
|
|
178
|
+
<path
|
|
179
|
+
d="M215.79,118.17a8,8,0,0,0-5-5.66L153.18,90.9l14.66-73.33a8,8,0,0,0-13.69-7l-112,120a8,8,0,0,0,3,13l57.63,21.61L88.16,238.43a8,8,0,0,0,13.69,7l112-120A8,8,0,0,0,215.79,118.17ZM109.37,214l10.47-52.38a8,8,0,0,0-5-9.06L62,132.71l84.62-90.66L136.16,94.43a8,8,0,0,0,5,9.06l52.8,19.8Z"
|
|
180
|
+
></path>
|
|
181
|
+
</svg>
|
|
182
|
+
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
183
|
+
}
|
|
184
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: BoltIconComponent, decorators: [{
|
|
185
|
+
type: Component,
|
|
186
|
+
args: [{
|
|
187
|
+
selector: 'ndt-bolt-icon',
|
|
188
|
+
standalone: true,
|
|
189
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
190
|
+
template: `
|
|
191
|
+
<svg
|
|
192
|
+
[attr.fill]="fill()"
|
|
193
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
194
|
+
width="24"
|
|
195
|
+
height="24"
|
|
196
|
+
viewBox="0 0 256 256"
|
|
197
|
+
>
|
|
198
|
+
<path
|
|
199
|
+
d="M160,16,144,96H208l-96,144,16-80H64Z"
|
|
200
|
+
opacity="0.2"
|
|
201
|
+
></path>
|
|
202
|
+
<path
|
|
203
|
+
d="M215.79,118.17a8,8,0,0,0-5-5.66L153.18,90.9l14.66-73.33a8,8,0,0,0-13.69-7l-112,120a8,8,0,0,0,3,13l57.63,21.61L88.16,238.43a8,8,0,0,0,13.69,7l112-120A8,8,0,0,0,215.79,118.17ZM109.37,214l10.47-52.38a8,8,0,0,0-5-9.06L62,132.71l84.62-90.66L136.16,94.43a8,8,0,0,0,5,9.06l52.8,19.8Z"
|
|
204
|
+
></path>
|
|
205
|
+
</svg>
|
|
206
|
+
`,
|
|
207
|
+
}]
|
|
208
|
+
}] });
|
|
209
|
+
|
|
161
210
|
class BugIconComponent {
|
|
162
211
|
constructor() {
|
|
163
212
|
this.fill = input('#FFFF');
|
|
@@ -414,6 +463,55 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
414
463
|
}]
|
|
415
464
|
}] });
|
|
416
465
|
|
|
466
|
+
class FilterIconComponent {
|
|
467
|
+
constructor() {
|
|
468
|
+
this.fill = input('#FFFF');
|
|
469
|
+
}
|
|
470
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: FilterIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
471
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.0.5", type: FilterIconComponent, isStandalone: true, selector: "ndt-filter-icon", inputs: { fill: { classPropertyName: "fill", publicName: "fill", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
472
|
+
<svg
|
|
473
|
+
[attr.fill]="fill()"
|
|
474
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
475
|
+
width="24"
|
|
476
|
+
height="24"
|
|
477
|
+
viewBox="0 0 256 256"
|
|
478
|
+
>
|
|
479
|
+
<path
|
|
480
|
+
d="M227.81,66.76l-.08.09L160,139.17v55.49A8,8,0,0,1,156.94,201l-32,21.33A8,8,0,0,1,112,216V139.17L44.27,66.85l-.08-.09A16,16,0,0,1,56,40H200a16,16,0,0,1,11.84,26.76Z"
|
|
481
|
+
opacity="0.2"
|
|
482
|
+
></path>
|
|
483
|
+
<path
|
|
484
|
+
d="M230.6,49.53A23.94,23.94,0,0,0,200,32H56A24,24,0,0,0,38.15,65.67L104,139.37V216a8,8,0,0,0,11.58,7.16l32-16A8,8,0,0,0,152,200V139.37l65.85-73.7A23.93,23.93,0,0,0,230.6,49.53ZM203.36,54.86a8,8,0,0,1,.07,9.12L136,139.17V196.58l-16,8V139.17L52.57,64A8,8,0,0,1,56,48H200A8,8,0,0,1,203.36,54.86Z"
|
|
485
|
+
></path>
|
|
486
|
+
</svg>
|
|
487
|
+
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
488
|
+
}
|
|
489
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: FilterIconComponent, decorators: [{
|
|
490
|
+
type: Component,
|
|
491
|
+
args: [{
|
|
492
|
+
selector: 'ndt-filter-icon',
|
|
493
|
+
standalone: true,
|
|
494
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
495
|
+
template: `
|
|
496
|
+
<svg
|
|
497
|
+
[attr.fill]="fill()"
|
|
498
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
499
|
+
width="24"
|
|
500
|
+
height="24"
|
|
501
|
+
viewBox="0 0 256 256"
|
|
502
|
+
>
|
|
503
|
+
<path
|
|
504
|
+
d="M227.81,66.76l-.08.09L160,139.17v55.49A8,8,0,0,1,156.94,201l-32,21.33A8,8,0,0,1,112,216V139.17L44.27,66.85l-.08-.09A16,16,0,0,1,56,40H200a16,16,0,0,1,11.84,26.76Z"
|
|
505
|
+
opacity="0.2"
|
|
506
|
+
></path>
|
|
507
|
+
<path
|
|
508
|
+
d="M230.6,49.53A23.94,23.94,0,0,0,200,32H56A24,24,0,0,0,38.15,65.67L104,139.37V216a8,8,0,0,0,11.58,7.16l32-16A8,8,0,0,0,152,200V139.37l65.85-73.7A23.93,23.93,0,0,0,230.6,49.53ZM203.36,54.86a8,8,0,0,1,.07,9.12L136,139.17V196.58l-16,8V139.17L52.57,64A8,8,0,0,1,56,48H200A8,8,0,0,1,203.36,54.86Z"
|
|
509
|
+
></path>
|
|
510
|
+
</svg>
|
|
511
|
+
`,
|
|
512
|
+
}]
|
|
513
|
+
}] });
|
|
514
|
+
|
|
417
515
|
class GaugeIconComponent {
|
|
418
516
|
constructor() {
|
|
419
517
|
this.fill = input('#FFFF');
|
|
@@ -729,6 +827,47 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
729
827
|
}]
|
|
730
828
|
}] });
|
|
731
829
|
|
|
830
|
+
class LockIconComponent {
|
|
831
|
+
constructor() {
|
|
832
|
+
this.fill = input('#FFFF');
|
|
833
|
+
}
|
|
834
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LockIconComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
835
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.1.0", version: "19.0.5", type: LockIconComponent, isStandalone: true, selector: "ndt-lock-icon", inputs: { fill: { classPropertyName: "fill", publicName: "fill", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
836
|
+
<svg
|
|
837
|
+
[attr.fill]="fill()"
|
|
838
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
839
|
+
width="24"
|
|
840
|
+
height="24"
|
|
841
|
+
viewBox="0 0 256 256"
|
|
842
|
+
>
|
|
843
|
+
<path
|
|
844
|
+
d="M208,80H176V56a48,48,0,0,0-96,0V80H48A16,16,0,0,0,32,96V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V96A16,16,0,0,0,208,80ZM96,56a32,32,0,0,1,64,0V80H96ZM208,208H48V96H208V208Zm-68-56a12,12,0,1,1-12-12A12,12,0,0,1,140,152Z"
|
|
845
|
+
></path>
|
|
846
|
+
</svg>
|
|
847
|
+
`, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
848
|
+
}
|
|
849
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: LockIconComponent, decorators: [{
|
|
850
|
+
type: Component,
|
|
851
|
+
args: [{
|
|
852
|
+
selector: 'ndt-lock-icon',
|
|
853
|
+
standalone: true,
|
|
854
|
+
changeDetection: ChangeDetectionStrategy.OnPush,
|
|
855
|
+
template: `
|
|
856
|
+
<svg
|
|
857
|
+
[attr.fill]="fill()"
|
|
858
|
+
xmlns="http://www.w3.org/2000/svg"
|
|
859
|
+
width="24"
|
|
860
|
+
height="24"
|
|
861
|
+
viewBox="0 0 256 256"
|
|
862
|
+
>
|
|
863
|
+
<path
|
|
864
|
+
d="M208,80H176V56a48,48,0,0,0-96,0V80H48A16,16,0,0,0,32,96V208a16,16,0,0,0,16,16H208a16,16,0,0,0,16-16V96A16,16,0,0,0,208,80ZM96,56a32,32,0,0,1,64,0V80H96ZM208,208H48V96H208V208Zm-68-56a12,12,0,1,1-12-12A12,12,0,0,1,140,152Z"
|
|
865
|
+
></path>
|
|
866
|
+
</svg>
|
|
867
|
+
`,
|
|
868
|
+
}]
|
|
869
|
+
}] });
|
|
870
|
+
|
|
732
871
|
class MoonIconComponent {
|
|
733
872
|
constructor() {
|
|
734
873
|
this.fill = input('#FFFF');
|
|
@@ -1262,6 +1401,8 @@ class DevToolbarIconComponent {
|
|
|
1262
1401
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: DevToolbarIconComponent, isStandalone: true, selector: "ndt-icon", inputs: { name: { classPropertyName: "name", publicName: "name", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0, template: `
|
|
1263
1402
|
@switch (name()) { @case ('angular') {
|
|
1264
1403
|
<ndt-angular-icon />
|
|
1404
|
+
} @case ('bolt') {
|
|
1405
|
+
<ndt-bolt-icon [fill]="fill()" />
|
|
1265
1406
|
} @case ('bug') {
|
|
1266
1407
|
<ndt-bug-icon [fill]="fill()" />
|
|
1267
1408
|
} @case ('code') {
|
|
@@ -1272,6 +1413,8 @@ class DevToolbarIconComponent {
|
|
|
1272
1413
|
<ndt-docs-icon [fill]="fill()" />
|
|
1273
1414
|
} @case ('export') {
|
|
1274
1415
|
<ndt-export-icon [fill]="fill()" />
|
|
1416
|
+
} @case ('filter') {
|
|
1417
|
+
<ndt-filter-icon [fill]="fill()" />
|
|
1275
1418
|
} @case ('gauge') {
|
|
1276
1419
|
<ndt-gauge-icon [fill]="fill()" />
|
|
1277
1420
|
} @case ('gear') {
|
|
@@ -1286,6 +1429,8 @@ class DevToolbarIconComponent {
|
|
|
1286
1429
|
<ndt-lighting-icon [fill]="fill()" />
|
|
1287
1430
|
} @case ('lightbulb') {
|
|
1288
1431
|
<ndt-lightbulb-icon [fill]="fill()" />
|
|
1432
|
+
} @case ('lock') {
|
|
1433
|
+
<ndt-lock-icon [fill]="fill()" />
|
|
1289
1434
|
} @case ('network') {
|
|
1290
1435
|
<ndt-network-icon [fill]="fill()" />
|
|
1291
1436
|
} @case ('puzzle') {
|
|
@@ -1311,7 +1456,7 @@ class DevToolbarIconComponent {
|
|
|
1311
1456
|
} @case ('trash') {
|
|
1312
1457
|
<ndt-trash-icon [fill]="fill()" />
|
|
1313
1458
|
} }
|
|
1314
|
-
`, isInline: true, dependencies: [{ kind: "component", type: AngularIconComponent, selector: "ndt-angular-icon" }, { kind: "component", type: BugIconComponent, selector: "ndt-bug-icon", inputs: ["fill"] }, { kind: "component", type: CodeIconComponent, selector: "ndt-code-icon", inputs: ["fill"] }, { kind: "component", type: DatabaseIconComponent, selector: "ndt-database-icon", inputs: ["fill"] }, { kind: "component", type: DocsIconComponent, selector: "ndt-docs-icon", inputs: ["fill"] }, { kind: "component", type: DiscordIconComponent, selector: "ndt-discord-icon", inputs: ["fill"] }, { kind: "component", type: ExportIconComponent, selector: "ndt-export-icon", inputs: ["fill"] }, { kind: "component", type: GaugeIconComponent, selector: "ndt-gauge-icon", inputs: ["fill"] }, { kind: "component", type: GearIconComponent, selector: "ndt-gear-icon", inputs: ["fill"] }, { kind: "component", type: GitBranchIconComponent, selector: "ndt-git-branch-icon", inputs: ["fill"] }, { kind: "component", type: ImportIconComponent, selector: "ndt-import-icon", inputs: ["fill"] }, { kind: "component", type: LayoutIconComponent, selector: "ndt-layout-icon", inputs: ["fill"] }, { kind: "component", type: LightbulbIconComponent, selector: "ndt-lightbulb-icon", inputs: ["fill"] }, { kind: "component", type: LightingIconComponent, selector: "ndt-lighting-icon", inputs: ["fill"] }, { kind: "component", type: NetworkIconComponent, selector: "ndt-network-icon", inputs: ["fill"] }, { kind: "component", type: PuzzleIconComponent, selector: "ndt-puzzle-icon", inputs: ["fill"] }, { kind: "component", type: RefreshIconComponent, selector: "ndt-refresh-icon", inputs: ["fill"] }, { kind: "component", type: StarIconComponent, selector: "ndt-star-icon", inputs: ["fill"] }, { kind: "component", type: TerminalIconComponent, selector: "ndt-terminal-icon", inputs: ["fill"] }, { kind: "component", type: ToggleLeftIconComponent, selector: "ndt-toggle-left-icon", inputs: ["fill"] }, { kind: "component", type: UsersIconComponent, selector: "ndt-users-icon", inputs: ["fill"] }, { kind: "component", type: SunIconComponent, selector: "ndt-sun-icon", inputs: ["fill"] }, { kind: "component", type: MoonIconComponent, selector: "ndt-moon-icon", inputs: ["fill"] }, { kind: "component", type: TranslateIconComponent, selector: "ndt-translate-icon", inputs: ["fill"] }, { kind: "component", type: TrashIconComponent, selector: "ndt-trash-icon", inputs: ["fill"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1459
|
+
`, isInline: true, dependencies: [{ kind: "component", type: AngularIconComponent, selector: "ndt-angular-icon" }, { kind: "component", type: BoltIconComponent, selector: "ndt-bolt-icon", inputs: ["fill"] }, { kind: "component", type: BugIconComponent, selector: "ndt-bug-icon", inputs: ["fill"] }, { kind: "component", type: CodeIconComponent, selector: "ndt-code-icon", inputs: ["fill"] }, { kind: "component", type: DatabaseIconComponent, selector: "ndt-database-icon", inputs: ["fill"] }, { kind: "component", type: DocsIconComponent, selector: "ndt-docs-icon", inputs: ["fill"] }, { kind: "component", type: DiscordIconComponent, selector: "ndt-discord-icon", inputs: ["fill"] }, { kind: "component", type: ExportIconComponent, selector: "ndt-export-icon", inputs: ["fill"] }, { kind: "component", type: FilterIconComponent, selector: "ndt-filter-icon", inputs: ["fill"] }, { kind: "component", type: GaugeIconComponent, selector: "ndt-gauge-icon", inputs: ["fill"] }, { kind: "component", type: GearIconComponent, selector: "ndt-gear-icon", inputs: ["fill"] }, { kind: "component", type: GitBranchIconComponent, selector: "ndt-git-branch-icon", inputs: ["fill"] }, { kind: "component", type: ImportIconComponent, selector: "ndt-import-icon", inputs: ["fill"] }, { kind: "component", type: LayoutIconComponent, selector: "ndt-layout-icon", inputs: ["fill"] }, { kind: "component", type: LightbulbIconComponent, selector: "ndt-lightbulb-icon", inputs: ["fill"] }, { kind: "component", type: LightingIconComponent, selector: "ndt-lighting-icon", inputs: ["fill"] }, { kind: "component", type: LockIconComponent, selector: "ndt-lock-icon", inputs: ["fill"] }, { kind: "component", type: NetworkIconComponent, selector: "ndt-network-icon", inputs: ["fill"] }, { kind: "component", type: PuzzleIconComponent, selector: "ndt-puzzle-icon", inputs: ["fill"] }, { kind: "component", type: RefreshIconComponent, selector: "ndt-refresh-icon", inputs: ["fill"] }, { kind: "component", type: StarIconComponent, selector: "ndt-star-icon", inputs: ["fill"] }, { kind: "component", type: TerminalIconComponent, selector: "ndt-terminal-icon", inputs: ["fill"] }, { kind: "component", type: ToggleLeftIconComponent, selector: "ndt-toggle-left-icon", inputs: ["fill"] }, { kind: "component", type: UsersIconComponent, selector: "ndt-users-icon", inputs: ["fill"] }, { kind: "component", type: SunIconComponent, selector: "ndt-sun-icon", inputs: ["fill"] }, { kind: "component", type: MoonIconComponent, selector: "ndt-moon-icon", inputs: ["fill"] }, { kind: "component", type: TranslateIconComponent, selector: "ndt-translate-icon", inputs: ["fill"] }, { kind: "component", type: TrashIconComponent, selector: "ndt-trash-icon", inputs: ["fill"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1315
1460
|
}
|
|
1316
1461
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarIconComponent, decorators: [{
|
|
1317
1462
|
type: Component,
|
|
@@ -1320,12 +1465,14 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
1320
1465
|
standalone: true,
|
|
1321
1466
|
imports: [
|
|
1322
1467
|
AngularIconComponent,
|
|
1468
|
+
BoltIconComponent,
|
|
1323
1469
|
BugIconComponent,
|
|
1324
1470
|
CodeIconComponent,
|
|
1325
1471
|
DatabaseIconComponent,
|
|
1326
1472
|
DocsIconComponent,
|
|
1327
1473
|
DiscordIconComponent,
|
|
1328
1474
|
ExportIconComponent,
|
|
1475
|
+
FilterIconComponent,
|
|
1329
1476
|
GaugeIconComponent,
|
|
1330
1477
|
GearIconComponent,
|
|
1331
1478
|
GitBranchIconComponent,
|
|
@@ -1333,6 +1480,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
1333
1480
|
LayoutIconComponent,
|
|
1334
1481
|
LightbulbIconComponent,
|
|
1335
1482
|
LightingIconComponent,
|
|
1483
|
+
LockIconComponent,
|
|
1336
1484
|
NetworkIconComponent,
|
|
1337
1485
|
PuzzleIconComponent,
|
|
1338
1486
|
RefreshIconComponent,
|
|
@@ -1349,6 +1497,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
1349
1497
|
template: `
|
|
1350
1498
|
@switch (name()) { @case ('angular') {
|
|
1351
1499
|
<ndt-angular-icon />
|
|
1500
|
+
} @case ('bolt') {
|
|
1501
|
+
<ndt-bolt-icon [fill]="fill()" />
|
|
1352
1502
|
} @case ('bug') {
|
|
1353
1503
|
<ndt-bug-icon [fill]="fill()" />
|
|
1354
1504
|
} @case ('code') {
|
|
@@ -1359,6 +1509,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
1359
1509
|
<ndt-docs-icon [fill]="fill()" />
|
|
1360
1510
|
} @case ('export') {
|
|
1361
1511
|
<ndt-export-icon [fill]="fill()" />
|
|
1512
|
+
} @case ('filter') {
|
|
1513
|
+
<ndt-filter-icon [fill]="fill()" />
|
|
1362
1514
|
} @case ('gauge') {
|
|
1363
1515
|
<ndt-gauge-icon [fill]="fill()" />
|
|
1364
1516
|
} @case ('gear') {
|
|
@@ -1373,6 +1525,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
1373
1525
|
<ndt-lighting-icon [fill]="fill()" />
|
|
1374
1526
|
} @case ('lightbulb') {
|
|
1375
1527
|
<ndt-lightbulb-icon [fill]="fill()" />
|
|
1528
|
+
} @case ('lock') {
|
|
1529
|
+
<ndt-lock-icon [fill]="fill()" />
|
|
1376
1530
|
} @case ('network') {
|
|
1377
1531
|
<ndt-network-icon [fill]="fill()" />
|
|
1378
1532
|
} @case ('puzzle') {
|
|
@@ -1464,7 +1618,7 @@ class DevToolbarToolButtonComponent {
|
|
|
1464
1618
|
}
|
|
1465
1619
|
<ng-content />
|
|
1466
1620
|
</button>
|
|
1467
|
-
`, isInline: true, styles: [".
|
|
1621
|
+
`, isInline: true, styles: [".tool-button{display:flex;justify-content:center;align-items:center;width:44px;height:40px;border:0;background:transparent;color:var(--ndt-text-primary);transition:var(--ndt-transition-default);cursor:pointer;opacity:.5;position:relative}.tool-button--active,.tool-button:hover{background:var(--ndt-hover-bg);opacity:1}.tool-button ::ng-deep svg{width:24px;height:24px;display:block;margin:auto}.tool-button__badge{position:absolute;top:-.25rem;right:-.25rem;background-color:var(--ndt-hover-danger);color:var(--ndt-text-primary);border-radius:var(--ndt-border-radius-full);min-width:1rem;height:1rem;font-size:.75rem;display:flex;align-items:center;justify-content:center;padding:.125rem}.tooltip{position:absolute;bottom:calc(100% + 1.2rem);left:50%;transform:translate(-50%);background:var(--ndt-bg-primary);color:var(--ndt-text-primary);padding:.5rem .75rem;border-radius:var(--ndt-border-radius-medium);font-size:.75rem;white-space:nowrap;pointer-events:none;z-index:1000;box-shadow:var(--ndt-shadow-tooltip)}\n"], animations: [
|
|
1468
1622
|
trigger('tooltipAnimation', [
|
|
1469
1623
|
state('hidden', style({
|
|
1470
1624
|
opacity: 0,
|
|
@@ -1515,7 +1669,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
1515
1669
|
transition('hidden => visible', [animate('200ms ease-out')]),
|
|
1516
1670
|
transition('visible => hidden', [animate('150ms ease-in')]),
|
|
1517
1671
|
]),
|
|
1518
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, styles: [".
|
|
1672
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, styles: [".tool-button{display:flex;justify-content:center;align-items:center;width:44px;height:40px;border:0;background:transparent;color:var(--ndt-text-primary);transition:var(--ndt-transition-default);cursor:pointer;opacity:.5;position:relative}.tool-button--active,.tool-button:hover{background:var(--ndt-hover-bg);opacity:1}.tool-button ::ng-deep svg{width:24px;height:24px;display:block;margin:auto}.tool-button__badge{position:absolute;top:-.25rem;right:-.25rem;background-color:var(--ndt-hover-danger);color:var(--ndt-text-primary);border-radius:var(--ndt-border-radius-full);min-width:1rem;height:1rem;font-size:.75rem;display:flex;align-items:center;justify-content:center;padding:.125rem}.tooltip{position:absolute;bottom:calc(100% + 1.2rem);left:50%;transform:translate(-50%);background:var(--ndt-bg-primary);color:var(--ndt-text-primary);padding:.5rem .75rem;border-radius:var(--ndt-border-radius-medium);font-size:.75rem;white-space:nowrap;pointer-events:none;z-index:1000;box-shadow:var(--ndt-shadow-tooltip)}\n"] }]
|
|
1519
1673
|
}] });
|
|
1520
1674
|
|
|
1521
1675
|
class DevToolbarWindowComponent {
|
|
@@ -1575,11 +1729,11 @@ class DevToolbarWindowComponent {
|
|
|
1575
1729
|
<ng-content></ng-content>
|
|
1576
1730
|
</div>
|
|
1577
1731
|
</div>
|
|
1578
|
-
`, isInline: true, styles: ["
|
|
1732
|
+
`, isInline: true, styles: [":host{--ndt-border-radius-small: 4px;--ndt-border-radius-medium: 8px;--ndt-border-radius-large: 12px;--ndt-transition-default: all .2s ease-out;--ndt-transition-smooth: all .2s ease-in-out;--ndt-bg-primary: rgb(255, 255, 255);--ndt-bg-gradient: linear-gradient(180deg, rgb(243, 244, 246) 0%, rgba(243, 244, 246, .88) 100%);--ndt-text-primary: rgb(17, 24, 39);--ndt-text-secondary: rgb(55, 65, 81);--ndt-text-muted: rgb(107, 114, 128);--ndt-border-primary: #e5e7eb;--ndt-border-subtle: rgba(17, 24, 39, .1);--ndt-hover-bg: rgba(17, 24, 39, .05);--ndt-hover-danger: rgb(239, 68, 68);--ndt-shadow-toolbar: 0 2px 8px rgba(156, 163, 175, .2);--ndt-shadow-tooltip: 0 0 0 1px rgba(17, 24, 39, .05), 0 4px 8px rgba(107, 114, 128, .15), 0 2px 4px rgba(107, 114, 128, .1);--ndt-shadow-window: 0px 0px 0px 0px rgba(156, 163, 175, .1), 0px 1px 2px 0px rgba(156, 163, 175, .12), 0px 4px 4px 0px rgba(156, 163, 175, .1), 0px 10px 6px 0px rgba(156, 163, 175, .08), 0px 17px 7px 0px rgba(156, 163, 175, .05), 0px 26px 7px 0px rgba(156, 163, 175, .02);--ndt-spacing-xs: 4px;--ndt-spacing-sm: 6px;--ndt-spacing-md: 12px;--ndt-window-padding: 16px;--ndt-font-size-xs: .75rem;--ndt-font-size-sm: .875rem;--ndt-font-size-md: 1rem;--ndt-font-size-lg: 1.25rem;--ndt-font-size-xl: 2rem;--ndt-background-secondary: var(--ndt-bg-primary);--ndt-background-hover: var(--ndt-hover-bg);--ndt-primary: #df30d4;--ndt-primary-rgb: 223, 48, 212;--ndt-text-on-primary: rgb(255, 255, 255);--ndt-border-color: var(--ndt-border-primary);--ndt-note-background: rgb(219, 234, 254);--ndt-note-border: rgba(37, 99, 235, .2);--ndt-warning-background: rgb(254, 249, 195);--ndt-warning-border: rgba(202, 138, 4, .2);--ndt-error-background: rgb(254, 226, 226);--ndt-error-border: rgba(220, 38, 38, .2);display:block;width:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\"}:host[data-theme=dark]{--ndt-bg-primary: rgb(17, 24, 39);--ndt-bg-gradient: linear-gradient(180deg, rgb(19, 21, 26) 0%, rgba(19, 21, 26, .88) 100%);--ndt-text-primary: rgb(255, 255, 255);--ndt-text-secondary: rgb(229, 231, 235);--ndt-text-muted: rgb(156, 163, 175);--ndt-border-primary: #343841;--ndt-border-subtle: rgba(255, 255, 255, .1);--ndt-hover-bg: rgba(255, 255, 255, .12);--ndt-hover-danger: rgb(220, 38, 38);--ndt-shadow-toolbar: 0 2px 8px rgba(19, 21, 26, .3);--ndt-shadow-tooltip: 0 0 0 1px rgba(255, 255, 255, .1), 0 4px 8px rgba(0, 0, 0, .4), 0 2px 4px rgba(0, 0, 0, .3);--ndt-shadow-window: 0px 0px 0px 0px rgba(19, 21, 26, .3), 0px 1px 2px 0px rgba(19, 21, 26, .29), 0px 4px 4px 0px rgba(19, 21, 26, .26), 0px 10px 6px 0px rgba(19, 21, 26, .15), 0px 17px 7px 0px rgba(19, 21, 26, .04), 0px 26px 7px 0px rgba(19, 21, 26, .01);--ndt-note-background: rgba(37, 99, 235, .15);--ndt-note-border: rgba(37, 99, 235, .3);--ndt-warning-background: rgba(202, 138, 4, .15);--ndt-warning-border: rgba(202, 138, 4, .3);--ndt-error-background: rgba(220, 38, 38, .15);--ndt-error-border: rgba(220, 38, 38, .3)}.window{box-sizing:border-box;display:flex;flex-direction:column;width:100%;height:100%;background:var(--ndt-bg-primary);border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-large);padding:var(--ndt-window-padding);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\";color:var(--ndt-text-secondary);z-index:999999999;box-shadow:var(--ndt-shadow-window)}.header{display:flex;flex-direction:row;justify-content:space-between;align-items:flex-start}.header h1{font-size:var(--ndt-font-size-lg);line-height:1.2;margin:0}.header__title{display:flex;align-items:center;gap:var(--ndt-spacing-sm)}.header__title .beta-tag{font-size:var(--ndt-font-size-xxs, .65rem);background:var(--ndt-purple, #8b5cf6);color:var(--ndt-text-on-primary);padding:1px 4px;margin-left:var(--ndt-spacing-xs);border-radius:var(--ndt-border-radius-small);font-weight:500;text-transform:uppercase;letter-spacing:.5px}.header__description{font-size:var(--ndt-font-size-sm);color:var(--ndt-text-muted);word-wrap:break-word;overflow-wrap:break-word;max-width:100%;line-height:1.4;margin:0}.header__content{display:flex;flex-direction:column;gap:var(--ndt-spacing-xs)}.header__controls{display:flex;gap:var(--ndt-spacing-sm)}.content{flex:1;overflow:auto}.divider{height:1px;background-color:var(--ndt-border-primary);margin-bottom:var(--ndt-spacing-md);margin-top:var(--ndt-spacing-md)}.control{background:none;border:none;color:var(--ndt-text-secondary);cursor:pointer;padding:var(--ndt-spacing-xs) var(--ndt-spacing-sm);border-radius:var(--ndt-border-radius-small);font-size:var(--ndt-font-size-md);line-height:1;transition:var(--ndt-transition-smooth)}.control:hover{background:var(--ndt-hover-bg);color:var(--ndt-text-primary)}.control--close:hover{background:var(--ndt-hover-danger)}\n"], encapsulation: i0.ViewEncapsulation.ShadowDom }); }
|
|
1579
1733
|
}
|
|
1580
1734
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarWindowComponent, decorators: [{
|
|
1581
1735
|
type: Component,
|
|
1582
|
-
args: [{ selector: 'ndt-window', standalone: true, template: `
|
|
1736
|
+
args: [{ selector: 'ndt-window', standalone: true, encapsulation: ViewEncapsulation.ShadowDom, template: `
|
|
1583
1737
|
<div class="window dev-toolbar" [attr.data-theme]="theme()">
|
|
1584
1738
|
<div class="header">
|
|
1585
1739
|
<div class="header__content">
|
|
@@ -1617,7 +1771,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
1617
1771
|
<ng-content></ng-content>
|
|
1618
1772
|
</div>
|
|
1619
1773
|
</div>
|
|
1620
|
-
`, styles: ["
|
|
1774
|
+
`, styles: [":host{--ndt-border-radius-small: 4px;--ndt-border-radius-medium: 8px;--ndt-border-radius-large: 12px;--ndt-transition-default: all .2s ease-out;--ndt-transition-smooth: all .2s ease-in-out;--ndt-bg-primary: rgb(255, 255, 255);--ndt-bg-gradient: linear-gradient(180deg, rgb(243, 244, 246) 0%, rgba(243, 244, 246, .88) 100%);--ndt-text-primary: rgb(17, 24, 39);--ndt-text-secondary: rgb(55, 65, 81);--ndt-text-muted: rgb(107, 114, 128);--ndt-border-primary: #e5e7eb;--ndt-border-subtle: rgba(17, 24, 39, .1);--ndt-hover-bg: rgba(17, 24, 39, .05);--ndt-hover-danger: rgb(239, 68, 68);--ndt-shadow-toolbar: 0 2px 8px rgba(156, 163, 175, .2);--ndt-shadow-tooltip: 0 0 0 1px rgba(17, 24, 39, .05), 0 4px 8px rgba(107, 114, 128, .15), 0 2px 4px rgba(107, 114, 128, .1);--ndt-shadow-window: 0px 0px 0px 0px rgba(156, 163, 175, .1), 0px 1px 2px 0px rgba(156, 163, 175, .12), 0px 4px 4px 0px rgba(156, 163, 175, .1), 0px 10px 6px 0px rgba(156, 163, 175, .08), 0px 17px 7px 0px rgba(156, 163, 175, .05), 0px 26px 7px 0px rgba(156, 163, 175, .02);--ndt-spacing-xs: 4px;--ndt-spacing-sm: 6px;--ndt-spacing-md: 12px;--ndt-window-padding: 16px;--ndt-font-size-xs: .75rem;--ndt-font-size-sm: .875rem;--ndt-font-size-md: 1rem;--ndt-font-size-lg: 1.25rem;--ndt-font-size-xl: 2rem;--ndt-background-secondary: var(--ndt-bg-primary);--ndt-background-hover: var(--ndt-hover-bg);--ndt-primary: #df30d4;--ndt-primary-rgb: 223, 48, 212;--ndt-text-on-primary: rgb(255, 255, 255);--ndt-border-color: var(--ndt-border-primary);--ndt-note-background: rgb(219, 234, 254);--ndt-note-border: rgba(37, 99, 235, .2);--ndt-warning-background: rgb(254, 249, 195);--ndt-warning-border: rgba(202, 138, 4, .2);--ndt-error-background: rgb(254, 226, 226);--ndt-error-border: rgba(220, 38, 38, .2);display:block;width:100%;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\"}:host[data-theme=dark]{--ndt-bg-primary: rgb(17, 24, 39);--ndt-bg-gradient: linear-gradient(180deg, rgb(19, 21, 26) 0%, rgba(19, 21, 26, .88) 100%);--ndt-text-primary: rgb(255, 255, 255);--ndt-text-secondary: rgb(229, 231, 235);--ndt-text-muted: rgb(156, 163, 175);--ndt-border-primary: #343841;--ndt-border-subtle: rgba(255, 255, 255, .1);--ndt-hover-bg: rgba(255, 255, 255, .12);--ndt-hover-danger: rgb(220, 38, 38);--ndt-shadow-toolbar: 0 2px 8px rgba(19, 21, 26, .3);--ndt-shadow-tooltip: 0 0 0 1px rgba(255, 255, 255, .1), 0 4px 8px rgba(0, 0, 0, .4), 0 2px 4px rgba(0, 0, 0, .3);--ndt-shadow-window: 0px 0px 0px 0px rgba(19, 21, 26, .3), 0px 1px 2px 0px rgba(19, 21, 26, .29), 0px 4px 4px 0px rgba(19, 21, 26, .26), 0px 10px 6px 0px rgba(19, 21, 26, .15), 0px 17px 7px 0px rgba(19, 21, 26, .04), 0px 26px 7px 0px rgba(19, 21, 26, .01);--ndt-note-background: rgba(37, 99, 235, .15);--ndt-note-border: rgba(37, 99, 235, .3);--ndt-warning-background: rgba(202, 138, 4, .15);--ndt-warning-border: rgba(202, 138, 4, .3);--ndt-error-background: rgba(220, 38, 38, .15);--ndt-error-border: rgba(220, 38, 38, .3)}.window{box-sizing:border-box;display:flex;flex-direction:column;width:100%;height:100%;background:var(--ndt-bg-primary);border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-large);padding:var(--ndt-window-padding);font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\";color:var(--ndt-text-secondary);z-index:999999999;box-shadow:var(--ndt-shadow-window)}.header{display:flex;flex-direction:row;justify-content:space-between;align-items:flex-start}.header h1{font-size:var(--ndt-font-size-lg);line-height:1.2;margin:0}.header__title{display:flex;align-items:center;gap:var(--ndt-spacing-sm)}.header__title .beta-tag{font-size:var(--ndt-font-size-xxs, .65rem);background:var(--ndt-purple, #8b5cf6);color:var(--ndt-text-on-primary);padding:1px 4px;margin-left:var(--ndt-spacing-xs);border-radius:var(--ndt-border-radius-small);font-weight:500;text-transform:uppercase;letter-spacing:.5px}.header__description{font-size:var(--ndt-font-size-sm);color:var(--ndt-text-muted);word-wrap:break-word;overflow-wrap:break-word;max-width:100%;line-height:1.4;margin:0}.header__content{display:flex;flex-direction:column;gap:var(--ndt-spacing-xs)}.header__controls{display:flex;gap:var(--ndt-spacing-sm)}.content{flex:1;overflow:auto}.divider{height:1px;background-color:var(--ndt-border-primary);margin-bottom:var(--ndt-spacing-md);margin-top:var(--ndt-spacing-md)}.control{background:none;border:none;color:var(--ndt-text-secondary);cursor:pointer;padding:var(--ndt-spacing-xs) var(--ndt-spacing-sm);border-radius:var(--ndt-border-radius-small);font-size:var(--ndt-font-size-md);line-height:1;transition:var(--ndt-transition-smooth)}.control:hover{background:var(--ndt-hover-bg);color:var(--ndt-text-primary)}.control--close:hover{background:var(--ndt-hover-danger)}\n"] }]
|
|
1621
1775
|
}] });
|
|
1622
1776
|
|
|
1623
1777
|
class DevToolbarToolComponent {
|
|
@@ -1718,7 +1872,7 @@ class DevToolbarToolComponent {
|
|
|
1718
1872
|
</ng-template>
|
|
1719
1873
|
}
|
|
1720
1874
|
</div>
|
|
1721
|
-
`, isInline: true, styles: [".
|
|
1875
|
+
`, isInline: true, styles: [".tool{position:relative}.trigger{cursor:pointer}\n"], dependencies: [{ kind: "directive", type: CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "component", type: DevToolbarWindowComponent, selector: "ndt-window", inputs: ["config"], outputs: ["close", "maximize", "minimize"] }, { kind: "component", type: DevToolbarToolButtonComponent, selector: "ndt-tool-button", inputs: ["title", "toolId"], outputs: ["open"] }, { kind: "component", type: DevToolbarIconComponent, selector: "ndt-icon", inputs: ["name"] }], animations: [
|
|
1722
1876
|
trigger('slideAnimation', [
|
|
1723
1877
|
transition(':enter', [
|
|
1724
1878
|
style({
|
|
@@ -1810,7 +1964,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
1810
1964
|
})),
|
|
1811
1965
|
]),
|
|
1812
1966
|
]),
|
|
1813
|
-
], styles: [".
|
|
1967
|
+
], styles: [".tool{position:relative}.trigger{cursor:pointer}\n"] }]
|
|
1814
1968
|
}], propDecorators: { buttonContainer: [{
|
|
1815
1969
|
type: ViewChild,
|
|
1816
1970
|
args: ['buttonContainer']
|
|
@@ -1837,7 +1991,7 @@ class DevToolbarInputComponent {
|
|
|
1837
1991
|
[placeholder]="placeholder()"
|
|
1838
1992
|
(ngModelChange)="value.set($event)"
|
|
1839
1993
|
/>
|
|
1840
|
-
`, isInline: true, styles: [":host{display:block}.input{width:100%;padding:var(--ndt-spacing-sm) var(--ndt-spacing-md);border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-small);background-color:var(--ndt-bg-primary);color:var(--ndt-text-primary);font-size:var(--ndt-font-size-sm);transition:var(--ndt-transition-default);box-sizing:border-box}.input::placeholder{color:var(--ndt-text-muted)}.input:focus{outline:none;border-color:var(--ndt-primary);box-shadow:0 0 0 2px rgba(var(--ndt-primary-rgb),.2)}.input:disabled{background-color:var(--ndt-bg-secondary);cursor:not-allowed;color:var(--ndt-text-muted)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.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: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1994
|
+
`, isInline: true, styles: [":host{display:block}.input{width:100%;padding:var(--ndt-spacing-sm) var(--ndt-spacing-md);border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-small);background-color:var(--ndt-bg-primary);color:var(--ndt-text-primary);font-size:var(--ndt-font-size-sm);transition:var(--ndt-transition-default);box-sizing:border-box;min-height:36px}.input::placeholder{color:var(--ndt-text-muted)}.input:focus{outline:none;border-color:var(--ndt-primary);box-shadow:0 0 0 2px rgba(var(--ndt-primary-rgb),.2)}.input:disabled{background-color:var(--ndt-bg-secondary);cursor:not-allowed;color:var(--ndt-text-muted)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.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: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
1841
1995
|
}
|
|
1842
1996
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInputComponent, decorators: [{
|
|
1843
1997
|
type: Component,
|
|
@@ -1850,7 +2004,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
1850
2004
|
[placeholder]="placeholder()"
|
|
1851
2005
|
(ngModelChange)="value.set($event)"
|
|
1852
2006
|
/>
|
|
1853
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}.input{width:100%;padding:var(--ndt-spacing-sm) var(--ndt-spacing-md);border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-small);background-color:var(--ndt-bg-primary);color:var(--ndt-text-primary);font-size:var(--ndt-font-size-sm);transition:var(--ndt-transition-default);box-sizing:border-box}.input::placeholder{color:var(--ndt-text-muted)}.input:focus{outline:none;border-color:var(--ndt-primary);box-shadow:0 0 0 2px rgba(var(--ndt-primary-rgb),.2)}.input:disabled{background-color:var(--ndt-bg-secondary);cursor:not-allowed;color:var(--ndt-text-muted)}\n"] }]
|
|
2007
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{display:block}.input{width:100%;padding:var(--ndt-spacing-sm) var(--ndt-spacing-md);border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-small);background-color:var(--ndt-bg-primary);color:var(--ndt-text-primary);font-size:var(--ndt-font-size-sm);transition:var(--ndt-transition-default);box-sizing:border-box;min-height:36px}.input::placeholder{color:var(--ndt-text-muted)}.input:focus{outline:none;border-color:var(--ndt-primary);box-shadow:0 0 0 2px rgba(var(--ndt-primary-rgb),.2)}.input:disabled{background-color:var(--ndt-bg-secondary);cursor:not-allowed;color:var(--ndt-text-muted)}\n"] }]
|
|
1854
2008
|
}] });
|
|
1855
2009
|
|
|
1856
2010
|
class DevToolbarSelectComponent {
|
|
@@ -1947,11 +2101,11 @@ class DevToolbarSelectComponent {
|
|
|
1947
2101
|
}
|
|
1948
2102
|
</div>
|
|
1949
2103
|
</ng-template>
|
|
1950
|
-
`, isInline: true, styles: ["
|
|
2104
|
+
`, isInline: true, styles: [":host{--ndt-border-radius-small: 4px;--ndt-border-radius-medium: 8px;--ndt-border-radius-large: 12px;--ndt-transition-default: all .2s ease-out;--ndt-transition-smooth: all .2s ease-in-out;--ndt-bg-primary: rgb(255, 255, 255);--ndt-bg-gradient: linear-gradient(180deg, rgb(243, 244, 246) 0%, rgba(243, 244, 246, .88) 100%);--ndt-text-primary: rgb(17, 24, 39);--ndt-text-secondary: rgb(55, 65, 81);--ndt-text-muted: rgb(107, 114, 128);--ndt-border-primary: #e5e7eb;--ndt-border-subtle: rgba(17, 24, 39, .1);--ndt-hover-bg: rgba(17, 24, 39, .05);--ndt-hover-danger: rgb(239, 68, 68);--ndt-shadow-toolbar: 0 2px 8px rgba(156, 163, 175, .2);--ndt-shadow-tooltip: 0 0 0 1px rgba(17, 24, 39, .05), 0 4px 8px rgba(107, 114, 128, .15), 0 2px 4px rgba(107, 114, 128, .1);--ndt-shadow-window: 0px 0px 0px 0px rgba(156, 163, 175, .1), 0px 1px 2px 0px rgba(156, 163, 175, .12), 0px 4px 4px 0px rgba(156, 163, 175, .1), 0px 10px 6px 0px rgba(156, 163, 175, .08), 0px 17px 7px 0px rgba(156, 163, 175, .05), 0px 26px 7px 0px rgba(156, 163, 175, .02);--ndt-spacing-xs: 4px;--ndt-spacing-sm: 6px;--ndt-spacing-md: 12px;--ndt-window-padding: 16px;--ndt-font-size-xs: .75rem;--ndt-font-size-sm: .875rem;--ndt-font-size-md: 1rem;--ndt-font-size-lg: 1.25rem;--ndt-font-size-xl: 2rem;--ndt-background-secondary: var(--ndt-bg-primary);--ndt-background-hover: var(--ndt-hover-bg);--ndt-primary: #df30d4;--ndt-primary-rgb: 223, 48, 212;--ndt-text-on-primary: rgb(255, 255, 255);--ndt-border-color: var(--ndt-border-primary);--ndt-note-background: rgb(219, 234, 254);--ndt-note-border: rgba(37, 99, 235, .2);--ndt-warning-background: rgb(254, 249, 195);--ndt-warning-border: rgba(202, 138, 4, .2);--ndt-error-background: rgb(254, 226, 226);--ndt-error-border: rgba(220, 38, 38, .2);display:inline-block;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\"}:host[data-theme=dark]{--ndt-bg-primary: rgb(17, 24, 39);--ndt-bg-gradient: linear-gradient(180deg, rgb(19, 21, 26) 0%, rgba(19, 21, 26, .88) 100%);--ndt-text-primary: rgb(255, 255, 255);--ndt-text-secondary: rgb(229, 231, 235);--ndt-text-muted: rgb(156, 163, 175);--ndt-border-primary: #343841;--ndt-border-subtle: rgba(255, 255, 255, .1);--ndt-hover-bg: rgba(255, 255, 255, .12);--ndt-hover-danger: rgb(220, 38, 38);--ndt-shadow-toolbar: 0 2px 8px rgba(19, 21, 26, .3);--ndt-shadow-tooltip: 0 0 0 1px rgba(255, 255, 255, .1), 0 4px 8px rgba(0, 0, 0, .4), 0 2px 4px rgba(0, 0, 0, .3);--ndt-shadow-window: 0px 0px 0px 0px rgba(19, 21, 26, .3), 0px 1px 2px 0px rgba(19, 21, 26, .29), 0px 4px 4px 0px rgba(19, 21, 26, .26), 0px 10px 6px 0px rgba(19, 21, 26, .15), 0px 17px 7px 0px rgba(19, 21, 26, .04), 0px 26px 7px 0px rgba(19, 21, 26, .01);--ndt-note-background: rgba(37, 99, 235, .15);--ndt-note-border: rgba(37, 99, 235, .3);--ndt-warning-background: rgba(202, 138, 4, .15);--ndt-warning-border: rgba(202, 138, 4, .3);--ndt-error-background: rgba(220, 38, 38, .15);--ndt-error-border: rgba(220, 38, 38, .3)}.select{position:relative;width:100%;min-width:120px;display:flex;align-items:center;justify-content:space-between;padding:var(--ndt-spacing-sm) var(--ndt-spacing-md);border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-small);background-color:var(--ndt-bg-primary);color:var(--ndt-text-primary);font-size:var(--ndt-font-size-sm);cursor:pointer;-webkit-user-select:none;user-select:none;transition:var(--ndt-transition-default);outline:none;min-height:36px;box-sizing:border-box}.select:hover{background-color:var(--ndt-hover-bg);border-color:var(--ndt-primary)}.select:focus-visible{outline:none;border-color:var(--ndt-primary);box-shadow:0 0 0 2px rgba(var(--ndt-primary-rgb),.2)}.select.small{padding:var(--ndt-spacing-xs) var(--ndt-spacing-sm);font-size:var(--ndt-font-size-sm);height:24px}.select.open{border-color:var(--ndt-primary);box-shadow:0 0 0 2px rgba(var(--ndt-primary-rgb),.2)}.select.open .select__arrow{transform:rotate(180deg)}.select__value{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.4;margin-right:var(--ndt-spacing-sm);min-width:0;display:flex;align-items:center}.select__arrow{width:16px;height:16px;flex-shrink:0;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:center;background-size:contain;transition:transform .2s ease;opacity:.9}.select-menu{display:inline-flex;flex-direction:column;min-width:180px;background-color:var(--ndt-bg-primary);padding:var(--ndt-spacing-xs) 0;border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-small);box-shadow:var(--ndt-shadow-window);color:var(--ndt-text-primary);max-height:min(400px,70vh);overflow-y:auto;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.select-menu::-webkit-scrollbar{width:8px;height:8px}.select-menu::-webkit-scrollbar-track{background:transparent}.select-menu::-webkit-scrollbar-thumb{background-color:var(--ndt-border-primary);border-radius:4px;border:2px solid var(--ndt-bg-primary)}.select-menu-item{background-color:transparent;cursor:pointer;border:none;color:inherit;-webkit-user-select:none;user-select:none;min-width:64px;line-height:36px;padding:0 var(--ndt-spacing-md);display:flex;align-items:center;flex-direction:row;flex:1;font-size:var(--ndt-font-size-sm);font-family:inherit;position:relative;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.select-menu-item:hover{background-color:var(--ndt-hover-bg)}.select-menu-item:active{background-color:rgba(var(--ndt-primary-rgb),.15)}.select-menu-item.selected{color:var(--ndt-primary);background-color:rgba(var(--ndt-primary-rgb),.1);font-weight:500}.select-menu-item.selected:hover{background-color:rgba(var(--ndt-primary-rgb),.15)}.select-menu-item.selected:before{content:\"\";position:absolute;left:0;top:8px;width:3px;height:calc(100% - 16px);background-color:var(--ndt-primary);border-radius:2px}.select-menu-item:focus-visible{outline:none;background-color:var(--ndt-hover-bg)}.select-overlay{-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: FormsModule }, { kind: "ngmodule", type: OverlayModule }, { kind: "directive", type: i1.CdkConnectedOverlay, selector: "[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]", inputs: ["cdkConnectedOverlayOrigin", "cdkConnectedOverlayPositions", "cdkConnectedOverlayPositionStrategy", "cdkConnectedOverlayOffsetX", "cdkConnectedOverlayOffsetY", "cdkConnectedOverlayWidth", "cdkConnectedOverlayHeight", "cdkConnectedOverlayMinWidth", "cdkConnectedOverlayMinHeight", "cdkConnectedOverlayBackdropClass", "cdkConnectedOverlayPanelClass", "cdkConnectedOverlayViewportMargin", "cdkConnectedOverlayScrollStrategy", "cdkConnectedOverlayOpen", "cdkConnectedOverlayDisableClose", "cdkConnectedOverlayTransformOriginOn", "cdkConnectedOverlayHasBackdrop", "cdkConnectedOverlayLockPosition", "cdkConnectedOverlayFlexibleDimensions", "cdkConnectedOverlayGrowAfterOpen", "cdkConnectedOverlayPush", "cdkConnectedOverlayDisposeOnNavigation"], outputs: ["backdropClick", "positionChange", "attach", "detach", "overlayKeydown", "overlayOutsideClick"], exportAs: ["cdkConnectedOverlay"] }, { kind: "directive", type: i1.CdkOverlayOrigin, selector: "[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]", exportAs: ["cdkOverlayOrigin"] }, { kind: "ngmodule", type: CdkMenuModule }, { kind: "directive", type: i2.CdkMenu, selector: "[cdkMenu]", outputs: ["closed"], exportAs: ["cdkMenu"] }, { kind: "directive", type: i2.CdkMenuItem, selector: "[cdkMenuItem]", inputs: ["cdkMenuItemDisabled", "cdkMenuitemTypeaheadLabel"], outputs: ["cdkMenuItemTriggered"], exportAs: ["cdkMenuItem"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush, encapsulation: i0.ViewEncapsulation.ShadowDom }); }
|
|
1951
2105
|
}
|
|
1952
2106
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarSelectComponent, decorators: [{
|
|
1953
2107
|
type: Component,
|
|
1954
|
-
args: [{ selector: 'ndt-select', standalone: true, imports: [CommonModule, FormsModule, OverlayModule, CdkMenuModule], template: `
|
|
2108
|
+
args: [{ selector: 'ndt-select', standalone: true, encapsulation: ViewEncapsulation.ShadowDom, imports: [CommonModule, FormsModule, OverlayModule, CdkMenuModule], template: `
|
|
1955
2109
|
<div
|
|
1956
2110
|
class="dev-toolbar select"
|
|
1957
2111
|
[class.small]="size() === 'small'"
|
|
@@ -2000,7 +2154,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2000
2154
|
}
|
|
2001
2155
|
</div>
|
|
2002
2156
|
</ng-template>
|
|
2003
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: ["
|
|
2157
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [":host{--ndt-border-radius-small: 4px;--ndt-border-radius-medium: 8px;--ndt-border-radius-large: 12px;--ndt-transition-default: all .2s ease-out;--ndt-transition-smooth: all .2s ease-in-out;--ndt-bg-primary: rgb(255, 255, 255);--ndt-bg-gradient: linear-gradient(180deg, rgb(243, 244, 246) 0%, rgba(243, 244, 246, .88) 100%);--ndt-text-primary: rgb(17, 24, 39);--ndt-text-secondary: rgb(55, 65, 81);--ndt-text-muted: rgb(107, 114, 128);--ndt-border-primary: #e5e7eb;--ndt-border-subtle: rgba(17, 24, 39, .1);--ndt-hover-bg: rgba(17, 24, 39, .05);--ndt-hover-danger: rgb(239, 68, 68);--ndt-shadow-toolbar: 0 2px 8px rgba(156, 163, 175, .2);--ndt-shadow-tooltip: 0 0 0 1px rgba(17, 24, 39, .05), 0 4px 8px rgba(107, 114, 128, .15), 0 2px 4px rgba(107, 114, 128, .1);--ndt-shadow-window: 0px 0px 0px 0px rgba(156, 163, 175, .1), 0px 1px 2px 0px rgba(156, 163, 175, .12), 0px 4px 4px 0px rgba(156, 163, 175, .1), 0px 10px 6px 0px rgba(156, 163, 175, .08), 0px 17px 7px 0px rgba(156, 163, 175, .05), 0px 26px 7px 0px rgba(156, 163, 175, .02);--ndt-spacing-xs: 4px;--ndt-spacing-sm: 6px;--ndt-spacing-md: 12px;--ndt-window-padding: 16px;--ndt-font-size-xs: .75rem;--ndt-font-size-sm: .875rem;--ndt-font-size-md: 1rem;--ndt-font-size-lg: 1.25rem;--ndt-font-size-xl: 2rem;--ndt-background-secondary: var(--ndt-bg-primary);--ndt-background-hover: var(--ndt-hover-bg);--ndt-primary: #df30d4;--ndt-primary-rgb: 223, 48, 212;--ndt-text-on-primary: rgb(255, 255, 255);--ndt-border-color: var(--ndt-border-primary);--ndt-note-background: rgb(219, 234, 254);--ndt-note-border: rgba(37, 99, 235, .2);--ndt-warning-background: rgb(254, 249, 195);--ndt-warning-border: rgba(202, 138, 4, .2);--ndt-error-background: rgb(254, 226, 226);--ndt-error-border: rgba(220, 38, 38, .2);display:inline-block;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\"}:host[data-theme=dark]{--ndt-bg-primary: rgb(17, 24, 39);--ndt-bg-gradient: linear-gradient(180deg, rgb(19, 21, 26) 0%, rgba(19, 21, 26, .88) 100%);--ndt-text-primary: rgb(255, 255, 255);--ndt-text-secondary: rgb(229, 231, 235);--ndt-text-muted: rgb(156, 163, 175);--ndt-border-primary: #343841;--ndt-border-subtle: rgba(255, 255, 255, .1);--ndt-hover-bg: rgba(255, 255, 255, .12);--ndt-hover-danger: rgb(220, 38, 38);--ndt-shadow-toolbar: 0 2px 8px rgba(19, 21, 26, .3);--ndt-shadow-tooltip: 0 0 0 1px rgba(255, 255, 255, .1), 0 4px 8px rgba(0, 0, 0, .4), 0 2px 4px rgba(0, 0, 0, .3);--ndt-shadow-window: 0px 0px 0px 0px rgba(19, 21, 26, .3), 0px 1px 2px 0px rgba(19, 21, 26, .29), 0px 4px 4px 0px rgba(19, 21, 26, .26), 0px 10px 6px 0px rgba(19, 21, 26, .15), 0px 17px 7px 0px rgba(19, 21, 26, .04), 0px 26px 7px 0px rgba(19, 21, 26, .01);--ndt-note-background: rgba(37, 99, 235, .15);--ndt-note-border: rgba(37, 99, 235, .3);--ndt-warning-background: rgba(202, 138, 4, .15);--ndt-warning-border: rgba(202, 138, 4, .3);--ndt-error-background: rgba(220, 38, 38, .15);--ndt-error-border: rgba(220, 38, 38, .3)}.select{position:relative;width:100%;min-width:120px;display:flex;align-items:center;justify-content:space-between;padding:var(--ndt-spacing-sm) var(--ndt-spacing-md);border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-small);background-color:var(--ndt-bg-primary);color:var(--ndt-text-primary);font-size:var(--ndt-font-size-sm);cursor:pointer;-webkit-user-select:none;user-select:none;transition:var(--ndt-transition-default);outline:none;min-height:36px;box-sizing:border-box}.select:hover{background-color:var(--ndt-hover-bg);border-color:var(--ndt-primary)}.select:focus-visible{outline:none;border-color:var(--ndt-primary);box-shadow:0 0 0 2px rgba(var(--ndt-primary-rgb),.2)}.select.small{padding:var(--ndt-spacing-xs) var(--ndt-spacing-sm);font-size:var(--ndt-font-size-sm);height:24px}.select.open{border-color:var(--ndt-primary);box-shadow:0 0 0 2px rgba(var(--ndt-primary-rgb),.2)}.select.open .select__arrow{transform:rotate(180deg)}.select__value{flex:1;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;line-height:1.4;margin-right:var(--ndt-spacing-sm);min-width:0;display:flex;align-items:center}.select__arrow{width:16px;height:16px;flex-shrink:0;background-image:url(\"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='24' height='24' viewBox='0 0 24 24' fill='none' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpolyline points='6 9 12 15 18 9'%3E%3C/polyline%3E%3C/svg%3E\");background-repeat:no-repeat;background-position:center;background-size:contain;transition:transform .2s ease;opacity:.9}.select-menu{display:inline-flex;flex-direction:column;min-width:180px;background-color:var(--ndt-bg-primary);padding:var(--ndt-spacing-xs) 0;border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-small);box-shadow:var(--ndt-shadow-window);color:var(--ndt-text-primary);max-height:min(400px,70vh);overflow-y:auto;-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}.select-menu::-webkit-scrollbar{width:8px;height:8px}.select-menu::-webkit-scrollbar-track{background:transparent}.select-menu::-webkit-scrollbar-thumb{background-color:var(--ndt-border-primary);border-radius:4px;border:2px solid var(--ndt-bg-primary)}.select-menu-item{background-color:transparent;cursor:pointer;border:none;color:inherit;-webkit-user-select:none;user-select:none;min-width:64px;line-height:36px;padding:0 var(--ndt-spacing-md);display:flex;align-items:center;flex-direction:row;flex:1;font-size:var(--ndt-font-size-sm);font-family:inherit;position:relative;white-space:nowrap;text-overflow:ellipsis;overflow:hidden}.select-menu-item:hover{background-color:var(--ndt-hover-bg)}.select-menu-item:active{background-color:rgba(var(--ndt-primary-rgb),.15)}.select-menu-item.selected{color:var(--ndt-primary);background-color:rgba(var(--ndt-primary-rgb),.1);font-weight:500}.select-menu-item.selected:hover{background-color:rgba(var(--ndt-primary-rgb),.15)}.select-menu-item.selected:before{content:\"\";position:absolute;left:0;top:8px;width:3px;height:calc(100% - 16px);background-color:var(--ndt-primary);border-radius:2px}.select-menu-item:focus-visible{outline:none;background-color:var(--ndt-hover-bg)}.select-overlay{-webkit-backdrop-filter:blur(8px);backdrop-filter:blur(8px)}\n"] }]
|
|
2004
2158
|
}] });
|
|
2005
2159
|
|
|
2006
2160
|
class DevToolsStorageService {
|
|
@@ -2076,170 +2230,658 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2076
2230
|
args: [{ providedIn: 'root' }]
|
|
2077
2231
|
}] });
|
|
2078
2232
|
|
|
2079
|
-
|
|
2233
|
+
/**
|
|
2234
|
+
* Internal service for managing app features state and forced overrides.
|
|
2235
|
+
*
|
|
2236
|
+
* This service handles:
|
|
2237
|
+
* - Feature configuration storage
|
|
2238
|
+
* - Forced feature state management
|
|
2239
|
+
* - localStorage persistence
|
|
2240
|
+
* - State validation and cleanup
|
|
2241
|
+
*
|
|
2242
|
+
* @internal This service is for internal toolbar use only. Consumers should use DevToolbarAppFeaturesService.
|
|
2243
|
+
*/
|
|
2244
|
+
class DevToolbarInternalAppFeaturesService {
|
|
2080
2245
|
constructor() {
|
|
2081
|
-
this.STORAGE_KEY = '
|
|
2246
|
+
this.STORAGE_KEY = 'app-features';
|
|
2082
2247
|
this.storageService = inject(DevToolsStorageService);
|
|
2083
|
-
this.
|
|
2084
|
-
this.
|
|
2248
|
+
this.appFeaturesSubject = new BehaviorSubject([]);
|
|
2249
|
+
this.forcedFeaturesSubject = new BehaviorSubject({
|
|
2085
2250
|
enabled: [],
|
|
2086
2251
|
disabled: [],
|
|
2087
2252
|
});
|
|
2088
|
-
this.
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
|
|
2094
|
-
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
2099
|
-
this.
|
|
2100
|
-
this.
|
|
2253
|
+
this.forcedFeatures$ = this.forcedFeaturesSubject.asObservable();
|
|
2254
|
+
/**
|
|
2255
|
+
* Observable stream of all features with merged forced state
|
|
2256
|
+
*/
|
|
2257
|
+
this.features$ = combineLatest([
|
|
2258
|
+
this.appFeaturesSubject.asObservable(),
|
|
2259
|
+
this.forcedFeatures$,
|
|
2260
|
+
]).pipe(map(([appFeatures, forcedState]) => this.mergeForcedState(appFeatures, forcedState)));
|
|
2261
|
+
/**
|
|
2262
|
+
* Signal containing current features with merged forced state
|
|
2263
|
+
*/
|
|
2264
|
+
this.features = toSignal(this.features$, { initialValue: [] });
|
|
2265
|
+
this.loadForcedFeatures();
|
|
2101
2266
|
}
|
|
2102
|
-
|
|
2103
|
-
|
|
2267
|
+
/**
|
|
2268
|
+
* Set available app features for the application.
|
|
2269
|
+
* Validates features, trims whitespace, and triggers validation of forced state.
|
|
2270
|
+
*
|
|
2271
|
+
* @param features - Array of app features to configure
|
|
2272
|
+
* @throws Error if duplicate feature IDs or empty IDs are detected
|
|
2273
|
+
*/
|
|
2274
|
+
setAppFeatures(features) {
|
|
2275
|
+
// Validate for empty IDs
|
|
2276
|
+
const emptyIdFeature = features.find((f) => !f.id || f.id.trim() === '');
|
|
2277
|
+
if (emptyIdFeature) {
|
|
2278
|
+
throw new Error('Feature ID cannot be empty');
|
|
2279
|
+
}
|
|
2280
|
+
// Validate for duplicate IDs
|
|
2281
|
+
const ids = features.map((f) => f.id);
|
|
2282
|
+
const duplicateIds = ids.filter((id, index) => ids.indexOf(id) !== index);
|
|
2283
|
+
if (duplicateIds.length > 0) {
|
|
2284
|
+
throw new Error(`Duplicate feature IDs detected: ${duplicateIds.join(', ')}`);
|
|
2285
|
+
}
|
|
2286
|
+
// Trim whitespace from names and warn about empty names
|
|
2287
|
+
const processedFeatures = features.map((feature) => {
|
|
2288
|
+
const trimmedName = feature.name.trim();
|
|
2289
|
+
if (!trimmedName) {
|
|
2290
|
+
console.warn(`Feature '${feature.id}' has empty name`);
|
|
2291
|
+
}
|
|
2292
|
+
return {
|
|
2293
|
+
...feature,
|
|
2294
|
+
name: trimmedName || feature.name,
|
|
2295
|
+
};
|
|
2296
|
+
});
|
|
2297
|
+
this.appFeaturesSubject.next(processedFeatures);
|
|
2298
|
+
this.validateAndCleanForcedState();
|
|
2104
2299
|
}
|
|
2105
|
-
|
|
2106
|
-
|
|
2300
|
+
/**
|
|
2301
|
+
* Get observable stream of app features (natural state, no forced state merged)
|
|
2302
|
+
*/
|
|
2303
|
+
getAppFeatures() {
|
|
2304
|
+
return this.appFeaturesSubject.asObservable();
|
|
2107
2305
|
}
|
|
2108
|
-
|
|
2109
|
-
|
|
2306
|
+
/**
|
|
2307
|
+
* Get observable stream of features that have forced overrides
|
|
2308
|
+
*/
|
|
2309
|
+
getForcedFeatures() {
|
|
2310
|
+
return this.features$.pipe(map((features) => features.filter((feature) => feature.isForced)));
|
|
2110
2311
|
}
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2312
|
+
/**
|
|
2313
|
+
* Force a feature to enabled or disabled state.
|
|
2314
|
+
* Persists the forced state to localStorage.
|
|
2315
|
+
*
|
|
2316
|
+
* @param featureId - ID of the feature to force
|
|
2317
|
+
* @param isEnabled - Whether to force feature to enabled (true) or disabled (false)
|
|
2318
|
+
*/
|
|
2319
|
+
setFeature(featureId, isEnabled) {
|
|
2320
|
+
const { enabled, disabled } = this.forcedFeaturesSubject.value;
|
|
2321
|
+
// Remove feature from both arrays
|
|
2322
|
+
const newEnabled = enabled.filter((id) => id !== featureId);
|
|
2323
|
+
const newDisabled = disabled.filter((id) => id !== featureId);
|
|
2324
|
+
// Add to appropriate array
|
|
2115
2325
|
if (isEnabled) {
|
|
2116
|
-
newEnabled.push(
|
|
2326
|
+
newEnabled.push(featureId);
|
|
2117
2327
|
}
|
|
2118
2328
|
else {
|
|
2119
|
-
newDisabled.push(
|
|
2329
|
+
newDisabled.push(featureId);
|
|
2120
2330
|
}
|
|
2121
2331
|
const newState = { enabled: newEnabled, disabled: newDisabled };
|
|
2122
|
-
this.
|
|
2123
|
-
this.
|
|
2332
|
+
this.forcedFeaturesSubject.next(newState);
|
|
2333
|
+
this.saveForcedFeatures(newState);
|
|
2124
2334
|
}
|
|
2125
|
-
|
|
2126
|
-
|
|
2335
|
+
/**
|
|
2336
|
+
* Remove forced override for a feature, returning it to natural state.
|
|
2337
|
+
* Persists the change to localStorage.
|
|
2338
|
+
*
|
|
2339
|
+
* @param featureId - ID of the feature to unforce
|
|
2340
|
+
*/
|
|
2341
|
+
removeFeatureOverride(featureId) {
|
|
2342
|
+
const { enabled, disabled } = this.forcedFeaturesSubject.value;
|
|
2127
2343
|
const newState = {
|
|
2128
|
-
enabled: enabled.filter((id) => id !==
|
|
2129
|
-
disabled: disabled.filter((id) => id !==
|
|
2344
|
+
enabled: enabled.filter((id) => id !== featureId),
|
|
2345
|
+
disabled: disabled.filter((id) => id !== featureId),
|
|
2130
2346
|
};
|
|
2131
|
-
this.
|
|
2132
|
-
this.
|
|
2347
|
+
this.forcedFeaturesSubject.next(newState);
|
|
2348
|
+
this.saveForcedFeatures(newState);
|
|
2133
2349
|
}
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
2137
|
-
|
|
2350
|
+
/**
|
|
2351
|
+
* Apply a preset forced state (for preset integration).
|
|
2352
|
+
* Validates and cleans invalid feature IDs before applying.
|
|
2353
|
+
*
|
|
2354
|
+
* @param state - Forced features state from preset
|
|
2355
|
+
*/
|
|
2356
|
+
applyForcedState(state) {
|
|
2357
|
+
const configuredFeatureIds = this.appFeaturesSubject.value.map((f) => f.id);
|
|
2358
|
+
// Validate and filter to only valid IDs
|
|
2359
|
+
const validEnabled = state.enabled.filter((id) => configuredFeatureIds.includes(id));
|
|
2360
|
+
const validDisabled = state.disabled.filter((id) => configuredFeatureIds.includes(id));
|
|
2361
|
+
const invalidIds = [
|
|
2362
|
+
...state.enabled.filter((id) => !configuredFeatureIds.includes(id)),
|
|
2363
|
+
...state.disabled.filter((id) => !configuredFeatureIds.includes(id)),
|
|
2364
|
+
];
|
|
2365
|
+
if (invalidIds.length > 0) {
|
|
2366
|
+
console.warn(`Preset contains invalid feature IDs (ignored): ${invalidIds.join(', ')}`);
|
|
2138
2367
|
}
|
|
2368
|
+
const cleanedState = { enabled: validEnabled, disabled: validDisabled };
|
|
2369
|
+
this.forcedFeaturesSubject.next(cleanedState);
|
|
2370
|
+
this.saveForcedFeatures(cleanedState);
|
|
2139
2371
|
}
|
|
2140
|
-
|
|
2141
|
-
|
|
2372
|
+
/**
|
|
2373
|
+
* Get current forced state as a snapshot (defensive copy).
|
|
2374
|
+
* Useful for preset exports and debugging.
|
|
2375
|
+
*
|
|
2376
|
+
* @returns Current forced features state
|
|
2377
|
+
*/
|
|
2378
|
+
getCurrentForcedState() {
|
|
2379
|
+
const state = this.forcedFeaturesSubject.value;
|
|
2380
|
+
return {
|
|
2381
|
+
enabled: [...state.enabled],
|
|
2382
|
+
disabled: [...state.disabled],
|
|
2383
|
+
};
|
|
2384
|
+
}
|
|
2385
|
+
/**
|
|
2386
|
+
* Merge natural app features with forced state.
|
|
2387
|
+
*
|
|
2388
|
+
* @param appFeatures - Natural feature configuration
|
|
2389
|
+
* @param forcedState - Forced overrides from localStorage/toolbar
|
|
2390
|
+
* @returns Features with merged forced state
|
|
2391
|
+
*/
|
|
2392
|
+
mergeForcedState(appFeatures, forcedState) {
|
|
2393
|
+
return appFeatures.map((feature) => {
|
|
2394
|
+
const isInEnabled = forcedState.enabled.includes(feature.id);
|
|
2395
|
+
const isInDisabled = forcedState.disabled.includes(feature.id);
|
|
2396
|
+
const isForced = isInEnabled || isInDisabled;
|
|
2397
|
+
return {
|
|
2398
|
+
...feature,
|
|
2399
|
+
isEnabled: isInEnabled ? true : isInDisabled ? false : feature.isEnabled,
|
|
2400
|
+
isForced,
|
|
2401
|
+
};
|
|
2402
|
+
});
|
|
2403
|
+
}
|
|
2404
|
+
/**
|
|
2405
|
+
* Load forced features state from localStorage on initialization.
|
|
2406
|
+
* Handles missing or corrupted data gracefully.
|
|
2407
|
+
*/
|
|
2408
|
+
loadForcedFeatures() {
|
|
2409
|
+
try {
|
|
2410
|
+
const savedState = this.storageService.get(this.STORAGE_KEY);
|
|
2411
|
+
if (savedState) {
|
|
2412
|
+
this.forcedFeaturesSubject.next(savedState);
|
|
2413
|
+
}
|
|
2414
|
+
}
|
|
2415
|
+
catch (error) {
|
|
2416
|
+
console.error('Failed to load forced app features from localStorage:', error);
|
|
2417
|
+
// Use default empty state on error
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
/**
|
|
2421
|
+
* Persist forced features state to localStorage.
|
|
2422
|
+
* Handles quota exceeded errors gracefully.
|
|
2423
|
+
*
|
|
2424
|
+
* @param state - Forced state to persist
|
|
2425
|
+
*/
|
|
2426
|
+
saveForcedFeatures(state) {
|
|
2427
|
+
try {
|
|
2428
|
+
this.storageService.set(this.STORAGE_KEY, state);
|
|
2429
|
+
}
|
|
2430
|
+
catch (error) {
|
|
2431
|
+
console.error('Failed to persist app features to localStorage:', error);
|
|
2432
|
+
// Continue execution - state is still valid in memory for current session
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
/**
|
|
2436
|
+
* Validate forced feature IDs against configured features and clean up invalid ones.
|
|
2437
|
+
* Called after setAppFeatures() to ensure forced state references valid features.
|
|
2438
|
+
*/
|
|
2439
|
+
validateAndCleanForcedState() {
|
|
2440
|
+
const configuredFeatureIds = this.appFeaturesSubject.value.map((f) => f.id);
|
|
2441
|
+
const currentForcedState = this.forcedFeaturesSubject.value;
|
|
2442
|
+
const validEnabled = currentForcedState.enabled.filter((id) => configuredFeatureIds.includes(id));
|
|
2443
|
+
const validDisabled = currentForcedState.disabled.filter((id) => configuredFeatureIds.includes(id));
|
|
2444
|
+
const removedIds = [
|
|
2445
|
+
...currentForcedState.enabled.filter((id) => !configuredFeatureIds.includes(id)),
|
|
2446
|
+
...currentForcedState.disabled.filter((id) => !configuredFeatureIds.includes(id)),
|
|
2447
|
+
];
|
|
2448
|
+
if (removedIds.length > 0) {
|
|
2449
|
+
console.warn(`Removed invalid feature IDs from forced state: ${removedIds.join(', ')}`);
|
|
2450
|
+
const cleanedState = { enabled: validEnabled, disabled: validDisabled };
|
|
2451
|
+
this.forcedFeaturesSubject.next(cleanedState);
|
|
2452
|
+
this.saveForcedFeatures(cleanedState);
|
|
2453
|
+
}
|
|
2454
|
+
}
|
|
2455
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalAppFeaturesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2456
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalAppFeaturesService, providedIn: 'root' }); }
|
|
2142
2457
|
}
|
|
2143
|
-
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type:
|
|
2458
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalAppFeaturesService, decorators: [{
|
|
2144
2459
|
type: Injectable,
|
|
2145
2460
|
args: [{ providedIn: 'root' }]
|
|
2146
2461
|
}], ctorParameters: () => [] });
|
|
2147
2462
|
|
|
2148
|
-
|
|
2463
|
+
/**
|
|
2464
|
+
* Component for managing app features in the dev toolbar.
|
|
2465
|
+
*
|
|
2466
|
+
* Provides UI for:
|
|
2467
|
+
* - Searching features by name and description
|
|
2468
|
+
* - Filtering features by state (all/forced/enabled/disabled)
|
|
2469
|
+
* - Forcing features to enabled/disabled state via 3-state dropdown
|
|
2470
|
+
* - Viewing feature descriptions and current state
|
|
2471
|
+
*
|
|
2472
|
+
* @example
|
|
2473
|
+
* ```html
|
|
2474
|
+
* <ndt-app-features-tool />
|
|
2475
|
+
* ```
|
|
2476
|
+
*/
|
|
2477
|
+
class DevToolbarAppFeaturesToolComponent {
|
|
2149
2478
|
constructor() {
|
|
2150
2479
|
// Injects
|
|
2151
|
-
this.
|
|
2480
|
+
this.appFeaturesService = inject(DevToolbarInternalAppFeaturesService);
|
|
2152
2481
|
// Signals
|
|
2153
2482
|
this.activeFilter = signal('all');
|
|
2154
2483
|
this.searchQuery = signal('');
|
|
2155
|
-
this.
|
|
2156
|
-
this.
|
|
2157
|
-
this.
|
|
2158
|
-
return this.
|
|
2484
|
+
this.features = this.appFeaturesService.features;
|
|
2485
|
+
this.hasNoFeatures = computed(() => this.features().length === 0);
|
|
2486
|
+
this.filteredFeatures = computed(() => {
|
|
2487
|
+
return this.features().filter((feature) => {
|
|
2159
2488
|
const searchTerm = this.searchQuery().toLowerCase();
|
|
2160
|
-
const
|
|
2161
|
-
const
|
|
2489
|
+
const featureName = feature.name.toLowerCase();
|
|
2490
|
+
const featureDescription = feature.description?.toLowerCase() ?? '';
|
|
2162
2491
|
const matchesSearch = !this.searchQuery() ||
|
|
2163
|
-
|
|
2164
|
-
|
|
2492
|
+
featureName.includes(searchTerm) ||
|
|
2493
|
+
featureDescription.includes(searchTerm);
|
|
2165
2494
|
const matchesFilter = this.activeFilter() === 'all' ||
|
|
2166
|
-
(this.activeFilter() === 'forced' &&
|
|
2167
|
-
(this.activeFilter() === 'enabled' &&
|
|
2168
|
-
(this.activeFilter() === 'disabled' && !
|
|
2495
|
+
(this.activeFilter() === 'forced' && feature.isForced) ||
|
|
2496
|
+
(this.activeFilter() === 'enabled' && feature.isEnabled) ||
|
|
2497
|
+
(this.activeFilter() === 'disabled' && !feature.isEnabled);
|
|
2169
2498
|
return matchesSearch && matchesFilter;
|
|
2170
2499
|
});
|
|
2171
2500
|
});
|
|
2172
|
-
this.
|
|
2501
|
+
this.hasNoFilteredFeatures = computed(() => this.filteredFeatures().length === 0);
|
|
2173
2502
|
// Other properties
|
|
2174
2503
|
this.options = {
|
|
2175
|
-
title: '
|
|
2176
|
-
description: '
|
|
2504
|
+
title: 'App Features',
|
|
2505
|
+
description: 'Override product features to test different tiers and configurations',
|
|
2177
2506
|
isClosable: true,
|
|
2178
2507
|
size: 'tall',
|
|
2179
|
-
id: 'ndt-
|
|
2180
|
-
isBeta: true,
|
|
2508
|
+
id: 'ndt-app-features',
|
|
2181
2509
|
};
|
|
2182
2510
|
this.filterOptions = [
|
|
2183
|
-
{ value: 'all', label: 'All
|
|
2511
|
+
{ value: 'all', label: 'All Features' },
|
|
2184
2512
|
{ value: 'forced', label: 'Forced' },
|
|
2185
2513
|
{ value: 'enabled', label: 'Enabled' },
|
|
2186
2514
|
{ value: 'disabled', label: 'Disabled' },
|
|
2187
2515
|
];
|
|
2188
|
-
this.
|
|
2189
|
-
{ value: '
|
|
2190
|
-
{ value: 'off', label: '
|
|
2191
|
-
{ value: 'on', label: '
|
|
2516
|
+
this.featureValueOptions = [
|
|
2517
|
+
{ value: '', label: 'Not Forced' },
|
|
2518
|
+
{ value: 'off', label: 'Disabled' },
|
|
2519
|
+
{ value: 'on', label: 'Enabled' },
|
|
2192
2520
|
];
|
|
2193
2521
|
}
|
|
2194
2522
|
// Public methods
|
|
2523
|
+
/**
|
|
2524
|
+
* Handle filter dropdown change.
|
|
2525
|
+
* Updates the active filter to show all/forced/enabled/disabled features.
|
|
2526
|
+
*/
|
|
2195
2527
|
onFilterChange(value) {
|
|
2196
2528
|
const filter = this.filterOptions.find((f) => f.value === value);
|
|
2197
2529
|
if (filter) {
|
|
2198
2530
|
this.activeFilter.set(filter.value);
|
|
2199
2531
|
}
|
|
2200
2532
|
}
|
|
2201
|
-
|
|
2533
|
+
/**
|
|
2534
|
+
* Handle feature value change from 3-state dropdown.
|
|
2535
|
+
* - 'not-forced' (empty string): Remove forced override
|
|
2536
|
+
* - 'on': Force feature to enabled
|
|
2537
|
+
* - 'off': Force feature to disabled
|
|
2538
|
+
*/
|
|
2539
|
+
onFeatureChange(featureId, value) {
|
|
2202
2540
|
switch (value) {
|
|
2203
|
-
case '
|
|
2204
|
-
this.
|
|
2541
|
+
case '':
|
|
2542
|
+
this.appFeaturesService.removeFeatureOverride(featureId);
|
|
2205
2543
|
break;
|
|
2206
2544
|
case 'on':
|
|
2207
|
-
this.
|
|
2545
|
+
this.appFeaturesService.setFeature(featureId, true);
|
|
2208
2546
|
break;
|
|
2209
2547
|
case 'off':
|
|
2210
|
-
this.
|
|
2548
|
+
this.appFeaturesService.setFeature(featureId, false);
|
|
2211
2549
|
break;
|
|
2212
2550
|
}
|
|
2213
2551
|
}
|
|
2552
|
+
/**
|
|
2553
|
+
* Handle search input change.
|
|
2554
|
+
* Updates the search query to filter features by name/description.
|
|
2555
|
+
*/
|
|
2214
2556
|
onSearchChange(query) {
|
|
2215
2557
|
this.searchQuery.set(query);
|
|
2216
2558
|
}
|
|
2217
2559
|
// Protected methods
|
|
2218
|
-
|
|
2219
|
-
|
|
2560
|
+
/**
|
|
2561
|
+
* Get the dropdown value for a feature's current state.
|
|
2562
|
+
* - Returns empty string if not forced (natural state)
|
|
2563
|
+
* - Returns 'on' if forced to enabled
|
|
2564
|
+
* - Returns 'off' if forced to disabled
|
|
2565
|
+
*/
|
|
2566
|
+
getFeatureValue(feature) {
|
|
2567
|
+
if (!feature.isForced)
|
|
2220
2568
|
return '';
|
|
2221
|
-
return
|
|
2569
|
+
return feature.isEnabled ? 'on' : 'off';
|
|
2222
2570
|
}
|
|
2223
|
-
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type:
|
|
2224
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type:
|
|
2571
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarAppFeaturesToolComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2572
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: DevToolbarAppFeaturesToolComponent, isStandalone: true, selector: "ndt-app-features-tool", ngImport: i0, template: `
|
|
2225
2573
|
<ndt-toolbar-tool
|
|
2226
2574
|
[options]="options"
|
|
2227
|
-
title="
|
|
2228
|
-
icon="
|
|
2575
|
+
title="App Features"
|
|
2576
|
+
icon="puzzle"
|
|
2229
2577
|
>
|
|
2230
2578
|
<div class="container">
|
|
2231
2579
|
<div class="header">
|
|
2232
2580
|
<ndt-input
|
|
2233
2581
|
[value]="searchQuery()"
|
|
2234
2582
|
(valueChange)="onSearchChange($event)"
|
|
2235
|
-
placeholder="Search..."
|
|
2236
|
-
/>
|
|
2237
|
-
<ndt-select
|
|
2238
|
-
[value]="activeFilter()"
|
|
2239
|
-
[options]="filterOptions"
|
|
2240
|
-
[size]="'medium'"
|
|
2241
|
-
(valueChange)="onFilterChange($event)"
|
|
2583
|
+
placeholder="Search features..."
|
|
2242
2584
|
/>
|
|
2585
|
+
<div class="filter-wrapper">
|
|
2586
|
+
<ndt-icon name="filter" class="filter-icon" />
|
|
2587
|
+
<ndt-select
|
|
2588
|
+
[value]="activeFilter()"
|
|
2589
|
+
[options]="filterOptions"
|
|
2590
|
+
[size]="'medium'"
|
|
2591
|
+
(valueChange)="onFilterChange($event)"
|
|
2592
|
+
/>
|
|
2593
|
+
</div>
|
|
2594
|
+
</div>
|
|
2595
|
+
|
|
2596
|
+
@if (hasNoFeatures()) {
|
|
2597
|
+
<div class="empty">
|
|
2598
|
+
<p>No app features found</p>
|
|
2599
|
+
<small>Call setAvailableOptions() to configure features</small>
|
|
2600
|
+
</div>
|
|
2601
|
+
} @else if (hasNoFilteredFeatures()) {
|
|
2602
|
+
<div class="empty">
|
|
2603
|
+
<p>No features match your filter</p>
|
|
2604
|
+
</div>
|
|
2605
|
+
} @else {
|
|
2606
|
+
<div class="feature-list">
|
|
2607
|
+
@for (feature of filteredFeatures(); track feature.id) {
|
|
2608
|
+
<div class="feature">
|
|
2609
|
+
<div class="info">
|
|
2610
|
+
<h3>{{ feature.name }}</h3>
|
|
2611
|
+
@if (feature.description) {
|
|
2612
|
+
<p>{{ feature.description }}</p>
|
|
2613
|
+
}
|
|
2614
|
+
</div>
|
|
2615
|
+
|
|
2616
|
+
<ndt-select
|
|
2617
|
+
[value]="getFeatureValue(feature)"
|
|
2618
|
+
[options]="featureValueOptions"
|
|
2619
|
+
[ariaLabel]="'Set value for ' + feature.name"
|
|
2620
|
+
(valueChange)="onFeatureChange(feature.id, $event ?? '')"
|
|
2621
|
+
size="small"
|
|
2622
|
+
/>
|
|
2623
|
+
</div>
|
|
2624
|
+
}
|
|
2625
|
+
</div>
|
|
2626
|
+
}
|
|
2627
|
+
</div>
|
|
2628
|
+
</ndt-toolbar-tool>
|
|
2629
|
+
`, isInline: true, styles: [".container{display:flex;flex-direction:column;height:100%}.header{flex-shrink:0;display:flex;gap:var(--ndt-spacing-sm);margin-bottom:var(--ndt-spacing-md)}.header ndt-input{flex:1}.header .filter-wrapper{flex:0 0 auto;display:flex;align-items:center;gap:var(--ndt-spacing-md)}.header .filter-wrapper .filter-icon{width:18px;height:18px;flex-shrink:0;opacity:.6}.header .filter-wrapper ndt-select{flex:0 0 auto;min-width:180px}.empty{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;justify-content:center;align-items:center;border:1px solid var(--ndt-warning-border);border-radius:var(--ndt-border-radius-medium);padding:var(--ndt-spacing-md);background:var(--ndt-warning-background);color:var(--ndt-text-muted)}.empty p{margin:0;font-size:var(--ndt-font-size-md)}.empty small{font-size:var(--ndt-font-size-xs);opacity:.8}.feature-list{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;overflow-y:auto;padding-right:var(--ndt-spacing-sm);scrollbar-width:thin;scrollbar-color:var(--ndt-border-primary) var(--ndt-background-secondary)}.feature-list::-webkit-scrollbar{width:8px}.feature-list::-webkit-scrollbar-track{background:var(--ndt-background-secondary);border-radius:4px}.feature-list::-webkit-scrollbar-thumb{background:var(--ndt-border-primary);border-radius:4px}:is():hover{background:var(--ndt-hover-bg)}.feature{display:flex;flex-direction:row;gap:var(--ndt-spacing-sm);background:var(--ndt-background-secondary);padding:var(--ndt-spacing-md);border-radius:var(--ndt-border-radius-medium)}.feature .info{flex:0 0 65%}.feature .info h3{margin:0;font-size:var(--ndt-font-size-md);color:var(--ndt-text-primary)}.feature .info p{margin:var(--ndt-spacing-xs) 0 0 0;font-size:var(--ndt-font-size-xs);color:var(--ndt-text-muted)}.feature ndt-select{flex:0 0 35%}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "component", type: DevToolbarToolComponent, selector: "ndt-toolbar-tool", inputs: ["options", "icon", "title"] }, { kind: "component", type: DevToolbarInputComponent, selector: "ndt-input", inputs: ["value", "type", "placeholder", "ariaLabel", "inputClass"], outputs: ["valueChange"] }, { kind: "component", type: DevToolbarSelectComponent, selector: "ndt-select", inputs: ["value", "options", "ariaLabel", "label", "size"], outputs: ["valueChange"] }, { kind: "component", type: DevToolbarIconComponent, selector: "ndt-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2630
|
+
}
|
|
2631
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarAppFeaturesToolComponent, decorators: [{
|
|
2632
|
+
type: Component,
|
|
2633
|
+
args: [{ selector: 'ndt-app-features-tool', standalone: true, imports: [
|
|
2634
|
+
FormsModule,
|
|
2635
|
+
DevToolbarToolComponent,
|
|
2636
|
+
DevToolbarInputComponent,
|
|
2637
|
+
DevToolbarSelectComponent,
|
|
2638
|
+
DevToolbarIconComponent,
|
|
2639
|
+
], template: `
|
|
2640
|
+
<ndt-toolbar-tool
|
|
2641
|
+
[options]="options"
|
|
2642
|
+
title="App Features"
|
|
2643
|
+
icon="puzzle"
|
|
2644
|
+
>
|
|
2645
|
+
<div class="container">
|
|
2646
|
+
<div class="header">
|
|
2647
|
+
<ndt-input
|
|
2648
|
+
[value]="searchQuery()"
|
|
2649
|
+
(valueChange)="onSearchChange($event)"
|
|
2650
|
+
placeholder="Search features..."
|
|
2651
|
+
/>
|
|
2652
|
+
<div class="filter-wrapper">
|
|
2653
|
+
<ndt-icon name="filter" class="filter-icon" />
|
|
2654
|
+
<ndt-select
|
|
2655
|
+
[value]="activeFilter()"
|
|
2656
|
+
[options]="filterOptions"
|
|
2657
|
+
[size]="'medium'"
|
|
2658
|
+
(valueChange)="onFilterChange($event)"
|
|
2659
|
+
/>
|
|
2660
|
+
</div>
|
|
2661
|
+
</div>
|
|
2662
|
+
|
|
2663
|
+
@if (hasNoFeatures()) {
|
|
2664
|
+
<div class="empty">
|
|
2665
|
+
<p>No app features found</p>
|
|
2666
|
+
<small>Call setAvailableOptions() to configure features</small>
|
|
2667
|
+
</div>
|
|
2668
|
+
} @else if (hasNoFilteredFeatures()) {
|
|
2669
|
+
<div class="empty">
|
|
2670
|
+
<p>No features match your filter</p>
|
|
2671
|
+
</div>
|
|
2672
|
+
} @else {
|
|
2673
|
+
<div class="feature-list">
|
|
2674
|
+
@for (feature of filteredFeatures(); track feature.id) {
|
|
2675
|
+
<div class="feature">
|
|
2676
|
+
<div class="info">
|
|
2677
|
+
<h3>{{ feature.name }}</h3>
|
|
2678
|
+
@if (feature.description) {
|
|
2679
|
+
<p>{{ feature.description }}</p>
|
|
2680
|
+
}
|
|
2681
|
+
</div>
|
|
2682
|
+
|
|
2683
|
+
<ndt-select
|
|
2684
|
+
[value]="getFeatureValue(feature)"
|
|
2685
|
+
[options]="featureValueOptions"
|
|
2686
|
+
[ariaLabel]="'Set value for ' + feature.name"
|
|
2687
|
+
(valueChange)="onFeatureChange(feature.id, $event ?? '')"
|
|
2688
|
+
size="small"
|
|
2689
|
+
/>
|
|
2690
|
+
</div>
|
|
2691
|
+
}
|
|
2692
|
+
</div>
|
|
2693
|
+
}
|
|
2694
|
+
</div>
|
|
2695
|
+
</ndt-toolbar-tool>
|
|
2696
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".container{display:flex;flex-direction:column;height:100%}.header{flex-shrink:0;display:flex;gap:var(--ndt-spacing-sm);margin-bottom:var(--ndt-spacing-md)}.header ndt-input{flex:1}.header .filter-wrapper{flex:0 0 auto;display:flex;align-items:center;gap:var(--ndt-spacing-md)}.header .filter-wrapper .filter-icon{width:18px;height:18px;flex-shrink:0;opacity:.6}.header .filter-wrapper ndt-select{flex:0 0 auto;min-width:180px}.empty{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;justify-content:center;align-items:center;border:1px solid var(--ndt-warning-border);border-radius:var(--ndt-border-radius-medium);padding:var(--ndt-spacing-md);background:var(--ndt-warning-background);color:var(--ndt-text-muted)}.empty p{margin:0;font-size:var(--ndt-font-size-md)}.empty small{font-size:var(--ndt-font-size-xs);opacity:.8}.feature-list{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;overflow-y:auto;padding-right:var(--ndt-spacing-sm);scrollbar-width:thin;scrollbar-color:var(--ndt-border-primary) var(--ndt-background-secondary)}.feature-list::-webkit-scrollbar{width:8px}.feature-list::-webkit-scrollbar-track{background:var(--ndt-background-secondary);border-radius:4px}.feature-list::-webkit-scrollbar-thumb{background:var(--ndt-border-primary);border-radius:4px}:is():hover{background:var(--ndt-hover-bg)}.feature{display:flex;flex-direction:row;gap:var(--ndt-spacing-sm);background:var(--ndt-background-secondary);padding:var(--ndt-spacing-md);border-radius:var(--ndt-border-radius-medium)}.feature .info{flex:0 0 65%}.feature .info h3{margin:0;font-size:var(--ndt-font-size-md);color:var(--ndt-text-primary)}.feature .info p{margin:var(--ndt-spacing-xs) 0 0 0;font-size:var(--ndt-font-size-xs);color:var(--ndt-text-muted)}.feature ndt-select{flex:0 0 35%}\n"] }]
|
|
2697
|
+
}] });
|
|
2698
|
+
|
|
2699
|
+
class DevToolbarInternalFeatureFlagService {
|
|
2700
|
+
constructor() {
|
|
2701
|
+
this.STORAGE_KEY = 'feature-flags';
|
|
2702
|
+
this.storageService = inject(DevToolsStorageService);
|
|
2703
|
+
this.appFlags$ = new BehaviorSubject([]);
|
|
2704
|
+
this.forcedFlagsSubject = new BehaviorSubject({
|
|
2705
|
+
enabled: [],
|
|
2706
|
+
disabled: [],
|
|
2707
|
+
});
|
|
2708
|
+
this.forcedFlags$ = this.forcedFlagsSubject.asObservable();
|
|
2709
|
+
this.flags$ = combineLatest([
|
|
2710
|
+
this.appFlags$,
|
|
2711
|
+
this.forcedFlags$,
|
|
2712
|
+
]).pipe(map(([appFlags, { enabled, disabled }]) => {
|
|
2713
|
+
return appFlags.map((flag) => ({
|
|
2714
|
+
...flag,
|
|
2715
|
+
isForced: enabled.includes(flag.id) || disabled.includes(flag.id),
|
|
2716
|
+
isEnabled: enabled.includes(flag.id)
|
|
2717
|
+
? true
|
|
2718
|
+
: disabled.includes(flag.id)
|
|
2719
|
+
? false
|
|
2720
|
+
: flag.isEnabled,
|
|
2721
|
+
}));
|
|
2722
|
+
}));
|
|
2723
|
+
this.flags = toSignal(this.flags$, { initialValue: [] });
|
|
2724
|
+
this.loadForcedFlags();
|
|
2725
|
+
}
|
|
2726
|
+
setAppFlags(flags) {
|
|
2727
|
+
this.appFlags$.next(flags);
|
|
2728
|
+
}
|
|
2729
|
+
getAppFlags() {
|
|
2730
|
+
return this.appFlags$.asObservable();
|
|
2731
|
+
}
|
|
2732
|
+
getForcedFlags() {
|
|
2733
|
+
return this.flags$.pipe(map((flags) => flags.filter((flag) => flag.isForced)));
|
|
2734
|
+
}
|
|
2735
|
+
setFlag(flagId, isEnabled) {
|
|
2736
|
+
const { enabled, disabled } = this.forcedFlagsSubject.value;
|
|
2737
|
+
const newEnabled = enabled.filter((id) => id !== flagId);
|
|
2738
|
+
const newDisabled = disabled.filter((id) => id !== flagId);
|
|
2739
|
+
if (isEnabled) {
|
|
2740
|
+
newEnabled.push(flagId);
|
|
2741
|
+
}
|
|
2742
|
+
else {
|
|
2743
|
+
newDisabled.push(flagId);
|
|
2744
|
+
}
|
|
2745
|
+
const newState = { enabled: newEnabled, disabled: newDisabled };
|
|
2746
|
+
this.forcedFlagsSubject.next(newState);
|
|
2747
|
+
this.storageService.set(this.STORAGE_KEY, newState);
|
|
2748
|
+
}
|
|
2749
|
+
removeFlagOverride(flagId) {
|
|
2750
|
+
const { enabled, disabled } = this.forcedFlagsSubject.value;
|
|
2751
|
+
const newState = {
|
|
2752
|
+
enabled: enabled.filter((id) => id !== flagId),
|
|
2753
|
+
disabled: disabled.filter((id) => id !== flagId),
|
|
2754
|
+
};
|
|
2755
|
+
this.forcedFlagsSubject.next(newState);
|
|
2756
|
+
this.storageService.set(this.STORAGE_KEY, newState);
|
|
2757
|
+
}
|
|
2758
|
+
loadForcedFlags() {
|
|
2759
|
+
const savedFlags = this.storageService.get(this.STORAGE_KEY);
|
|
2760
|
+
if (savedFlags) {
|
|
2761
|
+
this.forcedFlagsSubject.next(savedFlags);
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
/**
|
|
2765
|
+
* Apply feature flags from a preset (used by Presets Tool)
|
|
2766
|
+
* This method directly sets the forced flags state without user interaction
|
|
2767
|
+
*/
|
|
2768
|
+
applyPresetFlags(presetState) {
|
|
2769
|
+
this.forcedFlagsSubject.next(presetState);
|
|
2770
|
+
this.storageService.set(this.STORAGE_KEY, presetState);
|
|
2771
|
+
}
|
|
2772
|
+
/**
|
|
2773
|
+
* Get current forced state for saving to preset
|
|
2774
|
+
* Returns the raw state of enabled and disabled flag IDs
|
|
2775
|
+
*/
|
|
2776
|
+
getCurrentForcedState() {
|
|
2777
|
+
return this.forcedFlagsSubject.value;
|
|
2778
|
+
}
|
|
2779
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalFeatureFlagService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2780
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalFeatureFlagService, providedIn: 'root' }); }
|
|
2781
|
+
}
|
|
2782
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalFeatureFlagService, decorators: [{
|
|
2783
|
+
type: Injectable,
|
|
2784
|
+
args: [{ providedIn: 'root' }]
|
|
2785
|
+
}], ctorParameters: () => [] });
|
|
2786
|
+
|
|
2787
|
+
class DevToolbarFeatureFlagsToolComponent {
|
|
2788
|
+
constructor() {
|
|
2789
|
+
// Injects
|
|
2790
|
+
this.featureFlags = inject(DevToolbarInternalFeatureFlagService);
|
|
2791
|
+
// Signals
|
|
2792
|
+
this.activeFilter = signal('all');
|
|
2793
|
+
this.searchQuery = signal('');
|
|
2794
|
+
this.flags = this.featureFlags.flags;
|
|
2795
|
+
this.hasNoFlags = computed(() => this.flags().length === 0);
|
|
2796
|
+
this.filteredFlags = computed(() => {
|
|
2797
|
+
return this.flags().filter((flag) => {
|
|
2798
|
+
const searchTerm = this.searchQuery().toLowerCase();
|
|
2799
|
+
const flagName = flag.name.toLowerCase();
|
|
2800
|
+
const flagDescription = flag.description?.toLowerCase() ?? '';
|
|
2801
|
+
const matchesSearch = !this.searchQuery() ||
|
|
2802
|
+
flagName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
2803
|
+
flagDescription.toLowerCase().includes(searchTerm.toLowerCase());
|
|
2804
|
+
const matchesFilter = this.activeFilter() === 'all' ||
|
|
2805
|
+
(this.activeFilter() === 'forced' && flag.isForced) ||
|
|
2806
|
+
(this.activeFilter() === 'enabled' && flag.isEnabled) ||
|
|
2807
|
+
(this.activeFilter() === 'disabled' && !flag.isEnabled);
|
|
2808
|
+
return matchesSearch && matchesFilter;
|
|
2809
|
+
});
|
|
2810
|
+
});
|
|
2811
|
+
this.hasNoFilteredFlags = computed(() => this.filteredFlags().length === 0);
|
|
2812
|
+
// Other properties
|
|
2813
|
+
this.options = {
|
|
2814
|
+
title: 'Feature Flags',
|
|
2815
|
+
description: 'Manage the feature flags for your current session',
|
|
2816
|
+
isClosable: true,
|
|
2817
|
+
size: 'tall',
|
|
2818
|
+
id: 'ndt-feature-flags',
|
|
2819
|
+
isBeta: true,
|
|
2820
|
+
};
|
|
2821
|
+
this.filterOptions = [
|
|
2822
|
+
{ value: 'all', label: 'All Flags' },
|
|
2823
|
+
{ value: 'forced', label: 'Forced' },
|
|
2824
|
+
{ value: 'enabled', label: 'Enabled' },
|
|
2825
|
+
{ value: 'disabled', label: 'Disabled' },
|
|
2826
|
+
];
|
|
2827
|
+
this.flagValueOptions = [
|
|
2828
|
+
{ value: 'not-forced', label: 'Not Forced' },
|
|
2829
|
+
{ value: 'off', label: 'Forced Off' },
|
|
2830
|
+
{ value: 'on', label: 'Forced On' },
|
|
2831
|
+
];
|
|
2832
|
+
}
|
|
2833
|
+
// Public methods
|
|
2834
|
+
onFilterChange(value) {
|
|
2835
|
+
const filter = this.filterOptions.find((f) => f.value === value);
|
|
2836
|
+
if (filter) {
|
|
2837
|
+
this.activeFilter.set(filter.value);
|
|
2838
|
+
}
|
|
2839
|
+
}
|
|
2840
|
+
onFlagChange(flagId, value) {
|
|
2841
|
+
switch (value) {
|
|
2842
|
+
case 'not-forced':
|
|
2843
|
+
this.featureFlags.removeFlagOverride(flagId);
|
|
2844
|
+
break;
|
|
2845
|
+
case 'on':
|
|
2846
|
+
this.featureFlags.setFlag(flagId, true);
|
|
2847
|
+
break;
|
|
2848
|
+
case 'off':
|
|
2849
|
+
this.featureFlags.setFlag(flagId, false);
|
|
2850
|
+
break;
|
|
2851
|
+
}
|
|
2852
|
+
}
|
|
2853
|
+
onSearchChange(query) {
|
|
2854
|
+
this.searchQuery.set(query);
|
|
2855
|
+
}
|
|
2856
|
+
// Protected methods
|
|
2857
|
+
getFlagValue(flag) {
|
|
2858
|
+
if (!flag.isForced)
|
|
2859
|
+
return '';
|
|
2860
|
+
return flag.isEnabled ? 'on' : 'off';
|
|
2861
|
+
}
|
|
2862
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarFeatureFlagsToolComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2863
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: DevToolbarFeatureFlagsToolComponent, isStandalone: true, selector: "ndt-feature-flags-tool", ngImport: i0, template: `
|
|
2864
|
+
<ndt-toolbar-tool
|
|
2865
|
+
[options]="options"
|
|
2866
|
+
title="Feature Flags"
|
|
2867
|
+
icon="toggle-left"
|
|
2868
|
+
>
|
|
2869
|
+
<div class="container">
|
|
2870
|
+
<div class="header">
|
|
2871
|
+
<ndt-input
|
|
2872
|
+
[value]="searchQuery()"
|
|
2873
|
+
(valueChange)="onSearchChange($event)"
|
|
2874
|
+
placeholder="Search..."
|
|
2875
|
+
/>
|
|
2876
|
+
<div class="filter-wrapper">
|
|
2877
|
+
<ndt-icon name="filter" class="filter-icon" />
|
|
2878
|
+
<ndt-select
|
|
2879
|
+
[value]="activeFilter()"
|
|
2880
|
+
[options]="filterOptions"
|
|
2881
|
+
[size]="'medium'"
|
|
2882
|
+
(valueChange)="onFilterChange($event)"
|
|
2883
|
+
/>
|
|
2884
|
+
</div>
|
|
2243
2885
|
</div>
|
|
2244
2886
|
|
|
2245
2887
|
@if (hasNoFlags()) {
|
|
@@ -2272,7 +2914,7 @@ class DevToolbarFeatureFlagsToolComponent {
|
|
|
2272
2914
|
}
|
|
2273
2915
|
</div>
|
|
2274
2916
|
</ndt-toolbar-tool>
|
|
2275
|
-
`, isInline: true, styles: [".container{display:flex;flex-direction:column;height:100%}.header{flex-shrink:0;display:flex;gap:var(--ndt-spacing-sm);margin-bottom:var(--ndt-spacing-md)}.header ndt-input{flex:.
|
|
2917
|
+
`, isInline: true, styles: [".container{display:flex;flex-direction:column;height:100%}.header{flex-shrink:0;display:flex;gap:var(--ndt-spacing-sm);margin-bottom:var(--ndt-spacing-md)}.header ndt-input{flex:1}.header .filter-wrapper{flex:0 0 auto;display:flex;align-items:center;gap:var(--ndt-spacing-md)}.header .filter-wrapper .filter-icon{width:18px;height:18px;flex-shrink:0;opacity:.6}.header .filter-wrapper ndt-select{flex:0 0 auto;min-width:180px}.empty{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;justify-content:center;align-items:center;border:1px solid var(--ndt-warning-border);border-radius:var(--ndt-border-radius-medium);padding:var(--ndt-spacing-md);background:var(--ndt-warning-background);color:var(--ndt-text-muted)}.flag-list{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;overflow-y:auto;padding-right:var(--ndt-spacing-sm);scrollbar-width:thin;scrollbar-color:var(--ndt-border-primary) var(--ndt-background-secondary)}.flag-list::-webkit-scrollbar{width:8px}.flag-list::-webkit-scrollbar-track{background:var(--ndt-background-secondary);border-radius:4px}.flag-list::-webkit-scrollbar-thumb{background:var(--ndt-border-primary);border-radius:4px}:is():hover{background:var(--ndt-hover-bg)}.flag{display:flex;flex-direction:row;gap:var(--ndt-spacing-sm);background:var(--ndt-background-secondary)}.flag .info{flex:0 0 65%}.flag .info h3{margin:0;font-size:var(--ndt-font-size-md);color:var(--ndt-text-primary)}.flag .info p{font-size:var(--ndt-font-size-xs);color:var(--ndt-text-muted)}.flag ndt-select{flex:0 0 35%}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "component", type: DevToolbarToolComponent, selector: "ndt-toolbar-tool", inputs: ["options", "icon", "title"] }, { kind: "component", type: DevToolbarInputComponent, selector: "ndt-input", inputs: ["value", "type", "placeholder", "ariaLabel", "inputClass"], outputs: ["valueChange"] }, { kind: "component", type: DevToolbarSelectComponent, selector: "ndt-select", inputs: ["value", "options", "ariaLabel", "label", "size"], outputs: ["valueChange"] }, { kind: "component", type: DevToolbarIconComponent, selector: "ndt-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2276
2918
|
}
|
|
2277
2919
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarFeatureFlagsToolComponent, decorators: [{
|
|
2278
2920
|
type: Component,
|
|
@@ -2281,6 +2923,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2281
2923
|
DevToolbarToolComponent,
|
|
2282
2924
|
DevToolbarInputComponent,
|
|
2283
2925
|
DevToolbarSelectComponent,
|
|
2926
|
+
DevToolbarIconComponent,
|
|
2284
2927
|
], template: `
|
|
2285
2928
|
<ndt-toolbar-tool
|
|
2286
2929
|
[options]="options"
|
|
@@ -2294,12 +2937,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2294
2937
|
(valueChange)="onSearchChange($event)"
|
|
2295
2938
|
placeholder="Search..."
|
|
2296
2939
|
/>
|
|
2297
|
-
<
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2940
|
+
<div class="filter-wrapper">
|
|
2941
|
+
<ndt-icon name="filter" class="filter-icon" />
|
|
2942
|
+
<ndt-select
|
|
2943
|
+
[value]="activeFilter()"
|
|
2944
|
+
[options]="filterOptions"
|
|
2945
|
+
[size]="'medium'"
|
|
2946
|
+
(valueChange)="onFilterChange($event)"
|
|
2947
|
+
/>
|
|
2948
|
+
</div>
|
|
2303
2949
|
</div>
|
|
2304
2950
|
|
|
2305
2951
|
@if (hasNoFlags()) {
|
|
@@ -2332,7 +2978,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2332
2978
|
}
|
|
2333
2979
|
</div>
|
|
2334
2980
|
</ndt-toolbar-tool>
|
|
2335
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".container{display:flex;flex-direction:column;height:100%}.header{flex-shrink:0;display:flex;gap:var(--ndt-spacing-sm);margin-bottom:var(--ndt-spacing-md)}.header ndt-input{flex:.
|
|
2981
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".container{display:flex;flex-direction:column;height:100%}.header{flex-shrink:0;display:flex;gap:var(--ndt-spacing-sm);margin-bottom:var(--ndt-spacing-md)}.header ndt-input{flex:1}.header .filter-wrapper{flex:0 0 auto;display:flex;align-items:center;gap:var(--ndt-spacing-md)}.header .filter-wrapper .filter-icon{width:18px;height:18px;flex-shrink:0;opacity:.6}.header .filter-wrapper ndt-select{flex:0 0 auto;min-width:180px}.empty{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;justify-content:center;align-items:center;border:1px solid var(--ndt-warning-border);border-radius:var(--ndt-border-radius-medium);padding:var(--ndt-spacing-md);background:var(--ndt-warning-background);color:var(--ndt-text-muted)}.flag-list{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;overflow-y:auto;padding-right:var(--ndt-spacing-sm);scrollbar-width:thin;scrollbar-color:var(--ndt-border-primary) var(--ndt-background-secondary)}.flag-list::-webkit-scrollbar{width:8px}.flag-list::-webkit-scrollbar-track{background:var(--ndt-background-secondary);border-radius:4px}.flag-list::-webkit-scrollbar-thumb{background:var(--ndt-border-primary);border-radius:4px}:is():hover{background:var(--ndt-hover-bg)}.flag{display:flex;flex-direction:row;gap:var(--ndt-spacing-sm);background:var(--ndt-background-secondary)}.flag .info{flex:0 0 65%}.flag .info h3{margin:0;font-size:var(--ndt-font-size-md);color:var(--ndt-text-primary)}.flag .info p{font-size:var(--ndt-font-size-xs);color:var(--ndt-text-muted)}.flag ndt-select{flex:0 0 35%}\n"] }]
|
|
2336
2982
|
}] });
|
|
2337
2983
|
|
|
2338
2984
|
class DevToolbarButtonComponent {
|
|
@@ -2361,7 +3007,7 @@ class DevToolbarButtonComponent {
|
|
|
2361
3007
|
}
|
|
2362
3008
|
<ng-content />
|
|
2363
3009
|
</button>
|
|
2364
|
-
`, isInline: true, styles: [".
|
|
3010
|
+
`, isInline: true, styles: [".button{display:inline-flex;align-items:center;gap:var(--ndt-spacing-xs);padding:var(--ndt-spacing-sm) var(--ndt-spacing-md);min-height:36px;border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-medium);background:var(--ndt-bg-primary);color:var(--ndt-text-primary);cursor:pointer;transition:var(--ndt-transition-default);outline:none;font-family:inherit}.button:hover{background:var(--ndt-hover-bg);border-color:var(--ndt-primary)}.button:focus-visible{outline:none;background:var(--ndt-hover-bg);box-shadow:0 0 0 2px rgba(var(--ndt-primary-rgb),.2)}.button.primary{background:var(--ndt-primary);color:var(--ndt-text-on-primary);border-color:var(--ndt-primary)}.button.primary:hover{background:var(--ndt-primary);border-color:var(--ndt-primary)}.button.icon-only{padding:var(--ndt-spacing-xs);width:32px;height:32px;justify-content:center}.button.small{font-size:var(--ndt-font-size-sm)}\n"], dependencies: [{ kind: "component", type: DevToolbarIconComponent, selector: "ndt-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2365
3011
|
}
|
|
2366
3012
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarButtonComponent, decorators: [{
|
|
2367
3013
|
type: Component,
|
|
@@ -2381,7 +3027,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2381
3027
|
}
|
|
2382
3028
|
<ng-content />
|
|
2383
3029
|
</button>
|
|
2384
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".
|
|
3030
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".button{display:inline-flex;align-items:center;gap:var(--ndt-spacing-xs);padding:var(--ndt-spacing-sm) var(--ndt-spacing-md);min-height:36px;border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-medium);background:var(--ndt-bg-primary);color:var(--ndt-text-primary);cursor:pointer;transition:var(--ndt-transition-default);outline:none;font-family:inherit}.button:hover{background:var(--ndt-hover-bg);border-color:var(--ndt-primary)}.button:focus-visible{outline:none;background:var(--ndt-hover-bg);box-shadow:0 0 0 2px rgba(var(--ndt-primary-rgb),.2)}.button.primary{background:var(--ndt-primary);color:var(--ndt-text-on-primary);border-color:var(--ndt-primary)}.button.primary:hover{background:var(--ndt-primary);border-color:var(--ndt-primary)}.button.icon-only{padding:var(--ndt-spacing-xs);width:32px;height:32px;justify-content:center}.button.small{font-size:var(--ndt-font-size-sm)}\n"] }]
|
|
2385
3031
|
}] });
|
|
2386
3032
|
|
|
2387
3033
|
class DevToolbarCardComponent {
|
|
@@ -2451,7 +3097,7 @@ class DevToolbarClickableCardComponent {
|
|
|
2451
3097
|
</div>
|
|
2452
3098
|
</div>
|
|
2453
3099
|
</ndt-card>
|
|
2454
|
-
`, isInline: true, styles: [".clickable-card{display:flex;flex-direction:column;gap:var(--ndt-spacing-
|
|
3100
|
+
`, isInline: true, styles: [".clickable-card{display:flex;flex-direction:column;gap:var(--ndt-spacing-xs);height:100%}.clickable-card__icon{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:var(--ndt-border-radius-medium);background:var(--ndt-hover-bg);color:var(--ndt-text-primary)}.clickable-card__content{display:flex;flex-direction:column;gap:var(--ndt-spacing-xs)}.clickable-card__title{color:var(--ndt-text-primary);font-size:var(--ndt-font-size-sm);font-weight:500}.clickable-card__subtitle{color:var(--ndt-text-muted);font-size:var(--ndt-font-size-xs);line-height:1.4;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n"], dependencies: [{ kind: "component", type: DevToolbarCardComponent, selector: "ndt-card" }, { kind: "component", type: DevToolbarIconComponent, selector: "ndt-icon", inputs: ["name"] }] }); }
|
|
2455
3101
|
}
|
|
2456
3102
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarClickableCardComponent, decorators: [{
|
|
2457
3103
|
type: Component,
|
|
@@ -2467,7 +3113,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2467
3113
|
</div>
|
|
2468
3114
|
</div>
|
|
2469
3115
|
</ndt-card>
|
|
2470
|
-
`, styles: [".clickable-card{display:flex;flex-direction:column;gap:var(--ndt-spacing-
|
|
3116
|
+
`, styles: [".clickable-card{display:flex;flex-direction:column;gap:var(--ndt-spacing-xs);height:100%}.clickable-card__icon{display:flex;align-items:center;justify-content:center;width:32px;height:32px;border-radius:var(--ndt-border-radius-medium);background:var(--ndt-hover-bg);color:var(--ndt-text-primary)}.clickable-card__content{display:flex;flex-direction:column;gap:var(--ndt-spacing-xs)}.clickable-card__title{color:var(--ndt-text-primary);font-size:var(--ndt-font-size-sm);font-weight:500}.clickable-card__subtitle{color:var(--ndt-text-muted);font-size:var(--ndt-font-size-xs);line-height:1.4;display:-webkit-box;-webkit-line-clamp:2;-webkit-box-orient:vertical;overflow:hidden}\n"] }]
|
|
2471
3117
|
}] });
|
|
2472
3118
|
|
|
2473
3119
|
class DevToolbarLinkButtonComponent {
|
|
@@ -2694,7 +3340,7 @@ class DevToolbarHomeToolComponent {
|
|
|
2694
3340
|
</div>
|
|
2695
3341
|
</section>
|
|
2696
3342
|
</ndt-toolbar-tool>
|
|
2697
|
-
`, isInline: true, styles: [".
|
|
3343
|
+
`, isInline: true, styles: [".settings{display:flex;flex-direction:column;justify-content:space-between;min-height:100%}.instruction{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--ndt-spacing-sm)}.instruction__label{display:flex;flex-direction:column;gap:var(--ndt-spacing-xs)}.instruction__label-text{color:var(--ndt-text-primary);font-size:var(--ndt-font-size-sm);font-weight:500}.instruction__label-description{color:var(--ndt-text-muted);font-size:var(--ndt-font-size-xs)}.instruction__control{flex:1}.instruction__control-button{display:flex;gap:var(--ndt-spacing-xs);justify-content:flex-end}.settings-container{display:flex;flex-direction:column}.settings-container .settings-actions{display:flex;gap:var(--ndt-spacing-md);padding-block:var(--ndt-spacing-sm)}.settings-container .settings-actions>*{width:50%;min-width:0}.footer-links{border-top:1px solid var(--ndt-border-subtle);padding-top:1em;display:flex;flex-direction:row;justify-content:space-between;gap:var(--ndt-spacing-lg)}\n"], dependencies: [{ kind: "component", type: DevToolbarToolComponent, selector: "ndt-toolbar-tool", inputs: ["options", "icon", "title"] }, { kind: "ngmodule", type: FormsModule }, { kind: "component", type: DevToolbarButtonComponent, selector: "ndt-button", inputs: ["type", "variant", "icon", "label", "ariaLabel", "isActive"] }, { kind: "component", type: DevToolbarClickableCardComponent, selector: "ndt-clickable-card", inputs: ["icon", "title", "subtitle"] }, { kind: "component", type: DevToolbarLinkButtonComponent, selector: "ndt-link-button", inputs: ["url", "icon"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
2698
3344
|
}
|
|
2699
3345
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarHomeToolComponent, decorators: [{
|
|
2700
3346
|
type: Component,
|
|
@@ -2775,7 +3421,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2775
3421
|
</div>
|
|
2776
3422
|
</section>
|
|
2777
3423
|
</ndt-toolbar-tool>
|
|
2778
|
-
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".
|
|
3424
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".settings{display:flex;flex-direction:column;justify-content:space-between;min-height:100%}.instruction{display:flex;justify-content:space-between;align-items:flex-start;gap:var(--ndt-spacing-sm)}.instruction__label{display:flex;flex-direction:column;gap:var(--ndt-spacing-xs)}.instruction__label-text{color:var(--ndt-text-primary);font-size:var(--ndt-font-size-sm);font-weight:500}.instruction__label-description{color:var(--ndt-text-muted);font-size:var(--ndt-font-size-xs)}.instruction__control{flex:1}.instruction__control-button{display:flex;gap:var(--ndt-spacing-xs);justify-content:flex-end}.settings-container{display:flex;flex-direction:column}.settings-container .settings-actions{display:flex;gap:var(--ndt-spacing-md);padding-block:var(--ndt-spacing-sm)}.settings-container .settings-actions>*{width:50%;min-width:0}.footer-links{border-top:1px solid var(--ndt-border-subtle);padding-top:1em;display:flex;flex-direction:row;justify-content:space-between;gap:var(--ndt-spacing-lg)}\n"] }]
|
|
2779
3425
|
}] });
|
|
2780
3426
|
|
|
2781
3427
|
class DevToolbarInternalLanguageService {
|
|
@@ -2810,6 +3456,32 @@ class DevToolbarInternalLanguageService {
|
|
|
2810
3456
|
this.forcedLanguage$.next(savedLanguage);
|
|
2811
3457
|
}
|
|
2812
3458
|
}
|
|
3459
|
+
/**
|
|
3460
|
+
* Apply language from a preset (used by Presets Tool)
|
|
3461
|
+
* Accepts a language ID and finds the corresponding Language object from available languages
|
|
3462
|
+
*/
|
|
3463
|
+
async applyPresetLanguage(languageId) {
|
|
3464
|
+
if (languageId === null) {
|
|
3465
|
+
this.removeForcedLanguage();
|
|
3466
|
+
return;
|
|
3467
|
+
}
|
|
3468
|
+
// Get available languages and find matching one
|
|
3469
|
+
const languages = await firstValueFrom(this.languages$);
|
|
3470
|
+
const language = languages.find((lang) => lang.id === languageId);
|
|
3471
|
+
if (language) {
|
|
3472
|
+
this.setForcedLanguage(language);
|
|
3473
|
+
}
|
|
3474
|
+
else {
|
|
3475
|
+
console.warn(`Language ${languageId} not found in available languages. Skipping.`);
|
|
3476
|
+
}
|
|
3477
|
+
}
|
|
3478
|
+
/**
|
|
3479
|
+
* Get current forced language ID for saving to preset
|
|
3480
|
+
* Returns the language ID or null if no language is forced
|
|
3481
|
+
*/
|
|
3482
|
+
getCurrentForcedLanguage() {
|
|
3483
|
+
return this.forcedLanguage$.value?.id ?? null;
|
|
3484
|
+
}
|
|
2813
3485
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalLanguageService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2814
3486
|
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalLanguageService, providedIn: 'root' }); }
|
|
2815
3487
|
}
|
|
@@ -2883,18 +3555,923 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2883
3555
|
`, styles: [".language-select{display:flex;flex-direction:row;gap:.5rem;align-items:center;justify-content:space-between}\n"] }]
|
|
2884
3556
|
}] });
|
|
2885
3557
|
|
|
2886
|
-
class
|
|
3558
|
+
class DevToolbarInternalPermissionsService {
|
|
2887
3559
|
constructor() {
|
|
2888
|
-
this.
|
|
2889
|
-
this.
|
|
2890
|
-
this.
|
|
2891
|
-
this.
|
|
2892
|
-
|
|
2893
|
-
|
|
2894
|
-
|
|
2895
|
-
this.
|
|
2896
|
-
|
|
2897
|
-
|
|
3560
|
+
this.STORAGE_KEY = 'permissions';
|
|
3561
|
+
this.storageService = inject(DevToolsStorageService);
|
|
3562
|
+
this.appPermissions$ = new BehaviorSubject([]);
|
|
3563
|
+
this.forcedStateSubject = new BehaviorSubject({
|
|
3564
|
+
granted: [],
|
|
3565
|
+
denied: [],
|
|
3566
|
+
});
|
|
3567
|
+
this.forcedState$ = this.forcedStateSubject.asObservable();
|
|
3568
|
+
this.permissions$ = combineLatest([
|
|
3569
|
+
this.appPermissions$,
|
|
3570
|
+
this.forcedState$,
|
|
3571
|
+
]).pipe(map(([appPermissions, { granted, denied }]) => {
|
|
3572
|
+
return appPermissions.map((permission) => ({
|
|
3573
|
+
...permission,
|
|
3574
|
+
isForced: granted.includes(permission.id) || denied.includes(permission.id),
|
|
3575
|
+
isGranted: granted.includes(permission.id)
|
|
3576
|
+
? true
|
|
3577
|
+
: denied.includes(permission.id)
|
|
3578
|
+
? false
|
|
3579
|
+
: permission.isGranted,
|
|
3580
|
+
}));
|
|
3581
|
+
}));
|
|
3582
|
+
this.permissions = toSignal(this.permissions$, { initialValue: [] });
|
|
3583
|
+
this.loadForcedState();
|
|
3584
|
+
}
|
|
3585
|
+
setAppPermissions(permissions) {
|
|
3586
|
+
this.appPermissions$.next(permissions);
|
|
3587
|
+
this.validateAndCleanForcedState(permissions);
|
|
3588
|
+
}
|
|
3589
|
+
setPermission(id, granted) {
|
|
3590
|
+
const { granted: grantedIds, denied: deniedIds } = this.forcedStateSubject.value;
|
|
3591
|
+
const newGranted = grantedIds.filter((permId) => permId !== id);
|
|
3592
|
+
const newDenied = deniedIds.filter((permId) => permId !== id);
|
|
3593
|
+
if (granted) {
|
|
3594
|
+
newGranted.push(id);
|
|
3595
|
+
}
|
|
3596
|
+
else {
|
|
3597
|
+
newDenied.push(id);
|
|
3598
|
+
}
|
|
3599
|
+
const newState = { granted: newGranted, denied: newDenied };
|
|
3600
|
+
this.forcedStateSubject.next(newState);
|
|
3601
|
+
this.storageService.set(this.STORAGE_KEY, newState);
|
|
3602
|
+
}
|
|
3603
|
+
removePermissionOverride(id) {
|
|
3604
|
+
const { granted, denied } = this.forcedStateSubject.value;
|
|
3605
|
+
const newState = {
|
|
3606
|
+
granted: granted.filter((permId) => permId !== id),
|
|
3607
|
+
denied: denied.filter((permId) => permId !== id),
|
|
3608
|
+
};
|
|
3609
|
+
this.forcedStateSubject.next(newState);
|
|
3610
|
+
this.storageService.set(this.STORAGE_KEY, newState);
|
|
3611
|
+
}
|
|
3612
|
+
getForcedPermissions() {
|
|
3613
|
+
return this.permissions$.pipe(map((permissions) => permissions.filter((permission) => permission.isForced)));
|
|
3614
|
+
}
|
|
3615
|
+
/**
|
|
3616
|
+
* Apply a preset permissions state, replacing the current forced state.
|
|
3617
|
+
* Useful for automated testing or restoring saved configurations.
|
|
3618
|
+
* @param state The preset forced permissions state to apply
|
|
3619
|
+
*/
|
|
3620
|
+
applyPresetPermissions(state) {
|
|
3621
|
+
this.forcedStateSubject.next(state);
|
|
3622
|
+
this.storageService.set(this.STORAGE_KEY, state);
|
|
3623
|
+
}
|
|
3624
|
+
/**
|
|
3625
|
+
* Get the current forced permissions state.
|
|
3626
|
+
* Returns a deep copy to prevent external mutations.
|
|
3627
|
+
* @returns Current forced permissions state
|
|
3628
|
+
*/
|
|
3629
|
+
getCurrentForcedState() {
|
|
3630
|
+
const currentState = this.forcedStateSubject.value;
|
|
3631
|
+
return {
|
|
3632
|
+
granted: [...currentState.granted],
|
|
3633
|
+
denied: [...currentState.denied],
|
|
3634
|
+
};
|
|
3635
|
+
}
|
|
3636
|
+
loadForcedState() {
|
|
3637
|
+
try {
|
|
3638
|
+
const savedState = this.storageService.get(this.STORAGE_KEY);
|
|
3639
|
+
if (savedState && this.isValidForcedState(savedState)) {
|
|
3640
|
+
this.forcedStateSubject.next(savedState);
|
|
3641
|
+
}
|
|
3642
|
+
}
|
|
3643
|
+
catch (error) {
|
|
3644
|
+
console.warn('Error loading forced permissions state from localStorage:', error);
|
|
3645
|
+
}
|
|
3646
|
+
}
|
|
3647
|
+
isValidForcedState(state) {
|
|
3648
|
+
return (state &&
|
|
3649
|
+
typeof state === 'object' &&
|
|
3650
|
+
Array.isArray(state.granted) &&
|
|
3651
|
+
Array.isArray(state.denied));
|
|
3652
|
+
}
|
|
3653
|
+
validateAndCleanForcedState(permissions) {
|
|
3654
|
+
const currentState = this.forcedStateSubject.value;
|
|
3655
|
+
const validIds = new Set(permissions.map((p) => p.id));
|
|
3656
|
+
const cleanedGranted = currentState.granted.filter((id) => validIds.has(id));
|
|
3657
|
+
const cleanedDenied = currentState.denied.filter((id) => validIds.has(id));
|
|
3658
|
+
const hasInvalidIds = cleanedGranted.length !== currentState.granted.length ||
|
|
3659
|
+
cleanedDenied.length !== currentState.denied.length;
|
|
3660
|
+
if (hasInvalidIds) {
|
|
3661
|
+
const cleanedState = {
|
|
3662
|
+
granted: cleanedGranted,
|
|
3663
|
+
denied: cleanedDenied,
|
|
3664
|
+
};
|
|
3665
|
+
this.forcedStateSubject.next(cleanedState);
|
|
3666
|
+
this.storageService.set(this.STORAGE_KEY, cleanedState);
|
|
3667
|
+
const invalidIds = [
|
|
3668
|
+
...currentState.granted.filter((id) => !validIds.has(id)),
|
|
3669
|
+
...currentState.denied.filter((id) => !validIds.has(id)),
|
|
3670
|
+
];
|
|
3671
|
+
if (invalidIds.length > 0) {
|
|
3672
|
+
console.warn('Removed invalid permission IDs from forced state:', invalidIds);
|
|
3673
|
+
}
|
|
3674
|
+
}
|
|
3675
|
+
}
|
|
3676
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalPermissionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3677
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalPermissionsService, providedIn: 'root' }); }
|
|
3678
|
+
}
|
|
3679
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalPermissionsService, decorators: [{
|
|
3680
|
+
type: Injectable,
|
|
3681
|
+
args: [{ providedIn: 'root' }]
|
|
3682
|
+
}], ctorParameters: () => [] });
|
|
3683
|
+
|
|
3684
|
+
class DevToolbarPermissionsToolComponent {
|
|
3685
|
+
constructor() {
|
|
3686
|
+
// Injects
|
|
3687
|
+
this.permissionsService = inject(DevToolbarInternalPermissionsService);
|
|
3688
|
+
// Signals
|
|
3689
|
+
this.activeFilter = signal('all');
|
|
3690
|
+
this.searchQuery = signal('');
|
|
3691
|
+
this.permissions = this.permissionsService.permissions;
|
|
3692
|
+
this.hasNoPermissions = computed(() => this.permissions().length === 0);
|
|
3693
|
+
this.filteredPermissions = computed(() => {
|
|
3694
|
+
return this.permissions().filter((permission) => {
|
|
3695
|
+
const searchTerm = this.searchQuery().toLowerCase();
|
|
3696
|
+
const permissionName = permission.name.toLowerCase();
|
|
3697
|
+
const permissionDescription = permission.description?.toLowerCase() ?? '';
|
|
3698
|
+
const matchesSearch = !this.searchQuery() ||
|
|
3699
|
+
permissionName.includes(searchTerm) ||
|
|
3700
|
+
permissionDescription.includes(searchTerm);
|
|
3701
|
+
const matchesFilter = this.activeFilter() === 'all' ||
|
|
3702
|
+
(this.activeFilter() === 'forced' && permission.isForced) ||
|
|
3703
|
+
(this.activeFilter() === 'granted' && permission.isGranted) ||
|
|
3704
|
+
(this.activeFilter() === 'denied' && !permission.isGranted);
|
|
3705
|
+
return matchesSearch && matchesFilter;
|
|
3706
|
+
});
|
|
3707
|
+
});
|
|
3708
|
+
this.hasNoFilteredPermissions = computed(() => this.filteredPermissions().length === 0);
|
|
3709
|
+
// Other properties
|
|
3710
|
+
this.options = {
|
|
3711
|
+
title: 'Permissions',
|
|
3712
|
+
description: 'Manage permission overrides for your current session',
|
|
3713
|
+
isClosable: true,
|
|
3714
|
+
size: 'tall',
|
|
3715
|
+
id: 'ndt-permissions',
|
|
3716
|
+
isBeta: true,
|
|
3717
|
+
};
|
|
3718
|
+
this.filterOptions = [
|
|
3719
|
+
{ value: 'all', label: 'All Permissions' },
|
|
3720
|
+
{ value: 'forced', label: 'Forced' },
|
|
3721
|
+
{ value: 'granted', label: 'Granted' },
|
|
3722
|
+
{ value: 'denied', label: 'Denied' },
|
|
3723
|
+
];
|
|
3724
|
+
this.permissionValueOptions = [
|
|
3725
|
+
{ value: 'not-forced', label: 'Not Forced' },
|
|
3726
|
+
{ value: 'denied', label: 'Forced Denied' },
|
|
3727
|
+
{ value: 'granted', label: 'Forced Granted' },
|
|
3728
|
+
];
|
|
3729
|
+
}
|
|
3730
|
+
// Public methods
|
|
3731
|
+
onFilterChange(value) {
|
|
3732
|
+
const filter = this.filterOptions.find((f) => f.value === value);
|
|
3733
|
+
if (filter) {
|
|
3734
|
+
this.activeFilter.set(filter.value);
|
|
3735
|
+
}
|
|
3736
|
+
}
|
|
3737
|
+
onPermissionChange(id, value) {
|
|
3738
|
+
switch (value) {
|
|
3739
|
+
case 'not-forced':
|
|
3740
|
+
this.permissionsService.removePermissionOverride(id);
|
|
3741
|
+
break;
|
|
3742
|
+
case 'granted':
|
|
3743
|
+
this.permissionsService.setPermission(id, true);
|
|
3744
|
+
break;
|
|
3745
|
+
case 'denied':
|
|
3746
|
+
this.permissionsService.setPermission(id, false);
|
|
3747
|
+
break;
|
|
3748
|
+
}
|
|
3749
|
+
}
|
|
3750
|
+
onSearchChange(query) {
|
|
3751
|
+
this.searchQuery.set(query);
|
|
3752
|
+
}
|
|
3753
|
+
// Protected methods
|
|
3754
|
+
getPermissionValue(permission) {
|
|
3755
|
+
if (!permission.isForced)
|
|
3756
|
+
return '';
|
|
3757
|
+
return permission.isGranted ? 'granted' : 'denied';
|
|
3758
|
+
}
|
|
3759
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPermissionsToolComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3760
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: DevToolbarPermissionsToolComponent, isStandalone: true, selector: "ndt-permissions-tool", ngImport: i0, template: `
|
|
3761
|
+
<ndt-toolbar-tool
|
|
3762
|
+
[options]="options"
|
|
3763
|
+
title="Permissions"
|
|
3764
|
+
icon="lock"
|
|
3765
|
+
>
|
|
3766
|
+
<div class="container">
|
|
3767
|
+
<div class="header">
|
|
3768
|
+
<ndt-input
|
|
3769
|
+
[value]="searchQuery()"
|
|
3770
|
+
(valueChange)="onSearchChange($event)"
|
|
3771
|
+
placeholder="Search permissions..."
|
|
3772
|
+
[ariaLabel]="'Search permissions'"
|
|
3773
|
+
/>
|
|
3774
|
+
<div class="filter-wrapper">
|
|
3775
|
+
<ndt-icon name="filter" class="filter-icon" />
|
|
3776
|
+
<ndt-select
|
|
3777
|
+
[value]="activeFilter()"
|
|
3778
|
+
[options]="filterOptions"
|
|
3779
|
+
[size]="'medium'"
|
|
3780
|
+
(valueChange)="onFilterChange($event)"
|
|
3781
|
+
[ariaLabel]="'Filter permissions by state'"
|
|
3782
|
+
/>
|
|
3783
|
+
</div>
|
|
3784
|
+
</div>
|
|
3785
|
+
|
|
3786
|
+
@if (hasNoPermissions()) {
|
|
3787
|
+
<div class="empty">
|
|
3788
|
+
<p>No permissions found</p>
|
|
3789
|
+
<p class="hint">Call setAvailableOptions() to configure permissions</p>
|
|
3790
|
+
</div>
|
|
3791
|
+
} @else if (hasNoFilteredPermissions()) {
|
|
3792
|
+
<div class="empty">
|
|
3793
|
+
<p>No permissions match your filter</p>
|
|
3794
|
+
</div>
|
|
3795
|
+
} @else {
|
|
3796
|
+
<div class="permission-list">
|
|
3797
|
+
@for (permission of filteredPermissions(); track permission.id) {
|
|
3798
|
+
<div class="permission">
|
|
3799
|
+
<div class="info">
|
|
3800
|
+
<h3>{{ permission.name }}</h3>
|
|
3801
|
+
<p>{{ permission?.description }}</p>
|
|
3802
|
+
</div>
|
|
3803
|
+
|
|
3804
|
+
<ndt-select
|
|
3805
|
+
[value]="getPermissionValue(permission)"
|
|
3806
|
+
[options]="permissionValueOptions"
|
|
3807
|
+
[ariaLabel]="'Override state for ' + permission.name"
|
|
3808
|
+
(valueChange)="onPermissionChange(permission.id, $event ?? '')"
|
|
3809
|
+
size="small"
|
|
3810
|
+
/>
|
|
3811
|
+
</div>
|
|
3812
|
+
}
|
|
3813
|
+
</div>
|
|
3814
|
+
}
|
|
3815
|
+
</div>
|
|
3816
|
+
</ndt-toolbar-tool>
|
|
3817
|
+
`, isInline: true, styles: [".container{display:flex;flex-direction:column;height:100%}.header{flex-shrink:0;display:flex;gap:var(--ndt-spacing-sm);margin-bottom:var(--ndt-spacing-md)}.header ndt-input{flex:1}.header .filter-wrapper{flex:0 0 auto;display:flex;align-items:center;gap:var(--ndt-spacing-md)}.header .filter-wrapper .filter-icon{width:18px;height:18px;flex-shrink:0;opacity:.6}.header .filter-wrapper ndt-select{flex:0 0 auto;min-width:180px}.empty{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;justify-content:center;align-items:center;border:1px solid var(--ndt-warning-border);border-radius:var(--ndt-border-radius-medium);padding:var(--ndt-spacing-md);background:var(--ndt-warning-background);color:var(--ndt-text-muted)}.empty p{margin:0}.empty .hint{font-size:var(--ndt-font-size-xs)}.permission-list{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;overflow-y:auto;padding-right:var(--ndt-spacing-sm);scrollbar-width:thin;scrollbar-color:var(--ndt-border-primary) var(--ndt-background-secondary)}.permission-list::-webkit-scrollbar{width:8px}.permission-list::-webkit-scrollbar-track{background:var(--ndt-background-secondary);border-radius:4px}.permission-list::-webkit-scrollbar-thumb{background:var(--ndt-border-primary);border-radius:4px}:is():hover{background:var(--ndt-hover-bg)}.permission{display:flex;flex-direction:row;gap:var(--ndt-spacing-sm);background:var(--ndt-background-secondary)}.permission .info{flex:0 0 65%}.permission .info h3{margin:0;font-size:var(--ndt-font-size-md);color:var(--ndt-text-primary)}.permission .info p{font-size:var(--ndt-font-size-xs);color:var(--ndt-text-muted)}.permission ndt-select{flex:0 0 35%}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "component", type: DevToolbarToolComponent, selector: "ndt-toolbar-tool", inputs: ["options", "icon", "title"] }, { kind: "component", type: DevToolbarInputComponent, selector: "ndt-input", inputs: ["value", "type", "placeholder", "ariaLabel", "inputClass"], outputs: ["valueChange"] }, { kind: "component", type: DevToolbarSelectComponent, selector: "ndt-select", inputs: ["value", "options", "ariaLabel", "label", "size"], outputs: ["valueChange"] }, { kind: "component", type: DevToolbarIconComponent, selector: "ndt-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3818
|
+
}
|
|
3819
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPermissionsToolComponent, decorators: [{
|
|
3820
|
+
type: Component,
|
|
3821
|
+
args: [{ selector: 'ndt-permissions-tool', standalone: true, imports: [
|
|
3822
|
+
FormsModule,
|
|
3823
|
+
DevToolbarToolComponent,
|
|
3824
|
+
DevToolbarInputComponent,
|
|
3825
|
+
DevToolbarSelectComponent,
|
|
3826
|
+
DevToolbarIconComponent,
|
|
3827
|
+
], template: `
|
|
3828
|
+
<ndt-toolbar-tool
|
|
3829
|
+
[options]="options"
|
|
3830
|
+
title="Permissions"
|
|
3831
|
+
icon="lock"
|
|
3832
|
+
>
|
|
3833
|
+
<div class="container">
|
|
3834
|
+
<div class="header">
|
|
3835
|
+
<ndt-input
|
|
3836
|
+
[value]="searchQuery()"
|
|
3837
|
+
(valueChange)="onSearchChange($event)"
|
|
3838
|
+
placeholder="Search permissions..."
|
|
3839
|
+
[ariaLabel]="'Search permissions'"
|
|
3840
|
+
/>
|
|
3841
|
+
<div class="filter-wrapper">
|
|
3842
|
+
<ndt-icon name="filter" class="filter-icon" />
|
|
3843
|
+
<ndt-select
|
|
3844
|
+
[value]="activeFilter()"
|
|
3845
|
+
[options]="filterOptions"
|
|
3846
|
+
[size]="'medium'"
|
|
3847
|
+
(valueChange)="onFilterChange($event)"
|
|
3848
|
+
[ariaLabel]="'Filter permissions by state'"
|
|
3849
|
+
/>
|
|
3850
|
+
</div>
|
|
3851
|
+
</div>
|
|
3852
|
+
|
|
3853
|
+
@if (hasNoPermissions()) {
|
|
3854
|
+
<div class="empty">
|
|
3855
|
+
<p>No permissions found</p>
|
|
3856
|
+
<p class="hint">Call setAvailableOptions() to configure permissions</p>
|
|
3857
|
+
</div>
|
|
3858
|
+
} @else if (hasNoFilteredPermissions()) {
|
|
3859
|
+
<div class="empty">
|
|
3860
|
+
<p>No permissions match your filter</p>
|
|
3861
|
+
</div>
|
|
3862
|
+
} @else {
|
|
3863
|
+
<div class="permission-list">
|
|
3864
|
+
@for (permission of filteredPermissions(); track permission.id) {
|
|
3865
|
+
<div class="permission">
|
|
3866
|
+
<div class="info">
|
|
3867
|
+
<h3>{{ permission.name }}</h3>
|
|
3868
|
+
<p>{{ permission?.description }}</p>
|
|
3869
|
+
</div>
|
|
3870
|
+
|
|
3871
|
+
<ndt-select
|
|
3872
|
+
[value]="getPermissionValue(permission)"
|
|
3873
|
+
[options]="permissionValueOptions"
|
|
3874
|
+
[ariaLabel]="'Override state for ' + permission.name"
|
|
3875
|
+
(valueChange)="onPermissionChange(permission.id, $event ?? '')"
|
|
3876
|
+
size="small"
|
|
3877
|
+
/>
|
|
3878
|
+
</div>
|
|
3879
|
+
}
|
|
3880
|
+
</div>
|
|
3881
|
+
}
|
|
3882
|
+
</div>
|
|
3883
|
+
</ndt-toolbar-tool>
|
|
3884
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".container{display:flex;flex-direction:column;height:100%}.header{flex-shrink:0;display:flex;gap:var(--ndt-spacing-sm);margin-bottom:var(--ndt-spacing-md)}.header ndt-input{flex:1}.header .filter-wrapper{flex:0 0 auto;display:flex;align-items:center;gap:var(--ndt-spacing-md)}.header .filter-wrapper .filter-icon{width:18px;height:18px;flex-shrink:0;opacity:.6}.header .filter-wrapper ndt-select{flex:0 0 auto;min-width:180px}.empty{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;justify-content:center;align-items:center;border:1px solid var(--ndt-warning-border);border-radius:var(--ndt-border-radius-medium);padding:var(--ndt-spacing-md);background:var(--ndt-warning-background);color:var(--ndt-text-muted)}.empty p{margin:0}.empty .hint{font-size:var(--ndt-font-size-xs)}.permission-list{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;overflow-y:auto;padding-right:var(--ndt-spacing-sm);scrollbar-width:thin;scrollbar-color:var(--ndt-border-primary) var(--ndt-background-secondary)}.permission-list::-webkit-scrollbar{width:8px}.permission-list::-webkit-scrollbar-track{background:var(--ndt-background-secondary);border-radius:4px}.permission-list::-webkit-scrollbar-thumb{background:var(--ndt-border-primary);border-radius:4px}:is():hover{background:var(--ndt-hover-bg)}.permission{display:flex;flex-direction:row;gap:var(--ndt-spacing-sm);background:var(--ndt-background-secondary)}.permission .info{flex:0 0 65%}.permission .info h3{margin:0;font-size:var(--ndt-font-size-md);color:var(--ndt-text-primary)}.permission .info p{font-size:var(--ndt-font-size-xs);color:var(--ndt-text-muted)}.permission ndt-select{flex:0 0 35%}\n"] }]
|
|
3885
|
+
}] });
|
|
3886
|
+
|
|
3887
|
+
/**
|
|
3888
|
+
* Internal service for managing presets state.
|
|
3889
|
+
* Handles CRUD operations, captures current toolbar config, and applies presets.
|
|
3890
|
+
*/
|
|
3891
|
+
class DevToolbarInternalPresetsService {
|
|
3892
|
+
constructor() {
|
|
3893
|
+
this.STORAGE_KEY = 'presets';
|
|
3894
|
+
this.storageService = inject(DevToolsStorageService);
|
|
3895
|
+
// Inject all other tool internal services (for reading/writing state)
|
|
3896
|
+
this.featureFlagsService = inject(DevToolbarInternalFeatureFlagService);
|
|
3897
|
+
this.languageService = inject(DevToolbarInternalLanguageService);
|
|
3898
|
+
this.permissionsService = inject(DevToolbarInternalPermissionsService);
|
|
3899
|
+
this.appFeaturesService = inject(DevToolbarInternalAppFeaturesService);
|
|
3900
|
+
this.presetsSubject = new BehaviorSubject([]);
|
|
3901
|
+
this.presets$ = this.presetsSubject.asObservable();
|
|
3902
|
+
this.presets = toSignal(this.presets$, { initialValue: [] });
|
|
3903
|
+
this.loadPresets();
|
|
3904
|
+
}
|
|
3905
|
+
/**
|
|
3906
|
+
* Capture current toolbar state as a new preset
|
|
3907
|
+
*/
|
|
3908
|
+
saveCurrentAsPreset(name, description) {
|
|
3909
|
+
const preset = {
|
|
3910
|
+
id: this.generateId(),
|
|
3911
|
+
name,
|
|
3912
|
+
description,
|
|
3913
|
+
createdAt: new Date().toISOString(),
|
|
3914
|
+
updatedAt: new Date().toISOString(),
|
|
3915
|
+
config: this.captureCurrentConfig(),
|
|
3916
|
+
};
|
|
3917
|
+
const presets = [...this.presetsSubject.value, preset];
|
|
3918
|
+
this.presetsSubject.next(presets);
|
|
3919
|
+
this.storageService.set(this.STORAGE_KEY, presets);
|
|
3920
|
+
return preset;
|
|
3921
|
+
}
|
|
3922
|
+
/**
|
|
3923
|
+
* Apply a preset to all tools (THIS IS THE KEY METHOD)
|
|
3924
|
+
*/
|
|
3925
|
+
async applyPreset(presetId) {
|
|
3926
|
+
const preset = this.presetsSubject.value.find((p) => p.id === presetId);
|
|
3927
|
+
if (!preset)
|
|
3928
|
+
return;
|
|
3929
|
+
// Apply to each tool's internal service
|
|
3930
|
+
this.featureFlagsService.applyPresetFlags(preset.config.featureFlags);
|
|
3931
|
+
await this.languageService.applyPresetLanguage(preset.config.language);
|
|
3932
|
+
this.permissionsService.applyPresetPermissions(preset.config.permissions);
|
|
3933
|
+
this.appFeaturesService.applyForcedState(preset.config.appFeatures);
|
|
3934
|
+
}
|
|
3935
|
+
/**
|
|
3936
|
+
* Update an existing preset with current toolbar state
|
|
3937
|
+
*/
|
|
3938
|
+
updatePreset(presetId) {
|
|
3939
|
+
const presets = this.presetsSubject.value.map((preset) => {
|
|
3940
|
+
if (preset.id === presetId) {
|
|
3941
|
+
return {
|
|
3942
|
+
...preset,
|
|
3943
|
+
updatedAt: new Date().toISOString(),
|
|
3944
|
+
config: this.captureCurrentConfig(),
|
|
3945
|
+
};
|
|
3946
|
+
}
|
|
3947
|
+
return preset;
|
|
3948
|
+
});
|
|
3949
|
+
this.presetsSubject.next(presets);
|
|
3950
|
+
this.storageService.set(this.STORAGE_KEY, presets);
|
|
3951
|
+
}
|
|
3952
|
+
/**
|
|
3953
|
+
* Delete a preset
|
|
3954
|
+
*/
|
|
3955
|
+
deletePreset(presetId) {
|
|
3956
|
+
const presets = this.presetsSubject.value.filter((p) => p.id !== presetId);
|
|
3957
|
+
this.presetsSubject.next(presets);
|
|
3958
|
+
this.storageService.set(this.STORAGE_KEY, presets);
|
|
3959
|
+
}
|
|
3960
|
+
/**
|
|
3961
|
+
* Add a preset (used for import)
|
|
3962
|
+
*/
|
|
3963
|
+
addPreset(preset) {
|
|
3964
|
+
// Generate new ID to avoid conflicts
|
|
3965
|
+
const newPreset = {
|
|
3966
|
+
...preset,
|
|
3967
|
+
id: this.generateId(),
|
|
3968
|
+
createdAt: new Date().toISOString(),
|
|
3969
|
+
updatedAt: new Date().toISOString(),
|
|
3970
|
+
};
|
|
3971
|
+
const presets = [...this.presetsSubject.value, newPreset];
|
|
3972
|
+
this.presetsSubject.next(presets);
|
|
3973
|
+
this.storageService.set(this.STORAGE_KEY, presets);
|
|
3974
|
+
return newPreset;
|
|
3975
|
+
}
|
|
3976
|
+
/**
|
|
3977
|
+
* Get a preset by ID
|
|
3978
|
+
*/
|
|
3979
|
+
getPresetById(presetId) {
|
|
3980
|
+
return this.presetsSubject.value.find((p) => p.id === presetId);
|
|
3981
|
+
}
|
|
3982
|
+
/**
|
|
3983
|
+
* Capture current configuration from all tools
|
|
3984
|
+
*/
|
|
3985
|
+
captureCurrentConfig() {
|
|
3986
|
+
return {
|
|
3987
|
+
featureFlags: this.featureFlagsService.getCurrentForcedState(),
|
|
3988
|
+
language: this.languageService.getCurrentForcedLanguage(),
|
|
3989
|
+
permissions: this.permissionsService.getCurrentForcedState(),
|
|
3990
|
+
appFeatures: this.appFeaturesService.getCurrentForcedState(),
|
|
3991
|
+
};
|
|
3992
|
+
}
|
|
3993
|
+
/**
|
|
3994
|
+
* Load presets from localStorage
|
|
3995
|
+
*/
|
|
3996
|
+
loadPresets() {
|
|
3997
|
+
try {
|
|
3998
|
+
const saved = this.storageService.get(this.STORAGE_KEY);
|
|
3999
|
+
if (saved && Array.isArray(saved)) {
|
|
4000
|
+
this.presetsSubject.next(saved);
|
|
4001
|
+
}
|
|
4002
|
+
}
|
|
4003
|
+
catch (error) {
|
|
4004
|
+
console.error('Failed to load presets from localStorage:', error);
|
|
4005
|
+
}
|
|
4006
|
+
}
|
|
4007
|
+
/**
|
|
4008
|
+
* Generate unique preset ID
|
|
4009
|
+
*/
|
|
4010
|
+
generateId() {
|
|
4011
|
+
return `preset-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
|
|
4012
|
+
}
|
|
4013
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalPresetsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4014
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalPresetsService, providedIn: 'root' }); }
|
|
4015
|
+
}
|
|
4016
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalPresetsService, decorators: [{
|
|
4017
|
+
type: Injectable,
|
|
4018
|
+
args: [{ providedIn: 'root' }]
|
|
4019
|
+
}], ctorParameters: () => [] });
|
|
4020
|
+
|
|
4021
|
+
class DevToolbarPresetsToolComponent {
|
|
4022
|
+
constructor() {
|
|
4023
|
+
// Injects
|
|
4024
|
+
this.presetsService = inject(DevToolbarInternalPresetsService);
|
|
4025
|
+
this.featureFlagsService = inject(DevToolbarInternalFeatureFlagService);
|
|
4026
|
+
this.permissionsService = inject(DevToolbarInternalPermissionsService);
|
|
4027
|
+
this.appFeaturesService = inject(DevToolbarInternalAppFeaturesService);
|
|
4028
|
+
this.languageService = inject(DevToolbarInternalLanguageService);
|
|
4029
|
+
// Signals
|
|
4030
|
+
this.viewMode = signal('list');
|
|
4031
|
+
this.searchQuery = signal('');
|
|
4032
|
+
this.presetName = signal('');
|
|
4033
|
+
this.presetDescription = signal('');
|
|
4034
|
+
this.presets = this.presetsService.presets;
|
|
4035
|
+
this.filteredPresets = computed(() => {
|
|
4036
|
+
const query = this.searchQuery().toLowerCase();
|
|
4037
|
+
return this.presets().filter((preset) => preset.name.toLowerCase().includes(query) ||
|
|
4038
|
+
preset.description?.toLowerCase().includes(query));
|
|
4039
|
+
});
|
|
4040
|
+
this.hasNoPresets = computed(() => this.presets().length === 0);
|
|
4041
|
+
this.hasNoFilteredPresets = computed(() => this.filteredPresets().length === 0);
|
|
4042
|
+
// Other properties
|
|
4043
|
+
this.options = {
|
|
4044
|
+
title: 'Presets',
|
|
4045
|
+
description: 'Save and load toolbar configurations',
|
|
4046
|
+
isClosable: true,
|
|
4047
|
+
size: 'tall',
|
|
4048
|
+
id: 'ndt-presets',
|
|
4049
|
+
isBeta: true,
|
|
4050
|
+
};
|
|
4051
|
+
}
|
|
4052
|
+
// Public methods
|
|
4053
|
+
onSearchChange(query) {
|
|
4054
|
+
this.searchQuery.set(query);
|
|
4055
|
+
}
|
|
4056
|
+
onSwitchToCreateMode() {
|
|
4057
|
+
this.viewMode.set('create');
|
|
4058
|
+
this.presetName.set('');
|
|
4059
|
+
this.presetDescription.set('');
|
|
4060
|
+
}
|
|
4061
|
+
onSwitchToListMode() {
|
|
4062
|
+
this.viewMode.set('list');
|
|
4063
|
+
}
|
|
4064
|
+
onSavePreset(event) {
|
|
4065
|
+
event.preventDefault();
|
|
4066
|
+
if (!this.presetName())
|
|
4067
|
+
return;
|
|
4068
|
+
this.presetsService.saveCurrentAsPreset(this.presetName(), this.presetDescription());
|
|
4069
|
+
this.onSwitchToListMode();
|
|
4070
|
+
}
|
|
4071
|
+
onApplyPreset(presetId) {
|
|
4072
|
+
this.presetsService.applyPreset(presetId);
|
|
4073
|
+
}
|
|
4074
|
+
onUpdatePreset(presetId) {
|
|
4075
|
+
this.presetsService.updatePreset(presetId);
|
|
4076
|
+
}
|
|
4077
|
+
onExportPreset(presetId) {
|
|
4078
|
+
const preset = this.presets().find((p) => p.id === presetId);
|
|
4079
|
+
if (!preset)
|
|
4080
|
+
return;
|
|
4081
|
+
const json = JSON.stringify(preset, null, 2);
|
|
4082
|
+
const blob = new Blob([json], { type: 'application/json' });
|
|
4083
|
+
const url = URL.createObjectURL(blob);
|
|
4084
|
+
const link = document.createElement('a');
|
|
4085
|
+
link.href = url;
|
|
4086
|
+
link.download = `preset-${preset.name.toLowerCase().replace(/\s+/g, '-')}.json`;
|
|
4087
|
+
link.click();
|
|
4088
|
+
URL.revokeObjectURL(url);
|
|
4089
|
+
}
|
|
4090
|
+
onDeletePreset(presetId) {
|
|
4091
|
+
if (confirm('Are you sure you want to delete this preset?')) {
|
|
4092
|
+
this.presetsService.deletePreset(presetId);
|
|
4093
|
+
}
|
|
4094
|
+
}
|
|
4095
|
+
// Protected methods
|
|
4096
|
+
getCurrentFlagsCount() {
|
|
4097
|
+
const state = this.featureFlagsService.getCurrentForcedState();
|
|
4098
|
+
return state.enabled.length + state.disabled.length;
|
|
4099
|
+
}
|
|
4100
|
+
getCurrentPermissionsCount() {
|
|
4101
|
+
const state = this.permissionsService.getCurrentForcedState();
|
|
4102
|
+
return state.granted.length + state.denied.length;
|
|
4103
|
+
}
|
|
4104
|
+
getCurrentAppFeaturesCount() {
|
|
4105
|
+
const state = this.appFeaturesService.getCurrentForcedState();
|
|
4106
|
+
return state.enabled.length + state.disabled.length;
|
|
4107
|
+
}
|
|
4108
|
+
getCurrentLanguage() {
|
|
4109
|
+
return this.languageService.getCurrentForcedLanguage() || 'Not Forced';
|
|
4110
|
+
}
|
|
4111
|
+
formatDate(isoString) {
|
|
4112
|
+
return new Date(isoString).toLocaleDateString();
|
|
4113
|
+
}
|
|
4114
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPresetsToolComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4115
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: DevToolbarPresetsToolComponent, isStandalone: true, selector: "ndt-presets-tool", ngImport: i0, template: `
|
|
4116
|
+
<ndt-toolbar-tool [options]="options" title="Presets" icon="layout">
|
|
4117
|
+
<div class="container">
|
|
4118
|
+
<!-- Mode Toggle -->
|
|
4119
|
+
@if (!hasNoPresets() || viewMode() === 'create') {
|
|
4120
|
+
<div class="header">
|
|
4121
|
+
@if (viewMode() === 'list') {
|
|
4122
|
+
<ndt-input
|
|
4123
|
+
[value]="searchQuery()"
|
|
4124
|
+
(valueChange)="onSearchChange($event)"
|
|
4125
|
+
placeholder="Search presets..."
|
|
4126
|
+
[ariaLabel]="'Search presets'"
|
|
4127
|
+
/>
|
|
4128
|
+
<ndt-button
|
|
4129
|
+
(click)="onSwitchToCreateMode()"
|
|
4130
|
+
[ariaLabel]="'Create new preset'"
|
|
4131
|
+
>
|
|
4132
|
+
New Preset
|
|
4133
|
+
</ndt-button>
|
|
4134
|
+
} @else {
|
|
4135
|
+
<ndt-button
|
|
4136
|
+
(click)="onSwitchToListMode()"
|
|
4137
|
+
[ariaLabel]="'Back to list'"
|
|
4138
|
+
>
|
|
4139
|
+
← Back to List
|
|
4140
|
+
</ndt-button>
|
|
4141
|
+
}
|
|
4142
|
+
</div>
|
|
4143
|
+
}
|
|
4144
|
+
|
|
4145
|
+
<!-- Create Form -->
|
|
4146
|
+
@if (viewMode() === 'create') {
|
|
4147
|
+
<form (submit)="onSavePreset($event)" class="preset-form">
|
|
4148
|
+
<ndt-input
|
|
4149
|
+
label="Preset Name"
|
|
4150
|
+
[value]="presetName()"
|
|
4151
|
+
(valueChange)="presetName.set($event)"
|
|
4152
|
+
placeholder="e.g., Admin User - Full Access"
|
|
4153
|
+
[ariaLabel]="'Preset name'"
|
|
4154
|
+
/>
|
|
4155
|
+
<ndt-input
|
|
4156
|
+
label="Description (optional)"
|
|
4157
|
+
[value]="presetDescription()"
|
|
4158
|
+
(valueChange)="presetDescription.set($event)"
|
|
4159
|
+
placeholder="Brief description of this preset"
|
|
4160
|
+
[ariaLabel]="'Preset description'"
|
|
4161
|
+
/>
|
|
4162
|
+
|
|
4163
|
+
<!-- Summary of what will be saved -->
|
|
4164
|
+
<div class="preset-summary">
|
|
4165
|
+
<h4>Configuration to Save:</h4>
|
|
4166
|
+
<ul>
|
|
4167
|
+
<li>Feature Flags: {{ getCurrentFlagsCount() }} forced</li>
|
|
4168
|
+
<li>Permissions: {{ getCurrentPermissionsCount() }} forced</li>
|
|
4169
|
+
<li>App Features: {{ getCurrentAppFeaturesCount() }} forced</li>
|
|
4170
|
+
<li>Language: {{ getCurrentLanguage() }}</li>
|
|
4171
|
+
</ul>
|
|
4172
|
+
</div>
|
|
4173
|
+
|
|
4174
|
+
<div class="form-actions">
|
|
4175
|
+
<ndt-button type="submit">Save Preset</ndt-button>
|
|
4176
|
+
</div>
|
|
4177
|
+
</form>
|
|
4178
|
+
}
|
|
4179
|
+
|
|
4180
|
+
<!-- Empty State -->
|
|
4181
|
+
@if (viewMode() === 'list' && hasNoPresets()) {
|
|
4182
|
+
<div class="empty">
|
|
4183
|
+
<p>No presets saved yet</p>
|
|
4184
|
+
<p class="hint">
|
|
4185
|
+
Save the current toolbar configuration as a preset for quick access
|
|
4186
|
+
</p>
|
|
4187
|
+
<ndt-button (click)="onSwitchToCreateMode()">
|
|
4188
|
+
Create Your First Preset
|
|
4189
|
+
</ndt-button>
|
|
4190
|
+
</div>
|
|
4191
|
+
} @else if (viewMode() === 'list' && hasNoFilteredPresets()) {
|
|
4192
|
+
<div class="empty">
|
|
4193
|
+
<p>No presets match your search</p>
|
|
4194
|
+
</div>
|
|
4195
|
+
} @else if (viewMode() === 'list') {
|
|
4196
|
+
<!-- Preset List -->
|
|
4197
|
+
<div class="preset-list">
|
|
4198
|
+
@for (preset of filteredPresets(); track preset.id) {
|
|
4199
|
+
<div class="preset-card">
|
|
4200
|
+
<div class="preset-card__header">
|
|
4201
|
+
<h3>{{ preset.name }}</h3>
|
|
4202
|
+
<div class="preset-card__actions">
|
|
4203
|
+
<button
|
|
4204
|
+
class="icon-button"
|
|
4205
|
+
(click)="onApplyPreset(preset.id)"
|
|
4206
|
+
[attr.aria-label]="'Apply preset ' + preset.name"
|
|
4207
|
+
title="Apply preset"
|
|
4208
|
+
>
|
|
4209
|
+
<ndt-icon name="refresh" />
|
|
4210
|
+
</button>
|
|
4211
|
+
<button
|
|
4212
|
+
class="icon-button"
|
|
4213
|
+
(click)="onUpdatePreset(preset.id)"
|
|
4214
|
+
[attr.aria-label]="'Update preset ' + preset.name"
|
|
4215
|
+
title="Update with current state"
|
|
4216
|
+
>
|
|
4217
|
+
<ndt-icon name="gear" />
|
|
4218
|
+
</button>
|
|
4219
|
+
<button
|
|
4220
|
+
class="icon-button"
|
|
4221
|
+
(click)="onExportPreset(preset.id)"
|
|
4222
|
+
[attr.aria-label]="'Export preset ' + preset.name"
|
|
4223
|
+
title="Export as JSON"
|
|
4224
|
+
>
|
|
4225
|
+
<ndt-icon name="export" />
|
|
4226
|
+
</button>
|
|
4227
|
+
<button
|
|
4228
|
+
class="icon-button"
|
|
4229
|
+
(click)="onDeletePreset(preset.id)"
|
|
4230
|
+
[attr.aria-label]="'Delete preset ' + preset.name"
|
|
4231
|
+
title="Delete preset"
|
|
4232
|
+
>
|
|
4233
|
+
<ndt-icon name="trash" />
|
|
4234
|
+
</button>
|
|
4235
|
+
</div>
|
|
4236
|
+
</div>
|
|
4237
|
+
@if (preset.description) {
|
|
4238
|
+
<p class="preset-card__description">{{ preset.description }}</p>
|
|
4239
|
+
}
|
|
4240
|
+
<div class="preset-card__meta">
|
|
4241
|
+
<span>Updated: {{ formatDate(preset.updatedAt) }}</span>
|
|
4242
|
+
</div>
|
|
4243
|
+
<!-- Preview of preset config -->
|
|
4244
|
+
<div class="preset-card__preview">
|
|
4245
|
+
@if (preset.config.featureFlags.enabled.length > 0 ||
|
|
4246
|
+
preset.config.featureFlags.disabled.length > 0) {
|
|
4247
|
+
<span class="badge">
|
|
4248
|
+
{{
|
|
4249
|
+
preset.config.featureFlags.enabled.length +
|
|
4250
|
+
preset.config.featureFlags.disabled.length
|
|
4251
|
+
}}
|
|
4252
|
+
flags
|
|
4253
|
+
</span>
|
|
4254
|
+
} @if (preset.config.permissions.granted.length > 0 ||
|
|
4255
|
+
preset.config.permissions.denied.length > 0) {
|
|
4256
|
+
<span class="badge">
|
|
4257
|
+
{{
|
|
4258
|
+
preset.config.permissions.granted.length +
|
|
4259
|
+
preset.config.permissions.denied.length
|
|
4260
|
+
}}
|
|
4261
|
+
perms
|
|
4262
|
+
</span>
|
|
4263
|
+
} @if (preset.config.appFeatures.enabled.length > 0 ||
|
|
4264
|
+
preset.config.appFeatures.disabled.length > 0) {
|
|
4265
|
+
<span class="badge">
|
|
4266
|
+
{{
|
|
4267
|
+
preset.config.appFeatures.enabled.length +
|
|
4268
|
+
preset.config.appFeatures.disabled.length
|
|
4269
|
+
}}
|
|
4270
|
+
features
|
|
4271
|
+
</span>
|
|
4272
|
+
} @if (preset.config.language) {
|
|
4273
|
+
<span class="badge">{{ preset.config.language }}</span>
|
|
4274
|
+
}
|
|
4275
|
+
</div>
|
|
4276
|
+
</div>
|
|
4277
|
+
}
|
|
4278
|
+
</div>
|
|
4279
|
+
}
|
|
4280
|
+
</div>
|
|
4281
|
+
</ndt-toolbar-tool>
|
|
4282
|
+
`, isInline: true, styles: [".container{display:flex;flex-direction:column;height:100%}.header{flex-shrink:0;display:flex;gap:var(--ndt-spacing-sm);margin-bottom:var(--ndt-spacing-md)}.header ndt-input{flex:1}.header ndt-button{flex-shrink:0}.empty{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;justify-content:center;align-items:center;border:1px solid var(--ndt-border-subtle);border-radius:var(--ndt-border-radius-medium);padding:var(--ndt-spacing-md);background:transparent;color:var(--ndt-text-muted);text-align:center}.empty p{margin:0}.empty .hint{font-size:var(--ndt-font-size-xs)}.preset-list{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;overflow-y:auto;padding-right:var(--ndt-spacing-sm);scrollbar-width:thin;scrollbar-color:var(--ndt-border-primary) var(--ndt-background-secondary)}.preset-list::-webkit-scrollbar{width:8px}.preset-list::-webkit-scrollbar-track{background:var(--ndt-background-secondary);border-radius:4px}.preset-list::-webkit-scrollbar-thumb{background:var(--ndt-border-primary);border-radius:4px}:is():hover{background:var(--ndt-hover-bg)}.preset-card{background:var(--ndt-background-secondary);padding:var(--ndt-spacing-md);border-radius:var(--ndt-border-radius-medium);display:flex;flex-direction:column;gap:var(--ndt-spacing-sm)}.preset-card__header{display:flex;justify-content:space-between;align-items:center;gap:var(--ndt-spacing-sm)}.preset-card__header h3{margin:0;font-size:var(--ndt-font-size-md);color:var(--ndt-text-primary);flex:1}.preset-card__actions{display:flex;gap:var(--ndt-spacing-xs)}.icon-button{background:transparent;border:none;cursor:pointer;padding:var(--ndt-spacing-xs);border-radius:var(--ndt-border-radius-small);color:var(--ndt-text-secondary);display:flex;align-items:center;justify-content:center}.icon-button:hover{background:var(--ndt-hover-bg);color:var(--ndt-text-primary)}.icon-button ndt-icon{width:16px;height:16px}.preset-card__description{margin:0;font-size:var(--ndt-font-size-sm);color:var(--ndt-text-secondary)}.preset-card__meta{font-size:var(--ndt-font-size-xs);color:var(--ndt-text-muted)}.preset-card__meta span{margin-right:var(--ndt-spacing-sm)}.preset-card__preview{display:flex;gap:var(--ndt-spacing-xs);flex-wrap:wrap}.badge{background:var(--ndt-primary-color);color:#fff;padding:2px 8px;border-radius:12px;font-size:var(--ndt-font-size-xs);font-weight:500}.preset-form{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:var(--ndt-spacing-md);padding:var(--ndt-spacing-md)}.preset-form ndt-input{width:100%}.preset-summary{background:var(--ndt-background-secondary);padding:var(--ndt-spacing-md);border-radius:var(--ndt-border-radius-medium)}.preset-summary h4{margin:0 0 var(--ndt-spacing-sm) 0;font-size:var(--ndt-font-size-sm);color:var(--ndt-text-primary)}.preset-summary ul{margin:0;padding-left:var(--ndt-spacing-md);color:var(--ndt-text-secondary);font-size:var(--ndt-font-size-sm)}.preset-summary ul li{margin-bottom:var(--ndt-spacing-xs)}.form-actions{display:flex;justify-content:flex-end;gap:var(--ndt-spacing-sm)}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.NgForm, selector: "form:not([ngNoForm]):not([formGroup]),ng-form,[ngForm]", inputs: ["ngFormOptions"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "component", type: DevToolbarToolComponent, selector: "ndt-toolbar-tool", inputs: ["options", "icon", "title"] }, { kind: "component", type: DevToolbarInputComponent, selector: "ndt-input", inputs: ["value", "type", "placeholder", "ariaLabel", "inputClass"], outputs: ["valueChange"] }, { kind: "component", type: DevToolbarButtonComponent, selector: "ndt-button", inputs: ["type", "variant", "icon", "label", "ariaLabel", "isActive"] }, { kind: "component", type: DevToolbarIconComponent, selector: "ndt-icon", inputs: ["name"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
4283
|
+
}
|
|
4284
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPresetsToolComponent, decorators: [{
|
|
4285
|
+
type: Component,
|
|
4286
|
+
args: [{ selector: 'ndt-presets-tool', standalone: true, imports: [
|
|
4287
|
+
FormsModule,
|
|
4288
|
+
DevToolbarToolComponent,
|
|
4289
|
+
DevToolbarInputComponent,
|
|
4290
|
+
DevToolbarButtonComponent,
|
|
4291
|
+
DevToolbarIconComponent,
|
|
4292
|
+
DevToolbarWindowComponent,
|
|
4293
|
+
], template: `
|
|
4294
|
+
<ndt-toolbar-tool [options]="options" title="Presets" icon="layout">
|
|
4295
|
+
<div class="container">
|
|
4296
|
+
<!-- Mode Toggle -->
|
|
4297
|
+
@if (!hasNoPresets() || viewMode() === 'create') {
|
|
4298
|
+
<div class="header">
|
|
4299
|
+
@if (viewMode() === 'list') {
|
|
4300
|
+
<ndt-input
|
|
4301
|
+
[value]="searchQuery()"
|
|
4302
|
+
(valueChange)="onSearchChange($event)"
|
|
4303
|
+
placeholder="Search presets..."
|
|
4304
|
+
[ariaLabel]="'Search presets'"
|
|
4305
|
+
/>
|
|
4306
|
+
<ndt-button
|
|
4307
|
+
(click)="onSwitchToCreateMode()"
|
|
4308
|
+
[ariaLabel]="'Create new preset'"
|
|
4309
|
+
>
|
|
4310
|
+
New Preset
|
|
4311
|
+
</ndt-button>
|
|
4312
|
+
} @else {
|
|
4313
|
+
<ndt-button
|
|
4314
|
+
(click)="onSwitchToListMode()"
|
|
4315
|
+
[ariaLabel]="'Back to list'"
|
|
4316
|
+
>
|
|
4317
|
+
← Back to List
|
|
4318
|
+
</ndt-button>
|
|
4319
|
+
}
|
|
4320
|
+
</div>
|
|
4321
|
+
}
|
|
4322
|
+
|
|
4323
|
+
<!-- Create Form -->
|
|
4324
|
+
@if (viewMode() === 'create') {
|
|
4325
|
+
<form (submit)="onSavePreset($event)" class="preset-form">
|
|
4326
|
+
<ndt-input
|
|
4327
|
+
label="Preset Name"
|
|
4328
|
+
[value]="presetName()"
|
|
4329
|
+
(valueChange)="presetName.set($event)"
|
|
4330
|
+
placeholder="e.g., Admin User - Full Access"
|
|
4331
|
+
[ariaLabel]="'Preset name'"
|
|
4332
|
+
/>
|
|
4333
|
+
<ndt-input
|
|
4334
|
+
label="Description (optional)"
|
|
4335
|
+
[value]="presetDescription()"
|
|
4336
|
+
(valueChange)="presetDescription.set($event)"
|
|
4337
|
+
placeholder="Brief description of this preset"
|
|
4338
|
+
[ariaLabel]="'Preset description'"
|
|
4339
|
+
/>
|
|
4340
|
+
|
|
4341
|
+
<!-- Summary of what will be saved -->
|
|
4342
|
+
<div class="preset-summary">
|
|
4343
|
+
<h4>Configuration to Save:</h4>
|
|
4344
|
+
<ul>
|
|
4345
|
+
<li>Feature Flags: {{ getCurrentFlagsCount() }} forced</li>
|
|
4346
|
+
<li>Permissions: {{ getCurrentPermissionsCount() }} forced</li>
|
|
4347
|
+
<li>App Features: {{ getCurrentAppFeaturesCount() }} forced</li>
|
|
4348
|
+
<li>Language: {{ getCurrentLanguage() }}</li>
|
|
4349
|
+
</ul>
|
|
4350
|
+
</div>
|
|
4351
|
+
|
|
4352
|
+
<div class="form-actions">
|
|
4353
|
+
<ndt-button type="submit">Save Preset</ndt-button>
|
|
4354
|
+
</div>
|
|
4355
|
+
</form>
|
|
4356
|
+
}
|
|
4357
|
+
|
|
4358
|
+
<!-- Empty State -->
|
|
4359
|
+
@if (viewMode() === 'list' && hasNoPresets()) {
|
|
4360
|
+
<div class="empty">
|
|
4361
|
+
<p>No presets saved yet</p>
|
|
4362
|
+
<p class="hint">
|
|
4363
|
+
Save the current toolbar configuration as a preset for quick access
|
|
4364
|
+
</p>
|
|
4365
|
+
<ndt-button (click)="onSwitchToCreateMode()">
|
|
4366
|
+
Create Your First Preset
|
|
4367
|
+
</ndt-button>
|
|
4368
|
+
</div>
|
|
4369
|
+
} @else if (viewMode() === 'list' && hasNoFilteredPresets()) {
|
|
4370
|
+
<div class="empty">
|
|
4371
|
+
<p>No presets match your search</p>
|
|
4372
|
+
</div>
|
|
4373
|
+
} @else if (viewMode() === 'list') {
|
|
4374
|
+
<!-- Preset List -->
|
|
4375
|
+
<div class="preset-list">
|
|
4376
|
+
@for (preset of filteredPresets(); track preset.id) {
|
|
4377
|
+
<div class="preset-card">
|
|
4378
|
+
<div class="preset-card__header">
|
|
4379
|
+
<h3>{{ preset.name }}</h3>
|
|
4380
|
+
<div class="preset-card__actions">
|
|
4381
|
+
<button
|
|
4382
|
+
class="icon-button"
|
|
4383
|
+
(click)="onApplyPreset(preset.id)"
|
|
4384
|
+
[attr.aria-label]="'Apply preset ' + preset.name"
|
|
4385
|
+
title="Apply preset"
|
|
4386
|
+
>
|
|
4387
|
+
<ndt-icon name="refresh" />
|
|
4388
|
+
</button>
|
|
4389
|
+
<button
|
|
4390
|
+
class="icon-button"
|
|
4391
|
+
(click)="onUpdatePreset(preset.id)"
|
|
4392
|
+
[attr.aria-label]="'Update preset ' + preset.name"
|
|
4393
|
+
title="Update with current state"
|
|
4394
|
+
>
|
|
4395
|
+
<ndt-icon name="gear" />
|
|
4396
|
+
</button>
|
|
4397
|
+
<button
|
|
4398
|
+
class="icon-button"
|
|
4399
|
+
(click)="onExportPreset(preset.id)"
|
|
4400
|
+
[attr.aria-label]="'Export preset ' + preset.name"
|
|
4401
|
+
title="Export as JSON"
|
|
4402
|
+
>
|
|
4403
|
+
<ndt-icon name="export" />
|
|
4404
|
+
</button>
|
|
4405
|
+
<button
|
|
4406
|
+
class="icon-button"
|
|
4407
|
+
(click)="onDeletePreset(preset.id)"
|
|
4408
|
+
[attr.aria-label]="'Delete preset ' + preset.name"
|
|
4409
|
+
title="Delete preset"
|
|
4410
|
+
>
|
|
4411
|
+
<ndt-icon name="trash" />
|
|
4412
|
+
</button>
|
|
4413
|
+
</div>
|
|
4414
|
+
</div>
|
|
4415
|
+
@if (preset.description) {
|
|
4416
|
+
<p class="preset-card__description">{{ preset.description }}</p>
|
|
4417
|
+
}
|
|
4418
|
+
<div class="preset-card__meta">
|
|
4419
|
+
<span>Updated: {{ formatDate(preset.updatedAt) }}</span>
|
|
4420
|
+
</div>
|
|
4421
|
+
<!-- Preview of preset config -->
|
|
4422
|
+
<div class="preset-card__preview">
|
|
4423
|
+
@if (preset.config.featureFlags.enabled.length > 0 ||
|
|
4424
|
+
preset.config.featureFlags.disabled.length > 0) {
|
|
4425
|
+
<span class="badge">
|
|
4426
|
+
{{
|
|
4427
|
+
preset.config.featureFlags.enabled.length +
|
|
4428
|
+
preset.config.featureFlags.disabled.length
|
|
4429
|
+
}}
|
|
4430
|
+
flags
|
|
4431
|
+
</span>
|
|
4432
|
+
} @if (preset.config.permissions.granted.length > 0 ||
|
|
4433
|
+
preset.config.permissions.denied.length > 0) {
|
|
4434
|
+
<span class="badge">
|
|
4435
|
+
{{
|
|
4436
|
+
preset.config.permissions.granted.length +
|
|
4437
|
+
preset.config.permissions.denied.length
|
|
4438
|
+
}}
|
|
4439
|
+
perms
|
|
4440
|
+
</span>
|
|
4441
|
+
} @if (preset.config.appFeatures.enabled.length > 0 ||
|
|
4442
|
+
preset.config.appFeatures.disabled.length > 0) {
|
|
4443
|
+
<span class="badge">
|
|
4444
|
+
{{
|
|
4445
|
+
preset.config.appFeatures.enabled.length +
|
|
4446
|
+
preset.config.appFeatures.disabled.length
|
|
4447
|
+
}}
|
|
4448
|
+
features
|
|
4449
|
+
</span>
|
|
4450
|
+
} @if (preset.config.language) {
|
|
4451
|
+
<span class="badge">{{ preset.config.language }}</span>
|
|
4452
|
+
}
|
|
4453
|
+
</div>
|
|
4454
|
+
</div>
|
|
4455
|
+
}
|
|
4456
|
+
</div>
|
|
4457
|
+
}
|
|
4458
|
+
</div>
|
|
4459
|
+
</ndt-toolbar-tool>
|
|
4460
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".container{display:flex;flex-direction:column;height:100%}.header{flex-shrink:0;display:flex;gap:var(--ndt-spacing-sm);margin-bottom:var(--ndt-spacing-md)}.header ndt-input{flex:1}.header ndt-button{flex-shrink:0}.empty{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;justify-content:center;align-items:center;border:1px solid var(--ndt-border-subtle);border-radius:var(--ndt-border-radius-medium);padding:var(--ndt-spacing-md);background:transparent;color:var(--ndt-text-muted);text-align:center}.empty p{margin:0}.empty .hint{font-size:var(--ndt-font-size-xs)}.preset-list{display:flex;flex-direction:column;gap:var(--ndt-spacing-md);flex:1;min-height:0;overflow-y:auto;padding-right:var(--ndt-spacing-sm);scrollbar-width:thin;scrollbar-color:var(--ndt-border-primary) var(--ndt-background-secondary)}.preset-list::-webkit-scrollbar{width:8px}.preset-list::-webkit-scrollbar-track{background:var(--ndt-background-secondary);border-radius:4px}.preset-list::-webkit-scrollbar-thumb{background:var(--ndt-border-primary);border-radius:4px}:is():hover{background:var(--ndt-hover-bg)}.preset-card{background:var(--ndt-background-secondary);padding:var(--ndt-spacing-md);border-radius:var(--ndt-border-radius-medium);display:flex;flex-direction:column;gap:var(--ndt-spacing-sm)}.preset-card__header{display:flex;justify-content:space-between;align-items:center;gap:var(--ndt-spacing-sm)}.preset-card__header h3{margin:0;font-size:var(--ndt-font-size-md);color:var(--ndt-text-primary);flex:1}.preset-card__actions{display:flex;gap:var(--ndt-spacing-xs)}.icon-button{background:transparent;border:none;cursor:pointer;padding:var(--ndt-spacing-xs);border-radius:var(--ndt-border-radius-small);color:var(--ndt-text-secondary);display:flex;align-items:center;justify-content:center}.icon-button:hover{background:var(--ndt-hover-bg);color:var(--ndt-text-primary)}.icon-button ndt-icon{width:16px;height:16px}.preset-card__description{margin:0;font-size:var(--ndt-font-size-sm);color:var(--ndt-text-secondary)}.preset-card__meta{font-size:var(--ndt-font-size-xs);color:var(--ndt-text-muted)}.preset-card__meta span{margin-right:var(--ndt-spacing-sm)}.preset-card__preview{display:flex;gap:var(--ndt-spacing-xs);flex-wrap:wrap}.badge{background:var(--ndt-primary-color);color:#fff;padding:2px 8px;border-radius:12px;font-size:var(--ndt-font-size-xs);font-weight:500}.preset-form{flex:1;min-height:0;overflow-y:auto;display:flex;flex-direction:column;gap:var(--ndt-spacing-md);padding:var(--ndt-spacing-md)}.preset-form ndt-input{width:100%}.preset-summary{background:var(--ndt-background-secondary);padding:var(--ndt-spacing-md);border-radius:var(--ndt-border-radius-medium)}.preset-summary h4{margin:0 0 var(--ndt-spacing-sm) 0;font-size:var(--ndt-font-size-sm);color:var(--ndt-text-primary)}.preset-summary ul{margin:0;padding-left:var(--ndt-spacing-md);color:var(--ndt-text-secondary);font-size:var(--ndt-font-size-sm)}.preset-summary ul li{margin-bottom:var(--ndt-spacing-xs)}.form-actions{display:flex;justify-content:flex-end;gap:var(--ndt-spacing-sm)}\n"] }]
|
|
4461
|
+
}] });
|
|
4462
|
+
|
|
4463
|
+
class DevToolbarComponent {
|
|
4464
|
+
constructor() {
|
|
4465
|
+
this.state = inject(DevToolbarStateService);
|
|
4466
|
+
this.destroyRef = inject(DestroyRef);
|
|
4467
|
+
this.settingsService = inject(SettingsService);
|
|
4468
|
+
this.config = input({});
|
|
4469
|
+
this.keyboardShortcut = fromEvent(window, 'keydown')
|
|
4470
|
+
.pipe(filter((event) => event.ctrlKey && event.shiftKey && event.key === 'D'), takeUntilDestroyed(this.destroyRef))
|
|
4471
|
+
.subscribe(() => this.toggleDevTools());
|
|
4472
|
+
this.mouseLeave = fromEvent(document, 'mouseleave')
|
|
4473
|
+
.pipe(throttleTime(3000), takeUntilDestroyed(this.destroyRef))
|
|
4474
|
+
.subscribe(() => this.onMouseLeave());
|
|
2898
4475
|
}
|
|
2899
4476
|
ngOnInit() {
|
|
2900
4477
|
const settings = this.settingsService.getSettings();
|
|
@@ -2910,8 +4487,7 @@ class DevToolbarComponent {
|
|
|
2910
4487
|
this.state.setVisibility(!this.state.isVisible());
|
|
2911
4488
|
}
|
|
2912
4489
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2913
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: DevToolbarComponent, isStandalone: true, selector: "ndt-toolbar", ngImport: i0, template: `
|
|
2914
|
-
@if (isDevMode) {
|
|
4490
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: DevToolbarComponent, isStandalone: true, selector: "ndt-toolbar", inputs: { config: { classPropertyName: "config", publicName: "config", isSignal: true, isRequired: false, transformFunction: null } }, ngImport: i0, template: `
|
|
2915
4491
|
<div
|
|
2916
4492
|
aria-label="Developer tools"
|
|
2917
4493
|
role="toolbar"
|
|
@@ -2922,12 +4498,24 @@ class DevToolbarComponent {
|
|
|
2922
4498
|
(mouseenter)="onMouseEnter()"
|
|
2923
4499
|
>
|
|
2924
4500
|
<ndt-home-tool />
|
|
2925
|
-
|
|
2926
|
-
|
|
4501
|
+
@if (config().showLanguageTool ?? true) {
|
|
4502
|
+
<ndt-language-tool />
|
|
4503
|
+
}
|
|
4504
|
+
@if (config().showFeatureFlagsTool ?? true) {
|
|
4505
|
+
<ndt-feature-flags-tool />
|
|
4506
|
+
}
|
|
4507
|
+
@if (config().showAppFeaturesTool ?? true) {
|
|
4508
|
+
<ndt-app-features-tool />
|
|
4509
|
+
}
|
|
4510
|
+
@if (config().showPermissionsTool ?? true) {
|
|
4511
|
+
<ndt-permissions-tool />
|
|
4512
|
+
}
|
|
4513
|
+
@if (config().showPresetsTool ?? true) {
|
|
4514
|
+
<ndt-presets-tool />
|
|
4515
|
+
}
|
|
2927
4516
|
<ng-content />
|
|
2928
4517
|
</div>
|
|
2929
|
-
|
|
2930
|
-
`, isInline: true, styles: [".dev-toolbar{--ndt-border-radius-small: 4px;--ndt-border-radius-medium: 8px;--ndt-border-radius-large: 12px;--ndt-transition-default: all .2s ease-out;--ndt-transition-smooth: all .2s ease-in-out;--ndt-bg-primary: rgb(255, 255, 255);--ndt-bg-gradient: linear-gradient(180deg, rgb(243, 244, 246) 0%, rgba(243, 244, 246, .88) 100%);--ndt-text-primary: rgb(17, 24, 39);--ndt-text-secondary: rgb(55, 65, 81);--ndt-text-muted: rgb(107, 114, 128);--ndt-border-primary: #e5e7eb;--ndt-border-subtle: rgba(17, 24, 39, .1);--ndt-hover-bg: rgba(17, 24, 39, .05);--ndt-hover-danger: rgb(239, 68, 68);--ndt-shadow-toolbar: 0 2px 8px rgba(156, 163, 175, .2);--ndt-shadow-tooltip: 0 0 0 1px rgba(17, 24, 39, .05), 0 4px 8px rgba(107, 114, 128, .15), 0 2px 4px rgba(107, 114, 128, .1);--ndt-shadow-window: 0px 0px 0px 0px rgba(156, 163, 175, .1), 0px 1px 2px 0px rgba(156, 163, 175, .12), 0px 4px 4px 0px rgba(156, 163, 175, .1), 0px 10px 6px 0px rgba(156, 163, 175, .08), 0px 17px 7px 0px rgba(156, 163, 175, .05), 0px 26px 7px 0px rgba(156, 163, 175, .02);--ndt-spacing-xs: 4px;--ndt-spacing-sm: 8px;--ndt-spacing-md: 16px;--ndt-window-padding: 24px;--ndt-font-size-xs: .75rem;--ndt-font-size-sm: .875rem;--ndt-font-size-md: 1rem;--ndt-font-size-lg: 1.25rem;--ndt-font-size-xl: 2rem;--ndt-background-secondary: var(--ndt-bg-primary);--ndt-background-hover: var(--ndt-hover-bg);--ndt-primary: #df30d4;--ndt-primary-rgb: 223, 48, 212;--ndt-text-on-primary: rgb(255, 255, 255);--ndt-border-color: var(--ndt-border-primary);--ndt-note-background: rgb(219, 234, 254);--ndt-note-border: rgba(37, 99, 235, .2);--ndt-warning-background: rgb(254, 249, 195);--ndt-warning-border: rgba(202, 138, 4, .2);--ndt-error-background: rgb(254, 226, 226);--ndt-error-border: rgba(220, 38, 38, .2)}.dev-toolbar[data-theme=dark]{--ndt-bg-primary: rgb(17, 24, 39);--ndt-bg-gradient: linear-gradient(180deg, rgb(19, 21, 26) 0%, rgba(19, 21, 26, .88) 100%);--ndt-text-primary: rgb(255, 255, 255);--ndt-text-secondary: rgb(229, 231, 235);--ndt-text-muted: rgb(156, 163, 175);--ndt-border-primary: #343841;--ndt-border-subtle: rgba(255, 255, 255, .1);--ndt-hover-bg: rgba(255, 255, 255, .12);--ndt-hover-danger: rgb(220, 38, 38);--ndt-shadow-toolbar: 0 2px 8px rgba(19, 21, 26, .3);--ndt-shadow-tooltip: 0 0 0 1px rgba(255, 255, 255, .1), 0 4px 8px rgba(0, 0, 0, .4), 0 2px 4px rgba(0, 0, 0, .3);--ndt-shadow-window: 0px 0px 0px 0px rgba(19, 21, 26, .3), 0px 1px 2px 0px rgba(19, 21, 26, .29), 0px 4px 4px 0px rgba(19, 21, 26, .26), 0px 10px 6px 0px rgba(19, 21, 26, .15), 0px 17px 7px 0px rgba(19, 21, 26, .04), 0px 26px 7px 0px rgba(19, 21, 26, .01);--ndt-note-background: rgba(37, 99, 235, .15);--ndt-note-border: rgba(37, 99, 235, .3);--ndt-warning-background: rgba(202, 138, 4, .15);--ndt-warning-border: rgba(202, 138, 4, .3);--ndt-error-background: rgba(220, 38, 38, .15);--ndt-error-border: rgba(220, 38, 38, .3)}.dev-toolbar h1,.dev-toolbar h2,.dev-toolbar h3,.dev-toolbar h4,.dev-toolbar h5{font-weight:600;color:var(--ndt-text-primary);margin:0}.dev-toolbar h1{font-size:var(--ndt-font-size-xl)}.dev-toolbar h2{font-size:var(--ndt-font-size-lg)}.dev-toolbar h3{font-size:var(--ndt-font-size-md)}.dev-toolbar h4{font-size:var(--ndt-font-size-sm)}.dev-toolbar h5{font-size:var(--ndt-font-size-xs)}.dev-toolbar hr{border:1px solid var(--ndt-border-subtle);margin:1em 0}.dev-toolbar p{line-height:1.5em;margin:0}.dev-toolbar{position:fixed;bottom:0;left:50%;z-index:999999;transform:translate(-50%);display:flex;pointer-events:auto;background:var(--ndt-bg-primary);border:1px solid var(--ndt-border-primary);border-radius:9999px;box-shadow:var(--ndt-shadow-toolbar);height:40px;overflow:hidden}.dev-toolbar--active{opacity:1}\n"], dependencies: [{ kind: "component", type: DevToolbarHomeToolComponent, selector: "ndt-home-tool", inputs: ["badge"] }, { kind: "component", type: DevToolbarLanguageToolComponent, selector: "ndt-language-tool" }, { kind: "component", type: DevToolbarFeatureFlagsToolComponent, selector: "ndt-feature-flags-tool" }], animations: [
|
|
4518
|
+
`, isInline: true, styles: [":host{--ndt-border-radius-small: 4px;--ndt-border-radius-medium: 8px;--ndt-border-radius-large: 12px;--ndt-transition-default: all .2s ease-out;--ndt-transition-smooth: all .2s ease-in-out;--ndt-bg-primary: rgb(255, 255, 255);--ndt-bg-gradient: linear-gradient(180deg, rgb(243, 244, 246) 0%, rgba(243, 244, 246, .88) 100%);--ndt-text-primary: rgb(17, 24, 39);--ndt-text-secondary: rgb(55, 65, 81);--ndt-text-muted: rgb(107, 114, 128);--ndt-border-primary: #e5e7eb;--ndt-border-subtle: rgba(17, 24, 39, .1);--ndt-hover-bg: rgba(17, 24, 39, .05);--ndt-hover-danger: rgb(239, 68, 68);--ndt-shadow-toolbar: 0 2px 8px rgba(156, 163, 175, .2);--ndt-shadow-tooltip: 0 0 0 1px rgba(17, 24, 39, .05), 0 4px 8px rgba(107, 114, 128, .15), 0 2px 4px rgba(107, 114, 128, .1);--ndt-shadow-window: 0px 0px 0px 0px rgba(156, 163, 175, .1), 0px 1px 2px 0px rgba(156, 163, 175, .12), 0px 4px 4px 0px rgba(156, 163, 175, .1), 0px 10px 6px 0px rgba(156, 163, 175, .08), 0px 17px 7px 0px rgba(156, 163, 175, .05), 0px 26px 7px 0px rgba(156, 163, 175, .02);--ndt-spacing-xs: 4px;--ndt-spacing-sm: 6px;--ndt-spacing-md: 12px;--ndt-window-padding: 16px;--ndt-font-size-xs: .75rem;--ndt-font-size-sm: .875rem;--ndt-font-size-md: 1rem;--ndt-font-size-lg: 1.25rem;--ndt-font-size-xl: 2rem;--ndt-background-secondary: var(--ndt-bg-primary);--ndt-background-hover: var(--ndt-hover-bg);--ndt-primary: #df30d4;--ndt-primary-rgb: 223, 48, 212;--ndt-text-on-primary: rgb(255, 255, 255);--ndt-border-color: var(--ndt-border-primary);--ndt-note-background: rgb(219, 234, 254);--ndt-note-border: rgba(37, 99, 235, .2);--ndt-warning-background: rgb(254, 249, 195);--ndt-warning-border: rgba(202, 138, 4, .2);--ndt-error-background: rgb(254, 226, 226);--ndt-error-border: rgba(220, 38, 38, .2);display:contents;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\"}:host[data-theme=dark]{--ndt-bg-primary: rgb(17, 24, 39);--ndt-bg-gradient: linear-gradient(180deg, rgb(19, 21, 26) 0%, rgba(19, 21, 26, .88) 100%);--ndt-text-primary: rgb(255, 255, 255);--ndt-text-secondary: rgb(229, 231, 235);--ndt-text-muted: rgb(156, 163, 175);--ndt-border-primary: #343841;--ndt-border-subtle: rgba(255, 255, 255, .1);--ndt-hover-bg: rgba(255, 255, 255, .12);--ndt-hover-danger: rgb(220, 38, 38);--ndt-shadow-toolbar: 0 2px 8px rgba(19, 21, 26, .3);--ndt-shadow-tooltip: 0 0 0 1px rgba(255, 255, 255, .1), 0 4px 8px rgba(0, 0, 0, .4), 0 2px 4px rgba(0, 0, 0, .3);--ndt-shadow-window: 0px 0px 0px 0px rgba(19, 21, 26, .3), 0px 1px 2px 0px rgba(19, 21, 26, .29), 0px 4px 4px 0px rgba(19, 21, 26, .26), 0px 10px 6px 0px rgba(19, 21, 26, .15), 0px 17px 7px 0px rgba(19, 21, 26, .04), 0px 26px 7px 0px rgba(19, 21, 26, .01);--ndt-note-background: rgba(37, 99, 235, .15);--ndt-note-border: rgba(37, 99, 235, .3);--ndt-warning-background: rgba(202, 138, 4, .15);--ndt-warning-border: rgba(202, 138, 4, .3);--ndt-error-background: rgba(220, 38, 38, .15);--ndt-error-border: rgba(220, 38, 38, .3)}.dev-toolbar{position:fixed;bottom:0;left:50%;z-index:999999;transform:translate(-50%);display:flex;pointer-events:auto;background:var(--ndt-bg-primary);border:1px solid var(--ndt-border-primary);border-radius:9999px;box-shadow:var(--ndt-shadow-toolbar);height:40px;overflow:hidden}.dev-toolbar--active{opacity:1}h1,h2,h3,h4,h5{font-weight:600;color:var(--ndt-text-primary);margin:0}h1{font-size:var(--ndt-font-size-xl)}h2{font-size:var(--ndt-font-size-lg)}h3{font-size:var(--ndt-font-size-md)}h4{font-size:var(--ndt-font-size-sm)}h5{font-size:var(--ndt-font-size-xs)}hr{border:1px solid var(--ndt-border-subtle);margin:1em 0}p{line-height:1.5em;margin:0}\n"], dependencies: [{ kind: "component", type: DevToolbarHomeToolComponent, selector: "ndt-home-tool", inputs: ["badge"] }, { kind: "component", type: DevToolbarLanguageToolComponent, selector: "ndt-language-tool" }, { kind: "component", type: DevToolbarFeatureFlagsToolComponent, selector: "ndt-feature-flags-tool" }, { kind: "component", type: DevToolbarAppFeaturesToolComponent, selector: "ndt-app-features-tool" }, { kind: "component", type: DevToolbarPermissionsToolComponent, selector: "ndt-permissions-tool" }, { kind: "component", type: DevToolbarPresetsToolComponent, selector: "ndt-presets-tool" }], animations: [
|
|
2931
4519
|
trigger('toolbarState', [
|
|
2932
4520
|
state('hidden', style({
|
|
2933
4521
|
transform: 'translate(-50%, calc(100% + -1.2rem))',
|
|
@@ -2939,16 +4527,18 @@ class DevToolbarComponent {
|
|
|
2939
4527
|
animate('300ms cubic-bezier(0.4, 0, 0.2, 1)'),
|
|
2940
4528
|
]),
|
|
2941
4529
|
]),
|
|
2942
|
-
] }); }
|
|
4530
|
+
], encapsulation: i0.ViewEncapsulation.ShadowDom }); }
|
|
2943
4531
|
}
|
|
2944
4532
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarComponent, decorators: [{
|
|
2945
4533
|
type: Component,
|
|
2946
|
-
args: [{ standalone: true, selector: 'ndt-toolbar', imports: [
|
|
4534
|
+
args: [{ standalone: true, selector: 'ndt-toolbar', encapsulation: ViewEncapsulation.ShadowDom, imports: [
|
|
2947
4535
|
DevToolbarHomeToolComponent,
|
|
2948
4536
|
DevToolbarLanguageToolComponent,
|
|
2949
4537
|
DevToolbarFeatureFlagsToolComponent,
|
|
4538
|
+
DevToolbarAppFeaturesToolComponent,
|
|
4539
|
+
DevToolbarPermissionsToolComponent,
|
|
4540
|
+
DevToolbarPresetsToolComponent,
|
|
2950
4541
|
], template: `
|
|
2951
|
-
@if (isDevMode) {
|
|
2952
4542
|
<div
|
|
2953
4543
|
aria-label="Developer tools"
|
|
2954
4544
|
role="toolbar"
|
|
@@ -2959,11 +4549,23 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2959
4549
|
(mouseenter)="onMouseEnter()"
|
|
2960
4550
|
>
|
|
2961
4551
|
<ndt-home-tool />
|
|
2962
|
-
|
|
2963
|
-
|
|
4552
|
+
@if (config().showLanguageTool ?? true) {
|
|
4553
|
+
<ndt-language-tool />
|
|
4554
|
+
}
|
|
4555
|
+
@if (config().showFeatureFlagsTool ?? true) {
|
|
4556
|
+
<ndt-feature-flags-tool />
|
|
4557
|
+
}
|
|
4558
|
+
@if (config().showAppFeaturesTool ?? true) {
|
|
4559
|
+
<ndt-app-features-tool />
|
|
4560
|
+
}
|
|
4561
|
+
@if (config().showPermissionsTool ?? true) {
|
|
4562
|
+
<ndt-permissions-tool />
|
|
4563
|
+
}
|
|
4564
|
+
@if (config().showPresetsTool ?? true) {
|
|
4565
|
+
<ndt-presets-tool />
|
|
4566
|
+
}
|
|
2964
4567
|
<ng-content />
|
|
2965
4568
|
</div>
|
|
2966
|
-
}
|
|
2967
4569
|
`, animations: [
|
|
2968
4570
|
trigger('toolbarState', [
|
|
2969
4571
|
state('hidden', style({
|
|
@@ -2976,7 +4578,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2976
4578
|
animate('300ms cubic-bezier(0.4, 0, 0.2, 1)'),
|
|
2977
4579
|
]),
|
|
2978
4580
|
]),
|
|
2979
|
-
], styles: ["
|
|
4581
|
+
], styles: [":host{--ndt-border-radius-small: 4px;--ndt-border-radius-medium: 8px;--ndt-border-radius-large: 12px;--ndt-transition-default: all .2s ease-out;--ndt-transition-smooth: all .2s ease-in-out;--ndt-bg-primary: rgb(255, 255, 255);--ndt-bg-gradient: linear-gradient(180deg, rgb(243, 244, 246) 0%, rgba(243, 244, 246, .88) 100%);--ndt-text-primary: rgb(17, 24, 39);--ndt-text-secondary: rgb(55, 65, 81);--ndt-text-muted: rgb(107, 114, 128);--ndt-border-primary: #e5e7eb;--ndt-border-subtle: rgba(17, 24, 39, .1);--ndt-hover-bg: rgba(17, 24, 39, .05);--ndt-hover-danger: rgb(239, 68, 68);--ndt-shadow-toolbar: 0 2px 8px rgba(156, 163, 175, .2);--ndt-shadow-tooltip: 0 0 0 1px rgba(17, 24, 39, .05), 0 4px 8px rgba(107, 114, 128, .15), 0 2px 4px rgba(107, 114, 128, .1);--ndt-shadow-window: 0px 0px 0px 0px rgba(156, 163, 175, .1), 0px 1px 2px 0px rgba(156, 163, 175, .12), 0px 4px 4px 0px rgba(156, 163, 175, .1), 0px 10px 6px 0px rgba(156, 163, 175, .08), 0px 17px 7px 0px rgba(156, 163, 175, .05), 0px 26px 7px 0px rgba(156, 163, 175, .02);--ndt-spacing-xs: 4px;--ndt-spacing-sm: 6px;--ndt-spacing-md: 12px;--ndt-window-padding: 16px;--ndt-font-size-xs: .75rem;--ndt-font-size-sm: .875rem;--ndt-font-size-md: 1rem;--ndt-font-size-lg: 1.25rem;--ndt-font-size-xl: 2rem;--ndt-background-secondary: var(--ndt-bg-primary);--ndt-background-hover: var(--ndt-hover-bg);--ndt-primary: #df30d4;--ndt-primary-rgb: 223, 48, 212;--ndt-text-on-primary: rgb(255, 255, 255);--ndt-border-color: var(--ndt-border-primary);--ndt-note-background: rgb(219, 234, 254);--ndt-note-border: rgba(37, 99, 235, .2);--ndt-warning-background: rgb(254, 249, 195);--ndt-warning-border: rgba(202, 138, 4, .2);--ndt-error-background: rgb(254, 226, 226);--ndt-error-border: rgba(220, 38, 38, .2);display:contents;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,\"Apple Color Emoji\",\"Segoe UI Emoji\",Segoe UI Symbol,\"Noto Color Emoji\"}:host[data-theme=dark]{--ndt-bg-primary: rgb(17, 24, 39);--ndt-bg-gradient: linear-gradient(180deg, rgb(19, 21, 26) 0%, rgba(19, 21, 26, .88) 100%);--ndt-text-primary: rgb(255, 255, 255);--ndt-text-secondary: rgb(229, 231, 235);--ndt-text-muted: rgb(156, 163, 175);--ndt-border-primary: #343841;--ndt-border-subtle: rgba(255, 255, 255, .1);--ndt-hover-bg: rgba(255, 255, 255, .12);--ndt-hover-danger: rgb(220, 38, 38);--ndt-shadow-toolbar: 0 2px 8px rgba(19, 21, 26, .3);--ndt-shadow-tooltip: 0 0 0 1px rgba(255, 255, 255, .1), 0 4px 8px rgba(0, 0, 0, .4), 0 2px 4px rgba(0, 0, 0, .3);--ndt-shadow-window: 0px 0px 0px 0px rgba(19, 21, 26, .3), 0px 1px 2px 0px rgba(19, 21, 26, .29), 0px 4px 4px 0px rgba(19, 21, 26, .26), 0px 10px 6px 0px rgba(19, 21, 26, .15), 0px 17px 7px 0px rgba(19, 21, 26, .04), 0px 26px 7px 0px rgba(19, 21, 26, .01);--ndt-note-background: rgba(37, 99, 235, .15);--ndt-note-border: rgba(37, 99, 235, .3);--ndt-warning-background: rgba(202, 138, 4, .15);--ndt-warning-border: rgba(202, 138, 4, .3);--ndt-error-background: rgba(220, 38, 38, .15);--ndt-error-border: rgba(220, 38, 38, .3)}.dev-toolbar{position:fixed;bottom:0;left:50%;z-index:999999;transform:translate(-50%);display:flex;pointer-events:auto;background:var(--ndt-bg-primary);border:1px solid var(--ndt-border-primary);border-radius:9999px;box-shadow:var(--ndt-shadow-toolbar);height:40px;overflow:hidden}.dev-toolbar--active{opacity:1}h1,h2,h3,h4,h5{font-weight:600;color:var(--ndt-text-primary);margin:0}h1{font-size:var(--ndt-font-size-xl)}h2{font-size:var(--ndt-font-size-lg)}h3{font-size:var(--ndt-font-size-md)}h4{font-size:var(--ndt-font-size-sm)}h5{font-size:var(--ndt-font-size-xs)}hr{border:1px solid var(--ndt-border-subtle);margin:1em 0}p{line-height:1.5em;margin:0}\n"] }]
|
|
2980
4582
|
}] });
|
|
2981
4583
|
|
|
2982
4584
|
class DevToolbarFeatureFlagService {
|
|
@@ -3031,9 +4633,342 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
3031
4633
|
args: [{ providedIn: 'root' }]
|
|
3032
4634
|
}] });
|
|
3033
4635
|
|
|
4636
|
+
/**
|
|
4637
|
+
* Public service for managing app features in the dev toolbar.
|
|
4638
|
+
*
|
|
4639
|
+
* This service implements the DevToolsService interface and provides methods for:
|
|
4640
|
+
* - Configuring available product features
|
|
4641
|
+
* - Retrieving forced feature overrides
|
|
4642
|
+
* - Applying preset feature configurations
|
|
4643
|
+
* - Exporting current forced state for presets
|
|
4644
|
+
*
|
|
4645
|
+
* @example
|
|
4646
|
+
* ```typescript
|
|
4647
|
+
* import { DevToolbarAppFeaturesService } from 'ngx-dev-toolbar';
|
|
4648
|
+
*
|
|
4649
|
+
* @Component({...})
|
|
4650
|
+
* export class AppComponent implements OnInit {
|
|
4651
|
+
* private appFeaturesService = inject(DevToolbarAppFeaturesService);
|
|
4652
|
+
*
|
|
4653
|
+
* ngOnInit() {
|
|
4654
|
+
* // Configure available features based on current tier
|
|
4655
|
+
* const features: DevToolbarAppFeature[] = [
|
|
4656
|
+
* { id: 'analytics', name: 'Analytics Dashboard', isEnabled: true, isForced: false },
|
|
4657
|
+
* { id: 'multi-user', name: 'Multi-User Support', isEnabled: false, isForced: false }
|
|
4658
|
+
* ];
|
|
4659
|
+
* this.appFeaturesService.setAvailableOptions(features);
|
|
4660
|
+
*
|
|
4661
|
+
* // Subscribe to forced overrides
|
|
4662
|
+
* this.appFeaturesService.getForcedValues().subscribe(forcedFeatures => {
|
|
4663
|
+
* forcedFeatures.forEach(feature => {
|
|
4664
|
+
* // Apply forced feature state to application logic
|
|
4665
|
+
* this.applyFeatureState(feature.id, feature.isEnabled);
|
|
4666
|
+
* });
|
|
4667
|
+
* });
|
|
4668
|
+
* }
|
|
4669
|
+
* }
|
|
4670
|
+
* ```
|
|
4671
|
+
*/
|
|
4672
|
+
class DevToolbarAppFeaturesService {
|
|
4673
|
+
constructor() {
|
|
4674
|
+
this.internalService = inject(DevToolbarInternalAppFeaturesService);
|
|
4675
|
+
}
|
|
4676
|
+
/**
|
|
4677
|
+
* Set available app features for the application.
|
|
4678
|
+
*
|
|
4679
|
+
* Configures the list of product features that can be toggled in the dev toolbar.
|
|
4680
|
+
* Features should represent product-level capabilities like license tiers,
|
|
4681
|
+
* deployment configurations, or environment flags.
|
|
4682
|
+
*
|
|
4683
|
+
* @param features - Array of app features to display in the toolbar
|
|
4684
|
+
* @throws Error if duplicate feature IDs or empty IDs are detected
|
|
4685
|
+
*
|
|
4686
|
+
* @example
|
|
4687
|
+
* ```typescript
|
|
4688
|
+
* const features: DevToolbarAppFeature[] = [
|
|
4689
|
+
* {
|
|
4690
|
+
* id: 'advanced-analytics',
|
|
4691
|
+
* name: 'Advanced Analytics Dashboard',
|
|
4692
|
+
* description: 'Access premium reporting and data visualization',
|
|
4693
|
+
* isEnabled: false, // Not available in current tier
|
|
4694
|
+
* isForced: false
|
|
4695
|
+
* },
|
|
4696
|
+
* {
|
|
4697
|
+
* id: 'multi-user-support',
|
|
4698
|
+
* name: 'Multi-User Collaboration',
|
|
4699
|
+
* description: 'Enable team features and user management',
|
|
4700
|
+
* isEnabled: true, // Available in current tier
|
|
4701
|
+
* isForced: false
|
|
4702
|
+
* }
|
|
4703
|
+
* ];
|
|
4704
|
+
* this.appFeaturesService.setAvailableOptions(features);
|
|
4705
|
+
* ```
|
|
4706
|
+
*/
|
|
4707
|
+
setAvailableOptions(features) {
|
|
4708
|
+
this.internalService.setAppFeatures(features);
|
|
4709
|
+
}
|
|
4710
|
+
/**
|
|
4711
|
+
* Get observable stream of features that have forced overrides.
|
|
4712
|
+
*
|
|
4713
|
+
* Emits an array of features that have been forced via the dev toolbar.
|
|
4714
|
+
* Only features with `isForced = true` are included in the emissions.
|
|
4715
|
+
* Use this to react to feature override changes and update application behavior.
|
|
4716
|
+
*
|
|
4717
|
+
* @returns Observable that emits array of forced features whenever state changes
|
|
4718
|
+
*
|
|
4719
|
+
* @example
|
|
4720
|
+
* ```typescript
|
|
4721
|
+
* this.appFeaturesService.getForcedValues()
|
|
4722
|
+
* .pipe(takeUntilDestroyed())
|
|
4723
|
+
* .subscribe(forcedFeatures => {
|
|
4724
|
+
* forcedFeatures.forEach(feature => {
|
|
4725
|
+
* if (feature.isEnabled) {
|
|
4726
|
+
* this.enableFeature(feature.id);
|
|
4727
|
+
* } else {
|
|
4728
|
+
* this.disableFeature(feature.id);
|
|
4729
|
+
* }
|
|
4730
|
+
* });
|
|
4731
|
+
* });
|
|
4732
|
+
* ```
|
|
4733
|
+
*/
|
|
4734
|
+
getForcedValues() {
|
|
4735
|
+
return this.internalService.getForcedFeatures();
|
|
4736
|
+
}
|
|
4737
|
+
/**
|
|
4738
|
+
* Apply a preset feature configuration (for preset tool integration).
|
|
4739
|
+
*
|
|
4740
|
+
* Accepts a forced features state object and applies it to the current configuration.
|
|
4741
|
+
* Invalid feature IDs (not in configured features) are filtered out with a warning.
|
|
4742
|
+
*
|
|
4743
|
+
* @param state - Forced features state containing enabled/disabled arrays
|
|
4744
|
+
*
|
|
4745
|
+
* @example
|
|
4746
|
+
* ```typescript
|
|
4747
|
+
* // Apply "Enterprise Tier" preset
|
|
4748
|
+
* const enterprisePreset: ForcedAppFeaturesState = {
|
|
4749
|
+
* enabled: ['analytics', 'multi-user', 'white-label', 'sso'],
|
|
4750
|
+
* disabled: []
|
|
4751
|
+
* };
|
|
4752
|
+
* this.appFeaturesService.applyPresetFeatures(enterprisePreset);
|
|
4753
|
+
*
|
|
4754
|
+
* // Apply "Basic Tier" preset
|
|
4755
|
+
* const basicPreset: ForcedAppFeaturesState = {
|
|
4756
|
+
* enabled: [],
|
|
4757
|
+
* disabled: ['analytics', 'multi-user', 'white-label', 'sso']
|
|
4758
|
+
* };
|
|
4759
|
+
* this.appFeaturesService.applyPresetFeatures(basicPreset);
|
|
4760
|
+
* ```
|
|
4761
|
+
*/
|
|
4762
|
+
applyPresetFeatures(state) {
|
|
4763
|
+
this.internalService.applyForcedState(state);
|
|
4764
|
+
}
|
|
4765
|
+
/**
|
|
4766
|
+
* Get current forced feature state as a snapshot (for preset export).
|
|
4767
|
+
*
|
|
4768
|
+
* Returns the current forced features state with enabled/disabled arrays.
|
|
4769
|
+
* Useful for exporting toolbar state to save as a preset or for debugging.
|
|
4770
|
+
* Returns a defensive copy - mutations will not affect internal state.
|
|
4771
|
+
*
|
|
4772
|
+
* @returns Current forced features state
|
|
4773
|
+
*
|
|
4774
|
+
* @example
|
|
4775
|
+
* ```typescript
|
|
4776
|
+
* // Export current toolbar state to save as preset
|
|
4777
|
+
* const currentState = this.appFeaturesService.getCurrentForcedState();
|
|
4778
|
+
* this.presetsService.savePreset('my-config', {
|
|
4779
|
+
* appFeatures: currentState,
|
|
4780
|
+
* // ... other tool states
|
|
4781
|
+
* });
|
|
4782
|
+
*
|
|
4783
|
+
* console.log(currentState);
|
|
4784
|
+
* // { enabled: ['analytics'], disabled: ['white-label'] }
|
|
4785
|
+
* ```
|
|
4786
|
+
*/
|
|
4787
|
+
getCurrentForcedState() {
|
|
4788
|
+
return this.internalService.getCurrentForcedState();
|
|
4789
|
+
}
|
|
4790
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarAppFeaturesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4791
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarAppFeaturesService, providedIn: 'root' }); }
|
|
4792
|
+
}
|
|
4793
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarAppFeaturesService, decorators: [{
|
|
4794
|
+
type: Injectable,
|
|
4795
|
+
args: [{ providedIn: 'root' }]
|
|
4796
|
+
}] });
|
|
4797
|
+
|
|
4798
|
+
/**
|
|
4799
|
+
* Public service for integrating the Permissions Tool with your application.
|
|
4800
|
+
* Use this service to:
|
|
4801
|
+
* 1. Register your application's permissions with setAvailableOptions()
|
|
4802
|
+
* 2. Listen for toolbar permission overrides with getForcedValues()
|
|
4803
|
+
* 3. Apply preset permission states for testing with applyPreset()
|
|
4804
|
+
*
|
|
4805
|
+
* @example
|
|
4806
|
+
* ```typescript
|
|
4807
|
+
* constructor(private permissionsService: DevToolbarPermissionsService) {
|
|
4808
|
+
* // Register permissions
|
|
4809
|
+
* this.permissionsService.setAvailableOptions([
|
|
4810
|
+
* { id: 'can-edit', name: 'Can Edit', isGranted: false, isForced: false }
|
|
4811
|
+
* ]);
|
|
4812
|
+
*
|
|
4813
|
+
* // Listen for overrides
|
|
4814
|
+
* this.permissionsService.getForcedValues().subscribe(forcedPermissions => {
|
|
4815
|
+
* // Update your app's permission state
|
|
4816
|
+
* });
|
|
4817
|
+
* }
|
|
4818
|
+
* ```
|
|
4819
|
+
*/
|
|
4820
|
+
class DevToolbarPermissionsService {
|
|
4821
|
+
constructor() {
|
|
4822
|
+
this.internalService = inject(DevToolbarInternalPermissionsService);
|
|
4823
|
+
}
|
|
4824
|
+
/**
|
|
4825
|
+
* Sets the available permissions that will be displayed in the toolbar tool.
|
|
4826
|
+
* Call this in your app initialization to register permissions.
|
|
4827
|
+
*
|
|
4828
|
+
* @param permissions Array of permissions to display in the toolbar
|
|
4829
|
+
*
|
|
4830
|
+
* @example
|
|
4831
|
+
* ```typescript
|
|
4832
|
+
* this.permissionsService.setAvailableOptions([
|
|
4833
|
+
* {
|
|
4834
|
+
* id: 'can-edit-posts',
|
|
4835
|
+
* name: 'Edit Posts',
|
|
4836
|
+
* description: 'Can edit blog posts',
|
|
4837
|
+
* isGranted: false,
|
|
4838
|
+
* isForced: false
|
|
4839
|
+
* }
|
|
4840
|
+
* ]);
|
|
4841
|
+
* ```
|
|
4842
|
+
*/
|
|
4843
|
+
setAvailableOptions(permissions) {
|
|
4844
|
+
this.internalService.setAppPermissions(permissions);
|
|
4845
|
+
}
|
|
4846
|
+
/**
|
|
4847
|
+
* Gets an observable of permissions that were forced/overridden through the toolbar.
|
|
4848
|
+
* Subscribe to this to update your application's permission state.
|
|
4849
|
+
*
|
|
4850
|
+
* @returns Observable emitting array of forced permissions whenever changes occur
|
|
4851
|
+
*
|
|
4852
|
+
* @example
|
|
4853
|
+
* ```typescript
|
|
4854
|
+
* this.permissionsService.getForcedValues().subscribe(forcedPermissions => {
|
|
4855
|
+
* forcedPermissions.forEach(permission => {
|
|
4856
|
+
* this.updatePermission(permission.id, permission.isGranted);
|
|
4857
|
+
* });
|
|
4858
|
+
* });
|
|
4859
|
+
* ```
|
|
4860
|
+
*/
|
|
4861
|
+
getForcedValues() {
|
|
4862
|
+
return this.internalService.getForcedPermissions();
|
|
4863
|
+
}
|
|
4864
|
+
/**
|
|
4865
|
+
* Apply a preset permission state. Useful for automated testing scenarios.
|
|
4866
|
+
*
|
|
4867
|
+
* @param state The forced permissions state to apply
|
|
4868
|
+
*
|
|
4869
|
+
* @example
|
|
4870
|
+
* ```typescript
|
|
4871
|
+
* this.permissionsService.applyPreset({
|
|
4872
|
+
* granted: ['can-edit-posts'],
|
|
4873
|
+
* denied: ['can-delete-posts']
|
|
4874
|
+
* });
|
|
4875
|
+
* ```
|
|
4876
|
+
*/
|
|
4877
|
+
applyPreset(state) {
|
|
4878
|
+
this.internalService.applyPresetPermissions(state);
|
|
4879
|
+
}
|
|
4880
|
+
/**
|
|
4881
|
+
* Get the current forced permission state.
|
|
4882
|
+
*
|
|
4883
|
+
* @returns Current forced permissions state
|
|
4884
|
+
*/
|
|
4885
|
+
getCurrentState() {
|
|
4886
|
+
return this.internalService.getCurrentForcedState();
|
|
4887
|
+
}
|
|
4888
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPermissionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4889
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPermissionsService, providedIn: 'root' }); }
|
|
4890
|
+
}
|
|
4891
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPermissionsService, decorators: [{
|
|
4892
|
+
type: Injectable,
|
|
4893
|
+
args: [{ providedIn: 'root' }]
|
|
4894
|
+
}] });
|
|
4895
|
+
|
|
4896
|
+
/**
|
|
4897
|
+
* Public service for managing dev toolbar presets.
|
|
4898
|
+
* Allows developers to programmatically save, load, and manage presets.
|
|
4899
|
+
*/
|
|
4900
|
+
class DevToolbarPresetsService {
|
|
4901
|
+
constructor() {
|
|
4902
|
+
this.internalService = inject(DevToolbarInternalPresetsService);
|
|
4903
|
+
}
|
|
4904
|
+
/**
|
|
4905
|
+
* Get all saved presets as an Observable
|
|
4906
|
+
*/
|
|
4907
|
+
getPresets() {
|
|
4908
|
+
return this.internalService.presets$;
|
|
4909
|
+
}
|
|
4910
|
+
/**
|
|
4911
|
+
* Save current toolbar state as a preset
|
|
4912
|
+
* @param name - Name for the preset
|
|
4913
|
+
* @param description - Optional description
|
|
4914
|
+
* @returns The created preset
|
|
4915
|
+
*/
|
|
4916
|
+
savePreset(name, description) {
|
|
4917
|
+
return this.internalService.saveCurrentAsPreset(name, description);
|
|
4918
|
+
}
|
|
4919
|
+
/**
|
|
4920
|
+
* Apply a preset (load its configuration into all tools)
|
|
4921
|
+
* @param presetId - ID of the preset to apply
|
|
4922
|
+
*/
|
|
4923
|
+
async applyPreset(presetId) {
|
|
4924
|
+
return this.internalService.applyPreset(presetId);
|
|
4925
|
+
}
|
|
4926
|
+
/**
|
|
4927
|
+
* Update a preset with current toolbar state
|
|
4928
|
+
* @param presetId - ID of the preset to update
|
|
4929
|
+
*/
|
|
4930
|
+
updatePreset(presetId) {
|
|
4931
|
+
this.internalService.updatePreset(presetId);
|
|
4932
|
+
}
|
|
4933
|
+
/**
|
|
4934
|
+
* Delete a preset
|
|
4935
|
+
* @param presetId - ID of the preset to delete
|
|
4936
|
+
*/
|
|
4937
|
+
deletePreset(presetId) {
|
|
4938
|
+
this.internalService.deletePreset(presetId);
|
|
4939
|
+
}
|
|
4940
|
+
/**
|
|
4941
|
+
* Export a preset as JSON string
|
|
4942
|
+
* @param presetId - ID of the preset to export
|
|
4943
|
+
* @returns JSON string representation of the preset
|
|
4944
|
+
*/
|
|
4945
|
+
exportPreset(presetId) {
|
|
4946
|
+
const preset = this.internalService.getPresetById(presetId);
|
|
4947
|
+
if (!preset)
|
|
4948
|
+
return null;
|
|
4949
|
+
return JSON.stringify(preset, null, 2);
|
|
4950
|
+
}
|
|
4951
|
+
/**
|
|
4952
|
+
* Import a preset from JSON string
|
|
4953
|
+
* @param json - JSON string representation of a preset
|
|
4954
|
+
* @returns The imported preset
|
|
4955
|
+
* @throws Error if JSON is invalid
|
|
4956
|
+
*/
|
|
4957
|
+
importPreset(json) {
|
|
4958
|
+
const preset = JSON.parse(json);
|
|
4959
|
+
return this.internalService.addPreset(preset);
|
|
4960
|
+
}
|
|
4961
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPresetsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4962
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPresetsService, providedIn: 'root' }); }
|
|
4963
|
+
}
|
|
4964
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPresetsService, decorators: [{
|
|
4965
|
+
type: Injectable,
|
|
4966
|
+
args: [{ providedIn: 'root' }]
|
|
4967
|
+
}] });
|
|
4968
|
+
|
|
3034
4969
|
/**
|
|
3035
4970
|
* Generated bundle index. Do not edit.
|
|
3036
4971
|
*/
|
|
3037
4972
|
|
|
3038
|
-
export { DevToolbarComponent, DevToolbarFeatureFlagService, DevToolbarIconComponent, DevToolbarLanguageService, DevToolbarToolComponent };
|
|
4973
|
+
export { DevToolbarAppFeaturesService, DevToolbarAppFeaturesToolComponent, DevToolbarComponent, DevToolbarFeatureFlagService, DevToolbarIconComponent, DevToolbarLanguageService, DevToolbarPermissionsService, DevToolbarPermissionsToolComponent, DevToolbarPresetsService, DevToolbarPresetsToolComponent, DevToolbarToolComponent };
|
|
3039
4974
|
//# sourceMappingURL=ngx-dev-toolbar.mjs.map
|