diff --git a/src/cockpit/389-console/src/lib/database/databaseTables.jsx b/src/cockpit/389-console/src/lib/database/databaseTables.jsx index 8e7b1c9ecf..3f3bfe6ec3 100644 --- a/src/cockpit/389-console/src/lib/database/databaseTables.jsx +++ b/src/cockpit/389-console/src/lib/database/databaseTables.jsx @@ -8,6 +8,7 @@ import { SearchInput, } from '@patternfly/react-core'; import { + Table, Thead, Tr, Th, @@ -17,9 +18,6 @@ import { ExpandableRowContent, SortByDirection } from '@patternfly/react-table'; -import { - Table -} from '@patternfly/react-table/deprecated'; import { TrashAltIcon } from '@patternfly/react-icons/dist/js/icons/trash-alt-icon'; import { ArrowRightIcon } from '@patternfly/react-icons/dist/js/icons/arrow-right-icon'; import PropTypes from "prop-types"; diff --git a/src/cockpit/389-console/src/lib/plugins/managedEntries.jsx b/src/cockpit/389-console/src/lib/plugins/managedEntries.jsx index 8c3e3b3e66..a62c2de1c0 100644 --- a/src/cockpit/389-console/src/lib/plugins/managedEntries.jsx +++ b/src/cockpit/389-console/src/lib/plugins/managedEntries.jsx @@ -29,6 +29,9 @@ import { SelectOption, SelectVariant } from '@patternfly/react-core/deprecated'; +import { + ExclamationCircleIcon, +} from '@patternfly/react-icons'; import { ManagedDefinitionTable, ManagedTemplateTable } from "./pluginTables.jsx"; import PluginBasicConfig from "./pluginBasicConfig.jsx"; diff --git a/src/cockpit/389-console/src/lib/plugins/pluginTables.jsx b/src/cockpit/389-console/src/lib/plugins/pluginTables.jsx index 3307fa5bda..ad2b18e6d5 100644 --- a/src/cockpit/389-console/src/lib/plugins/pluginTables.jsx +++ b/src/cockpit/389-console/src/lib/plugins/pluginTables.jsx @@ -4,21 +4,20 @@ import { Grid, GridItem, Pagination, - PaginationVariant, SearchInput, Switch, } from "@patternfly/react-core"; import { - expandable, - TableVariant, - sortable, - SortByDirection + Table, + Thead, + Tr, + Th, + Tbody, + Td, + ExpandableRowContent, + ActionsColumn, + SortByDirection } from '@patternfly/react-table'; -import { - Table, - TableHeader, - TableBody -} from '@patternfly/react-table/deprecated'; import PropTypes from "prop-types"; const _ = cockpit.gettext; @@ -33,15 +32,10 @@ class PluginTable extends React.Component { value: '', sortBy: {}, rows: [], - dropdownIsOpen: false, columns: [ - { - title: _("Plugin Name"), - transforms: [sortable], - cellFormatters: [expandable] - }, - { title: _("Plugin Type"), transforms: [sortable] }, - { title: _("Enabled"), transforms: [sortable] }, + { title: _("Plugin Name"), sortable: true }, + { title: _("Plugin Type"), sortable: true }, + { title: _("Enabled"), sortable: true }, ], }; @@ -63,50 +57,24 @@ class PluginTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - handleCollapse(event, rowKey, isOpen) { - const { rows, perPage, page } = this.state; - const index = (perPage * (page - 1) * 2) + rowKey; // Adjust for page set - rows[index].isOpen = isOpen; - this.setState({ - rows - }); + handleCollapse(_event, rowIndex, isExpanding) { + const rows = [...this.state.rows]; + const index = (this.state.perPage * (this.state.page - 1)) + rowIndex; + rows[index].isOpen = isExpanding; + this.setState({ rows }); } - handleSort(_event, index, direction) { - const sorted_rows = []; - const rows = []; - let count = 0; - - // Convert the rows pairings into a sortable array based on the column indexes - for (let idx = 0; idx < this.state.rows.length; idx += 2) { - sorted_rows.push({ - expandedRow: this.state.rows[idx + 1], - 1: this.state.rows[idx].cells[0], - 2: this.state.rows[idx].cells[1], - 3: this.state.rows[idx].cells[2], - }); - } - - // Sort the rows and build the new rows - sorted_rows.sort((a, b) => (a[index] > b[index]) ? 1 : -1); + handleSort(_event, columnIndex, direction) { + const rows = [...this.state.rows]; + + rows.sort((a, b) => (a.cells[columnIndex].content > b.cells[columnIndex].content) ? 1 : -1); if (direction !== SortByDirection.asc) { - sorted_rows.reverse(); - } - for (const srow of sorted_rows) { - rows.push({ - isOpen: false, - cells: [ - srow[1], srow[2], srow[3] - ], - }); - srow.expandedRow.parent = count; // reset parent idx - rows.push(srow.expandedRow); - count += 2; + rows.reverse(); } this.setState({ sortBy: { - index, + index: columnIndex, direction }, rows, @@ -116,7 +84,6 @@ class PluginTable extends React.Component { handleSearchChange(event, value) { const rows = []; - let count = 0; for (const row of this.props.rows) { const val = value.toLowerCase(); @@ -128,22 +95,15 @@ class PluginTable extends React.Component { continue; } - rows.push( - { - isOpen: false, - cells: [ - row.cn[0], - row["nsslapd-pluginType"][0], - row["nsslapd-pluginEnabled"][0] - ], - }, - { - parent: count, - fullWidth: true, - cells: [{ title: this.getExpandedRow(row) }] - }, - ); - count += 2; + rows.push({ + isOpen: false, + cells: [ + { content: row.cn[0] }, + { content: row["nsslapd-pluginType"][0] }, + { content: row["nsslapd-pluginEnabled"][0] } + ], + originalData: row + }); } this.setState({ @@ -206,25 +166,18 @@ class PluginTable extends React.Component { componentDidMount() { const rows = []; - let count = 0; for (const row of this.props.rows) { - rows.push( - { - isOpen: false, - cells: [ - row.cn[0], - row["nsslapd-pluginType"][0], - row["nsslapd-pluginEnabled"][0] - ], - }, - { - parent: count, - fullWidth: true, - cells: [{ title: this.getExpandedRow(row) }] - }, - ); - count += 2; + // Create row with properly formatted cells + rows.push({ + isOpen: false, + cells: [ + { content: row.cn[0] }, + { content: row["nsslapd-pluginType"][0] }, + { content: row["nsslapd-pluginEnabled"][0] } + ], + originalData: row + }); } this.setState({ rows, @@ -233,14 +186,8 @@ class PluginTable extends React.Component { render() { const { perPage, page, sortBy, rows, columns } = this.state; - const origRows = [...rows]; - const startIdx = ((perPage * page) - perPage) * 2; - const tableRows = origRows.splice(startIdx, perPage * 2); - - for (let idx = 1, count = 0; idx < tableRows.length; idx += 2, count += 2) { - // Rewrite parent index to match new spliced array - tableRows[idx].parent = count; - } + const startIdx = (perPage * page) - perPage; + const tableRows = rows.slice(startIdx, startIdx + perPage); return (
@@ -251,24 +198,62 @@ class PluginTable extends React.Component { onClear={(evt) => this.handleSearchChange(evt, '')} /> - - + + + + ))} + + + + {tableRows.map((row, rowIndex) => ( + + + + ))} + + {row.isOpen && ( + + + + )} + + ))} +
+ {columns.map((column, columnIndex) => ( + + {column.title} +
this.handleCollapse(null, rowIndex, !row.isOpen) + }} + /> + {row.cells.map((cell, cellIndex) => ( + + {cell.content} +
+ + {this.getExpandedRow(row.originalData)} + +
@@ -296,9 +281,9 @@ class AttrUniqConfigTable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("Config Name"), transforms: [sortable] }, - { title: _("Attribute"), transforms: [sortable] }, - { title: _("Enabled"), transforms: [sortable] } + { title: _("Config Name"), sortable: true }, + { title: _("Attribute"), sortable: true }, + { title: _("Enabled"), sortable: true } ], }; @@ -318,37 +303,34 @@ class AttrUniqConfigTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - actions() { - return [ - { - title: _("Edit Config"), - onClick: (event, rowId, rowData, extra) => - this.props.editConfig(rowData[0]) - }, - { - isSeparator: true - }, - { - title: _("Delete Config"), - onClick: (event, rowId, rowData, extra) => - this.props.deleteConfig(rowData[0]) - } - ]; - } - - componentDidMount () { - // Copy the rows so we can handle sorting and searching - const rows = []; - for (const row of this.props.rows) { - rows.push([row.cn[0], row['uniqueness-attribute-name'].join(", "), row["nsslapd-pluginenabled"][0]]); + getActionsForRow = (rowData) => [ + { + title: _("Edit Config"), + onClick: () => this.props.editConfig(rowData[0]) + }, + { + isSeparator: true + }, + { + title: _("Delete Config"), + onClick: () => this.props.deleteConfig(rowData[0]) } - this.setState({ - rows - }); + ]; + + componentDidMount() { + const rows = this.props.rows.map(row => [ + row.cn[0], + row['uniqueness-attribute-name'].join(", "), + row["nsslapd-pluginenabled"][0] + ]); + this.setState({ rows }); } handleSort(_event, index, direction) { - const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)); + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); + this.setState({ sortBy: { index, @@ -359,23 +341,22 @@ class AttrUniqConfigTable extends React.Component { } handleSearchChange(event, value) { - const rows = []; + let rows = []; const val = value.toLowerCase(); - for (const row of this.state.rows) { - if (val !== "" && - row[0].indexOf(val) === -1 && - row[1].indexOf(val) === -1) { - // Not a match, skip it - continue; - } - rows.push([row[0], row[1], row[2]]); - } + if (val === "") { - // reset rows - for (const row of this.props.rows) { - rows.push([row.cn[0], row['uniqueness-attribute-name'].join(", "), row["nsslapd-pluginenabled"][0]]); - } + rows = this.props.rows.map(row => [ + row.cn[0], + row['uniqueness-attribute-name'].join(", "), + row["nsslapd-pluginenabled"][0] + ]); + } else { + rows = this.state.rows.filter(row => + row[0].toLowerCase().includes(val) || + row[1].toLowerCase().includes(val) + ); } + this.setState({ rows, value, @@ -384,10 +365,11 @@ class AttrUniqConfigTable extends React.Component { } render() { - const rows = JSON.parse(JSON.stringify(this.state.rows)); // Deep copy + const rows = JSON.parse(JSON.stringify(this.state.rows)); let columns = this.state.columns; let has_rows = true; let tableRows; + if (rows.length === 0) { has_rows = false; columns = [{ title: _("Attribute Uniqueness Configurations") }]; @@ -396,6 +378,7 @@ class AttrUniqConfigTable extends React.Component { const startIdx = (this.state.perPage * this.state.page) - this.state.perPage; tableRows = rows.splice(startIdx, this.state.perPage); } + return (
this.handleSearchChange(evt, '')} /> - - - + + + {columns.map((column, idx) => ( + + ))} + {has_rows && + + + {tableRows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + {has_rows && ( + + )} + + ))} +
+ {column.title} + } +
{cell}{cell} + +
@@ -454,10 +467,10 @@ class LinkedAttributesTable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("Config Name"), transforms: [sortable] }, - { title: _("Link Type"), transforms: [sortable] }, - { title: _("Managed Type"), transforms: [sortable] }, - { title: _("Link Scope"), transforms: [sortable] } + { title: _("Config Name"), sortable: true }, + { title: _("Link Type"), sortable: true }, + { title: _("Managed Type"), sortable: true }, + { title: _("Link Scope"), sortable: true } ], }; @@ -477,41 +490,35 @@ class LinkedAttributesTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - actions() { - return [ - { - title: _("Edit Config"), - onClick: (event, rowId, rowData, extra) => - this.props.editConfig(rowData[0]) - }, - { - isSeparator: true - }, - { - title: _("Delete Config"), - onClick: (event, rowId, rowData, extra) => - this.props.deleteConfig(rowData[0]) - } - ]; - } - - componentDidMount () { - // Copy the rows so we can handle sorting and searching - const rows = []; - for (const row of this.props.rows) { - const configName = row.cn === undefined ? "" : row.cn[0]; - const linkType = row.linktype === undefined ? "" : row.linktype[0]; - const managedType = row.managedtype === undefined ? "" : row.managedtype[0]; - const linkScope = row.linkscope === undefined ? "" : row.linkscope[0]; - rows.push([configName, linkType, managedType, linkScope]); + getActionsForRow = (rowData) => [ + { + title: _("Edit Config"), + onClick: () => this.props.editConfig(rowData[0]) + }, + { + isSeparator: true + }, + { + title: _("Delete Config"), + onClick: () => this.props.deleteConfig(rowData[0]) } - this.setState({ - rows - }); + ]; + + componentDidMount() { + const rows = this.props.rows.map(row => [ + row.cn?.[0] || "", + row.linktype?.[0] || "", + row.managedtype?.[0] || "", + row.linkscope?.[0] || "" + ]); + this.setState({ rows }); } handleSort(_event, index, direction) { - const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)); + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); + this.setState({ sortBy: { index, @@ -522,29 +529,22 @@ class LinkedAttributesTable extends React.Component { } handleSearchChange(event, value) { - const rows = []; + let rows = []; const val = value.toLowerCase(); - for (const row of this.state.rows) { - if (val !== "" && - row[0].indexOf(val) === -1 && - row[1].indexOf(val) === -1 && - row[2].indexOf(val) === -1 && - row[3].indexOf(val) === -1) { - // Not a match, skip it - continue; - } - rows.push([row[0], row[1], row[2], row[3]]); - } + if (val === "") { - // reset rows - for (const row of this.props.rows) { - const configName = row.cn === undefined ? "" : row.cn[0]; - const linkType = row.linktype === undefined ? "" : row.linktype[0]; - const managedType = row.managedtype === undefined ? "" : row.managedtype[0]; - const linkScope = row.linkscope === undefined ? "" : row.linkscope[0]; - rows.push([configName, linkType, managedType, linkScope]); - } + rows = this.props.rows.map(row => [ + row.cn?.[0] || "", + row.linktype?.[0] || "", + row.managedtype?.[0] || "", + row.linkscope?.[0] || "" + ]); + } else { + rows = this.state.rows.filter(row => + row.some(cell => cell.toLowerCase().includes(val)) + ); } + this.setState({ rows, value, @@ -553,10 +553,11 @@ class LinkedAttributesTable extends React.Component { } render() { - const rows = JSON.parse(JSON.stringify(this.state.rows)); // Deep copy + const rows = JSON.parse(JSON.stringify(this.state.rows)); let columns = this.state.columns; let has_rows = true; let tableRows; + if (rows.length === 0) { has_rows = false; columns = [{ title: _("Linked Attributes Configurations") }]; @@ -565,6 +566,7 @@ class LinkedAttributesTable extends React.Component { const startIdx = (this.state.perPage * this.state.page) - this.state.perPage; tableRows = rows.splice(startIdx, this.state.perPage); } + return (
this.handleSearchChange(evt, '')} /> - - - + + + {columns.map((column, idx) => ( + + ))} + {has_rows && + + + {tableRows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + {has_rows && ( + + )} + + ))} +
+ {column.title} + } +
{cell}{cell} + +
@@ -622,10 +654,10 @@ class DNATable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("Config Name"), transforms: [sortable] }, - { title: _("Scope"), transforms: [sortable] }, - { title: _("Filter"), transforms: [sortable] }, - { title: _("Next Value"), transforms: [sortable] } + { title: _("Config Name"), sortable: true }, + { title: _("Scope"), sortable: true }, + { title: _("Filter"), sortable: true }, + { title: _("Next Value"), sortable: true } ], }; @@ -645,23 +677,35 @@ class DNATable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - componentDidMount () { - // Copy the rows so we can handle sorting and searching - const rows = []; - for (const row of this.props.rows) { - const configName = row.cn === undefined ? "" : row.cn[0]; - const nextValue = row.dnanextvalue === undefined ? "" : row.dnanextvalue[0]; - const filter = row.dnafilter === undefined ? "" : row.dnafilter[0]; - const scope = row.dnascope === undefined ? "" : row.dnascope[0]; - rows.push([configName, scope, filter, nextValue]); + componentDidMount() { + const rows = this.props.rows.map(row => [ + row.cn?.[0] || "", + row.dnascope?.[0] || "", + row.dnafilter?.[0] || "", + row.dnanextvalue?.[0] || "" + ]); + this.setState({ rows }); + } + + getActionsForRow = (rowData) => [ + { + title: _("Edit Config"), + onClick: () => this.props.editConfig(rowData[0]) + }, + { + isSeparator: true + }, + { + title: _("Delete Config"), + onClick: () => this.props.deleteConfig(rowData[0]) } - this.setState({ - rows - }); - } + ]; handleSort(_event, index, direction) { - const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)); + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); + this.setState({ sortBy: { index, @@ -672,29 +716,22 @@ class DNATable extends React.Component { } handleSearchChange(event, value) { - const rows = []; + let rows = []; const val = value.toLowerCase(); - for (const row of this.state.rows) { - if (val !== "" && - row[0].indexOf(val) === -1 && - row[1].indexOf(val) === -1 && - row[2].indexOf(val) === -1 && - row[3].indexOf(val) === -1) { - // Not a match, skip it - continue; - } - rows.push([row[0], row[1], row[2], row[3]]); - } + if (val === "") { - // reset rows - for (const row of this.props.rows) { - const configName = row.cn === undefined ? "" : row.cn[0]; - const nextValue = row.dnanextvalue === undefined ? "" : row.dnanextvalue[0]; - const filter = row.dnafilter === undefined ? "" : row.dnafilter[0]; - const scope = row.scope === undefined ? "" : row.scope[0]; - rows.push([configName, scope, filter, nextValue]); - } + rows = this.props.rows.map(row => [ + row.cn?.[0] || "", + row.dnascope?.[0] || "", + row.dnafilter?.[0] || "", + row.dnanextvalue?.[0] || "" + ]); + } else { + rows = this.state.rows.filter(row => + row.some(cell => cell.toLowerCase().includes(val)) + ); } + this.setState({ rows, value, @@ -702,29 +739,12 @@ class DNATable extends React.Component { }); } - actions() { - return [ - { - title: _("Edit Config"), - onClick: (event, rowId, rowData, extra) => - this.props.editConfig(rowData[0]) - }, - { - isSeparator: true - }, - { - title: _("Delete Config"), - onClick: (event, rowId, rowData, extra) => - this.props.deleteConfig(rowData[0]) - } - ]; - } - render() { - const rows = JSON.parse(JSON.stringify(this.state.rows)); // Deep copy + const rows = JSON.parse(JSON.stringify(this.state.rows)); let columns = this.state.columns; let has_rows = true; let tableRows; + if (rows.length === 0) { has_rows = false; columns = [{ title: _("DNA Configurations") }]; @@ -742,27 +762,57 @@ class DNATable extends React.Component { onChange={this.handleSearchChange} onClear={(evt) => this.handleSearchChange(evt, '')} /> - - - + + + {columns.map((column, idx) => ( + + ))} + {has_rows && + + + {tableRows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + {has_rows && ( + + )} + + ))} +
+ {column.title} + } +
{cell}{cell} + +
@@ -791,9 +841,9 @@ class DNASharedTable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("Hostname"), transforms: [sortable] }, - { title: _("Port"), transforms: [sortable] }, - { title: _("Remaining Values"), transforms: [sortable] }, + { title: _("Hostname"), sortable: true }, + { title: _("Port"), sortable: true }, + { title: _("Remaining Values"), sortable: true }, ], }; @@ -813,22 +863,20 @@ class DNASharedTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - componentDidMount () { - const rows = []; - for (const row of this.props.rows) { - rows.push([ - row.dnahostname[0], - row.dnaportnum[0], - row.dnaremainingvalues[0] - ]); - } - this.setState({ - rows - }); + componentDidMount() { + const rows = this.props.rows.map(row => [ + row.dnahostname[0], + row.dnaportnum[0], + row.dnaremainingvalues[0] + ]); + this.setState({ rows }); } handleSort(_event, index, direction) { - const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)); + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); + this.setState({ sortBy: { index, @@ -839,28 +887,21 @@ class DNASharedTable extends React.Component { } handleSearchChange(event, value) { - const rows = []; + let rows = []; const val = value.toLowerCase(); - for (const row of this.state.rows) { - if (val !== "" && - row[0].indexOf(val) === -1 && - row[1].indexOf(val) === -1 && - row[2].indexOf(val) === -1) { - // Not a match, skip it - continue; - } - rows.push([row[0], row[1], row[2]]); - } + if (val === "") { - // reset rows - for (const row of this.props.rows) { - rows.push([ - row.dnahostname[0], - row.dnaportnum[0], - row.dnaremainingvalues[0] - ]); - } + rows = this.props.rows.map(row => [ + row.dnahostname[0], + row.dnaportnum[0], + row.dnaremainingvalues[0] + ]); + } else { + rows = this.state.rows.filter(row => + row.some(cell => cell.toLowerCase().includes(val)) + ); } + this.setState({ rows, value, @@ -868,29 +909,26 @@ class DNASharedTable extends React.Component { }); } - actions() { - return [ - { - title: _("Edit Config"), - onClick: (event, rowId, rowData, extra) => - this.props.editConfig(rowData[0] + ":" + rowData[1]) - }, - { - isSeparator: true - }, - { - title: _("Delete Config"), - onClick: (event, rowId, rowData, extra) => - this.props.deleteConfig(rowData[0] + ":" + rowData[1]) - } - ]; - } + getActionsForRow = (rowData) => [ + { + title: _("Edit Config"), + onClick: () => this.props.editConfig(`${rowData[0]}:${rowData[1]}`) + }, + { + isSeparator: true + }, + { + title: _("Delete Config"), + onClick: () => this.props.deleteConfig(`${rowData[0]}:${rowData[1]}`) + } + ]; render() { - const rows = JSON.parse(JSON.stringify(this.state.rows)); // Deep copy + const rows = JSON.parse(JSON.stringify(this.state.rows)); let columns = this.state.columns; let has_rows = true; let tableRows; + if (rows.length === 0) { has_rows = false; columns = [{ title: _("DNA Shared Configurations") }]; @@ -908,27 +946,57 @@ class DNASharedTable extends React.Component { onChange={this.handleSearchChange} onClear={(evt) => this.handleSearchChange(evt, '')} /> - - - + + + {columns.map((column, idx) => ( + + ))} + {has_rows && + + + {tableRows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + {has_rows && ( + + )} + + ))} +
+ {column.title} + } +
{cell}{cell} + +
@@ -957,10 +1025,10 @@ class AutoMembershipDefinitionTable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("Definition Name"), transforms: [sortable] }, - { title: _("Default Group"), transforms: [sortable] }, - { title: _("Scope"), transforms: [sortable] }, - { title: _("Filter"), transforms: [sortable] }, + { title: _("Definition Name"), sortable: true }, + { title: _("Default Group"), sortable: true }, + { title: _("Scope"), sortable: true }, + { title: _("Filter"), sortable: true }, ], }; @@ -980,23 +1048,20 @@ class AutoMembershipDefinitionTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - componentDidMount () { - const rows = []; - for (const row of this.props.rows) { - rows.push([ - row.cn[0], - "automemberdefaultgroup" in row ? row.automemberdefaultgroup[0] : "", - row.automemberscope[0], - row.automemberfilter[0], - ]); - } - this.setState({ - rows - }); + componentDidMount() { + const rows = this.props.rows.map(row => [ + row.cn[0], + "automemberdefaultgroup" in row ? row.automemberdefaultgroup[0] : "", + row.automemberscope[0], + row.automemberfilter[0], + ]); + this.setState({ rows }); } handleSort(_event, index, direction) { - const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)); + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); this.setState({ sortBy: { index, @@ -1007,30 +1072,22 @@ class AutoMembershipDefinitionTable extends React.Component { } handleSearchChange(event, value) { - const rows = []; + let rows = []; const val = value.toLowerCase(); - for (const row of this.state.rows) { - if (val !== "" && - row[0].indexOf(val) === -1 && - row[1].indexOf(val) === -1 && - row[2].indexOf(val) === -1 && - row[3].indexOf(val) === -1) { - // Not a match, skip it - continue; - } - rows.push([row[0], row[1], row[2], row[3]]); - } + if (val === "") { - // reset rows - for (const row of this.props.rows) { - rows.push([ - row.cn[0], - row.automemberdefaultgroup[0], - row.automemberscope[0], - row.automemberfilter[0], - ]); - } + rows = this.props.rows.map(row => [ + row.cn[0], + "automemberdefaultgroup" in row ? row.automemberdefaultgroup[0] : "", + row.automemberscope[0], + row.automemberfilter[0], + ]); + } else { + rows = this.state.rows.filter(row => + row.some(cell => cell.toLowerCase().includes(val)) + ); } + this.setState({ rows, value, @@ -1038,29 +1095,26 @@ class AutoMembershipDefinitionTable extends React.Component { }); } - actions() { - return [ - { - title: _("Edit Config"), - onClick: (event, rowId, rowData, extra) => - this.props.editConfig(rowData[0]) - }, - { - isSeparator: true - }, - { - title: _("Delete Config"), - onClick: (event, rowId, rowData, extra) => - this.props.deleteConfig(rowData[0]) - } - ]; - } + getActionsForRow = (rowData) => [ + { + title: _("Edit Config"), + onClick: () => this.props.editConfig(rowData[0]) + }, + { + isSeparator: true + }, + { + title: _("Delete Config"), + onClick: () => this.props.deleteConfig(rowData[0]) + } + ]; render() { - const rows = JSON.parse(JSON.stringify(this.state.rows)); // Deep copy + const rows = JSON.parse(JSON.stringify(this.state.rows)); let columns = this.state.columns; let has_rows = true; let tableRows; + if (rows.length === 0) { has_rows = false; columns = [{ title: _("Automembership Definitions") }]; @@ -1069,6 +1123,7 @@ class AutoMembershipDefinitionTable extends React.Component { const startIdx = (this.state.perPage * this.state.page) - this.state.perPage; tableRows = rows.splice(startIdx, this.state.perPage); } + return (
this.handleSearchChange(evt, '')} /> - - - + + + {columns.map((column, idx) => ( + + ))} + {has_rows && + + + {tableRows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + {has_rows && ( + + )} + + ))} +
+ {column.title} + } +
{cell}{cell} + +
@@ -1127,10 +1212,10 @@ class AutoMembershipRegexTable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("Config Name"), transforms: [sortable] }, - { title: _("Exclusive Regex"), transforms: [sortable] }, - { title: _("Inclusive Regex"), transforms: [sortable] }, - { title: _("Target Group"), transforms: [sortable] }, + { title: _("Config Name"), sortable: true }, + { title: _("Exclusive Regex"), sortable: true }, + { title: _("Inclusive Regex"), sortable: true }, + { title: _("Target Group"), sortable: true }, ], }; @@ -1150,21 +1235,21 @@ class AutoMembershipRegexTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - componentDidMount () { - const rows = []; - for (const row of this.props.rows) { - const includeReg = row.automemberinclusiveregex === undefined ? "" : row.automemberinclusiveregex.join(", "); - const excludeReg = row.automemberexclusiveregex === undefined ? "" : row.automemberexclusiveregex.join(", "); - const targetGrp = row.automembertargetgroup === undefined ? "" : row.automembertargetgroup[0]; - rows.push([row.cn[0], excludeReg, includeReg, targetGrp]); - } - this.setState({ - rows - }); + componentDidMount() { + const rows = this.props.rows.map(row => [ + row.cn[0], + row.automemberexclusiveregex?.join(", ") || "", + row.automemberinclusiveregex?.join(", ") || "", + row.automembertargetgroup?.[0] || "" + ]); + this.setState({ rows }); } handleSort(_event, index, direction) { - const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)); + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); + this.setState({ sortBy: { index, @@ -1174,34 +1259,37 @@ class AutoMembershipRegexTable extends React.Component { }); } + getActionsForRow = (rowData) => [ + { + title: _("Edit Config"), + onClick: () => this.props.editConfig(rowData[0]) + }, + { + isSeparator: true + }, + { + title: _("Delete Config"), + onClick: () => this.props.deleteConfig(rowData[0]) + } + ]; + handleSearchChange(event, value) { - const rows = []; + let rows = []; const val = value.toLowerCase(); - for (const row of this.state.rows) { - if (val !== "" && - row[0].indexOf(val) === -1 && - row[1].indexOf(val) === -1 && - row[2].indexOf(val) === -1 && - row[3].indexOf(val) === -1) { - // Not a match, skip it - continue; - } - rows.push([row[0], row[1], row[2], row[3]]); - } + if (val === "") { - // reset rows - for (const row of this.props.rows) { - const includeReg = row.automemberinclusiveregex === undefined ? "" : row.automemberinclusiveregex[0]; - const excludeReg = row.automemberexclusiveregex === undefined ? "" : row.automemberexclusiveregex[0]; - const targetGrp = row.automembertargetgroup === undefined ? "" : row.automembertargetgroup[0]; - rows.push([ - row.cn[0], - excludeReg.join(", "), - includeReg.join(", "), - targetGrp, - ]); - } + rows = this.props.rows.map(row => [ + row.cn[0], + row.automemberexclusiveregex?.join(", ") || "", + row.automemberinclusiveregex?.join(", ") || "", + row.automembertargetgroup?.[0] || "" + ]); + } else { + rows = this.state.rows.filter(row => + row.some(cell => cell.toLowerCase().includes(val)) + ); } + this.setState({ rows, value, @@ -1209,29 +1297,12 @@ class AutoMembershipRegexTable extends React.Component { }); } - actions() { - return [ - { - title: _("Edit Config"), - onClick: (event, rowId, rowData, extra) => - this.props.editConfig(rowData[0]) - }, - { - isSeparator: true - }, - { - title: _("Delete Config"), - onClick: (event, rowId, rowData, extra) => - this.props.deleteConfig(rowData[0]) - } - ]; - } - render() { - const rows = JSON.parse(JSON.stringify(this.state.rows)); // Deep copy + const rows = JSON.parse(JSON.stringify(this.state.rows)); let columns = this.state.columns; let has_rows = true; let tableRows; + if (rows.length === 0) { has_rows = false; columns = [{ title: _("Automembership Regular Expressions") }]; @@ -1240,6 +1311,7 @@ class AutoMembershipRegexTable extends React.Component { const startIdx = (this.state.perPage * this.state.page) - this.state.perPage; tableRows = rows.splice(startIdx, this.state.perPage); } + return (
this.handleSearchChange(evt, '')} /> - - - + + + {columns.map((column, idx) => ( + + ))} + {has_rows && + + + {tableRows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + {has_rows && ( + + )} + + ))} +
+ {column.title} + } +
{cell}{cell} + +
@@ -1278,6 +1380,7 @@ class AutoMembershipRegexTable extends React.Component { } } + AutoMembershipRegexTable.propTypes = { rows: PropTypes.array, editConfig: PropTypes.func, @@ -1298,10 +1401,10 @@ class ManagedDefinitionTable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("Config Name"), transforms: [sortable] }, - { title: _("Scope"), transforms: [sortable] }, - { title: _("Filter"), transforms: [sortable] }, - { title: _("Managed Base"), transforms: [sortable] }, + { title: _("Config Name"), sortable: true }, + { title: _("Scope"), sortable: true }, + { title: _("Filter"), sortable: true }, + { title: _("Managed Base"), sortable: true }, ], }; @@ -1321,21 +1424,21 @@ class ManagedDefinitionTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - componentDidMount () { - const rows = []; - for (const row of this.props.rows) { - const managedBase = row.managedbase === undefined ? "" : row.managedbase[0]; - const scope = row.originscope === undefined ? "" : row.originscope[0]; - const filter = row.originfilter === undefined ? "" : row.originfilter[0]; - rows.push([row.cn[0], scope, filter, managedBase]); - } - this.setState({ - rows - }); + componentDidMount() { + const rows = this.props.rows.map(row => [ + row.cn[0], + row.originscope?.[0] || "", + row.originfilter?.[0] || "", + row.managedbase?.[0] || "" + ]); + this.setState({ rows }); } handleSort(_event, index, direction) { - const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)); + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); + this.setState({ sortBy: { index, @@ -1346,28 +1449,22 @@ class ManagedDefinitionTable extends React.Component { } handleSearchChange(event, value) { - const rows = []; + let rows = []; const val = value.toLowerCase(); - for (const row of this.state.rows) { - if (val !== "" && - row[0].indexOf(val) === -1 && - row[1].indexOf(val) === -1 && - row[2].indexOf(val) === -1 && - row[3].indexOf(val) === -1) { - // Not a match, skip it - continue; - } - rows.push([row[0], row[1], row[2], row[3]]); - } + if (val === "") { - // reset rows - for (const row of this.props.rows) { - const managedBase = row.managedbase === undefined ? "" : row.managedbase[0]; - const scope = row.originscope === undefined ? "" : row.originscope[0]; - const filter = row.originfilter === undefined ? "" : row.originfilter[0]; - rows.push([row.cn[0], scope, filter, managedBase]); - } + rows = this.props.rows.map(row => [ + row.cn[0], + row.originscope?.[0] || "", + row.originfilter?.[0] || "", + row.managedbase?.[0] || "" + ]); + } else { + rows = this.state.rows.filter(row => + row.some(cell => cell.toLowerCase().includes(val)) + ); } + this.setState({ rows, value, @@ -1375,29 +1472,26 @@ class ManagedDefinitionTable extends React.Component { }); } - actions() { - return [ - { - title: _("Edit Config"), - onClick: (event, rowId, rowData, extra) => - this.props.editConfig(rowData[0]) - }, - { - isSeparator: true - }, - { - title: _("Delete Config"), - onClick: (event, rowId, rowData, extra) => - this.props.deleteConfig(rowData[0]) - } - ]; - } + getActionsForRow = (rowData) => [ + { + title: _("Edit Config"), + onClick: () => this.props.editConfig(rowData[0]) + }, + { + isSeparator: true + }, + { + title: _("Delete Config"), + onClick: () => this.props.deleteConfig(rowData[0]) + } + ]; render() { - const rows = JSON.parse(JSON.stringify(this.state.rows)); // Deep copy + const rows = JSON.parse(JSON.stringify(this.state.rows)); let columns = this.state.columns; let has_rows = true; let tableRows; + if (rows.length === 0) { has_rows = false; columns = [{ title: _("Managed Entry Definitions") }]; @@ -1406,6 +1500,7 @@ class ManagedDefinitionTable extends React.Component { const startIdx = (this.state.perPage * this.state.page) - this.state.perPage; tableRows = rows.splice(startIdx, this.state.perPage); } + return (
this.handleSearchChange(evt, '')} /> - - - + + + {columns.map((column, idx) => ( + + ))} + {has_rows && + + + {tableRows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + {has_rows && ( + + )} + + ))} +
+ {column.title} + } +
{cell}{cell} + +
@@ -1464,7 +1589,7 @@ class ManagedTemplateTable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("Template DN"), transforms: [sortable] }, + { title: _("Template DN"), sortable: true }, ], }; @@ -1484,18 +1609,15 @@ class ManagedTemplateTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - componentDidMount () { - const rows = []; - for (const row of this.props.rows) { - rows.push([row.entrydn[0]]); - } - this.setState({ - rows - }); + componentDidMount() { + const rows = this.props.rows.map(row => [row.entrydn[0]]); + this.setState({ rows }); } handleSort(_event, index, direction) { - const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)); + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); this.setState({ sortBy: { index, @@ -1506,21 +1628,17 @@ class ManagedTemplateTable extends React.Component { } handleSearchChange(event, value) { - const rows = []; + let rows = []; const val = value.toLowerCase(); - for (const row of this.state.rows) { - if (val !== "" && row[0].indexOf(val) === -1) { - // Not a match, skip it - continue; - } - rows.push([row[0]]); - } + if (val === "") { - // reset rows - for (const row of this.props.rows) { - rows.push([row.entrydn[0]]); - } + rows = this.props.rows.map(row => [row.entrydn[0]]); + } else { + rows = this.state.rows.filter(row => + row[0].toLowerCase().includes(val) + ); } + this.setState({ rows, value, @@ -1528,29 +1646,26 @@ class ManagedTemplateTable extends React.Component { }); } - actions() { - return [ - { - title: _("Edit Config"), - onClick: (event, rowId, rowData, extra) => - this.props.editConfig(rowData[0]) - }, - { - isSeparator: true - }, - { - title: _("Delete Config"), - onClick: (event, rowId, rowData, extra) => - this.props.deleteConfig(rowData[0]) - } - ]; - } + getActionsForRow = (rowData) => [ + { + title: _("Edit Config"), + onClick: () => this.props.editConfig(rowData[0]) + }, + { + isSeparator: true + }, + { + title: _("Delete Config"), + onClick: () => this.props.deleteConfig(rowData[0]) + } + ]; render() { - const rows = JSON.parse(JSON.stringify(this.state.rows)); // Deep copy + const rows = JSON.parse(JSON.stringify(this.state.rows)); let columns = this.state.columns; let has_rows = true; let tableRows; + if (rows.length === 0) { has_rows = false; columns = [{ title: _("Managed Entry Templates") }]; @@ -1559,6 +1674,7 @@ class ManagedTemplateTable extends React.Component { const startIdx = (this.state.perPage * this.state.page) - this.state.perPage; tableRows = rows.splice(startIdx, this.state.perPage); } + return (
this.handleSearchChange(evt, '')} /> - - - + + + {columns.map((column, idx) => ( + + ))} + {has_rows && + + + {tableRows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + {has_rows && ( + + )} + + ))} +
+ {column.title} + } +
{cell}{cell} + +
@@ -1617,7 +1763,7 @@ class PassthroughAuthURLsTable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("URL"), transforms: [sortable] }, + { title: _("URL"), sortable: true }, ], }; @@ -1637,18 +1783,16 @@ class PassthroughAuthURLsTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - componentDidMount () { - const rows = []; - for (const row of this.props.rows) { - rows.push([row.url]); - } - this.setState({ - rows - }); + componentDidMount() { + const rows = this.props.rows.map(row => [row.url]); + this.setState({ rows }); } handleSort(_event, index, direction) { - const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)); + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); + this.setState({ sortBy: { index, @@ -1659,21 +1803,17 @@ class PassthroughAuthURLsTable extends React.Component { } handleSearchChange(event, value) { - const rows = []; + let rows = []; const val = value.toLowerCase(); - for (const row of this.state.rows) { - if (val !== "" && row[0].indexOf(val) === -1) { - // Not a match, skip it - continue; - } - rows.push([row[0]]); - } + if (val === "") { - // reset rows - for (const row of this.props.rows) { - rows.push([row.url]); - } + rows = this.props.rows.map(row => [row.url]); + } else { + rows = this.state.rows.filter(row => + row[0].toLowerCase().includes(val) + ); } + this.setState({ rows, value, @@ -1681,29 +1821,26 @@ class PassthroughAuthURLsTable extends React.Component { }); } - actions() { - return [ - { - title: _("Edit URL"), - onClick: (event, rowId, rowData, extra) => - this.props.editConfig(rowData[0]) - }, - { - isSeparator: true - }, - { - title: _("Delete URL"), - onClick: (event, rowId, rowData, extra) => - this.props.deleteConfig(rowData[0]) - } - ]; - } + getActionsForRow = (rowData) => [ + { + title: _("Edit URL"), + onClick: () => this.props.editConfig(rowData[0]) + }, + { + isSeparator: true + }, + { + title: _("Delete URL"), + onClick: () => this.props.deleteConfig(rowData[0]) + } + ]; render() { - const rows = JSON.parse(JSON.stringify(this.state.rows)); // Deep copy + const rows = JSON.parse(JSON.stringify(this.state.rows)); let columns = this.state.columns; let has_rows = true; let tableRows; + if (rows.length === 0) { has_rows = false; columns = [{ title: _("Pass-Through Authentication URLs") }]; @@ -1712,6 +1849,7 @@ class PassthroughAuthURLsTable extends React.Component { const startIdx = (this.state.perPage * this.state.page) - this.state.perPage; tableRows = rows.splice(startIdx, this.state.perPage); } + return (
this.handleSearchChange(evt, '')} /> - - - + + + {columns.map((column, idx) => ( + + ))} + {has_rows && + + + {tableRows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + {has_rows && ( + + )} + + ))} +
+ {column.title} + } +
{cell}{cell} + +
@@ -1770,10 +1938,10 @@ class PassthroughAuthConfigsTable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("Config Name"), transforms: [sortable] }, - { title: _("Attribute"), transforms: [sortable] }, - { title: _("Map Method"), transforms: [sortable] }, - { title: _("Filter"), transforms: [sortable] }, + { title: _("Config Name"), sortable: true }, + { title: _("Attribute"), sortable: true }, + { title: _("Map Method"), sortable: true }, + { title: _("Filter"), sortable: true }, ], }; @@ -1793,21 +1961,21 @@ class PassthroughAuthConfigsTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - componentDidMount () { - const rows = []; - for (const row of this.props.rows) { - const attr = row.pamidattr === undefined ? "" : row.pamidattr[0]; - const mapMethod = row.pamidmapmethod === undefined ? "" : row.pamidmapmethod[0]; - const filter = row.pamfilter === undefined ? "" : row.pamfilter[0]; - rows.push([row.cn[0], attr, mapMethod, filter]); - } - this.setState({ - rows - }); + componentDidMount() { + const rows = this.props.rows.map(row => [ + row.cn[0], + row.pamidattr?.[0] || "", + row.pamidmapmethod?.[0] || "", + row.pamfilter?.[0] || "" + ]); + this.setState({ rows }); } handleSort(_event, index, direction) { - const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)); + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); + this.setState({ sortBy: { index, @@ -1818,28 +1986,22 @@ class PassthroughAuthConfigsTable extends React.Component { } handleSearchChange(event, value) { - const rows = []; + let rows = []; const val = value.toLowerCase(); - for (const row of this.state.rows) { - if (val !== "" && - row[0].indexOf(val) === -1 && - row[1].indexOf(val) === -1 && - row[2].indexOf(val) === -1 && - row[3].indexOf(val) === -1) { - // Not a match, skip it - continue; - } - rows.push([row[0], row[1], row[2], row[3]]); - } + if (val === "") { - // reset rows - for (const row of this.props.rows) { - const attr = row.pamidattr === undefined ? "" : row.pamidattr[0]; - const mapMethod = row.pamidmapmethod === undefined ? "" : row.pamidmapmethod[0]; - const filter = row.pamfilter === undefined ? "" : row.pamfilter[0]; - rows.push([row.cn[0], attr, mapMethod, filter]); - } + rows = this.props.rows.map(row => [ + row.cn[0], + row.pamidattr?.[0] || "", + row.pamidmapmethod?.[0] || "", + row.pamfilter?.[0] || "" + ]); + } else { + rows = this.state.rows.filter(row => + row.some(cell => cell.toLowerCase().includes(val)) + ); } + this.setState({ rows, value, @@ -1847,29 +2009,26 @@ class PassthroughAuthConfigsTable extends React.Component { }); } - actions() { - return [ - { - title: _("Edit Config"), - onClick: (event, rowId, rowData, extra) => - this.props.editConfig(rowData[0]) - }, - { - isSeparator: true - }, - { - title: _("Delete Config"), - onClick: (event, rowId, rowData, extra) => - this.props.deleteConfig(rowData[0]) - } - ]; - } + getActionsForRow = (rowData) => [ + { + title: _("Edit Config"), + onClick: () => this.props.editConfig(rowData[0]) + }, + { + isSeparator: true + }, + { + title: _("Delete Config"), + onClick: () => this.props.deleteConfig(rowData[0]) + } + ]; render() { - const rows = JSON.parse(JSON.stringify(this.state.rows)); // Deep copy + const rows = JSON.parse(JSON.stringify(this.state.rows)); let columns = this.state.columns; let has_rows = true; let tableRows; + if (rows.length === 0) { has_rows = false; columns = [{ title: _("PAM Configurations") }]; @@ -1878,6 +2037,7 @@ class PassthroughAuthConfigsTable extends React.Component { const startIdx = (this.state.perPage * this.state.page) - this.state.perPage; tableRows = rows.splice(startIdx, this.state.perPage); } + return (
this.handleSearchChange(evt, '')} /> - - - + + + {columns.map((column, idx) => ( + + ))} + {has_rows && + + + {tableRows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + {has_rows && ( + + )} + + ))} +
+ {column.title} + } +
{cell}{cell} + +
diff --git a/src/cockpit/389-console/src/lib/replication/replTables.jsx b/src/cockpit/389-console/src/lib/replication/replTables.jsx index 163f7411f0..22dac10021 100644 --- a/src/cockpit/389-console/src/lib/replication/replTables.jsx +++ b/src/cockpit/389-console/src/lib/replication/replTables.jsx @@ -3,20 +3,19 @@ import React from "react"; import { Button, Pagination, - PaginationVariant, SearchInput, Spinner, } from '@patternfly/react-core'; -import { - TableVariant, - sortable, - SortByDirection -} from '@patternfly/react-table'; import { Table, - TableHeader, - TableBody -} from '@patternfly/react-table/deprecated'; + Thead, + Tr, + Th, + Tbody, + Td, + ActionsColumn, + SortByDirection +} from '@patternfly/react-table'; import { TrashAltIcon } from '@patternfly/react-icons/dist/js/icons/trash-alt-icon'; import PropTypes from "prop-types"; @@ -32,11 +31,11 @@ class ReplAgmtTable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("Name"), transforms: [sortable] }, - { title: _("Host"), transforms: [sortable] }, - { title: _("Port"), transforms: [sortable] }, - { title: _("State"), transforms: [sortable] }, - { title: _("Last Init Status"), transforms: [sortable] }, + { title: _("Name"), sortable: true }, + { title: _("Host"), sortable: true }, + { title: _("Port"), sortable: true }, + { title: _("State"), sortable: true }, + { title: _("Last Init Status"), sortable: true }, ], }; @@ -54,77 +53,59 @@ class ReplAgmtTable extends React.Component { } componentDidMount() { - // Deep copy the rows so we can handle sorting and searching this.setState({ page: this.props.page }); } - actions() { - return [ - { - title: _("Edit Agreement"), - onClick: (event, rowId, rowData, extra) => - this.props.edit(rowData.cells[0]) - }, - { - title: _("Initialize Agreement"), - onClick: (event, rowId, rowData, extra) => - this.props.init(rowData.cells[0]) - }, - { - title: _("Poke Agreement"), - onClick: (event, rowId, rowData, extra) => - this.props.poke(rowData.cells[0]) - }, - { - title: _("Disable/Enable Agreement"), - onClick: (event, rowId, rowData, extra) => - this.props.enable(rowData.cells[0], rowData.cells[3]) - }, - { - isSeparator: true - }, - { - title: _("Delete Agreement"), - onClick: (event, rowId, rowData, extra) => - this.props.delete(rowData.cells[0], rowData.cells[3]) - }, - - ]; - } + getActionsForRow = (rowData) => [ + { + title: _("Edit Agreement"), + onClick: () => this.props.edit(rowData[0]) + }, + { + title: _("Initialize Agreement"), + onClick: () => this.props.init(rowData[0]) + }, + { + title: _("Poke Agreement"), + onClick: () => this.props.poke(rowData[0]) + }, + { + title: _("Disable/Enable Agreement"), + onClick: () => this.props.enable(rowData[0], rowData[3]) + }, + { + isSeparator: true + }, + { + title: _("Delete Agreement"), + onClick: () => this.props.delete(rowData[0], rowData[3]) + }, + ]; convertStatus(msg) { if (msg === "Initialized") { - return ( - {_("Initialized")} - ); + return {_("Initialized")}; } else if (msg === "Not Initialized") { - return ( - {_("Not Initialized")} - ); + return {_("Not Initialized")}; } else if (msg === "Initializing") { return (
{_("Initializing")}
); - } else { - return ( - {msg} - ); } + return {msg}; } render() { - // let rows = this.state.rows; const rows = []; let columns = this.state.columns; let has_rows = true; let tableRows; const rows_copy = JSON.parse(JSON.stringify(this.props.rows)); - // Refine rows to handle JSX objects for (const row of rows_copy) { - rows.push({ cells: [row[0], row[1], row[2], row[3], { title: this.convertStatus(row[5]) }] }); + rows.push([row[0], row[1], row[2], row[3], this.convertStatus(row[5])]); } if (rows.length === 0) { @@ -135,6 +116,7 @@ class ReplAgmtTable extends React.Component { const startIdx = (this.state.perPage * this.state.page) - this.state.perPage; tableRows = rows.splice(startIdx, this.state.perPage); } + return (
this.props.search(evt, '')} /> - - - + + + {columns.map((column, idx) => ( + + ))} + {has_rows && + + + {tableRows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + {has_rows && ( + + )} + + ))} +
+ {column.title} + } +
{cell}{cell} + +
@@ -180,7 +192,10 @@ class ManagerTable extends React.Component { this.state = { sortBy: {}, rows: [], - columns: ['', ''], + columns: [ + { title: '', sortable: true }, + { title: '' } + ], }; this.handleSort = this.handleSort.bind(this); @@ -190,42 +205,36 @@ class ManagerTable extends React.Component { componentDidMount() { let rows = []; let columns = this.state.columns; + for (const managerRow of this.props.rows) { - rows.push({ - cells: [managerRow, { props: { textCenter: true }, title: this.getDeleteButton(managerRow) }] - }); + rows.push([ + managerRow, + this.getDeleteButton(managerRow) + ]); } + if (rows.length === 0) { - rows = [{ cells: [_("No Replication Managers")] }]; + rows = [[_("No Replication Managers")]]; columns = [{ title: '' }]; } + this.setState({ rows, columns }); } - handleSort(_event, index, direction) { - const rows = []; - const sortedManagers = [...this.state.rows]; - - // Sort the managers and build the new rows - sortedManagers.sort(); - if (direction !== SortByDirection.asc) { - sortedManagers.reverse(); - } - - for (const managerRow of sortedManagers) { - rows.push({ cells: [managerRow.cells[0], { props: { textCenter: true }, title: this.getDeleteButton(managerRow.cells[0]) }] }); - } + handleSort(_event, columnIndex, sortDirection) { + const sortedRows = [...this.state.rows].sort((a, b) => + (a[0] < b[0] ? -1 : a[0] > b[0] ? 1 : 0) + ); this.setState({ sortBy: { - index, - direction + index: columnIndex, + direction: sortDirection }, - rows, - page: 1, + rows: sortDirection === 'asc' ? sortedRows : sortedRows.reverse() }); } @@ -247,14 +256,38 @@ class ManagerTable extends React.Component { return ( - - + + + {this.state.columns.map((column, columnIndex) => ( + + ))} + + + + {this.state.rows.map((row, rowIndex) => ( + + {row.map((cell, cellIndex) => ( + + ))} + + ))} +
+ {column.title} +
+ {cell} +
); } @@ -268,9 +301,9 @@ class RUVTable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("Replica ID"), transforms: [sortable] }, - { title: _("Replica LDAP URL"), transforms: [sortable] }, - { title: _("Max CSN"), transforms: [sortable] }, + { title: _("Replica ID"), sortable: true }, + { title: _("Replica LDAP URL"), sortable: true }, + { title: _("Max CSN"), sortable: true }, { title: '' }, ], }; @@ -283,9 +316,12 @@ class RUVTable extends React.Component { let rows = []; let columns = this.state.columns; for (const row of this.props.rows) { - rows.push({ - cells: [row.rid, row.url, row.maxcsn, { props: { textCenter: true }, title: this.getCleanButton(row.rid) }] - }); + rows.push([ + row.rid, + row.url, + row.maxcsn, + this.getCleanButton(row.rid) + ]); } if (rows.length === 0) { rows = [{ cells: [_("No RUV's")] }]; @@ -298,7 +334,9 @@ class RUVTable extends React.Component { } handleSort(_event, index, direction) { - const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)); + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); this.setState({ sortBy: { index, @@ -323,19 +361,46 @@ class RUVTable extends React.Component { } render() { + const tableRows = this.state.rows.map((row, rowIndex) => ({ + cells: Array.isArray(row) ? row : row.cells + })); + return (
- - + + + {this.state.columns.map((column, columnIndex) => ( + + ))} + + + + {tableRows.map((row, rowIndex) => ( + + {row.cells.map((cell, cellIndex) => ( + + ))} + + ))} +
+ {column.title} +
+ {cell} +
); @@ -351,9 +416,9 @@ class ReplicaLDIFTable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("LDIF File"), transforms: [sortable] }, - { title: _("Creation Date"), transforms: [sortable] }, - { title: _("File Size"), transforms: [sortable] }, + { title: _("LDIF File"), sortable: true }, + { title: _("Creation Date"), sortable: true }, + { title: _("File Size"), sortable: true }, ], }; @@ -376,14 +441,10 @@ class ReplicaLDIFTable extends React.Component { let rows = []; let columns = this.state.columns; for (const ldifRow of this.props.rows) { - rows.push({ - cells: [ - ldifRow[0], ldifRow[1], ldifRow[2] - ] - }); + rows.push(ldifRow); } if (rows.length === 0) { - rows = [{ cells: [_("No LDIF files")] }]; + rows = [[_("No LDIF files")]]; columns = [{ title: _("LDIF File") }]; } this.setState({ @@ -393,29 +454,16 @@ class ReplicaLDIFTable extends React.Component { } handleSort(_event, index, direction) { - const rows = []; - const sortedLDIF = [...this.props.rows]; - - // Sort the referrals and build the new rows - sortedLDIF.sort(); - if (direction !== SortByDirection.asc) { - sortedLDIF.reverse(); - } - for (const ldifRow of sortedLDIF) { - rows.push({ - cells: - [ - ldifRow[0], ldifRow[1], ldifRow[2] - ] - }); - } + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); this.setState({ sortBy: { index, direction }, - rows, + rows: direction === SortByDirection.asc ? sortedRows : sortedRows.reverse(), page: 1, }); } @@ -426,16 +474,39 @@ class ReplicaLDIFTable extends React.Component { return ( - - + + + {columns.map((column, idx) => ( + + ))} + + + + {rows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + + ))} +
+ {column.title} +
{cell}{cell}
); } diff --git a/src/cockpit/389-console/src/lib/schema/schemaTables.jsx b/src/cockpit/389-console/src/lib/schema/schemaTables.jsx index e072bffffc..a401ab6379 100644 --- a/src/cockpit/389-console/src/lib/schema/schemaTables.jsx +++ b/src/cockpit/389-console/src/lib/schema/schemaTables.jsx @@ -4,7 +4,6 @@ import { Grid, GridItem, Pagination, - PaginationVariant, SearchInput, Spinner, Text, @@ -12,16 +11,16 @@ import { TextVariants, } from '@patternfly/react-core'; import { - expandable, - TableVariant, - sortable, + Table, + Thead, + Tr, + Th, + Tbody, + Td, + ExpandableRowContent, + ActionsColumn, SortByDirection } from '@patternfly/react-table'; -import { - Table, - TableHeader, - TableBody -} from '@patternfly/react-table/deprecated'; import PropTypes from "prop-types"; const _ = cockpit.gettext; @@ -36,14 +35,15 @@ class ObjectClassesTable extends React.Component { value: '', sortBy: {}, rows: [], - noRows: true, columns: [ { title: _("Objectclass Name"), - transforms: [sortable], - cellFormatters: [expandable] + sortable: true + }, + { + title: _("OID"), + sortable: true }, - { title: _("OID"), transforms: [sortable] }, ], }; @@ -65,45 +65,63 @@ class ObjectClassesTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - handleSort(_event, index, direction) { - const sorted_rows = []; + handleSort(_event, columnIndex, direction) { + const rows = [...this.state.rows]; + + rows.sort((a, b) => (a.cells[columnIndex].content > b.cells[columnIndex].content) ? 1 : -1); + if (direction !== SortByDirection.asc) { + rows.reverse(); + } + + this.setState({ + sortBy: { + index: columnIndex, + direction + }, + rows, + page: 1, + }); + } + + handleCollapse(_event, rowIndex, isExpanding) { + const rows = [...this.state.rows]; + const index = (this.state.perPage * (this.state.page - 1)) + rowIndex; + rows[index].isOpen = isExpanding; + this.setState({ rows }); + } + + handleSearchChange(event, value) { const rows = []; - let count = 0; + const val = value.toLowerCase(); - // Convert the rows pairings into a sortable array based on the column indexes - for (let idx = 0; idx < this.state.rows.length; idx += 2) { - sorted_rows.push({ - expandedRow: this.state.rows[idx + 1], - 1: this.state.rows[idx].cells[0], - 2: this.state.rows[idx].cells[1], - not_user_defined: this.state.rows[idx].disableActions - }); - } + for (const row of this.props.rows) { + // Check for matches of all the parts + if (val !== "" && + row.name[0].toLowerCase().indexOf(val) === -1 && + row.oid[0].toLowerCase().indexOf(val) === -1) { + continue; + } + + let user_defined = false; + if (row.x_origin.length > 0 && + row.x_origin.indexOf("user defined") !== -1) { + user_defined = true; + } - // Sort the rows and build the new rows - sorted_rows.sort((a, b) => (a[index] > b[index]) ? 1 : -1); - if (direction !== SortByDirection.asc) { - sorted_rows.reverse(); - } - for (const srow of sorted_rows) { rows.push({ isOpen: false, cells: [ - srow[1], srow[2] + { content: row.name[0] }, + { content: row.oid[0] } ], - disableActions: srow.not_user_defined + disableActions: !user_defined, + originalData: row }); - srow.expandedRow.parent = count; // reset parent idx - rows.push(srow.expandedRow); - count += 2; } this.setState({ - sortBy: { - index, - direction - }, rows, + value, page: 1, }); } @@ -132,118 +150,49 @@ class ObjectClassesTable extends React.Component { } componentDidMount() { - let rows = []; - let columns = this.state.columns; - let count = 0; - let noRows = false; - - for (const row of this.props.rows) { - let user_defined = false; - if (row.x_origin.length > 0 && - row.x_origin.indexOf("user defined") !== -1) { - user_defined = true; - } - rows.push( - { - isOpen: false, - cells: [row.name[0], row.oid[0]], - disableActions: !user_defined, - }, - { - parent: count, - fullWidth: true, - cells: [{ title: this.getExpandedRow(row) }] - }, - ); - count += 2; - } - if (rows.length === 0) { - noRows = true; - rows = [{ cells: [_("No Objectclasses")] }]; - columns = [{ title: _("Objectclasses") }]; - } - this.setState({ - rows, - columns, - noRows, - }); - } - - handleCollapse(event, rowKey, isOpen) { - const { rows, perPage, page } = this.state; - const index = (perPage * (page - 1) * 2) + rowKey; // Adjust for page set - rows[index].isOpen = isOpen; - this.setState({ - rows - }); - } - - handleSearchChange(event, value) { const rows = []; - let count = 0; for (const row of this.props.rows) { let user_defined = false; - const val = value.toLowerCase(); - - // Check for matches of all the parts - if (val !== "" && row.name[0].toLowerCase().indexOf(val) === -1 && - row.oid[0].toLowerCase().indexOf(val) === -1) { - // Not a match - continue; - } - if (row.x_origin.length > 0 && row.x_origin.indexOf("user defined") !== -1) { user_defined = true; } - rows.push( - { - isOpen: false, - cells: [row.name[0], row.oid[0]], - disableActions: !user_defined - }, - { - parent: count, - fullWidth: true, - cells: [{ title: this.getExpandedRow(row) }] - }, - ); - count += 2; + + rows.push({ + isOpen: false, + cells: [ + { content: row.name[0] }, + { content: row.oid[0] } + ], + disableActions: !user_defined, + originalData: row + }); } this.setState({ rows, - value, - page: 1, }); } - actions() { - return [ - { - title: _("Edit Objectclass"), - onClick: (event, rowId, rowData, extra) => - this.props.editModalHandler(rowData.cells[0]) - }, - { - title: _("Delete Objectclass"), - onClick: (event, rowId, rowData, extra) => - this.props.deleteHandler(rowData.cells[0]) - } - ]; - } + getActionsForRow = (rowData) => [ + { + title: _("Edit Objectclass"), + onClick: () => this.props.editModalHandler(rowData.cells[0].content) + }, + { + isSeparator: true + }, + { + title: _("Delete Objectclass"), + onClick: () => this.props.deleteHandler(rowData.cells[0].content) + } + ]; render() { - const { perPage, page, sortBy, rows, noRows, columns } = this.state; - const origRows = [...rows]; - const startIdx = ((perPage * page) - perPage) * 2; - const tableRows = origRows.splice(startIdx, perPage * 2); - - for (let idx = 1, count = 0; idx < tableRows.length; idx += 2, count += 2) { - // Rewrite parent index to match new spliced array - tableRows[idx].parent = count; - } + const { perPage, page, sortBy, rows, columns } = this.state; + const startIdx = (perPage * page) - perPage; + const tableRows = rows.slice(startIdx, startIdx + perPage); let content = (
@@ -269,28 +218,70 @@ class ObjectClassesTable extends React.Component { /> - - - + + + + ))} + + + + {tableRows.map((row, rowIndex) => ( + + + + ))} + + + {row.isOpen && ( + + + + )} + + ))} +
+ {columns.map((column, columnIndex) => ( + + {column.title} + +
this.handleCollapse(null, rowIndex, !row.isOpen) + }} + /> + {row.cells.map((cell, cellIndex) => ( + + {cell.content} + + +
+ + {this.getExpandedRow(row.originalData)} + +
@@ -330,11 +321,10 @@ class AttributesTable extends React.Component { columns: [ { title: _("Attribute Name"), - transforms: [sortable], - cellFormatters: [expandable] + sortable: true }, - { title: _("OID"), transforms: [sortable] }, - { title: _("Syntax"), transforms: [sortable] }, + { title: _("OID"), sortable: true }, + { title: _("Syntax"), sortable: true }, ], }; @@ -356,24 +346,24 @@ class AttributesTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - handleSort(_event, index, direction) { + handleSort(_event, columnIndex, direction) { const sorted_rows = []; const rows = []; let count = 0; - // Convert the rows pairings into a sortable array based on the column indexes + // Convert the rows pairings into a sortable array for (let idx = 0; idx < this.state.rows.length; idx += 2) { sorted_rows.push({ expandedRow: this.state.rows[idx + 1], - 1: this.state.rows[idx].cells[0], - 2: this.state.rows[idx].cells[1], - 3: this.state.rows[idx].cells[2], + 1: this.state.rows[idx].cells[0].content, + 2: this.state.rows[idx].cells[1].content, + 3: this.state.rows[idx].cells[2].content, not_user_defined: this.state.rows[idx].disableActions }); } - // Sort the rows and build the new rows - sorted_rows.sort((a, b) => (a[index] > b[index]) ? 1 : -1); + // Sort and rebuild rows + sorted_rows.sort((a, b) => (a[columnIndex + 1] > b[columnIndex + 1]) ? 1 : -1); if (direction !== SortByDirection.asc) { sorted_rows.reverse(); } @@ -381,18 +371,20 @@ class AttributesTable extends React.Component { rows.push({ isOpen: false, cells: [ - srow[1], srow[2], srow[2] + { content: srow[1] }, + { content: srow[2] }, + { content: srow[3] } ], disableActions: srow.not_user_defined }); - srow.expandedRow.parent = count; // reset parent idx + srow.expandedRow.parent = count; rows.push(srow.expandedRow); count += 2; } this.setState({ sortBy: { - index, + index: columnIndex, direction }, rows, @@ -433,34 +425,28 @@ class AttributesTable extends React.Component { componentDidMount() { let rows = []; let columns = this.state.columns; - let count = 0; let noRows = false; for (const row of this.props.rows) { - let user_defined = false; - if (row.x_origin.length > 0 && - row.x_origin.indexOf("user defined") !== -1) { - user_defined = true; - } - rows.push( - { - isOpen: false, - cells: [row.name[0], row.oid[0], row.syntax[0]], - disableActions: !user_defined, - }, - { - parent: count, - fullWidth: true, - cells: [{ title: this.getExpandedRow(row) }] - }, - ); - count += 2; + let user_defined = row.x_origin.includes("user defined"); + rows.push({ + isOpen: false, + cells: [ + { content: row.name[0] }, + { content: row.oid[0] }, + { content: row.syntax[0] } + ], + disableActions: !user_defined, + originalData: row + }); } + if (rows.length === 0) { noRows = true; - rows = [{ cells: [_("No Attributes")] }]; + rows = [{ cells: [{ content: _("No Attributes") }] }]; columns = [{ title: _("Attributes") }]; } + this.setState({ rows, columns, @@ -519,31 +505,21 @@ class AttributesTable extends React.Component { }); } - actions() { - return [ - { - title: _("Edit Attribute"), - onClick: (event, rowId, rowData, extra) => - this.props.editModalHandler(rowData.cells[0]) - }, - { - title: _("Delete Attribute"), - onClick: (event, rowId, rowData, extra) => - this.props.deleteHandler(rowData.cells[0]) - } - ]; - } + getActionsForRow = (rowData) => [ + { + title: _("Edit Attribute"), + onClick: () => this.props.editModalHandler(rowData.cells[0].content) + }, + { + title: _("Delete Attribute"), + onClick: () => this.props.deleteHandler(rowData.cells[0].content) + } + ]; render() { const { perPage, page, sortBy, rows, noRows, columns } = this.state; - const origRows = [...rows]; - const startIdx = ((perPage * page) - perPage) * 2; - const tableRows = origRows.splice(startIdx, perPage * 2); - - for (let idx = 1, count = 0; idx < tableRows.length; idx += 2, count += 2) { - // Rewrite parent index to match new spliced array - tableRows[idx].parent = count; - } + const startIdx = (perPage * page) - perPage; + const tableRows = rows.slice(startIdx, startIdx + perPage); let content = (
@@ -569,28 +545,70 @@ class AttributesTable extends React.Component { /> - - - + + + + ))} + + + + {tableRows.map((row, rowIndex) => ( + + + + ))} + + + {row.isOpen && ( + + + + )} + + ))} +
+ {columns.map((column, columnIndex) => ( + + {column.title} + +
this.handleCollapse(null, rowIndex, !row.isOpen) + }} + /> + {row.cells.map((cell, cellIndex) => ( + + {cell.content} + + +
+ + {this.getExpandedRow(row.originalData)} + +
@@ -630,13 +648,9 @@ class MatchingRulesTable extends React.Component { sortBy: {}, rows: [], columns: [ - { - title: _("Matching Rule"), - transforms: [sortable], - cellFormatters: [expandable] - }, - { title: _("OID"), transforms: [sortable] }, - { title: _("Syntax"), transforms: [sortable] }, + { title: _("Matching Rule"), sortable: true }, + { title: _("OID"), sortable: true }, + { title: _("Syntax"), sortable: true }, ], }; @@ -649,7 +663,7 @@ class MatchingRulesTable extends React.Component { this.handlePerPageSelect = (_event, perPage) => { this.setState({ perPage, - page: 1 // reset page back to 1 + page: 1 }); }; @@ -658,41 +672,45 @@ class MatchingRulesTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - handleSort(_event, index, direction) { + handleSort(_event, columnIndex, direction) { const sorted_rows = []; const rows = []; let count = 0; - // Convert the rows pairings into a sortable array based on the column indexes + // Convert the rows pairings into a sortable array for (let idx = 0; idx < this.state.rows.length; idx += 2) { sorted_rows.push({ expandedRow: this.state.rows[idx + 1], - 1: this.state.rows[idx].cells[0], - 2: this.state.rows[idx].cells[1], - 3: this.state.rows[idx].cells[2], + 1: this.state.rows[idx].cells[0].content, + 2: this.state.rows[idx].cells[1].content, + 3: this.state.rows[idx].cells[2].content, }); } - // Sort the rows and build the new rows - sorted_rows.sort((a, b) => (a[index] > b[index]) ? 1 : -1); + sorted_rows.sort((a, b) => (a[columnIndex + 1] > b[columnIndex + 1]) ? 1 : -1); if (direction !== SortByDirection.asc) { sorted_rows.reverse(); } + for (const srow of sorted_rows) { rows.push({ isOpen: false, cells: [ - srow[1], srow[2], srow[2] + { content: srow[1] }, + { content: srow[2] }, + { content: srow[3] } ], }); - srow.expandedRow.parent = count; // reset parent idx - rows.push(srow.expandedRow); + rows.push({ + ...srow.expandedRow, + parent: count + }); count += 2; } this.setState({ sortBy: { - index, + index: columnIndex, direction }, rows, @@ -714,42 +732,42 @@ class MatchingRulesTable extends React.Component { ); } + handleCollapse(_event, rowIndex, isExpanding) { + const rows = [...this.state.rows]; + const index = (this.state.perPage * (this.state.page - 1) * 2) + rowIndex; + rows[index].isOpen = isExpanding; + this.setState({ rows }); + } + componentDidMount() { let rows = []; - let columns = this.state.columns; let count = 0; for (const row of this.props.rows) { rows.push( { isOpen: false, - cells: [{ title: row.name[0] }, row.oid[0], row.syntax[0]], + cells: [ + { content: row.name[0] }, + { content: row.oid[0] }, + { content: row.syntax[0] } + ], }, { parent: count, fullWidth: true, - cells: [{ title: this.getExpandedRow(row) }] + cells: [{ content: this.getExpandedRow(row) }] }, ); count += 2; } if (rows.length === 0) { - rows = [{ cells: ['No Matching Rules'] }]; - columns = [{ title: 'Matching Rules' }]; + rows = [{ cells: [{ content: 'No Matching Rules' }] }]; + this.setState({ + columns: [{ title: 'Matching Rules' }] + }); } - this.setState({ - rows, - columns - }); - } - - handleCollapse(event, rowKey, isOpen) { - const { rows, perPage, page } = this.state; - const index = (perPage * (page - 1) * 2) + rowKey; // Adjust for page set - rows[index].isOpen = isOpen; - this.setState({ - rows - }); + this.setState({ rows }); } handleSearchChange(event, value) { @@ -760,24 +778,28 @@ class MatchingRulesTable extends React.Component { const val = value.toLowerCase(); let name = ""; // Check for matches of all the parts - if (row.names.length > 0) { + if (row.names && row.names.length > 0) { name = row.name[0]; } - if (val !== "" && name.indexOf(val) === -1 && - row.oid[0].indexOf(val) === -1 && - row.syntax[0].indexOf(val) === -1) { + if (name.toLowerCase().indexOf(val) === -1 && + row.oid[0].toLowerCase().indexOf(val) === -1 && + row.syntax[0].toLowerCase().indexOf(val) === -1) { // Not a match continue; } rows.push( { isOpen: false, - cells: [{ title: name === "" ? <{_("No Name")}> : name }, row.oid[0], row.syntax[0]], + cells: [ + { content: name || <{_("No Name")}> }, + { content: row.oid[0] }, + { content: row.syntax[0] } + ], }, { parent: count, fullWidth: true, - cells: [{ title: this.getExpandedRow(row) }] + cells: [{ content: this.getExpandedRow(row) }] }, ); count += 2; @@ -792,14 +814,12 @@ class MatchingRulesTable extends React.Component { render() { const { perPage, page, sortBy, rows, columns } = this.state; - const origRows = [...rows]; const startIdx = ((perPage * page) - perPage) * 2; - const tableRows = origRows.splice(startIdx, perPage * 2); + const tableRows = rows.slice(startIdx, startIdx + (perPage * 2)); - for (let idx = 1, count = 0; idx < tableRows.length; idx += 2, count += 2) { - // Rewrite parent index to match new spliced array - tableRows[idx].parent = count; - } + // Filter out the expanded rows for the main table display + const displayRows = tableRows.filter((row, index) => index % 2 === 0); + const expandedContent = tableRows.filter((row, index) => index % 2 === 1); return (
@@ -815,23 +835,62 @@ class MatchingRulesTable extends React.Component { - - + + + + ))} + + + + {displayRows.map((row, rowIndex) => ( + + + + ))} + + {row.isOpen && ( + + + + )} + + ))} +
+ {columns.map((column, columnIndex) => ( + + {column.title} +
this.handleCollapse(null, rowIndex * 2, !row.isOpen) + }} + /> + {row.cells.map((cell, cellIndex) => ( + + {cell.content} +
+ + {expandedContent[rowIndex].cells[0].content} + +
diff --git a/src/cockpit/389-console/src/lib/security/securityTables.jsx b/src/cockpit/389-console/src/lib/security/securityTables.jsx index 6276caae35..e33727a563 100644 --- a/src/cockpit/389-console/src/lib/security/securityTables.jsx +++ b/src/cockpit/389-console/src/lib/security/securityTables.jsx @@ -9,16 +9,16 @@ import { Tooltip, } from '@patternfly/react-core'; import { - expandable, - TableVariant, - sortable, - SortByDirection + Table, + SortByDirection, + Thead, + Tr, + Th, + Tbody, + Td, + ActionsColumn, + ExpandableRowContent } from '@patternfly/react-table'; -import { - Table, - TableHeader, - TableBody -} from '@patternfly/react-table/deprecated'; import PropTypes from "prop-types"; const _ = cockpit.gettext; @@ -35,9 +35,9 @@ class KeyTable extends React.Component { rows: [], hasRows: false, columns: [ - { title: _("Cipher"), transforms: [sortable] }, - { title: _("Key Identifier"), transforms: [sortable] }, - { title: _("State"), transforms: [sortable] }, + { title: _("Cipher"), sortable: true }, + { title: _("Key Identifier"), sortable: true }, + { title: _("State"), sortable: true }, ], }; @@ -52,6 +52,8 @@ class KeyTable extends React.Component { perPage }); }; + + this.handleSort = this.handleSort.bind(this); } componentDidMount() { @@ -60,12 +62,11 @@ class KeyTable extends React.Component { let hasRows = true; for (const ServerKey of this.props.ServerKeys) { - rows.push( - { - isOpen: false, - cells: [ServerKey.attrs.cipher, ServerKey.attrs.key_id, ServerKey.attrs.state], - }, - ); + rows.push([ + ServerKey.attrs.cipher, + ServerKey.attrs.key_id, + ServerKey.attrs.state + ]); } if (rows.length === 0) { @@ -81,63 +82,107 @@ class KeyTable extends React.Component { }); } - actions() { - return [ - { - title: _("Delete Key"), - onClick: (event, rowId, rowData, extra) => { - if (rowData.cells[1]) { - this.props.delKey(rowData.cells[1]); - } + getActionsForRow = (rowData) => [ + { + title: _("Delete Key"), + onClick: () => { + if (rowData[1]) { + this.props.delKey(rowData[1]); } } - ]; + } + ]; + + handleSort(_event, index, direction) { + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); + + this.setState({ + sortBy: { + index, + direction + }, + rows: direction === SortByDirection.asc ? sortedRows : sortedRows.reverse() + }); } render() { const { perPage, page, sortBy, rows, columns, hasRows } = this.state; + const startIdx = (perPage * page) - perPage; + const tableRows = rows.slice(startIdx, startIdx + perPage); return (
-

- {_("An orphan key is a private key in the NSS DB for which there is NO cert with the corresponding public key. An orphan key is created during CSR creation, when the certificate associated with a CSR has been imported into the NSS DB its orphan state will be removed.")} -

- {_("Make sure an orphan key is not associated with a submitted CSR before you delete it.")} -

-
- } + content={ +
+

+ {_("An orphan key is a private key in the NSS DB for which there is NO cert with the corresponding public key. An orphan key is created during CSR creation, when the certificate associated with a CSR has been imported into the NSS DB its orphan state will be removed.")} +

+ {_("Make sure an orphan key is not associated with a submitted CSR before you delete it.")} +

+
+ } > {_("What is an orphan key?")} - - - + + + {columns.map((column, idx) => ( + + ))} + {hasRows && + + + {tableRows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + {hasRows && ( + + )} + + ))} +
+ {column.title} + } +
{cell}{cell} + +
{hasRows && } + /> + }
); } @@ -154,10 +199,10 @@ class CSRTable extends React.Component { sortBy: {}, rows: [], columns: [ - { title: _("Name"), transforms: [sortable] }, - { title: _("Subject DN"), transforms: [sortable] }, - { title: _("Subject Alternative Names"), transforms: [sortable] }, - { title: _("Modification Date"), transforms: [sortable] }, + { title: _("Name"), sortable: true }, + { title: _("Subject DN"), sortable: true }, + { title: _("Subject Alternative Names"), sortable: true }, + { title: _("Modification Date"), sortable: true }, ], }; @@ -179,7 +224,9 @@ class CSRTable extends React.Component { } handleSort(_event, index, direction) { - const sortedRows = this.state.rows.sort((a, b) => (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0)); + const sortedRows = [...this.state.rows].sort((a, b) => + (a[index] < b[index] ? -1 : a[index] > b[index] ? 1 : 0) + ); this.setState({ sortBy: { index, @@ -189,27 +236,37 @@ class CSRTable extends React.Component { }); } + getActionsForRow = (rowData) => [ + { + title: _("Delete CSR"), + onClick: () => this.props.delCSR(rowData[0]) + }, + { + title: _("View CSR"), + onClick: () => this.props.viewCSR(rowData[0]) + } + ]; + componentDidMount() { let rows = []; let columns = this.state.columns; let hasRows = true; for (const ServerCSR of this.props.ServerCSRs) { - rows.push( - { - isOpen: false, - cells: [ - ServerCSR.attrs.name, ServerCSR.attrs.subject, - ServerCSR.attrs.subject_alt_names.join(", "), ServerCSR.attrs.modified - ], - }, - ); + rows.push([ + ServerCSR.attrs.name, + ServerCSR.attrs.subject, + ServerCSR.attrs.subject_alt_names.join(", "), + ServerCSR.attrs.modified + ]); } + if (rows.length === 0) { rows = [{ cells: [_("No Certificate Signing Requests")] }]; columns = [{ title: _("Certificate Signing Requests") }]; hasRows = false; } + this.setState({ rows, columns, @@ -223,27 +280,19 @@ class CSRTable extends React.Component { for (const cert of this.props.ServerCSRs) { const val = value.toLowerCase(); - // Check for matches of all the parts if (val !== "" && cert.attrs.name.toLowerCase().indexOf(val) === -1 && cert.attrs.subject.toLowerCase().indexOf(val) === -1 && - cert.attrs.subject_alt_names.join().toLowerCase() - .indexOf(val) === -1 && + cert.attrs.subject_alt_names.join().toLowerCase().indexOf(val) === -1 && cert.attrs.modified.toLowerCase().indexOf(val) === -1) { - // Not a match continue; } - rows.push( - { - isOpen: false, - cells: [ - cert.attrs.name, cert.attrs.subject, - cert.attrs.subject_alt_names.join(", "), - cert.attrs.modified - ], - - }, - ); + rows.push([ + cert.attrs.name, + cert.attrs.subject, + cert.attrs.subject_alt_names.join(", "), + cert.attrs.modified + ]); } this.setState({ @@ -253,29 +302,9 @@ class CSRTable extends React.Component { }); } - actions() { - return [ - { - title: _("Delete CSR"), - onClick: (event, rowId, rowData, extra) => { - if (rowData.cells.length > 1) { - this.props.delCSR(rowData.cells[0]); - } - } - }, - { - title: _("View CSR"), - onClick: (event, rowId, rowData, extra) => { - if (rowData.cells.length > 1) { - this.props.viewCSR(rowData.cells[0]); - } - } - } - ]; - } - render() { const { perPage, page, sortBy, rows, columns, hasRows } = this.state; + const tableRows = rows.slice((page - 1) * perPage, page * perPage); return (
@@ -285,22 +314,52 @@ class CSRTable extends React.Component { value={this.state.value} onChange={this.handleSearchChange} onClear={(evt) => this.handleSearchChange(evt, '')} - />} - + } +
- - + + + {columns.map((column, idx) => ( + + ))} + {hasRows && + + + {tableRows.map((row, rowIndex) => ( + + {Array.isArray(row) ? ( + row.map((cell, cellIndex) => ( + + )) + ) : ( + row.cells.map((cell, cellIndex) => ( + + )) + )} + {hasRows && ( + + )} + + ))} +
+ {column.title} + } +
{cell}{cell} + +
{hasRows && } + /> + }
); } @@ -332,11 +392,10 @@ class CertTable extends React.Component { columns: [ { title: _("Nickname"), - transforms: [sortable], - cellFormatters: [expandable] + sortable: true }, - { title: _("Subject DN"), transforms: [sortable] }, - { title: _("Expiration Date"), transforms: [sortable] }, + { title: _("Subject DN"), sortable: true }, + { title: _("Expiration Date"), sortable: true }, ], }; @@ -358,45 +417,47 @@ class CertTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } - handleSort(_event, index, direction) { + handleSort(_event, columnIndex, direction) { const sorted_rows = []; const rows = []; let count = 0; - // Convert the rows pairings into a sortable array based on the column indexes + // Convert the rows pairings into a sortable array for (let idx = 0; idx < this.state.rows.length; idx += 2) { sorted_rows.push({ expandedRow: this.state.rows[idx + 1], - 1: this.state.rows[idx].cells[0], - 2: this.state.rows[idx].cells[1], - 3: this.state.rows[idx].cells[2], + 1: this.state.rows[idx].cells[0].content, + 2: this.state.rows[idx].cells[1].content, + 3: this.state.rows[idx].cells[2].content, issuer: this.state.rows[idx].issuer, flags: this.state.rows[idx].flags }); } - // Sort the rows and build the new rows - sorted_rows.sort((a, b) => (a[index] > b[index]) ? 1 : -1); + sorted_rows.sort((a, b) => (a[columnIndex + 1] > b[columnIndex + 1]) ? 1 : -1); if (direction !== SortByDirection.asc) { sorted_rows.reverse(); } + for (const srow of sorted_rows) { rows.push({ isOpen: false, cells: [ - srow[1], srow[2], srow[3] + { content: srow[1] }, + { content: srow[2] }, + { content: srow[3] } ], issuer: srow.issuer, flags: srow.flags, }); - srow.expandedRow.parent = count; // reset parent idx + srow.expandedRow.parent = count; rows.push(srow.expandedRow); count += 2; } this.setState({ sortBy: { - index, + index: columnIndex, direction }, rows, @@ -411,7 +472,6 @@ class CertTable extends React.Component { {issuer} {_("Trust Flags:")} {flags} - ); } @@ -423,24 +483,21 @@ class CertTable extends React.Component { let hasRows = true; for (const cert of this.props.certs) { - rows.push( - { - isOpen: false, - cells: [cert.attrs.nickname, cert.attrs.subject, cert.attrs.expires], - issuer: cert.attrs.issuer, - flags: cert.attrs.flags, - - }, - { - parent: count, - fullWidth: true, - cells: [{ title: this.getExpandedRow(cert.attrs.issuer, cert.attrs.flags) }] - }, - ); - count += 2; + rows.push({ + isOpen: false, + cells: [ + { content: cert.attrs.nickname }, + { content: cert.attrs.subject }, + { content: cert.attrs.expires } + ], + issuer: cert.attrs.issuer, + flags: cert.attrs.flags, + originalData: cert.attrs // Store the original data for expansion + }); + count += 1; } if (rows.length === 0) { - rows = [{ cells: [_("No Certificates")] }]; + rows = [{ cells: [{ content: _("No Certificates") }] }]; columns = [{ title: _("Certificates") }]; hasRows = false; } @@ -451,13 +508,11 @@ class CertTable extends React.Component { }); } - handleCollapse(event, rowKey, isOpen) { - const { rows, perPage, page } = this.state; - const index = (perPage * (page - 1) * 2) + rowKey; // Adjust for page set - rows[index].isOpen = isOpen; - this.setState({ - rows - }); + handleCollapse(_event, rowIndex, isExpanding) { + const rows = [...this.state.rows]; + const index = (this.state.perPage * (this.state.page - 1) * 2) + rowIndex; + rows[index].isOpen = isExpanding; + this.setState({ rows }); } handleSearchChange(event, value) { @@ -500,39 +555,28 @@ class CertTable extends React.Component { }); } - actions() { - return [ - { - title: _("Edit Trust Flags"), - onClick: (event, rowId, rowData, extra) => - this.props.editCert(rowData.cells[0], rowData.flags) - }, - { - title: _("Export Certificate"), - onClick: (event, rowId, rowData, extra) => - this.props.exportCert(rowData.cells[0]) - }, - { - isSeparator: true - }, - { - title: _("Delete Certificate"), - onClick: (event, rowId, rowData, extra) => - this.props.delCert(rowData.cells[0]) - } - ]; - } + getActionsForRow = (rowData) => [ + { + title: _("Edit Trust Flags"), + onClick: () => this.props.editCert(rowData.cells[0].content, rowData.flags) + }, + { + title: _("Export Certificate"), + onClick: () => this.props.exportCert(rowData.cells[0].content) + }, + { + isSeparator: true + }, + { + title: _("Delete Certificate"), + onClick: () => this.props.delCert(rowData.cells[0].content) + } + ]; render() { const { perPage, page, sortBy, rows, columns, hasRows } = this.state; - const origRows = [...rows]; const startIdx = ((perPage * page) - perPage) * 2; - const tableRows = origRows.splice(startIdx, perPage * 2); - - for (let idx = 1, count = 0; idx < tableRows.length; idx += 2, count += 2) { - // Rewrite parent index to match new spliced array - tableRows[idx].parent = count; - } + const tableRows = rows.slice(startIdx, startIdx + (perPage * 2)); return (
@@ -543,22 +587,62 @@ class CertTable extends React.Component { onChange={this.handleSearchChange} onClear={(evt) => this.handleSearchChange(evt, '')} />} - - - + + + + ))} + + + + {tableRows.map((row, rowIndex) => ( + + + + ))} + + + {row.isOpen && ( + + + + )} + + ))} +
+ {columns.map((column, columnIndex) => ( + + {column.title} + +
this.handleCollapse(null, rowIndex, !row.isOpen) + }} + /> + {row.cells.map((cell, cellIndex) => ( + + {cell.content} + + +
+ + {this.getExpandedRow(row.issuer, row.flags)} + +
{hasRows && } @@ -586,13 +670,12 @@ class CRLTable extends React.Component { value: '', sortBy: {}, rows: [], - dropdownIsOpen: false, hasRows: false, columns: [ - { title: _("Issued By"), transforms: [sortable] }, - { title: _("Effective Date"), transforms: [sortable] }, - { title: _("Next Update"), transforms: [sortable] }, - { title: _("Type"), transforms: [sortable] }, + { title: _("Issued By"), sortable: true }, + { title: _("Effective Date"), sortable: true }, + { title: _("Next Update"), sortable: true }, + { title: _("Type"), sortable: true }, ], }; @@ -612,37 +695,48 @@ class CRLTable extends React.Component { this.handleSearchChange = this.handleSearchChange.bind(this); } + getActionsForRow = (rowData) => [ + { + title: _("View CRL"), + onClick: () => this.props.editConfig(rowData.cells[0], rowData.cells[1], rowData.credsBindpw, rowData.pwInteractive) + }, + { + title: _("Delete CRL"), + onClick: () => this.props.deleteConfig(rowData.cells[0]) + } + ]; + handleSort(_event, index, direction) { const sorted_rows = []; const rows = []; let count = 0; - // Convert the rows pairings into a sortable array based on the column indexes + // Convert the rows pairings into a sortable array for (let idx = 0; idx < this.state.rows.length; idx += 2) { sorted_rows.push({ 1: this.state.rows[idx].cells[0], 2: this.state.rows[idx].cells[1], 3: this.state.rows[idx].cells[2], issuer: this.state.rows[idx].issuer, - flags: this.state.rows[idx].flags + flags: this.state.rows[idx].flags, + expandedRow: this.state.rows[idx + 1] }); } - // Sort the rows and build the new rows + // Sort and rebuild rows sorted_rows.sort((a, b) => (a[index] > b[index]) ? 1 : -1); if (direction !== SortByDirection.asc) { sorted_rows.reverse(); } + for (const srow of sorted_rows) { rows.push({ isOpen: false, - cells: [ - srow[1], srow[2], srow[3] - ], + cells: [srow[1], srow[2], srow[3]], issuer: srow.issuer, flags: srow.flags, }); - srow.expandedRow.parent = count; // reset parent idx + srow.expandedRow.parent = count; rows.push(srow.expandedRow); count += 2; } @@ -698,22 +792,12 @@ class CRLTable extends React.Component { }); } - actions() { - return [ - { - title: _("View CRL"), - onClick: (event, rowId, rowData, extra) => - this.props.editConfig(rowData.cells[0], rowData.cells[1], rowData.credsBindpw, rowData.pwInteractive) - }, - { - title: _("Delete CRL"), - onClick: (event, rowId, rowData, extra) => - this.props.deleteConfig(rowData.cells[0]) - } - ]; - } - render() { + const tableRows = this.state.rows.slice( + (this.state.page - 1) * this.state.perPage, + this.state.page * this.state.perPage + ); + return (
this.handleSearchChange(evt, '')} /> - - - + + + {this.state.columns.map((column, idx) => ( + + ))} + {this.state.hasRows && + + + {tableRows.map((row, rowIndex) => ( + + + {row.cells.map((cell, cellIndex) => ( + + ))} + {this.state.hasRows && ( + + )} + + {row.isOpen && ( + + + + )} + + ))} +
+ {column.title} + } +
{cell} + +
+ + {this.getExpandedRow(row.issuer, row.flags)} + +
- {this.state.hasRows && + {this.state.hasRows && ( } + /> + )}
); } diff --git a/src/cockpit/389-console/src/lib/server/accessLog.jsx b/src/cockpit/389-console/src/lib/server/accessLog.jsx index b93fe8427a..8d9866f0d2 100644 --- a/src/cockpit/389-console/src/lib/server/accessLog.jsx +++ b/src/cockpit/389-console/src/lib/server/accessLog.jsx @@ -24,13 +24,13 @@ import { TimePicker, } from "@patternfly/react-core"; import { - TableVariant + Table, + Thead, + Tr, + Th, + Tbody, + Td, } from '@patternfly/react-table'; -import { - Table, - TableHeader, - TableBody -} from '@patternfly/react-table/deprecated'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSyncAlt @@ -590,20 +590,31 @@ export class ServerAccessLog extends React.Component { this.handleOnToggle(event, isExpanded)} + onToggle={this.handleOnToggle} isExpanded={this.state.isExpanded} > - - - +
+ + + + + + + {this.state.rows.map((row, rowIndex) => ( + + + + ))} +
{this.state.columns[0].title}
+ this.handleOnSelect(_event, isSelecting, rowIndex), + isSelected: row.selected + }} + > + {row.cells[0].title} +
diff --git a/src/cockpit/389-console/src/lib/server/errorLog.jsx b/src/cockpit/389-console/src/lib/server/errorLog.jsx index b6e2add1f5..6e460d8516 100644 --- a/src/cockpit/389-console/src/lib/server/errorLog.jsx +++ b/src/cockpit/389-console/src/lib/server/errorLog.jsx @@ -24,13 +24,13 @@ import { TimePicker, } from "@patternfly/react-core"; import { - TableVariant + Table, + Thead, + Tr, + Th, + Tbody, + Td } from '@patternfly/react-table'; -import { - Table, - TableHeader, - TableBody -} from '@patternfly/react-table/deprecated'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSyncAlt @@ -502,14 +502,14 @@ export class ServerErrorLog extends React.Component { }, this.props.enableTree); } - handleOnSelect(event, isSelected, rowId) { + handleOnSelect = (_event, isSelected, rowIndex) => { let disableSaveBtn = true; const rows = [...this.state.rows]; + + // Update the selected row + rows[rowIndex].selected = isSelected; - // Update the row - rows[rowId].selected = isSelected; - - // Handle "save button" state, first check the other config settings + // Check other config settings for (const config_attr of settings_attrs) { if (this.state['_' + config_attr] !== this.state[config_attr]) { disableSaveBtn = false; @@ -517,14 +517,12 @@ export class ServerErrorLog extends React.Component { } } - // Handle the table contents + // Check table contents for (const row of rows) { for (const orig_row of this.state._rows) { - if (orig_row.level === row.level) { - if (orig_row.selected !== row.selected) { - disableSaveBtn = false; - break; - } + if (orig_row.level === row.level && orig_row.selected !== row.selected) { + disableSaveBtn = false; + break; } } } @@ -600,16 +598,30 @@ export class ServerErrorLog extends React.Component { isExpanded={this.state.isExpanded} > - - + + + + + + + {this.state.rows.map((row, rowIndex) => ( + + + + ))} +
{_("Logging Level")}
+ this.handleOnSelect(_event, isSelecting, rowIndex), + isSelected: row.selected + }} + > + {row.cells[0].title} +
diff --git a/src/cockpit/389-console/src/lib/server/securityLog.jsx b/src/cockpit/389-console/src/lib/server/securityLog.jsx index 2fac4c91ab..92103c6d76 100644 --- a/src/cockpit/389-console/src/lib/server/securityLog.jsx +++ b/src/cockpit/389-console/src/lib/server/securityLog.jsx @@ -23,14 +23,6 @@ import { TextVariants, TimePicker, } from "@patternfly/react-core"; -import { - TableVariant -} from '@patternfly/react-table'; -import { - Table, - TableHeader, - TableBody -} from '@patternfly/react-table/deprecated'; import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; import { faSyncAlt @@ -85,16 +77,6 @@ export class ServerSecurityLog extends React.Component { saveRotationDisabled: true, saveExpDisabled: true, attrs: this.props.attrs, - canSelectAll: false, - isExpanded: false, - rows: [ - { cells: ['Default Logging'], level: 256, selected: true }, - { cells: ['Internal Operations'], level: 4, selected: false }, - { cells: ['Entry Security and Referrals'], level: 512, selected: false } - ], - columns: [ - { title: _("Logging Level") }, - ], }; // Toggle currently active tab @@ -104,12 +86,6 @@ export class ServerSecurityLog extends React.Component { }); }; - this.handleOnToggle = (_event, isExpanded) => { - this.setState({ - isExpanded - }); - }; - this.handleChange = this.handleChange.bind(this); this.handleSwitchChange = this.handleSwitchChange.bind(this); this.handleTimeChange = this.handleTimeChange.bind(this); @@ -582,26 +558,6 @@ export class ServerSecurityLog extends React.Component { label={_("Security Log Buffering Enabled")} /> - this.handleOnToggle(event, isExpanded)} - isExpanded={this.state.isExpanded} - > - - - -
-
-