ng-configcat-publicapi-ui 2.3.1 → 2.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/README.md +15 -15
  2. package/{esm2015/lib/_models/index.js → esm2020/lib/_models/index.mjs} +3 -3
  3. package/esm2020/lib/_models/settingValuesModel.mjs +2 -0
  4. package/{esm2015/lib/_models/updateSettingValuesModel.js → esm2020/lib/_models/updateSettingValuesModel.mjs} +2 -2
  5. package/esm2020/lib/_services/form-helper.mjs +21 -0
  6. package/{esm2015/lib/_services/index.js → esm2020/lib/_services/index.mjs} +2 -2
  7. package/esm2020/lib/_services/public-api.service.mjs +68 -0
  8. package/esm2020/lib/_services/setting-list-form-helper.mjs +152 -0
  9. package/esm2020/lib/authorization/authorization.component.mjs +50 -0
  10. package/esm2020/lib/base/base.component.mjs +45 -0
  11. package/esm2020/lib/configuration.mjs +13 -0
  12. package/esm2020/lib/dialogs/concurrent-dialog/concurrent-dialog.component.mjs +25 -0
  13. package/esm2020/lib/dialogs/expand-dialog/expand-dialog.component.mjs +77 -0
  14. package/esm2020/lib/dialogs/reason-dialog/reason-dialog.component.mjs +36 -0
  15. package/esm2020/lib/dialogs/save-snackbar/save-snackbar.component.mjs +14 -0
  16. package/esm2020/lib/ng-configcat-publicapi-ui.module.mjs +160 -0
  17. package/esm2020/lib/selects/config-select/config-select.component.mjs +56 -0
  18. package/esm2020/lib/selects/environment-select/environment-select.component.mjs +43 -0
  19. package/esm2020/lib/selects/product-select/product-select.component.mjs +36 -0
  20. package/esm2020/lib/selects/setting-select/setting-select.component.mjs +43 -0
  21. package/esm2020/lib/setting-item/setting-item.component.mjs +129 -0
  22. package/esm2020/lib/setting-list/setting/rollout-percentage-items/rollout-percentage-items.component.mjs +81 -0
  23. package/esm2020/lib/setting-list/setting/rollout-rules/rollout-rules.component.mjs +295 -0
  24. package/esm2020/lib/setting-list/setting/setting.component.mjs +137 -0
  25. package/esm2020/lib/setting-list/setting/value/value.component.mjs +32 -0
  26. package/esm2020/lib/setting-list/setting-list.component.mjs +200 -0
  27. package/esm2020/ng-configcat-publicapi-ui.mjs +5 -0
  28. package/{esm2015/public-api.js → esm2020/public-api.mjs} +12 -12
  29. package/fesm2015/ng-configcat-publicapi-ui.mjs +1588 -0
  30. package/fesm2015/ng-configcat-publicapi-ui.mjs.map +1 -0
  31. package/fesm2020/ng-configcat-publicapi-ui.mjs +1569 -0
  32. package/fesm2020/ng-configcat-publicapi-ui.mjs.map +1 -0
  33. package/lib/_models/index.d.ts +2 -2
  34. package/lib/_models/settingValuesModel.d.ts +11 -11
  35. package/lib/_models/updateSettingValuesModel.d.ts +7 -7
  36. package/lib/_services/form-helper.d.ts +4 -4
  37. package/lib/_services/index.d.ts +1 -1
  38. package/lib/_services/public-api.service.d.ts +19 -15
  39. package/lib/_services/setting-list-form-helper.d.ts +17 -14
  40. package/lib/authorization/authorization.component.d.ts +18 -15
  41. package/lib/base/base.component.d.ts +17 -13
  42. package/lib/configuration.d.ts +8 -5
  43. package/lib/dialogs/concurrent-dialog/concurrent-dialog.component.d.ts +12 -9
  44. package/lib/dialogs/expand-dialog/expand-dialog.component.d.ts +24 -20
  45. package/lib/dialogs/reason-dialog/reason-dialog.component.d.ts +15 -12
  46. package/lib/dialogs/save-snackbar/save-snackbar.component.d.ts +8 -5
  47. package/lib/ng-configcat-publicapi-ui.module.d.ts +44 -6
  48. package/lib/selects/config-select/config-select.component.d.ts +17 -14
  49. package/lib/selects/environment-select/environment-select.component.d.ts +17 -14
  50. package/lib/selects/product-select/product-select.component.d.ts +14 -11
  51. package/lib/selects/setting-select/setting-select.component.d.ts +17 -14
  52. package/lib/setting-item/setting-item.component.d.ts +37 -31
  53. package/lib/setting-list/setting/rollout-percentage-items/rollout-percentage-items.component.d.ts +27 -22
  54. package/lib/setting-list/setting/rollout-rules/rollout-rules.component.d.ts +60 -46
  55. package/lib/setting-list/setting/setting.component.d.ts +43 -37
  56. package/lib/setting-list/setting/value/value.component.d.ts +19 -16
  57. package/lib/setting-list/setting-list.component.d.ts +50 -42
  58. package/ng-configcat-publicapi-ui.d.ts +5 -18
  59. package/package.json +26 -21
  60. package/public-api.d.ts +8 -8
  61. package/bundles/ng-configcat-publicapi-ui.umd.js +0 -1826
  62. package/bundles/ng-configcat-publicapi-ui.umd.js.map +0 -1
  63. package/esm2015/lib/_models/settingValuesModel.js +0 -2
  64. package/esm2015/lib/_services/form-helper.js +0 -21
  65. package/esm2015/lib/_services/public-api.service.js +0 -71
  66. package/esm2015/lib/_services/setting-list-form-helper.js +0 -128
  67. package/esm2015/lib/authorization/authorization.component.js +0 -49
  68. package/esm2015/lib/base/base.component.js +0 -40
  69. package/esm2015/lib/configuration.js +0 -10
  70. package/esm2015/lib/dialogs/concurrent-dialog/concurrent-dialog.component.js +0 -26
  71. package/esm2015/lib/dialogs/expand-dialog/expand-dialog.component.js +0 -70
  72. package/esm2015/lib/dialogs/reason-dialog/reason-dialog.component.js +0 -35
  73. package/esm2015/lib/dialogs/save-snackbar/save-snackbar.component.js +0 -15
  74. package/esm2015/lib/ng-configcat-publicapi-ui.module.js +0 -100
  75. package/esm2015/lib/selects/config-select/config-select.component.js +0 -48
  76. package/esm2015/lib/selects/environment-select/environment-select.component.js +0 -40
  77. package/esm2015/lib/selects/product-select/product-select.component.js +0 -34
  78. package/esm2015/lib/selects/setting-select/setting-select.component.js +0 -40
  79. package/esm2015/lib/setting-item/setting-item.component.js +0 -106
  80. package/esm2015/lib/setting-list/setting/rollout-percentage-items/rollout-percentage-items.component.js +0 -69
  81. package/esm2015/lib/setting-list/setting/rollout-rules/rollout-rules.component.js +0 -260
  82. package/esm2015/lib/setting-list/setting/setting.component.js +0 -112
  83. package/esm2015/lib/setting-list/setting/value/value.component.js +0 -31
  84. package/esm2015/lib/setting-list/setting-list.component.js +0 -179
  85. package/esm2015/ng-configcat-publicapi-ui.js +0 -19
  86. package/fesm2015/ng-configcat-publicapi-ui.js +0 -1415
  87. package/fesm2015/ng-configcat-publicapi-ui.js.map +0 -1
  88. package/ng-configcat-publicapi-ui.metadata.json +0 -1
@@ -0,0 +1,1569 @@
1
+ import * as i0 from '@angular/core';
2
+ import { Injectable, Optional, Component, Input, Inject, EventEmitter, Output, forwardRef, NgModule } from '@angular/core';
3
+ import { MeService, Configuration as Configuration$1, ProductsService, ConfigsService, EnvironmentsService, FeatureFlagsSettingsService, FeatureFlagSettingValuesService, IntegrationLinksService, SegmentsService, SettingType, RolloutRuleComparator, SegmentComparator, ApiModule } from 'ng-configcat-publicapi';
4
+ import * as i1 from '@angular/common/http';
5
+ import { forkJoin, throwError, of } from 'rxjs';
6
+ import { map, catchError } from 'rxjs/operators';
7
+ import * as i2 from '@angular/forms';
8
+ import { Validators, NG_VALUE_ACCESSOR, FormsModule, ReactiveFormsModule } from '@angular/forms';
9
+ import * as i1$1 from '@angular/material/dialog';
10
+ import { MAT_DIALOG_DATA, MatDialogModule } from '@angular/material/dialog';
11
+ import * as i3 from '@angular/material/form-field';
12
+ import { MatFormFieldModule } from '@angular/material/form-field';
13
+ import * as i4 from '@angular/material/button';
14
+ import { MatButtonModule } from '@angular/material/button';
15
+ import * as i5 from '@angular/material/input';
16
+ import { MatInputModule } from '@angular/material/input';
17
+ import * as i5$1 from '@angular/common';
18
+ import { CommonModule } from '@angular/common';
19
+ import * as i3$1 from '@angular/router';
20
+ import { RouterModule } from '@angular/router';
21
+ import * as i2$2 from '@angular/material/snack-bar';
22
+ import { MatSnackBarModule } from '@angular/material/snack-bar';
23
+ import * as i2$1 from '@angular/material/icon';
24
+ import { MatIconModule } from '@angular/material/icon';
25
+ import * as i8 from '@angular/cdk/drag-drop';
26
+ import { moveItemInArray, DragDropModule } from '@angular/cdk/drag-drop';
27
+ import { valid } from 'semver';
28
+ import * as i3$2 from '@angular/material/chips';
29
+ import { MatChipsModule } from '@angular/material/chips';
30
+ import * as i4$1 from '@angular/material/autocomplete';
31
+ import { MatAutocompleteModule } from '@angular/material/autocomplete';
32
+ import * as i4$2 from '@angular/material/core';
33
+ import { MatOptionModule } from '@angular/material/core';
34
+ import * as i5$2 from '@angular/material/tooltip';
35
+ import { MatTooltipModule } from '@angular/material/tooltip';
36
+ import * as i3$3 from '@angular/material/select';
37
+ import { MatSelectModule } from '@angular/material/select';
38
+ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
39
+ import { MatMenuModule } from '@angular/material/menu';
40
+
41
+ class Configuration {
42
+ constructor() {
43
+ this.basePath = 'https://api.configcat.com';
44
+ }
45
+ }
46
+ Configuration.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: Configuration, deps: [], target: i0.ɵɵFactoryTarget.Injectable });
47
+ Configuration.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: Configuration });
48
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: Configuration, decorators: [{
49
+ type: Injectable
50
+ }] });
51
+
52
+ class PublicApiService {
53
+ constructor(httpClient, configuration) {
54
+ this.httpClient = httpClient;
55
+ this.configuration = configuration;
56
+ }
57
+ createMeService(basicAuthUsername = null, basicAuthPassword = null, basePath = null) {
58
+ return new MeService(this.httpClient, basePath ?? this.configuration?.basePath, new Configuration$1({
59
+ username: basicAuthUsername ?? this.configuration?.basicAuthUsername,
60
+ password: basicAuthPassword ?? this.configuration?.basicAuthPassword
61
+ }));
62
+ }
63
+ createProductsService(basicAuthUsername = null, basicAuthPassword = null, basePath = null) {
64
+ return new ProductsService(this.httpClient, basePath ?? this.configuration?.basePath, new Configuration$1({
65
+ username: basicAuthUsername ?? this.configuration?.basicAuthUsername,
66
+ password: basicAuthPassword ?? this.configuration?.basicAuthPassword
67
+ }));
68
+ }
69
+ createConfigsService(basicAuthUsername = null, basicAuthPassword = null, basePath = null) {
70
+ return new ConfigsService(this.httpClient, basePath ?? this.configuration?.basePath, new Configuration$1({
71
+ username: basicAuthUsername ?? this.configuration?.basicAuthUsername,
72
+ password: basicAuthPassword ?? this.configuration?.basicAuthPassword
73
+ }));
74
+ }
75
+ createEnvironmentsService(basicAuthUsername = null, basicAuthPassword = null, basePath = null) {
76
+ return new EnvironmentsService(this.httpClient, basePath ?? this.configuration?.basePath, new Configuration$1({
77
+ username: basicAuthUsername ?? this.configuration?.basicAuthUsername,
78
+ password: basicAuthPassword ?? this.configuration?.basicAuthPassword
79
+ }));
80
+ }
81
+ createSettingsService(basicAuthUsername = null, basicAuthPassword = null, basePath = null) {
82
+ return new FeatureFlagsSettingsService(this.httpClient, basePath ?? this.configuration?.basePath, new Configuration$1({
83
+ username: basicAuthUsername ?? this.configuration?.basicAuthUsername,
84
+ password: basicAuthPassword ?? this.configuration?.basicAuthPassword
85
+ }));
86
+ }
87
+ createSettingValuesService(basicAuthUsername = null, basicAuthPassword = null, basePath = null) {
88
+ return new FeatureFlagSettingValuesService(this.httpClient, basePath ?? this.configuration?.basePath, new Configuration$1({
89
+ username: basicAuthUsername ?? this.configuration?.basicAuthUsername,
90
+ password: basicAuthPassword ?? this.configuration?.basicAuthPassword
91
+ }));
92
+ }
93
+ createIntegrationLinksService(basicAuthUsername = null, basicAuthPassword = null, basePath = null) {
94
+ return new IntegrationLinksService(this.httpClient, basePath ?? this.configuration?.basePath, new Configuration$1({
95
+ username: basicAuthUsername ?? this.configuration?.basicAuthUsername,
96
+ password: basicAuthPassword ?? this.configuration?.basicAuthPassword
97
+ }));
98
+ }
99
+ createSegmentsService(basicAuthUsername = null, basicAuthPassword = null, basePath = null) {
100
+ return new SegmentsService(this.httpClient, basePath ?? this.configuration?.basePath, new Configuration$1({
101
+ username: basicAuthUsername ?? this.configuration?.basicAuthUsername,
102
+ password: basicAuthPassword ?? this.configuration?.basicAuthPassword
103
+ }));
104
+ }
105
+ }
106
+ PublicApiService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: PublicApiService, deps: [{ token: i1.HttpClient }, { token: Configuration, optional: true }], target: i0.ɵɵFactoryTarget.Injectable });
107
+ PublicApiService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: PublicApiService, providedIn: 'root' });
108
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: PublicApiService, decorators: [{
109
+ type: Injectable,
110
+ args: [{ providedIn: 'root' }]
111
+ }], ctorParameters: function () { return [{ type: i1.HttpClient }, { type: Configuration, decorators: [{
112
+ type: Optional
113
+ }] }]; } });
114
+
115
+ class BaseComponent {
116
+ constructor(publicApiService) {
117
+ this.publicApiService = publicApiService;
118
+ this.basePath = null;
119
+ this.basicAuthUsername = null;
120
+ this.basicAuthPassword = null;
121
+ }
122
+ createProductsService() {
123
+ return this.publicApiService.createProductsService(this.basicAuthUsername, this.basicAuthPassword, this.basePath);
124
+ }
125
+ createConfigsService() {
126
+ return this.publicApiService.createConfigsService(this.basicAuthUsername, this.basicAuthPassword, this.basePath);
127
+ }
128
+ createEnvironmentsService() {
129
+ return this.publicApiService.createEnvironmentsService(this.basicAuthUsername, this.basicAuthPassword, this.basePath);
130
+ }
131
+ createSettingsService() {
132
+ return this.publicApiService.createSettingsService(this.basicAuthUsername, this.basicAuthPassword, this.basePath);
133
+ }
134
+ createSettingValuesService() {
135
+ return this.publicApiService.createSettingValuesService(this.basicAuthUsername, this.basicAuthPassword, this.basePath);
136
+ }
137
+ createSegmentsService() {
138
+ return this.publicApiService.createSegmentsService(this.basicAuthUsername, this.basicAuthPassword, this.basePath);
139
+ }
140
+ }
141
+ BaseComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: BaseComponent, deps: [{ token: PublicApiService }], target: i0.ɵɵFactoryTarget.Component });
142
+ BaseComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: BaseComponent, selector: "base", inputs: { basePath: "basePath", basicAuthUsername: "basicAuthUsername", basicAuthPassword: "basicAuthPassword" }, ngImport: i0, template: '<div></div>', isInline: true });
143
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: BaseComponent, decorators: [{
144
+ type: Component,
145
+ args: [{
146
+ selector: 'base',
147
+ template: '<div></div>'
148
+ }]
149
+ }], ctorParameters: function () { return [{ type: PublicApiService }]; }, propDecorators: { basePath: [{
150
+ type: Input
151
+ }], basicAuthUsername: [{
152
+ type: Input
153
+ }], basicAuthPassword: [{
154
+ type: Input
155
+ }] } });
156
+
157
+ class ReasonDialogComponent {
158
+ constructor(dialogRef, formBuilder) {
159
+ this.dialogRef = dialogRef;
160
+ this.formBuilder = formBuilder;
161
+ }
162
+ ngOnInit() {
163
+ this.formGroup = this.formBuilder.group({
164
+ reason: ['', [Validators.required, Validators.maxLength(1000)]]
165
+ });
166
+ }
167
+ handleSaveButton() {
168
+ if (!this.formGroup.valid) {
169
+ return;
170
+ }
171
+ this.dialogRef.close({ button: 'save', reason: this.formGroup.controls.reason.value });
172
+ }
173
+ cancel() {
174
+ this.dialogRef.close({ button: 'cancel' });
175
+ }
176
+ }
177
+ ReasonDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ReasonDialogComponent, deps: [{ token: i1$1.MatDialogRef }, { token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Component });
178
+ ReasonDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: ReasonDialogComponent, selector: "configcat-reason-dialog", ngImport: i0, template: "<h3 mat-dialog-title>Add notes</h3>\n<p>This will appear in the Why column of the Audit Log.</p>\n<form [formGroup]=\"formGroup\" (ngSubmit)=\"handleSaveButton()\">\n <div mat-dialog-content class=\"container\">\n <mat-form-field appearance=\"outline\">\n <mat-label></mat-label>\n <textarea matInput formControlName=\"reason\" name=\"reason\" placeholder=\"I'm changing settings because...\"\n rows=\"3\"></textarea>\n <mat-error *ngIf=\"formGroup.controls.reason.invalid\">The field is required.</mat-error>\n </mat-form-field>\n </div>\n <br>\n <div mat-dialog-actions>\n <button type=\"submit\" style=\"margin-right: 10px;\" mat-raised-button color=\"primary\">Add notes & Save</button>\n <button type=\"button\" mat-raised-button (click)=\"cancel()\">Cancel</button>\n </div>\n</form>", styles: [".container>*{width:100%}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i4.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i1$1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i1$1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { type: i3.MatLabel, selector: "mat-label" }, { type: i5.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i5$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }, { type: i1$1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]" }] });
179
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ReasonDialogComponent, decorators: [{
180
+ type: Component,
181
+ args: [{ selector: 'configcat-reason-dialog', template: "<h3 mat-dialog-title>Add notes</h3>\n<p>This will appear in the Why column of the Audit Log.</p>\n<form [formGroup]=\"formGroup\" (ngSubmit)=\"handleSaveButton()\">\n <div mat-dialog-content class=\"container\">\n <mat-form-field appearance=\"outline\">\n <mat-label></mat-label>\n <textarea matInput formControlName=\"reason\" name=\"reason\" placeholder=\"I'm changing settings because...\"\n rows=\"3\"></textarea>\n <mat-error *ngIf=\"formGroup.controls.reason.invalid\">The field is required.</mat-error>\n </mat-form-field>\n </div>\n <br>\n <div mat-dialog-actions>\n <button type=\"submit\" style=\"margin-right: 10px;\" mat-raised-button color=\"primary\">Add notes & Save</button>\n <button type=\"button\" mat-raised-button (click)=\"cancel()\">Cancel</button>\n </div>\n</form>", styles: [".container>*{width:100%}\n"] }]
182
+ }], ctorParameters: function () { return [{ type: i1$1.MatDialogRef }, { type: i2.FormBuilder }]; } });
183
+
184
+ class SaveSnackbarComponent {
185
+ constructor() { }
186
+ ngOnInit() {
187
+ }
188
+ }
189
+ SaveSnackbarComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: SaveSnackbarComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
190
+ SaveSnackbarComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: SaveSnackbarComponent, selector: "configcat-save-snackbar", ngImport: i0, template: "<p class=\"header\">Settings saved successfully.</p>", styles: ["p{text-align:center;font-weight:700}.header{font-size:1.2em}\n"] });
191
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: SaveSnackbarComponent, decorators: [{
192
+ type: Component,
193
+ args: [{ selector: 'configcat-save-snackbar', template: "<p class=\"header\">Settings saved successfully.</p>", styles: ["p{text-align:center;font-weight:700}.header{font-size:1.2em}\n"] }]
194
+ }], ctorParameters: function () { return []; } });
195
+
196
+ class ConcurrentDialogComponent {
197
+ constructor(dialogRef) {
198
+ this.dialogRef = dialogRef;
199
+ }
200
+ ngOnInit() {
201
+ }
202
+ save() {
203
+ this.dialogRef.close({ button: 'save' });
204
+ }
205
+ discard() {
206
+ this.dialogRef.close({ button: 'discard' });
207
+ }
208
+ }
209
+ ConcurrentDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ConcurrentDialogComponent, deps: [{ token: i1$1.MatDialogRef }], target: i0.ɵɵFactoryTarget.Component });
210
+ ConcurrentDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: ConcurrentDialogComponent, selector: "configcat-concurrent-dialog", ngImport: i0, template: "<h3 mat-dialog-title>Concurrent update detected</h3>\n<p>\n Somebody updated the feature flags & settings while you were editing them.\n</p>\n<ul>\n <li>\n To discard your local changes and reload the updated values, click <strong>Discard my changes & reload</strong>\n </li>\n <li>\n To save you local values and overwrite the remote changes, click <strong>Save anyway</strong>\n </li>\n</ul>\n<p>For more info about the changes check the <a [routerLink]=\"['/auditlog']\" target=\"_blank\" rel=\"noopener noreferrer\" >audit logs</a> in a new tab.</p>\n<div mat-dialog-actions>\n <button type=\"button\" style=\"margin-right: 10px;\" mat-raised-button color=\"primary\" (click)=\"discard()\">Discard\n local changes & reload</button>\n <button type=\"button\" mat-raised-button (click)=\"save()\">Save anyway</button>\n</div>", styles: [""], components: [{ type: i4.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i1$1.MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { type: i3$1.RouterLinkWithHref, selector: "a[routerLink],area[routerLink]", inputs: ["target", "queryParams", "fragment", "queryParamsHandling", "preserveFragment", "skipLocationChange", "replaceUrl", "state", "relativeTo", "routerLink"] }, { type: i1$1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]" }] });
211
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ConcurrentDialogComponent, decorators: [{
212
+ type: Component,
213
+ args: [{ selector: 'configcat-concurrent-dialog', template: "<h3 mat-dialog-title>Concurrent update detected</h3>\n<p>\n Somebody updated the feature flags & settings while you were editing them.\n</p>\n<ul>\n <li>\n To discard your local changes and reload the updated values, click <strong>Discard my changes & reload</strong>\n </li>\n <li>\n To save you local values and overwrite the remote changes, click <strong>Save anyway</strong>\n </li>\n</ul>\n<p>For more info about the changes check the <a [routerLink]=\"['/auditlog']\" target=\"_blank\" rel=\"noopener noreferrer\" >audit logs</a> in a new tab.</p>\n<div mat-dialog-actions>\n <button type=\"button\" style=\"margin-right: 10px;\" mat-raised-button color=\"primary\" (click)=\"discard()\">Discard\n local changes & reload</button>\n <button type=\"button\" mat-raised-button (click)=\"save()\">Save anyway</button>\n</div>", styles: [""] }]
214
+ }], ctorParameters: function () { return [{ type: i1$1.MatDialogRef }]; } });
215
+
216
+ class SettingListFormHelper {
217
+ constructor(formBuilder) {
218
+ this.formBuilder = formBuilder;
219
+ }
220
+ createSettingValuesFormGroup(settingValuesModel) {
221
+ const formGroup = this.formBuilder.group({
222
+ settingValues: this.formBuilder.array(settingValuesModel.settingValues.map(sv => {
223
+ return this.createSettingValueFormGroup(sv, settingValuesModel.readOnly);
224
+ })),
225
+ // Decorator
226
+ environment: this.formBuilder.group({
227
+ environmentId: [{ value: settingValuesModel.environment.environmentId, disabled: true }],
228
+ name: [{ value: settingValuesModel.environment.name, disabled: true }],
229
+ }),
230
+ comparisonAttributes: [[]],
231
+ allRolloutRulesCount: [0]
232
+ });
233
+ const rolloutRules = this.getAllRolloutRules(formGroup);
234
+ const comparisonAttributes = this.getComparisonAttributes(rolloutRules);
235
+ formGroup.patchValue({ allRolloutRulesCount: rolloutRules.length });
236
+ formGroup.patchValue({ comparisonAttributes: comparisonAttributes });
237
+ return formGroup;
238
+ }
239
+ createSettingValueFormGroup(settingValueModel, readOnly) {
240
+ if (!settingValueModel.setting) {
241
+ return this.formBuilder.group({});
242
+ }
243
+ return this.formBuilder.group({
244
+ settingId: [settingValueModel.setting.settingId],
245
+ value: [
246
+ { value: settingValueModel.value, disabled: readOnly },
247
+ this.getValidatorsForSettingType(settingValueModel.setting.settingType)
248
+ ],
249
+ rolloutPercentageItems: settingValueModel.rolloutPercentageItems
250
+ ? this.formBuilder.array(settingValueModel.rolloutPercentageItems.map(p => {
251
+ // @ts-ignore()
252
+ return this.createRolloutPercentageItemFormGroup(p, readOnly, settingValueModel.setting.settingType);
253
+ }))
254
+ : this.formBuilder.array([]), rolloutRules: settingValueModel.rolloutRules
255
+ ? this.formBuilder.array(settingValueModel.rolloutRules.map(r => {
256
+ // @ts-ignore()
257
+ return this.createRolloutRuleFormGroup(r, readOnly, settingValueModel.setting.settingType);
258
+ }))
259
+ : this.formBuilder.array([]),
260
+ updatedAt: [{ value: settingValueModel.updatedAt, disabled: true }],
261
+ lastUpdaterUserEmail: [{ value: settingValueModel.lastUpdaterUserEmail, disabled: true }],
262
+ lastUpdaterUserFullName: [{ value: settingValueModel.lastUpdaterUserFullName, disabled: true }],
263
+ rolloutPercentageItemsSum: [{ value: 100, disabled: false }, [Validators.min(100), Validators.max(100)]],
264
+ // Decoration
265
+ setting: this.formBuilder.group({
266
+ settingId: [{ value: settingValueModel.setting.settingId, disabled: true }],
267
+ key: [{ value: settingValueModel.setting.key, disabled: true }],
268
+ name: [{ value: settingValueModel.setting.name, disabled: true }],
269
+ hint: [{ value: settingValueModel.setting.hint, disabled: true }],
270
+ settingType: [{ value: settingValueModel.setting.settingType, disabled: true }],
271
+ creatorEmail: [{ value: settingValueModel.setting.creatorEmail, disabled: true }],
272
+ creatorFullName: [{ value: settingValueModel.setting.creatorFullName, disabled: true }],
273
+ createdAt: [{ value: settingValueModel.setting.createdAt, disabled: true }]
274
+ }),
275
+ integrationLinks: settingValueModel.integrationLinks ? this.formBuilder.array(settingValueModel.integrationLinks.map(il => {
276
+ return this.formBuilder.group({
277
+ key: [{ value: il.key, disabled: true }],
278
+ description: [{ value: il.description, disabled: true }],
279
+ integrationLinkType: [{ value: il.integrationLinkType, disabled: true }],
280
+ url: [{ value: il.url, disabled: true }],
281
+ });
282
+ })) : this.formBuilder.array([])
283
+ });
284
+ }
285
+ createRolloutPercentageItemFormGroup(p, readOnly, settingType) {
286
+ return this.formBuilder.group({
287
+ percentage: [{ value: p.percentage, disabled: readOnly }, [Validators.required, Validators.min(0), Validators.max(100)]],
288
+ value: [
289
+ { value: p.value, disabled: readOnly },
290
+ this.getValidatorsForSettingType(settingType)
291
+ ],
292
+ valueDisabled: [
293
+ { value: p.value, disabled: true }, // For percentage item value
294
+ ]
295
+ });
296
+ }
297
+ createRolloutRuleFormGroup(r, readOnly, settingType) {
298
+ if (r.comparator) {
299
+ return this.formBuilder.group({
300
+ type: [{ value: 0, disabled: true }],
301
+ comparisonAttribute: [{ value: r.comparisonAttribute, disabled: readOnly }, [Validators.required]],
302
+ comparator: [{ value: r.comparator, disabled: readOnly }, [Validators.required]],
303
+ comparisonValue: [{ value: r.comparisonValue, disabled: readOnly }, [Validators.required]],
304
+ value: [
305
+ { value: r.value, disabled: readOnly },
306
+ this.getValidatorsForSettingType(settingType)
307
+ ],
308
+ });
309
+ }
310
+ else if (r.segmentComparator) {
311
+ return this.formBuilder.group({
312
+ type: [{ value: 1, disabled: true }],
313
+ segmentComparator: [{ value: r.segmentComparator, disabled: readOnly }, [Validators.required]],
314
+ segmentId: [{ value: r.segmentId, disabled: readOnly }, [Validators.required]],
315
+ value: [
316
+ { value: r.value, disabled: readOnly },
317
+ this.getValidatorsForSettingType(settingType)
318
+ ],
319
+ });
320
+ }
321
+ else {
322
+ throw new Error('Invalid rollout rule');
323
+ }
324
+ }
325
+ getValidatorsForSettingType(settingType) {
326
+ switch (settingType) {
327
+ case SettingType.Int:
328
+ return [Validators.required,
329
+ Validators.min(-2147483648), Validators.max(2147483647), Validators.pattern('^[-+]?[0-9]\\d*$')];
330
+ case SettingType.Double:
331
+ return [Validators.required, Validators.min(-1.79769313486232E+308), Validators.max(1.79769313486232E+308)];
332
+ case SettingType.String:
333
+ case SettingType.Boolean:
334
+ return [Validators.required];
335
+ default:
336
+ return [];
337
+ }
338
+ }
339
+ getAllRolloutRules(formGroup) {
340
+ const settingValues = formGroup.get('settingValues');
341
+ const rolloutRules = settingValues.controls.map(cv => cv.get('rolloutRules').value);
342
+ return rolloutRules.length === 0 ? rolloutRules : rolloutRules.reduce((a, b) => a.concat(b));
343
+ }
344
+ getComparisonAttributes(rolloutRules) {
345
+ if (rolloutRules.length > 0) {
346
+ const currentComparisonAttributes = rolloutRules.map(r => r.comparisonAttribute);
347
+ const defaultComparisonAttributes = ['Identifier', 'Email', 'Country'];
348
+ const comparisonAttributes = currentComparisonAttributes.filter(c => defaultComparisonAttributes.indexOf(c) === -1);
349
+ return Array.from(new Set(comparisonAttributes));
350
+ }
351
+ else {
352
+ return [];
353
+ }
354
+ }
355
+ }
356
+ SettingListFormHelper.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: SettingListFormHelper, deps: [{ token: i2.FormBuilder }], target: i0.ɵɵFactoryTarget.Injectable });
357
+ SettingListFormHelper.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: SettingListFormHelper, providedIn: 'root' });
358
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: SettingListFormHelper, decorators: [{
359
+ type: Injectable,
360
+ args: [{ providedIn: 'root' }]
361
+ }], ctorParameters: function () { return [{ type: i2.FormBuilder }]; } });
362
+
363
+ class ExpandDialogComponent {
364
+ constructor(dialogRef, formBuilder, data) {
365
+ this.dialogRef = dialogRef;
366
+ this.formBuilder = formBuilder;
367
+ this.data = data;
368
+ }
369
+ ngOnInit() {
370
+ if (this.data.multiline) {
371
+ this.buildFormGroup();
372
+ }
373
+ else {
374
+ this.formControlSubscription = this.data.control.valueChanges.subscribe((value) => {
375
+ this.data.control.setValue(value, { onlySelf: true, emitEvent: false, emitModelToViewChange: true });
376
+ this.data.control.markAsDirty();
377
+ }, () => { }, () => { });
378
+ }
379
+ }
380
+ values() {
381
+ return this.formGroup.get('values');
382
+ }
383
+ getValueControls() {
384
+ return this.values().controls.map(c => c);
385
+ }
386
+ buildFormGroup() {
387
+ const value = this.data.control.value ? this.data.control.value : '';
388
+ const list = value.split(',').map((v) => v.trim()).filter((v) => !!v);
389
+ this.formGroup = this.formBuilder.group({
390
+ values: this.formBuilder.array(list.map((v) => this.formBuilder.control(v)))
391
+ });
392
+ this.formGroupSubscription = this.formGroup.valueChanges.subscribe((formGroupValue) => {
393
+ this.data.control.setValue(formGroupValue.values
394
+ .filter((v) => !!v)
395
+ .join(','), { onlySelf: true, emitEvent: false, emitModelToViewChange: true });
396
+ this.data.control.updateValueAndValidity();
397
+ this.data.control.markAsDirty();
398
+ });
399
+ }
400
+ add() {
401
+ this.formGroup.controls.values.push(this.formBuilder.control(''));
402
+ }
403
+ remove(index) {
404
+ this.formGroup.controls.values.removeAt(index);
405
+ }
406
+ ngOnDestroy() {
407
+ if (this.formControlSubscription) {
408
+ this.formControlSubscription.unsubscribe();
409
+ this.formControlSubscription = null;
410
+ }
411
+ if (this.formGroupSubscription) {
412
+ this.formGroupSubscription.unsubscribe();
413
+ this.formGroupSubscription = null;
414
+ }
415
+ }
416
+ close() {
417
+ this.dialogRef.close();
418
+ }
419
+ }
420
+ ExpandDialogComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ExpandDialogComponent, deps: [{ token: i1$1.MatDialogRef }, { token: i2.FormBuilder }, { token: MAT_DIALOG_DATA }], target: i0.ɵɵFactoryTarget.Component });
421
+ ExpandDialogComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: ExpandDialogComponent, selector: "configcat-expand-dialog", ngImport: i0, template: "<div mat-dialog-content class=\"container\">\n\n <mat-form-field appearance=\"outline\" *ngIf=\"!data.multiline\">\n <mat-label></mat-label>\n <textarea matInput [formControl]=\"data.control\" rows=\"15\"></textarea>\n </mat-form-field>\n <div [formGroup]=\"formGroup\" *ngIf=\"data.multiline\">\n <div *ngFor=\"let valueControl of getValueControls(); let i = index;\"\n class=\"value-field\">\n <mat-form-field appearance=\"outline\">\n <input matInput [formControl]=\"valueControl\" rows=\"15\" />\n </mat-form-field>\n <button (click)=\"remove(i)\" mat-icon-button type=\"button\">\n <mat-icon>delete_outline</mat-icon>\n </button>\n </div>\n <button (click)=\"add()\" mat-icon-button type=\"button\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n</div>\n<div mat-dialog-actions>\n <button type=\"button\" mat-raised-button color=\"primary\" (click)=\"close()\">Done</button>\n</div>", styles: [".container>*{width:100%}.container>* .value-field{display:flex;font-size:12px;flex-wrap:nowrap}.container>* .value-field mat-form-field{flex-grow:1}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i4.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i1$1.MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { type: i5$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i5.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i1$1.MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]" }] });
422
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ExpandDialogComponent, decorators: [{
423
+ type: Component,
424
+ args: [{ selector: 'configcat-expand-dialog', template: "<div mat-dialog-content class=\"container\">\n\n <mat-form-field appearance=\"outline\" *ngIf=\"!data.multiline\">\n <mat-label></mat-label>\n <textarea matInput [formControl]=\"data.control\" rows=\"15\"></textarea>\n </mat-form-field>\n <div [formGroup]=\"formGroup\" *ngIf=\"data.multiline\">\n <div *ngFor=\"let valueControl of getValueControls(); let i = index;\"\n class=\"value-field\">\n <mat-form-field appearance=\"outline\">\n <input matInput [formControl]=\"valueControl\" rows=\"15\" />\n </mat-form-field>\n <button (click)=\"remove(i)\" mat-icon-button type=\"button\">\n <mat-icon>delete_outline</mat-icon>\n </button>\n </div>\n <button (click)=\"add()\" mat-icon-button type=\"button\">\n <mat-icon>add</mat-icon>\n </button>\n </div>\n</div>\n<div mat-dialog-actions>\n <button type=\"button\" mat-raised-button color=\"primary\" (click)=\"close()\">Done</button>\n</div>", styles: [".container>*{width:100%}.container>* .value-field{display:flex;font-size:12px;flex-wrap:nowrap}.container>* .value-field mat-form-field{flex-grow:1}\n"] }]
425
+ }], ctorParameters: function () { return [{ type: i1$1.MatDialogRef }, { type: i2.FormBuilder }, { type: undefined, decorators: [{
426
+ type: Inject,
427
+ args: [MAT_DIALOG_DATA]
428
+ }] }]; } });
429
+
430
+ class ValueComponent {
431
+ constructor(dialog) {
432
+ this.dialog = dialog;
433
+ this.SettingType = SettingType;
434
+ }
435
+ popOut() {
436
+ this.dialog.open(ExpandDialogComponent, {
437
+ width: '640px',
438
+ data: { control: this.valueFormControl }
439
+ });
440
+ }
441
+ }
442
+ ValueComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ValueComponent, deps: [{ token: i1$1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
443
+ ValueComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: ValueComponent, selector: "configcat-value", inputs: { valueFormControl: "valueFormControl", setting: "setting" }, ngImport: i0, template: "<div class=\"flex\">\n <div class=\"container\" [ngSwitch]=\"setting.settingType\">\n <div *ngSwitchCase=\"SettingType.String\" class=\"with-validation\">\n <span *ngIf=\"valueFormControl.invalid\" class=\"error\">*</span>\n <input [ngClass]=\"{'invalid': valueFormControl.invalid}\" type=\"text\"\n [formControl]=\"valueFormControl\" placeholder=\"my value\" name=\"value\">\n <div class=\"expand\" (click)=\"popOut()\" matTooltip=\"Pop-out Editor\">\n <mat-icon>height</mat-icon>\n </div>\n </div>\n <div *ngSwitchCase=\"SettingType.Int\" class=\"with-validation\">\n <span *ngIf=\"valueFormControl.invalid\" class=\"error\">*</span>\n <input [ngClass]=\"{'invalid': valueFormControl.invalid}\" type=\"number\" [formControl]=\"valueFormControl\"\n placeholder=\"42\" name=\"value\" />\n </div>\n <div *ngSwitchCase=\"SettingType.Double\" class=\"with-validation\">\n <span *ngIf=\"valueFormControl.invalid\" class=\"error\">*</span>\n <input [ngClass]=\"{'invalid': valueFormControl.invalid}\" type=\"number\" [formControl]=\"valueFormControl\"\n placeholder=\"3.14\" name=\"value\">\n </div>\n <div *ngSwitchCase=\"SettingType.Boolean\" class=\"toggle\">\n <label class=\"switch\">\n <input type=\"checkbox\" [formControl]=\"valueFormControl\" name=\"value\" />\n <span class=\"slider round\"></span>\n </label>\n </div>\n </div>\n <div *ngIf=\"setting.settingType === SettingType.Boolean\" class=\"spacer\"></div>\n\n</div>\n", styles: [".switch{position:relative;width:66px;height:30px;margin-left:4px;margin-top:0;margin-bottom:0}.switch input{display:none}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ff5252;transition:.4s;width:66px;height:30px}.slider:before{position:absolute;content:\"\";height:22px;width:22px;left:4px;bottom:4px;background-color:#fff;transition:.4s}input:checked+.slider{background-color:#9acd32}input:focus+.slider{box-shadow:0 0 1px #9acd32}input:checked+.slider:before{transform:translate(36px)}.slider.round{border-radius:34px}.slider.round:before{border-radius:50%}.slider:after{content:\"Off\";color:#fff;display:block;position:absolute;transform:translate(-14%,-50%);top:50%;left:50%;font-size:10px;font-family:Verdana,sans-serif}input:checked+.slider:after{content:\"On\";transform:translate(-91%,-50%)}\n", ".flex{display:flex;margin-right:20px;align-items:center}.flex .spacer{width:15px}.flex .container .with-validation{display:flex;flex-wrap:nowrap}.flex .container .toggle{width:66px;height:30px}.flex .container input{background-color:#fff;border:1px solid #e5e5e5;min-height:28px;font-size:15px;padding:0 30px 0 10px;font-family:Montserrat,Roboto,Helvetica Neue,sans-serif;font-weight:300;min-width:170px}.flex .container .invalid{border:1px solid #ff5252}.flex .container .error{color:#ff5252;margin-right:5px}@media (max-width: 1200px){.flex .container input{min-width:auto}}.flex .variationId{margin-left:5px;cursor:pointer;color:#888;display:flex;align-items:center}.flex .expand{position:relative;top:2px;height:24px;cursor:pointer;margin-left:-28px;z-index:1;color:#b3b3b3;background-color:#fff}.flex .expand mat-icon{transform:rotate(45deg)}\n"], components: [{ type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i5$1.NgSwitch, selector: "[ngSwitch]", inputs: ["ngSwitch"] }, { type: i5$1.NgSwitchCase, selector: "[ngSwitchCase]", inputs: ["ngSwitchCase"] }, { type: i5$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i5$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i5$2.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }] });
444
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ValueComponent, decorators: [{
445
+ type: Component,
446
+ args: [{ selector: 'configcat-value', template: "<div class=\"flex\">\n <div class=\"container\" [ngSwitch]=\"setting.settingType\">\n <div *ngSwitchCase=\"SettingType.String\" class=\"with-validation\">\n <span *ngIf=\"valueFormControl.invalid\" class=\"error\">*</span>\n <input [ngClass]=\"{'invalid': valueFormControl.invalid}\" type=\"text\"\n [formControl]=\"valueFormControl\" placeholder=\"my value\" name=\"value\">\n <div class=\"expand\" (click)=\"popOut()\" matTooltip=\"Pop-out Editor\">\n <mat-icon>height</mat-icon>\n </div>\n </div>\n <div *ngSwitchCase=\"SettingType.Int\" class=\"with-validation\">\n <span *ngIf=\"valueFormControl.invalid\" class=\"error\">*</span>\n <input [ngClass]=\"{'invalid': valueFormControl.invalid}\" type=\"number\" [formControl]=\"valueFormControl\"\n placeholder=\"42\" name=\"value\" />\n </div>\n <div *ngSwitchCase=\"SettingType.Double\" class=\"with-validation\">\n <span *ngIf=\"valueFormControl.invalid\" class=\"error\">*</span>\n <input [ngClass]=\"{'invalid': valueFormControl.invalid}\" type=\"number\" [formControl]=\"valueFormControl\"\n placeholder=\"3.14\" name=\"value\">\n </div>\n <div *ngSwitchCase=\"SettingType.Boolean\" class=\"toggle\">\n <label class=\"switch\">\n <input type=\"checkbox\" [formControl]=\"valueFormControl\" name=\"value\" />\n <span class=\"slider round\"></span>\n </label>\n </div>\n </div>\n <div *ngIf=\"setting.settingType === SettingType.Boolean\" class=\"spacer\"></div>\n\n</div>\n", styles: [".switch{position:relative;width:66px;height:30px;margin-left:4px;margin-top:0;margin-bottom:0}.switch input{display:none}.slider{position:absolute;cursor:pointer;top:0;left:0;right:0;bottom:0;background-color:#ff5252;transition:.4s;width:66px;height:30px}.slider:before{position:absolute;content:\"\";height:22px;width:22px;left:4px;bottom:4px;background-color:#fff;transition:.4s}input:checked+.slider{background-color:#9acd32}input:focus+.slider{box-shadow:0 0 1px #9acd32}input:checked+.slider:before{transform:translate(36px)}.slider.round{border-radius:34px}.slider.round:before{border-radius:50%}.slider:after{content:\"Off\";color:#fff;display:block;position:absolute;transform:translate(-14%,-50%);top:50%;left:50%;font-size:10px;font-family:Verdana,sans-serif}input:checked+.slider:after{content:\"On\";transform:translate(-91%,-50%)}\n", ".flex{display:flex;margin-right:20px;align-items:center}.flex .spacer{width:15px}.flex .container .with-validation{display:flex;flex-wrap:nowrap}.flex .container .toggle{width:66px;height:30px}.flex .container input{background-color:#fff;border:1px solid #e5e5e5;min-height:28px;font-size:15px;padding:0 30px 0 10px;font-family:Montserrat,Roboto,Helvetica Neue,sans-serif;font-weight:300;min-width:170px}.flex .container .invalid{border:1px solid #ff5252}.flex .container .error{color:#ff5252;margin-right:5px}@media (max-width: 1200px){.flex .container input{min-width:auto}}.flex .variationId{margin-left:5px;cursor:pointer;color:#888;display:flex;align-items:center}.flex .expand{position:relative;top:2px;height:24px;cursor:pointer;margin-left:-28px;z-index:1;color:#b3b3b3;background-color:#fff}.flex .expand mat-icon{transform:rotate(45deg)}\n"] }]
447
+ }], ctorParameters: function () { return [{ type: i1$1.MatDialog }]; }, propDecorators: { valueFormControl: [{
448
+ type: Input
449
+ }], setting: [{
450
+ type: Input
451
+ }] } });
452
+
453
+ class RolloutRulesComponent {
454
+ constructor(dialog) {
455
+ this.dialog = dialog;
456
+ this.readOnly = false;
457
+ this.SettingType = SettingType;
458
+ this.defaultComparisonAttributes = ['Identifier', 'Email', 'Country'];
459
+ this.rolloutRuleComparators = [
460
+ { value: RolloutRuleComparator.IsOneOf, label: 'IS ONE OF' },
461
+ { value: RolloutRuleComparator.IsNotOneOf, label: 'IS NOT ONE OF' },
462
+ { value: RolloutRuleComparator.Contains, label: 'CONTAINS' },
463
+ { value: RolloutRuleComparator.DoesNotContain, label: 'DOES NOT CONTAIN' },
464
+ { value: RolloutRuleComparator.SemVerIsOneOf, label: 'IS ONE OF (SemVer)' },
465
+ { value: RolloutRuleComparator.SemVerIsNotOneOf, label: 'IS NOT ONE OF (SemVer)' },
466
+ { value: RolloutRuleComparator.SemVerLess, label: '< (SemVer)' },
467
+ { value: RolloutRuleComparator.SemVerLessOrEquals, label: '<= (SemVer)' },
468
+ { value: RolloutRuleComparator.SemVerGreater, label: '> (SemVer)' },
469
+ { value: RolloutRuleComparator.SemVerGreaterOrEquals, label: '>= (SemVer)' },
470
+ { value: RolloutRuleComparator.NumberEquals, label: '= (Number)' },
471
+ { value: RolloutRuleComparator.NumberDoesNotEqual, label: '!= (Number)' },
472
+ { value: RolloutRuleComparator.NumberLess, label: '< (Number)' },
473
+ { value: RolloutRuleComparator.NumberLessOrEquals, label: '<= (Number)' },
474
+ { value: RolloutRuleComparator.NumberGreater, label: '> (Number)' },
475
+ { value: RolloutRuleComparator.NumberGreaterOrEquals, label: '>= (Number)' },
476
+ { value: RolloutRuleComparator.SensitiveIsOneOf, label: 'IS ONE OF (Sensitive)' },
477
+ { value: RolloutRuleComparator.SensitiveIsNotOneOf, label: 'IS NOT ONE OF (Sensitive)' },
478
+ ];
479
+ this.segmentComparators = [
480
+ { value: SegmentComparator.IsIn, label: 'IS IN SEGMENT' },
481
+ { value: SegmentComparator.IsNotIn, label: 'IS NOT IN SEGMENT' },
482
+ ];
483
+ }
484
+ onlyFirstTooltip() {
485
+ return this.formGroup.root.get('allRolloutRulesCount')?.value > 20 || this.rolloutRules().controls.length > 10;
486
+ }
487
+ setting() {
488
+ return this.formGroup.get('setting')?.value;
489
+ }
490
+ rolloutRules() {
491
+ return this.formGroup.get('rolloutRules');
492
+ }
493
+ comparisonAttributes() {
494
+ return this.formGroup.root.get('comparisonAttributes')?.value;
495
+ }
496
+ removeRule(index) {
497
+ this.rolloutRules().removeAt(index);
498
+ this.rolloutRules().markAsDirty();
499
+ }
500
+ onDrop(event) {
501
+ const rolloutRules = this.rolloutRules().controls;
502
+ moveItemInArray(rolloutRules, event.previousIndex, event.currentIndex);
503
+ this.formGroup.markAsDirty();
504
+ }
505
+ attributeChanged(event, comparisonAttribute) {
506
+ if (this.defaultComparisonAttributes.indexOf(event.value) !== -1) {
507
+ if (comparisonAttribute.value !== event.value) {
508
+ comparisonAttribute.setValue(event.value);
509
+ this.formGroup.markAsDirty();
510
+ }
511
+ }
512
+ else {
513
+ if (comparisonAttribute.value !== '') {
514
+ comparisonAttribute.setValue('');
515
+ this.formGroup.markAsDirty();
516
+ }
517
+ }
518
+ }
519
+ getPlaceHolder(rolloutRule) {
520
+ if (!rolloutRule.controls.comparisonAttribute.value) {
521
+ return '';
522
+ }
523
+ switch (rolloutRule.controls.comparator.value) {
524
+ case RolloutRuleComparator.IsOneOf:
525
+ case RolloutRuleComparator.IsNotOneOf:
526
+ case RolloutRuleComparator.SensitiveIsOneOf:
527
+ case RolloutRuleComparator.SensitiveIsNotOneOf:
528
+ switch (rolloutRule.controls.comparisonAttribute.value.toLowerCase()) {
529
+ case 'identifier':
530
+ return 'e.g: user_id1, user_id2, user_id3';
531
+ case 'email':
532
+ return 'e.g: jane@example.com, john@example.com';
533
+ case 'country':
534
+ return 'e.g: France, Brazil';
535
+ default:
536
+ return 'e.g: value1, value2, value3';
537
+ }
538
+ case RolloutRuleComparator.Contains:
539
+ case RolloutRuleComparator.DoesNotContain:
540
+ switch (rolloutRule.controls.comparisonAttribute.value.toLowerCase()) {
541
+ case 'identifier':
542
+ return 'part-of-id';
543
+ case 'email':
544
+ return 'e.g: @example.com';
545
+ case 'country':
546
+ return 'e.g: United';
547
+ default:
548
+ return 'e.g: any-part-of-your-value-string';
549
+ }
550
+ case RolloutRuleComparator.SemVerIsOneOf:
551
+ case RolloutRuleComparator.SemVerIsNotOneOf:
552
+ return 'e.g: 1.0.0, 2.0.1';
553
+ case RolloutRuleComparator.SemVerLessOrEquals:
554
+ case RolloutRuleComparator.SemVerLess:
555
+ case RolloutRuleComparator.SemVerGreater:
556
+ case RolloutRuleComparator.SemVerGreaterOrEquals:
557
+ return 'e.g: 1.0.0';
558
+ case RolloutRuleComparator.NumberEquals:
559
+ case RolloutRuleComparator.NumberDoesNotEqual:
560
+ case RolloutRuleComparator.NumberLess:
561
+ case RolloutRuleComparator.NumberLessOrEquals:
562
+ case RolloutRuleComparator.NumberGreater:
563
+ case RolloutRuleComparator.NumberGreaterOrEquals:
564
+ return 'e.g: 42';
565
+ }
566
+ return '';
567
+ }
568
+ getComparisonValueType(rolloutRule) {
569
+ switch (rolloutRule.controls.comparator.value) {
570
+ case RolloutRuleComparator.NumberEquals:
571
+ case RolloutRuleComparator.NumberDoesNotEqual:
572
+ case RolloutRuleComparator.NumberLess:
573
+ case RolloutRuleComparator.NumberLessOrEquals:
574
+ case RolloutRuleComparator.NumberGreater:
575
+ case RolloutRuleComparator.NumberGreaterOrEquals:
576
+ return 'number';
577
+ default:
578
+ return 'text';
579
+ }
580
+ }
581
+ getInfoClass(rolloutRule) {
582
+ if (!rolloutRule.controls.comparisonAttribute.value) {
583
+ return 'info';
584
+ }
585
+ switch (rolloutRule.controls.comparator.value) {
586
+ case RolloutRuleComparator.IsOneOf:
587
+ case RolloutRuleComparator.IsNotOneOf:
588
+ case RolloutRuleComparator.Contains:
589
+ case RolloutRuleComparator.DoesNotContain:
590
+ return 'warn';
591
+ default:
592
+ return 'info';
593
+ }
594
+ }
595
+ getInfoTooltip(rolloutRule) {
596
+ if (!rolloutRule.controls.comparisonAttribute.value) {
597
+ return 'Learn more about comparators';
598
+ }
599
+ switch (rolloutRule.controls.comparator.value) {
600
+ case RolloutRuleComparator.IsOneOf:
601
+ case RolloutRuleComparator.IsNotOneOf:
602
+ case RolloutRuleComparator.Contains:
603
+ case RolloutRuleComparator.DoesNotContain:
604
+ return 'Consider using sensitive text comparators. Click to learn more.';
605
+ default:
606
+ return 'Click to learn more about comparators';
607
+ }
608
+ }
609
+ comparatorChanged(rolloutRule) {
610
+ let validators = [];
611
+ switch (rolloutRule.controls.comparator.value) {
612
+ case RolloutRuleComparator.IsOneOf:
613
+ case RolloutRuleComparator.IsNotOneOf:
614
+ case RolloutRuleComparator.SensitiveIsOneOf:
615
+ case RolloutRuleComparator.SensitiveIsNotOneOf:
616
+ case RolloutRuleComparator.Contains:
617
+ case RolloutRuleComparator.DoesNotContain:
618
+ validators = [Validators.required, Validators.maxLength(65535)];
619
+ break;
620
+ case RolloutRuleComparator.SemVerIsOneOf:
621
+ case RolloutRuleComparator.SemVerIsNotOneOf:
622
+ validators = [Validators.required, this.validateSemVerList];
623
+ break;
624
+ case RolloutRuleComparator.SemVerLessOrEquals:
625
+ case RolloutRuleComparator.SemVerLess:
626
+ case RolloutRuleComparator.SemVerGreater:
627
+ case RolloutRuleComparator.SemVerGreaterOrEquals:
628
+ validators = [Validators.required, this.validateSemVer];
629
+ break;
630
+ case RolloutRuleComparator.NumberEquals:
631
+ case RolloutRuleComparator.NumberDoesNotEqual:
632
+ case RolloutRuleComparator.NumberLess:
633
+ case RolloutRuleComparator.NumberLessOrEquals:
634
+ case RolloutRuleComparator.NumberGreater:
635
+ case RolloutRuleComparator.NumberGreaterOrEquals:
636
+ validators = [Validators.required, Validators.min(-1.79769313486232E+308), Validators.max(1.79769313486232E+308)];
637
+ break;
638
+ }
639
+ rolloutRule.controls.comparisonValue.setValidators(validators);
640
+ rolloutRule.controls.comparisonValue.updateValueAndValidity();
641
+ }
642
+ isListType(rolloutRule) {
643
+ switch (rolloutRule.controls.comparator.value) {
644
+ case RolloutRuleComparator.IsOneOf:
645
+ case RolloutRuleComparator.IsNotOneOf:
646
+ case RolloutRuleComparator.SensitiveIsOneOf:
647
+ case RolloutRuleComparator.SensitiveIsNotOneOf:
648
+ case RolloutRuleComparator.SemVerIsOneOf:
649
+ case RolloutRuleComparator.SemVerIsNotOneOf:
650
+ return true;
651
+ default:
652
+ return false;
653
+ }
654
+ }
655
+ validateSemVer(c) {
656
+ if (valid(c.value) === null) {
657
+ return {
658
+ validateSemVer: {
659
+ valid: false
660
+ }
661
+ };
662
+ }
663
+ return null;
664
+ }
665
+ validateSemVerList(c) {
666
+ if (!c.value) {
667
+ return {
668
+ validateSemVerList: {
669
+ valid: false
670
+ }
671
+ };
672
+ }
673
+ const semvers = c.value.split(',').map((s) => s.trim());
674
+ if (semvers.find((s) => s && s !== '' && valid(s) === null)) {
675
+ return {
676
+ validateSemVerList: {
677
+ valid: false
678
+ }
679
+ };
680
+ }
681
+ return null;
682
+ }
683
+ popOut(rolloutRule) {
684
+ this.dialog.open(ExpandDialogComponent, {
685
+ width: '640px',
686
+ data: {
687
+ control: rolloutRule.controls.comparisonValue,
688
+ multiline: this.isListType(rolloutRule)
689
+ }
690
+ });
691
+ }
692
+ trackByIndex(index) {
693
+ return index;
694
+ }
695
+ getRolloutRuleValueFormControl(rolloutRule) {
696
+ return rolloutRule.controls.value;
697
+ }
698
+ getRolloutRuleComparisonValueFormControl(rolloutRule) {
699
+ return rolloutRule.controls.comparisonValue;
700
+ }
701
+ getRolloutRuleComparisonAttributeFormControl(rolloutRule) {
702
+ return rolloutRule.controls.comparisonAttribute;
703
+ }
704
+ getRolloutRuleTypeFormControl(rolloutRule) {
705
+ return rolloutRule.controls.type;
706
+ }
707
+ getRolloutRuleComparatorFormControl(rolloutRule) {
708
+ return rolloutRule.controls.comparator;
709
+ }
710
+ getRolloutRuleSegmentComparatorFormControl(rolloutRule) {
711
+ return rolloutRule.controls.segmentComparator;
712
+ }
713
+ getRolloutRuleSegmentIdFormControl(rolloutRule) {
714
+ return rolloutRule.controls.segmentId;
715
+ }
716
+ }
717
+ RolloutRulesComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: RolloutRulesComponent, deps: [{ token: i1$1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
718
+ RolloutRulesComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: RolloutRulesComponent, selector: "configcat-rollout-rules", inputs: { formGroup: "formGroup", readOnly: "readOnly", segments: "segments" }, ngImport: i0, template: "<div [formGroup]=\"formGroup\">\n <div cdkDropList (cdkDropListDropped)=\"onDrop($event)\" [cdkDropListDisabled]=\"readOnly\"\n [cdkDropListData]=\"rolloutRules().controls\">\n <div *ngFor=\"let rolloutRule of rolloutRules().controls; trackBy: trackByIndex; let i = index\" cdkDrag>\n <div class=\"targeting-row\">\n <div class=\"fields flex\" *ngIf=\"getRolloutRuleTypeFormControl(rolloutRule).value === 0\">\n <div class=\"drag-handle\" cdkDragHandle data-tooltip=\"Drag here to reorder\" *ngIf=\"!readOnly\">\n <mat-icon>drag_indicator</mat-icon>\n </div>\n <div class=\"if\">\n <mat-chip-list [class.spacing]=\"i === 0\">\n <mat-chip class=\"chip\">{{ i === 0 ? 'IF' : 'ELSE IF' }}</mat-chip>\n </mat-chip-list>\n <a href=\"https://configcat.com/docs/advanced/user-object\" target=\"_blank\"\n rel=\"noopener noreferrer\">user's</a>\n </div>\n\n <select class=\"custom-select attribute-select\" matTooltip=\"Comparison attribute\"\n matTooltipPosition=\"above\" [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\"\n (change)=\"attributeChanged($event.target, getRolloutRuleComparisonAttributeFormControl(rolloutRule))\">\n <option *ngFor=\"let comparisonAttribute of defaultComparisonAttributes\"\n [selected]=\"comparisonAttribute === getRolloutRuleComparisonAttributeFormControl(rolloutRule).value\">\n {{comparisonAttribute}}</option>\n <option\n [selected]=\"defaultComparisonAttributes.indexOf(getRolloutRuleComparisonAttributeFormControl(rolloutRule).value) === -1\">\n Custom\n </option>\n </select>\n\n\n <span class=\"attribute-span\" data-tooltip=\"Custom user attribute\"\n [hidden]=\"defaultComparisonAttributes.indexOf(getRolloutRuleComparisonAttributeFormControl(rolloutRule).value) !== -1\">\n <span class=\"attribute-error\"\n *ngIf=\"getRolloutRuleComparisonAttributeFormControl(rolloutRule).invalid\">*</span>\n <input\n [ngClass]=\"{'invalid': getRolloutRuleComparisonAttributeFormControl(rolloutRule).invalid}\"\n type=\"text\" matInput [matAutocomplete]=\"auto\"\n [formControl]=\"getRolloutRuleComparisonAttributeFormControl(rolloutRule)\" class=\"attribute\"\n placeholder=\"e.g. Eye color\">\n </span>\n\n <mat-autocomplete #auto=\"matAutocomplete\">\n <mat-option *ngFor=\"let option of comparisonAttributes()\" [value]=\"option\">\n {{option}}\n </mat-option>\n </mat-autocomplete>\n\n <div class=\"select-wrapper\">\n <select class=\"custom-select\" [formControl]=\"getRolloutRuleComparatorFormControl(rolloutRule)\"\n matTooltip=\"Comparator\" matTooltipPosition=\"above\"\n [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\"\n (change)=\"comparatorChanged(rolloutRule)\">\n <optgroup label=\"SENSITIVE TEXT\">\n <option *ngFor=\"let comparator of rolloutRuleComparators.slice(16, 18)\"\n [ngValue]=\"comparator.value\">\n {{comparator.label}}\n </option>\n </optgroup>\n <optgroup label=\"TEXT\">\n <option *ngFor=\"let comparator of rolloutRuleComparators.slice(0, 4)\"\n [ngValue]=\"comparator.value\">\n {{comparator.label}}\n </option>\n </optgroup>\n <optgroup label=\"SEMANTIC VERSION\">\n <option *ngFor=\"let comparator of rolloutRuleComparators.slice(4, 10)\"\n [ngValue]=\"comparator.value\">\n {{comparator.label}}\n </option>\n </optgroup>\n <optgroup label=\"NUMBER\">\n <option *ngFor=\"let comparator of rolloutRuleComparators.slice(10, 16)\"\n [ngValue]=\"comparator.value\">\n {{comparator.label}}\n </option>\n </optgroup>\n </select>\n <div [class]=\"getInfoClass(rolloutRule)\" [matTooltip]=\"getInfoTooltip(rolloutRule)\"\n [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\">\n <a href=\"https://configcat.com/docs/advanced/targeting/#comparator\" target=\"_blank\"\n rel=\"noopener noreferrer\">\n <mat-icon>info</mat-icon>\n </a>\n </div>\n </div>\n\n <div class=\"comparison-value\" data-tooltip=\"Comparison value\">\n <span class=\"error\"\n *ngIf=\"getRolloutRuleComparisonValueFormControl(rolloutRule).invalid\">*</span>\n\n <input [ngClass]=\"{'invalid': getRolloutRuleComparisonValueFormControl(rolloutRule).invalid}\"\n [formControl]=\"getRolloutRuleComparisonValueFormControl(rolloutRule)\"\n [type]=\"getComparisonValueType(rolloutRule)\" [placeholder]=\"getPlaceHolder(rolloutRule)\">\n <div class=\"expand\" matTooltip=\"Pop-out Editor\" (click)=\"popOut(rolloutRule)\"\n *ngIf=\"getComparisonValueType(rolloutRule)==='text'\">\n <mat-icon>height</mat-icon>\n </div>\n </div>\n\n <div class=\"delete\" matTooltip=\"Remove targeting rule\"\n [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\" *ngIf=\"!readOnly\" (click)=\"removeRule(i)\">\n <mat-icon>cancel</mat-icon>\n </div>\n </div>\n\n <div class=\"fields flex\" *ngIf=\"getRolloutRuleTypeFormControl(rolloutRule).value === 1\">\n <div class=\"drag-handle\" cdkDragHandle data-tooltip=\"Drag here to reorder\" *ngIf=\"!readOnly\">\n <mat-icon>drag_indicator</mat-icon>\n </div>\n <div class=\"if\">\n <mat-chip-list [class.spacing]=\"i === 0\">\n <mat-chip class=\"chip\">{{ i === 0 ? 'IF' : 'ELSE IF' }}</mat-chip>\n </mat-chip-list>\n <a href=\"https://configcat.com/docs/advanced/user-object\" target=\"_blank\"\n rel=\"noopener noreferrer\">user</a>\n </div>\n\n\n <div class=\"select-wrapper\">\n <select class=\"custom-select segment-comparator\"\n [formControl]=\"getRolloutRuleSegmentComparatorFormControl(rolloutRule)\"\n matTooltip=\"Segment comparator\" matTooltipPosition=\"above\"\n [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\">\n <option *ngFor=\"let comparator of segmentComparators\" [ngValue]=\"comparator.value\">\n {{comparator.label}}\n </option>\n </select>\n </div>\n\n <div class=\"select-wrapper\">\n <span class=\"attribute-error\"\n *ngIf=\"getRolloutRuleSegmentIdFormControl(rolloutRule).invalid\">*</span>\n <select class=\"custom-select segment-select\"\n [formControl]=\"getRolloutRuleSegmentIdFormControl(rolloutRule)\" matTooltip=\"Segment\"\n matTooltipPosition=\"above\" [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\"\n [ngClass]=\"{'invalid': getRolloutRuleSegmentIdFormControl(rolloutRule).invalid}\">\n <option *ngFor=\"let segment of segments\" [ngValue]=\"segment.segmentId\">\n {{segment.name}}\n </option>\n </select>\n </div>\n\n\n <div class=\"delete\" matTooltip=\"Remove targeting rule\"\n [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\" *ngIf=\"!readOnly\" (click)=\"removeRule(i)\">\n <mat-icon>cancel</mat-icon>\n </div>\n </div>\n\n\n <div class=\"value flex\">\n <div class=\"serve\" *ngIf=\"setting().settingType !== SettingType.Boolean\">\n <mat-chip-list>\n <mat-chip class=\"chip\">Serve:</mat-chip>\n </mat-chip-list>\n </div>\n\n <configcat-value class=\"served-value\"\n [valueFormControl]=\"getRolloutRuleValueFormControl(rolloutRule)\" [setting]=\"setting()\">\n </configcat-value>\n </div>\n </div>\n </div>\n </div>\n</div>", styles: [".cdk-drop-list-dragging .cdk-drag{transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-animating{transition:transform .3s cubic-bezier(0,0,.2,1)}.targeting-row{border:1px solid #d5d5d5;border-radius:4px;background-color:#fff;margin:.5em 1em;display:flex;position:relative;padding:.5em 0}.targeting-row .select-wrapper{position:relative}.targeting-row .info{position:absolute;cursor:pointer;top:-8px;left:166px}.targeting-row .info a{color:#7fb3fd}.targeting-row .info a:hover{color:#0068f0}.targeting-row .info mat-icon{font-size:18px}.targeting-row .warn{position:absolute;cursor:pointer;top:-8px;left:128px}.targeting-row .warn a{color:#fdc67f}.targeting-row .warn a:hover{color:#ff9200}.targeting-row .warn mat-icon{font-size:18px}.chip{background-color:#67b1fc3d}.fields{justify-content:left;max-width:1060px;flex-grow:100}.fields .if{display:flex;align-items:center}.fields .if>*{margin:0 .5em}.fields .if .spacing{margin-right:46px}.fields .attribute-span{margin-left:.5em}.fields .attribute{width:170px;background-color:#fff;border:1px solid #e5e5e5;min-height:28px;min-width:170px;font-size:15px;padding:0 10px;font-family:Montserrat,Roboto,Helvetica Neue,sans-serif;font-weight:300}.fields .invalid{border:1px solid #ff5252}.fields .attribute-error{color:#ff5252;margin-right:5px}.fields .delete{position:absolute;color:#d6a9a9;cursor:pointer;top:-8px;right:-12px;z-index:999}.fields .delete:hover{color:#ed5251}.fields .delete mat-icon{font-size:20px}.fields .drag-handle{position:absolute;cursor:-moz-grab;left:-20px;top:14px}.fields .drag-handle mat-icon{font-size:20px}.fields .custom-select{margin-left:.5em;width:170px;background-color:#fff;border:1px solid #e5e5e5;min-height:30px;min-width:170px;font-size:.8em;padding:0 5px;font-family:Montserrat,Roboto,Helvetica Neue,sans-serif;font-weight:300}.fields .attribute-select{min-width:100px;width:100px;margin-left:0}.fields .comparison-value{flex-grow:100;min-width:200px;display:flex;align-items:center;margin-left:.5em}.fields .comparison-value .error{color:#ff5252;margin:0 5px}.fields .comparison-value input{background-color:#fff;border:1px solid #e5e5e5;min-height:28px;min-width:170px;flex-grow:100;font-size:15px;padding:0 30px 0 10px;font-family:Montserrat,Roboto,Helvetica Neue,sans-serif;font-weight:300}.fields .comparison-value .invalid{border:1px solid #ff5252}.value{margin-left:auto;flex-wrap:nowrap}.value .serve{margin:0 5px}.warn{padding-left:3em;font-size:.8em}.flex{display:flex;flex-wrap:wrap;align-items:center}.expand{position:absolute;right:2px;font-size:8px;cursor:pointer;margin-left:-28px;z-index:1;color:#b3b3b3;background-color:#fff}.expand mat-icon{transform:rotate(45deg)}@media (max-width: 1200px){.targeting-row{flex-wrap:wrap}.targeting-row .fields{max-width:500px}}@media (max-width: 700px){.targeting-row{flex-direction:column;margin:.5em .3em}.targeting-row .help{left:161px}.targeting-row .fields{flex-direction:column;align-items:stretch}.targeting-row .fields .custom-select,.targeting-row .fields .comparison-value{margin:0}}\n"], components: [{ type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: i3$2.MatChipList, selector: "mat-chip-list", inputs: ["errorStateMatcher", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "aria-orientation", "selectable", "tabIndex"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i4$1.MatAutocomplete, selector: "mat-autocomplete", inputs: ["disableRipple"], exportAs: ["matAutocomplete"] }, { type: i4$2.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { type: ValueComponent, selector: "configcat-value", inputs: ["valueFormControl", "setting"] }], directives: [{ type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i8.CdkDropList, selector: "[cdkDropList], cdk-drop-list", inputs: ["cdkDropListConnectedTo", "cdkDropListData", "cdkDropListOrientation", "id", "cdkDropListLockAxis", "cdkDropListDisabled", "cdkDropListSortingDisabled", "cdkDropListEnterPredicate", "cdkDropListSortPredicate", "cdkDropListAutoScrollDisabled", "cdkDropListAutoScrollStep"], outputs: ["cdkDropListDropped", "cdkDropListEntered", "cdkDropListExited", "cdkDropListSorted"], exportAs: ["cdkDropList"] }, { type: i5$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i8.CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { type: i5$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i8.CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { type: i3$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$2.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i2.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { type: i2.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { type: i5.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i4$1.MatAutocompleteTrigger, selector: "input[matAutocomplete], textarea[matAutocomplete]", exportAs: ["matAutocompleteTrigger"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i5$1.NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i2.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }] });
719
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: RolloutRulesComponent, decorators: [{
720
+ type: Component,
721
+ args: [{ selector: 'configcat-rollout-rules', template: "<div [formGroup]=\"formGroup\">\n <div cdkDropList (cdkDropListDropped)=\"onDrop($event)\" [cdkDropListDisabled]=\"readOnly\"\n [cdkDropListData]=\"rolloutRules().controls\">\n <div *ngFor=\"let rolloutRule of rolloutRules().controls; trackBy: trackByIndex; let i = index\" cdkDrag>\n <div class=\"targeting-row\">\n <div class=\"fields flex\" *ngIf=\"getRolloutRuleTypeFormControl(rolloutRule).value === 0\">\n <div class=\"drag-handle\" cdkDragHandle data-tooltip=\"Drag here to reorder\" *ngIf=\"!readOnly\">\n <mat-icon>drag_indicator</mat-icon>\n </div>\n <div class=\"if\">\n <mat-chip-list [class.spacing]=\"i === 0\">\n <mat-chip class=\"chip\">{{ i === 0 ? 'IF' : 'ELSE IF' }}</mat-chip>\n </mat-chip-list>\n <a href=\"https://configcat.com/docs/advanced/user-object\" target=\"_blank\"\n rel=\"noopener noreferrer\">user's</a>\n </div>\n\n <select class=\"custom-select attribute-select\" matTooltip=\"Comparison attribute\"\n matTooltipPosition=\"above\" [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\"\n (change)=\"attributeChanged($event.target, getRolloutRuleComparisonAttributeFormControl(rolloutRule))\">\n <option *ngFor=\"let comparisonAttribute of defaultComparisonAttributes\"\n [selected]=\"comparisonAttribute === getRolloutRuleComparisonAttributeFormControl(rolloutRule).value\">\n {{comparisonAttribute}}</option>\n <option\n [selected]=\"defaultComparisonAttributes.indexOf(getRolloutRuleComparisonAttributeFormControl(rolloutRule).value) === -1\">\n Custom\n </option>\n </select>\n\n\n <span class=\"attribute-span\" data-tooltip=\"Custom user attribute\"\n [hidden]=\"defaultComparisonAttributes.indexOf(getRolloutRuleComparisonAttributeFormControl(rolloutRule).value) !== -1\">\n <span class=\"attribute-error\"\n *ngIf=\"getRolloutRuleComparisonAttributeFormControl(rolloutRule).invalid\">*</span>\n <input\n [ngClass]=\"{'invalid': getRolloutRuleComparisonAttributeFormControl(rolloutRule).invalid}\"\n type=\"text\" matInput [matAutocomplete]=\"auto\"\n [formControl]=\"getRolloutRuleComparisonAttributeFormControl(rolloutRule)\" class=\"attribute\"\n placeholder=\"e.g. Eye color\">\n </span>\n\n <mat-autocomplete #auto=\"matAutocomplete\">\n <mat-option *ngFor=\"let option of comparisonAttributes()\" [value]=\"option\">\n {{option}}\n </mat-option>\n </mat-autocomplete>\n\n <div class=\"select-wrapper\">\n <select class=\"custom-select\" [formControl]=\"getRolloutRuleComparatorFormControl(rolloutRule)\"\n matTooltip=\"Comparator\" matTooltipPosition=\"above\"\n [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\"\n (change)=\"comparatorChanged(rolloutRule)\">\n <optgroup label=\"SENSITIVE TEXT\">\n <option *ngFor=\"let comparator of rolloutRuleComparators.slice(16, 18)\"\n [ngValue]=\"comparator.value\">\n {{comparator.label}}\n </option>\n </optgroup>\n <optgroup label=\"TEXT\">\n <option *ngFor=\"let comparator of rolloutRuleComparators.slice(0, 4)\"\n [ngValue]=\"comparator.value\">\n {{comparator.label}}\n </option>\n </optgroup>\n <optgroup label=\"SEMANTIC VERSION\">\n <option *ngFor=\"let comparator of rolloutRuleComparators.slice(4, 10)\"\n [ngValue]=\"comparator.value\">\n {{comparator.label}}\n </option>\n </optgroup>\n <optgroup label=\"NUMBER\">\n <option *ngFor=\"let comparator of rolloutRuleComparators.slice(10, 16)\"\n [ngValue]=\"comparator.value\">\n {{comparator.label}}\n </option>\n </optgroup>\n </select>\n <div [class]=\"getInfoClass(rolloutRule)\" [matTooltip]=\"getInfoTooltip(rolloutRule)\"\n [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\">\n <a href=\"https://configcat.com/docs/advanced/targeting/#comparator\" target=\"_blank\"\n rel=\"noopener noreferrer\">\n <mat-icon>info</mat-icon>\n </a>\n </div>\n </div>\n\n <div class=\"comparison-value\" data-tooltip=\"Comparison value\">\n <span class=\"error\"\n *ngIf=\"getRolloutRuleComparisonValueFormControl(rolloutRule).invalid\">*</span>\n\n <input [ngClass]=\"{'invalid': getRolloutRuleComparisonValueFormControl(rolloutRule).invalid}\"\n [formControl]=\"getRolloutRuleComparisonValueFormControl(rolloutRule)\"\n [type]=\"getComparisonValueType(rolloutRule)\" [placeholder]=\"getPlaceHolder(rolloutRule)\">\n <div class=\"expand\" matTooltip=\"Pop-out Editor\" (click)=\"popOut(rolloutRule)\"\n *ngIf=\"getComparisonValueType(rolloutRule)==='text'\">\n <mat-icon>height</mat-icon>\n </div>\n </div>\n\n <div class=\"delete\" matTooltip=\"Remove targeting rule\"\n [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\" *ngIf=\"!readOnly\" (click)=\"removeRule(i)\">\n <mat-icon>cancel</mat-icon>\n </div>\n </div>\n\n <div class=\"fields flex\" *ngIf=\"getRolloutRuleTypeFormControl(rolloutRule).value === 1\">\n <div class=\"drag-handle\" cdkDragHandle data-tooltip=\"Drag here to reorder\" *ngIf=\"!readOnly\">\n <mat-icon>drag_indicator</mat-icon>\n </div>\n <div class=\"if\">\n <mat-chip-list [class.spacing]=\"i === 0\">\n <mat-chip class=\"chip\">{{ i === 0 ? 'IF' : 'ELSE IF' }}</mat-chip>\n </mat-chip-list>\n <a href=\"https://configcat.com/docs/advanced/user-object\" target=\"_blank\"\n rel=\"noopener noreferrer\">user</a>\n </div>\n\n\n <div class=\"select-wrapper\">\n <select class=\"custom-select segment-comparator\"\n [formControl]=\"getRolloutRuleSegmentComparatorFormControl(rolloutRule)\"\n matTooltip=\"Segment comparator\" matTooltipPosition=\"above\"\n [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\">\n <option *ngFor=\"let comparator of segmentComparators\" [ngValue]=\"comparator.value\">\n {{comparator.label}}\n </option>\n </select>\n </div>\n\n <div class=\"select-wrapper\">\n <span class=\"attribute-error\"\n *ngIf=\"getRolloutRuleSegmentIdFormControl(rolloutRule).invalid\">*</span>\n <select class=\"custom-select segment-select\"\n [formControl]=\"getRolloutRuleSegmentIdFormControl(rolloutRule)\" matTooltip=\"Segment\"\n matTooltipPosition=\"above\" [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\"\n [ngClass]=\"{'invalid': getRolloutRuleSegmentIdFormControl(rolloutRule).invalid}\">\n <option *ngFor=\"let segment of segments\" [ngValue]=\"segment.segmentId\">\n {{segment.name}}\n </option>\n </select>\n </div>\n\n\n <div class=\"delete\" matTooltip=\"Remove targeting rule\"\n [matTooltipDisabled]=\"onlyFirstTooltip() && i !== 0\" *ngIf=\"!readOnly\" (click)=\"removeRule(i)\">\n <mat-icon>cancel</mat-icon>\n </div>\n </div>\n\n\n <div class=\"value flex\">\n <div class=\"serve\" *ngIf=\"setting().settingType !== SettingType.Boolean\">\n <mat-chip-list>\n <mat-chip class=\"chip\">Serve:</mat-chip>\n </mat-chip-list>\n </div>\n\n <configcat-value class=\"served-value\"\n [valueFormControl]=\"getRolloutRuleValueFormControl(rolloutRule)\" [setting]=\"setting()\">\n </configcat-value>\n </div>\n </div>\n </div>\n </div>\n</div>", styles: [".cdk-drop-list-dragging .cdk-drag{transition:transform .25s cubic-bezier(0,0,.2,1)}.cdk-drag-animating{transition:transform .3s cubic-bezier(0,0,.2,1)}.targeting-row{border:1px solid #d5d5d5;border-radius:4px;background-color:#fff;margin:.5em 1em;display:flex;position:relative;padding:.5em 0}.targeting-row .select-wrapper{position:relative}.targeting-row .info{position:absolute;cursor:pointer;top:-8px;left:166px}.targeting-row .info a{color:#7fb3fd}.targeting-row .info a:hover{color:#0068f0}.targeting-row .info mat-icon{font-size:18px}.targeting-row .warn{position:absolute;cursor:pointer;top:-8px;left:128px}.targeting-row .warn a{color:#fdc67f}.targeting-row .warn a:hover{color:#ff9200}.targeting-row .warn mat-icon{font-size:18px}.chip{background-color:#67b1fc3d}.fields{justify-content:left;max-width:1060px;flex-grow:100}.fields .if{display:flex;align-items:center}.fields .if>*{margin:0 .5em}.fields .if .spacing{margin-right:46px}.fields .attribute-span{margin-left:.5em}.fields .attribute{width:170px;background-color:#fff;border:1px solid #e5e5e5;min-height:28px;min-width:170px;font-size:15px;padding:0 10px;font-family:Montserrat,Roboto,Helvetica Neue,sans-serif;font-weight:300}.fields .invalid{border:1px solid #ff5252}.fields .attribute-error{color:#ff5252;margin-right:5px}.fields .delete{position:absolute;color:#d6a9a9;cursor:pointer;top:-8px;right:-12px;z-index:999}.fields .delete:hover{color:#ed5251}.fields .delete mat-icon{font-size:20px}.fields .drag-handle{position:absolute;cursor:-moz-grab;left:-20px;top:14px}.fields .drag-handle mat-icon{font-size:20px}.fields .custom-select{margin-left:.5em;width:170px;background-color:#fff;border:1px solid #e5e5e5;min-height:30px;min-width:170px;font-size:.8em;padding:0 5px;font-family:Montserrat,Roboto,Helvetica Neue,sans-serif;font-weight:300}.fields .attribute-select{min-width:100px;width:100px;margin-left:0}.fields .comparison-value{flex-grow:100;min-width:200px;display:flex;align-items:center;margin-left:.5em}.fields .comparison-value .error{color:#ff5252;margin:0 5px}.fields .comparison-value input{background-color:#fff;border:1px solid #e5e5e5;min-height:28px;min-width:170px;flex-grow:100;font-size:15px;padding:0 30px 0 10px;font-family:Montserrat,Roboto,Helvetica Neue,sans-serif;font-weight:300}.fields .comparison-value .invalid{border:1px solid #ff5252}.value{margin-left:auto;flex-wrap:nowrap}.value .serve{margin:0 5px}.warn{padding-left:3em;font-size:.8em}.flex{display:flex;flex-wrap:wrap;align-items:center}.expand{position:absolute;right:2px;font-size:8px;cursor:pointer;margin-left:-28px;z-index:1;color:#b3b3b3;background-color:#fff}.expand mat-icon{transform:rotate(45deg)}@media (max-width: 1200px){.targeting-row{flex-wrap:wrap}.targeting-row .fields{max-width:500px}}@media (max-width: 700px){.targeting-row{flex-direction:column;margin:.5em .3em}.targeting-row .help{left:161px}.targeting-row .fields{flex-direction:column;align-items:stretch}.targeting-row .fields .custom-select,.targeting-row .fields .comparison-value{margin:0}}\n"] }]
722
+ }], ctorParameters: function () { return [{ type: i1$1.MatDialog }]; }, propDecorators: { formGroup: [{
723
+ type: Input
724
+ }], readOnly: [{
725
+ type: Input
726
+ }], segments: [{
727
+ type: Input
728
+ }] } });
729
+
730
+ class RolloutPercentageItemsComponent {
731
+ constructor() {
732
+ this.readOnly = false;
733
+ this.SettingType = SettingType;
734
+ }
735
+ setting() {
736
+ return this.formGroup.get('setting')?.value;
737
+ }
738
+ rolloutRules() {
739
+ return this.formGroup.get('rolloutRules');
740
+ }
741
+ rolloutPercentageItems() {
742
+ return this.formGroup.get('rolloutPercentageItems');
743
+ }
744
+ rolloutPercentageItemsSum() {
745
+ return this.formGroup.get('rolloutPercentageItemsSum');
746
+ }
747
+ value(rolloutPercentageItem) {
748
+ return this.setting().settingType === SettingType.Boolean ?
749
+ rolloutPercentageItem.get('valueDisabled') :
750
+ rolloutPercentageItem.get('value');
751
+ }
752
+ percentageChanged(index) {
753
+ if (this.rolloutPercentageItems().controls[index].value.percentage < 0) {
754
+ this.rolloutPercentageItems().controls[index].controls.percentage.setValue(0);
755
+ }
756
+ if (this.rolloutPercentageItems().controls[index].value.percentage > 100) {
757
+ this.rolloutPercentageItems().controls[index].controls.percentage.setValue(100);
758
+ }
759
+ if (this.rolloutPercentageItems().controls.length === 2) {
760
+ this.rolloutPercentageItems().controls[1 - index].controls.percentage
761
+ .setValue(100 - this.rolloutPercentageItems().controls[index].value.percentage);
762
+ }
763
+ this.updateSum();
764
+ }
765
+ updateSum() {
766
+ if (this.rolloutPercentageItems().controls.length === 0) {
767
+ this.rolloutPercentageItemsSum().setValue(100);
768
+ }
769
+ else {
770
+ this.rolloutPercentageItemsSum().setValue(this.rolloutPercentageItems().controls.map(v => v.value.percentage)
771
+ .reduce((a, b) => a + b));
772
+ }
773
+ }
774
+ removeRolloutPercentageItem(index) {
775
+ this.rolloutPercentageItems().removeAt(index);
776
+ this.rolloutPercentageItems().markAsDirty();
777
+ this.updateSum();
778
+ }
779
+ removeAll() {
780
+ this.rolloutPercentageItems().clear();
781
+ this.rolloutPercentageItems().markAsDirty();
782
+ this.updateSum();
783
+ }
784
+ getRolloutPercentageItemFormGroups() {
785
+ return this.rolloutPercentageItems()?.controls?.map(c => c);
786
+ }
787
+ getPercentageFormControl(rolloutPercentageItem) {
788
+ return rolloutPercentageItem.controls.percentage;
789
+ }
790
+ }
791
+ RolloutPercentageItemsComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: RolloutPercentageItemsComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
792
+ RolloutPercentageItemsComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: RolloutPercentageItemsComponent, selector: "configcat-rollout-percentage-items", inputs: { formGroup: "formGroup", readOnly: "readOnly" }, ngImport: i0, template: "<div class=\"percentage-wrapper\" [formGroup]=\"formGroup\">\n\n <div class=\"if\" *ngIf=\"rolloutRules().controls.length > 0\">\n <mat-chip-list>\n <mat-chip class=\"chip\">ELSE IF</mat-chip>\n </mat-chip-list>\n </div>\n <div class=\"grow\">\n <div class=\"percentage-row flex\"\n *ngFor=\"let rolloutPercentageItem of getRolloutPercentageItemFormGroups(); let i = index\">\n <div class=\"flex\">\n <input type=\"number\" [formControl]=\"getPercentageFormControl(rolloutPercentageItem)\"\n (input)=\"percentageChanged(i)\">%\n <span class=\"users\">of <a href=\"https://configcat.com/docs/advanced/user-object\" target=\"_blank\"\n rel=\"noopener noreferrer\">users</a>\n </span>\n </div>\n\n <div class=\"delete-option\" matTooltip=\"Remove this % option\"\n *ngIf=\"!readOnly && rolloutPercentageItems().controls.length > 2\"\n (click)=\"removeRolloutPercentageItem(i)\">\n <mat-icon>cancel</mat-icon>\n </div>\n\n <span data-tooltip=\"The sum of percentages must be equal to 100.\"\n *ngIf=\"(i === rolloutPercentageItems().controls.length -1) && (rolloutPercentageItemsSum().invalid)\">\n <mat-icon color=\"warn\">\n error_outline\n </mat-icon>\n </span>\n\n <div class=\"value flex\">\n <span class=\"value-name\" *ngIf=\"setting().settingType !== SettingType.Boolean\">Served value:</span>\n <configcat-value class=\"served-value\" [valueFormControl]=\"value(rolloutPercentageItem)\"\n [setting]=\"setting()\">\n </configcat-value>\n </div>\n <div class=\"delete\" matTooltip=\"Remove % options\" (click)=\"removeAll()\" *ngIf=\"!readOnly\">\n <mat-icon>cancel</mat-icon>\n </div>\n </div>\n </div>\n</div>", styles: [".percentage-wrapper{border:1px solid #d5d5d5;background-color:#fff;border-radius:4px;margin:.5em 1em;position:relative;padding:.5em 0;display:flex}.percentage-wrapper .delete{position:absolute;color:#d6a9a9;cursor:pointer;top:-8px;right:-12px}.percentage-wrapper .delete:hover{color:#ed5251}.percentage-wrapper .delete mat-icon{font-size:20px}.percentage-wrapper .delete-option{color:#d6a9a9;cursor:pointer;margin-left:1rem;margin-top:4px}.percentage-wrapper .delete-option:hover{color:#ed5251}.percentage-wrapper .delete-option mat-icon{font-size:20px}.if{display:flex;align-items:center}.if>*{margin:0 .5em}.if .spacing{margin-right:44px}.if .chip{background-color:#67b1fc3d}.grow{flex-grow:1}.percentage-row{min-height:40px;margin-left:.5em}.flex{display:flex;flex-wrap:wrap;align-items:center}.value{margin-left:auto;min-width:100px}.value .value-name{display:none}input{background-color:#fff;border:1px solid #e5e5e5;min-height:28px;width:40px;margin-right:5px;font-size:15px;padding:0 5px;font-family:Montserrat,Roboto,Helvetica Neue,sans-serif;font-weight:300}.users{margin-left:20px}@media (max-width: 700px){.percentage-wrapper{margin:.5em .3em}}\n"], components: [{ type: i3$2.MatChipList, selector: "mat-chip-list", inputs: ["errorStateMatcher", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "aria-orientation", "selectable", "tabIndex"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: ValueComponent, selector: "configcat-value", inputs: ["valueFormControl", "setting"] }], directives: [{ type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }, { type: i5$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { type: i2.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i5$2.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }] });
793
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: RolloutPercentageItemsComponent, decorators: [{
794
+ type: Component,
795
+ args: [{ selector: 'configcat-rollout-percentage-items', template: "<div class=\"percentage-wrapper\" [formGroup]=\"formGroup\">\n\n <div class=\"if\" *ngIf=\"rolloutRules().controls.length > 0\">\n <mat-chip-list>\n <mat-chip class=\"chip\">ELSE IF</mat-chip>\n </mat-chip-list>\n </div>\n <div class=\"grow\">\n <div class=\"percentage-row flex\"\n *ngFor=\"let rolloutPercentageItem of getRolloutPercentageItemFormGroups(); let i = index\">\n <div class=\"flex\">\n <input type=\"number\" [formControl]=\"getPercentageFormControl(rolloutPercentageItem)\"\n (input)=\"percentageChanged(i)\">%\n <span class=\"users\">of <a href=\"https://configcat.com/docs/advanced/user-object\" target=\"_blank\"\n rel=\"noopener noreferrer\">users</a>\n </span>\n </div>\n\n <div class=\"delete-option\" matTooltip=\"Remove this % option\"\n *ngIf=\"!readOnly && rolloutPercentageItems().controls.length > 2\"\n (click)=\"removeRolloutPercentageItem(i)\">\n <mat-icon>cancel</mat-icon>\n </div>\n\n <span data-tooltip=\"The sum of percentages must be equal to 100.\"\n *ngIf=\"(i === rolloutPercentageItems().controls.length -1) && (rolloutPercentageItemsSum().invalid)\">\n <mat-icon color=\"warn\">\n error_outline\n </mat-icon>\n </span>\n\n <div class=\"value flex\">\n <span class=\"value-name\" *ngIf=\"setting().settingType !== SettingType.Boolean\">Served value:</span>\n <configcat-value class=\"served-value\" [valueFormControl]=\"value(rolloutPercentageItem)\"\n [setting]=\"setting()\">\n </configcat-value>\n </div>\n <div class=\"delete\" matTooltip=\"Remove % options\" (click)=\"removeAll()\" *ngIf=\"!readOnly\">\n <mat-icon>cancel</mat-icon>\n </div>\n </div>\n </div>\n</div>", styles: [".percentage-wrapper{border:1px solid #d5d5d5;background-color:#fff;border-radius:4px;margin:.5em 1em;position:relative;padding:.5em 0;display:flex}.percentage-wrapper .delete{position:absolute;color:#d6a9a9;cursor:pointer;top:-8px;right:-12px}.percentage-wrapper .delete:hover{color:#ed5251}.percentage-wrapper .delete mat-icon{font-size:20px}.percentage-wrapper .delete-option{color:#d6a9a9;cursor:pointer;margin-left:1rem;margin-top:4px}.percentage-wrapper .delete-option:hover{color:#ed5251}.percentage-wrapper .delete-option mat-icon{font-size:20px}.if{display:flex;align-items:center}.if>*{margin:0 .5em}.if .spacing{margin-right:44px}.if .chip{background-color:#67b1fc3d}.grow{flex-grow:1}.percentage-row{min-height:40px;margin-left:.5em}.flex{display:flex;flex-wrap:wrap;align-items:center}.value{margin-left:auto;min-width:100px}.value .value-name{display:none}input{background-color:#fff;border:1px solid #e5e5e5;min-height:28px;width:40px;margin-right:5px;font-size:15px;padding:0 5px;font-family:Montserrat,Roboto,Helvetica Neue,sans-serif;font-weight:300}.users{margin-left:20px}@media (max-width: 700px){.percentage-wrapper{margin:.5em .3em}}\n"] }]
796
+ }], ctorParameters: function () { return []; }, propDecorators: { formGroup: [{
797
+ type: Input
798
+ }], readOnly: [{
799
+ type: Input
800
+ }] } });
801
+
802
+ class SettingComponent {
803
+ constructor(formHelper, cdRef) {
804
+ this.formHelper = formHelper;
805
+ this.cdRef = cdRef;
806
+ this.readOnly = false;
807
+ this.canEditSetting = false;
808
+ this.canDeleteSetting = false;
809
+ this.deleteSettingText = 'Delete setting';
810
+ this.showEnvironmentName = false;
811
+ this.segmentsEnabled = false;
812
+ this.editSettingRequested = new EventEmitter();
813
+ this.deleteSettingRequested = new EventEmitter();
814
+ this.rulesBeingRendered = false;
815
+ this.SettingType = SettingType;
816
+ }
817
+ ngOnInit() { }
818
+ environment() {
819
+ return this.formGroup.root.get('environment')?.value;
820
+ }
821
+ setting() {
822
+ return this.formGroup.get('setting')?.value;
823
+ }
824
+ integrationLinks() {
825
+ return this.formGroup.get('integrationLinks');
826
+ }
827
+ rolloutRules() {
828
+ return this.formGroup.get('rolloutRules');
829
+ }
830
+ rolloutPercentageItems() {
831
+ return this.formGroup.get('rolloutPercentageItems');
832
+ }
833
+ value() {
834
+ return this.formGroup.get('value');
835
+ }
836
+ addRolloutRule() {
837
+ this.rolloutRules().push(this.formHelper.createRolloutRuleFormGroup({
838
+ comparisonAttribute: 'Identifier',
839
+ comparator: RolloutRuleComparator.SensitiveIsOneOf,
840
+ comparisonValue: '',
841
+ value: this.setting().settingType === SettingType.Boolean ? false : null
842
+ }, this.readOnly, this.setting().settingType));
843
+ this.rolloutRules().markAsDirty();
844
+ }
845
+ addSegmentRolloutRule() {
846
+ this.rolloutRules().push(this.formHelper.createRolloutRuleFormGroup({
847
+ segmentComparator: SegmentComparator.IsIn,
848
+ value: this.setting().settingType === SettingType.Boolean ? false : null
849
+ }, this.readOnly, this.setting().settingType));
850
+ this.rolloutRules().markAsDirty();
851
+ }
852
+ removeRolloutRules() {
853
+ this.rolloutRules().clear();
854
+ this.rolloutRules().markAsDirty();
855
+ }
856
+ addRolloutPercentageItem() {
857
+ if (this.rolloutPercentageItems().length === 0) {
858
+ switch (this.setting().settingType) {
859
+ case SettingType.Boolean:
860
+ this.rolloutPercentageItems().push(this.formHelper.createRolloutPercentageItemFormGroup({
861
+ percentage: 0,
862
+ value: true
863
+ }, this.readOnly, this.setting().settingType));
864
+ this.rolloutPercentageItems().push(this.formHelper.createRolloutPercentageItemFormGroup({
865
+ percentage: 100,
866
+ value: false
867
+ }, this.readOnly, this.setting().settingType));
868
+ break;
869
+ case SettingType.String:
870
+ case SettingType.Int:
871
+ case SettingType.Double:
872
+ for (let i = 0; i < 4; i++) {
873
+ this.rolloutPercentageItems().push(this.formHelper.createRolloutPercentageItemFormGroup({
874
+ percentage: 25,
875
+ value: null
876
+ }, this.readOnly, this.setting().settingType));
877
+ }
878
+ break;
879
+ }
880
+ }
881
+ else if (this.setting().settingType !== SettingType.Boolean) {
882
+ this.rolloutPercentageItems().push(this.formHelper.createRolloutPercentageItemFormGroup({
883
+ percentage: 0,
884
+ value: null
885
+ }, this.readOnly, this.setting().settingType));
886
+ }
887
+ this.rolloutPercentageItems().markAsDirty();
888
+ }
889
+ removeRolloutPercentageItems() {
890
+ this.rolloutPercentageItems().clear();
891
+ this.rolloutPercentageItems().markAsDirty();
892
+ }
893
+ editSetting() {
894
+ this.editSettingRequested.emit({ setting: this.setting() });
895
+ }
896
+ deleteSetting() {
897
+ this.deleteSettingRequested.emit({ setting: this.setting() });
898
+ }
899
+ }
900
+ SettingComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: SettingComponent, deps: [{ token: SettingListFormHelper }, { token: i0.ChangeDetectorRef }], target: i0.ɵɵFactoryTarget.Component });
901
+ SettingComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: SettingComponent, selector: "setting", inputs: { formGroup: "formGroup", readOnly: "readOnly", canEditSetting: "canEditSetting", canDeleteSetting: "canDeleteSetting", deleteSettingText: "deleteSettingText", showEnvironmentName: "showEnvironmentName", segments: "segments", segmentsEnabled: "segmentsEnabled" }, outputs: { editSettingRequested: "editSettingRequested", deleteSettingRequested: "deleteSettingRequested" }, ngImport: i0, template: "<div class=\"setting-full\"\n [formGroup]=\"formGroup\">\n <div class=\"delete\" (click)=\"deleteSetting()\" *ngIf=\"canDeleteSetting\" [matTooltip]=\"deleteSettingText\"\n data-robot=\"deleteSetting\">\n <mat-icon>cancel</mat-icon>\n </div>\n <div class=\"setting-header flex\">\n <div class=\"setting-name flex\">\n <div class=\"name\" data-robot=\"settingName\">\n {{setting().name}}\n <span *ngIf=\"showEnvironmentName\"> ({{environment().name}})</span>\n </div>\n <div class=\"edit\" matTooltip=\"Edit name and description\" (click)=\"editSetting()\" *ngIf=\"canEditSetting\"\n data-robot=\"renameSetting\">\n <mat-icon>edit</mat-icon>\n </div>\n </div>\n </div>\n <div class=\"setting-content\">\n <div class=\"setting-details\">\n <div class=\"setting-key\"><code data-robot=\"settingKey\">{{setting().key}}</code></div>\n <span *ngIf=\"setting().hint\" class=\"description\">{{setting().hint}}</span>\n </div>\n\n <div class=\"rules-list\">\n <div>\n <configcat-rollout-rules *ngIf=\"rolloutRules().controls.length !== 0\" [formGroup]=\"formGroup\" [segments]=\"segments\">\n </configcat-rollout-rules>\n </div>\n\n <configcat-rollout-percentage-items *ngIf=\"rolloutPercentageItems().controls.length !== 0\"\n [formGroup]=\"formGroup\">\n </configcat-rollout-percentage-items>\n\n <div class=\"all-other flex\">\n <div *ngIf=\"rolloutPercentageItems().length === 0 && rolloutRules().length !== 0\"\n data-tooltip=\"This value will be served to all users who the above rules don't apply.\">\n <mat-chip-list>\n <mat-chip class=\"chip\">To all other users, serve:</mat-chip>\n </mat-chip-list>\n </div>\n <div *ngIf=\"rolloutPercentageItems().length !== 0\"\n data-tooltip=\"This fallback value will be served in case the user can't be identified.\">\n <mat-chip-list>\n <mat-chip class=\"chip\">To unidentified users, serve:</mat-chip>\n </mat-chip-list>\n </div>\n <div *ngIf=\"rolloutPercentageItems().length === 0 && rolloutRules().length === 0\">\n <mat-chip-list>\n <mat-chip class=\"chip\">To all users, serve:</mat-chip>\n </mat-chip-list>\n </div>\n <configcat-value class=\"served-value\" [valueFormControl]=\"value()\" [setting]=\"setting()\">\n </configcat-value>\n </div>\n <div class=\"buttons\">\n <button type=\"button\" class=\"sige-button targeting-button\" (click)=\"addRolloutRule()\" *ngIf=\"!readOnly\">\n {{rolloutRules().length === 0 ? 'Target specific users' : 'Add new targeting rule'}}\n </button>\n <button type=\"button\" class=\"sige-button targeting-button\" (click)=\"addRolloutRule()\" *ngIf=\"!readOnly && segmentsEnabled\">\n {{rolloutRules().length === 0 ? 'Target segment' : 'Add new targeting rule'}}\n </button>\n <button type=\"button\" class=\"sige-button targeting-button\" (click)=\"addRolloutPercentageItem()\"\n *ngIf=\"!readOnly\"\n [disabled]=\"setting().settingType === SettingType.Boolean && rolloutPercentageItems().length !== 0\">\n {{rolloutPercentageItems().length === 0 ? 'Target % of users' : 'Add new % option'}}\n </button>\n </div>\n </div>\n </div>\n</div>\n", styles: [".setting-full{position:relative;display:flex;flex-wrap:nowrap;flex-direction:column;border-radius:3px}.setting-full .delete{position:absolute;right:-15px;top:-10px;color:#d6a9a9;cursor:pointer}.setting-full .delete:hover{color:#ed5251}.setting-full .delete mat-icon{font-size:20px}.setting-full .setting-header{padding:1.5em 1.5em 0}.setting-full .setting-header .setting-name{flex-direction:row}.setting-full .setting-header .setting-name:hover>.edit{visibility:visible}.setting-full .setting-header .setting-name .name{font-weight:700;word-wrap:break-word;max-width:100%}.setting-full .setting-header .setting-name .edit{margin:5px 0 0 5px;cursor:pointer;visibility:hidden;color:gray}.setting-full .setting-header .setting-name .edit:hover{visibility:visible}.setting-full .setting-header .setting-name .edit mat-icon{font-size:18px}.setting-full .setting-header .setting-meta{margin-left:auto;margin-right:14px;font-size:.7em;color:gray}.setting-full .setting-content{display:flex}.setting-full .setting-content .setting-details{display:flex;flex-direction:column;width:400px;padding:0 0 1em 1em}.setting-full .setting-content .setting-details>*{margin:.5em}.setting-full .setting-content .setting-details .integrations{font-size:.8rem}.setting-full .setting-content .setting-details .integrations>div{margin:3px}.setting-full .setting-content .setting-details .integrations>div>a:hover{text-decoration:underline}.setting-full .setting-content .setting-details .setting-key{word-wrap:break-word}.setting-full .setting-content .setting-details .description{font-size:.8em;white-space:pre-wrap;word-wrap:break-word;max-width:300px}.setting-full .setting-content .setting-details code{background-color:#d3d3d3;padding:3px 6px}.setting-full .setting-content .rules-list{width:100%;padding:0 1em 1em}.setting-full .setting-content .targeting-button{margin-left:.5rem;margin-right:.5rem;margin-bottom:1em}.all-other{min-height:40px;justify-content:flex-start;border:1px solid #d5d5d5;border-radius:4px;background-color:#fff;margin:.5em 1em;padding:4px 0 4px .5em}.all-other .chip{background-color:#67b1fc3d}.all-other .served-value{margin-left:auto;min-width:100px}.end{margin-left:auto}.buttons{display:flex;margin-left:.5rem;margin-right:.5rem}.buttons .updated-date{font-size:.7em;margin-left:auto;margin-right:22px;color:gray}.flex{display:flex;flex-wrap:wrap;align-items:center}.show-hide-toggle{margin-left:1em;cursor:pointer}.show-hide-toggle a{font-size:.8rem}.sige-button{background-color:#d9eadc;color:#363636;cursor:pointer;justify-content:center;padding:.375em .75em;text-align:center;white-space:nowrap;border-radius:2px;font-size:.75rem;border:1px solid #dbdbdb;box-shadow:none;display:inline-flex;font-family:Montserrat,Roboto,Helvetica Neue,sans-serif}.sige-button:hover{background-color:#bad0be}.sige-button:disabled{background-color:#fff;color:#b3b3b3}@media (max-width: 1200px){.setting-details{width:300px}}@media (max-width: 700px){.setting-full .setting-content{flex-wrap:wrap}.setting-full .setting-content .rules-list{padding:0}.buttons{flex-direction:column}.updated-date{display:none}.setting-details{padding:.2em 0 .2em .2em}.all-other{margin:.5em .3em}}\n"], components: [{ type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { type: RolloutRulesComponent, selector: "configcat-rollout-rules", inputs: ["formGroup", "readOnly", "segments"] }, { type: RolloutPercentageItemsComponent, selector: "configcat-rollout-percentage-items", inputs: ["formGroup", "readOnly"] }, { type: i3$2.MatChipList, selector: "mat-chip-list", inputs: ["errorStateMatcher", "multiple", "compareWith", "value", "required", "placeholder", "disabled", "aria-orientation", "selectable", "tabIndex"], outputs: ["change", "valueChange"], exportAs: ["matChipList"] }, { type: ValueComponent, selector: "configcat-value", inputs: ["valueFormControl", "setting"] }], directives: [{ type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i5$2.MatTooltip, selector: "[matTooltip]", exportAs: ["matTooltip"] }, { type: i3$2.MatChip, selector: "mat-basic-chip, [mat-basic-chip], mat-chip, [mat-chip]", inputs: ["color", "disableRipple", "tabIndex", "selected", "value", "selectable", "disabled", "removable"], outputs: ["selectionChange", "destroyed", "removed"], exportAs: ["matChip"] }] });
902
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: SettingComponent, decorators: [{
903
+ type: Component,
904
+ args: [{ selector: 'setting', template: "<div class=\"setting-full\"\n [formGroup]=\"formGroup\">\n <div class=\"delete\" (click)=\"deleteSetting()\" *ngIf=\"canDeleteSetting\" [matTooltip]=\"deleteSettingText\"\n data-robot=\"deleteSetting\">\n <mat-icon>cancel</mat-icon>\n </div>\n <div class=\"setting-header flex\">\n <div class=\"setting-name flex\">\n <div class=\"name\" data-robot=\"settingName\">\n {{setting().name}}\n <span *ngIf=\"showEnvironmentName\"> ({{environment().name}})</span>\n </div>\n <div class=\"edit\" matTooltip=\"Edit name and description\" (click)=\"editSetting()\" *ngIf=\"canEditSetting\"\n data-robot=\"renameSetting\">\n <mat-icon>edit</mat-icon>\n </div>\n </div>\n </div>\n <div class=\"setting-content\">\n <div class=\"setting-details\">\n <div class=\"setting-key\"><code data-robot=\"settingKey\">{{setting().key}}</code></div>\n <span *ngIf=\"setting().hint\" class=\"description\">{{setting().hint}}</span>\n </div>\n\n <div class=\"rules-list\">\n <div>\n <configcat-rollout-rules *ngIf=\"rolloutRules().controls.length !== 0\" [formGroup]=\"formGroup\" [segments]=\"segments\">\n </configcat-rollout-rules>\n </div>\n\n <configcat-rollout-percentage-items *ngIf=\"rolloutPercentageItems().controls.length !== 0\"\n [formGroup]=\"formGroup\">\n </configcat-rollout-percentage-items>\n\n <div class=\"all-other flex\">\n <div *ngIf=\"rolloutPercentageItems().length === 0 && rolloutRules().length !== 0\"\n data-tooltip=\"This value will be served to all users who the above rules don't apply.\">\n <mat-chip-list>\n <mat-chip class=\"chip\">To all other users, serve:</mat-chip>\n </mat-chip-list>\n </div>\n <div *ngIf=\"rolloutPercentageItems().length !== 0\"\n data-tooltip=\"This fallback value will be served in case the user can't be identified.\">\n <mat-chip-list>\n <mat-chip class=\"chip\">To unidentified users, serve:</mat-chip>\n </mat-chip-list>\n </div>\n <div *ngIf=\"rolloutPercentageItems().length === 0 && rolloutRules().length === 0\">\n <mat-chip-list>\n <mat-chip class=\"chip\">To all users, serve:</mat-chip>\n </mat-chip-list>\n </div>\n <configcat-value class=\"served-value\" [valueFormControl]=\"value()\" [setting]=\"setting()\">\n </configcat-value>\n </div>\n <div class=\"buttons\">\n <button type=\"button\" class=\"sige-button targeting-button\" (click)=\"addRolloutRule()\" *ngIf=\"!readOnly\">\n {{rolloutRules().length === 0 ? 'Target specific users' : 'Add new targeting rule'}}\n </button>\n <button type=\"button\" class=\"sige-button targeting-button\" (click)=\"addRolloutRule()\" *ngIf=\"!readOnly && segmentsEnabled\">\n {{rolloutRules().length === 0 ? 'Target segment' : 'Add new targeting rule'}}\n </button>\n <button type=\"button\" class=\"sige-button targeting-button\" (click)=\"addRolloutPercentageItem()\"\n *ngIf=\"!readOnly\"\n [disabled]=\"setting().settingType === SettingType.Boolean && rolloutPercentageItems().length !== 0\">\n {{rolloutPercentageItems().length === 0 ? 'Target % of users' : 'Add new % option'}}\n </button>\n </div>\n </div>\n </div>\n</div>\n", styles: [".setting-full{position:relative;display:flex;flex-wrap:nowrap;flex-direction:column;border-radius:3px}.setting-full .delete{position:absolute;right:-15px;top:-10px;color:#d6a9a9;cursor:pointer}.setting-full .delete:hover{color:#ed5251}.setting-full .delete mat-icon{font-size:20px}.setting-full .setting-header{padding:1.5em 1.5em 0}.setting-full .setting-header .setting-name{flex-direction:row}.setting-full .setting-header .setting-name:hover>.edit{visibility:visible}.setting-full .setting-header .setting-name .name{font-weight:700;word-wrap:break-word;max-width:100%}.setting-full .setting-header .setting-name .edit{margin:5px 0 0 5px;cursor:pointer;visibility:hidden;color:gray}.setting-full .setting-header .setting-name .edit:hover{visibility:visible}.setting-full .setting-header .setting-name .edit mat-icon{font-size:18px}.setting-full .setting-header .setting-meta{margin-left:auto;margin-right:14px;font-size:.7em;color:gray}.setting-full .setting-content{display:flex}.setting-full .setting-content .setting-details{display:flex;flex-direction:column;width:400px;padding:0 0 1em 1em}.setting-full .setting-content .setting-details>*{margin:.5em}.setting-full .setting-content .setting-details .integrations{font-size:.8rem}.setting-full .setting-content .setting-details .integrations>div{margin:3px}.setting-full .setting-content .setting-details .integrations>div>a:hover{text-decoration:underline}.setting-full .setting-content .setting-details .setting-key{word-wrap:break-word}.setting-full .setting-content .setting-details .description{font-size:.8em;white-space:pre-wrap;word-wrap:break-word;max-width:300px}.setting-full .setting-content .setting-details code{background-color:#d3d3d3;padding:3px 6px}.setting-full .setting-content .rules-list{width:100%;padding:0 1em 1em}.setting-full .setting-content .targeting-button{margin-left:.5rem;margin-right:.5rem;margin-bottom:1em}.all-other{min-height:40px;justify-content:flex-start;border:1px solid #d5d5d5;border-radius:4px;background-color:#fff;margin:.5em 1em;padding:4px 0 4px .5em}.all-other .chip{background-color:#67b1fc3d}.all-other .served-value{margin-left:auto;min-width:100px}.end{margin-left:auto}.buttons{display:flex;margin-left:.5rem;margin-right:.5rem}.buttons .updated-date{font-size:.7em;margin-left:auto;margin-right:22px;color:gray}.flex{display:flex;flex-wrap:wrap;align-items:center}.show-hide-toggle{margin-left:1em;cursor:pointer}.show-hide-toggle a{font-size:.8rem}.sige-button{background-color:#d9eadc;color:#363636;cursor:pointer;justify-content:center;padding:.375em .75em;text-align:center;white-space:nowrap;border-radius:2px;font-size:.75rem;border:1px solid #dbdbdb;box-shadow:none;display:inline-flex;font-family:Montserrat,Roboto,Helvetica Neue,sans-serif}.sige-button:hover{background-color:#bad0be}.sige-button:disabled{background-color:#fff;color:#b3b3b3}@media (max-width: 1200px){.setting-details{width:300px}}@media (max-width: 700px){.setting-full .setting-content{flex-wrap:wrap}.setting-full .setting-content .rules-list{padding:0}.buttons{flex-direction:column}.updated-date{display:none}.setting-details{padding:.2em 0 .2em .2em}.all-other{margin:.5em .3em}}\n"] }]
905
+ }], ctorParameters: function () { return [{ type: SettingListFormHelper }, { type: i0.ChangeDetectorRef }]; }, propDecorators: { formGroup: [{
906
+ type: Input
907
+ }], readOnly: [{
908
+ type: Input
909
+ }], canEditSetting: [{
910
+ type: Input
911
+ }], canDeleteSetting: [{
912
+ type: Input
913
+ }], deleteSettingText: [{
914
+ type: Input
915
+ }], showEnvironmentName: [{
916
+ type: Input
917
+ }], segments: [{
918
+ type: Input
919
+ }], segmentsEnabled: [{
920
+ type: Input
921
+ }], editSettingRequested: [{
922
+ type: Output
923
+ }], deleteSettingRequested: [{
924
+ type: Output
925
+ }] } });
926
+
927
+ class SettingListComponent {
928
+ constructor(formHelper, snackBar, dialog) {
929
+ this.formHelper = formHelper;
930
+ this.snackBar = snackBar;
931
+ this.dialog = dialog;
932
+ this.canEditSetting = false;
933
+ this.canDeleteSetting = false;
934
+ this.deleteSettingText = 'Delete setting';
935
+ this.showEnvironmentName = false;
936
+ this.editSettingRequested = new EventEmitter();
937
+ this.deleteSettingRequested = new EventEmitter();
938
+ this.formValuesChanged = new EventEmitter();
939
+ this.loading = true;
940
+ this.submitting = false;
941
+ this.showRevertQuestion = false;
942
+ this.showFeedBackMessage = false;
943
+ this.readOnly = false;
944
+ this.segmentsEnabled = false;
945
+ }
946
+ ngOnInit() {
947
+ this.reloadSettingValues();
948
+ }
949
+ ngOnChanges() {
950
+ this.reloadSettingValues();
951
+ }
952
+ ngOnDestroy() {
953
+ if (this.formValuesChangedSubscription) {
954
+ this.formValuesChangedSubscription.unsubscribe();
955
+ this.formValuesChangedSubscription = null;
956
+ }
957
+ }
958
+ reloadSettingValues() {
959
+ this.showFeedBackMessage = false;
960
+ this.loading = true;
961
+ forkJoin({
962
+ segments: this.loadSegments(),
963
+ settingValues: this.loadSettingValues()
964
+ }).subscribe(result => {
965
+ this.readOnly = result.settingValues.readOnly;
966
+ this.settingValues = result.settingValues;
967
+ this.segments = result.segments;
968
+ this.createFormGroup();
969
+ this.loading = false;
970
+ }, error => {
971
+ this.snackBar.open('Ooops. We could not load your Feature Flags and Settings. Please try again or contact us.', 'Dismiss', { duration: 60000, panelClass: 'red-snackbar' });
972
+ });
973
+ }
974
+ createFormGroup() {
975
+ this.formGroup = this.formHelper.createSettingValuesFormGroup(this.settingValues);
976
+ this.formValuesChangedSubscription = this.formGroup.valueChanges.subscribe(() => {
977
+ this.formValuesChanged.emit();
978
+ });
979
+ }
980
+ settingValuesFormArray() {
981
+ return this.formGroup.get('settingValues');
982
+ }
983
+ getSettingValueFormGroups() {
984
+ return this.settingValuesFormArray().controls.map(c => c);
985
+ }
986
+ submit() {
987
+ if (!this.formGroup || !this.formGroup.valid) {
988
+ this.showFeedBackMessage = true;
989
+ this.formGroup.markAsTouched();
990
+ return;
991
+ }
992
+ this.showFeedBackMessage = false;
993
+ this.submitting = true;
994
+ const updateSettingValuesModel = {
995
+ settingValues: this.formGroup.controls.settingValues.value,
996
+ knownLastUpdatedAt: this.settingValues.lastUpdatedAt,
997
+ forced: false
998
+ };
999
+ if (this.settingValues.reasonRequired) {
1000
+ const dialogRef = this.dialog.open(ReasonDialogComponent, {
1001
+ width: '450px'
1002
+ });
1003
+ dialogRef.afterClosed()
1004
+ .subscribe(result => {
1005
+ if (result && result.button === 'save' && result.reason) {
1006
+ updateSettingValuesModel.reason = result.reason;
1007
+ this.updateSettingValues(updateSettingValuesModel);
1008
+ }
1009
+ else {
1010
+ this.submitting = false;
1011
+ }
1012
+ });
1013
+ return;
1014
+ }
1015
+ this.updateSettingValues(updateSettingValuesModel);
1016
+ }
1017
+ updateSettingValues(updateSettingValuesModel) {
1018
+ this.onSave(updateSettingValuesModel).subscribe(settingValues => {
1019
+ this.settingValues = settingValues;
1020
+ this.createFormGroup();
1021
+ this.submitting = false;
1022
+ this.snackBar.openFromComponent(SaveSnackbarComponent, { duration: 5000, panelClass: 'green-snackbar' });
1023
+ }, (error) => {
1024
+ if (error.status === 400 && error.error
1025
+ && error.error.KnownLastUpdatedAt && error.error.KnownLastUpdatedAt[0] === 'Concurrent update') {
1026
+ const dialogRef = this.dialog.open(ConcurrentDialogComponent, {
1027
+ width: '560px'
1028
+ });
1029
+ dialogRef.afterClosed()
1030
+ .subscribe(result => {
1031
+ if (result && result.button === 'save') {
1032
+ updateSettingValuesModel.forced = true;
1033
+ this.updateSettingValues(updateSettingValuesModel);
1034
+ }
1035
+ else {
1036
+ this.reloadSettingValues();
1037
+ this.submitting = false;
1038
+ }
1039
+ });
1040
+ return;
1041
+ }
1042
+ if (error.status === 400 && error.error && error.error.Reason && error.error.Reason[0] === 'Reason required') {
1043
+ const dialogRef = this.dialog.open(ReasonDialogComponent, {
1044
+ width: '450px'
1045
+ });
1046
+ dialogRef.afterClosed()
1047
+ .subscribe(result => {
1048
+ if (result && result.button === 'save' && result.reason) {
1049
+ updateSettingValuesModel.reason = result.reason;
1050
+ this.updateSettingValues(updateSettingValuesModel);
1051
+ }
1052
+ else {
1053
+ this.submitting = false;
1054
+ }
1055
+ });
1056
+ return;
1057
+ }
1058
+ this.formGroup.setErrors({ internalServerError: 'Internal server error' });
1059
+ this.showFeedBackMessage = true;
1060
+ });
1061
+ }
1062
+ handleRevertYes() {
1063
+ this.showRevertQuestion = false;
1064
+ this.reloadSettingValues();
1065
+ }
1066
+ handleRevertCancel() {
1067
+ this.showRevertQuestion = false;
1068
+ }
1069
+ onEditSettingRequested(setting) {
1070
+ this.editSettingRequested.emit({
1071
+ setting: setting.setting,
1072
+ environment: this.settingValues.environment,
1073
+ config: this.settingValues.config
1074
+ });
1075
+ }
1076
+ onDeleteSettingRequested(setting) {
1077
+ this.deleteSettingRequested.emit({
1078
+ setting: setting.setting,
1079
+ environment: this.settingValues.environment,
1080
+ config: this.settingValues.config
1081
+ });
1082
+ }
1083
+ }
1084
+ SettingListComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: SettingListComponent, deps: [{ token: SettingListFormHelper }, { token: i2$2.MatSnackBar }, { token: i1$1.MatDialog }], target: i0.ɵɵFactoryTarget.Component });
1085
+ SettingListComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: SettingListComponent, selector: "configcat-setting-list", inputs: { canEditSetting: "canEditSetting", canDeleteSetting: "canDeleteSetting", onSave: "onSave", loadSettingValues: "loadSettingValues", loadSegments: "loadSegments", deleteSettingText: "deleteSettingText", showEnvironmentName: "showEnvironmentName", segmentsEnabled: "segmentsEnabled" }, outputs: { editSettingRequested: "editSettingRequested", deleteSettingRequested: "deleteSettingRequested", formValuesChanged: "formValuesChanged" }, usesOnChanges: true, ngImport: i0, template: "<form [formGroup]=\"formGroup\" (ngSubmit)=\"submit()\" *ngIf=\"!loading\">\n <div class=\"wrapper\" *ngFor=\"let settingValueFromGroup of getSettingValueFormGroups(); let i = index\">\n <setting [formGroup]=\"settingValueFromGroup\" [readOnly]=\"readOnly\" [canEditSetting]=\"canEditSetting\"\n [canDeleteSetting]=\"canDeleteSetting\" (editSettingRequested)=\"onEditSettingRequested($event)\"\n (deleteSettingRequested)=\"onDeleteSettingRequested($event)\" [deleteSettingText]=\"deleteSettingText\"\n [showEnvironmentName]=\"showEnvironmentName\" [segments]=\"segments\" [segmentsEnabled]=\"segmentsEnabled\">\n </setting>\n </div>\n\n <div class=\"save\" *ngIf=\"!readOnly && !submitting && formGroup.dirty\">\n <div class=\"feedback\" *ngIf=\"formGroup.touched && formGroup.invalid && showFeedBackMessage\">\n <div class=\"error\" *ngIf=\"formGroup.errors && formGroup.errors.internalServerError\">\n <span>Something went wrong and we could not save your settings. You can try again or <a\n href=\"https://configcat.com/support\" target=\"_blank\" rel=\"noopener noreferrer\">contact us.</a></span>\n </div>\n <div class=\"error\" *ngIf=\"!formGroup.errors || !formGroup.errors.internalServerError\">\n <span>Oh no! A feature flag has invalid or missing data.</span>\n </div>\n </div>\n <button type=\"button\" mat-stroked-button *ngIf=\"!showRevertQuestion\" (click)=\"showRevertQuestion = true\">\n <mat-icon>history</mat-icon><span>Revert changes</span>\n </button>\n <div *ngIf=\"showRevertQuestion\">\n <span class=\"revert\">Revert to last saved state?</span>\n <button type=\"button\" class=\"yes\" mat-stroked-button (click)=\"handleRevertYes()\">Yes</button>\n <button type=\"button\" mat-stroked-button (click)=\"handleRevertCancel()\">No</button>\n </div>\n <button class=\"save-button\" mat-flat-button color=\"warn\" type=\"submit\" [disabled]=\"submitting\">\n <mat-icon>backup</mat-icon> <span> Save & publish changes</span>\n </button>\n </div>\n</form>", styles: [".wrapper{background-color:#f3f3f3;border:1px solid rgba(0,0,0,.12);border-radius:4px;margin:1em 0}.show-hide a{cursor:pointer;font-size:.8rem}.save{position:sticky;bottom:0;min-height:38px;padding:.5rem .5rem .5rem 0;background-color:#fff;display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:flex-end;z-index:1000}.save .save-button{animation:shadow-pulse 1s 3;margin-left:1rem}.save>*{margin:.3em}.save .revert{margin:0 16px;font-size:14px}.save .yes{margin:0 5px}.error{background-color:#a32b2d;color:#fff;padding:5px;font-size:.9em}.error a{color:#fff;text-decoration:underline}@media (max-width: 700px){.save{padding:.5rem 0}}\n"], components: [{ type: SettingComponent, selector: "setting", inputs: ["formGroup", "readOnly", "canEditSetting", "canDeleteSetting", "deleteSettingText", "showEnvironmentName", "segments", "segmentsEnabled"], outputs: ["editSettingRequested", "deleteSettingRequested"] }, { type: i4.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { type: i2$1.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], directives: [{ type: i5$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i5$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
1086
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: SettingListComponent, decorators: [{
1087
+ type: Component,
1088
+ args: [{ selector: 'configcat-setting-list', template: "<form [formGroup]=\"formGroup\" (ngSubmit)=\"submit()\" *ngIf=\"!loading\">\n <div class=\"wrapper\" *ngFor=\"let settingValueFromGroup of getSettingValueFormGroups(); let i = index\">\n <setting [formGroup]=\"settingValueFromGroup\" [readOnly]=\"readOnly\" [canEditSetting]=\"canEditSetting\"\n [canDeleteSetting]=\"canDeleteSetting\" (editSettingRequested)=\"onEditSettingRequested($event)\"\n (deleteSettingRequested)=\"onDeleteSettingRequested($event)\" [deleteSettingText]=\"deleteSettingText\"\n [showEnvironmentName]=\"showEnvironmentName\" [segments]=\"segments\" [segmentsEnabled]=\"segmentsEnabled\">\n </setting>\n </div>\n\n <div class=\"save\" *ngIf=\"!readOnly && !submitting && formGroup.dirty\">\n <div class=\"feedback\" *ngIf=\"formGroup.touched && formGroup.invalid && showFeedBackMessage\">\n <div class=\"error\" *ngIf=\"formGroup.errors && formGroup.errors.internalServerError\">\n <span>Something went wrong and we could not save your settings. You can try again or <a\n href=\"https://configcat.com/support\" target=\"_blank\" rel=\"noopener noreferrer\">contact us.</a></span>\n </div>\n <div class=\"error\" *ngIf=\"!formGroup.errors || !formGroup.errors.internalServerError\">\n <span>Oh no! A feature flag has invalid or missing data.</span>\n </div>\n </div>\n <button type=\"button\" mat-stroked-button *ngIf=\"!showRevertQuestion\" (click)=\"showRevertQuestion = true\">\n <mat-icon>history</mat-icon><span>Revert changes</span>\n </button>\n <div *ngIf=\"showRevertQuestion\">\n <span class=\"revert\">Revert to last saved state?</span>\n <button type=\"button\" class=\"yes\" mat-stroked-button (click)=\"handleRevertYes()\">Yes</button>\n <button type=\"button\" mat-stroked-button (click)=\"handleRevertCancel()\">No</button>\n </div>\n <button class=\"save-button\" mat-flat-button color=\"warn\" type=\"submit\" [disabled]=\"submitting\">\n <mat-icon>backup</mat-icon> <span> Save & publish changes</span>\n </button>\n </div>\n</form>", styles: [".wrapper{background-color:#f3f3f3;border:1px solid rgba(0,0,0,.12);border-radius:4px;margin:1em 0}.show-hide a{cursor:pointer;font-size:.8rem}.save{position:sticky;bottom:0;min-height:38px;padding:.5rem .5rem .5rem 0;background-color:#fff;display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;justify-content:flex-end;z-index:1000}.save .save-button{animation:shadow-pulse 1s 3;margin-left:1rem}.save>*{margin:.3em}.save .revert{margin:0 16px;font-size:14px}.save .yes{margin:0 5px}.error{background-color:#a32b2d;color:#fff;padding:5px;font-size:.9em}.error a{color:#fff;text-decoration:underline}@media (max-width: 700px){.save{padding:.5rem 0}}\n"] }]
1089
+ }], ctorParameters: function () { return [{ type: SettingListFormHelper }, { type: i2$2.MatSnackBar }, { type: i1$1.MatDialog }]; }, propDecorators: { canEditSetting: [{
1090
+ type: Input
1091
+ }], canDeleteSetting: [{
1092
+ type: Input
1093
+ }], onSave: [{
1094
+ type: Input
1095
+ }], loadSettingValues: [{
1096
+ type: Input
1097
+ }], loadSegments: [{
1098
+ type: Input
1099
+ }], deleteSettingText: [{
1100
+ type: Input
1101
+ }], showEnvironmentName: [{
1102
+ type: Input
1103
+ }], editSettingRequested: [{
1104
+ type: Output
1105
+ }], deleteSettingRequested: [{
1106
+ type: Output
1107
+ }], formValuesChanged: [{
1108
+ type: Output
1109
+ }], segmentsEnabled: [{
1110
+ type: Input
1111
+ }] } });
1112
+
1113
+ class SettingItemComponent extends BaseComponent {
1114
+ constructor(publicApiService) {
1115
+ super(publicApiService);
1116
+ this.canEditSetting = true;
1117
+ this.canDeleteSetting = true;
1118
+ this.deleteSettingText = 'Delete setting';
1119
+ this.showEnvironmentName = true;
1120
+ this.segmentsEnabled = false;
1121
+ this.editSettingRequested = new EventEmitter();
1122
+ this.deleteSettingRequested = new EventEmitter();
1123
+ this.loadSucceeded = new EventEmitter();
1124
+ this.loadFailed = new EventEmitter();
1125
+ this.saveSucceeded = new EventEmitter();
1126
+ this.saveFailed = new EventEmitter();
1127
+ this.formValuesChanged = new EventEmitter();
1128
+ this.loadSettingValues = () => {
1129
+ return this.createSettingValuesService().getSettingValue(this.environmentId, this.settingId)
1130
+ .pipe(map(settingValue => {
1131
+ this.settingValue = settingValue;
1132
+ const settingValues = {
1133
+ settingValues: [settingValue],
1134
+ readOnly: settingValue.readOnly,
1135
+ config: settingValue.config,
1136
+ environment: settingValue.environment
1137
+ };
1138
+ this.loadSucceeded.emit(settingValues);
1139
+ return settingValues;
1140
+ }), catchError(error => {
1141
+ this.loadFailed.emit(error);
1142
+ return throwError(error);
1143
+ }));
1144
+ };
1145
+ this.loadSegments = () => {
1146
+ return this.segmentsEnabled ? this.createSegmentsService().getSegments(this.productId)
1147
+ .pipe(map(segments => {
1148
+ this.segments = segments;
1149
+ return segments;
1150
+ }), catchError(error => {
1151
+ return throwError(error);
1152
+ })) : of([]);
1153
+ };
1154
+ this.handleSave = (model) => {
1155
+ if (model.settingValues.length === 0) {
1156
+ return of();
1157
+ }
1158
+ const updateModel = model.settingValues[0];
1159
+ return this.createSettingValuesService().replaceSettingValue(this.environmentId, this.settingId, updateModel, model.reason)
1160
+ .pipe(map(settingValue => {
1161
+ this.settingValue = settingValue;
1162
+ const settingValues = {
1163
+ settingValues: [settingValue],
1164
+ readOnly: settingValue.readOnly,
1165
+ config: settingValue.config,
1166
+ environment: settingValue.environment
1167
+ };
1168
+ this.saveSucceeded.emit(settingValues);
1169
+ return settingValues;
1170
+ }), catchError(error => {
1171
+ this.saveFailed.emit(error);
1172
+ return throwError(error);
1173
+ }));
1174
+ };
1175
+ }
1176
+ ngOnInit() {
1177
+ }
1178
+ onEditSettingRequested(setting) {
1179
+ this.editSettingRequested.emit({
1180
+ setting: setting.setting,
1181
+ environment: this.settingValue.environment,
1182
+ config: this.settingValue.config
1183
+ });
1184
+ }
1185
+ onDeleteSettingRequested(setting) {
1186
+ this.deleteSettingRequested.emit({
1187
+ setting: setting.setting,
1188
+ environment: this.settingValue.environment,
1189
+ config: this.settingValue.config
1190
+ });
1191
+ }
1192
+ onFormValuesChanged() {
1193
+ this.formValuesChanged.emit();
1194
+ }
1195
+ }
1196
+ SettingItemComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: SettingItemComponent, deps: [{ token: PublicApiService }], target: i0.ɵɵFactoryTarget.Component });
1197
+ SettingItemComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: SettingItemComponent, selector: "configcat-setting-item", inputs: { productId: "productId", environmentId: "environmentId", configId: "configId", settingId: "settingId", canEditSetting: "canEditSetting", canDeleteSetting: "canDeleteSetting", deleteSettingText: "deleteSettingText", showEnvironmentName: "showEnvironmentName", segmentsEnabled: "segmentsEnabled" }, outputs: { editSettingRequested: "editSettingRequested", deleteSettingRequested: "deleteSettingRequested", loadSucceeded: "loadSucceeded", loadFailed: "loadFailed", saveSucceeded: "saveSucceeded", saveFailed: "saveFailed", formValuesChanged: "formValuesChanged" }, usesInheritance: true, ngImport: i0, template: "<configcat-setting-list [canEditSetting]=\"canEditSetting\" [canDeleteSetting]=\"canDeleteSetting\" [onSave]=\"handleSave\"\n [loadSettingValues]=\"loadSettingValues\" [loadSegments]=\"loadSegments\"\n (editSettingRequested)=\"onEditSettingRequested($event)\" (deleteSettingRequested)=\"onDeleteSettingRequested($event)\"\n [deleteSettingText]=\"deleteSettingText\" [showEnvironmentName]=\"showEnvironmentName\"\n (formValuesChanged)=\"onFormValuesChanged()\" [segmentsEnabled]=\"segmentsEnabled\">\n</configcat-setting-list>", styles: [".container{font-family:Montserrat,Roboto,Helvetica Neue,sans-serif;background-color:#f3f3f3;border:1px solid rgba(0,0,0,.12);border-radius:4px;margin:1em 0}.container .setting-full{position:relative;display:flex;flex-wrap:nowrap}.container .setting-full .setting-details{display:flex;flex-direction:column;width:400px;padding:1em 0 1em 1em}.container .setting-full .setting-details>*{margin:.5em}.container .setting-full .setting-details .setting-name{flex-direction:row}.container .setting-full .setting-details .setting-name .name{font-weight:700;word-wrap:break-word;max-width:100%}.container .setting-full .setting-details .setting-key{word-wrap:break-word}.container .setting-full .setting-details .description{font-size:.8em}.container .setting-full .setting-details code{background-color:#d3d3d3;padding:3px 6px}.container .setting-full .rules-list{width:100%;padding:1em}.container .setting-full .targeting-button{margin-left:1rem;margin-bottom:1em}.all-other{min-height:40px;justify-content:flex-start;border:1px solid #d5d5d5;border-radius:4px;background-color:#fff;margin:.5em 1em;padding:4px 0 4px .5em}.all-other .chip{background-color:#67b1fc3d}.all-other .served-value{margin-left:auto;min-width:100px}.end{margin-left:auto}.flex{display:flex;flex-wrap:wrap;align-items:center}.show-hide-toggle{margin-left:1em;cursor:pointer}@media (max-width: 1200px){.setting-full .setting-details{width:300px}}@media (max-width: 700px){.setting-full{flex-wrap:wrap}.setting-full .setting-details{padding:.2em 0 .2em .2em}.setting-full .all-other{margin:.5em .3em}}\n"], components: [{ type: SettingListComponent, selector: "configcat-setting-list", inputs: ["canEditSetting", "canDeleteSetting", "onSave", "loadSettingValues", "loadSegments", "deleteSettingText", "showEnvironmentName", "segmentsEnabled"], outputs: ["editSettingRequested", "deleteSettingRequested", "formValuesChanged"] }] });
1198
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: SettingItemComponent, decorators: [{
1199
+ type: Component,
1200
+ args: [{ selector: 'configcat-setting-item', template: "<configcat-setting-list [canEditSetting]=\"canEditSetting\" [canDeleteSetting]=\"canDeleteSetting\" [onSave]=\"handleSave\"\n [loadSettingValues]=\"loadSettingValues\" [loadSegments]=\"loadSegments\"\n (editSettingRequested)=\"onEditSettingRequested($event)\" (deleteSettingRequested)=\"onDeleteSettingRequested($event)\"\n [deleteSettingText]=\"deleteSettingText\" [showEnvironmentName]=\"showEnvironmentName\"\n (formValuesChanged)=\"onFormValuesChanged()\" [segmentsEnabled]=\"segmentsEnabled\">\n</configcat-setting-list>", styles: [".container{font-family:Montserrat,Roboto,Helvetica Neue,sans-serif;background-color:#f3f3f3;border:1px solid rgba(0,0,0,.12);border-radius:4px;margin:1em 0}.container .setting-full{position:relative;display:flex;flex-wrap:nowrap}.container .setting-full .setting-details{display:flex;flex-direction:column;width:400px;padding:1em 0 1em 1em}.container .setting-full .setting-details>*{margin:.5em}.container .setting-full .setting-details .setting-name{flex-direction:row}.container .setting-full .setting-details .setting-name .name{font-weight:700;word-wrap:break-word;max-width:100%}.container .setting-full .setting-details .setting-key{word-wrap:break-word}.container .setting-full .setting-details .description{font-size:.8em}.container .setting-full .setting-details code{background-color:#d3d3d3;padding:3px 6px}.container .setting-full .rules-list{width:100%;padding:1em}.container .setting-full .targeting-button{margin-left:1rem;margin-bottom:1em}.all-other{min-height:40px;justify-content:flex-start;border:1px solid #d5d5d5;border-radius:4px;background-color:#fff;margin:.5em 1em;padding:4px 0 4px .5em}.all-other .chip{background-color:#67b1fc3d}.all-other .served-value{margin-left:auto;min-width:100px}.end{margin-left:auto}.flex{display:flex;flex-wrap:wrap;align-items:center}.show-hide-toggle{margin-left:1em;cursor:pointer}@media (max-width: 1200px){.setting-full .setting-details{width:300px}}@media (max-width: 700px){.setting-full{flex-wrap:wrap}.setting-full .setting-details{padding:.2em 0 .2em .2em}.setting-full .all-other{margin:.5em .3em}}\n"] }]
1201
+ }], ctorParameters: function () { return [{ type: PublicApiService }]; }, propDecorators: { productId: [{
1202
+ type: Input
1203
+ }], environmentId: [{
1204
+ type: Input
1205
+ }], configId: [{
1206
+ type: Input
1207
+ }], settingId: [{
1208
+ type: Input
1209
+ }], canEditSetting: [{
1210
+ type: Input
1211
+ }], canDeleteSetting: [{
1212
+ type: Input
1213
+ }], deleteSettingText: [{
1214
+ type: Input
1215
+ }], showEnvironmentName: [{
1216
+ type: Input
1217
+ }], segmentsEnabled: [{
1218
+ type: Input
1219
+ }], editSettingRequested: [{
1220
+ type: Output
1221
+ }], deleteSettingRequested: [{
1222
+ type: Output
1223
+ }], loadSucceeded: [{
1224
+ type: Output
1225
+ }], loadFailed: [{
1226
+ type: Output
1227
+ }], saveSucceeded: [{
1228
+ type: Output
1229
+ }], saveFailed: [{
1230
+ type: Output
1231
+ }], formValuesChanged: [{
1232
+ type: Output
1233
+ }] } });
1234
+
1235
+ class SettingSelectComponent extends BaseComponent {
1236
+ constructor(publicApiService) {
1237
+ super(publicApiService);
1238
+ this.settings = [];
1239
+ }
1240
+ ngOnInit() {
1241
+ this.settings = [];
1242
+ this.reloadSettings();
1243
+ }
1244
+ ngOnChanges() {
1245
+ this.reloadSettings();
1246
+ }
1247
+ reloadSettings() {
1248
+ if (this.configId) {
1249
+ this.createSettingsService().getSettings(this.configId).subscribe(settings => {
1250
+ this.settings = settings;
1251
+ if (this.settings.length > 0) {
1252
+ this.valueFormControl.setValue(this.settings[0].settingId);
1253
+ }
1254
+ });
1255
+ }
1256
+ }
1257
+ }
1258
+ SettingSelectComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: SettingSelectComponent, deps: [{ token: PublicApiService }], target: i0.ɵɵFactoryTarget.Component });
1259
+ SettingSelectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: SettingSelectComponent, selector: "configcat-setting-select", inputs: { valueFormControl: "valueFormControl", configId: "configId" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<mat-form-field class=\"form-field\">\n <mat-select placeholder=\"Feature flag or setting\" [formControl]=\"valueFormControl\" *ngIf=\"settings\" name=\"value\">\n <mat-option *ngFor=\"let setting of settings\" [value]=\"setting.settingId\">{{setting.name}}\n </mat-option>\n </mat-select>\n</mat-form-field>", styles: [".form-field{width:100%}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i3$3.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i4$2.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i5$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i5$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
1260
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: SettingSelectComponent, decorators: [{
1261
+ type: Component,
1262
+ args: [{ selector: 'configcat-setting-select', template: "<mat-form-field class=\"form-field\">\n <mat-select placeholder=\"Feature flag or setting\" [formControl]=\"valueFormControl\" *ngIf=\"settings\" name=\"value\">\n <mat-option *ngFor=\"let setting of settings\" [value]=\"setting.settingId\">{{setting.name}}\n </mat-option>\n </mat-select>\n</mat-form-field>", styles: [".form-field{width:100%}\n"] }]
1263
+ }], ctorParameters: function () { return [{ type: PublicApiService }]; }, propDecorators: { valueFormControl: [{
1264
+ type: Input
1265
+ }], configId: [{
1266
+ type: Input
1267
+ }] } });
1268
+
1269
+ class ProductSelectComponent extends BaseComponent {
1270
+ constructor(publicApiService) {
1271
+ super(publicApiService);
1272
+ this.products = [];
1273
+ }
1274
+ ngOnInit() {
1275
+ this.products = [];
1276
+ this.createProductsService().getProducts().subscribe(products => {
1277
+ this.products = products;
1278
+ if (this.products.length > 0) {
1279
+ this.valueFormControl.setValue(this.products[0].productId, {
1280
+ emitEvent: true,
1281
+ emitModelToViewChange: true, emitViewToModelChange: true
1282
+ });
1283
+ }
1284
+ });
1285
+ }
1286
+ }
1287
+ ProductSelectComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ProductSelectComponent, deps: [{ token: PublicApiService }], target: i0.ɵɵFactoryTarget.Component });
1288
+ ProductSelectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: ProductSelectComponent, selector: "configcat-product-select", inputs: { valueFormControl: "valueFormControl" }, usesInheritance: true, ngImport: i0, template: "<mat-form-field class=\"form-field\">\n <mat-select placeholder=\"Product\" [formControl]=\"valueFormControl\" name=\"productValue\">\n <mat-option *ngFor=\"let product of products\" [value]=\"product.productId\">{{product.name}}\n </mat-option>\n </mat-select>\n</mat-form-field>", styles: [".form-field{width:100%}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i3$3.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i4$2.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i5$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
1289
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ProductSelectComponent, decorators: [{
1290
+ type: Component,
1291
+ args: [{ selector: 'configcat-product-select', template: "<mat-form-field class=\"form-field\">\n <mat-select placeholder=\"Product\" [formControl]=\"valueFormControl\" name=\"productValue\">\n <mat-option *ngFor=\"let product of products\" [value]=\"product.productId\">{{product.name}}\n </mat-option>\n </mat-select>\n</mat-form-field>", styles: [".form-field{width:100%}\n"] }]
1292
+ }], ctorParameters: function () { return [{ type: PublicApiService }]; }, propDecorators: { valueFormControl: [{
1293
+ type: Input
1294
+ }] } });
1295
+
1296
+ class ConfigSelectComponent extends BaseComponent {
1297
+ constructor(publicApiService) {
1298
+ super(publicApiService);
1299
+ this.configs = [];
1300
+ }
1301
+ ngOnInit() {
1302
+ this.configs = [];
1303
+ this.reloadConfigs();
1304
+ }
1305
+ ngOnChanges() {
1306
+ this.reloadConfigs();
1307
+ }
1308
+ reloadConfigs() {
1309
+ if (this.productId) {
1310
+ this.createConfigsService().getConfigs(this.productId).subscribe(configs => {
1311
+ this.configs = configs;
1312
+ if (this.configs.length > 0) {
1313
+ this.valueFormControl.setValue(this.configs[0].configId);
1314
+ }
1315
+ });
1316
+ }
1317
+ }
1318
+ }
1319
+ ConfigSelectComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ConfigSelectComponent, deps: [{ token: PublicApiService }], target: i0.ɵɵFactoryTarget.Component });
1320
+ ConfigSelectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: ConfigSelectComponent, selector: "configcat-config-select", inputs: { valueFormControl: "valueFormControl", productId: "productId" }, providers: [
1321
+ {
1322
+ provide: NG_VALUE_ACCESSOR,
1323
+ useExisting: forwardRef(() => ConfigSelectComponent),
1324
+ multi: true
1325
+ }
1326
+ ], usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<mat-form-field class=\"form-field\">\n <mat-select placeholder=\"Config\" [formControl]=\"valueFormControl\" *ngIf=\"configs\" name=\"value\">\n <mat-option *ngFor=\"let config of configs\" [value]=\"config.configId\">{{config.name}}</mat-option>\n </mat-select>\n</mat-form-field>", styles: [".form-field{width:100%}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i3$3.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i4$2.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i5$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i5$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
1327
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: ConfigSelectComponent, decorators: [{
1328
+ type: Component,
1329
+ args: [{ selector: 'configcat-config-select', providers: [
1330
+ {
1331
+ provide: NG_VALUE_ACCESSOR,
1332
+ useExisting: forwardRef(() => ConfigSelectComponent),
1333
+ multi: true
1334
+ }
1335
+ ], template: "<mat-form-field class=\"form-field\">\n <mat-select placeholder=\"Config\" [formControl]=\"valueFormControl\" *ngIf=\"configs\" name=\"value\">\n <mat-option *ngFor=\"let config of configs\" [value]=\"config.configId\">{{config.name}}</mat-option>\n </mat-select>\n</mat-form-field>", styles: [".form-field{width:100%}\n"] }]
1336
+ }], ctorParameters: function () { return [{ type: PublicApiService }]; }, propDecorators: { valueFormControl: [{
1337
+ type: Input
1338
+ }], productId: [{
1339
+ type: Input
1340
+ }] } });
1341
+
1342
+ class EnvironmentSelectComponent extends BaseComponent {
1343
+ constructor(publicApiService) {
1344
+ super(publicApiService);
1345
+ this.environments = [];
1346
+ }
1347
+ ngOnInit() {
1348
+ this.environments = [];
1349
+ this.reloadEnvironments();
1350
+ }
1351
+ ngOnChanges() {
1352
+ this.reloadEnvironments();
1353
+ }
1354
+ reloadEnvironments() {
1355
+ if (this.productId) {
1356
+ this.createEnvironmentsService().getEnvironments(this.productId).subscribe(environments => {
1357
+ this.environments = environments;
1358
+ if (this.environments.length > 0) {
1359
+ this.valueFormControl.setValue(this.environments[0].environmentId);
1360
+ }
1361
+ });
1362
+ }
1363
+ }
1364
+ }
1365
+ EnvironmentSelectComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: EnvironmentSelectComponent, deps: [{ token: PublicApiService }], target: i0.ɵɵFactoryTarget.Component });
1366
+ EnvironmentSelectComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: EnvironmentSelectComponent, selector: "configcat-environment-select", inputs: { valueFormControl: "valueFormControl", productId: "productId" }, usesInheritance: true, usesOnChanges: true, ngImport: i0, template: "<mat-form-field class=\"form-field\">\n <mat-select placeholder=\"Environment\" [formControl]=\"valueFormControl\" *ngIf=\"environments\" name=\"value\">\n <mat-option *ngFor=\"let environment of environments\" [value]=\"environment.environmentId\">{{environment.name}}\n </mat-option>\n </mat-select>\n</mat-form-field>", styles: [".form-field{width:100%}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i3$3.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex"], exportAs: ["matSelect"] }, { type: i4$2.MatOption, selector: "mat-option", exportAs: ["matOption"] }], directives: [{ type: i5$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { type: i5$1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }] });
1367
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: EnvironmentSelectComponent, decorators: [{
1368
+ type: Component,
1369
+ args: [{ selector: 'configcat-environment-select', template: "<mat-form-field class=\"form-field\">\n <mat-select placeholder=\"Environment\" [formControl]=\"valueFormControl\" *ngIf=\"environments\" name=\"value\">\n <mat-option *ngFor=\"let environment of environments\" [value]=\"environment.environmentId\">{{environment.name}}\n </mat-option>\n </mat-select>\n</mat-form-field>", styles: [".form-field{width:100%}\n"] }]
1370
+ }], ctorParameters: function () { return [{ type: PublicApiService }]; }, propDecorators: { valueFormControl: [{
1371
+ type: Input
1372
+ }], productId: [{
1373
+ type: Input
1374
+ }] } });
1375
+
1376
+ class FormHelper {
1377
+ static getErrorMessage(control, hint = '') {
1378
+ if (!control || control.valid) {
1379
+ return;
1380
+ }
1381
+ if (control.hasError('required')) {
1382
+ return `${hint} The field is required.`;
1383
+ }
1384
+ if (control.hasError('pattern')) {
1385
+ return 'Not a valid e-mail address.';
1386
+ }
1387
+ if (control.hasError('minlength')) {
1388
+ return 'The field must be at least ' + control.getError('minlength').requiredLength + ' characters long';
1389
+ }
1390
+ if (control.hasError('maxlength')) {
1391
+ return 'The field must be at max ' + control.getError('maxlength').requiredLength + ' characters long';
1392
+ }
1393
+ return;
1394
+ }
1395
+ }
1396
+
1397
+ class AuthorizationComponent {
1398
+ constructor(formBuilder, publicApiService) {
1399
+ this.formBuilder = formBuilder;
1400
+ this.publicApiService = publicApiService;
1401
+ this.basePath = null;
1402
+ this.authorized = new EventEmitter();
1403
+ this.FormHelper = FormHelper;
1404
+ }
1405
+ ngOnInit() {
1406
+ this.formGroup = this.formBuilder.group({
1407
+ basicAuthUsername: ['', Validators.required],
1408
+ basicAuthPassword: ['', Validators.required],
1409
+ });
1410
+ }
1411
+ onSubmit() {
1412
+ if (!this.formGroup.valid) {
1413
+ return;
1414
+ }
1415
+ const meService = this.publicApiService.createMeService(this.formGroup.controls.basicAuthUsername.value, this.formGroup.controls.basicAuthPassword.value, this.basePath);
1416
+ meService.getMe().subscribe(me => {
1417
+ this.authorized.emit({
1418
+ basicAuthUsername: this.formGroup.controls.basicAuthUsername.value,
1419
+ basicAuthPassword: this.formGroup.controls.basicAuthPassword.value
1420
+ });
1421
+ }, error => {
1422
+ this.formGroup.setErrors({ invalidAuthorization: 'Invalid Basic auth user name or password' });
1423
+ });
1424
+ }
1425
+ }
1426
+ AuthorizationComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: AuthorizationComponent, deps: [{ token: i2.FormBuilder }, { token: PublicApiService }], target: i0.ɵɵFactoryTarget.Component });
1427
+ AuthorizationComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "12.0.0", version: "13.2.0", type: AuthorizationComponent, selector: "configcat-authorization", inputs: { basePath: "basePath" }, outputs: { authorized: "authorized" }, ngImport: i0, template: "<form [formGroup]=\"formGroup\" (ngSubmit)=\"onSubmit()\">\n <div class=\"container\">\n <div class=\"form\">\n <p>\n <a href=\"https://app.configcat.com/my-account/public-api-credentials\" target=\"_blank\">\n Get your Basic Auth user name and password</a> to access ConfigCat Public API.\n <br /><br />\n <b>Note!</b> Your ConfigCat account's email address and password will not work here.\n </p>\n\n <mat-form-field class=\"form-field\">\n <mat-label>Basic auth user name</mat-label>\n <input matInput placeholder=\"Basic auth user name\" formControlName=\"basicAuthUsername\">\n <mat-error *ngIf=\"formGroup.controls.basicAuthUsername.invalid\">\n {{FormHelper.getErrorMessage(formGroup.controls.basicAuthUsername)}}\n </mat-error>\n </mat-form-field>\n <mat-form-field class=\"form-field\">\n <mat-label>Basic auth password</mat-label>\n <input matInput placeholder=\"Basic auth password\" formControlName=\"basicAuthPassword\" type=\"password\"\n autocomplete=\"current-password\">\n <mat-error *ngIf=\"formGroup.controls.basicAuthPassword.invalid\">\n {{FormHelper.getErrorMessage(formGroup.controls.basicAuthPassword)}}\n </mat-error>\n </mat-form-field>\n <div>\n <button mat-raised-button color=\"primary\" type=\"submit\" class=\"submit\">Authorize</button>\n <mat-error *ngIf=\"formGroup.invalid && formGroup.errors && formGroup.errors.invalidAuthorization\">\n {{formGroup.errors.invalidAuthorization}}</mat-error>\n </div>\n </div>\n </div>\n</form>", styles: [".container{display:flex;margin:8px}.form{width:100%}.form-field{width:100%;margin-bottom:8px}.submit{margin-top:8px;margin-bottom:8px}\n"], components: [{ type: i3.MatFormField, selector: "mat-form-field", inputs: ["color", "appearance", "hideRequiredMarker", "hintLabel", "floatLabel"], exportAs: ["matFormField"] }, { type: i4.MatButton, selector: "button[mat-button], button[mat-raised-button], button[mat-icon-button], button[mat-fab], button[mat-mini-fab], button[mat-stroked-button], button[mat-flat-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }], directives: [{ type: i2.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { type: i3.MatLabel, selector: "mat-label" }, { type: i5.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { type: i5$1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { type: i3.MatError, selector: "mat-error", inputs: ["id"] }] });
1428
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: AuthorizationComponent, decorators: [{
1429
+ type: Component,
1430
+ args: [{ selector: 'configcat-authorization', template: "<form [formGroup]=\"formGroup\" (ngSubmit)=\"onSubmit()\">\n <div class=\"container\">\n <div class=\"form\">\n <p>\n <a href=\"https://app.configcat.com/my-account/public-api-credentials\" target=\"_blank\">\n Get your Basic Auth user name and password</a> to access ConfigCat Public API.\n <br /><br />\n <b>Note!</b> Your ConfigCat account's email address and password will not work here.\n </p>\n\n <mat-form-field class=\"form-field\">\n <mat-label>Basic auth user name</mat-label>\n <input matInput placeholder=\"Basic auth user name\" formControlName=\"basicAuthUsername\">\n <mat-error *ngIf=\"formGroup.controls.basicAuthUsername.invalid\">\n {{FormHelper.getErrorMessage(formGroup.controls.basicAuthUsername)}}\n </mat-error>\n </mat-form-field>\n <mat-form-field class=\"form-field\">\n <mat-label>Basic auth password</mat-label>\n <input matInput placeholder=\"Basic auth password\" formControlName=\"basicAuthPassword\" type=\"password\"\n autocomplete=\"current-password\">\n <mat-error *ngIf=\"formGroup.controls.basicAuthPassword.invalid\">\n {{FormHelper.getErrorMessage(formGroup.controls.basicAuthPassword)}}\n </mat-error>\n </mat-form-field>\n <div>\n <button mat-raised-button color=\"primary\" type=\"submit\" class=\"submit\">Authorize</button>\n <mat-error *ngIf=\"formGroup.invalid && formGroup.errors && formGroup.errors.invalidAuthorization\">\n {{formGroup.errors.invalidAuthorization}}</mat-error>\n </div>\n </div>\n </div>\n</form>", styles: [".container{display:flex;margin:8px}.form{width:100%}.form-field{width:100%;margin-bottom:8px}.submit{margin-top:8px;margin-bottom:8px}\n"] }]
1431
+ }], ctorParameters: function () { return [{ type: i2.FormBuilder }, { type: PublicApiService }]; }, propDecorators: { basePath: [{
1432
+ type: Input
1433
+ }], authorized: [{
1434
+ type: Output
1435
+ }] } });
1436
+
1437
+ class NgConfigCatPublicApiUIModule {
1438
+ constructor() { }
1439
+ static forRoot(configurationFactory) {
1440
+ return {
1441
+ ngModule: NgConfigCatPublicApiUIModule,
1442
+ providers: [{ provide: Configuration, useFactory: configurationFactory }]
1443
+ };
1444
+ }
1445
+ }
1446
+ NgConfigCatPublicApiUIModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: NgConfigCatPublicApiUIModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
1447
+ NgConfigCatPublicApiUIModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: NgConfigCatPublicApiUIModule, declarations: [BaseComponent,
1448
+ ProductSelectComponent,
1449
+ ConfigSelectComponent,
1450
+ EnvironmentSelectComponent,
1451
+ SettingSelectComponent,
1452
+ SettingItemComponent,
1453
+ AuthorizationComponent,
1454
+ SettingListComponent,
1455
+ SettingComponent,
1456
+ RolloutPercentageItemsComponent,
1457
+ RolloutRulesComponent,
1458
+ ValueComponent,
1459
+ ReasonDialogComponent,
1460
+ ConcurrentDialogComponent,
1461
+ SaveSnackbarComponent,
1462
+ ExpandDialogComponent], imports: [CommonModule,
1463
+ FormsModule,
1464
+ ReactiveFormsModule,
1465
+ BrowserAnimationsModule,
1466
+ MatFormFieldModule,
1467
+ MatOptionModule,
1468
+ MatSelectModule,
1469
+ MatButtonModule,
1470
+ MatInputModule,
1471
+ MatIconModule,
1472
+ MatTooltipModule,
1473
+ MatChipsModule,
1474
+ MatAutocompleteModule,
1475
+ DragDropModule,
1476
+ RouterModule,
1477
+ MatSnackBarModule,
1478
+ MatDialogModule,
1479
+ MatMenuModule,
1480
+ ApiModule], exports: [AuthorizationComponent,
1481
+ ProductSelectComponent,
1482
+ ConfigSelectComponent,
1483
+ EnvironmentSelectComponent,
1484
+ SettingSelectComponent,
1485
+ SettingItemComponent] });
1486
+ NgConfigCatPublicApiUIModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: NgConfigCatPublicApiUIModule, imports: [[
1487
+ CommonModule,
1488
+ FormsModule,
1489
+ ReactiveFormsModule,
1490
+ BrowserAnimationsModule,
1491
+ MatFormFieldModule,
1492
+ MatOptionModule,
1493
+ MatSelectModule,
1494
+ MatButtonModule,
1495
+ MatInputModule,
1496
+ MatIconModule,
1497
+ MatTooltipModule,
1498
+ MatChipsModule,
1499
+ MatAutocompleteModule,
1500
+ DragDropModule,
1501
+ RouterModule,
1502
+ MatSnackBarModule,
1503
+ MatDialogModule,
1504
+ MatMenuModule,
1505
+ ApiModule
1506
+ ]] });
1507
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "13.2.0", ngImport: i0, type: NgConfigCatPublicApiUIModule, decorators: [{
1508
+ type: NgModule,
1509
+ args: [{
1510
+ declarations: [
1511
+ BaseComponent,
1512
+ ProductSelectComponent,
1513
+ ConfigSelectComponent,
1514
+ EnvironmentSelectComponent,
1515
+ SettingSelectComponent,
1516
+ SettingItemComponent,
1517
+ AuthorizationComponent,
1518
+ SettingListComponent,
1519
+ SettingComponent,
1520
+ RolloutPercentageItemsComponent,
1521
+ RolloutRulesComponent,
1522
+ ValueComponent,
1523
+ ReasonDialogComponent,
1524
+ ConcurrentDialogComponent,
1525
+ SaveSnackbarComponent,
1526
+ ExpandDialogComponent
1527
+ ],
1528
+ imports: [
1529
+ CommonModule,
1530
+ FormsModule,
1531
+ ReactiveFormsModule,
1532
+ BrowserAnimationsModule,
1533
+ MatFormFieldModule,
1534
+ MatOptionModule,
1535
+ MatSelectModule,
1536
+ MatButtonModule,
1537
+ MatInputModule,
1538
+ MatIconModule,
1539
+ MatTooltipModule,
1540
+ MatChipsModule,
1541
+ MatAutocompleteModule,
1542
+ DragDropModule,
1543
+ RouterModule,
1544
+ MatSnackBarModule,
1545
+ MatDialogModule,
1546
+ MatMenuModule,
1547
+ ApiModule
1548
+ ],
1549
+ exports: [
1550
+ AuthorizationComponent,
1551
+ ProductSelectComponent,
1552
+ ConfigSelectComponent,
1553
+ EnvironmentSelectComponent,
1554
+ SettingSelectComponent,
1555
+ SettingItemComponent
1556
+ ]
1557
+ }]
1558
+ }], ctorParameters: function () { return []; } });
1559
+
1560
+ /*
1561
+ * Public API Surface of ng-configcat-publicapi-ui
1562
+ */
1563
+
1564
+ /**
1565
+ * Generated bundle index. Do not edit.
1566
+ */
1567
+
1568
+ export { AuthorizationComponent, ConfigSelectComponent, EnvironmentSelectComponent, NgConfigCatPublicApiUIModule, ProductSelectComponent, PublicApiService, SettingItemComponent, SettingSelectComponent };
1569
+ //# sourceMappingURL=ng-configcat-publicapi-ui.mjs.map