Fleet UI: Allow DataSet value to wrap, apply to policy (#46733)
This commit is contained in:
@@ -0,0 +1 @@
|
||||
* Long policy resolution text now wraps on the policy details page instead of being truncated.
|
||||
@@ -1,3 +1,4 @@
|
||||
import React from "react";
|
||||
import { Meta, StoryObj } from "@storybook/react";
|
||||
|
||||
import DataSet from "./DataSet";
|
||||
@@ -22,3 +23,19 @@ export const HorizontalOrientation: Story = {
|
||||
orientation: "horizontal",
|
||||
},
|
||||
};
|
||||
|
||||
// Multiline values wrap instead of truncating with an ellipsis. Use for
|
||||
// free-form prose like "Resolve" or "Description".
|
||||
export const Multiline: Story = {
|
||||
args: {
|
||||
title: "Resolve",
|
||||
value:
|
||||
"Re-enable FileVault on the device. Open System Settings, navigate to Privacy & Security, and turn on FileVault. Store the recovery key in a safe place.",
|
||||
multiline: true,
|
||||
},
|
||||
decorators: [
|
||||
(Story) => (
|
||||
<div style={{ maxWidth: "320px", padding: "16px" }}>{Story()}</div>
|
||||
),
|
||||
],
|
||||
};
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
|
||||
import DataSet from "./DataSet";
|
||||
|
||||
describe("DataSet", () => {
|
||||
it("renders title and value", () => {
|
||||
render(<DataSet title="Author" value="Alice" />);
|
||||
expect(screen.getByText("Author")).toBeInTheDocument();
|
||||
expect(screen.getByText("Alice")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("uses vertical orientation by default (no horizontal class, no colon)", () => {
|
||||
const { container } = render(<DataSet title="Author" value="Alice" />);
|
||||
expect(container.querySelector(".data-set__horizontal")).toBeNull();
|
||||
expect(container.querySelector("dt")?.textContent).toBe("Author");
|
||||
});
|
||||
|
||||
it("applies horizontal orientation class and appends a colon to the title", () => {
|
||||
const { container } = render(
|
||||
<DataSet title="Author" value="Alice" orientation="horizontal" />
|
||||
);
|
||||
expect(
|
||||
container.querySelector(".data-set__horizontal")
|
||||
).toBeInTheDocument();
|
||||
expect(container.querySelector("dt")?.textContent).toBe("Author:");
|
||||
});
|
||||
|
||||
it("applies the text-only modifier when textOnly is set", () => {
|
||||
const { container } = render(
|
||||
<DataSet title="Author" value="Alice" textOnly />
|
||||
);
|
||||
expect(container.querySelector(".data-set--text-only")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("applies the multiline modifier when multiline is set", () => {
|
||||
const { container } = render(
|
||||
<DataSet title="Resolve" value="Long remediation text." multiline />
|
||||
);
|
||||
expect(container.querySelector(".data-set--multiline")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not apply the multiline modifier by default", () => {
|
||||
const { container } = render(<DataSet title="Author" value="Alice" />);
|
||||
expect(container.querySelector(".data-set--multiline")).toBeNull();
|
||||
});
|
||||
|
||||
it("merges a custom className alongside the base class", () => {
|
||||
const { container } = render(
|
||||
<DataSet title="Author" value="Alice" className="custom-class" />
|
||||
);
|
||||
const root = container.firstChild as HTMLElement;
|
||||
expect(root).toHaveClass("data-set");
|
||||
expect(root).toHaveClass("custom-class");
|
||||
});
|
||||
});
|
||||
@@ -13,6 +13,12 @@ interface IDataSetProps {
|
||||
* baseline. Do NOT use when the value contains icons, buttons, or status
|
||||
* indicators that need vertical centering. */
|
||||
textOnly?: boolean;
|
||||
/** When true, the value wraps onto multiple lines instead of truncating
|
||||
* with an ellipsis. Use for free-form prose like "Resolve" or
|
||||
* "Description" where the full text needs to be readable. Default behavior
|
||||
* (single-line truncation with ellipsis) assumes the consumer wraps the
|
||||
* value in a tooltip-on-truncate helper. */
|
||||
multiline?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
@@ -21,11 +27,13 @@ const DataSet = ({
|
||||
value,
|
||||
orientation = "vertical",
|
||||
textOnly = false,
|
||||
multiline = false,
|
||||
className,
|
||||
}: IDataSetProps) => {
|
||||
const classNames = classnames(baseClass, className, {
|
||||
[`${baseClass}__horizontal`]: orientation === "horizontal",
|
||||
[`${baseClass}--text-only`]: textOnly,
|
||||
[`${baseClass}--multiline`]: multiline,
|
||||
});
|
||||
|
||||
return (
|
||||
|
||||
@@ -23,6 +23,12 @@
|
||||
align-items: baseline;
|
||||
}
|
||||
|
||||
&--multiline dd {
|
||||
white-space: pre-wrap;
|
||||
overflow: visible;
|
||||
overflow-wrap: anywhere;
|
||||
}
|
||||
|
||||
&__horizontal {
|
||||
flex-direction: row;
|
||||
}
|
||||
|
||||
@@ -426,6 +426,7 @@ const PolicyDetailsPage = ({
|
||||
className={`${baseClass}__resolve`}
|
||||
title="Resolve"
|
||||
value={lastEditedQueryResolution}
|
||||
multiline
|
||||
/>
|
||||
)}
|
||||
{renderAuthor()}
|
||||
|
||||
Reference in New Issue
Block a user