1 import { ChangeDetectorRef, Component, Inject, OnInit, Optional } from '@angular/core';
9 } from '@angular/forms';
10 import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
11 import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
12 import { CdValidators } from '~/app/shared/forms/cd-validators';
13 import { Bucket } from '../models/rgw-bucket';
14 import { RgwBucketService } from '~/app/shared/api/rgw-bucket.service';
15 import { NotificationService } from '~/app/shared/services/notification.service';
16 import { NotificationType } from '~/app/shared/enum/notification-type.enum';
17 import { RgwZonegroupService } from '~/app/shared/api/rgw-zonegroup.service';
18 import { BucketTieringUtils } from '../utils/rgw-bucket-tiering';
19 import { StorageClass, ZoneGroupDetails } from '../models/rgw-storage-class.model';
20 import { CdForm } from '~/app/shared/forms/cd-form';
21 import { Router } from '@angular/router';
22 import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
23 import { Lifecycle, Rule, Tag } from '../models/rgw-bucket-lifecycle';
25 export interface Tags {
31 selector: 'cd-rgw-bucket-tiering',
32 templateUrl: './rgw-bucket-tiering-form.component.html',
33 styleUrls: ['./rgw-bucket-tiering-form.component.scss']
35 export class RgwBucketTieringFormComponent extends CdForm implements OnInit {
36 tieringForm: CdFormGroup;
37 tagsToRemove: Tags[] = [];
38 storageClassList: StorageClass[] = null;
39 configuredLifecycle: Lifecycle;
40 isStorageClassFetched = false;
43 @Inject('bucket') public bucket: Bucket,
44 @Optional() @Inject('selectedLifecycle') public selectedLifecycle: Rule,
45 @Optional() @Inject('editing') public editing = false,
46 public actionLabels: ActionLabelsI18n,
47 private rgwBucketService: RgwBucketService,
48 private fb: CdFormBuilder,
49 private cd: ChangeDetectorRef,
50 private rgwZonegroupService: RgwZonegroupService,
51 private notificationService: NotificationService,
52 private router: Router
59 .getLifecycle(this.bucket.bucket, this.bucket.owner, this.bucket.tenant)
60 .subscribe((lifecycle: Lifecycle) => {
61 if (lifecycle === null) {
62 lifecycle = { LifecycleConfiguration: { Rule: [] } };
64 lifecycle.LifecycleConfiguration.Rule = lifecycle.LifecycleConfiguration.Rule.map(
66 if (rule?.['Filter']?.['Tag'] && !Array.isArray(rule?.['Filter']?.['Tag'])) {
67 rule['Filter']['Tag'] = [rule['Filter']['Tag']];
70 rule?.['Filter']?.['And']?.['Tag'] &&
71 !Array.isArray(rule?.['Filter']?.['And']?.['Tag'])
73 rule['Filter']['And']['Tag'] = [rule['Filter']['And']['Tag']];
78 this.configuredLifecycle = lifecycle;
80 const ruleToEdit = this.configuredLifecycle?.['LifecycleConfiguration']?.['Rule'].filter(
81 (rule: Rule) => rule?.['ID'] === this.selectedLifecycle?.['ID']
83 this.tieringForm.patchValue({
84 name: ruleToEdit?.['ID'],
85 hasPrefix: this.checkIfRuleHasFilters(ruleToEdit),
87 ruleToEdit?.['Prefix'] ||
88 ruleToEdit?.['Filter']?.['Prefix'] ||
89 ruleToEdit?.['Filter']?.['And']?.['Prefix'] ||
91 status: ruleToEdit?.['Status'],
92 days: ruleToEdit?.['Transition']?.['Days']
94 this.setTags(ruleToEdit);
95 this.tieringForm.get('name').disable();
98 this.tieringForm = this.fb.group({
99 name: [null, [Validators.required, this.duplicateConfigName.bind(this)]],
100 storageClass: [null, Validators.required],
101 hasPrefix: [false, [Validators.required]],
102 prefix: [null, [CdValidators.composeIf({ hasPrefix: true }, [Validators.required])]],
103 tags: this.fb.array([]),
104 status: ['Enabled', [Validators.required]],
105 days: [60, [Validators.required, CdValidators.number(false)]]
107 this.loadStorageClass();
110 checkIfRuleHasFilters(rule: Rule) {
112 this.isValidPrefix(rule?.['Prefix']) ||
113 this.isValidPrefix(rule?.['Filter']?.['Prefix']) ||
114 this.isValidArray(rule?.['Filter']?.['Tag']) ||
115 this.isValidPrefix(rule?.['Filter']?.['And']?.['Prefix']) ||
116 this.isValidArray(rule?.['Filter']?.['And']?.['Tag'])
123 isValidPrefix(value: string) {
127 isValidArray(value: Tag | Tag[]) {
128 return Array.isArray(value) && value.length > 0;
131 setTags(rule: Rule) {
132 if (Array.isArray(rule?.Filter?.Tag) && rule?.Filter?.Tag?.length > 0) {
133 rule?.['Filter']?.['Tag']?.forEach((tag: { Key: string; Value: string }) =>
134 this.addTags(tag.Key, tag.Value)
137 if (Array.isArray(rule?.Filter?.And?.Tag) && rule?.Filter?.And?.Tag?.length > 0) {
138 rule?.['Filter']?.['And']?.['Tag']?.forEach((tag: { Key: string; Value: string }) =>
139 this.addTags(tag.Key, tag.Value)
145 return this.tieringForm.get('tags') as FormArray;
148 addTags(key?: string, value?: string) {
151 Key: new FormControl(key || '', Validators.required),
152 Value: new FormControl(value || '', Validators.required)
155 this.cd.detectChanges();
158 duplicateConfigName(control: AbstractControl): ValidationErrors | null {
159 if (this.configuredLifecycle?.LifecycleConfiguration?.Rule?.length > 0) {
160 const ruleIds = this.configuredLifecycle.LifecycleConfiguration.Rule.map(
161 (rule: Rule) => rule.ID
163 return ruleIds.includes(control.value) ? { duplicate: true } : null;
168 removeTags(idx: number) {
169 this.tags.removeAt(idx);
170 this.cd.detectChanges();
173 loadStorageClass(): Promise<void> {
174 return new Promise((resolve, reject) => {
175 this.rgwZonegroupService.getAllZonegroupsInfo().subscribe(
176 (data: ZoneGroupDetails) => {
177 this.storageClassList = [];
178 const tierObj = BucketTieringUtils.filterAndMapTierTargets(data);
179 this.isStorageClassFetched = true;
180 this.storageClassList.push(...tierObj);
184 .setValue(this.selectedLifecycle?.['Transition']?.['StorageClass']);
196 submitTieringConfig() {
197 const formValue = this.tieringForm.value;
198 if (!this.tieringForm.valid) {
202 let lifecycle: Rule = {
203 ID: this.tieringForm.getRawValue().name,
204 Status: formValue.status,
206 Days: formValue.days,
207 StorageClass: formValue.storageClass
210 if (formValue.hasPrefix) {
211 if (this.tags.length > 0) {
212 Object.assign(lifecycle, {
215 Prefix: formValue.prefix,
221 Object.assign(lifecycle, {
223 Prefix: formValue.prefix
228 Object.assign(lifecycle, {
233 this.configuredLifecycle.LifecycleConfiguration.Rule.push(lifecycle);
234 this.rgwBucketService
237 JSON.stringify(this.configuredLifecycle.LifecycleConfiguration),
243 this.notificationService.show(
244 NotificationType.success,
245 $localize`Bucket lifecycle created succesfully`
248 error: (error: any) => {
249 this.notificationService.show(NotificationType.error, error);
250 this.tieringForm.setErrors({ cdSubmitButton: true });
257 const rules = this.configuredLifecycle.LifecycleConfiguration.Rule;
258 const index = rules.findIndex(
259 (rule: Rule) => rule?.['ID'] === this.selectedLifecycle?.['ID']
261 rules.splice(index, 1, lifecycle);
262 this.rgwBucketService
265 JSON.stringify(this.configuredLifecycle.LifecycleConfiguration),
271 this.notificationService.show(
272 NotificationType.success,
273 $localize`Bucket lifecycle modified succesfully`
276 error: (error: any) => {
277 this.notificationService.show(NotificationType.error, error);
278 this.tieringForm.setErrors({ cdSubmitButton: true });
287 goToCreateStorageClass() {
288 this.router.navigate(['rgw/tiering/create']);