From f3af36c4ccebb5a8297c573e9a89f250e23d4a9d Mon Sep 17 00:00:00 2001 From: Samuel Liu Date: Mon, 26 Aug 2024 14:18:53 -0400 Subject: [PATCH] Convert settings details tab to use carbon component --- .../components/miq-data-table/index.jsx | 24 ++++--- .../components/settings-details-tab/index.jsx | 72 +++++++++++++++++++ .../packs/component-definitions-common.js | 2 + .../settings-details-tab.spec.js.snap | 17 +++++ .../settings-details-tab.spec.js | 40 +++++++++++ app/stylesheet/settings.scss | 4 ++ app/views/ops/_settings_details_tab.html.haml | 35 ++------- .../settings_details_tab.cy.js | 42 +++++++++++ 8 files changed, 197 insertions(+), 39 deletions(-) create mode 100644 app/javascript/components/settings-details-tab/index.jsx create mode 100644 app/javascript/spec/settings-details-tab/__snapshots__/settings-details-tab.spec.js.snap create mode 100644 app/javascript/spec/settings-details-tab/settings-details-tab.spec.js create mode 100644 cypress/e2e/ui/Settings/Application-Settings/settings_details_tab.cy.js diff --git a/app/javascript/components/miq-data-table/index.jsx b/app/javascript/components/miq-data-table/index.jsx index a9d1332861d..cb2c3af58bd 100644 --- a/app/javascript/components/miq-data-table/index.jsx +++ b/app/javascript/components/miq-data-table/index.jsx @@ -100,9 +100,11 @@ const MiqDataTable = ({ isSortable={isSortable} isSortHeader={sortHeader} sortDirection={sortDirection} - className={ - classNames('miq-data-table-header', (header.contentButton ? 'header-button' : ''), (header.actionCell ? 'action-cell-holder' : '')) - } + className={classNames( + 'miq-data-table-header', + header.contentButton ? 'header-button' : '', + header.actionCell ? 'action-cell-holder' : '' + )} > {headerLabel(header.header)} @@ -148,15 +150,17 @@ const MiqDataTable = ({ stickyHeader={stickyHeader} > {({ - rows, getTableProps, getHeaderProps, getRowProps, getSelectionProps, + rows, headers, getTableProps, getHeaderProps, getRowProps, getSelectionProps, }) => ( - - - {rowCheckBox && selectAll(getSelectionProps)} - {renderHeaders(getHeaderProps)} - - + {headers[0] && headers[0].header !== '' ? ( + + + {rowCheckBox && selectAll(getSelectionProps)} + {renderHeaders(getHeaderProps)} + + + ) : undefined} {sortableRows(rows).map((row, index) => { const item = propRows[index]; diff --git a/app/javascript/components/settings-details-tab/index.jsx b/app/javascript/components/settings-details-tab/index.jsx new file mode 100644 index 00000000000..15d0f3f5cba --- /dev/null +++ b/app/javascript/components/settings-details-tab/index.jsx @@ -0,0 +1,72 @@ +import React, { useState } from 'react'; +import MiqDataTable from '../miq-data-table'; +import RegionForm from '../region-form'; + +const settingsDetailsTab = ({ + region, scanItemsCount, zonesCount, miqSchedulesCount, +}) => { + const [rows, setRows] = useState([ + { + id: '0', + region: { + text: `${region.description} [${region.region}]`, + icon: 'carbon--Db2Database', + }, + treeBox: 'settings_tree', + }, + { + id: '1', + region: { + text: `${__('Analysis Profiles')} (${scanItemsCount})`, + icon: 'carbon--Search', + }, + treeBox: 'settings_tree', + nodeKey: 'xx-sis', + }, + { + id: '2', + region: { + text: `${__('Zones')} (${zonesCount})`, + icon: 'carbon--ChartVennDiagram', + }, + treeBox: 'settings_tree', + nodeKey: 'xx-z', + }, + { + id: '3', + region: { + text: `${__('Schedules')} (${miqSchedulesCount})`, + icon: 'carbon--Time', + }, + treeBox: 'settings_tree', + nodeKey: 'xx-msc', + }, + ]); + + const headers = [ + { + key: 'region', + header: '', + }, + ]; + + const onSelect = (selectedRow) => { + const selected = rows.find((row) => row.id === selectedRow.id); + if (selected.nodeKey) { + miqTreeActivateNode(selected.treeBox, selected.nodeKey); + } else { + setRows((prevRows) => prevRows.filter((row) => row.id !== '0')); + } + }; + + return ( +
+ {rows.find((row) => row.id === '0') === undefined && ( + + )} + onSelect(selectedRow)} /> +
+ ); +}; + +export default settingsDetailsTab; diff --git a/app/javascript/packs/component-definitions-common.js b/app/javascript/packs/component-definitions-common.js index f56709a0b77..a196a68e5cd 100644 --- a/app/javascript/packs/component-definitions-common.js +++ b/app/javascript/packs/component-definitions-common.js @@ -134,6 +134,7 @@ import SettingsCategoryForm from '../components/settings-category-form'; import SettingsCompanyCategories from '../components/settings-company-categories'; import SettingsCompanyTags from '../components/settings-company-tags'; import SettingsCompanyTagsEntryForm from '../components/settings-company-tags-entry-form'; +import SettingsDetailsTab from '../components/settings-details-tab'; import SettingsLabelTagMapping from '../components/settings-label-tag-mapping'; import SettingsTasksForm from '../components/settings-tasks-form'; import SettingsTimeProfileForm from '../components/settings-time-profile-form'; @@ -315,6 +316,7 @@ ManageIQ.component.addReact('SettingsCategoryForm', SettingsCategoryForm); ManageIQ.component.addReact('SettingsCompanyCategories', SettingsCompanyCategories); ManageIQ.component.addReact('SettingsCompanyTags', SettingsCompanyTags); ManageIQ.component.addReact('SettingsCompanyTagsEntryForm', SettingsCompanyTagsEntryForm); +ManageIQ.component.addReact('SettingsDetailsTab', SettingsDetailsTab); ManageIQ.component.addReact('SettingsLabelTagMapping', SettingsLabelTagMapping); ManageIQ.component.addReact('SettingsTasksForm', SettingsTasksForm); ManageIQ.component.addReact('SettingsTimeProfileForm', SettingsTimeProfileForm); diff --git a/app/javascript/spec/settings-details-tab/__snapshots__/settings-details-tab.spec.js.snap b/app/javascript/spec/settings-details-tab/__snapshots__/settings-details-tab.spec.js.snap new file mode 100644 index 00000000000..e9b53ac45e4 --- /dev/null +++ b/app/javascript/spec/settings-details-tab/__snapshots__/settings-details-tab.spec.js.snap @@ -0,0 +1,17 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`SettingsDetailsTab Component should render settings details tab 1`] = ` + +`; diff --git a/app/javascript/spec/settings-details-tab/settings-details-tab.spec.js b/app/javascript/spec/settings-details-tab/settings-details-tab.spec.js new file mode 100644 index 00000000000..a9771d0be75 --- /dev/null +++ b/app/javascript/spec/settings-details-tab/settings-details-tab.spec.js @@ -0,0 +1,40 @@ +import React from 'react'; +import fetchMock from 'fetch-mock'; +import { shallow } from 'enzyme'; +import toJson from 'enzyme-to-json'; +import settingsDetailsTab from '../../components/settings-details-tab'; + +describe('SettingsDetailsTab Component', () => { + const region = { + id: 1, + region: 0, + description: 'Region 3', + maintenance_zone_id: 1, + }; + + const scanItemsCount = 3; + const zonesCount = 1; + const miqSchedulesCount = 0; + + afterEach(() => { + fetchMock.reset(); + fetchMock.restore(); + }); + + it('should render settings details tab', async() => { + const wrapper = shallow(); + + await new Promise((resolve) => { + setImmediate(() => { + wrapper.update(); + expect(toJson(wrapper)).toMatchSnapshot(); + resolve(); + }); + }); + }); +}); diff --git a/app/stylesheet/settings.scss b/app/stylesheet/settings.scss index 36dcfeadbab..d55ecf4e42a 100644 --- a/app/stylesheet/settings.scss +++ b/app/stylesheet/settings.scss @@ -45,3 +45,7 @@ color: red; } } + +.bx--front-line { + margin-left: 10px; +} diff --git a/app/views/ops/_settings_details_tab.html.haml b/app/views/ops/_settings_details_tab.html.haml index a32d1a740c1..d607edca29d 100644 --- a/app/views/ops/_settings_details_tab.html.haml +++ b/app/views/ops/_settings_details_tab.html.haml @@ -7,32 +7,9 @@ %table.table.table-striped.table-bordered.table-hover %tbody - - unless @edit - %tr - %td.table-view-pf-select{:onclick => remote_function(:url => {:action => 'region_edit', :id => region.id}, - :loading => "miqSparkle(true);"), - :title => _("Edit this Region")} - %i.pficon.pficon-regions - %td{:onclick => remote_function(:url => {:action => 'region_edit', :id => region.id}, - :loading => "miqSparkle(true);"), - :title => _("Edit this Region")} - = h(region.description) - [#{h(region.region)}] - %tr - %td.table-view-pf-select{:onclick => "miqTreeActivateNode('settings_tree', 'xx-sis');", :title => _("View Analysis Profiles")} - %i.fa.fa-search - %td{:onclick => "miqTreeActivateNode('settings_tree', 'xx-sis');", :title => _("View Analysis Profiles")} - = _("Analysis Profiles") - (#{h(@scan_items.size)}) - %tr - %td.table-view-pf-select{:onclick => "miqTreeActivateNode('settings_tree', 'xx-z');", :title => _("View Zones")} - %i.pficon.pficon-zone - %td{:onclick => "miqTreeActivateNode('settings_tree', 'xx-z');", :title => _("View Zones")} - = _("Zones") - (#{h(@zones.size)}) - %tr - %td.table-view-pf-select{:onclick => "miqTreeActivateNode('settings_tree', 'xx-msc');", :title => _("View Schedules")} - %i.fa.fa-clock-o - %td{:onclick => "miqTreeActivateNode('settings_tree', 'xx-msc');", :title => _("View Schedules")} - = _("Schedules") - (#{h(@miq_schedules.size)}) + = react('SettingsDetailsTab', + :region => region, + :scanItemsCount => @scan_items.size, + :zonesCount => @zones.size, + :miqSchedulesCount => @miq_schedules.size) + \ No newline at end of file diff --git a/cypress/e2e/ui/Settings/Application-Settings/settings_details_tab.cy.js b/cypress/e2e/ui/Settings/Application-Settings/settings_details_tab.cy.js new file mode 100644 index 00000000000..1d6a0b2e116 --- /dev/null +++ b/cypress/e2e/ui/Settings/Application-Settings/settings_details_tab.cy.js @@ -0,0 +1,42 @@ +/* eslint-disable no-undef */ + +describe('Settings > Application Settings > Details', () => { + beforeEach(() => { + cy.login(); + cy.intercept('POST', '/ops/accordion_select?id=rbac_accord').as('accordion'); + cy.menu('Settings', 'Application Settings'); + cy.get('[data-nodeid="0.0"].node-treeview-settings_tree').contains('ManageIQ Region').click(); + cy.get('#explorer_title_text'); + }); + + describe('Settings Details Tab', () => { + it('Region row is replaced by region form when clicked', () => { + cy.get('.bx--front-line').contains('Region 0').click({force: true}); + cy.get('.bx--label').contains('Description').should('exist'); + }); + it('Clicks on analysis profiles row and reroutes', () => { + cy.get('.bx--front-line').contains('Analysis Profiles').click({force: true}); + cy.get('#explorer_title_text').contains('Settings Analysis Profiles').should('exist'); + }); + it('Clicks on zones row and reroutes', () => { + cy.get('.bx--front-line').contains('Zones').click({force: true}); + cy.get('#explorer_title_text').contains('Settings Zones').should('exist'); + }); + it('Clicks on schedules row and reroutes', () => { + cy.get('.bx--front-line').contains('Schedules').click({force: true}); + cy.get('#explorer_title_text').contains('Settings Schedules').should('exist'); + }); + it('Updates region name when changed', () => { + cy.get('.bx--front-line').contains('Region 0').click({force: true}); + cy.get('#description').clear().type('Region 1'); + cy.get('button.bx--btn.bx--btn--primary').contains('Save').should('not.be.disabled').click(); + cy.get('.bx--front-line').contains('Region 1').should('exist'); + + // Clean up + cy.get('.bx--front-line').contains('Region 1').click({force: true}); + cy.get('#description').clear().type('Region 0'); + cy.get('button.bx--btn.bx--btn--primary').contains('Save').should('not.be.disabled').click(); + cy.get('.bx--front-line').contains('Region 0').should('exist'); + }); + }); +});