UI - update empty styles in 5 places (#20079)

## Addresses #19557 
<img width="143" alt="Screenshot 2024-06-27 at 1 44 12 PM"
src="https://github.com/fleetdm/fleet/assets/61553566/e9ad83b2-dda4-4972-b8c2-412389e45823">
<img width="177" alt="Screenshot 2024-06-27 at 1 44 25 PM"
src="https://github.com/fleetdm/fleet/assets/61553566/bb5f808e-0d5a-47cc-84ed-f55797caebfe">
<img width="210" alt="Screenshot 2024-06-27 at 1 49 47 PM"
src="https://github.com/fleetdm/fleet/assets/61553566/2dff046b-6cfa-45fa-8a0c-93ab46e2c8a9">
<img width="194" alt="Screenshot 2024-06-27 at 1 56 56 PM"
src="https://github.com/fleetdm/fleet/assets/61553566/fdaaeac8-e944-427b-917e-87b98ae763b9">
<img width="238" alt="Screenshot 2024-06-27 at 4 39 22 PM"
src="https://github.com/fleetdm/fleet/assets/61553566/bb774af5-07c0-44b6-994f-dc787c5bf606">

- [x] Changes file added for user-visible changes in `changes/`,
- [x] Manual QA for all new/changed functionality

---------

Co-authored-by: Jacob Shandling <jacob@fleetdm.com>
This commit is contained in:
jacobshandling
2024-07-03 09:40:03 -07:00
committed by GitHub
co-authored by Jacob Shandling
parent 39f5583e00
commit 0b45afcaa8
14 changed files with 56 additions and 70 deletions
+1
View File
@@ -0,0 +1 @@
* Update empty state styles in 4 places, clean up
@@ -1,26 +1,26 @@
import classnames from "classnames";
import { uniqueId } from "lodash";
import React from "react";
import ReactTooltip from "react-tooltip";
import { COLORS } from "styles/var/colors";
import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants";
const baseClass = "text-cell";
interface ITextCellProps {
value?: string | number | boolean | { timeString: string } | null;
formatter?: (val: any) => React.ReactNode; // string, number, or null
/** adds a greyed styling to the cell. This will italicise and add a grey
* color to the cell text.
* @default false
*/
greyed?: boolean;
classes?: string;
grey?: boolean;
italic?: boolean;
className?: string;
emptyCellTooltipText?: React.ReactNode;
}
const TextCell = ({
value,
formatter = (val) => val, // identity function if no formatter is provided
greyed = false,
classes = "w250",
grey = false,
italic = false,
className = "w250",
emptyCellTooltipText,
}: ITextCellProps) => {
let val = value;
@@ -43,7 +43,7 @@ const TextCell = ({
formattedValue === "";
if (isEmptyValue) {
greyed = true;
[grey, italic] = [true, true];
}
const renderEmptyCell = () => {
@@ -70,11 +70,11 @@ const TextCell = ({
const cellText = isEmptyValue ? renderEmptyCell() : formattedValue;
return (
<span className={`text-cell ${classes} ${greyed ? "grey-cell" : ""}`}>
{cellText}
</span>
);
const cellClasses = classnames(baseClass, className, {
"grey-cell": grey,
"italic-cell": italic,
});
return <span className={cellClasses}>{cellText}</span>;
};
export default TextCell;
@@ -276,13 +276,15 @@ $shadow-transition-width: 10px;
min-width: 100%;
text-align: left;
}
.grey-cell {
color: $ui-fleet-black-50;
.italic-cell {
font-style: italic;
.__react_component_tooltip {
font-style: normal;
}
}
.grey-cell {
color: $ui-fleet-black-50;
}
}
.disable-highlight:hover {
@@ -108,7 +108,7 @@ const generateDefaultTableHeaders = (
Cell: (cellProps: IVulnCellProps) => {
const platform = cellProps.row.original.platform;
if (platform !== "darwin" && platform !== "windows") {
return <TextCell value="Not supported" greyed />;
return <TextCell value="Not supported" grey italic />;
}
return <VulnerabilitiesCell vulnerabilities={cellProps.cell.value} />;
},
@@ -73,7 +73,7 @@ export const generateSolutionsTableHeaders = (
accessor: "hosts_count",
Cell: (cellProps: ICellProps) => (
<div className="host-count-cell">
<TextCell value={cellProps.cell.value} classes="" />
<TextCell value={cellProps.cell.value} className="" />
<ViewAllHostsLink
queryParams={{ mdm_id: cellProps.row.original.id, team_id: teamId }}
className="view-mdm-solution-link"
@@ -3,15 +3,13 @@ import React from "react";
import TextCell from "components/TableContainer/DataTable/TextCell";
import TooltipWrapper from "components/TooltipWrapper";
const baseClass = "version-cell";
const generateText = <T extends { version: string }>(versions: T[] | null) => {
if (!versions) {
return <TextCell value="---" greyed />;
return <TextCell value="---" grey italic />;
}
const text =
versions.length !== 1 ? `${versions.length} versions` : versions[0].version;
return <TextCell value={text} greyed={versions.length !== 1} />;
return <TextCell value={text} italic={versions.length !== 1} />;
};
interface IVersionCellProps<T extends { version: string }> {
@@ -29,11 +27,7 @@ const VersionCell = <T extends { version: string }>({
return (
<TooltipWrapper
tipContent={
<p className={`${baseClass}__versions`}>
{versions.map((version) => version.version).join(", ")}
</p>
}
tipContent={<>{versions.map((version) => version.version).join(", ")}</>}
tipOffset={14}
position="top"
showArrow
@@ -13,15 +13,15 @@ const generateCell = (
vulnerabilities: ISoftwareVulnerability[] | string[] | null
) => {
if (vulnerabilities === null) {
return <TextCell value="---" greyed />;
return <TextCell value="---" grey italic />;
}
let text = "";
let isGrayed = true;
let italicize = true;
if (vulnerabilities.length === 0) {
text = "---";
} else if (vulnerabilities.length === 1) {
isGrayed = false;
italicize = false;
text =
typeof vulnerabilities[0] === "string"
? vulnerabilities[0]
@@ -30,7 +30,7 @@ const generateCell = (
text = `${vulnerabilities.length} vulnerabilities`;
}
return <TextCell value={text} greyed={isGrayed} />;
return <TextCell value={text} italic={italicize} />;
};
const getName = (vulnerabiltiy: ISoftwareVulnerability | string) => {
@@ -90,7 +90,7 @@ const generateTableHeaders = (
sortType: "caseInsensitive",
accessor: "name",
Cell: (cellProps: ICellProps) => (
<TextCell value={cellProps.cell.value} classes="w400" />
<TextCell value={cellProps.cell.value} className="w400" />
),
},
{
@@ -166,7 +166,7 @@ const generateColumnConfigs = (
disableSortBy: true,
accessor: "email",
Cell: (cellProps: ICellProps) => (
<TextCell classes="w400" value={cellProps.cell.value} />
<TextCell className="w400" value={cellProps.cell.value} />
),
},
{
@@ -163,10 +163,12 @@ const generateTableHeaders = (
</TooltipWrapper>
);
}
const greyAndItalic = greyCell(cellProps.cell.value);
return (
<TextCell
value={cellProps.cell.value}
greyed={greyCell(cellProps.cell.value)}
grey={greyAndItalic}
italic={greyAndItalic}
/>
);
},
@@ -210,7 +212,7 @@ const generateTableHeaders = (
},
];
// Add Teams tab for premium tier only
// Add Teams column for premium tier
if (isPremiumTier) {
tableHeaders.splice(2, 0, {
title: "Teams",
@@ -218,10 +220,7 @@ const generateTableHeaders = (
accessor: "teams",
disableSortBy: true,
Cell: (cellProps: ICellProps) => (
<TextCell
value={cellProps.cell.value}
greyed={greyCell(cellProps.cell.value)}
/>
<TextCell value={cellProps.cell.value} />
),
});
}
@@ -345,34 +345,23 @@ const allHostTableHeaders: IHostTableColumnConfig[] = [
Cell: (cellProps: IDeviceUserCellProps) => {
const numUsers = cellProps.cell.value?.length || 0;
const users = condenseDeviceUsers(cellProps.cell.value || []);
if (users.length) {
const tooltipText = tooltipTextWithLineBreaks(users);
if (users.length > 1) {
return (
<>
<span
className={`text-cell ${
users.length > 1 ? "text-muted tooltip" : ""
}`}
data-tip
data-for={`device_mapping__${cellProps.row.original.id}`}
data-tip-disable={users.length <= 1}
>
{numUsers === 1 ? users[0] : `${numUsers} users`}
</span>
<ReactTooltip
effect="solid"
backgroundColor={COLORS["tooltip-bg"]}
id={`device_mapping__${cellProps.row.original.id}`}
data-html
clickable
delayHide={300}
>
<span className={`tooltip__tooltip-text`}>{tooltipText}</span>
</ReactTooltip>
</>
<TooltipWrapper
tipContent={tooltipTextWithLineBreaks(users)}
underline={false}
showArrow
position="top"
tipOffset={10}
>
<TextCell italic value={`${numUsers} users`} />
</TooltipWrapper>
);
}
return <span className="text-muted">{DEFAULT_EMPTY_CELL_VALUE}</span>;
if (users.length === 1) {
return <TextCell value={users[0]} />;
}
return <TextCell />;
},
},
{
@@ -55,7 +55,7 @@ const generateTableConfig = (
return (
<TextCell
value={cellProps.cell.value}
classes="os-settings-name-cell"
className="os-settings-name-cell"
/>
);
},
@@ -34,7 +34,7 @@ const ReportUpdatedCell = ({
// query runs, sends results to a logging dest, doesn't cache
return (
<TextCell
classes={`${baseClass}__value no-report`}
className={`${baseClass}__value no-report`}
formatter={(val) => {
const tooltipId = uniqueId();
return (
@@ -87,8 +87,9 @@ const ReportUpdatedCell = ({
</ReactTooltip>
</>
)}
greyed
classes={`${baseClass}__value`}
grey
italic
className={`${baseClass}__value`}
/>
);
}
@@ -101,7 +102,7 @@ const ReportUpdatedCell = ({
// last_fetched will be truthy at this point
value={{ timeString: last_fetched ?? "" }}
formatter={HumanTimeDiffWithFleetLaunchCutoff}
classes={`${baseClass}__value`}
className={`${baseClass}__value`}
/>
</>
);
@@ -96,7 +96,7 @@ const InstallStatusCell = ({
} else if (softwareName) {
displayStatus = "avaiableForInstall";
} else {
return <TextCell value="---" greyed />;
return <TextCell value="---" grey italic />;
}
const displayConfig = INSTALL_STATUS_DISPLAY_OPTIONS[displayStatus];