ng-configcat-publicapi-ui 5.6.1 → 5.6.3
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.
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { OVERLAY_DEFAULT_CONFIG, Overlay } from '@angular/cdk/overlay';
|
|
2
2
|
import { DatePipe, NgClass, NgTemplateOutlet, SlicePipe, KeyValuePipe } from '@angular/common';
|
|
3
3
|
import * as i0 from '@angular/core';
|
|
4
|
-
import { inject, Injectable, ChangeDetectionStrategy, Component, viewChild, DestroyRef, DOCUMENT, InjectionToken, HostListener, Directive, input, ElementRef, model, effect, output, forwardRef, signal, viewChildren, linkedSignal,
|
|
4
|
+
import { inject, Injectable, ChangeDetectionStrategy, Component, viewChild, DestroyRef, DOCUMENT, InjectionToken, HostListener, Directive, input, ElementRef, model, effect, output, forwardRef, signal, computed, viewChildren, linkedSignal, ViewEncapsulation, ChangeDetectorRef } from '@angular/core';
|
|
5
5
|
import { MAT_AUTOCOMPLETE_SCROLL_STRATEGY, MatAutocompleteTrigger, MatAutocomplete } from '@angular/material/autocomplete';
|
|
6
6
|
import { MAT_BUTTON_TOGGLE_DEFAULT_OPTIONS, MatButtonToggleGroup, MatButtonToggle } from '@angular/material/button-toggle';
|
|
7
7
|
import { MAT_DATEPICKER_SCROLL_STRATEGY, MatDatepicker, MatDatepickerToggle, MatDatepickerInput } from '@angular/material/datepicker';
|
|
@@ -2697,6 +2697,14 @@ class SettingListComponent {
|
|
|
2697
2697
|
this.deleteSettingRequested = output();
|
|
2698
2698
|
this.formValuesChanged = output();
|
|
2699
2699
|
this.saveFailed = output();
|
|
2700
|
+
// Track actual value changes, not just form interaction. If a value is modified then reverted to its original state,
|
|
2701
|
+
// it's not considered dirty. This ensures save/publish buttons activate only for genuine changes, avoiding unnecessary backend operations.
|
|
2702
|
+
this.initialValueJson = signal("", /* @ts-ignore */
|
|
2703
|
+
...(ngDevMode ? [{ debugName: "initialValueJson" }] : /* istanbul ignore next */ []));
|
|
2704
|
+
this.settingValueFormGroupChanged = signal("", /* @ts-ignore */
|
|
2705
|
+
...(ngDevMode ? [{ debugName: "settingValueFormGroupChanged" }] : /* istanbul ignore next */ []));
|
|
2706
|
+
this.formGroupDirty = computed(() => this.settingValueFormGroupChanged() !== this.initialValueJson(), /* @ts-ignore */
|
|
2707
|
+
...(ngDevMode ? [{ debugName: "formGroupDirty" }] : /* istanbul ignore next */ []));
|
|
2700
2708
|
this.loading = true;
|
|
2701
2709
|
this.submitting = false;
|
|
2702
2710
|
this.showFeedBackMessage = false;
|
|
@@ -2744,8 +2752,12 @@ class SettingListComponent {
|
|
|
2744
2752
|
}
|
|
2745
2753
|
createFormGroup() {
|
|
2746
2754
|
this.formGroup = this.formHelper.createSettingValuesFormGroup(this.settingValues);
|
|
2755
|
+
const initialValueRaw = JSON.stringify(this.formGroup.getRawValue());
|
|
2756
|
+
this.initialValueJson.set(initialValueRaw);
|
|
2757
|
+
this.settingValueFormGroupChanged.set(initialValueRaw);
|
|
2747
2758
|
this.formValuesChangedSubscription = this.formGroup.valueChanges.subscribe(() => {
|
|
2748
2759
|
this.formValuesChanged.emit();
|
|
2760
|
+
this.settingValueFormGroupChanged.set(JSON.stringify(this.formGroup.getRawValue()));
|
|
2749
2761
|
});
|
|
2750
2762
|
}
|
|
2751
2763
|
settingValuesFormArray() {
|
|
@@ -2877,11 +2889,11 @@ class SettingListComponent {
|
|
|
2877
2889
|
});
|
|
2878
2890
|
}
|
|
2879
2891
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SettingListComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
2880
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: SettingListComponent, isStandalone: true, selector: "app-setting-list", inputs: { productId: { classPropertyName: "productId", publicName: "productId", isSignal: true, isRequired: true, transformFunction: null }, environmentId: { classPropertyName: "environmentId", publicName: "environmentId", isSignal: true, isRequired: true, transformFunction: null }, configId: { classPropertyName: "configId", publicName: "configId", isSignal: true, isRequired: true, transformFunction: null }, dashboardBasePath: { classPropertyName: "dashboardBasePath", publicName: "dashboardBasePath", isSignal: true, isRequired: false, transformFunction: null }, canDeleteSetting: { classPropertyName: "canDeleteSetting", publicName: "canDeleteSetting", isSignal: true, isRequired: false, transformFunction: null }, onSave: { classPropertyName: "onSave", publicName: "onSave", isSignal: true, isRequired: true, transformFunction: null }, loadSettingValues: { classPropertyName: "loadSettingValues", publicName: "loadSettingValues", isSignal: true, isRequired: true, transformFunction: null }, loadSegments: { classPropertyName: "loadSegments", publicName: "loadSegments", isSignal: true, isRequired: true, transformFunction: null }, deleteSettingText: { classPropertyName: "deleteSettingText", publicName: "deleteSettingText", isSignal: true, isRequired: false, transformFunction: null }, showEnvironmentName: { classPropertyName: "showEnvironmentName", publicName: "showEnvironmentName", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loadSucceeded: "loadSucceeded", deleteSettingRequested: "deleteSettingRequested", formValuesChanged: "formValuesChanged", saveFailed: "saveFailed" }, usesOnChanges: true, ngImport: i0, template: "@if (!loading) {\n <form [formGroup]=\"formGroup\" (ngSubmit)=\"submit()\">\n @for (settingValueFromGroup of formGroup!.controls.settingValues.controls; track $index; let i = $index) {\n <div class=\"wrapper\">\n <div class=\"size-obs\" [style.display]=\"'block'\">\n <div>\n <app-setting\n [formGroup]=\"settingValueFromGroup\"\n [readOnly]=\"readOnly\"\n [canDeleteSetting]=\"canDeleteSetting()\"\n [deleteSettingText]=\"deleteSettingText()\"\n [showEnvironmentName]=\"showEnvironmentName()\"\n [model]=\"settingValues!.settingValues[i]\"\n [segments]=\"segments\"\n [productId]=\"productId()\"\n [configId]=\"configId()\"\n [environmentId]=\"environmentId()\"\n [dashboardBasePath]=\"dashboardBasePath()\"\n [featureFlagLimitations]=\"settingValues!.featureFlagLimitations\"\n (subscriptionLimitReached)=\"onSubscriptionLimitReached()\"\n (deleteSettingRequested)=\"onDeleteSettingRequested($event)\" />\n </div>\n </div>\n </div>\n }\n @if (!readOnly &&
|
|
2892
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: SettingListComponent, isStandalone: true, selector: "app-setting-list", inputs: { productId: { classPropertyName: "productId", publicName: "productId", isSignal: true, isRequired: true, transformFunction: null }, environmentId: { classPropertyName: "environmentId", publicName: "environmentId", isSignal: true, isRequired: true, transformFunction: null }, configId: { classPropertyName: "configId", publicName: "configId", isSignal: true, isRequired: true, transformFunction: null }, dashboardBasePath: { classPropertyName: "dashboardBasePath", publicName: "dashboardBasePath", isSignal: true, isRequired: false, transformFunction: null }, canDeleteSetting: { classPropertyName: "canDeleteSetting", publicName: "canDeleteSetting", isSignal: true, isRequired: false, transformFunction: null }, onSave: { classPropertyName: "onSave", publicName: "onSave", isSignal: true, isRequired: true, transformFunction: null }, loadSettingValues: { classPropertyName: "loadSettingValues", publicName: "loadSettingValues", isSignal: true, isRequired: true, transformFunction: null }, loadSegments: { classPropertyName: "loadSegments", publicName: "loadSegments", isSignal: true, isRequired: true, transformFunction: null }, deleteSettingText: { classPropertyName: "deleteSettingText", publicName: "deleteSettingText", isSignal: true, isRequired: false, transformFunction: null }, showEnvironmentName: { classPropertyName: "showEnvironmentName", publicName: "showEnvironmentName", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { loadSucceeded: "loadSucceeded", deleteSettingRequested: "deleteSettingRequested", formValuesChanged: "formValuesChanged", saveFailed: "saveFailed" }, usesOnChanges: true, ngImport: i0, template: "@if (!loading) {\n <form [formGroup]=\"formGroup\" (ngSubmit)=\"submit()\">\n @for (settingValueFromGroup of formGroup!.controls.settingValues.controls; track $index; let i = $index) {\n <div class=\"wrapper\">\n <div class=\"size-obs\" [style.display]=\"'block'\">\n <div>\n <app-setting\n [formGroup]=\"settingValueFromGroup\"\n [readOnly]=\"readOnly\"\n [canDeleteSetting]=\"canDeleteSetting()\"\n [deleteSettingText]=\"deleteSettingText()\"\n [showEnvironmentName]=\"showEnvironmentName()\"\n [model]=\"settingValues!.settingValues[i]\"\n [segments]=\"segments\"\n [productId]=\"productId()\"\n [configId]=\"configId()\"\n [environmentId]=\"environmentId()\"\n [dashboardBasePath]=\"dashboardBasePath()\"\n [featureFlagLimitations]=\"settingValues!.featureFlagLimitations\"\n (subscriptionLimitReached)=\"onSubscriptionLimitReached()\"\n (deleteSettingRequested)=\"onDeleteSettingRequested($event)\" />\n </div>\n </div>\n </div>\n }\n @if (!readOnly && formGroupDirty()) {\n <div class=\"save\">\n <button class=\"save-button\" mat-flat-button color=\"warn\" type=\"submit\" [disabled]=\"submitting\">\n <mat-icon>backup</mat-icon>\n <span>Save & publish changes</span>\n </button>\n <button type=\"button\" class=\"revert-button\" mat-stroked-button [disabled]=\"submitting\" (click)=\"revert()\">\n <span>Revert</span>\n </button>\n @if (formGroup.touched && formGroup.invalid && showFeedBackMessage) {\n <div class=\"feedback\">\n @if (formGroup.errors && formGroup.errors[\"internalServerError\"]) {\n <div class=\"error\">\n <span>\n Something went wrong and we could not save your settings. You can try again or\n <a href=\"https://configcat.com/support\" target=\"_blank\" rel=\"noopener noreferrer\">contact us.</a>\n </span>\n </div>\n }\n @if (!formGroup.errors || !formGroup.errors[\"internalServerError\"]) {\n <div class=\"error\">\n <span>Oh no! A feature flag has invalid or missing data.</span>\n </div>\n }\n </div>\n }\n </div>\n }\n </form>\n}\n", styles: [".wrapper{margin:1rem 0;padding:0 .5rem}.size-obs .hidden{display:none}.size-obs .visible{display:block}.show-hide a{cursor:pointer;font-size:.8rem}.save{position:sticky;bottom:0;min-height:38px;padding:.5rem 0 .5rem 12px;background-color:var(--page-background-color);display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;z-index:999}.save .save-button{animation:shadow-pulse 1s 3}.save .save-button:disabled{animation:none}.save>*{margin:.3em}.save .revert{margin:0 16px;font-size:14px}.save .yes{margin:0 5px}.error{color:var(--flag-validation-error);padding:5px;font-size:.9em}.error a{color:var(--flag-validation-error);text-decoration:underline}@media(max-width:700px){.save{padding:.5rem 0}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: RxReactiveFormsModule }, { kind: "directive", type: i2.RxwebFormDirective, selector: "[formGroup],[rxwebForm]", inputs: ["formGroup", "rxwebForm"] }, { kind: "component", type: SettingComponent, selector: "app-setting", inputs: ["dashboardBasePath", "productId", "environmentId", "configId", "featureFlagLimitations", "formGroup", "readOnly", "canDeleteSetting", "deleteSettingText", "showEnvironmentName", "segments", "model"], outputs: ["deleteSettingRequested", "subscriptionLimitReached"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
|
|
2881
2893
|
}
|
|
2882
2894
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: SettingListComponent, decorators: [{
|
|
2883
2895
|
type: Component,
|
|
2884
|
-
args: [{ selector: "app-setting-list", changeDetection: ChangeDetectionStrategy.Eager, imports: [FormsModule, ReactiveFormsModule, RxReactiveFormsModule, SettingComponent, MatButton, MatIcon], template: "@if (!loading) {\n <form [formGroup]=\"formGroup\" (ngSubmit)=\"submit()\">\n @for (settingValueFromGroup of formGroup!.controls.settingValues.controls; track $index; let i = $index) {\n <div class=\"wrapper\">\n <div class=\"size-obs\" [style.display]=\"'block'\">\n <div>\n <app-setting\n [formGroup]=\"settingValueFromGroup\"\n [readOnly]=\"readOnly\"\n [canDeleteSetting]=\"canDeleteSetting()\"\n [deleteSettingText]=\"deleteSettingText()\"\n [showEnvironmentName]=\"showEnvironmentName()\"\n [model]=\"settingValues!.settingValues[i]\"\n [segments]=\"segments\"\n [productId]=\"productId()\"\n [configId]=\"configId()\"\n [environmentId]=\"environmentId()\"\n [dashboardBasePath]=\"dashboardBasePath()\"\n [featureFlagLimitations]=\"settingValues!.featureFlagLimitations\"\n (subscriptionLimitReached)=\"onSubscriptionLimitReached()\"\n (deleteSettingRequested)=\"onDeleteSettingRequested($event)\" />\n </div>\n </div>\n </div>\n }\n @if (!readOnly &&
|
|
2896
|
+
args: [{ selector: "app-setting-list", changeDetection: ChangeDetectionStrategy.Eager, imports: [FormsModule, ReactiveFormsModule, RxReactiveFormsModule, SettingComponent, MatButton, MatIcon], template: "@if (!loading) {\n <form [formGroup]=\"formGroup\" (ngSubmit)=\"submit()\">\n @for (settingValueFromGroup of formGroup!.controls.settingValues.controls; track $index; let i = $index) {\n <div class=\"wrapper\">\n <div class=\"size-obs\" [style.display]=\"'block'\">\n <div>\n <app-setting\n [formGroup]=\"settingValueFromGroup\"\n [readOnly]=\"readOnly\"\n [canDeleteSetting]=\"canDeleteSetting()\"\n [deleteSettingText]=\"deleteSettingText()\"\n [showEnvironmentName]=\"showEnvironmentName()\"\n [model]=\"settingValues!.settingValues[i]\"\n [segments]=\"segments\"\n [productId]=\"productId()\"\n [configId]=\"configId()\"\n [environmentId]=\"environmentId()\"\n [dashboardBasePath]=\"dashboardBasePath()\"\n [featureFlagLimitations]=\"settingValues!.featureFlagLimitations\"\n (subscriptionLimitReached)=\"onSubscriptionLimitReached()\"\n (deleteSettingRequested)=\"onDeleteSettingRequested($event)\" />\n </div>\n </div>\n </div>\n }\n @if (!readOnly && formGroupDirty()) {\n <div class=\"save\">\n <button class=\"save-button\" mat-flat-button color=\"warn\" type=\"submit\" [disabled]=\"submitting\">\n <mat-icon>backup</mat-icon>\n <span>Save & publish changes</span>\n </button>\n <button type=\"button\" class=\"revert-button\" mat-stroked-button [disabled]=\"submitting\" (click)=\"revert()\">\n <span>Revert</span>\n </button>\n @if (formGroup.touched && formGroup.invalid && showFeedBackMessage) {\n <div class=\"feedback\">\n @if (formGroup.errors && formGroup.errors[\"internalServerError\"]) {\n <div class=\"error\">\n <span>\n Something went wrong and we could not save your settings. You can try again or\n <a href=\"https://configcat.com/support\" target=\"_blank\" rel=\"noopener noreferrer\">contact us.</a>\n </span>\n </div>\n }\n @if (!formGroup.errors || !formGroup.errors[\"internalServerError\"]) {\n <div class=\"error\">\n <span>Oh no! A feature flag has invalid or missing data.</span>\n </div>\n }\n </div>\n }\n </div>\n }\n </form>\n}\n", styles: [".wrapper{margin:1rem 0;padding:0 .5rem}.size-obs .hidden{display:none}.size-obs .visible{display:block}.show-hide a{cursor:pointer;font-size:.8rem}.save{position:sticky;bottom:0;min-height:38px;padding:.5rem 0 .5rem 12px;background-color:var(--page-background-color);display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;z-index:999}.save .save-button{animation:shadow-pulse 1s 3}.save .save-button:disabled{animation:none}.save>*{margin:.3em}.save .revert{margin:0 16px;font-size:14px}.save .yes{margin:0 5px}.error{color:var(--flag-validation-error);padding:5px;font-size:.9em}.error a{color:var(--flag-validation-error);text-decoration:underline}@media(max-width:700px){.save{padding:.5rem 0}}\n"] }]
|
|
2885
2897
|
}], propDecorators: { productId: [{ type: i0.Input, args: [{ isSignal: true, alias: "productId", required: true }] }], environmentId: [{ type: i0.Input, args: [{ isSignal: true, alias: "environmentId", required: true }] }], configId: [{ type: i0.Input, args: [{ isSignal: true, alias: "configId", required: true }] }], dashboardBasePath: [{ type: i0.Input, args: [{ isSignal: true, alias: "dashboardBasePath", required: false }] }], canDeleteSetting: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDeleteSetting", required: false }] }], onSave: [{ type: i0.Input, args: [{ isSignal: true, alias: "onSave", required: true }] }], loadSettingValues: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadSettingValues", required: true }] }], loadSegments: [{ type: i0.Input, args: [{ isSignal: true, alias: "loadSegments", required: true }] }], deleteSettingText: [{ type: i0.Input, args: [{ isSignal: true, alias: "deleteSettingText", required: false }] }], showEnvironmentName: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEnvironmentName", required: false }] }], loadSucceeded: [{ type: i0.Output, args: ["loadSucceeded"] }], deleteSettingRequested: [{ type: i0.Output, args: ["deleteSettingRequested"] }], formValuesChanged: [{ type: i0.Output, args: ["formValuesChanged"] }], saveFailed: [{ type: i0.Output, args: ["saveFailed"] }] } });
|
|
2886
2898
|
|
|
2887
2899
|
class SettingItemComponent extends BaseComponent {
|
|
@@ -3609,6 +3621,12 @@ class DateTimePickerComponent {
|
|
|
3609
3621
|
if (this.onTouchModel) {
|
|
3610
3622
|
this.onTouchModel();
|
|
3611
3623
|
}
|
|
3624
|
+
if (this.onValidatorChange) {
|
|
3625
|
+
this.onValidatorChange();
|
|
3626
|
+
}
|
|
3627
|
+
this.formGroup.statusChanges
|
|
3628
|
+
.pipe(takeUntilDestroyed(this.destroyRef))
|
|
3629
|
+
.subscribe(() => this.onValidatorChange?.());
|
|
3612
3630
|
});
|
|
3613
3631
|
}
|
|
3614
3632
|
writeValue(obj) {
|
|
@@ -3636,7 +3654,20 @@ class DateTimePickerComponent {
|
|
|
3636
3654
|
}
|
|
3637
3655
|
}
|
|
3638
3656
|
validate() {
|
|
3639
|
-
|
|
3657
|
+
const dateErrors = this.formGroup.controls.dateValue.errors;
|
|
3658
|
+
const timeErrors = this.formGroup.controls.timeValue.errors;
|
|
3659
|
+
if (!dateErrors && !timeErrors) {
|
|
3660
|
+
return null;
|
|
3661
|
+
}
|
|
3662
|
+
return {
|
|
3663
|
+
dateTimePicker: {
|
|
3664
|
+
...(dateErrors ? { dateValue: FormHelper.getErrorMessage(this.formGroup.controls.dateValue) } : {}),
|
|
3665
|
+
...(timeErrors ? { timeValue: FormHelper.getErrorMessage(this.formGroup.controls.timeValue) } : {}),
|
|
3666
|
+
},
|
|
3667
|
+
};
|
|
3668
|
+
}
|
|
3669
|
+
registerOnValidatorChange(fn) {
|
|
3670
|
+
this.onValidatorChange = fn;
|
|
3640
3671
|
}
|
|
3641
3672
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: DateTimePickerComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3642
3673
|
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: DateTimePickerComponent, isStandalone: true, selector: "app-date-time-picker", inputs: { dateTooltip: { classPropertyName: "dateTooltip", publicName: "dateTooltip", isSignal: true, isRequired: false, transformFunction: null }, timeTooltip: { classPropertyName: "timeTooltip", publicName: "timeTooltip", isSignal: true, isRequired: false, transformFunction: null } }, providers: [
|
|
@@ -3732,6 +3763,22 @@ class CreateChangeRequestDialogComponent {
|
|
|
3732
3763
|
error: (error) => {
|
|
3733
3764
|
this.saving.set(false);
|
|
3734
3765
|
FormHelper.handleErrors(this.formGroup, error);
|
|
3766
|
+
// Concurrent update and concurrent delete common handling
|
|
3767
|
+
if (error instanceof HttpErrorResponse && (error.status === 409 || error.status === 404)) {
|
|
3768
|
+
const dialogRef = this.dialog.open(ConfirmationDialogComponent, {
|
|
3769
|
+
width: "450px",
|
|
3770
|
+
data: {
|
|
3771
|
+
title: "There was a conflict while trying to create your change request",
|
|
3772
|
+
body: "Seems like some of the feature flags or settings were deleted or updated by someone else while you were editing them. Reload the config to see its latest state, apply your changes and try the save again.",
|
|
3773
|
+
yesButtonLabel: "Reload",
|
|
3774
|
+
hideCancelButton: true,
|
|
3775
|
+
},
|
|
3776
|
+
});
|
|
3777
|
+
dialogRef.afterClosed().subscribe(() => {
|
|
3778
|
+
this.dialogRef.close({ shouldReloadSettingValues: true });
|
|
3779
|
+
});
|
|
3780
|
+
return;
|
|
3781
|
+
}
|
|
3735
3782
|
if (error instanceof HttpErrorResponse
|
|
3736
3783
|
&& error.status === 400
|
|
3737
3784
|
&& FormHelper.getHttpErrorResponseMessage(error, "SegmentCondition") === "Segment not found.") {
|
|
@@ -3822,7 +3869,7 @@ class CreateChangeRequestDialogComponent {
|
|
|
3822
3869
|
};
|
|
3823
3870
|
}
|
|
3824
3871
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: CreateChangeRequestDialogComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
|
|
3825
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: CreateChangeRequestDialogComponent, isStandalone: true, selector: "app-create-change-request-dialog", viewQueries: [{ propertyName: "reasonInput", first: true, predicate: ["reason"], descendants: true, isSignal: true }], ngImport: i0, template: "<div mat-dialog-title cdkDrag cdkDragRootElement=\".cdk-overlay-pane\" cdkDragHandle class=\"draggable title\">\n @if (data.isSchedule) {\n <div>Schedule change request</div>\n } @else {\n <div>Create change request</div>\n }\n</div>\n\n<div mat-dialog-content>\n <form class=\"form\" [formGroup]=\"formGroup\">\n <mat-form-field appearance=\"outline\" class=\"field-name\">\n <mat-label>Title</mat-label>\n <mat-hint>A short name your team will see on the ConfigCat Dashboard.</mat-hint>\n <input matInput formControlName=\"title\" placeholder=\"e.g. Enable dark mode for beta users\" maxlength=\"255\" />\n @if (formGroup.controls.title.invalid) {\n <mat-error>\n A short name your team will see on the ConfigCat Dashboard.\n {{ FormHelper.getErrorMessage(formGroup.controls.title) }}\n </mat-error>\n }\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" class=\"field-reason\" subscriptSizing=\"dynamic\">\n <mat-label>\n Notes\n @if (!data.reasonRequired) {\n <span class=\"optional\">(optional)</span>\n }\n </mat-label>\n <mat-hint>\n This will appear in the Audit Log (in the Notes section when you expand the corresponding entry) upon applying\n the change request.\n </mat-hint>\n <textarea\n #reason\n matInput\n formControlName=\"reason\"\n rows=\"2\"\n maxlength=\"1000\"\n placeholder=\"Why is this change needed?\"></textarea>\n @if (formGroup.controls.reason.invalid) {\n <mat-error>\n Notes are mandatory for the target environment. {{ FormHelper.getErrorMessage(formGroup.controls.reason) }}\n </mat-error>\n }\n </mat-form-field>\n\n @if (data.isSchedule) {\n <div class=\"section\">\n <h3>When should the proposed changes be applied?</h3>\n <div class=\"scheduled\">\n <div class=\"date-selector\">\n <app-date-time-picker [formControl]=\"formGroup.controls.applyAt\" />\n @if (formGroup.controls.applyAt.invalid) {\n <mat-error class=\"error\">\n {{ FormHelper.getErrorMessage(formGroup.controls.applyAt) }}\n </mat-error>\n }\n </div>\n @if (data.environmentApproveRequired && data.canBypassApproval) {\n <div>\n <mat-checkbox\n matInput\n color=\"primary\"\n class=\"bypass-approval-checkbox\"\n formControlName=\"bypassApproval\"\n matTooltip=\"Enabling this option will bypass the approval requirement of the target environment and \n lets the change request be applied on schedule even if it's not approved.\"\n matTooltipPosition=\"below\">\n Bypass approval requirement for scheduled changes\n </mat-checkbox>\n </div>\n }\n <app-box type=\"info\">\n The proposed changes will be applied at the scheduled time.\n <br />\n If conflicting changes occur before the scheduled time, they will prevent applying the scheduled changes.\n <br />\n You can always cancel the scheduled operation before it is executed and apply the changes manually.\n </app-box>\n </div>\n </div>\n }\n </form>\n</div>\n\n<div mat-dialog-actions>\n <button class=\"submit-button\" mat-flat-button type=\"submit\" color=\"success\" [disabled]=\"saving()\" (click)=\"submit()\">\n @if (data.isSchedule) {\n <mat-icon class=\"icon-transform-rotate\">schedule</mat-icon>\n } @else {\n <mat-icon>merge_type</mat-icon>\n }\n <span>{{ submitLabel }}</span>\n </button>\n <button type=\"button\" mat-stroked-button [mat-dialog-close]>Cancel</button>\n</div>\n", styles: [".title{display:flex;justify-content:space-between;align-items:center;gap:16px}.title .sub-title{font-size:13px;font-weight:400;color:var(--panel-description-color)}.form{display:flex;flex-direction:column;gap:10px;margin-top:10px;margin-bottom:10px}.form .field-name,.form .field-reason,.form .field-apply-at{width:100%}.form .optional{font-size:12px;font-weight:400;color:var(--panel-description-color)}h3{font-size:14px;font-weight:500;color:var(--text-color)}.changes-title{display:flex;justify-content:space-between;align-items:center}.error{font-size:10px}.section{margin-top:.8rem}.section .scheduled{display:flex;flex-direction:column;flex-wrap:wrap;gap:12px}.section .scheduled .bypass-approval-checkbox{--mat-checkbox-label-text-size: 12px;--mat-checkbox-label-text-color: var(--panel-description-color);margin-left:-2px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: BoxComponent, selector: "app-box", inputs: ["type", "title"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: DateTimePickerComponent, selector: "app-date-time-picker", inputs: ["dateTooltip", "timeTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3872
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: CreateChangeRequestDialogComponent, isStandalone: true, selector: "app-create-change-request-dialog", viewQueries: [{ propertyName: "reasonInput", first: true, predicate: ["reason"], descendants: true, isSignal: true }], ngImport: i0, template: "<div mat-dialog-title cdkDrag cdkDragRootElement=\".cdk-overlay-pane\" cdkDragHandle class=\"draggable title\">\n @if (data.isSchedule) {\n <div>Schedule change request</div>\n } @else {\n <div>Create change request</div>\n }\n</div>\n\n<div mat-dialog-content>\n <form class=\"form\" [formGroup]=\"formGroup\">\n <mat-form-field appearance=\"outline\" class=\"field-name\">\n <mat-label>Title</mat-label>\n <mat-hint>A short name your team will see on the ConfigCat Dashboard.</mat-hint>\n <input matInput formControlName=\"title\" placeholder=\"e.g. Enable dark mode for beta users\" maxlength=\"255\" />\n @if (formGroup.controls.title.invalid) {\n <mat-error>\n A short name your team will see on the ConfigCat Dashboard.\n {{ FormHelper.getErrorMessage(formGroup.controls.title) }}\n </mat-error>\n }\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" class=\"field-reason\" subscriptSizing=\"dynamic\">\n <mat-label>\n Notes\n @if (!data.reasonRequired) {\n <span class=\"optional\">(optional)</span>\n }\n </mat-label>\n <mat-hint>\n This will appear in the Audit Log (in the Notes section when you expand the corresponding entry) upon applying\n the change request.\n </mat-hint>\n <textarea\n #reason\n matInput\n formControlName=\"reason\"\n rows=\"2\"\n maxlength=\"1000\"\n placeholder=\"Why is this change needed?\"></textarea>\n @if (formGroup.controls.reason.invalid) {\n <mat-error>\n Notes are mandatory for the target environment. {{ FormHelper.getErrorMessage(formGroup.controls.reason) }}\n </mat-error>\n }\n </mat-form-field>\n\n @if (data.isSchedule) {\n <div class=\"section\">\n <h3>When should the proposed changes be applied?</h3>\n <div class=\"scheduled\">\n <div class=\"date-selector\">\n <app-date-time-picker [formControl]=\"formGroup.controls.applyAt\" />\n @if (formGroup.controls.applyAt.invalid) {\n @let scheduleErrorMessage = FormHelper.getErrorMessage(formGroup.controls.applyAt);\n @if (scheduleErrorMessage) {\n <mat-error class=\"error\">\n {{ scheduleErrorMessage }}\n </mat-error>\n }\n }\n </div>\n @if (data.environmentApproveRequired && data.canBypassApproval) {\n <div>\n <mat-checkbox\n matInput\n color=\"primary\"\n class=\"bypass-approval-checkbox\"\n formControlName=\"bypassApproval\"\n matTooltip=\"Enabling this option will bypass the approval requirement of the target environment and \n lets the change request be applied on schedule even if it's not approved.\"\n matTooltipPosition=\"below\">\n Bypass approval requirement for scheduled changes\n </mat-checkbox>\n </div>\n }\n <app-box type=\"info\">\n The proposed changes will be applied at the scheduled time.\n <br />\n If conflicting changes occur before the scheduled time, they will prevent applying the scheduled changes.\n <br />\n You can always cancel the scheduled operation before it is executed and apply the changes manually.\n </app-box>\n </div>\n </div>\n }\n @if (formGroup.errors && formGroup.errors[\"serverSide\"]) {\n <mat-error>\n <span>{{ formGroup.errors[\"serverSide\"] }}</span>\n </mat-error>\n }\n </form>\n</div>\n\n<div mat-dialog-actions>\n <button class=\"submit-button\" mat-flat-button type=\"submit\" color=\"success\" [disabled]=\"saving()\" (click)=\"submit()\">\n @if (data.isSchedule) {\n <mat-icon class=\"icon-transform-rotate\">schedule</mat-icon>\n } @else {\n <mat-icon>merge_type</mat-icon>\n }\n <span>{{ submitLabel }}</span>\n </button>\n <button type=\"button\" mat-stroked-button [mat-dialog-close]>Cancel</button>\n</div>\n", styles: [".title{display:flex;justify-content:space-between;align-items:center;gap:16px}.title .sub-title{font-size:13px;font-weight:400;color:var(--panel-description-color)}.form{display:flex;flex-direction:column;gap:10px;margin-top:10px;margin-bottom:10px}.form .field-name,.form .field-reason,.form .field-apply-at{width:100%}.form .optional{font-size:12px;font-weight:400;color:var(--panel-description-color)}h3{font-size:14px;font-weight:500;color:var(--text-color)}.changes-title{display:flex;justify-content:space-between;align-items:center}.error{font-size:10px;color:var(--flag-validation-error)}.section{margin-top:.8rem}.section .scheduled{display:flex;flex-direction:column;flex-wrap:wrap;gap:12px}.section .scheduled .bypass-approval-checkbox{--mat-checkbox-label-text-size: 12px;--mat-checkbox-label-text-color: var(--panel-description-color);margin-left:-2px}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox]):not([ngNoCva])[formControlName],textarea:not([ngNoCva])[formControlName],input:not([type=checkbox]):not([ngNoCva])[formControl],textarea:not([ngNoCva])[formControl],input:not([type=checkbox]):not([ngNoCva])[ngModel],textarea:not([ngNoCva])[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.MaxLengthValidator, selector: "[maxlength][formControlName],[maxlength][formControl],[maxlength][ngModel]", inputs: ["maxlength"] }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: MatDialogTitle, selector: "[mat-dialog-title], [matDialogTitle]", inputs: ["id"], exportAs: ["matDialogTitle"] }, { kind: "directive", type: MatDialogClose, selector: "[mat-dialog-close], [matDialogClose]", inputs: ["aria-label", "type", "mat-dialog-close", "matDialogClose"], exportAs: ["matDialogClose"] }, { kind: "directive", type: MatDialogContent, selector: "[mat-dialog-content], mat-dialog-content, [matDialogContent]" }, { kind: "directive", type: MatDialogActions, selector: "[mat-dialog-actions], mat-dialog-actions, [matDialogActions]", inputs: ["align"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: MatLabel, selector: "mat-label" }, { kind: "directive", type: MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly", "disabledInteractive"], exportAs: ["matInput"] }, { kind: "directive", type: MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "directive", type: MatHint, selector: "mat-hint", inputs: ["align", "id"] }, { kind: "component", type: MatCheckbox, selector: "mat-checkbox", inputs: ["aria-label", "aria-labelledby", "aria-describedby", "aria-expanded", "aria-controls", "aria-owns", "id", "required", "labelPosition", "name", "value", "disableRipple", "tabIndex", "color", "disabledInteractive", "checked", "disabled", "indeterminate"], outputs: ["change", "indeterminateChange"], exportAs: ["matCheckbox"] }, { kind: "component", type: BoxComponent, selector: "app-box", inputs: ["type", "title"] }, { kind: "directive", type: MatTooltip, selector: "[matTooltip]", inputs: ["matTooltipPosition", "matTooltipPositionAtOrigin", "matTooltipDisabled", "matTooltipShowDelay", "matTooltipHideDelay", "matTooltipTouchGestures", "matTooltip", "matTooltipClass"], exportAs: ["matTooltip"] }, { kind: "directive", type: CdkDrag, selector: "[cdkDrag]", inputs: ["cdkDragData", "cdkDragLockAxis", "cdkDragRootElement", "cdkDragBoundary", "cdkDragStartDelay", "cdkDragFreeDragPosition", "cdkDragDisabled", "cdkDragConstrainPosition", "cdkDragPreviewClass", "cdkDragPreviewContainer", "cdkDragScale"], outputs: ["cdkDragStarted", "cdkDragReleased", "cdkDragEnded", "cdkDragEntered", "cdkDragExited", "cdkDragDropped", "cdkDragMoved"], exportAs: ["cdkDrag"] }, { kind: "directive", type: CdkDragHandle, selector: "[cdkDragHandle]", inputs: ["cdkDragHandleDisabled"] }, { kind: "component", type: DateTimePickerComponent, selector: "app-date-time-picker", inputs: ["dateTooltip", "timeTooltip"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush }); }
|
|
3826
3873
|
}
|
|
3827
3874
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: CreateChangeRequestDialogComponent, decorators: [{
|
|
3828
3875
|
type: Component,
|
|
@@ -3846,7 +3893,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
|
|
|
3846
3893
|
CdkDrag,
|
|
3847
3894
|
CdkDragHandle,
|
|
3848
3895
|
DateTimePickerComponent,
|
|
3849
|
-
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div mat-dialog-title cdkDrag cdkDragRootElement=\".cdk-overlay-pane\" cdkDragHandle class=\"draggable title\">\n @if (data.isSchedule) {\n <div>Schedule change request</div>\n } @else {\n <div>Create change request</div>\n }\n</div>\n\n<div mat-dialog-content>\n <form class=\"form\" [formGroup]=\"formGroup\">\n <mat-form-field appearance=\"outline\" class=\"field-name\">\n <mat-label>Title</mat-label>\n <mat-hint>A short name your team will see on the ConfigCat Dashboard.</mat-hint>\n <input matInput formControlName=\"title\" placeholder=\"e.g. Enable dark mode for beta users\" maxlength=\"255\" />\n @if (formGroup.controls.title.invalid) {\n <mat-error>\n A short name your team will see on the ConfigCat Dashboard.\n {{ FormHelper.getErrorMessage(formGroup.controls.title) }}\n </mat-error>\n }\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" class=\"field-reason\" subscriptSizing=\"dynamic\">\n <mat-label>\n Notes\n @if (!data.reasonRequired) {\n <span class=\"optional\">(optional)</span>\n }\n </mat-label>\n <mat-hint>\n This will appear in the Audit Log (in the Notes section when you expand the corresponding entry) upon applying\n the change request.\n </mat-hint>\n <textarea\n #reason\n matInput\n formControlName=\"reason\"\n rows=\"2\"\n maxlength=\"1000\"\n placeholder=\"Why is this change needed?\"></textarea>\n @if (formGroup.controls.reason.invalid) {\n <mat-error>\n Notes are mandatory for the target environment. {{ FormHelper.getErrorMessage(formGroup.controls.reason) }}\n </mat-error>\n }\n </mat-form-field>\n\n @if (data.isSchedule) {\n <div class=\"section\">\n <h3>When should the proposed changes be applied?</h3>\n <div class=\"scheduled\">\n <div class=\"date-selector\">\n <app-date-time-picker [formControl]=\"formGroup.controls.applyAt\" />\n @if (formGroup.controls.applyAt.invalid) {\n <mat-error class=\"error\">\n
|
|
3896
|
+
], changeDetection: ChangeDetectionStrategy.OnPush, template: "<div mat-dialog-title cdkDrag cdkDragRootElement=\".cdk-overlay-pane\" cdkDragHandle class=\"draggable title\">\n @if (data.isSchedule) {\n <div>Schedule change request</div>\n } @else {\n <div>Create change request</div>\n }\n</div>\n\n<div mat-dialog-content>\n <form class=\"form\" [formGroup]=\"formGroup\">\n <mat-form-field appearance=\"outline\" class=\"field-name\">\n <mat-label>Title</mat-label>\n <mat-hint>A short name your team will see on the ConfigCat Dashboard.</mat-hint>\n <input matInput formControlName=\"title\" placeholder=\"e.g. Enable dark mode for beta users\" maxlength=\"255\" />\n @if (formGroup.controls.title.invalid) {\n <mat-error>\n A short name your team will see on the ConfigCat Dashboard.\n {{ FormHelper.getErrorMessage(formGroup.controls.title) }}\n </mat-error>\n }\n </mat-form-field>\n\n <mat-form-field appearance=\"outline\" class=\"field-reason\" subscriptSizing=\"dynamic\">\n <mat-label>\n Notes\n @if (!data.reasonRequired) {\n <span class=\"optional\">(optional)</span>\n }\n </mat-label>\n <mat-hint>\n This will appear in the Audit Log (in the Notes section when you expand the corresponding entry) upon applying\n the change request.\n </mat-hint>\n <textarea\n #reason\n matInput\n formControlName=\"reason\"\n rows=\"2\"\n maxlength=\"1000\"\n placeholder=\"Why is this change needed?\"></textarea>\n @if (formGroup.controls.reason.invalid) {\n <mat-error>\n Notes are mandatory for the target environment. {{ FormHelper.getErrorMessage(formGroup.controls.reason) }}\n </mat-error>\n }\n </mat-form-field>\n\n @if (data.isSchedule) {\n <div class=\"section\">\n <h3>When should the proposed changes be applied?</h3>\n <div class=\"scheduled\">\n <div class=\"date-selector\">\n <app-date-time-picker [formControl]=\"formGroup.controls.applyAt\" />\n @if (formGroup.controls.applyAt.invalid) {\n @let scheduleErrorMessage = FormHelper.getErrorMessage(formGroup.controls.applyAt);\n @if (scheduleErrorMessage) {\n <mat-error class=\"error\">\n {{ scheduleErrorMessage }}\n </mat-error>\n }\n }\n </div>\n @if (data.environmentApproveRequired && data.canBypassApproval) {\n <div>\n <mat-checkbox\n matInput\n color=\"primary\"\n class=\"bypass-approval-checkbox\"\n formControlName=\"bypassApproval\"\n matTooltip=\"Enabling this option will bypass the approval requirement of the target environment and \n lets the change request be applied on schedule even if it's not approved.\"\n matTooltipPosition=\"below\">\n Bypass approval requirement for scheduled changes\n </mat-checkbox>\n </div>\n }\n <app-box type=\"info\">\n The proposed changes will be applied at the scheduled time.\n <br />\n If conflicting changes occur before the scheduled time, they will prevent applying the scheduled changes.\n <br />\n You can always cancel the scheduled operation before it is executed and apply the changes manually.\n </app-box>\n </div>\n </div>\n }\n @if (formGroup.errors && formGroup.errors[\"serverSide\"]) {\n <mat-error>\n <span>{{ formGroup.errors[\"serverSide\"] }}</span>\n </mat-error>\n }\n </form>\n</div>\n\n<div mat-dialog-actions>\n <button class=\"submit-button\" mat-flat-button type=\"submit\" color=\"success\" [disabled]=\"saving()\" (click)=\"submit()\">\n @if (data.isSchedule) {\n <mat-icon class=\"icon-transform-rotate\">schedule</mat-icon>\n } @else {\n <mat-icon>merge_type</mat-icon>\n }\n <span>{{ submitLabel }}</span>\n </button>\n <button type=\"button\" mat-stroked-button [mat-dialog-close]>Cancel</button>\n</div>\n", styles: [".title{display:flex;justify-content:space-between;align-items:center;gap:16px}.title .sub-title{font-size:13px;font-weight:400;color:var(--panel-description-color)}.form{display:flex;flex-direction:column;gap:10px;margin-top:10px;margin-bottom:10px}.form .field-name,.form .field-reason,.form .field-apply-at{width:100%}.form .optional{font-size:12px;font-weight:400;color:var(--panel-description-color)}h3{font-size:14px;font-weight:500;color:var(--text-color)}.changes-title{display:flex;justify-content:space-between;align-items:center}.error{font-size:10px;color:var(--flag-validation-error)}.section{margin-top:.8rem}.section .scheduled{display:flex;flex-direction:column;flex-wrap:wrap;gap:12px}.section .scheduled .bypass-approval-checkbox{--mat-checkbox-label-text-size: 12px;--mat-checkbox-label-text-color: var(--panel-description-color);margin-left:-2px}\n"] }]
|
|
3850
3897
|
}], propDecorators: { reasonInput: [{ type: i0.ViewChild, args: ["reason", { isSignal: true }] }] } });
|
|
3851
3898
|
|
|
3852
3899
|
class CopyableValueComponent {
|
|
@@ -6966,6 +7013,14 @@ class FeatureFlagItemComponent extends BaseComponent {
|
|
|
6966
7013
|
this.showFeedBackMessage = false;
|
|
6967
7014
|
this.hasSettingValues = false;
|
|
6968
7015
|
this.hasOtherEnvironment = false;
|
|
7016
|
+
// Track actual value changes, not just form interaction. If a value is modified then reverted to its original state,
|
|
7017
|
+
// it's not considered dirty. This ensures save/publish buttons activate only for genuine changes, avoiding unnecessary backend operations.
|
|
7018
|
+
this.initialValueJson = signal("", /* @ts-ignore */
|
|
7019
|
+
...(ngDevMode ? [{ debugName: "initialValueJson" }] : /* istanbul ignore next */ []));
|
|
7020
|
+
this.settingValueFormGroupChanged = signal("", /* @ts-ignore */
|
|
7021
|
+
...(ngDevMode ? [{ debugName: "settingValueFormGroupChanged" }] : /* istanbul ignore next */ []));
|
|
7022
|
+
this.formGroupDirty = computed(() => this.settingValueFormGroupChanged() !== this.initialValueJson(), /* @ts-ignore */
|
|
7023
|
+
...(ngDevMode ? [{ debugName: "formGroupDirty" }] : /* istanbul ignore next */ []));
|
|
6969
7024
|
this.comparisonAttributes = computed(() => {
|
|
6970
7025
|
const settingFormula = this.settingFormula();
|
|
6971
7026
|
if (this.loading || !settingFormula)
|
|
@@ -7035,8 +7090,12 @@ class FeatureFlagItemComponent extends BaseComponent {
|
|
|
7035
7090
|
};
|
|
7036
7091
|
this.unsubscribeFormValueChangesSubscription();
|
|
7037
7092
|
this.createFormGroupFromState(model);
|
|
7093
|
+
const initialValueRaw = JSON.stringify(this.formGroup.getRawValue());
|
|
7094
|
+
this.initialValueJson.set(initialValueRaw);
|
|
7095
|
+
this.settingValueFormGroupChanged.set(initialValueRaw);
|
|
7038
7096
|
this.formValueChangesSubscription = this.formGroup.valueChanges.subscribe(() => {
|
|
7039
7097
|
this.formValuesChanged.emit();
|
|
7098
|
+
this.settingValueFormGroupChanged.set(JSON.stringify(this.formGroup.getRawValue()));
|
|
7040
7099
|
});
|
|
7041
7100
|
this.recalcAddButtons();
|
|
7042
7101
|
this.recalcPrerequisites();
|
|
@@ -7195,6 +7254,9 @@ class FeatureFlagItemComponent extends BaseComponent {
|
|
|
7195
7254
|
this.messagingService.showSuccessSnack("Change request created successfully.", 5000);
|
|
7196
7255
|
this.reloadSettingValues();
|
|
7197
7256
|
}
|
|
7257
|
+
else if (result?.shouldReloadSettingValues) {
|
|
7258
|
+
this.reloadSettingValues();
|
|
7259
|
+
}
|
|
7198
7260
|
});
|
|
7199
7261
|
}
|
|
7200
7262
|
updateSettingValues(updateModel, bypassApproval, reason, latestVersionId) {
|
|
@@ -7505,7 +7567,7 @@ class FeatureFlagItemComponent extends BaseComponent {
|
|
|
7505
7567
|
});
|
|
7506
7568
|
}
|
|
7507
7569
|
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FeatureFlagItemComponent, deps: null, target: i0.ɵɵFactoryTarget.Component }); }
|
|
7508
|
-
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: FeatureFlagItemComponent, isStandalone: true, selector: "app-feature-flag-item", inputs: { productId: { classPropertyName: "productId", publicName: "productId", isSignal: true, isRequired: true, transformFunction: null }, environmentId: { classPropertyName: "environmentId", publicName: "environmentId", isSignal: true, isRequired: true, transformFunction: null }, configId: { classPropertyName: "configId", publicName: "configId", isSignal: true, isRequired: true, transformFunction: null }, settingId: { classPropertyName: "settingId", publicName: "settingId", isSignal: true, isRequired: true, transformFunction: null }, canDeleteSetting: { classPropertyName: "canDeleteSetting", publicName: "canDeleteSetting", isSignal: true, isRequired: false, transformFunction: null }, customize: { classPropertyName: "customize", publicName: "customize", isSignal: true, isRequired: false, transformFunction: null }, showEnvironmentName: { classPropertyName: "showEnvironmentName", publicName: "showEnvironmentName", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { deleteSettingRequested: "deleteSettingRequested", loadSucceeded: "loadSucceeded", loadFailed: "loadFailed", saveSucceeded: "saveSucceeded", componentError: "componentError", expandedStateChanged: "expandedStateChanged", formValuesChanged: "formValuesChanged" }, usesInheritance: true, ngImport: i0, template: "@let settingFormulaValue = settingFormula();\n<div class=\"container\">\n @if (!loading && settingFormulaValue) {\n <form id=\"feature-flag-form\" [formGroup]=\"formGroup\" (ngSubmit)=\"submit()\">\n <div [ngClass]=\"{ 'invalid-flag': formGroup.invalid }\">\n <app-feature-flag\n [formGroup]=\"formGroup\"\n [flagState]=\"flagState\"\n [segments]=\"segments\"\n [comparisonAttributes]=\"comparisonAttributes()\"\n [featureFlagLimitations]=\"settingFormulaValue.featureFlagLimitations\"\n [hasOtherEnvironment]=\"false\"\n [showEnvironmentName]=\"showEnvironmentName()\"\n [environmentName]=\"settingFormulaValue.environment.name\"\n [canDeleteSetting]=\"canDeleteSetting()\"\n [predefinedVariationsEnabled]=\"true\"\n [dashboardBasePath]=\"dashboardBasePath\"\n [customize]=\"customize()\"\n (deleteSettingRequested)=\"onDeleteSettingRequested($event)\"\n (subscriptionLimitReached)=\"subscriptionLimitReachedCalled()\"\n (addSegmentConditionRequestedWithoutSegments)=\"addSegmentConditionRequestedWithoutSegments()\"\n (prerequisiteConditionChanged)=\"recalcPrerequisites()\"\n (recalcAddButtons)=\"recalcAddButtons()\"\n (expandedChanged)=\"expandedChanged($event)\"\n (viewVariationsRequested)=\"viewVariations($event)\" />\n </div>\n @if (!settingFormulaValue.readOnly && formGroup!.dirty) {\n <div class=\"save\">\n <div class=\"save-button-group\">\n @if (!settingFormulaValue.approveRequired) {\n <button\n class=\"save-button right-side-flat\"\n mat-flat-button\n color=\"warn\"\n type=\"submit\"\n [disabled]=\"submitting\">\n <mat-icon>backup</mat-icon>\n <span>Save & publish changes</span>\n </button>\n <button\n class=\"save-button-dropdown\"\n mat-flat-button\n color=\"warn\"\n type=\"button\"\n [disabled]=\"submitting\"\n [matMenuTriggerFor]=\"proposeMenu\">\n <mat-icon>arrow_drop_down</mat-icon>\n </button>\n <mat-menu #proposeMenu=\"matMenu\" xPosition=\"before\">\n <button type=\"button\" mat-menu-item (click)=\"createChangeRequest(false)\">\n <mat-icon>call_merge</mat-icon>\n <span>Propose changes</span>\n </button>\n <button type=\"button\" mat-menu-item (click)=\"createChangeRequest(true)\">\n <mat-icon class=\"icon-transform-rotate\">schedule</mat-icon>\n <span>Schedule changes</span>\n </button>\n </mat-menu>\n } @else {\n <button\n class=\"save-button right-side-flat\"\n mat-flat-button\n type=\"button\"\n color=\"success\"\n [disabled]=\"submitting\"\n (click)=\"createChangeRequest(false)\">\n <mat-icon>call_merge</mat-icon>\n <span>Propose changes</span>\n </button>\n <button\n class=\"save-button-dropdown\"\n mat-flat-button\n color=\"success\"\n type=\"button\"\n [disabled]=\"submitting\"\n [matMenuTriggerFor]=\"proposeMenu\">\n <mat-icon>arrow_drop_down</mat-icon>\n </button>\n <mat-menu #proposeMenu=\"matMenu\" xPosition=\"before\" class=\"full-width-menu\">\n <button type=\"button\" mat-menu-item (click)=\"createChangeRequest(true)\">\n <mat-icon class=\"icon-transform-rotate\">schedule</mat-icon>\n <span>Schedule changes</span>\n </button>\n @if (settingFormulaValue.canBypassApproval) {\n <button type=\"button\" mat-menu-item (click)=\"submit(true)\">\n <mat-icon>backup</mat-icon>\n <span>Save & publish without approval</span>\n </button>\n }\n </mat-menu>\n }\n </div>\n <button\n type=\"button\"\n class=\"revert-button\"\n mat-stroked-button\n [disabled]=\"submitting\"\n [track]=\"['revert click', 'feature flags and settings']\"\n (click)=\"revert()\">\n <span>Revert</span>\n </button>\n @if (formGroup.touched && formGroup.invalid && showFeedBackMessage) {\n <div class=\"feedback\">\n @if (formGroup.errors && formGroup.errors[\"internalServerError\"]) {\n <div class=\"error\">\n <span>\n Something went wrong and we could not save your settings. You can try again or\n <a href=\"https://configcat.com/support\" target=\"_blank\" rel=\"noopener noreferrer\">contact us.</a>\n </span>\n </div>\n }\n @if (!formGroup.errors || !formGroup.errors[\"internalServerError\"]) {\n <div class=\"error\">\n <span>Oh no! A feature flag has invalid or missing data. </span>\n </div>\n }\n </div>\n }\n </div>\n }\n </form>\n }\n</div>\n", styles: [".container{padding:0 .5rem 1rem}.container .container-content{padding-top:1rem}.container .size-obs{min-width:40px;min-height:120px}.container .size-obs .hidden{display:none}.container .size-obs .visible{display:block}.container .controls{display:flex;flex-wrap:wrap;justify-content:space-between;padding-bottom:.5rem;padding-top:.2rem;gap:1rem}.container .controls .controls-left{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem}.container .controls .controls-left .add-feature-flag-wrapper{display:flex;flex-wrap:nowrap}.container .controls .controls-left .add-feature-flag-wrapper .add-feature-flag{border-bottom-right-radius:0%;border-top-right-radius:0%}.container .controls .controls-left .add-feature-flag-wrapper .add-other-setting{min-width:0;border-bottom-left-radius:0%;border-top-left-radius:0%;border-left:0px;padding:0 12px}.container .controls .controls-left .add-feature-flag-wrapper .add-other-setting .mat-icon{margin-right:0;margin-left:0}.container .controls .controls-left .tag-filter{min-width:0}.container .controls .controls-left .tag-filter mat-form-field{max-width:600px;min-width:246px}.container .controls .controls-left .tag-filter mat-form-field input{max-width:100px}.container .controls .controls-left .tag-filter .tag{font-size:.9em;max-width:120px;min-width:0}.container .controls .more-container{display:flex;gap:.5rem}.container .controls .more-container .more-button{padding:0 8px;min-width:unset}.container .controls .more-container .more-button mat-icon{margin-left:unset;margin-right:unset}.container .controls .option-icon{opacity:.7}.container .controls .option-name{font-size:14px}.container .controls .option-name mat-icon{font-size:22px;width:22px;height:22px}.container .not-found{text-align:center;padding-top:2rem}.container .not-found img{width:300px}.container .history-link{display:flex;align-items:center;margin-left:.2em}.container .history-link mat-icon{margin-right:5px;font-size:20px;width:20px;height:20px}.container .jump{cursor:pointer}.container .feature-flags-container{margin-bottom:.3rem}.container .save{position:sticky;bottom:0;background-color:var(--page-background-color);display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;z-index:999;padding-top:1rem;padding-bottom:1rem;gap:.5rem}.container .save .save-button{height:38px;font-size:13px!important}.container .save .save-button:disabled{animation:none}.container .save .save-button-group{display:flex;align-items:stretch}.container .save .save-button-group .save-button.right-side-flat{border-top-right-radius:0;border-bottom-right-radius:0}.container .save .save-button-group .save-button-dropdown{border-top-left-radius:0;border-bottom-left-radius:0;min-width:unset;height:38px;padding:0 12px;border-left:1px var(--save-separator-color) solid}.container .save .save-button-group .save-button-dropdown .mat-icon{margin-right:0;margin-left:0}.container .save .save-button-group .save-button-dropdown:disabled{border-left-color:var(--save-separator-disabled-color)}.container .error{color:var(--flag-validation-error);padding:5px;font-size:.9em}.container .error a{color:var(--flag-validation-error);text-decoration:underline}.container .steps{display:flex;align-items:center;margin:1rem 0;justify-content:space-between;flex-wrap:wrap}.container .steps .steps-left{display:flex;flex-wrap:nowrap;align-items:center;justify-content:flex-start}.container .steps .steps-left>h2{cursor:pointer}.container .steps .connected{display:flex;align-items:center}.container .divider{margin-top:1.3rem}.add-menu-item{display:flex;align-items:center;text-wrap:nowrap}.add-menu-item .add-menu-img{width:24px;height:24px;margin-right:8px}.top-menu-selector .strong{font-weight:600}.top-menu-selector .feature-flag-selector-item{display:flex;flex-wrap:nowrap}.top-menu-selector .feature-flag-selector-item .feature-flag-selector-img{width:24px;height:24px;margin-right:8px;align-self:center}.top-menu-selector .feature-flag-selector-item span{overflow:hidden;text-overflow:ellipsis}.top-menu-selector .filter{display:flex;margin:0 8px 8px;justify-content:space-around}.top-menu-selector .filter mat-form-field{width:100%}.top-menu-selector .filter-not-found{margin-left:12px}.connect-title{font-size:17px;font-weight:700;margin:16px 0;cursor:pointer}.search-key-icon{display:inline-flex;justify-content:center;align-items:center;font-size:11px;width:1.8em;height:1.8em;margin-right:1px;background-color:var(--flag-search-bar-icon-background);border-radius:3px;border:1px solid var(--flag-search-bar-icon-border)}@media(max-width:750px){.container{padding:0 .5rem 1rem}.expand-collapse{flex-wrap:wrap!important}.expand-collapse .btn{margin-bottom:2px}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: RxReactiveFormsModule }, { kind: "directive", type: i2.RxwebFormDirective, selector: "[formGroup],[rxwebForm]", inputs: ["formGroup", "rxwebForm"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: FeatureFlagComponent, selector: "app-feature-flag", inputs: ["formGroup", "flagState", "segments", "featureFlagLimitations", "hasOtherEnvironment", "environmentName", "showEnvironmentName", "canDeleteSetting", "predefinedVariationsEnabled", "dashboardBasePath", "comparisonAttributes", "customize"], outputs: ["addSegmentConditionRequestedWithoutSegments", "expandedChanged", "deleteSettingRequested", "subscriptionLimitReached", "prerequisiteConditionChanged", "recalcAddButtons", "viewVariationsRequested"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: TrackingDirective, selector: "[track]", inputs: ["track"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
|
|
7570
|
+
static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "22.1.1", type: FeatureFlagItemComponent, isStandalone: true, selector: "app-feature-flag-item", inputs: { productId: { classPropertyName: "productId", publicName: "productId", isSignal: true, isRequired: true, transformFunction: null }, environmentId: { classPropertyName: "environmentId", publicName: "environmentId", isSignal: true, isRequired: true, transformFunction: null }, configId: { classPropertyName: "configId", publicName: "configId", isSignal: true, isRequired: true, transformFunction: null }, settingId: { classPropertyName: "settingId", publicName: "settingId", isSignal: true, isRequired: true, transformFunction: null }, canDeleteSetting: { classPropertyName: "canDeleteSetting", publicName: "canDeleteSetting", isSignal: true, isRequired: false, transformFunction: null }, customize: { classPropertyName: "customize", publicName: "customize", isSignal: true, isRequired: false, transformFunction: null }, showEnvironmentName: { classPropertyName: "showEnvironmentName", publicName: "showEnvironmentName", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { deleteSettingRequested: "deleteSettingRequested", loadSucceeded: "loadSucceeded", loadFailed: "loadFailed", saveSucceeded: "saveSucceeded", componentError: "componentError", expandedStateChanged: "expandedStateChanged", formValuesChanged: "formValuesChanged" }, usesInheritance: true, ngImport: i0, template: "@let settingFormulaValue = settingFormula();\n<div class=\"container\">\n @if (!loading && settingFormulaValue) {\n <form id=\"feature-flag-form\" [formGroup]=\"formGroup\" (ngSubmit)=\"submit()\">\n <div [ngClass]=\"{ 'invalid-flag': formGroup.invalid }\">\n <app-feature-flag\n [formGroup]=\"formGroup\"\n [flagState]=\"flagState\"\n [segments]=\"segments\"\n [comparisonAttributes]=\"comparisonAttributes()\"\n [featureFlagLimitations]=\"settingFormulaValue.featureFlagLimitations\"\n [hasOtherEnvironment]=\"false\"\n [showEnvironmentName]=\"showEnvironmentName()\"\n [environmentName]=\"settingFormulaValue.environment.name\"\n [canDeleteSetting]=\"canDeleteSetting()\"\n [predefinedVariationsEnabled]=\"true\"\n [dashboardBasePath]=\"dashboardBasePath\"\n [customize]=\"customize()\"\n (deleteSettingRequested)=\"onDeleteSettingRequested($event)\"\n (subscriptionLimitReached)=\"subscriptionLimitReachedCalled()\"\n (addSegmentConditionRequestedWithoutSegments)=\"addSegmentConditionRequestedWithoutSegments()\"\n (prerequisiteConditionChanged)=\"recalcPrerequisites()\"\n (recalcAddButtons)=\"recalcAddButtons()\"\n (expandedChanged)=\"expandedChanged($event)\"\n (viewVariationsRequested)=\"viewVariations($event)\" />\n </div>\n @if (!settingFormulaValue.readOnly && formGroupDirty()) {\n <div class=\"save\">\n <div class=\"save-button-group\">\n @if (!settingFormulaValue.approveRequired) {\n <button\n class=\"save-button right-side-flat\"\n mat-flat-button\n color=\"warn\"\n type=\"submit\"\n [disabled]=\"submitting\">\n <mat-icon>backup</mat-icon>\n <span>Save & publish changes</span>\n </button>\n <button\n class=\"save-button-dropdown\"\n mat-flat-button\n color=\"warn\"\n type=\"button\"\n [disabled]=\"submitting\"\n [matMenuTriggerFor]=\"proposeMenu\">\n <mat-icon>arrow_drop_down</mat-icon>\n </button>\n <mat-menu #proposeMenu=\"matMenu\" xPosition=\"before\">\n <button type=\"button\" mat-menu-item (click)=\"createChangeRequest(false)\">\n <mat-icon>call_merge</mat-icon>\n <span>Propose changes</span>\n </button>\n <button type=\"button\" mat-menu-item (click)=\"createChangeRequest(true)\">\n <mat-icon class=\"icon-transform-rotate\">schedule</mat-icon>\n <span>Schedule changes</span>\n </button>\n </mat-menu>\n } @else {\n <button\n class=\"save-button right-side-flat\"\n mat-flat-button\n type=\"button\"\n color=\"success\"\n [disabled]=\"submitting\"\n (click)=\"createChangeRequest(false)\">\n <mat-icon>call_merge</mat-icon>\n <span>Propose changes</span>\n </button>\n <button\n class=\"save-button-dropdown\"\n mat-flat-button\n color=\"success\"\n type=\"button\"\n [disabled]=\"submitting\"\n [matMenuTriggerFor]=\"proposeMenu\">\n <mat-icon>arrow_drop_down</mat-icon>\n </button>\n <mat-menu #proposeMenu=\"matMenu\" xPosition=\"before\" class=\"full-width-menu\">\n <button type=\"button\" mat-menu-item (click)=\"createChangeRequest(true)\">\n <mat-icon class=\"icon-transform-rotate\">schedule</mat-icon>\n <span>Schedule changes</span>\n </button>\n @if (settingFormulaValue.canBypassApproval) {\n <button type=\"button\" mat-menu-item (click)=\"submit(true)\">\n <mat-icon>backup</mat-icon>\n <span>Save & publish without approval</span>\n </button>\n }\n </mat-menu>\n }\n </div>\n <button\n type=\"button\"\n class=\"revert-button\"\n mat-stroked-button\n [disabled]=\"submitting\"\n [track]=\"['revert click', 'feature flags and settings']\"\n (click)=\"revert()\">\n <span>Revert</span>\n </button>\n @if (formGroup.touched && formGroup.invalid && showFeedBackMessage) {\n <div class=\"feedback\">\n @if (formGroup.errors && formGroup.errors[\"internalServerError\"]) {\n <div class=\"error\">\n <span>\n Something went wrong and we could not save your settings. You can try again or\n <a href=\"https://configcat.com/support\" target=\"_blank\" rel=\"noopener noreferrer\">contact us.</a>\n </span>\n </div>\n }\n @if (!formGroup.errors || !formGroup.errors[\"internalServerError\"]) {\n <div class=\"error\">\n <span>Oh no! A feature flag has invalid or missing data. </span>\n </div>\n }\n </div>\n }\n </div>\n }\n </form>\n }\n</div>\n", styles: [".container{padding:0 .5rem 1rem}.container .container-content{padding-top:1rem}.container .size-obs{min-width:40px;min-height:120px}.container .size-obs .hidden{display:none}.container .size-obs .visible{display:block}.container .controls{display:flex;flex-wrap:wrap;justify-content:space-between;padding-bottom:.5rem;padding-top:.2rem;gap:1rem}.container .controls .controls-left{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem}.container .controls .controls-left .add-feature-flag-wrapper{display:flex;flex-wrap:nowrap}.container .controls .controls-left .add-feature-flag-wrapper .add-feature-flag{border-bottom-right-radius:0%;border-top-right-radius:0%}.container .controls .controls-left .add-feature-flag-wrapper .add-other-setting{min-width:0;border-bottom-left-radius:0%;border-top-left-radius:0%;border-left:0px;padding:0 12px}.container .controls .controls-left .add-feature-flag-wrapper .add-other-setting .mat-icon{margin-right:0;margin-left:0}.container .controls .controls-left .tag-filter{min-width:0}.container .controls .controls-left .tag-filter mat-form-field{max-width:600px;min-width:246px}.container .controls .controls-left .tag-filter mat-form-field input{max-width:100px}.container .controls .controls-left .tag-filter .tag{font-size:.9em;max-width:120px;min-width:0}.container .controls .more-container{display:flex;gap:.5rem}.container .controls .more-container .more-button{padding:0 8px;min-width:unset}.container .controls .more-container .more-button mat-icon{margin-left:unset;margin-right:unset}.container .controls .option-icon{opacity:.7}.container .controls .option-name{font-size:14px}.container .controls .option-name mat-icon{font-size:22px;width:22px;height:22px}.container .not-found{text-align:center;padding-top:2rem}.container .not-found img{width:300px}.container .history-link{display:flex;align-items:center;margin-left:.2em}.container .history-link mat-icon{margin-right:5px;font-size:20px;width:20px;height:20px}.container .jump{cursor:pointer}.container .feature-flags-container{margin-bottom:.3rem}.container .save{position:sticky;bottom:0;background-color:var(--page-background-color);display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;z-index:999;padding-top:1rem;padding-bottom:1rem;gap:.5rem}.container .save .save-button{height:38px;font-size:13px!important}.container .save .save-button:disabled{animation:none}.container .save .save-button-group{display:flex;align-items:stretch}.container .save .save-button-group .save-button.right-side-flat{border-top-right-radius:0;border-bottom-right-radius:0}.container .save .save-button-group .save-button-dropdown{border-top-left-radius:0;border-bottom-left-radius:0;min-width:unset;height:38px;padding:0 12px;border-left:1px var(--save-separator-color) solid}.container .save .save-button-group .save-button-dropdown .mat-icon{margin-right:0;margin-left:0}.container .save .save-button-group .save-button-dropdown:disabled{border-left-color:var(--save-separator-disabled-color)}.container .error{color:var(--flag-validation-error);padding:5px;font-size:.9em}.container .error a{color:var(--flag-validation-error);text-decoration:underline}.container .steps{display:flex;align-items:center;margin:1rem 0;justify-content:space-between;flex-wrap:wrap}.container .steps .steps-left{display:flex;flex-wrap:nowrap;align-items:center;justify-content:flex-start}.container .steps .steps-left>h2{cursor:pointer}.container .steps .connected{display:flex;align-items:center}.container .divider{margin-top:1.3rem}.add-menu-item{display:flex;align-items:center;text-wrap:nowrap}.add-menu-item .add-menu-img{width:24px;height:24px;margin-right:8px}.top-menu-selector .strong{font-weight:600}.top-menu-selector .feature-flag-selector-item{display:flex;flex-wrap:nowrap}.top-menu-selector .feature-flag-selector-item .feature-flag-selector-img{width:24px;height:24px;margin-right:8px;align-self:center}.top-menu-selector .feature-flag-selector-item span{overflow:hidden;text-overflow:ellipsis}.top-menu-selector .filter{display:flex;margin:0 8px 8px;justify-content:space-around}.top-menu-selector .filter mat-form-field{width:100%}.top-menu-selector .filter-not-found{margin-left:12px}.connect-title{font-size:17px;font-weight:700;margin:16px 0;cursor:pointer}.search-key-icon{display:inline-flex;justify-content:center;align-items:center;font-size:11px;width:1.8em;height:1.8em;margin-right:1px;background-color:var(--flag-search-bar-icon-background);border-radius:3px;border:1px solid var(--flag-search-bar-icon-border)}@media(max-width:750px){.container{padding:0 .5rem 1rem}.expand-collapse{flex-wrap:wrap!important}.expand-collapse .btn{margin-bottom:2px}}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "ngmodule", type: ReactiveFormsModule }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "ngmodule", type: RxReactiveFormsModule }, { kind: "directive", type: i2.RxwebFormDirective, selector: "[formGroup],[rxwebForm]", inputs: ["formGroup", "rxwebForm"] }, { kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "component", type: FeatureFlagComponent, selector: "app-feature-flag", inputs: ["formGroup", "flagState", "segments", "featureFlagLimitations", "hasOtherEnvironment", "environmentName", "showEnvironmentName", "canDeleteSetting", "predefinedVariationsEnabled", "dashboardBasePath", "comparisonAttributes", "customize"], outputs: ["addSegmentConditionRequestedWithoutSegments", "expandedChanged", "deleteSettingRequested", "subscriptionLimitReached", "prerequisiteConditionChanged", "recalcAddButtons", "viewVariationsRequested"] }, { kind: "component", type: MatButton, selector: " button[matButton], a[matButton], button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button], a[mat-button], a[mat-raised-button], a[mat-flat-button], a[mat-stroked-button] ", inputs: ["matButton"], exportAs: ["matButton", "matAnchor"] }, { kind: "directive", type: TrackingDirective, selector: "[track]", inputs: ["track"] }, { kind: "component", type: MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: MatMenu, selector: "mat-menu", inputs: ["backdropClass", "aria-label", "aria-labelledby", "aria-describedby", "xPosition", "yPosition", "overlapTrigger", "hasBackdrop", "class", "classList"], outputs: ["closed", "close"], exportAs: ["matMenu"] }, { kind: "component", type: MatMenuItem, selector: "[mat-menu-item]", inputs: ["role", "disabled", "disableRipple"], exportAs: ["matMenuItem"] }, { kind: "directive", type: MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", inputs: ["mat-menu-trigger-for", "matMenuTriggerFor", "matMenuTriggerData", "matMenuTriggerRestoreFocus"], outputs: ["menuOpened", "onMenuOpen", "menuClosed", "onMenuClose"], exportAs: ["matMenuTrigger"] }], changeDetection: i0.ChangeDetectionStrategy.Eager }); }
|
|
7509
7571
|
}
|
|
7510
7572
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImport: i0, type: FeatureFlagItemComponent, decorators: [{
|
|
7511
7573
|
type: Component,
|
|
@@ -7521,7 +7583,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "22.1.1", ngImpor
|
|
|
7521
7583
|
MatMenu,
|
|
7522
7584
|
MatMenuItem,
|
|
7523
7585
|
MatMenuTrigger,
|
|
7524
|
-
], template: "@let settingFormulaValue = settingFormula();\n<div class=\"container\">\n @if (!loading && settingFormulaValue) {\n <form id=\"feature-flag-form\" [formGroup]=\"formGroup\" (ngSubmit)=\"submit()\">\n <div [ngClass]=\"{ 'invalid-flag': formGroup.invalid }\">\n <app-feature-flag\n [formGroup]=\"formGroup\"\n [flagState]=\"flagState\"\n [segments]=\"segments\"\n [comparisonAttributes]=\"comparisonAttributes()\"\n [featureFlagLimitations]=\"settingFormulaValue.featureFlagLimitations\"\n [hasOtherEnvironment]=\"false\"\n [showEnvironmentName]=\"showEnvironmentName()\"\n [environmentName]=\"settingFormulaValue.environment.name\"\n [canDeleteSetting]=\"canDeleteSetting()\"\n [predefinedVariationsEnabled]=\"true\"\n [dashboardBasePath]=\"dashboardBasePath\"\n [customize]=\"customize()\"\n (deleteSettingRequested)=\"onDeleteSettingRequested($event)\"\n (subscriptionLimitReached)=\"subscriptionLimitReachedCalled()\"\n (addSegmentConditionRequestedWithoutSegments)=\"addSegmentConditionRequestedWithoutSegments()\"\n (prerequisiteConditionChanged)=\"recalcPrerequisites()\"\n (recalcAddButtons)=\"recalcAddButtons()\"\n (expandedChanged)=\"expandedChanged($event)\"\n (viewVariationsRequested)=\"viewVariations($event)\" />\n </div>\n @if (!settingFormulaValue.readOnly && formGroup!.dirty) {\n <div class=\"save\">\n <div class=\"save-button-group\">\n @if (!settingFormulaValue.approveRequired) {\n <button\n class=\"save-button right-side-flat\"\n mat-flat-button\n color=\"warn\"\n type=\"submit\"\n [disabled]=\"submitting\">\n <mat-icon>backup</mat-icon>\n <span>Save & publish changes</span>\n </button>\n <button\n class=\"save-button-dropdown\"\n mat-flat-button\n color=\"warn\"\n type=\"button\"\n [disabled]=\"submitting\"\n [matMenuTriggerFor]=\"proposeMenu\">\n <mat-icon>arrow_drop_down</mat-icon>\n </button>\n <mat-menu #proposeMenu=\"matMenu\" xPosition=\"before\">\n <button type=\"button\" mat-menu-item (click)=\"createChangeRequest(false)\">\n <mat-icon>call_merge</mat-icon>\n <span>Propose changes</span>\n </button>\n <button type=\"button\" mat-menu-item (click)=\"createChangeRequest(true)\">\n <mat-icon class=\"icon-transform-rotate\">schedule</mat-icon>\n <span>Schedule changes</span>\n </button>\n </mat-menu>\n } @else {\n <button\n class=\"save-button right-side-flat\"\n mat-flat-button\n type=\"button\"\n color=\"success\"\n [disabled]=\"submitting\"\n (click)=\"createChangeRequest(false)\">\n <mat-icon>call_merge</mat-icon>\n <span>Propose changes</span>\n </button>\n <button\n class=\"save-button-dropdown\"\n mat-flat-button\n color=\"success\"\n type=\"button\"\n [disabled]=\"submitting\"\n [matMenuTriggerFor]=\"proposeMenu\">\n <mat-icon>arrow_drop_down</mat-icon>\n </button>\n <mat-menu #proposeMenu=\"matMenu\" xPosition=\"before\" class=\"full-width-menu\">\n <button type=\"button\" mat-menu-item (click)=\"createChangeRequest(true)\">\n <mat-icon class=\"icon-transform-rotate\">schedule</mat-icon>\n <span>Schedule changes</span>\n </button>\n @if (settingFormulaValue.canBypassApproval) {\n <button type=\"button\" mat-menu-item (click)=\"submit(true)\">\n <mat-icon>backup</mat-icon>\n <span>Save & publish without approval</span>\n </button>\n }\n </mat-menu>\n }\n </div>\n <button\n type=\"button\"\n class=\"revert-button\"\n mat-stroked-button\n [disabled]=\"submitting\"\n [track]=\"['revert click', 'feature flags and settings']\"\n (click)=\"revert()\">\n <span>Revert</span>\n </button>\n @if (formGroup.touched && formGroup.invalid && showFeedBackMessage) {\n <div class=\"feedback\">\n @if (formGroup.errors && formGroup.errors[\"internalServerError\"]) {\n <div class=\"error\">\n <span>\n Something went wrong and we could not save your settings. You can try again or\n <a href=\"https://configcat.com/support\" target=\"_blank\" rel=\"noopener noreferrer\">contact us.</a>\n </span>\n </div>\n }\n @if (!formGroup.errors || !formGroup.errors[\"internalServerError\"]) {\n <div class=\"error\">\n <span>Oh no! A feature flag has invalid or missing data. </span>\n </div>\n }\n </div>\n }\n </div>\n }\n </form>\n }\n</div>\n", styles: [".container{padding:0 .5rem 1rem}.container .container-content{padding-top:1rem}.container .size-obs{min-width:40px;min-height:120px}.container .size-obs .hidden{display:none}.container .size-obs .visible{display:block}.container .controls{display:flex;flex-wrap:wrap;justify-content:space-between;padding-bottom:.5rem;padding-top:.2rem;gap:1rem}.container .controls .controls-left{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem}.container .controls .controls-left .add-feature-flag-wrapper{display:flex;flex-wrap:nowrap}.container .controls .controls-left .add-feature-flag-wrapper .add-feature-flag{border-bottom-right-radius:0%;border-top-right-radius:0%}.container .controls .controls-left .add-feature-flag-wrapper .add-other-setting{min-width:0;border-bottom-left-radius:0%;border-top-left-radius:0%;border-left:0px;padding:0 12px}.container .controls .controls-left .add-feature-flag-wrapper .add-other-setting .mat-icon{margin-right:0;margin-left:0}.container .controls .controls-left .tag-filter{min-width:0}.container .controls .controls-left .tag-filter mat-form-field{max-width:600px;min-width:246px}.container .controls .controls-left .tag-filter mat-form-field input{max-width:100px}.container .controls .controls-left .tag-filter .tag{font-size:.9em;max-width:120px;min-width:0}.container .controls .more-container{display:flex;gap:.5rem}.container .controls .more-container .more-button{padding:0 8px;min-width:unset}.container .controls .more-container .more-button mat-icon{margin-left:unset;margin-right:unset}.container .controls .option-icon{opacity:.7}.container .controls .option-name{font-size:14px}.container .controls .option-name mat-icon{font-size:22px;width:22px;height:22px}.container .not-found{text-align:center;padding-top:2rem}.container .not-found img{width:300px}.container .history-link{display:flex;align-items:center;margin-left:.2em}.container .history-link mat-icon{margin-right:5px;font-size:20px;width:20px;height:20px}.container .jump{cursor:pointer}.container .feature-flags-container{margin-bottom:.3rem}.container .save{position:sticky;bottom:0;background-color:var(--page-background-color);display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;z-index:999;padding-top:1rem;padding-bottom:1rem;gap:.5rem}.container .save .save-button{height:38px;font-size:13px!important}.container .save .save-button:disabled{animation:none}.container .save .save-button-group{display:flex;align-items:stretch}.container .save .save-button-group .save-button.right-side-flat{border-top-right-radius:0;border-bottom-right-radius:0}.container .save .save-button-group .save-button-dropdown{border-top-left-radius:0;border-bottom-left-radius:0;min-width:unset;height:38px;padding:0 12px;border-left:1px var(--save-separator-color) solid}.container .save .save-button-group .save-button-dropdown .mat-icon{margin-right:0;margin-left:0}.container .save .save-button-group .save-button-dropdown:disabled{border-left-color:var(--save-separator-disabled-color)}.container .error{color:var(--flag-validation-error);padding:5px;font-size:.9em}.container .error a{color:var(--flag-validation-error);text-decoration:underline}.container .steps{display:flex;align-items:center;margin:1rem 0;justify-content:space-between;flex-wrap:wrap}.container .steps .steps-left{display:flex;flex-wrap:nowrap;align-items:center;justify-content:flex-start}.container .steps .steps-left>h2{cursor:pointer}.container .steps .connected{display:flex;align-items:center}.container .divider{margin-top:1.3rem}.add-menu-item{display:flex;align-items:center;text-wrap:nowrap}.add-menu-item .add-menu-img{width:24px;height:24px;margin-right:8px}.top-menu-selector .strong{font-weight:600}.top-menu-selector .feature-flag-selector-item{display:flex;flex-wrap:nowrap}.top-menu-selector .feature-flag-selector-item .feature-flag-selector-img{width:24px;height:24px;margin-right:8px;align-self:center}.top-menu-selector .feature-flag-selector-item span{overflow:hidden;text-overflow:ellipsis}.top-menu-selector .filter{display:flex;margin:0 8px 8px;justify-content:space-around}.top-menu-selector .filter mat-form-field{width:100%}.top-menu-selector .filter-not-found{margin-left:12px}.connect-title{font-size:17px;font-weight:700;margin:16px 0;cursor:pointer}.search-key-icon{display:inline-flex;justify-content:center;align-items:center;font-size:11px;width:1.8em;height:1.8em;margin-right:1px;background-color:var(--flag-search-bar-icon-background);border-radius:3px;border:1px solid var(--flag-search-bar-icon-border)}@media(max-width:750px){.container{padding:0 .5rem 1rem}.expand-collapse{flex-wrap:wrap!important}.expand-collapse .btn{margin-bottom:2px}}\n"] }]
|
|
7586
|
+
], template: "@let settingFormulaValue = settingFormula();\n<div class=\"container\">\n @if (!loading && settingFormulaValue) {\n <form id=\"feature-flag-form\" [formGroup]=\"formGroup\" (ngSubmit)=\"submit()\">\n <div [ngClass]=\"{ 'invalid-flag': formGroup.invalid }\">\n <app-feature-flag\n [formGroup]=\"formGroup\"\n [flagState]=\"flagState\"\n [segments]=\"segments\"\n [comparisonAttributes]=\"comparisonAttributes()\"\n [featureFlagLimitations]=\"settingFormulaValue.featureFlagLimitations\"\n [hasOtherEnvironment]=\"false\"\n [showEnvironmentName]=\"showEnvironmentName()\"\n [environmentName]=\"settingFormulaValue.environment.name\"\n [canDeleteSetting]=\"canDeleteSetting()\"\n [predefinedVariationsEnabled]=\"true\"\n [dashboardBasePath]=\"dashboardBasePath\"\n [customize]=\"customize()\"\n (deleteSettingRequested)=\"onDeleteSettingRequested($event)\"\n (subscriptionLimitReached)=\"subscriptionLimitReachedCalled()\"\n (addSegmentConditionRequestedWithoutSegments)=\"addSegmentConditionRequestedWithoutSegments()\"\n (prerequisiteConditionChanged)=\"recalcPrerequisites()\"\n (recalcAddButtons)=\"recalcAddButtons()\"\n (expandedChanged)=\"expandedChanged($event)\"\n (viewVariationsRequested)=\"viewVariations($event)\" />\n </div>\n @if (!settingFormulaValue.readOnly && formGroupDirty()) {\n <div class=\"save\">\n <div class=\"save-button-group\">\n @if (!settingFormulaValue.approveRequired) {\n <button\n class=\"save-button right-side-flat\"\n mat-flat-button\n color=\"warn\"\n type=\"submit\"\n [disabled]=\"submitting\">\n <mat-icon>backup</mat-icon>\n <span>Save & publish changes</span>\n </button>\n <button\n class=\"save-button-dropdown\"\n mat-flat-button\n color=\"warn\"\n type=\"button\"\n [disabled]=\"submitting\"\n [matMenuTriggerFor]=\"proposeMenu\">\n <mat-icon>arrow_drop_down</mat-icon>\n </button>\n <mat-menu #proposeMenu=\"matMenu\" xPosition=\"before\">\n <button type=\"button\" mat-menu-item (click)=\"createChangeRequest(false)\">\n <mat-icon>call_merge</mat-icon>\n <span>Propose changes</span>\n </button>\n <button type=\"button\" mat-menu-item (click)=\"createChangeRequest(true)\">\n <mat-icon class=\"icon-transform-rotate\">schedule</mat-icon>\n <span>Schedule changes</span>\n </button>\n </mat-menu>\n } @else {\n <button\n class=\"save-button right-side-flat\"\n mat-flat-button\n type=\"button\"\n color=\"success\"\n [disabled]=\"submitting\"\n (click)=\"createChangeRequest(false)\">\n <mat-icon>call_merge</mat-icon>\n <span>Propose changes</span>\n </button>\n <button\n class=\"save-button-dropdown\"\n mat-flat-button\n color=\"success\"\n type=\"button\"\n [disabled]=\"submitting\"\n [matMenuTriggerFor]=\"proposeMenu\">\n <mat-icon>arrow_drop_down</mat-icon>\n </button>\n <mat-menu #proposeMenu=\"matMenu\" xPosition=\"before\" class=\"full-width-menu\">\n <button type=\"button\" mat-menu-item (click)=\"createChangeRequest(true)\">\n <mat-icon class=\"icon-transform-rotate\">schedule</mat-icon>\n <span>Schedule changes</span>\n </button>\n @if (settingFormulaValue.canBypassApproval) {\n <button type=\"button\" mat-menu-item (click)=\"submit(true)\">\n <mat-icon>backup</mat-icon>\n <span>Save & publish without approval</span>\n </button>\n }\n </mat-menu>\n }\n </div>\n <button\n type=\"button\"\n class=\"revert-button\"\n mat-stroked-button\n [disabled]=\"submitting\"\n [track]=\"['revert click', 'feature flags and settings']\"\n (click)=\"revert()\">\n <span>Revert</span>\n </button>\n @if (formGroup.touched && formGroup.invalid && showFeedBackMessage) {\n <div class=\"feedback\">\n @if (formGroup.errors && formGroup.errors[\"internalServerError\"]) {\n <div class=\"error\">\n <span>\n Something went wrong and we could not save your settings. You can try again or\n <a href=\"https://configcat.com/support\" target=\"_blank\" rel=\"noopener noreferrer\">contact us.</a>\n </span>\n </div>\n }\n @if (!formGroup.errors || !formGroup.errors[\"internalServerError\"]) {\n <div class=\"error\">\n <span>Oh no! A feature flag has invalid or missing data. </span>\n </div>\n }\n </div>\n }\n </div>\n }\n </form>\n }\n</div>\n", styles: [".container{padding:0 .5rem 1rem}.container .container-content{padding-top:1rem}.container .size-obs{min-width:40px;min-height:120px}.container .size-obs .hidden{display:none}.container .size-obs .visible{display:block}.container .controls{display:flex;flex-wrap:wrap;justify-content:space-between;padding-bottom:.5rem;padding-top:.2rem;gap:1rem}.container .controls .controls-left{display:flex;flex-wrap:wrap;align-items:center;gap:.5rem}.container .controls .controls-left .add-feature-flag-wrapper{display:flex;flex-wrap:nowrap}.container .controls .controls-left .add-feature-flag-wrapper .add-feature-flag{border-bottom-right-radius:0%;border-top-right-radius:0%}.container .controls .controls-left .add-feature-flag-wrapper .add-other-setting{min-width:0;border-bottom-left-radius:0%;border-top-left-radius:0%;border-left:0px;padding:0 12px}.container .controls .controls-left .add-feature-flag-wrapper .add-other-setting .mat-icon{margin-right:0;margin-left:0}.container .controls .controls-left .tag-filter{min-width:0}.container .controls .controls-left .tag-filter mat-form-field{max-width:600px;min-width:246px}.container .controls .controls-left .tag-filter mat-form-field input{max-width:100px}.container .controls .controls-left .tag-filter .tag{font-size:.9em;max-width:120px;min-width:0}.container .controls .more-container{display:flex;gap:.5rem}.container .controls .more-container .more-button{padding:0 8px;min-width:unset}.container .controls .more-container .more-button mat-icon{margin-left:unset;margin-right:unset}.container .controls .option-icon{opacity:.7}.container .controls .option-name{font-size:14px}.container .controls .option-name mat-icon{font-size:22px;width:22px;height:22px}.container .not-found{text-align:center;padding-top:2rem}.container .not-found img{width:300px}.container .history-link{display:flex;align-items:center;margin-left:.2em}.container .history-link mat-icon{margin-right:5px;font-size:20px;width:20px;height:20px}.container .jump{cursor:pointer}.container .feature-flags-container{margin-bottom:.3rem}.container .save{position:sticky;bottom:0;background-color:var(--page-background-color);display:flex;flex-direction:row;flex-wrap:wrap;align-items:center;z-index:999;padding-top:1rem;padding-bottom:1rem;gap:.5rem}.container .save .save-button{height:38px;font-size:13px!important}.container .save .save-button:disabled{animation:none}.container .save .save-button-group{display:flex;align-items:stretch}.container .save .save-button-group .save-button.right-side-flat{border-top-right-radius:0;border-bottom-right-radius:0}.container .save .save-button-group .save-button-dropdown{border-top-left-radius:0;border-bottom-left-radius:0;min-width:unset;height:38px;padding:0 12px;border-left:1px var(--save-separator-color) solid}.container .save .save-button-group .save-button-dropdown .mat-icon{margin-right:0;margin-left:0}.container .save .save-button-group .save-button-dropdown:disabled{border-left-color:var(--save-separator-disabled-color)}.container .error{color:var(--flag-validation-error);padding:5px;font-size:.9em}.container .error a{color:var(--flag-validation-error);text-decoration:underline}.container .steps{display:flex;align-items:center;margin:1rem 0;justify-content:space-between;flex-wrap:wrap}.container .steps .steps-left{display:flex;flex-wrap:nowrap;align-items:center;justify-content:flex-start}.container .steps .steps-left>h2{cursor:pointer}.container .steps .connected{display:flex;align-items:center}.container .divider{margin-top:1.3rem}.add-menu-item{display:flex;align-items:center;text-wrap:nowrap}.add-menu-item .add-menu-img{width:24px;height:24px;margin-right:8px}.top-menu-selector .strong{font-weight:600}.top-menu-selector .feature-flag-selector-item{display:flex;flex-wrap:nowrap}.top-menu-selector .feature-flag-selector-item .feature-flag-selector-img{width:24px;height:24px;margin-right:8px;align-self:center}.top-menu-selector .feature-flag-selector-item span{overflow:hidden;text-overflow:ellipsis}.top-menu-selector .filter{display:flex;margin:0 8px 8px;justify-content:space-around}.top-menu-selector .filter mat-form-field{width:100%}.top-menu-selector .filter-not-found{margin-left:12px}.connect-title{font-size:17px;font-weight:700;margin:16px 0;cursor:pointer}.search-key-icon{display:inline-flex;justify-content:center;align-items:center;font-size:11px;width:1.8em;height:1.8em;margin-right:1px;background-color:var(--flag-search-bar-icon-background);border-radius:3px;border:1px solid var(--flag-search-bar-icon-border)}@media(max-width:750px){.container{padding:0 .5rem 1rem}.expand-collapse{flex-wrap:wrap!important}.expand-collapse .btn{margin-bottom:2px}}\n"] }]
|
|
7525
7587
|
}], propDecorators: { productId: [{ type: i0.Input, args: [{ isSignal: true, alias: "productId", required: true }] }], environmentId: [{ type: i0.Input, args: [{ isSignal: true, alias: "environmentId", required: true }] }], configId: [{ type: i0.Input, args: [{ isSignal: true, alias: "configId", required: true }] }], settingId: [{ type: i0.Input, args: [{ isSignal: true, alias: "settingId", required: true }] }], canDeleteSetting: [{ type: i0.Input, args: [{ isSignal: true, alias: "canDeleteSetting", required: false }] }], customize: [{ type: i0.Input, args: [{ isSignal: true, alias: "customize", required: false }] }], showEnvironmentName: [{ type: i0.Input, args: [{ isSignal: true, alias: "showEnvironmentName", required: false }] }], deleteSettingRequested: [{ type: i0.Output, args: ["deleteSettingRequested"] }], loadSucceeded: [{ type: i0.Output, args: ["loadSucceeded"] }], loadFailed: [{ type: i0.Output, args: ["loadFailed"] }], saveSucceeded: [{ type: i0.Output, args: ["saveSucceeded"] }], componentError: [{ type: i0.Output, args: ["componentError"] }], expandedStateChanged: [{ type: i0.Output, args: ["expandedStateChanged"] }], formValuesChanged: [{ type: i0.Output, args: ["formValuesChanged"] }] } });
|
|
7526
7588
|
|
|
7527
7589
|
const DEFAULT_CUSTOMIZE_LINK_FEATURE_FLAG = {
|