UI: Maintain header titles, remove "select all," "clear selection" options and selected item count from Select software table (#33301)
## For #33277 <img width="1046" height="821" alt="Screenshot 2025-09-22 at 4 26 20 PM" src="https://github.com/user-attachments/assets/d2e20d88-9795-42c3-91de-d3e7f98b2b6e" /> - [x] QA'd all new/changed functionality manually --------- Co-authored-by: Jacob Shandling <jacob@fleetdm.com>
This commit is contained in:
co-authored by
Jacob Shandling
parent
477f3cbaec
commit
5893b8186b
@@ -80,6 +80,7 @@ interface IDataTableProps {
|
||||
renderPagination?: () => JSX.Element | null;
|
||||
setExportRows?: (rows: Row[]) => void;
|
||||
onClearSelection?: () => void;
|
||||
suppressHeaderActions?: boolean;
|
||||
}
|
||||
|
||||
interface IHeaderGroup extends HeaderGroup {
|
||||
@@ -126,6 +127,7 @@ const DataTable = ({
|
||||
renderPagination,
|
||||
setExportRows,
|
||||
onClearSelection = noop,
|
||||
suppressHeaderActions,
|
||||
}: IDataTableProps): JSX.Element => {
|
||||
// used to track the initial mount of the component.
|
||||
const isInitialRender = useRef(true);
|
||||
@@ -515,6 +517,47 @@ const DataTable = ({
|
||||
"is-observer": isOnlyObserver,
|
||||
});
|
||||
|
||||
const renderHeaderWithActions = () => (
|
||||
<thead className="active-selection">
|
||||
<tr {...headerGroups[0].getHeaderGroupProps()}>
|
||||
<th
|
||||
className="active-selection__checkbox"
|
||||
{...headerGroups[0].headers[0].getHeaderProps(
|
||||
headerGroups[0].headers[0].getSortByToggleProps({
|
||||
title: null,
|
||||
})
|
||||
)}
|
||||
>
|
||||
{headerGroups[0].headers[0].render("Header")}
|
||||
</th>
|
||||
<th className="active-selection__container">
|
||||
<div className="active-selection__inner">
|
||||
{renderSelectedCount()}
|
||||
<div className="active-selection__inner-left">
|
||||
{secondarySelectActions && renderSecondarySelectActions()}
|
||||
</div>
|
||||
<div className="active-selection__inner-right">
|
||||
{primarySelectAction && renderPrimarySelectAction()}
|
||||
</div>
|
||||
{toggleAllPagesSelected && renderAreAllSelected()}
|
||||
{shouldRenderToggleAllPages && (
|
||||
<Button
|
||||
onClick={onToggleAllPagesClick}
|
||||
variant="text-link"
|
||||
className="light-text"
|
||||
>
|
||||
<>Select all matching {resultsTitle}</>
|
||||
</Button>
|
||||
)}
|
||||
<Button onClick={onClearSelectionClick} variant="text-link">
|
||||
Clear selection
|
||||
</Button>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
{isLoading && (
|
||||
@@ -524,46 +567,9 @@ const DataTable = ({
|
||||
)}
|
||||
<div className="data-table data-table__wrapper">
|
||||
<table className={tableStyles}>
|
||||
{Object.keys(selectedRowIds).length !== 0 && (
|
||||
<thead className="active-selection">
|
||||
<tr {...headerGroups[0].getHeaderGroupProps()}>
|
||||
<th
|
||||
className="active-selection__checkbox"
|
||||
{...headerGroups[0].headers[0].getHeaderProps(
|
||||
headerGroups[0].headers[0].getSortByToggleProps({
|
||||
title: null,
|
||||
})
|
||||
)}
|
||||
>
|
||||
{headerGroups[0].headers[0].render("Header")}
|
||||
</th>
|
||||
<th className="active-selection__container">
|
||||
<div className="active-selection__inner">
|
||||
{renderSelectedCount()}
|
||||
<div className="active-selection__inner-left">
|
||||
{secondarySelectActions && renderSecondarySelectActions()}
|
||||
</div>
|
||||
<div className="active-selection__inner-right">
|
||||
{primarySelectAction && renderPrimarySelectAction()}
|
||||
</div>
|
||||
{toggleAllPagesSelected && renderAreAllSelected()}
|
||||
{shouldRenderToggleAllPages && (
|
||||
<Button
|
||||
onClick={onToggleAllPagesClick}
|
||||
variant="text-link"
|
||||
className="light-text"
|
||||
>
|
||||
<>Select all matching {resultsTitle}</>
|
||||
</Button>
|
||||
)}
|
||||
<Button onClick={onClearSelectionClick} variant="text-link">
|
||||
Clear selection
|
||||
</Button>
|
||||
</div>
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
)}
|
||||
{!suppressHeaderActions &&
|
||||
Object.keys(selectedRowIds).length !== 0 &&
|
||||
renderHeaderWithActions()}
|
||||
<thead>
|
||||
{headerGroups.map((headerGroup) => (
|
||||
<tr {...headerGroup.getHeaderGroupProps()}>
|
||||
|
||||
@@ -123,6 +123,8 @@ interface ITableContainerProps<T = any> {
|
||||
hideFooter?: boolean;
|
||||
/** handler called when the `clear selection` button is called */
|
||||
onClearSelection?: () => void;
|
||||
/** don't show the Clear selection button and selected item count when items are selected */
|
||||
suppressHeaderActions?: boolean;
|
||||
}
|
||||
|
||||
const baseClass = "table-container";
|
||||
@@ -184,6 +186,7 @@ const TableContainer = <T,>({
|
||||
disableTableHeader,
|
||||
persistSelectedRows,
|
||||
onClearSelection = noop,
|
||||
suppressHeaderActions,
|
||||
}: ITableContainerProps<T>) => {
|
||||
const isControlledSearchQuery = controlledSearchQuery !== undefined;
|
||||
const [searchQuery, setSearchQuery] = useState(defaultSearchQuery);
|
||||
@@ -574,6 +577,7 @@ const TableContainer = <T,>({
|
||||
}
|
||||
setExportRows={setExportRows}
|
||||
onClearSelection={onClearSelection}
|
||||
suppressHeaderActions={suppressHeaderActions}
|
||||
persistSelectedRows={persistSelectedRows}
|
||||
hideFooter={hideFooter}
|
||||
/>
|
||||
|
||||
-8
@@ -76,13 +76,6 @@ const SelectSoftwareModal = ({
|
||||
});
|
||||
}, []);
|
||||
|
||||
const onChangeSelectAll = useCallback(
|
||||
(selectAll: boolean) => {
|
||||
setSelectedSoftwareIds(selectAll ? softwareTitles.map((s) => s.id) : []);
|
||||
},
|
||||
[softwareTitles]
|
||||
);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
className={baseClass}
|
||||
@@ -94,7 +87,6 @@ const SelectSoftwareModal = ({
|
||||
<SelectSoftwareTable
|
||||
softwareTitles={softwareTitles}
|
||||
onChangeSoftwareSelect={onChangeSoftwareSelect}
|
||||
onChangeSelectAll={onChangeSelectAll}
|
||||
platform={platform}
|
||||
/>
|
||||
<div className="modal-cta-wrap">
|
||||
|
||||
+3
-9
@@ -26,23 +26,17 @@ const generateSelectedRows = (softwareTitles: ISoftwareTitle[]) => {
|
||||
interface ISelectSoftwareTableProps {
|
||||
softwareTitles: ISoftwareTitle[];
|
||||
onChangeSoftwareSelect: (select: boolean, id: number) => void;
|
||||
onChangeSelectAll: (selectAll: boolean) => void;
|
||||
platform: SetupExperiencePlatform;
|
||||
}
|
||||
|
||||
const SelectSoftwareTable = ({
|
||||
softwareTitles,
|
||||
onChangeSoftwareSelect,
|
||||
onChangeSelectAll,
|
||||
platform,
|
||||
}: ISelectSoftwareTableProps) => {
|
||||
const tableConfig = useMemo(() => {
|
||||
return generateTableConfig(
|
||||
platform,
|
||||
onChangeSelectAll,
|
||||
onChangeSoftwareSelect
|
||||
);
|
||||
}, [onChangeSelectAll, onChangeSoftwareSelect, platform]);
|
||||
return generateTableConfig(platform, onChangeSoftwareSelect);
|
||||
}, [onChangeSoftwareSelect, platform]);
|
||||
|
||||
const initialSelectedSoftwareRows = useMemo(() => {
|
||||
return generateSelectedRows(softwareTitles);
|
||||
@@ -78,7 +72,6 @@ const SelectSoftwareTable = ({
|
||||
searchable
|
||||
searchQueryColumn="name"
|
||||
isClientSideFilter
|
||||
onClearSelection={() => onChangeSelectAll(false)}
|
||||
renderTableHelpText={() => (
|
||||
<p className={`${baseClass}__help-text`}>
|
||||
Software will be installed on{" "}
|
||||
@@ -87,6 +80,7 @@ const SelectSoftwareTable = ({
|
||||
experience.
|
||||
</p>
|
||||
)}
|
||||
suppressHeaderActions
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
+1
-28
@@ -1,7 +1,7 @@
|
||||
import React from "react";
|
||||
import { CellProps, Column } from "react-table";
|
||||
|
||||
import { IHeaderProps, IStringCellProps } from "interfaces/datatable_config";
|
||||
import { IStringCellProps } from "interfaces/datatable_config";
|
||||
import { ISoftwareTitle, SoftwareSource } from "interfaces/software";
|
||||
|
||||
import TextCell from "components/TableContainer/DataTable/TextCell";
|
||||
@@ -13,7 +13,6 @@ import { SetupExperiencePlatform } from "interfaces/platform";
|
||||
import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants";
|
||||
|
||||
type ISelectSoftwareTableConfig = Column<ISoftwareTitle>;
|
||||
type ITableHeaderProps = IHeaderProps<ISoftwareTitle>;
|
||||
type ITableStringCellProps = IStringCellProps<ISoftwareTitle>;
|
||||
type ISelectionCellProps = CellProps<ISoftwareTitle>;
|
||||
|
||||
@@ -32,38 +31,12 @@ const getSetupExperienceLinuxPackageCopy = (source: SoftwareSource) => {
|
||||
|
||||
const generateTableConfig = (
|
||||
platform: SetupExperiencePlatform,
|
||||
onSelectAll: (selectAll: boolean) => void,
|
||||
onSelectSoftware: (select: boolean, id: number) => void
|
||||
): ISelectSoftwareTableConfig[] => {
|
||||
const headerConfigs: ISelectSoftwareTableConfig[] = [
|
||||
{
|
||||
id: "selection",
|
||||
disableSortBy: true,
|
||||
Header: (cellProps: ITableHeaderProps) => {
|
||||
const {
|
||||
checked,
|
||||
indeterminate,
|
||||
} = cellProps.getToggleAllRowsSelectedProps();
|
||||
|
||||
const checkboxProps = {
|
||||
value: checked,
|
||||
indeterminate,
|
||||
onChange: () => {
|
||||
onSelectAll(!checked);
|
||||
cellProps.toggleAllRowsSelected();
|
||||
},
|
||||
};
|
||||
return (
|
||||
<GitOpsModeTooltipWrapper
|
||||
position="right"
|
||||
tipOffset={6}
|
||||
fixedPositionStrategy
|
||||
renderChildren={(disableChildren) => (
|
||||
<Checkbox disabled={disableChildren} {...checkboxProps} />
|
||||
)}
|
||||
/>
|
||||
);
|
||||
},
|
||||
Cell: (cellProps: ISelectionCellProps) => {
|
||||
const { checked } = cellProps.row.getToggleRowSelectedProps();
|
||||
const checkboxProps = {
|
||||
|
||||
Reference in New Issue
Block a user