1 import { Component, Inject, OnInit, Optional, ChangeDetectorRef } from '@angular/core';
8 } from '@angular/forms';
9 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
10 import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
11 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
12 import { CdForm } from '~/app/shared/forms/cd-form';
13 import { ComboBoxItem } from '~/app/shared/models/combo-box.model';
14 import { Topic } from '~/app/shared/models/topic.model';
15 import { Bucket } from '../models/rgw-bucket';
16 import { RgwBucketService } from '~/app/shared/api/rgw-bucket.service';
17 import { NotificationService } from '~/app/shared/services/notification.service';
18 import { Router } from '@angular/router';
19 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
20 import { RgwTopicService } from '~/app/shared/api/rgw-topic.service';
26 s3MetadataFilterTexts,
29 } from '~/app/shared/models/notification-configuration.model';
32 selector: 'cd-rgw-notification-form',
33 templateUrl: './rgw-notification-form.component.html',
34 styleUrls: ['./rgw-notification-form.component.scss']
36 export class RgwNotificationFormComponent extends CdForm implements OnInit {
37 notificationForm: CdFormGroup;
38 eventOption: ComboBoxItem[] = events;
39 s3KeyFilterValue: string[] = [];
40 topics: Partial<Topic[]> = [];
41 topicArn: string[] = [];
42 notification_id: string;
43 notificationList: TopicConfiguration[] = [];
44 filterTypes: string[] = ['s3Key', 's3Metadata', 's3Tags'];
45 typeLabels: Record<string, string> = {
46 s3Key: 'S3 Key configuration',
47 s3Metadata: 'S3 Metadata configuration',
48 s3Tags: 'S3 Tags configuration'
51 filterSettings: Record<
54 options: string[] | null;
56 namePlaceholder: string;
57 valuePlaceholder: string;
65 namePlaceholder: s3KeyFilterTexts.namePlaceholder,
66 valuePlaceholder: s3KeyFilterTexts.valuePlaceholder,
67 nameHelper: s3KeyFilterTexts.nameHelper,
68 valueHelper: s3KeyFilterTexts.valueHelper
73 namePlaceholder: s3MetadataFilterTexts.namePlaceholder,
74 valuePlaceholder: s3MetadataFilterTexts.valuePlaceholder,
75 nameHelper: s3MetadataFilterTexts.nameHelper,
76 valueHelper: s3MetadataFilterTexts.valueHelper
81 namePlaceholder: s3TagsFilterTexts.namePlaceholder,
82 valuePlaceholder: s3TagsFilterTexts.valuePlaceholder,
83 nameHelper: s3TagsFilterTexts.nameHelper,
84 valueHelper: s3TagsFilterTexts.valueHelper
88 get filterControls(): Record<string, FormArray> {
89 const controls: Record<string, FormArray> = {};
90 this.filterTypes.forEach((type) => {
91 controls[type] = this.getFormArray(type);
97 @Inject('bucket') public bucket: Bucket,
98 @Optional() @Inject('selectedNotification') public selectedNotification: TopicConfiguration,
99 @Optional() @Inject('editing') public editing = false,
100 public actionLabels: ActionLabelsI18n,
101 private rgwBucketService: RgwBucketService,
102 private rgwTopicService: RgwTopicService,
103 private notificationService: NotificationService,
104 private fb: CdFormBuilder,
105 private router: Router,
106 private cdRef: ChangeDetectorRef
112 this.editing = !!this.selectedNotification;
113 this.s3KeyFilterValue = Object.values(s3KeyFilter);
114 this.filterSettings.s3Key.options = this.s3KeyFilterValue;
115 this.createNotificationForm();
116 this.rgwBucketService.listNotification(this.bucket.bucket).subscribe({
117 next: (notificationList: TopicConfiguration[]) => {
118 this.notificationList = notificationList;
120 this.getTopicName().then(() => {
121 if (this.editing && this.selectedNotification) {
122 this.notification_id = this.selectedNotification.Id;
123 this.notificationForm.get('id').disable();
124 this.patchNotificationForm(this.selectedNotification);
131 getTopicName(): Promise<void> {
132 return new Promise((resolve, reject) => {
133 this.rgwTopicService.listTopic().subscribe({
134 next: (topics: Topic[]) => {
135 this.topics = topics;
136 this.topicArn = topics.map((topic: Topic) => topic.arn);
139 error: (err) => reject(err)
144 patchNotificationForm(config: any): void {
145 this.cdRef.detectChanges();
146 this.notificationForm.patchValue({
148 topic: typeof config.Topic === 'object' ? config.Topic.arn : config.Topic,
152 this.setFilterRules('s3Key', config.Filter?.S3Key?.FilterRule);
153 this.setFilterRules('s3Metadata', config.Filter?.S3Metadata?.FilterRule);
154 this.setFilterRules('s3Tags', config.Filter?.S3Tags?.FilterRule);
157 setFilterRules(type: string, rules: FilterRules[] = []): void {
158 let formArray = this.getFormArray(type);
160 const filterGroup = this.notificationForm.get('filter') as FormGroup;
161 filterGroup.setControl(type, this.fb.array([]));
162 formArray = this.getFormArray(type);
167 if (!rules || rules.length === 0) {
168 formArray.push(this.createNameValueGroup());
172 rules.forEach((rule) => {
173 formArray.push(this.fb.group({ Name: [rule.Name], Value: [rule.Value] }));
177 createNotificationForm() {
178 this.notificationForm = this.fb.group({
179 id: [null, [Validators.required, this.duplicateNotificationId.bind(this)]],
180 topic: [null, [Validators.required]],
182 filter: this.fb.group({
183 s3Key: this.fb.array([this.createNameValueGroup()]),
184 s3Metadata: this.fb.array([this.createNameValueGroup()]),
185 s3Tags: this.fb.array([this.createNameValueGroup()])
190 duplicateNotificationId(control: AbstractControl): ValidationErrors | null {
191 const currentId = control.value?.trim();
192 if (!currentId) return null;
193 if (Array.isArray(this.notificationList)) {
194 const duplicateFound = this.notificationList.some(
195 (notification: TopicConfiguration) => notification.Id === currentId
198 return duplicateFound ? { duplicate: true } : null;
204 private createNameValueGroup(): CdFormGroup {
205 return this.fb.group({
211 getFormArray(arrayName: string): FormArray {
212 const filterGroup = this.notificationForm.get('filter') as FormGroup;
213 return filterGroup?.get(arrayName) as FormArray;
216 getFiltersControls(type: string): FormArray {
217 return this.getFormArray(type);
220 addRow(arrayName: string, index: number): void {
221 const array = this.getFormArray(arrayName);
222 array.insert(index + 1, this.createNameValueGroup());
225 removeRow(arrayName: string, index: number): void {
226 const formArray = this.getFormArray(arrayName);
227 if (formArray && formArray.length > 1 && index >= 0 && index < formArray.length) {
228 formArray.removeAt(index);
229 } else if (formArray.length === 1) {
230 const group = formArray.at(0) as FormGroup;
234 this.cdRef.detectChanges();
237 showInvalid(field: string): boolean {
238 const control: AbstractControl | null = this.notificationForm.get(field);
239 return control?.invalid && (control.dirty || control.touched);
243 if (!this.notificationForm.valid) {
244 this.notificationForm.markAllAsTouched();
245 this.notificationForm.setErrors({ cdSubmitButton: true });
249 const formValue = this.notificationForm.getRawValue();
250 const buildRules = (rules: FilterRules[]) => {
251 const seen = new Set<string>();
254 ?.filter((item) => item.Name && item.Value)
256 if (seen.has(item.Name)) return false;
263 const successMessage = this.editing
264 ? $localize`Bucket notification updated successfully`
265 : $localize`Bucket notification created successfully`;
267 const notificationConfiguration = {
268 TopicConfiguration: {
270 Topic: formValue.topic,
271 Event: formValue.event,
274 FilterRules: buildRules(formValue.filter?.s3Key)
277 FilterRules: buildRules(formValue.filter?.s3Metadata)
280 FilterRules: buildRules(formValue.filter?.s3Tags)
286 this.rgwBucketService
289 JSON.stringify(notificationConfiguration),
294 this.notificationService.show(NotificationType.success, successMessage);
296 error: (error: any) => {
297 this.notificationService.show(NotificationType.error, error.message);
298 this.notificationForm.setErrors({ cdSubmitButton: true });
306 goToCreateNotification() {
307 this.router.navigate(['rgw/notification/create']);