Skip to content

Commit

Permalink
Common tag input component (#1643)
Browse files Browse the repository at this point in the history
* Common tag input component

* Removed commented code

* Merge branch 'dev' into feature/common-tag-input-component-1607

* Styling component

* Using Tag input component in FF Add feature flag modal (#1650)

* Using Tag input component in FF Add feature flag modal

* Made tags as empty array in formbuilder. Removed required attribute from component

---------

Co-authored-by: danoswaltCL <[email protected]>
  • Loading branch information
KD1712 and danoswaltCL authored Jun 18, 2024
1 parent 607014e commit 0978442
Show file tree
Hide file tree
Showing 7 changed files with 152 additions and 36 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,41 +7,39 @@
[primaryActionBtnDisabled$]="isLoadingAddFeatureFlag$"
(primaryActionBtnClicked)="onPrimaryActionBtnClicked()"
>
<form [formGroup]="featureFlagForm">
<mat-form-field appearance="outline">
<mat-label>Name</mat-label>
<input matInput formControlName="name" placeholder="e.g., My feature flag"/>
<mat-hint class="form-hint ft-10-400">{{ "feature-flags.add-flag-modal.name-hint.text" | translate }}</mat-hint>
</mat-form-field>
<form [formGroup]="featureFlagForm">
<mat-form-field appearance="outline">
<mat-label>Name</mat-label>
<input matInput formControlName="name" placeholder="e.g., My feature flag" />
<mat-hint class="form-hint ft-10-400">{{ 'feature-flags.add-flag-modal.name-hint.text' | translate }}</mat-hint>
</mat-form-field>

<mat-form-field appearance="outline">
<mat-label>Key</mat-label>
<input matInput formControlName="key" placeholder="Key for this feature flag"/>
<mat-hint class="form-hint ft-10-400">{{ "feature-flags.add-flag-modal.key-hint.text" | translate }}<a class="learn-more-link" href="https://www.upgradeplatform.org/">Learn more</a></mat-hint>
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Key</mat-label>
<input matInput formControlName="key" placeholder="Key for this feature flag" />
<mat-hint class="form-hint ft-10-400"
>{{ 'feature-flags.add-flag-modal.key-hint.text' | translate
}}<a class="learn-more-link" href="https://www.upgradeplatform.org/">Learn more</a></mat-hint
>
</mat-form-field>

<mat-form-field appearance="outline">
<mat-label>Description (optional)</mat-label>
<input matInput formControlName="description" placeholder="Describe your feature flag"/>
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>Description (optional)</mat-label>
<input matInput formControlName="description" placeholder="Describe your feature flag" />
</mat-form-field>

<mat-form-field appearance="outline">
<mat-label>App Context</mat-label>
<mat-select formControlName="appContext">
<mat-option *ngFor="let context of appContexts$ | async" [value]="context">{{ context }}</mat-option>
</mat-select>
<mat-hint class="form-hint ft-10-400">{{ "feature-flags.add-flag-modal.app-context-hint.text" | translate }}<a class="learn-more-link" href="https://www.upgradeplatform.org/">Learn more</a></mat-hint>
</mat-form-field>
<mat-form-field appearance="outline">
<mat-label>App Context</mat-label>
<mat-select formControlName="appContext">
<mat-option *ngFor="let context of appContexts$ | async" [value]="context">{{ context }}</mat-option>
</mat-select>
<mat-hint class="form-hint ft-10-400"
>{{ 'feature-flags.add-flag-modal.app-context-hint.text' | translate
}}<a class="learn-more-link" href="https://www.upgradeplatform.org/">Learn more</a></mat-hint
>
</mat-form-field>

<!-- TODO: create a story to create a tag input common component, don't want to copy over the logic of the mat-tag-grid from experiment-overview here -->
<mat-form-field appearance="outline">
<mat-label>Tags (optional)</mat-label>
<input
matInput
formControlName="tags"
placeholder="Tags separated by commas"
>
</mat-form-field>
</form>
<app-common-tags-input formControlName="tags"></app-common-tags-input>
</form>
</app-common-dialog>
</div>
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core';
import { CommonModalComponent } from '../../../../../shared-standalone-component-lib/components';
import {
CommonModalComponent,
CommonTagsInputComponent,
} from '../../../../../shared-standalone-component-lib/components';
import {
MAT_DIALOG_DATA,
MatDialog,
Expand Down Expand Up @@ -45,6 +48,7 @@ import { ExperimentService } from '../../../../../core/experiments/experiments.s
MatIcon,
ReactiveFormsModule,
TranslateModule,
CommonTagsInputComponent,
],
templateUrl: './add-feature-flag-modal.component.html',
styleUrl: './add-feature-flag-modal.component.scss',
Expand Down Expand Up @@ -81,7 +85,7 @@ export class AddFeatureFlagModalComponent {
key: ['', Validators.required],
description: [''],
appContext: ['', Validators.required],
tags: [null], // this will need corrected, it should be an array of strings, for now we're hackin
tags: [],
});
}

Expand Down Expand Up @@ -111,7 +115,7 @@ export class AddFeatureFlagModalComponent {
description,
status: FEATURE_FLAG_STATUS.DISABLED,
context: [appContext],
tags: tags?.split(',').map((tag: string) => tag.trim()) ?? [], // this will need corrected, it should be an array of strings, for now we're hackin
tags: tags, // it is now an array of strings
featureFlagSegmentInclusion: {
segment: {
type: SEGMENT_TYPE.PRIVATE,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,4 @@

.confirm-delete {
margin-bottom: 12px;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<mat-form-field appearance="outline" subscriptSizing="dynamic">
<mat-label class="ft-14-400">
{{ 'home.new-experiment.overview.tags.placeHolder' | translate }}
</mat-label>
<mat-chip-grid #tagsList class="chip-grid" aria-label="Tags" formControlName="tags">
<mat-chip-row
*ngFor="let componentTag of tags.value"
[selectable]="isChipSelectable"
[removable]="isChipRemovable"
(removed)="removeChip(componentTag)"
>
<span class="ft-12-600 chip-label">
{{ componentTag }}
</span>
<mat-icon matChipRemove *ngIf="isChipRemovable">cancel</mat-icon>
</mat-chip-row>
<input
class="ft-14-400"
[matChipInputFor]="tagsList"
[matChipInputSeparatorKeyCodes]="separatorKeysCodes"
[matChipInputAddOnBlur]="addChipOnBlur"
(matChipInputTokenEnd)="addChip($event)"
/>
</mat-chip-grid>
</mat-form-field>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mat-form-field {
width: 100%;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
import { Component, forwardRef } from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor, FormControl } from '@angular/forms';
import { MatChipInputEvent } from '@angular/material/chips';
import { ENTER, COMMA } from '@angular/cdk/keycodes';
import { CommonModule } from '@angular/common';
import { MatChipsModule } from '@angular/material/chips';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatIconModule } from '@angular/material/icon';
import { MatInputModule } from '@angular/material/input';
import { TranslateModule } from '@ngx-translate/core';

// This Component is made to manage a list of tags using mat-chips.
// It uses ControlValueAccessor which implements methods to synchronize the component's value with the parent form control.
// writeValue(value: string[]): Sets the component's value.
// registerOnChange(fn: any): Registers a callback for when the value changes.
// registerOnTouched(fn: any): Registers a callback for when the component is touched.

// Example Usage:
// <app-common-tags-input formControlName="tags"></app-common-tags-input>

@Component({
selector: 'app-common-tags-input',
templateUrl: './common-tag-input.component.html',
styleUrls: ['./common-tag-input.component.scss'],
standalone: true,
providers: [
{
provide: NG_VALUE_ACCESSOR,
useExisting: forwardRef(() => CommonTagsInputComponent),
multi: true,
},
],
imports: [CommonModule, MatChipsModule, MatFormFieldModule, MatIconModule, MatInputModule, TranslateModule],
})
export class CommonTagsInputComponent implements ControlValueAccessor {
isChipSelectable = true;
isChipRemovable = true;
addChipOnBlur = true;
readonly separatorKeysCodes: number[] = [ENTER, COMMA];

tags = new FormControl<string[]>([]);

addChip(event: MatChipInputEvent) {
const input = event.chipInput;
const value = (event.value || '').trim().toLowerCase();

// Add chip
if (value) {
const currentTags = this.tags.value || [];
if (!currentTags.includes(value)) {
this.tags.setValue([...currentTags, value]);
this.tags.updateValueAndValidity();
}
}

// Reset the input value
if (input) {
input.clear();
}
}

removeChip(tag: string) {
const currentTags = this.tags.value || [];
const index = currentTags.indexOf(tag);

if (index >= 0) {
currentTags.splice(index, 1);
this.tags.setValue(currentTags);
this.tags.updateValueAndValidity();
}
}

// Implement ControlValueAccessor methods
writeValue(value: string[]) {
this.tags.setValue(value || []);
}

registerOnChange(fn: any) {
this.tags.valueChanges.subscribe(fn);
}

// eslint-disable-next-line @typescript-eslint/no-empty-function
registerOnTouched(fn: any) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { CommonModalComponent } from './common-modal/common-modal.component';
import { CommonStatusIndicatorChipComponent } from './common-status-indicator-chip/common-status-indicator-chip.component';
import { CommonSectionCardTitleHeaderComponent } from './common-section-card-title-header/common-section-card-title-header.component';
import { CommonSectionCardOverviewDetailsComponent } from './common-section-card-overview-details/common-section-card-overview-details.component';
import { CommonTagsInputComponent } from './common-tag-input/common-tag-input.component';

export {
CommonPageComponent,
Expand All @@ -22,4 +23,5 @@ export {
CommonSectionCardOverviewDetailsComponent,
CommonModalComponent,
CommonStatusIndicatorChipComponent,
CommonTagsInputComponent,
};

0 comments on commit 0978442

Please sign in to comment.