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:
co-authored by
Jacob Shandling
parent
39f5583e00
commit
0b45afcaa8
@@ -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} />;
|
||||
},
|
||||
|
||||
+1
-1
@@ -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) => {
|
||||
|
||||
+1
-1
@@ -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" />
|
||||
),
|
||||
},
|
||||
{
|
||||
|
||||
+1
-1
@@ -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 />;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
+1
-1
@@ -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];
|
||||
|
||||
Reference in New Issue
Block a user