]> git.proxmox.com Git - ceph.git/blob - ceph/src/pybind/mgr/dashboard/frontend/src/app/ceph/block/rbd-configuration-form/rbd-configuration-form.component.ts
import 15.2.0 Octopus source
[ceph.git] / ceph / src / pybind / mgr / dashboard / frontend / src / app / ceph / block / rbd-configuration-form / rbd-configuration-form.component.ts
1 import { Component, EventEmitter, Input, OnInit, Output } from '@angular/core';
2 import { FormControl, Validators } from '@angular/forms';
3
4 import { Icons } from '../../../shared/enum/icons.enum';
5 import { CdFormGroup } from '../../../shared/forms/cd-form-group';
6 import {
7 RbdConfigurationEntry,
8 RbdConfigurationSourceField,
9 RbdConfigurationType
10 } from '../../../shared/models/configuration';
11 import { FormatterService } from '../../../shared/services/formatter.service';
12 import { RbdConfigurationService } from '../../../shared/services/rbd-configuration.service';
13
14 @Component({
15 selector: 'cd-rbd-configuration-form',
16 templateUrl: './rbd-configuration-form.component.html',
17 styleUrls: ['./rbd-configuration-form.component.scss']
18 })
19 export class RbdConfigurationFormComponent implements OnInit {
20 @Input()
21 form: CdFormGroup;
22 @Input()
23 initializeData: EventEmitter<{
24 initialData: RbdConfigurationEntry[];
25 sourceType: RbdConfigurationSourceField;
26 }>;
27 @Output()
28 changes = new EventEmitter<any>();
29
30 icons = Icons;
31
32 ngDataReady = new EventEmitter<any>();
33 initialData: RbdConfigurationEntry[];
34 configurationType = RbdConfigurationType;
35 sectionVisibility: { [key: string]: boolean } = {};
36
37 constructor(
38 public formatterService: FormatterService,
39 public rbdConfigurationService: RbdConfigurationService
40 ) {}
41
42 ngOnInit() {
43 const configFormGroup = this.createConfigurationFormGroup();
44 this.form.addControl('configuration', configFormGroup);
45
46 // Listen to changes and emit the values to the parent component
47 configFormGroup.valueChanges.subscribe(() => {
48 this.changes.emit(this.getDirtyValues.bind(this));
49 });
50
51 if (this.initializeData) {
52 this.initializeData.subscribe((data: Record<string, any>) => {
53 this.initialData = data.initialData;
54 const dataType = data.sourceType;
55
56 this.rbdConfigurationService.getWritableOptionFields().forEach((option) => {
57 const optionData = data.initialData
58 .filter((entry: Record<string, any>) => entry.name === option.name)
59 .pop();
60 if (optionData && optionData['source'] === dataType) {
61 this.form.get(`configuration.${option.name}`).setValue(optionData['value']);
62 }
63 });
64 this.ngDataReady.emit();
65 });
66 }
67
68 this.rbdConfigurationService
69 .getWritableSections()
70 .forEach((section) => (this.sectionVisibility[section.class] = false));
71 }
72
73 getDirtyValues(includeLocalValues = false, localFieldType?: RbdConfigurationSourceField) {
74 if (includeLocalValues && !localFieldType) {
75 const msg =
76 'ProgrammingError: If local values shall be included, a proper localFieldType argument has to be provided, too';
77 throw new Error(msg);
78 }
79 const result = {};
80
81 this.rbdConfigurationService.getWritableOptionFields().forEach((config) => {
82 const control: any = this.form.get('configuration').get(config.name);
83 const dirty = control.dirty;
84
85 if (this.initialData && this.initialData[config.name] === control.value) {
86 return; // Skip controls with initial data loaded
87 }
88
89 if (dirty || (includeLocalValues && control['source'] === localFieldType)) {
90 if (control.value === null) {
91 result[config.name] = control.value;
92 } else if (config.type === RbdConfigurationType.bps) {
93 result[config.name] = this.formatterService.toBytes(control.value);
94 } else if (config.type === RbdConfigurationType.milliseconds) {
95 result[config.name] = this.formatterService.toMilliseconds(control.value);
96 } else if (config.type === RbdConfigurationType.iops) {
97 result[config.name] = this.formatterService.toIops(control.value);
98 } else {
99 result[config.name] = control.value;
100 }
101 }
102 });
103
104 return result;
105 }
106
107 /**
108 * Dynamically create form controls.
109 */
110 private createConfigurationFormGroup() {
111 const configFormGroup = new CdFormGroup({});
112
113 this.rbdConfigurationService.getWritableOptionFields().forEach((c) => {
114 let control: FormControl;
115 if (
116 c.type === RbdConfigurationType.milliseconds ||
117 c.type === RbdConfigurationType.iops ||
118 c.type === RbdConfigurationType.bps
119 ) {
120 control = new FormControl(0, Validators.min(0));
121 } else {
122 throw new Error(
123 `Type ${c.type} is unknown, you may need to add it to RbdConfiguration class`
124 );
125 }
126 configFormGroup.addControl(c.name, control);
127 });
128
129 return configFormGroup;
130 }
131
132 /**
133 * Reset the value. The inherited value will be used instead.
134 */
135 reset(optionName: string) {
136 const formControl: any = this.form.get('configuration').get(optionName);
137 if (formControl.disabled) {
138 formControl.setValue(formControl['previousValue'] || 0);
139 formControl.enable();
140 if (!formControl['previousValue']) {
141 formControl.markAsPristine();
142 }
143 } else {
144 formControl['previousValue'] = formControl.value;
145 formControl.setValue(null);
146 formControl.markAsDirty();
147 formControl.disable();
148 }
149 }
150
151 isDisabled(optionName: string) {
152 return this.form.get('configuration').get(optionName).disabled;
153 }
154
155 toggleSectionVisibility(className: string) {
156 this.sectionVisibility[className] = !this.sectionVisibility[className];
157 }
158 }