ngx-dev-toolbar 1.0.4 → 1.0.5
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.component.d.ts +1 -1
- 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/fesm2022/ngx-dev-toolbar.mjs +1656 -125
- package/fesm2022/ngx-dev-toolbar.mjs.map +1 -1
- package/index.d.ts +9 -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/network-mocker-tool/network-mocker-tool.component.d.ts +23 -0
- package/tools/network-mocker-tool/network-mocker.models.d.ts +16 -0
- package/tools/network-mocker-tool/network-mocker.service.d.ts +16 -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
|
@@ -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') {
|
|
@@ -1575,7 +1729,7 @@ class DevToolbarWindowComponent {
|
|
|
1575
1729
|
<ng-content></ng-content>
|
|
1576
1730
|
</div>
|
|
1577
1731
|
</div>
|
|
1578
|
-
`, 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}:host{display:block;width:100%}.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__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)}.header__content{display:flex;flex-direction:column}.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"] }); }
|
|
1732
|
+
`, 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}:host{display:block;width:100%}.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__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%}.header__content{display:flex;flex-direction:column}.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"] }); }
|
|
1579
1733
|
}
|
|
1580
1734
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarWindowComponent, decorators: [{
|
|
1581
1735
|
type: Component,
|
|
@@ -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: [".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}:host{display:block;width:100%}.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__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)}.header__content{display:flex;flex-direction:column}.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"] }]
|
|
1774
|
+
`, 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}:host{display:block;width:100%}.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__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%}.header__content{display:flex;flex-direction:column}.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 {
|
|
@@ -2076,172 +2230,641 @@ 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
|
/>
|
|
2243
|
-
|
|
2244
|
-
|
|
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:.65}.header .filter-wrapper{flex:.35;display:flex;align-items:center;gap:var(--ndt-spacing-xs)}.header .filter-wrapper .filter-icon{width:18px;height:18px;flex-shrink:0;opacity:.6}.header .filter-wrapper ndt-select{flex:1}.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:.65}.header .filter-wrapper{flex:.35;display:flex;align-items:center;gap:var(--ndt-spacing-xs)}.header .filter-wrapper .filter-icon{width:18px;height:18px;flex-shrink:0;opacity:.6}.header .filter-wrapper ndt-select{flex:1}.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
|
+
}));
|
|
2718
|
+
}));
|
|
2719
|
+
this.flags = toSignal(this.flags$, { initialValue: [] });
|
|
2720
|
+
this.loadForcedFlags();
|
|
2721
|
+
}
|
|
2722
|
+
setAppFlags(flags) {
|
|
2723
|
+
this.appFlags$.next(flags);
|
|
2724
|
+
}
|
|
2725
|
+
getAppFlags() {
|
|
2726
|
+
return this.appFlags$.asObservable();
|
|
2727
|
+
}
|
|
2728
|
+
getForcedFlags() {
|
|
2729
|
+
return this.flags$.pipe(map((flags) => flags.filter((flag) => flag.isForced)));
|
|
2730
|
+
}
|
|
2731
|
+
setFlag(flagId, isEnabled) {
|
|
2732
|
+
const { enabled, disabled } = this.forcedFlagsSubject.value;
|
|
2733
|
+
const newEnabled = enabled.filter((id) => id !== flagId);
|
|
2734
|
+
const newDisabled = disabled.filter((id) => id !== flagId);
|
|
2735
|
+
if (isEnabled) {
|
|
2736
|
+
newEnabled.push(flagId);
|
|
2737
|
+
}
|
|
2738
|
+
else {
|
|
2739
|
+
newDisabled.push(flagId);
|
|
2740
|
+
}
|
|
2741
|
+
const newState = { enabled: newEnabled, disabled: newDisabled };
|
|
2742
|
+
this.forcedFlagsSubject.next(newState);
|
|
2743
|
+
this.storageService.set(this.STORAGE_KEY, newState);
|
|
2744
|
+
}
|
|
2745
|
+
removeFlagOverride(flagId) {
|
|
2746
|
+
const { enabled, disabled } = this.forcedFlagsSubject.value;
|
|
2747
|
+
const newState = {
|
|
2748
|
+
enabled: enabled.filter((id) => id !== flagId),
|
|
2749
|
+
disabled: disabled.filter((id) => id !== flagId),
|
|
2750
|
+
};
|
|
2751
|
+
this.forcedFlagsSubject.next(newState);
|
|
2752
|
+
this.storageService.set(this.STORAGE_KEY, newState);
|
|
2753
|
+
}
|
|
2754
|
+
loadForcedFlags() {
|
|
2755
|
+
const savedFlags = this.storageService.get(this.STORAGE_KEY);
|
|
2756
|
+
if (savedFlags) {
|
|
2757
|
+
this.forcedFlagsSubject.next(savedFlags);
|
|
2758
|
+
}
|
|
2759
|
+
}
|
|
2760
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalFeatureFlagService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
2761
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalFeatureFlagService, providedIn: 'root' }); }
|
|
2762
|
+
}
|
|
2763
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalFeatureFlagService, decorators: [{
|
|
2764
|
+
type: Injectable,
|
|
2765
|
+
args: [{ providedIn: 'root' }]
|
|
2766
|
+
}], ctorParameters: () => [] });
|
|
2767
|
+
|
|
2768
|
+
class DevToolbarFeatureFlagsToolComponent {
|
|
2769
|
+
constructor() {
|
|
2770
|
+
// Injects
|
|
2771
|
+
this.featureFlags = inject(DevToolbarInternalFeatureFlagService);
|
|
2772
|
+
// Signals
|
|
2773
|
+
this.activeFilter = signal('all');
|
|
2774
|
+
this.searchQuery = signal('');
|
|
2775
|
+
this.flags = this.featureFlags.flags;
|
|
2776
|
+
this.hasNoFlags = computed(() => this.flags().length === 0);
|
|
2777
|
+
this.filteredFlags = computed(() => {
|
|
2778
|
+
return this.flags().filter((flag) => {
|
|
2779
|
+
const searchTerm = this.searchQuery().toLowerCase();
|
|
2780
|
+
const flagName = flag.name.toLowerCase();
|
|
2781
|
+
const flagDescription = flag.description?.toLowerCase() ?? '';
|
|
2782
|
+
const matchesSearch = !this.searchQuery() ||
|
|
2783
|
+
flagName.toLowerCase().includes(searchTerm.toLowerCase()) ||
|
|
2784
|
+
flagDescription.toLowerCase().includes(searchTerm.toLowerCase());
|
|
2785
|
+
const matchesFilter = this.activeFilter() === 'all' ||
|
|
2786
|
+
(this.activeFilter() === 'forced' && flag.isForced) ||
|
|
2787
|
+
(this.activeFilter() === 'enabled' && flag.isEnabled) ||
|
|
2788
|
+
(this.activeFilter() === 'disabled' && !flag.isEnabled);
|
|
2789
|
+
return matchesSearch && matchesFilter;
|
|
2790
|
+
});
|
|
2791
|
+
});
|
|
2792
|
+
this.hasNoFilteredFlags = computed(() => this.filteredFlags().length === 0);
|
|
2793
|
+
// Other properties
|
|
2794
|
+
this.options = {
|
|
2795
|
+
title: 'Feature Flags',
|
|
2796
|
+
description: 'Manage the feature flags for your current session',
|
|
2797
|
+
isClosable: true,
|
|
2798
|
+
size: 'tall',
|
|
2799
|
+
id: 'ndt-feature-flags',
|
|
2800
|
+
isBeta: true,
|
|
2801
|
+
};
|
|
2802
|
+
this.filterOptions = [
|
|
2803
|
+
{ value: 'all', label: 'All Flags' },
|
|
2804
|
+
{ value: 'forced', label: 'Forced' },
|
|
2805
|
+
{ value: 'enabled', label: 'Enabled' },
|
|
2806
|
+
{ value: 'disabled', label: 'Disabled' },
|
|
2807
|
+
];
|
|
2808
|
+
this.flagValueOptions = [
|
|
2809
|
+
{ value: 'not-forced', label: 'Not Forced' },
|
|
2810
|
+
{ value: 'off', label: 'Forced Off' },
|
|
2811
|
+
{ value: 'on', label: 'Forced On' },
|
|
2812
|
+
];
|
|
2813
|
+
}
|
|
2814
|
+
// Public methods
|
|
2815
|
+
onFilterChange(value) {
|
|
2816
|
+
const filter = this.filterOptions.find((f) => f.value === value);
|
|
2817
|
+
if (filter) {
|
|
2818
|
+
this.activeFilter.set(filter.value);
|
|
2819
|
+
}
|
|
2820
|
+
}
|
|
2821
|
+
onFlagChange(flagId, value) {
|
|
2822
|
+
switch (value) {
|
|
2823
|
+
case 'not-forced':
|
|
2824
|
+
this.featureFlags.removeFlagOverride(flagId);
|
|
2825
|
+
break;
|
|
2826
|
+
case 'on':
|
|
2827
|
+
this.featureFlags.setFlag(flagId, true);
|
|
2828
|
+
break;
|
|
2829
|
+
case 'off':
|
|
2830
|
+
this.featureFlags.setFlag(flagId, false);
|
|
2831
|
+
break;
|
|
2832
|
+
}
|
|
2833
|
+
}
|
|
2834
|
+
onSearchChange(query) {
|
|
2835
|
+
this.searchQuery.set(query);
|
|
2836
|
+
}
|
|
2837
|
+
// Protected methods
|
|
2838
|
+
getFlagValue(flag) {
|
|
2839
|
+
if (!flag.isForced)
|
|
2840
|
+
return '';
|
|
2841
|
+
return flag.isEnabled ? 'on' : 'off';
|
|
2842
|
+
}
|
|
2843
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarFeatureFlagsToolComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2844
|
+
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: `
|
|
2845
|
+
<ndt-toolbar-tool
|
|
2846
|
+
[options]="options"
|
|
2847
|
+
title="Feature Flags"
|
|
2848
|
+
icon="toggle-left"
|
|
2849
|
+
>
|
|
2850
|
+
<div class="container">
|
|
2851
|
+
<div class="header">
|
|
2852
|
+
<ndt-input
|
|
2853
|
+
[value]="searchQuery()"
|
|
2854
|
+
(valueChange)="onSearchChange($event)"
|
|
2855
|
+
placeholder="Search..."
|
|
2856
|
+
/>
|
|
2857
|
+
<div class="filter-wrapper">
|
|
2858
|
+
<ndt-icon name="filter" class="filter-icon" />
|
|
2859
|
+
<ndt-select
|
|
2860
|
+
[value]="activeFilter()"
|
|
2861
|
+
[options]="filterOptions"
|
|
2862
|
+
[size]="'medium'"
|
|
2863
|
+
(valueChange)="onFilterChange($event)"
|
|
2864
|
+
/>
|
|
2865
|
+
</div>
|
|
2866
|
+
</div>
|
|
2867
|
+
|
|
2245
2868
|
@if (hasNoFlags()) {
|
|
2246
2869
|
<div class="empty">
|
|
2247
2870
|
<p>No flags found</p>
|
|
@@ -2272,7 +2895,7 @@ class DevToolbarFeatureFlagsToolComponent {
|
|
|
2272
2895
|
}
|
|
2273
2896
|
</div>
|
|
2274
2897
|
</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:.65}.header
|
|
2898
|
+
`, 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:.65}.header .filter-wrapper{flex:.35;display:flex;align-items:center;gap:var(--ndt-spacing-xs)}.header .filter-wrapper .filter-icon{width:18px;height:18px;flex-shrink:0;opacity:.6}.header .filter-wrapper ndt-select{flex:1}.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
2899
|
}
|
|
2277
2900
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarFeatureFlagsToolComponent, decorators: [{
|
|
2278
2901
|
type: Component,
|
|
@@ -2281,6 +2904,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2281
2904
|
DevToolbarToolComponent,
|
|
2282
2905
|
DevToolbarInputComponent,
|
|
2283
2906
|
DevToolbarSelectComponent,
|
|
2907
|
+
DevToolbarIconComponent,
|
|
2284
2908
|
], template: `
|
|
2285
2909
|
<ndt-toolbar-tool
|
|
2286
2910
|
[options]="options"
|
|
@@ -2294,12 +2918,15 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2294
2918
|
(valueChange)="onSearchChange($event)"
|
|
2295
2919
|
placeholder="Search..."
|
|
2296
2920
|
/>
|
|
2297
|
-
<
|
|
2298
|
-
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2921
|
+
<div class="filter-wrapper">
|
|
2922
|
+
<ndt-icon name="filter" class="filter-icon" />
|
|
2923
|
+
<ndt-select
|
|
2924
|
+
[value]="activeFilter()"
|
|
2925
|
+
[options]="filterOptions"
|
|
2926
|
+
[size]="'medium'"
|
|
2927
|
+
(valueChange)="onFilterChange($event)"
|
|
2928
|
+
/>
|
|
2929
|
+
</div>
|
|
2303
2930
|
</div>
|
|
2304
2931
|
|
|
2305
2932
|
@if (hasNoFlags()) {
|
|
@@ -2332,7 +2959,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2332
2959
|
}
|
|
2333
2960
|
</div>
|
|
2334
2961
|
</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:.65}.header
|
|
2962
|
+
`, 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:.65}.header .filter-wrapper{flex:.35;display:flex;align-items:center;gap:var(--ndt-spacing-xs)}.header .filter-wrapper .filter-icon{width:18px;height:18px;flex-shrink:0;opacity:.6}.header .filter-wrapper ndt-select{flex:1}.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
2963
|
}] });
|
|
2337
2964
|
|
|
2338
2965
|
class DevToolbarButtonComponent {
|
|
@@ -2883,36 +3510,671 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2883
3510
|
`, styles: [".language-select{display:flex;flex-direction:row;gap:.5rem;align-items:center;justify-content:space-between}\n"] }]
|
|
2884
3511
|
}] });
|
|
2885
3512
|
|
|
2886
|
-
class
|
|
3513
|
+
class DevToolbarNetworkMockerService {
|
|
2887
3514
|
constructor() {
|
|
2888
|
-
this.
|
|
2889
|
-
this.
|
|
2890
|
-
this.settingsService = inject(SettingsService);
|
|
2891
|
-
this.isDevMode = isDevMode();
|
|
2892
|
-
this.keyboardShortcut = fromEvent(window, 'keydown')
|
|
2893
|
-
.pipe(filter((event) => event.ctrlKey && event.shiftKey && event.key === 'D'), takeUntilDestroyed(this.destroyRef))
|
|
2894
|
-
.subscribe(() => this.toggleDevTools());
|
|
2895
|
-
this.mouseLeave = fromEvent(document, 'mouseleave')
|
|
2896
|
-
.pipe(throttleTime(3000), takeUntilDestroyed(this.destroyRef))
|
|
2897
|
-
.subscribe(() => this.onMouseLeave());
|
|
3515
|
+
this.mockRequests = signal([]);
|
|
3516
|
+
this.isMockingEnabled = signal(false);
|
|
2898
3517
|
}
|
|
2899
|
-
|
|
2900
|
-
|
|
2901
|
-
this.state.setTheme(settings.isDarkMode ? 'dark' : 'light');
|
|
3518
|
+
getMockRequests() {
|
|
3519
|
+
return this.mockRequests.asReadonly();
|
|
2902
3520
|
}
|
|
2903
|
-
|
|
2904
|
-
this.
|
|
3521
|
+
getIsMockingEnabled() {
|
|
3522
|
+
return this.isMockingEnabled.asReadonly();
|
|
2905
3523
|
}
|
|
2906
|
-
|
|
2907
|
-
|
|
3524
|
+
addMockRequest(config) {
|
|
3525
|
+
const mockRequest = {
|
|
3526
|
+
id: crypto.randomUUID(),
|
|
3527
|
+
url: config.url,
|
|
3528
|
+
method: config.method,
|
|
3529
|
+
status: config.status || 200,
|
|
3530
|
+
response: config.response || {},
|
|
3531
|
+
isActive: true,
|
|
3532
|
+
createdAt: new Date(),
|
|
3533
|
+
};
|
|
3534
|
+
this.mockRequests.update((requests) => [mockRequest, ...requests]);
|
|
2908
3535
|
}
|
|
2909
|
-
|
|
2910
|
-
this.
|
|
3536
|
+
removeMockRequest(id) {
|
|
3537
|
+
this.mockRequests.update((requests) => requests.filter((request) => request.id !== id));
|
|
2911
3538
|
}
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
3539
|
+
toggleMockRequest(id) {
|
|
3540
|
+
this.mockRequests.update((requests) => requests.map((request) => request.id === id
|
|
3541
|
+
? { ...request, isActive: !request.isActive }
|
|
3542
|
+
: request));
|
|
3543
|
+
}
|
|
3544
|
+
enableMocking() {
|
|
3545
|
+
this.isMockingEnabled.set(true);
|
|
3546
|
+
console.log('Network mocking enabled');
|
|
3547
|
+
}
|
|
3548
|
+
disableMocking() {
|
|
3549
|
+
this.isMockingEnabled.set(false);
|
|
3550
|
+
console.log('Network mocking disabled');
|
|
3551
|
+
}
|
|
3552
|
+
clearAllMocks() {
|
|
3553
|
+
this.mockRequests.set([]);
|
|
3554
|
+
this.isMockingEnabled.set(false);
|
|
3555
|
+
}
|
|
3556
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarNetworkMockerService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3557
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarNetworkMockerService, providedIn: 'root' }); }
|
|
3558
|
+
}
|
|
3559
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarNetworkMockerService, decorators: [{
|
|
3560
|
+
type: Injectable,
|
|
3561
|
+
args: [{
|
|
3562
|
+
providedIn: 'root',
|
|
3563
|
+
}]
|
|
3564
|
+
}] });
|
|
3565
|
+
|
|
3566
|
+
class DevToolbarNetworkMockerToolComponent {
|
|
3567
|
+
constructor() {
|
|
3568
|
+
// Injects
|
|
3569
|
+
this.networkMockerService = inject(DevToolbarNetworkMockerService);
|
|
3570
|
+
// Signals
|
|
3571
|
+
this.newMockUrl = signal('');
|
|
3572
|
+
this.newMockMethod = signal('GET');
|
|
3573
|
+
this.newMockStatus = signal('200');
|
|
3574
|
+
this.newMockResponse = signal('');
|
|
3575
|
+
// Computed values
|
|
3576
|
+
this.mockRequests = this.networkMockerService.getMockRequests();
|
|
3577
|
+
this.isMockingEnabled = this.networkMockerService.getIsMockingEnabled();
|
|
3578
|
+
this.hasNoMocks = computed(() => this.mockRequests().length === 0);
|
|
3579
|
+
// Window options
|
|
3580
|
+
this.options = {
|
|
3581
|
+
title: 'Network Mocker',
|
|
3582
|
+
description: 'Intercept and mock HTTP requests for testing and development',
|
|
3583
|
+
isClosable: true,
|
|
3584
|
+
size: 'tall',
|
|
3585
|
+
id: 'ndt-network-mocker',
|
|
3586
|
+
isBeta: true,
|
|
3587
|
+
};
|
|
3588
|
+
// Other properties
|
|
3589
|
+
this.httpMethods = [
|
|
3590
|
+
{ value: 'GET', label: 'GET' },
|
|
3591
|
+
{ value: 'POST', label: 'POST' },
|
|
3592
|
+
{ value: 'PUT', label: 'PUT' },
|
|
3593
|
+
{ value: 'DELETE', label: 'DELETE' },
|
|
3594
|
+
{ value: 'PATCH', label: 'PATCH' },
|
|
3595
|
+
];
|
|
3596
|
+
}
|
|
3597
|
+
// Public methods
|
|
3598
|
+
onAddMock() {
|
|
3599
|
+
const url = this.newMockUrl().trim();
|
|
3600
|
+
if (!url)
|
|
3601
|
+
return;
|
|
3602
|
+
const config = {
|
|
3603
|
+
url,
|
|
3604
|
+
method: this.newMockMethod(),
|
|
3605
|
+
status: parseInt(this.newMockStatus()) || 200,
|
|
3606
|
+
response: this.newMockResponse()
|
|
3607
|
+
? JSON.parse(this.newMockResponse())
|
|
3608
|
+
: {},
|
|
3609
|
+
};
|
|
3610
|
+
this.networkMockerService.addMockRequest(config);
|
|
3611
|
+
// Reset form
|
|
3612
|
+
this.newMockUrl.set('');
|
|
3613
|
+
this.newMockMethod.set('GET');
|
|
3614
|
+
this.newMockStatus.set('200');
|
|
3615
|
+
this.newMockResponse.set('');
|
|
3616
|
+
}
|
|
3617
|
+
onToggleMocking() {
|
|
3618
|
+
if (this.isMockingEnabled()) {
|
|
3619
|
+
this.networkMockerService.disableMocking();
|
|
3620
|
+
}
|
|
3621
|
+
else {
|
|
3622
|
+
this.networkMockerService.enableMocking();
|
|
3623
|
+
}
|
|
3624
|
+
}
|
|
3625
|
+
onToggleMock(mockId) {
|
|
3626
|
+
this.networkMockerService.toggleMockRequest(mockId);
|
|
3627
|
+
}
|
|
3628
|
+
onRemoveMock(mockId) {
|
|
3629
|
+
this.networkMockerService.removeMockRequest(mockId);
|
|
3630
|
+
}
|
|
3631
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarNetworkMockerToolComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3632
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: DevToolbarNetworkMockerToolComponent, isStandalone: true, selector: "ndt-network-mocker-tool", ngImport: i0, template: `
|
|
3633
|
+
<ndt-toolbar-tool [options]="options" title="Network Mocker" icon="network">
|
|
3634
|
+
<div class="container">
|
|
3635
|
+
<div class="header">
|
|
3636
|
+
<h3>Mock Network Requests</h3>
|
|
3637
|
+
<p>Intercept and mock HTTP requests for testing and development.</p>
|
|
3638
|
+
</div>
|
|
3639
|
+
|
|
3640
|
+
<div class="form">
|
|
3641
|
+
<div class="form-row">
|
|
3642
|
+
<ndt-input
|
|
3643
|
+
[(value)]="newMockUrl"
|
|
3644
|
+
placeholder="Enter URL pattern (e.g., /api/users/*)"
|
|
3645
|
+
ariaLabel="Mock URL"
|
|
3646
|
+
/>
|
|
3647
|
+
<ndt-select
|
|
3648
|
+
[(value)]="newMockMethod"
|
|
3649
|
+
[options]="httpMethods"
|
|
3650
|
+
size="small"
|
|
3651
|
+
ariaLabel="HTTP Method"
|
|
3652
|
+
/>
|
|
3653
|
+
</div>
|
|
3654
|
+
|
|
3655
|
+
<div class="form-row">
|
|
3656
|
+
<ndt-input
|
|
3657
|
+
[(value)]="newMockStatus"
|
|
3658
|
+
placeholder="Status code (default: 200)"
|
|
3659
|
+
type="number"
|
|
3660
|
+
ariaLabel="Status Code"
|
|
3661
|
+
/>
|
|
3662
|
+
<ndt-input
|
|
3663
|
+
[(value)]="newMockResponse"
|
|
3664
|
+
placeholder="Response JSON (optional)"
|
|
3665
|
+
ariaLabel="Response JSON"
|
|
3666
|
+
/>
|
|
3667
|
+
</div>
|
|
3668
|
+
|
|
3669
|
+
<div class="actions">
|
|
3670
|
+
<ndt-button label="Add Mock" icon="import" (click)="onAddMock()" />
|
|
3671
|
+
<ndt-button
|
|
3672
|
+
[label]="
|
|
3673
|
+
isMockingEnabled() ? 'Disable Mocking' : 'Enable Mocking'
|
|
3674
|
+
"
|
|
3675
|
+
[icon]="isMockingEnabled() ? 'trash' : 'network'"
|
|
3676
|
+
(click)="onToggleMocking()"
|
|
3677
|
+
/>
|
|
3678
|
+
</div>
|
|
3679
|
+
</div>
|
|
3680
|
+
|
|
3681
|
+
@if (hasNoMocks()) {
|
|
3682
|
+
<div class="empty">
|
|
3683
|
+
<p>No mock requests configured. Add your first mock above.</p>
|
|
3684
|
+
</div>
|
|
3685
|
+
} @else {
|
|
3686
|
+
<div class="mocks-list">
|
|
3687
|
+
<h4>Configured Mocks</h4>
|
|
3688
|
+
@for (mock of mockRequests(); track mock.id) {
|
|
3689
|
+
<div class="mock-item">
|
|
3690
|
+
<div class="mock-info">
|
|
3691
|
+
<div class="mock-method">{{ mock.method }}</div>
|
|
3692
|
+
<div class="mock-url">{{ mock.url }}</div>
|
|
3693
|
+
<div class="mock-status">{{ mock.status }}</div>
|
|
3694
|
+
</div>
|
|
3695
|
+
<div class="mock-actions">
|
|
3696
|
+
<ndt-button
|
|
3697
|
+
variant="icon"
|
|
3698
|
+
[icon]="mock.isActive ? 'star' : 'moon'"
|
|
3699
|
+
[ariaLabel]="mock.isActive ? 'Disable mock' : 'Enable mock'"
|
|
3700
|
+
(click)="onToggleMock(mock.id)"
|
|
3701
|
+
/>
|
|
3702
|
+
<ndt-button
|
|
3703
|
+
variant="icon"
|
|
3704
|
+
icon="trash"
|
|
3705
|
+
ariaLabel="Remove mock"
|
|
3706
|
+
(click)="onRemoveMock(mock.id)"
|
|
3707
|
+
/>
|
|
3708
|
+
</div>
|
|
3709
|
+
</div>
|
|
3710
|
+
}
|
|
3711
|
+
</div>
|
|
3712
|
+
} @if (isMockingEnabled()) {
|
|
3713
|
+
<div class="status">
|
|
3714
|
+
<p>✅ Network mocking is active</p>
|
|
3715
|
+
</div>
|
|
3716
|
+
}
|
|
3717
|
+
</div>
|
|
3718
|
+
</ndt-toolbar-tool>
|
|
3719
|
+
`, isInline: true, styles: [".container{display:flex;flex-direction:column;height:100%;gap:var(--ndt-spacing-md);padding:var(--ndt-spacing-md)}.header{text-align:center;flex-shrink:0}.header h3{margin:0 0 var(--ndt-spacing-sm) 0;font-size:var(--ndt-font-size-lg);color:var(--ndt-text-primary);font-weight:600}.header p{margin:0;font-size:var(--ndt-font-size-sm);color:var(--ndt-text-muted)}.form{display:flex;flex-direction:column;gap:var(--ndt-spacing-sm);flex-shrink:0;padding:var(--ndt-spacing-md);background:var(--ndt-background-secondary);border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-medium)}.form-row{display:flex;gap:var(--ndt-spacing-sm)}.form-row ndt-input{flex:1}.form-row ndt-select{flex:0 0 120px}.actions{display:flex;gap:var(--ndt-spacing-sm);margin-top:var(--ndt-spacing-sm)}.empty{display:flex;align-items:center;justify-content:center;flex:1;color:var(--ndt-text-muted);text-align:center;font-size:var(--ndt-font-size-sm)}.mocks-list{display:flex;flex-direction:column;gap:var(--ndt-spacing-sm);flex:1;min-height:0;overflow-y:auto}.mocks-list h4{margin:0 0 var(--ndt-spacing-sm) 0;font-size:var(--ndt-font-size-md);color:var(--ndt-text-primary);font-weight:600}.mocks-list::-webkit-scrollbar{width:8px}.mocks-list::-webkit-scrollbar-track{background:var(--ndt-background-secondary);border-radius:4px}.mocks-list::-webkit-scrollbar-thumb{background:var(--ndt-border-primary);border-radius:4px}:is():hover{background:var(--ndt-hover-bg)}.mock-item{display:flex;align-items:center;gap:var(--ndt-spacing-sm);padding:var(--ndt-spacing-sm);background:var(--ndt-background-secondary);border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-small)}.mock-item .mock-info{flex:1;display:flex;align-items:center;gap:var(--ndt-spacing-sm)}.mock-item .mock-method{font-weight:600;font-size:var(--ndt-font-size-xs);color:var(--ndt-primary);background:var(--ndt-primary-background);padding:2px 6px;border-radius:var(--ndt-border-radius-small);min-width:40px;text-align:center}.mock-item .mock-url{flex:1;font-size:var(--ndt-font-size-sm);color:var(--ndt-text-primary);font-family:monospace}.mock-item .mock-status{font-size:var(--ndt-font-size-xs);color:var(--ndt-text-muted);min-width:30px;text-align:center}.mock-item .mock-actions{display:flex;gap:var(--ndt-spacing-xs)}.status{text-align:center;padding:var(--ndt-spacing-sm) var(--ndt-spacing-md);background:var(--ndt-success-background);border:1px solid var(--ndt-success-border);border-radius:var(--ndt-border-radius-small);color:var(--ndt-success-text);font-size:var(--ndt-font-size-sm);flex-shrink:0}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "component", type: DevToolbarToolComponent, selector: "ndt-toolbar-tool", inputs: ["options", "icon", "title"] }, { kind: "component", type: DevToolbarButtonComponent, selector: "ndt-button", inputs: ["type", "variant", "icon", "label", "ariaLabel", "isActive"] }, { 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"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3720
|
+
}
|
|
3721
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarNetworkMockerToolComponent, decorators: [{
|
|
3722
|
+
type: Component,
|
|
3723
|
+
args: [{ selector: 'ndt-network-mocker-tool', standalone: true, imports: [
|
|
3724
|
+
FormsModule,
|
|
3725
|
+
DevToolbarToolComponent,
|
|
3726
|
+
DevToolbarButtonComponent,
|
|
3727
|
+
DevToolbarInputComponent,
|
|
3728
|
+
DevToolbarSelectComponent,
|
|
3729
|
+
], template: `
|
|
3730
|
+
<ndt-toolbar-tool [options]="options" title="Network Mocker" icon="network">
|
|
3731
|
+
<div class="container">
|
|
3732
|
+
<div class="header">
|
|
3733
|
+
<h3>Mock Network Requests</h3>
|
|
3734
|
+
<p>Intercept and mock HTTP requests for testing and development.</p>
|
|
3735
|
+
</div>
|
|
3736
|
+
|
|
3737
|
+
<div class="form">
|
|
3738
|
+
<div class="form-row">
|
|
3739
|
+
<ndt-input
|
|
3740
|
+
[(value)]="newMockUrl"
|
|
3741
|
+
placeholder="Enter URL pattern (e.g., /api/users/*)"
|
|
3742
|
+
ariaLabel="Mock URL"
|
|
3743
|
+
/>
|
|
3744
|
+
<ndt-select
|
|
3745
|
+
[(value)]="newMockMethod"
|
|
3746
|
+
[options]="httpMethods"
|
|
3747
|
+
size="small"
|
|
3748
|
+
ariaLabel="HTTP Method"
|
|
3749
|
+
/>
|
|
3750
|
+
</div>
|
|
3751
|
+
|
|
3752
|
+
<div class="form-row">
|
|
3753
|
+
<ndt-input
|
|
3754
|
+
[(value)]="newMockStatus"
|
|
3755
|
+
placeholder="Status code (default: 200)"
|
|
3756
|
+
type="number"
|
|
3757
|
+
ariaLabel="Status Code"
|
|
3758
|
+
/>
|
|
3759
|
+
<ndt-input
|
|
3760
|
+
[(value)]="newMockResponse"
|
|
3761
|
+
placeholder="Response JSON (optional)"
|
|
3762
|
+
ariaLabel="Response JSON"
|
|
3763
|
+
/>
|
|
3764
|
+
</div>
|
|
3765
|
+
|
|
3766
|
+
<div class="actions">
|
|
3767
|
+
<ndt-button label="Add Mock" icon="import" (click)="onAddMock()" />
|
|
3768
|
+
<ndt-button
|
|
3769
|
+
[label]="
|
|
3770
|
+
isMockingEnabled() ? 'Disable Mocking' : 'Enable Mocking'
|
|
3771
|
+
"
|
|
3772
|
+
[icon]="isMockingEnabled() ? 'trash' : 'network'"
|
|
3773
|
+
(click)="onToggleMocking()"
|
|
3774
|
+
/>
|
|
3775
|
+
</div>
|
|
3776
|
+
</div>
|
|
3777
|
+
|
|
3778
|
+
@if (hasNoMocks()) {
|
|
3779
|
+
<div class="empty">
|
|
3780
|
+
<p>No mock requests configured. Add your first mock above.</p>
|
|
3781
|
+
</div>
|
|
3782
|
+
} @else {
|
|
3783
|
+
<div class="mocks-list">
|
|
3784
|
+
<h4>Configured Mocks</h4>
|
|
3785
|
+
@for (mock of mockRequests(); track mock.id) {
|
|
3786
|
+
<div class="mock-item">
|
|
3787
|
+
<div class="mock-info">
|
|
3788
|
+
<div class="mock-method">{{ mock.method }}</div>
|
|
3789
|
+
<div class="mock-url">{{ mock.url }}</div>
|
|
3790
|
+
<div class="mock-status">{{ mock.status }}</div>
|
|
3791
|
+
</div>
|
|
3792
|
+
<div class="mock-actions">
|
|
3793
|
+
<ndt-button
|
|
3794
|
+
variant="icon"
|
|
3795
|
+
[icon]="mock.isActive ? 'star' : 'moon'"
|
|
3796
|
+
[ariaLabel]="mock.isActive ? 'Disable mock' : 'Enable mock'"
|
|
3797
|
+
(click)="onToggleMock(mock.id)"
|
|
3798
|
+
/>
|
|
3799
|
+
<ndt-button
|
|
3800
|
+
variant="icon"
|
|
3801
|
+
icon="trash"
|
|
3802
|
+
ariaLabel="Remove mock"
|
|
3803
|
+
(click)="onRemoveMock(mock.id)"
|
|
3804
|
+
/>
|
|
3805
|
+
</div>
|
|
3806
|
+
</div>
|
|
3807
|
+
}
|
|
3808
|
+
</div>
|
|
3809
|
+
} @if (isMockingEnabled()) {
|
|
3810
|
+
<div class="status">
|
|
3811
|
+
<p>✅ Network mocking is active</p>
|
|
3812
|
+
</div>
|
|
3813
|
+
}
|
|
3814
|
+
</div>
|
|
3815
|
+
</ndt-toolbar-tool>
|
|
3816
|
+
`, changeDetection: ChangeDetectionStrategy.OnPush, styles: [".container{display:flex;flex-direction:column;height:100%;gap:var(--ndt-spacing-md);padding:var(--ndt-spacing-md)}.header{text-align:center;flex-shrink:0}.header h3{margin:0 0 var(--ndt-spacing-sm) 0;font-size:var(--ndt-font-size-lg);color:var(--ndt-text-primary);font-weight:600}.header p{margin:0;font-size:var(--ndt-font-size-sm);color:var(--ndt-text-muted)}.form{display:flex;flex-direction:column;gap:var(--ndt-spacing-sm);flex-shrink:0;padding:var(--ndt-spacing-md);background:var(--ndt-background-secondary);border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-medium)}.form-row{display:flex;gap:var(--ndt-spacing-sm)}.form-row ndt-input{flex:1}.form-row ndt-select{flex:0 0 120px}.actions{display:flex;gap:var(--ndt-spacing-sm);margin-top:var(--ndt-spacing-sm)}.empty{display:flex;align-items:center;justify-content:center;flex:1;color:var(--ndt-text-muted);text-align:center;font-size:var(--ndt-font-size-sm)}.mocks-list{display:flex;flex-direction:column;gap:var(--ndt-spacing-sm);flex:1;min-height:0;overflow-y:auto}.mocks-list h4{margin:0 0 var(--ndt-spacing-sm) 0;font-size:var(--ndt-font-size-md);color:var(--ndt-text-primary);font-weight:600}.mocks-list::-webkit-scrollbar{width:8px}.mocks-list::-webkit-scrollbar-track{background:var(--ndt-background-secondary);border-radius:4px}.mocks-list::-webkit-scrollbar-thumb{background:var(--ndt-border-primary);border-radius:4px}:is():hover{background:var(--ndt-hover-bg)}.mock-item{display:flex;align-items:center;gap:var(--ndt-spacing-sm);padding:var(--ndt-spacing-sm);background:var(--ndt-background-secondary);border:1px solid var(--ndt-border-primary);border-radius:var(--ndt-border-radius-small)}.mock-item .mock-info{flex:1;display:flex;align-items:center;gap:var(--ndt-spacing-sm)}.mock-item .mock-method{font-weight:600;font-size:var(--ndt-font-size-xs);color:var(--ndt-primary);background:var(--ndt-primary-background);padding:2px 6px;border-radius:var(--ndt-border-radius-small);min-width:40px;text-align:center}.mock-item .mock-url{flex:1;font-size:var(--ndt-font-size-sm);color:var(--ndt-text-primary);font-family:monospace}.mock-item .mock-status{font-size:var(--ndt-font-size-xs);color:var(--ndt-text-muted);min-width:30px;text-align:center}.mock-item .mock-actions{display:flex;gap:var(--ndt-spacing-xs)}.status{text-align:center;padding:var(--ndt-spacing-sm) var(--ndt-spacing-md);background:var(--ndt-success-background);border:1px solid var(--ndt-success-border);border-radius:var(--ndt-border-radius-small);color:var(--ndt-success-text);font-size:var(--ndt-font-size-sm);flex-shrink:0}\n"] }]
|
|
3817
|
+
}] });
|
|
3818
|
+
|
|
3819
|
+
class DevToolbarInternalPermissionsService {
|
|
3820
|
+
constructor() {
|
|
3821
|
+
this.STORAGE_KEY = 'permissions';
|
|
3822
|
+
this.storageService = inject(DevToolsStorageService);
|
|
3823
|
+
this.appPermissions$ = new BehaviorSubject([]);
|
|
3824
|
+
this.forcedStateSubject = new BehaviorSubject({
|
|
3825
|
+
granted: [],
|
|
3826
|
+
denied: [],
|
|
3827
|
+
});
|
|
3828
|
+
this.forcedState$ = this.forcedStateSubject.asObservable();
|
|
3829
|
+
this.permissions$ = combineLatest([
|
|
3830
|
+
this.appPermissions$,
|
|
3831
|
+
this.forcedState$,
|
|
3832
|
+
]).pipe(map(([appPermissions, { granted, denied }]) => {
|
|
3833
|
+
return appPermissions.map((permission) => ({
|
|
3834
|
+
...permission,
|
|
3835
|
+
isForced: granted.includes(permission.id) || denied.includes(permission.id),
|
|
3836
|
+
isGranted: granted.includes(permission.id)
|
|
3837
|
+
? true
|
|
3838
|
+
: denied.includes(permission.id)
|
|
3839
|
+
? false
|
|
3840
|
+
: permission.isGranted,
|
|
3841
|
+
}));
|
|
3842
|
+
}));
|
|
3843
|
+
this.permissions = toSignal(this.permissions$, { initialValue: [] });
|
|
3844
|
+
this.loadForcedState();
|
|
3845
|
+
}
|
|
3846
|
+
setAppPermissions(permissions) {
|
|
3847
|
+
this.appPermissions$.next(permissions);
|
|
3848
|
+
this.validateAndCleanForcedState(permissions);
|
|
3849
|
+
}
|
|
3850
|
+
setPermission(id, granted) {
|
|
3851
|
+
const { granted: grantedIds, denied: deniedIds } = this.forcedStateSubject.value;
|
|
3852
|
+
const newGranted = grantedIds.filter((permId) => permId !== id);
|
|
3853
|
+
const newDenied = deniedIds.filter((permId) => permId !== id);
|
|
3854
|
+
if (granted) {
|
|
3855
|
+
newGranted.push(id);
|
|
3856
|
+
}
|
|
3857
|
+
else {
|
|
3858
|
+
newDenied.push(id);
|
|
3859
|
+
}
|
|
3860
|
+
const newState = { granted: newGranted, denied: newDenied };
|
|
3861
|
+
this.forcedStateSubject.next(newState);
|
|
3862
|
+
this.storageService.set(this.STORAGE_KEY, newState);
|
|
3863
|
+
}
|
|
3864
|
+
removePermissionOverride(id) {
|
|
3865
|
+
const { granted, denied } = this.forcedStateSubject.value;
|
|
3866
|
+
const newState = {
|
|
3867
|
+
granted: granted.filter((permId) => permId !== id),
|
|
3868
|
+
denied: denied.filter((permId) => permId !== id),
|
|
3869
|
+
};
|
|
3870
|
+
this.forcedStateSubject.next(newState);
|
|
3871
|
+
this.storageService.set(this.STORAGE_KEY, newState);
|
|
3872
|
+
}
|
|
3873
|
+
getForcedPermissions() {
|
|
3874
|
+
return this.permissions$.pipe(map((permissions) => permissions.filter((permission) => permission.isForced)));
|
|
3875
|
+
}
|
|
3876
|
+
/**
|
|
3877
|
+
* Apply a preset permissions state, replacing the current forced state.
|
|
3878
|
+
* Useful for automated testing or restoring saved configurations.
|
|
3879
|
+
* @param state The preset forced permissions state to apply
|
|
3880
|
+
*/
|
|
3881
|
+
applyPresetPermissions(state) {
|
|
3882
|
+
this.forcedStateSubject.next(state);
|
|
3883
|
+
this.storageService.set(this.STORAGE_KEY, state);
|
|
3884
|
+
}
|
|
3885
|
+
/**
|
|
3886
|
+
* Get the current forced permissions state.
|
|
3887
|
+
* Returns a deep copy to prevent external mutations.
|
|
3888
|
+
* @returns Current forced permissions state
|
|
3889
|
+
*/
|
|
3890
|
+
getCurrentForcedState() {
|
|
3891
|
+
const currentState = this.forcedStateSubject.value;
|
|
3892
|
+
return {
|
|
3893
|
+
granted: [...currentState.granted],
|
|
3894
|
+
denied: [...currentState.denied],
|
|
3895
|
+
};
|
|
3896
|
+
}
|
|
3897
|
+
loadForcedState() {
|
|
3898
|
+
try {
|
|
3899
|
+
const savedState = this.storageService.get(this.STORAGE_KEY);
|
|
3900
|
+
if (savedState && this.isValidForcedState(savedState)) {
|
|
3901
|
+
this.forcedStateSubject.next(savedState);
|
|
3902
|
+
}
|
|
3903
|
+
}
|
|
3904
|
+
catch (error) {
|
|
3905
|
+
console.warn('Error loading forced permissions state from localStorage:', error);
|
|
3906
|
+
}
|
|
3907
|
+
}
|
|
3908
|
+
isValidForcedState(state) {
|
|
3909
|
+
return (state &&
|
|
3910
|
+
typeof state === 'object' &&
|
|
3911
|
+
Array.isArray(state.granted) &&
|
|
3912
|
+
Array.isArray(state.denied));
|
|
3913
|
+
}
|
|
3914
|
+
validateAndCleanForcedState(permissions) {
|
|
3915
|
+
const currentState = this.forcedStateSubject.value;
|
|
3916
|
+
const validIds = new Set(permissions.map((p) => p.id));
|
|
3917
|
+
const cleanedGranted = currentState.granted.filter((id) => validIds.has(id));
|
|
3918
|
+
const cleanedDenied = currentState.denied.filter((id) => validIds.has(id));
|
|
3919
|
+
const hasInvalidIds = cleanedGranted.length !== currentState.granted.length ||
|
|
3920
|
+
cleanedDenied.length !== currentState.denied.length;
|
|
3921
|
+
if (hasInvalidIds) {
|
|
3922
|
+
const cleanedState = {
|
|
3923
|
+
granted: cleanedGranted,
|
|
3924
|
+
denied: cleanedDenied,
|
|
3925
|
+
};
|
|
3926
|
+
this.forcedStateSubject.next(cleanedState);
|
|
3927
|
+
this.storageService.set(this.STORAGE_KEY, cleanedState);
|
|
3928
|
+
const invalidIds = [
|
|
3929
|
+
...currentState.granted.filter((id) => !validIds.has(id)),
|
|
3930
|
+
...currentState.denied.filter((id) => !validIds.has(id)),
|
|
3931
|
+
];
|
|
3932
|
+
if (invalidIds.length > 0) {
|
|
3933
|
+
console.warn('Removed invalid permission IDs from forced state:', invalidIds);
|
|
3934
|
+
}
|
|
3935
|
+
}
|
|
3936
|
+
}
|
|
3937
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalPermissionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
3938
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalPermissionsService, providedIn: 'root' }); }
|
|
3939
|
+
}
|
|
3940
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarInternalPermissionsService, decorators: [{
|
|
3941
|
+
type: Injectable,
|
|
3942
|
+
args: [{ providedIn: 'root' }]
|
|
3943
|
+
}], ctorParameters: () => [] });
|
|
3944
|
+
|
|
3945
|
+
class DevToolbarPermissionsToolComponent {
|
|
3946
|
+
constructor() {
|
|
3947
|
+
// Injects
|
|
3948
|
+
this.permissionsService = inject(DevToolbarInternalPermissionsService);
|
|
3949
|
+
// Signals
|
|
3950
|
+
this.activeFilter = signal('all');
|
|
3951
|
+
this.searchQuery = signal('');
|
|
3952
|
+
this.permissions = this.permissionsService.permissions;
|
|
3953
|
+
this.hasNoPermissions = computed(() => this.permissions().length === 0);
|
|
3954
|
+
this.filteredPermissions = computed(() => {
|
|
3955
|
+
return this.permissions().filter((permission) => {
|
|
3956
|
+
const searchTerm = this.searchQuery().toLowerCase();
|
|
3957
|
+
const permissionName = permission.name.toLowerCase();
|
|
3958
|
+
const permissionDescription = permission.description?.toLowerCase() ?? '';
|
|
3959
|
+
const matchesSearch = !this.searchQuery() ||
|
|
3960
|
+
permissionName.includes(searchTerm) ||
|
|
3961
|
+
permissionDescription.includes(searchTerm);
|
|
3962
|
+
const matchesFilter = this.activeFilter() === 'all' ||
|
|
3963
|
+
(this.activeFilter() === 'forced' && permission.isForced) ||
|
|
3964
|
+
(this.activeFilter() === 'granted' && permission.isGranted) ||
|
|
3965
|
+
(this.activeFilter() === 'denied' && !permission.isGranted);
|
|
3966
|
+
return matchesSearch && matchesFilter;
|
|
3967
|
+
});
|
|
3968
|
+
});
|
|
3969
|
+
this.hasNoFilteredPermissions = computed(() => this.filteredPermissions().length === 0);
|
|
3970
|
+
// Other properties
|
|
3971
|
+
this.options = {
|
|
3972
|
+
title: 'Permissions',
|
|
3973
|
+
description: 'Manage permission overrides for your current session',
|
|
3974
|
+
isClosable: true,
|
|
3975
|
+
size: 'tall',
|
|
3976
|
+
id: 'ndt-permissions',
|
|
3977
|
+
isBeta: true,
|
|
3978
|
+
};
|
|
3979
|
+
this.filterOptions = [
|
|
3980
|
+
{ value: 'all', label: 'All Permissions' },
|
|
3981
|
+
{ value: 'forced', label: 'Forced' },
|
|
3982
|
+
{ value: 'granted', label: 'Granted' },
|
|
3983
|
+
{ value: 'denied', label: 'Denied' },
|
|
3984
|
+
];
|
|
3985
|
+
this.permissionValueOptions = [
|
|
3986
|
+
{ value: 'not-forced', label: 'Not Forced' },
|
|
3987
|
+
{ value: 'denied', label: 'Forced Denied' },
|
|
3988
|
+
{ value: 'granted', label: 'Forced Granted' },
|
|
3989
|
+
];
|
|
3990
|
+
}
|
|
3991
|
+
// Public methods
|
|
3992
|
+
onFilterChange(value) {
|
|
3993
|
+
const filter = this.filterOptions.find((f) => f.value === value);
|
|
3994
|
+
if (filter) {
|
|
3995
|
+
this.activeFilter.set(filter.value);
|
|
3996
|
+
}
|
|
3997
|
+
}
|
|
3998
|
+
onPermissionChange(id, value) {
|
|
3999
|
+
switch (value) {
|
|
4000
|
+
case 'not-forced':
|
|
4001
|
+
this.permissionsService.removePermissionOverride(id);
|
|
4002
|
+
break;
|
|
4003
|
+
case 'granted':
|
|
4004
|
+
this.permissionsService.setPermission(id, true);
|
|
4005
|
+
break;
|
|
4006
|
+
case 'denied':
|
|
4007
|
+
this.permissionsService.setPermission(id, false);
|
|
4008
|
+
break;
|
|
4009
|
+
}
|
|
4010
|
+
}
|
|
4011
|
+
onSearchChange(query) {
|
|
4012
|
+
this.searchQuery.set(query);
|
|
4013
|
+
}
|
|
4014
|
+
// Protected methods
|
|
4015
|
+
getPermissionValue(permission) {
|
|
4016
|
+
if (!permission.isForced)
|
|
4017
|
+
return '';
|
|
4018
|
+
return permission.isGranted ? 'granted' : 'denied';
|
|
4019
|
+
}
|
|
4020
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPermissionsToolComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4021
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: DevToolbarPermissionsToolComponent, isStandalone: true, selector: "ndt-permissions-tool", ngImport: i0, template: `
|
|
4022
|
+
<ndt-toolbar-tool
|
|
4023
|
+
[options]="options"
|
|
4024
|
+
title="Permissions"
|
|
4025
|
+
icon="lock"
|
|
4026
|
+
>
|
|
4027
|
+
<div class="container">
|
|
4028
|
+
<div class="header">
|
|
4029
|
+
<ndt-input
|
|
4030
|
+
[value]="searchQuery()"
|
|
4031
|
+
(valueChange)="onSearchChange($event)"
|
|
4032
|
+
placeholder="Search permissions..."
|
|
4033
|
+
[ariaLabel]="'Search permissions'"
|
|
4034
|
+
/>
|
|
4035
|
+
<div class="filter-wrapper">
|
|
4036
|
+
<ndt-icon name="filter" class="filter-icon" />
|
|
4037
|
+
<ndt-select
|
|
4038
|
+
[value]="activeFilter()"
|
|
4039
|
+
[options]="filterOptions"
|
|
4040
|
+
[size]="'medium'"
|
|
4041
|
+
(valueChange)="onFilterChange($event)"
|
|
4042
|
+
[ariaLabel]="'Filter permissions by state'"
|
|
4043
|
+
/>
|
|
4044
|
+
</div>
|
|
4045
|
+
</div>
|
|
4046
|
+
|
|
4047
|
+
@if (hasNoPermissions()) {
|
|
4048
|
+
<div class="empty">
|
|
4049
|
+
<p>No permissions found</p>
|
|
4050
|
+
<p class="hint">Call setAvailableOptions() to configure permissions</p>
|
|
4051
|
+
</div>
|
|
4052
|
+
} @else if (hasNoFilteredPermissions()) {
|
|
4053
|
+
<div class="empty">
|
|
4054
|
+
<p>No permissions match your filter</p>
|
|
4055
|
+
</div>
|
|
4056
|
+
} @else {
|
|
4057
|
+
<div class="permission-list">
|
|
4058
|
+
@for (permission of filteredPermissions(); track permission.id) {
|
|
4059
|
+
<div class="permission">
|
|
4060
|
+
<div class="info">
|
|
4061
|
+
<h3>{{ permission.name }}</h3>
|
|
4062
|
+
<p>{{ permission?.description }}</p>
|
|
4063
|
+
</div>
|
|
4064
|
+
|
|
4065
|
+
<ndt-select
|
|
4066
|
+
[value]="getPermissionValue(permission)"
|
|
4067
|
+
[options]="permissionValueOptions"
|
|
4068
|
+
[ariaLabel]="'Override state for ' + permission.name"
|
|
4069
|
+
(valueChange)="onPermissionChange(permission.id, $event ?? '')"
|
|
4070
|
+
size="small"
|
|
4071
|
+
/>
|
|
4072
|
+
</div>
|
|
4073
|
+
}
|
|
4074
|
+
</div>
|
|
4075
|
+
}
|
|
4076
|
+
</div>
|
|
4077
|
+
</ndt-toolbar-tool>
|
|
4078
|
+
`, 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:.65}.header .filter-wrapper{flex:.35;display:flex;align-items:center;gap:var(--ndt-spacing-xs)}.header .filter-wrapper .filter-icon{width:18px;height:18px;flex-shrink:0;opacity:.6}.header .filter-wrapper ndt-select{flex:1}.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 }); }
|
|
4079
|
+
}
|
|
4080
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPermissionsToolComponent, decorators: [{
|
|
4081
|
+
type: Component,
|
|
4082
|
+
args: [{ selector: 'ndt-permissions-tool', standalone: true, imports: [
|
|
4083
|
+
FormsModule,
|
|
4084
|
+
DevToolbarToolComponent,
|
|
4085
|
+
DevToolbarInputComponent,
|
|
4086
|
+
DevToolbarSelectComponent,
|
|
4087
|
+
DevToolbarIconComponent,
|
|
4088
|
+
], template: `
|
|
4089
|
+
<ndt-toolbar-tool
|
|
4090
|
+
[options]="options"
|
|
4091
|
+
title="Permissions"
|
|
4092
|
+
icon="lock"
|
|
4093
|
+
>
|
|
4094
|
+
<div class="container">
|
|
4095
|
+
<div class="header">
|
|
4096
|
+
<ndt-input
|
|
4097
|
+
[value]="searchQuery()"
|
|
4098
|
+
(valueChange)="onSearchChange($event)"
|
|
4099
|
+
placeholder="Search permissions..."
|
|
4100
|
+
[ariaLabel]="'Search permissions'"
|
|
4101
|
+
/>
|
|
4102
|
+
<div class="filter-wrapper">
|
|
4103
|
+
<ndt-icon name="filter" class="filter-icon" />
|
|
4104
|
+
<ndt-select
|
|
4105
|
+
[value]="activeFilter()"
|
|
4106
|
+
[options]="filterOptions"
|
|
4107
|
+
[size]="'medium'"
|
|
4108
|
+
(valueChange)="onFilterChange($event)"
|
|
4109
|
+
[ariaLabel]="'Filter permissions by state'"
|
|
4110
|
+
/>
|
|
4111
|
+
</div>
|
|
4112
|
+
</div>
|
|
4113
|
+
|
|
4114
|
+
@if (hasNoPermissions()) {
|
|
4115
|
+
<div class="empty">
|
|
4116
|
+
<p>No permissions found</p>
|
|
4117
|
+
<p class="hint">Call setAvailableOptions() to configure permissions</p>
|
|
4118
|
+
</div>
|
|
4119
|
+
} @else if (hasNoFilteredPermissions()) {
|
|
4120
|
+
<div class="empty">
|
|
4121
|
+
<p>No permissions match your filter</p>
|
|
4122
|
+
</div>
|
|
4123
|
+
} @else {
|
|
4124
|
+
<div class="permission-list">
|
|
4125
|
+
@for (permission of filteredPermissions(); track permission.id) {
|
|
4126
|
+
<div class="permission">
|
|
4127
|
+
<div class="info">
|
|
4128
|
+
<h3>{{ permission.name }}</h3>
|
|
4129
|
+
<p>{{ permission?.description }}</p>
|
|
4130
|
+
</div>
|
|
4131
|
+
|
|
4132
|
+
<ndt-select
|
|
4133
|
+
[value]="getPermissionValue(permission)"
|
|
4134
|
+
[options]="permissionValueOptions"
|
|
4135
|
+
[ariaLabel]="'Override state for ' + permission.name"
|
|
4136
|
+
(valueChange)="onPermissionChange(permission.id, $event ?? '')"
|
|
4137
|
+
size="small"
|
|
4138
|
+
/>
|
|
4139
|
+
</div>
|
|
4140
|
+
}
|
|
4141
|
+
</div>
|
|
4142
|
+
}
|
|
4143
|
+
</div>
|
|
4144
|
+
</ndt-toolbar-tool>
|
|
4145
|
+
`, 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:.65}.header .filter-wrapper{flex:.35;display:flex;align-items:center;gap:var(--ndt-spacing-xs)}.header .filter-wrapper .filter-icon{width:18px;height:18px;flex-shrink:0;opacity:.6}.header .filter-wrapper ndt-select{flex:1}.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"] }]
|
|
4146
|
+
}] });
|
|
4147
|
+
|
|
4148
|
+
class DevToolbarComponent {
|
|
4149
|
+
constructor() {
|
|
4150
|
+
this.state = inject(DevToolbarStateService);
|
|
4151
|
+
this.destroyRef = inject(DestroyRef);
|
|
4152
|
+
this.settingsService = inject(SettingsService);
|
|
4153
|
+
this.isDevMode = isDevMode();
|
|
4154
|
+
this.keyboardShortcut = fromEvent(window, 'keydown')
|
|
4155
|
+
.pipe(filter((event) => event.ctrlKey && event.shiftKey && event.key === 'D'), takeUntilDestroyed(this.destroyRef))
|
|
4156
|
+
.subscribe(() => this.toggleDevTools());
|
|
4157
|
+
this.mouseLeave = fromEvent(document, 'mouseleave')
|
|
4158
|
+
.pipe(throttleTime(3000), takeUntilDestroyed(this.destroyRef))
|
|
4159
|
+
.subscribe(() => this.onMouseLeave());
|
|
4160
|
+
}
|
|
4161
|
+
ngOnInit() {
|
|
4162
|
+
const settings = this.settingsService.getSettings();
|
|
4163
|
+
this.state.setTheme(settings.isDarkMode ? 'dark' : 'light');
|
|
4164
|
+
}
|
|
4165
|
+
onMouseEnter() {
|
|
4166
|
+
this.state.setVisibility(true);
|
|
4167
|
+
}
|
|
4168
|
+
onMouseLeave() {
|
|
4169
|
+
setTimeout(() => this.state.setVisibility(false), this.state.delay());
|
|
4170
|
+
}
|
|
4171
|
+
toggleDevTools() {
|
|
4172
|
+
this.state.setVisibility(!this.state.isVisible());
|
|
4173
|
+
}
|
|
4174
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
4175
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.5", type: DevToolbarComponent, isStandalone: true, selector: "ndt-toolbar", ngImport: i0, template: `
|
|
4176
|
+
@if (isDevMode) {
|
|
4177
|
+
<div
|
|
2916
4178
|
aria-label="Developer tools"
|
|
2917
4179
|
role="toolbar"
|
|
2918
4180
|
class="dev-toolbar"
|
|
@@ -2924,10 +4186,13 @@ class DevToolbarComponent {
|
|
|
2924
4186
|
<ndt-home-tool />
|
|
2925
4187
|
<ndt-language-tool />
|
|
2926
4188
|
<ndt-feature-flags-tool />
|
|
4189
|
+
<ndt-app-features-tool />
|
|
4190
|
+
<ndt-permissions-tool />
|
|
4191
|
+
<ndt-network-mocker-tool />
|
|
2927
4192
|
<ng-content />
|
|
2928
4193
|
</div>
|
|
2929
4194
|
}
|
|
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: [
|
|
4195
|
+
`, 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" }, { kind: "component", type: DevToolbarAppFeaturesToolComponent, selector: "ndt-app-features-tool" }, { kind: "component", type: DevToolbarNetworkMockerToolComponent, selector: "ndt-network-mocker-tool" }, { kind: "component", type: DevToolbarPermissionsToolComponent, selector: "ndt-permissions-tool" }], animations: [
|
|
2931
4196
|
trigger('toolbarState', [
|
|
2932
4197
|
state('hidden', style({
|
|
2933
4198
|
transform: 'translate(-50%, calc(100% + -1.2rem))',
|
|
@@ -2947,6 +4212,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2947
4212
|
DevToolbarHomeToolComponent,
|
|
2948
4213
|
DevToolbarLanguageToolComponent,
|
|
2949
4214
|
DevToolbarFeatureFlagsToolComponent,
|
|
4215
|
+
DevToolbarAppFeaturesToolComponent,
|
|
4216
|
+
DevToolbarNetworkMockerToolComponent,
|
|
4217
|
+
DevToolbarPermissionsToolComponent,
|
|
2950
4218
|
], template: `
|
|
2951
4219
|
@if (isDevMode) {
|
|
2952
4220
|
<div
|
|
@@ -2961,6 +4229,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
2961
4229
|
<ndt-home-tool />
|
|
2962
4230
|
<ndt-language-tool />
|
|
2963
4231
|
<ndt-feature-flags-tool />
|
|
4232
|
+
<ndt-app-features-tool />
|
|
4233
|
+
<ndt-permissions-tool />
|
|
4234
|
+
<ndt-network-mocker-tool />
|
|
2964
4235
|
<ng-content />
|
|
2965
4236
|
</div>
|
|
2966
4237
|
}
|
|
@@ -3031,9 +4302,269 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImpor
|
|
|
3031
4302
|
args: [{ providedIn: 'root' }]
|
|
3032
4303
|
}] });
|
|
3033
4304
|
|
|
4305
|
+
/**
|
|
4306
|
+
* Public service for managing app features in the dev toolbar.
|
|
4307
|
+
*
|
|
4308
|
+
* This service implements the DevToolsService interface and provides methods for:
|
|
4309
|
+
* - Configuring available product features
|
|
4310
|
+
* - Retrieving forced feature overrides
|
|
4311
|
+
* - Applying preset feature configurations
|
|
4312
|
+
* - Exporting current forced state for presets
|
|
4313
|
+
*
|
|
4314
|
+
* @example
|
|
4315
|
+
* ```typescript
|
|
4316
|
+
* import { DevToolbarAppFeaturesService } from 'ngx-dev-toolbar';
|
|
4317
|
+
*
|
|
4318
|
+
* @Component({...})
|
|
4319
|
+
* export class AppComponent implements OnInit {
|
|
4320
|
+
* private appFeaturesService = inject(DevToolbarAppFeaturesService);
|
|
4321
|
+
*
|
|
4322
|
+
* ngOnInit() {
|
|
4323
|
+
* // Configure available features based on current tier
|
|
4324
|
+
* const features: DevToolbarAppFeature[] = [
|
|
4325
|
+
* { id: 'analytics', name: 'Analytics Dashboard', isEnabled: true, isForced: false },
|
|
4326
|
+
* { id: 'multi-user', name: 'Multi-User Support', isEnabled: false, isForced: false }
|
|
4327
|
+
* ];
|
|
4328
|
+
* this.appFeaturesService.setAvailableOptions(features);
|
|
4329
|
+
*
|
|
4330
|
+
* // Subscribe to forced overrides
|
|
4331
|
+
* this.appFeaturesService.getForcedValues().subscribe(forcedFeatures => {
|
|
4332
|
+
* forcedFeatures.forEach(feature => {
|
|
4333
|
+
* // Apply forced feature state to application logic
|
|
4334
|
+
* this.applyFeatureState(feature.id, feature.isEnabled);
|
|
4335
|
+
* });
|
|
4336
|
+
* });
|
|
4337
|
+
* }
|
|
4338
|
+
* }
|
|
4339
|
+
* ```
|
|
4340
|
+
*/
|
|
4341
|
+
class DevToolbarAppFeaturesService {
|
|
4342
|
+
constructor() {
|
|
4343
|
+
this.internalService = inject(DevToolbarInternalAppFeaturesService);
|
|
4344
|
+
}
|
|
4345
|
+
/**
|
|
4346
|
+
* Set available app features for the application.
|
|
4347
|
+
*
|
|
4348
|
+
* Configures the list of product features that can be toggled in the dev toolbar.
|
|
4349
|
+
* Features should represent product-level capabilities like license tiers,
|
|
4350
|
+
* deployment configurations, or environment flags.
|
|
4351
|
+
*
|
|
4352
|
+
* @param features - Array of app features to display in the toolbar
|
|
4353
|
+
* @throws Error if duplicate feature IDs or empty IDs are detected
|
|
4354
|
+
*
|
|
4355
|
+
* @example
|
|
4356
|
+
* ```typescript
|
|
4357
|
+
* const features: DevToolbarAppFeature[] = [
|
|
4358
|
+
* {
|
|
4359
|
+
* id: 'advanced-analytics',
|
|
4360
|
+
* name: 'Advanced Analytics Dashboard',
|
|
4361
|
+
* description: 'Access premium reporting and data visualization',
|
|
4362
|
+
* isEnabled: false, // Not available in current tier
|
|
4363
|
+
* isForced: false
|
|
4364
|
+
* },
|
|
4365
|
+
* {
|
|
4366
|
+
* id: 'multi-user-support',
|
|
4367
|
+
* name: 'Multi-User Collaboration',
|
|
4368
|
+
* description: 'Enable team features and user management',
|
|
4369
|
+
* isEnabled: true, // Available in current tier
|
|
4370
|
+
* isForced: false
|
|
4371
|
+
* }
|
|
4372
|
+
* ];
|
|
4373
|
+
* this.appFeaturesService.setAvailableOptions(features);
|
|
4374
|
+
* ```
|
|
4375
|
+
*/
|
|
4376
|
+
setAvailableOptions(features) {
|
|
4377
|
+
this.internalService.setAppFeatures(features);
|
|
4378
|
+
}
|
|
4379
|
+
/**
|
|
4380
|
+
* Get observable stream of features that have forced overrides.
|
|
4381
|
+
*
|
|
4382
|
+
* Emits an array of features that have been forced via the dev toolbar.
|
|
4383
|
+
* Only features with `isForced = true` are included in the emissions.
|
|
4384
|
+
* Use this to react to feature override changes and update application behavior.
|
|
4385
|
+
*
|
|
4386
|
+
* @returns Observable that emits array of forced features whenever state changes
|
|
4387
|
+
*
|
|
4388
|
+
* @example
|
|
4389
|
+
* ```typescript
|
|
4390
|
+
* this.appFeaturesService.getForcedValues()
|
|
4391
|
+
* .pipe(takeUntilDestroyed())
|
|
4392
|
+
* .subscribe(forcedFeatures => {
|
|
4393
|
+
* forcedFeatures.forEach(feature => {
|
|
4394
|
+
* if (feature.isEnabled) {
|
|
4395
|
+
* this.enableFeature(feature.id);
|
|
4396
|
+
* } else {
|
|
4397
|
+
* this.disableFeature(feature.id);
|
|
4398
|
+
* }
|
|
4399
|
+
* });
|
|
4400
|
+
* });
|
|
4401
|
+
* ```
|
|
4402
|
+
*/
|
|
4403
|
+
getForcedValues() {
|
|
4404
|
+
return this.internalService.getForcedFeatures();
|
|
4405
|
+
}
|
|
4406
|
+
/**
|
|
4407
|
+
* Apply a preset feature configuration (for preset tool integration).
|
|
4408
|
+
*
|
|
4409
|
+
* Accepts a forced features state object and applies it to the current configuration.
|
|
4410
|
+
* Invalid feature IDs (not in configured features) are filtered out with a warning.
|
|
4411
|
+
*
|
|
4412
|
+
* @param state - Forced features state containing enabled/disabled arrays
|
|
4413
|
+
*
|
|
4414
|
+
* @example
|
|
4415
|
+
* ```typescript
|
|
4416
|
+
* // Apply "Enterprise Tier" preset
|
|
4417
|
+
* const enterprisePreset: ForcedAppFeaturesState = {
|
|
4418
|
+
* enabled: ['analytics', 'multi-user', 'white-label', 'sso'],
|
|
4419
|
+
* disabled: []
|
|
4420
|
+
* };
|
|
4421
|
+
* this.appFeaturesService.applyPresetFeatures(enterprisePreset);
|
|
4422
|
+
*
|
|
4423
|
+
* // Apply "Basic Tier" preset
|
|
4424
|
+
* const basicPreset: ForcedAppFeaturesState = {
|
|
4425
|
+
* enabled: [],
|
|
4426
|
+
* disabled: ['analytics', 'multi-user', 'white-label', 'sso']
|
|
4427
|
+
* };
|
|
4428
|
+
* this.appFeaturesService.applyPresetFeatures(basicPreset);
|
|
4429
|
+
* ```
|
|
4430
|
+
*/
|
|
4431
|
+
applyPresetFeatures(state) {
|
|
4432
|
+
this.internalService.applyForcedState(state);
|
|
4433
|
+
}
|
|
4434
|
+
/**
|
|
4435
|
+
* Get current forced feature state as a snapshot (for preset export).
|
|
4436
|
+
*
|
|
4437
|
+
* Returns the current forced features state with enabled/disabled arrays.
|
|
4438
|
+
* Useful for exporting toolbar state to save as a preset or for debugging.
|
|
4439
|
+
* Returns a defensive copy - mutations will not affect internal state.
|
|
4440
|
+
*
|
|
4441
|
+
* @returns Current forced features state
|
|
4442
|
+
*
|
|
4443
|
+
* @example
|
|
4444
|
+
* ```typescript
|
|
4445
|
+
* // Export current toolbar state to save as preset
|
|
4446
|
+
* const currentState = this.appFeaturesService.getCurrentForcedState();
|
|
4447
|
+
* this.presetsService.savePreset('my-config', {
|
|
4448
|
+
* appFeatures: currentState,
|
|
4449
|
+
* // ... other tool states
|
|
4450
|
+
* });
|
|
4451
|
+
*
|
|
4452
|
+
* console.log(currentState);
|
|
4453
|
+
* // { enabled: ['analytics'], disabled: ['white-label'] }
|
|
4454
|
+
* ```
|
|
4455
|
+
*/
|
|
4456
|
+
getCurrentForcedState() {
|
|
4457
|
+
return this.internalService.getCurrentForcedState();
|
|
4458
|
+
}
|
|
4459
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarAppFeaturesService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4460
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarAppFeaturesService, providedIn: 'root' }); }
|
|
4461
|
+
}
|
|
4462
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarAppFeaturesService, decorators: [{
|
|
4463
|
+
type: Injectable,
|
|
4464
|
+
args: [{ providedIn: 'root' }]
|
|
4465
|
+
}] });
|
|
4466
|
+
|
|
4467
|
+
/**
|
|
4468
|
+
* Public service for integrating the Permissions Tool with your application.
|
|
4469
|
+
* Use this service to:
|
|
4470
|
+
* 1. Register your application's permissions with setAvailableOptions()
|
|
4471
|
+
* 2. Listen for toolbar permission overrides with getForcedValues()
|
|
4472
|
+
* 3. Apply preset permission states for testing with applyPreset()
|
|
4473
|
+
*
|
|
4474
|
+
* @example
|
|
4475
|
+
* ```typescript
|
|
4476
|
+
* constructor(private permissionsService: DevToolbarPermissionsService) {
|
|
4477
|
+
* // Register permissions
|
|
4478
|
+
* this.permissionsService.setAvailableOptions([
|
|
4479
|
+
* { id: 'can-edit', name: 'Can Edit', isGranted: false, isForced: false }
|
|
4480
|
+
* ]);
|
|
4481
|
+
*
|
|
4482
|
+
* // Listen for overrides
|
|
4483
|
+
* this.permissionsService.getForcedValues().subscribe(forcedPermissions => {
|
|
4484
|
+
* // Update your app's permission state
|
|
4485
|
+
* });
|
|
4486
|
+
* }
|
|
4487
|
+
* ```
|
|
4488
|
+
*/
|
|
4489
|
+
class DevToolbarPermissionsService {
|
|
4490
|
+
constructor() {
|
|
4491
|
+
this.internalService = inject(DevToolbarInternalPermissionsService);
|
|
4492
|
+
}
|
|
4493
|
+
/**
|
|
4494
|
+
* Sets the available permissions that will be displayed in the toolbar tool.
|
|
4495
|
+
* Call this in your app initialization to register permissions.
|
|
4496
|
+
*
|
|
4497
|
+
* @param permissions Array of permissions to display in the toolbar
|
|
4498
|
+
*
|
|
4499
|
+
* @example
|
|
4500
|
+
* ```typescript
|
|
4501
|
+
* this.permissionsService.setAvailableOptions([
|
|
4502
|
+
* {
|
|
4503
|
+
* id: 'can-edit-posts',
|
|
4504
|
+
* name: 'Edit Posts',
|
|
4505
|
+
* description: 'Can edit blog posts',
|
|
4506
|
+
* isGranted: false,
|
|
4507
|
+
* isForced: false
|
|
4508
|
+
* }
|
|
4509
|
+
* ]);
|
|
4510
|
+
* ```
|
|
4511
|
+
*/
|
|
4512
|
+
setAvailableOptions(permissions) {
|
|
4513
|
+
this.internalService.setAppPermissions(permissions);
|
|
4514
|
+
}
|
|
4515
|
+
/**
|
|
4516
|
+
* Gets an observable of permissions that were forced/overridden through the toolbar.
|
|
4517
|
+
* Subscribe to this to update your application's permission state.
|
|
4518
|
+
*
|
|
4519
|
+
* @returns Observable emitting array of forced permissions whenever changes occur
|
|
4520
|
+
*
|
|
4521
|
+
* @example
|
|
4522
|
+
* ```typescript
|
|
4523
|
+
* this.permissionsService.getForcedValues().subscribe(forcedPermissions => {
|
|
4524
|
+
* forcedPermissions.forEach(permission => {
|
|
4525
|
+
* this.updatePermission(permission.id, permission.isGranted);
|
|
4526
|
+
* });
|
|
4527
|
+
* });
|
|
4528
|
+
* ```
|
|
4529
|
+
*/
|
|
4530
|
+
getForcedValues() {
|
|
4531
|
+
return this.internalService.getForcedPermissions();
|
|
4532
|
+
}
|
|
4533
|
+
/**
|
|
4534
|
+
* Apply a preset permission state. Useful for automated testing scenarios.
|
|
4535
|
+
*
|
|
4536
|
+
* @param state The forced permissions state to apply
|
|
4537
|
+
*
|
|
4538
|
+
* @example
|
|
4539
|
+
* ```typescript
|
|
4540
|
+
* this.permissionsService.applyPreset({
|
|
4541
|
+
* granted: ['can-edit-posts'],
|
|
4542
|
+
* denied: ['can-delete-posts']
|
|
4543
|
+
* });
|
|
4544
|
+
* ```
|
|
4545
|
+
*/
|
|
4546
|
+
applyPreset(state) {
|
|
4547
|
+
this.internalService.applyPresetPermissions(state);
|
|
4548
|
+
}
|
|
4549
|
+
/**
|
|
4550
|
+
* Get the current forced permission state.
|
|
4551
|
+
*
|
|
4552
|
+
* @returns Current forced permissions state
|
|
4553
|
+
*/
|
|
4554
|
+
getCurrentState() {
|
|
4555
|
+
return this.internalService.getCurrentForcedState();
|
|
4556
|
+
}
|
|
4557
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPermissionsService, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
4558
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPermissionsService, providedIn: 'root' }); }
|
|
4559
|
+
}
|
|
4560
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.5", ngImport: i0, type: DevToolbarPermissionsService, decorators: [{
|
|
4561
|
+
type: Injectable,
|
|
4562
|
+
args: [{ providedIn: 'root' }]
|
|
4563
|
+
}] });
|
|
4564
|
+
|
|
3034
4565
|
/**
|
|
3035
4566
|
* Generated bundle index. Do not edit.
|
|
3036
4567
|
*/
|
|
3037
4568
|
|
|
3038
|
-
export { DevToolbarComponent, DevToolbarFeatureFlagService, DevToolbarIconComponent, DevToolbarLanguageService, DevToolbarToolComponent };
|
|
4569
|
+
export { DevToolbarAppFeaturesService, DevToolbarAppFeaturesToolComponent, DevToolbarComponent, DevToolbarFeatureFlagService, DevToolbarIconComponent, DevToolbarLanguageService, DevToolbarNetworkMockerService, DevToolbarNetworkMockerToolComponent, DevToolbarPermissionsService, DevToolbarPermissionsToolComponent, DevToolbarToolComponent };
|
|
3039
4570
|
//# sourceMappingURL=ngx-dev-toolbar.mjs.map
|