From: Abhishek Desai Date: Sun, 24 May 2026 18:49:39 +0000 (+0530) Subject: mgr/dashboard : Carbonize configuration form X-Git-Url: http://git-server-git.apps.pok.os.sepia.ceph.com/?a=commitdiff_plain;h=1262deedb2d5c796eecf5ba3ae7f6204b0be09a6;p=ceph.git mgr/dashboard : Carbonize configuration form fixes : https://tracker.ceph.com/issues/76778 Signed-off-by: Abhishek Desai --- diff --git a/src/pybind/mgr/dashboard/controllers/cluster_configuration.py b/src/pybind/mgr/dashboard/controllers/cluster_configuration.py index eeda4289eb8..6a9c278579b 100644 --- a/src/pybind/mgr/dashboard/controllers/cluster_configuration.py +++ b/src/pybind/mgr/dashboard/controllers/cluster_configuration.py @@ -54,7 +54,7 @@ class ClusterConfiguration(RESTController): module_options = cephadm_module_config.get('module_options', {}) for option_name, opt in module_options.items(): - current_value = mgr.get_module_option_ex( + mgr_value = mgr.get_module_option_ex( 'cephadm', option_name, opt.get('default_value')) option = dict(opt) @@ -64,11 +64,19 @@ class ClusterConfiguration(RESTController): option['enum_values'] = option.pop('enum_allowed', []) option['services'] = ['mgr'] option['can_update_at_runtime'] = True - option['value'] = [{'section': 'mgr', 'value': current_value}] + option['value'] = [] option['source'] = 'mgr_module' + option['_mgr_value'] = mgr_value cephadm_options.append(option) + self._append_config_option_values(cephadm_options) + + for option in cephadm_options: + mgr_value = option.pop('_mgr_value') + if not any(v['section'] == 'mgr' for v in option.get('value', [])): + option['value'].append({'section': 'mgr', 'value': mgr_value}) + return cephadm_options def _append_config_option_values(self, options): diff --git a/src/pybind/mgr/dashboard/frontend/cypress/e2e/cluster/configuration.po.ts b/src/pybind/mgr/dashboard/frontend/cypress/e2e/cluster/configuration.po.ts index 920d118be87..6c2b4496528 100644 --- a/src/pybind/mgr/dashboard/frontend/cypress/e2e/cluster/configuration.po.ts +++ b/src/pybind/mgr/dashboard/frontend/cypress/e2e/cluster/configuration.po.ts @@ -5,6 +5,14 @@ export class ConfigurationPageHelper extends PageHelper { index: { url: '#/configuration', id: 'cd-configuration' } }; + private waitForEditForm(name: string) { + cy.contains('h3', `Edit ${name}`).should('be.visible'); + } + + private getSectionInput(section: string) { + return cy.get(`input#${section}`); + } + /** * Clears out all the values in a config to reset before and after testing * Does not work for configs with checkbox only, possible future PR @@ -14,16 +22,16 @@ export class ConfigurationPageHelper extends PageHelper { const valList = ['global', 'mon', 'mgr', 'osd', 'mds', 'client']; // Editable values this.getFirstTableCell(name).click(); cy.contains('button', 'Edit').click(); - // Waits for the data to load - cy.contains('.card-header', `Edit ${name}`); + this.waitForEditForm(name); for (const i of valList) { - cy.get(`#${i}`).clear(); + this.getSectionInput(i).clear({ force: true }).blur({ force: true }); } // Clicks save button and checks that values are not present for the selected config cy.get('[data-testid=submitBtn]').click(); - cy.wait(3 * 1000); + cy.url().should('include', '#/configuration'); + cy.get(this.pages.index.id); this.clearFilter(); @@ -54,18 +62,18 @@ export class ConfigurationPageHelper extends PageHelper { this.getFirstTableCell(name).click(); cy.contains('button', 'Edit').click(); - // Waits for data to load - cy.contains('.card-header', `Edit ${name}`); + this.waitForEditForm(name); values.forEach((valtuple) => { // Finds desired value based off given list - cy.get(`#${valtuple[0]}`).type(valtuple[1]); // of values and inserts the given number for the value + this.getSectionInput(valtuple[0]).type(valtuple[1]); }); // Clicks save button then waits until the desired config is visible, clicks it, // then checks that each desired value appears with the desired number cy.get('[data-testid=submitBtn]').click(); - cy.wait(3 * 1000); + cy.url().should('include', '#/configuration'); + cy.get(this.pages.index.id); // Enter config setting name into filter box this.searchTable(name, 100); diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.html b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.html index 13080dd7b2e..4c802c8fd07 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.html +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.html @@ -1,164 +1,269 @@ -
-
-
-
- Edit {{ configForm.getValue('name') }} -
- -
- -
- -
- -
+ + +
+
+
+

Edit {{ configForm.getValue('name') }}

- -
- -
- -
+ +
+ + Name + +
-
- -
- -
+ @if (response?.long_desc) { +
+ +

{{ response.long_desc }}

+ } -
- -
- -
+ @if (configForm.getValue('default') !== '') { +
+ + Default + +
+ } -
- -
- -
+ @if (configForm.getValue('daemon_default') !== '') { +
+ + Daemon default + +
+ } -
- -
- - - {{ service }} - - + @if (configForm.getValue('services')?.length > 0) { +
+
+ +
+
+ @for (service of configForm.getValue('services'); track service) { + + {{ service }} + + }
+ }
-

Values

- -
- -
- -
+
+

Values

+
+ + @for (section of availSections; track section) { + @if (type === 'bool') { +
+ + + + + + + + +
+ } + + @if (type !== 'bool' && inputType === 'number') { +
+ + + + +
+ } -
- -
- - - {{ patternHelpText }} - - - {{ patternHelpText }} - - The entered value is too high! It must not be greater than {{ maxValue }}. - The entered value is too low! It must not be lower than {{ minValue }}. -
+ @if (type !== 'bool' && inputType !== 'number') { +
+ + {{ section }} + + + + +
- + } + } +
+ +
+
-
- -
-
+ + + @if (control?.invalid && (control.dirty || control.touched)) { + @if (control.hasError('min')) { + The entered value is too low! It must not be lower than {{ minValue }}. + } + @if (control.hasError('max')) { + The entered value is too high! It must not be greater than {{ maxValue }}. + } + @if (control.hasError('pattern') || control.hasError('invalidUuid')) { + {{ patternHelpText }} + } + } + diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.scss b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.scss index ed2945d1d56..e69de29bb2d 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.scss +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.scss @@ -1,12 +0,0 @@ -.form-component-badge { - display: block; - height: 34px; - - span { - margin-top: 7px; - } -} - -.resize-vertical { - resize: vertical; -} diff --git a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.ts b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.ts index f4a0557795a..c98f93dc93b 100644 --- a/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.ts +++ b/src/pybind/mgr/dashboard/frontend/src/app/ceph/cluster/configuration/configuration-form/configuration-form.component.ts @@ -141,8 +141,12 @@ export class ConfigurationFormComponent extends CdForm implements OnInit { this.availSections.forEach((section) => { const sectionValue = this.configForm.getValue(section); - if (sectionValue !== null) { + const hadValue = this.response?.value?.some((v) => v.section === section); + + if (sectionValue !== null && sectionValue !== undefined && sectionValue !== '') { values.push({ section: section, value: sectionValue }); + } else if (hadValue) { + values.push({ section: section, value: '' }); } }); @@ -188,8 +192,8 @@ export class ConfigurationFormComponent extends CdForm implements OnInit { this.configForm.setErrors({ cdSubmitButton: true }); } ); + } else { + this.router.navigate(['/configuration']); } - - this.router.navigate(['/configuration']); } }