mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
Refactor Tooltip Wrapper (#13845)
This commit is contained in:
parent
b112505bf1
commit
bf8504a028
71 changed files with 735 additions and 544 deletions
|
|
@ -239,7 +239,7 @@ const DownloadInstallers = ({
|
|||
Include
|
||||
<TooltipWrapper
|
||||
tipContent={
|
||||
"<p>Include Fleet Desktop if your’re adding workstations.</p>"
|
||||
<p>Include Fleet Desktop if you're adding workstations.</p>
|
||||
}
|
||||
>
|
||||
Fleet Desktop
|
||||
|
|
|
|||
|
|
@ -538,7 +538,7 @@ const PlatformWrapper = ({
|
|||
Include
|
||||
<TooltipWrapper
|
||||
tipContent={
|
||||
"Include Fleet Desktop if your’re adding workstations."
|
||||
"Include Fleet Desktop if you're adding workstations."
|
||||
}
|
||||
>
|
||||
Fleet Desktop
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { renderWithSetup } from "test/test-utils";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
|
||||
import LastUpdatedText from ".";
|
||||
|
||||
|
|
@ -27,11 +26,9 @@ describe("Last updated text", () => {
|
|||
});
|
||||
|
||||
it("renders tooltip on hover", async () => {
|
||||
const { user } = renderWithSetup(
|
||||
<LastUpdatedText whatToRetrieve="software" />
|
||||
);
|
||||
render(<LastUpdatedText whatToRetrieve="software" />);
|
||||
|
||||
await user.hover(screen.getByText("Updated never"));
|
||||
await fireEvent.mouseEnter(screen.getByText("Updated never"));
|
||||
|
||||
expect(screen.getByText(/to retrieve software/i)).toBeInTheDocument();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -27,7 +27,12 @@ const LastUpdatedText = ({
|
|||
return (
|
||||
<span className={baseClass}>
|
||||
<TooltipWrapper
|
||||
tipContent={`Fleet periodically queries all hosts <br />to retrieve ${whatToRetrieve}.`}
|
||||
tipContent={
|
||||
<>
|
||||
Fleet periodically queries all hosts <br />
|
||||
to retrieve {whatToRetrieve}.
|
||||
</>
|
||||
}
|
||||
>
|
||||
{`Updated ${lastUpdatedAt}`}
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -399,7 +399,13 @@ const SelectTargets = ({
|
|||
{onlinePercentage()}
|
||||
%
|
||||
<TooltipWrapper
|
||||
tipContent={`Hosts are online if they<br /> have recently checked <br />into Fleet.`}
|
||||
tipContent={
|
||||
<>
|
||||
Hosts are online if they <br />
|
||||
have recently checked <br />
|
||||
into Fleet.
|
||||
</>
|
||||
}
|
||||
>
|
||||
online
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -49,30 +49,62 @@ const LogDestinationIndicator = ({
|
|||
const tooltipText = () => {
|
||||
switch (logDestination) {
|
||||
case "filesystem":
|
||||
return `Each time a query runs, the data is sent to <br />
|
||||
return (
|
||||
<>
|
||||
Each time a query runs, the data is sent to <br />
|
||||
/var/log/osquery/osqueryd.snapshots.log <br />
|
||||
in each host's filesystem.`;
|
||||
in each host's filesystem.
|
||||
</>
|
||||
);
|
||||
case "firehose":
|
||||
return `Each time a query runs, the data is sent to <br />
|
||||
Amazon Kinesis Data Firehose.`;
|
||||
return (
|
||||
<>
|
||||
Each time a query runs, the data is sent to <br />
|
||||
Amazon Kinesis Data Firehose.`
|
||||
</>
|
||||
);
|
||||
case "kinesis":
|
||||
return `Each time a query runs, the data is sent to <br />
|
||||
Amazon Kinesis Data Streams.`;
|
||||
return (
|
||||
<>
|
||||
Each time a query runs, the data is sent to <br />
|
||||
Amazon Kinesis Data Streams.
|
||||
</>
|
||||
);
|
||||
case "lambda":
|
||||
return `
|
||||
Each time a query runs, the data <br />is sent to AWS Lambda.
|
||||
`;
|
||||
return (
|
||||
<>
|
||||
Each time a query runs, the data <br />
|
||||
is sent to AWS Lambda.
|
||||
</>
|
||||
);
|
||||
case "pubsub":
|
||||
return `Each time a query runs, the data is <br />sent to Google Cloud Pub/Sub.`;
|
||||
return (
|
||||
<>
|
||||
Each time a query runs, the data is <br /> sent to Google Cloud Pub
|
||||
/ Sub.`
|
||||
</>
|
||||
);
|
||||
case "kafta":
|
||||
return `Each time a query runs, the data <br />is sent to Apache Kafka.`;
|
||||
return (
|
||||
<>
|
||||
Each time a query runs, the data <br /> is sent to Apache Kafka.
|
||||
</>
|
||||
);
|
||||
case "stdout":
|
||||
return `Each time a query runs, the data is sent to <br />
|
||||
standard output (stdout) on the Fleet server.`;
|
||||
return (
|
||||
<>
|
||||
Each time a query runs, the data is sent to <br />
|
||||
standard output(stdout) on the Fleet server.
|
||||
</>
|
||||
);
|
||||
case "":
|
||||
return "Please configure a log destination.";
|
||||
return <>Please configure a log destination.</>;
|
||||
default:
|
||||
return "No additional information is available about this log destination.";
|
||||
return (
|
||||
<>
|
||||
No additional information is available about this log destination.
|
||||
</>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -56,8 +56,12 @@ const PlatformCompatibility = ({
|
|||
<span className={baseClass}>
|
||||
<b>
|
||||
<TooltipWrapper
|
||||
tipContent="Estimated compatiblity based on <br /> the tables used in the query."
|
||||
isDelayed
|
||||
tipContent={
|
||||
<>
|
||||
Estimated compatiblity based on <br />
|
||||
the tables used in the query.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Compatible with:
|
||||
</TooltipWrapper>
|
||||
|
|
@ -73,8 +77,12 @@ const PlatformCompatibility = ({
|
|||
<span className={baseClass}>
|
||||
<b>
|
||||
<TooltipWrapper
|
||||
tipContent="Estimated compatiblity based on <br /> the tables used in the query."
|
||||
isDelayed
|
||||
tipContent={
|
||||
<>
|
||||
Estimated compatiblity based on <br /> the tables used in the
|
||||
query.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Compatible with:
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -1,20 +1,17 @@
|
|||
import React from "react";
|
||||
|
||||
import classnames from "classnames";
|
||||
import TooltipWrapper from "components/TooltipWrapper";
|
||||
|
||||
interface IHeaderCellProps {
|
||||
value: string | JSX.Element; // either a string or a TooltipWrapper
|
||||
isSortedDesc?: boolean;
|
||||
disableSortBy?: boolean;
|
||||
isLastColumn?: boolean;
|
||||
}
|
||||
|
||||
const HeaderCell = ({
|
||||
value,
|
||||
isSortedDesc,
|
||||
disableSortBy,
|
||||
isLastColumn = false,
|
||||
}: IHeaderCellProps): JSX.Element => {
|
||||
let sortArrowClass = "";
|
||||
if (isSortedDesc === undefined) {
|
||||
|
|
@ -25,23 +22,8 @@ const HeaderCell = ({
|
|||
sortArrowClass = "ascending";
|
||||
}
|
||||
|
||||
let lastColumnHeaderWithTooltipClass = "";
|
||||
if (
|
||||
typeof value !== "string" &&
|
||||
value.type === TooltipWrapper &&
|
||||
isLastColumn
|
||||
) {
|
||||
lastColumnHeaderWithTooltipClass = "last-col-header-with-tip";
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={classnames(
|
||||
"header-cell",
|
||||
sortArrowClass,
|
||||
lastColumnHeaderWithTooltipClass
|
||||
)}
|
||||
>
|
||||
<div className={classnames("header-cell", sortArrowClass)}>
|
||||
<span>{value}</span>
|
||||
{!disableSortBy && (
|
||||
<div className="sort-arrows">
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ interface ILinkCellProps {
|
|||
className?: string;
|
||||
customOnClick?: (e: React.MouseEvent) => void;
|
||||
/** allows viewing overflow for tooltip */
|
||||
tooltipContent?: string;
|
||||
tooltipContent?: string | React.ReactNode;
|
||||
title?: string;
|
||||
}
|
||||
|
||||
|
|
@ -33,7 +33,7 @@ const LinkCell = ({
|
|||
|
||||
return tooltipContent ? (
|
||||
<TooltipWrapper
|
||||
position="top"
|
||||
position="top-start"
|
||||
className="link-cell-tooltip-wrapper"
|
||||
tipContent={tooltipContent}
|
||||
>
|
||||
|
|
|
|||
|
|
@ -248,17 +248,10 @@ $shadow-transition-width: 10px;
|
|||
white-space: nowrap; // single line
|
||||
text-overflow: ellipsis; // truncates text
|
||||
overflow: hidden;
|
||||
&__underline {
|
||||
width: 100%;
|
||||
|
||||
&::after {
|
||||
bottom: 9px; // compensate for padding to make larger clickable area
|
||||
}
|
||||
}
|
||||
// TODO – this naming is now confusing, as this .link-cell is not the outermost layer of
|
||||
// the cell – it's a NameCell
|
||||
.link-cell {
|
||||
padding: 10px 0;
|
||||
padding: 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
# Tooltips Notes
|
||||
|
||||
This tooltip component was created to allow any content to be shown as a tooltip. You can place any
|
||||
HTML inside of the `tipContent` prop. Also, very important, the `TooltipWrapper` is designed **ONLY**
|
||||
JSX inside of the `tipContent` prop. Also, very important, the `TooltipWrapper` is designed **ONLY**
|
||||
to wrap text so make sure to use static text or text returned from a function.
|
||||
|
||||
## Use cases
|
||||
|
|
@ -24,11 +24,13 @@ You can even make the tooltip more dynamic HTML:
|
|||
|
||||
```jsx
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
The "snapshot" key includes the query's results.
|
||||
tipContent={
|
||||
<>
|
||||
The "snapshot" key includes the query's results.
|
||||
<br />
|
||||
These will be unique to your query.
|
||||
`}
|
||||
</>
|
||||
}
|
||||
>
|
||||
The data sent to your configured log destination will look similar
|
||||
to the following JSON:
|
||||
|
|
@ -38,7 +40,7 @@ You can even make the tooltip more dynamic HTML:
|
|||
**Within a form input element**
|
||||
|
||||
Inside a form input element, you only need to specify a `tooltip` prop for the input. This can be
|
||||
text or HTML as mentioned before.
|
||||
any JSX as mentioned before.
|
||||
|
||||
```jsx
|
||||
<InputField
|
||||
|
|
@ -53,9 +55,11 @@ text or HTML as mentioned before.
|
|||
"Must include 12 characters, at least 1 number (e.g. 0 - 9), and at least 1 symbol (e.g. &*#)",
|
||||
]}
|
||||
blockAutoComplete
|
||||
tooltip={`\
|
||||
This password is temporary. This user will be asked to set a new password after logging in to the Fleet UI.<br /><br />
|
||||
This user will not be asked to set a new password after logging in to fleetctl or the Fleet API.
|
||||
`}
|
||||
tooltip={
|
||||
<>
|
||||
This password is temporary. This user will be asked to set a new password after logging in to the Fleet UI.<br /><br />
|
||||
This user will not be asked to set a new password after logging in to fleetctl or the Fleet API.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
```
|
||||
|
|
@ -6,8 +6,8 @@ import TooltipWrapper from ".";
|
|||
import "../../index.scss";
|
||||
|
||||
interface ITooltipWrapperProps {
|
||||
children: string;
|
||||
tipContent: string;
|
||||
children: React.ReactNode;
|
||||
tipContent: React.ReactNode;
|
||||
}
|
||||
|
||||
export default {
|
||||
|
|
@ -18,7 +18,20 @@ export default {
|
|||
},
|
||||
argTypes: {
|
||||
position: {
|
||||
options: ["top", "bottom"],
|
||||
options: [
|
||||
"top",
|
||||
"top-start",
|
||||
"top-end",
|
||||
"right",
|
||||
"right-start",
|
||||
"right-end",
|
||||
"bottom",
|
||||
"bottom-start",
|
||||
"bottom-end",
|
||||
"left",
|
||||
"left-start",
|
||||
"left-end",
|
||||
],
|
||||
control: "radio",
|
||||
},
|
||||
},
|
||||
|
|
@ -32,6 +45,10 @@ const Template: Story<ITooltipWrapperProps> = (props) => (
|
|||
<br />
|
||||
<br />
|
||||
<TooltipWrapper {...props}>Example text</TooltipWrapper>
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
<br />
|
||||
</>
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,52 +1,78 @@
|
|||
import classnames from "classnames";
|
||||
import React from "react";
|
||||
import { Tooltip as ReactTooltip5, PlacesType } from "react-tooltip-5";
|
||||
|
||||
import * as DOMPurify from "dompurify";
|
||||
import { uniqueId } from "lodash";
|
||||
|
||||
interface ITooltipWrapperProps {
|
||||
children: string | JSX.Element;
|
||||
tipContent: string;
|
||||
/** Default: bottom */
|
||||
position?: "top" | "bottom";
|
||||
interface ITooltipWrapper {
|
||||
children: React.ReactNode;
|
||||
// default is bottom-start
|
||||
position?: PlacesType;
|
||||
isDelayed?: boolean;
|
||||
underline?: boolean;
|
||||
// Below two props used here to maintain the API of the old TooltipWrapper
|
||||
// A clearer system would be to use the 3 below commented props, which describe exactly where they
|
||||
// will apply, `element` being the element this tooltip will wrap. Associated logic is commented
|
||||
// out, but ready to be used.
|
||||
className?: string;
|
||||
tooltipClass?: string;
|
||||
// wrapperCustomClass?: string;
|
||||
// elementCustomClass?: string;
|
||||
// tipCustomClass?: string;
|
||||
clickable?: boolean;
|
||||
tipContent: React.ReactNode;
|
||||
}
|
||||
|
||||
const baseClass = "component__tooltip-wrapper";
|
||||
|
||||
const TooltipWrapper = ({
|
||||
// wrapperCustomClass,
|
||||
// elementCustomClass,
|
||||
// tipCustomClass,
|
||||
children,
|
||||
tipContent,
|
||||
position = "bottom",
|
||||
position = "bottom-start",
|
||||
isDelayed,
|
||||
underline = true,
|
||||
className,
|
||||
tooltipClass,
|
||||
}: ITooltipWrapperProps): JSX.Element => {
|
||||
const classname = classnames(baseClass, className);
|
||||
const tipClass = classnames(`${baseClass}__tip-text`, tooltipClass, {
|
||||
"delayed-tip": isDelayed,
|
||||
clickable = true,
|
||||
}: ITooltipWrapper) => {
|
||||
const wrapperClassNames = classnames(baseClass, className, {
|
||||
// [`${baseClass}__${wrapperCustomClass}`]: !!wrapperCustomClass,
|
||||
});
|
||||
|
||||
const sanitizedTipContent = DOMPurify.sanitize(tipContent);
|
||||
const elementClassNames = classnames(`${baseClass}__element`, {
|
||||
// [`${baseClass}__${elementCustomClass}`]: !!elementCustomClass,
|
||||
[`${baseClass}__underline`]: underline,
|
||||
});
|
||||
|
||||
const tipClassNames = classnames(`${baseClass}__tip-text`, tooltipClass, {
|
||||
// [`${baseClass}__${tipCustomClass}`]: !!tipCustomClass,
|
||||
});
|
||||
|
||||
const tipId = uniqueId();
|
||||
|
||||
return (
|
||||
<div className={classname} data-position={position}>
|
||||
<div className={`${baseClass}__element`}>
|
||||
<span className={wrapperClassNames}>
|
||||
<div className={elementClassNames} data-tooltip-id={tipId}>
|
||||
{children}
|
||||
<div
|
||||
className={`${baseClass}__element__underline`}
|
||||
data-text={children}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={tipClass}
|
||||
dangerouslySetInnerHTML={{ __html: sanitizedTipContent }}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
<ReactTooltip5
|
||||
className={tipClassNames}
|
||||
id={tipId}
|
||||
delayShow={isDelayed ? 500 : undefined}
|
||||
delayHide={isDelayed ? 500 : undefined}
|
||||
noArrow
|
||||
place={position}
|
||||
opacity={1}
|
||||
disableStyleInjection
|
||||
clickable={clickable}
|
||||
offset={5}
|
||||
>
|
||||
{tipContent}
|
||||
</ReactTooltip5>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -1,92 +1,30 @@
|
|||
.component__tooltip-wrapper {
|
||||
display: inline-flex;
|
||||
position: relative;
|
||||
|
||||
&:hover {
|
||||
.component__tooltip-wrapper__tip-text {
|
||||
visibility: visible;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.delayed-tip {
|
||||
transition: 300ms all;
|
||||
transition-delay: 300ms;
|
||||
}
|
||||
&__underline {
|
||||
position: relative;
|
||||
width: fit-content;
|
||||
// compensate for bottom border and padding to maintain centering
|
||||
top: 2px;
|
||||
border-bottom: 1px dashed $ui-fleet-black-50;
|
||||
padding-bottom: 1px;
|
||||
}
|
||||
|
||||
&__element {
|
||||
position: static;
|
||||
display: inline; // treat like a span but allow other tags as children
|
||||
white-space: nowrap;
|
||||
&__underline {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
|
||||
&::before {
|
||||
content: attr(data-text);
|
||||
opacity: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
&::after {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
bottom: -2px;
|
||||
left: 0;
|
||||
border-bottom: 1px dashed $ui-fleet-black-50;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
position: relative;
|
||||
z-index: 99;
|
||||
}
|
||||
}
|
||||
&__tip-text {
|
||||
width: max-content;
|
||||
max-width: 360px;
|
||||
padding: 6px;
|
||||
color: $core-white;
|
||||
background-color: $core-fleet-blue;
|
||||
background-color: $tooltip-bg;
|
||||
font-weight: $regular;
|
||||
font-size: $xx-small;
|
||||
border-radius: 4px;
|
||||
position: absolute;
|
||||
top: calc(100% + 6px);
|
||||
left: 0;
|
||||
box-sizing: border-box;
|
||||
z-index: 99; // not more than the site nav
|
||||
visibility: hidden;
|
||||
opacity: 0;
|
||||
transition: opacity 0.3s ease;
|
||||
line-height: 1.375;
|
||||
white-space: initial;
|
||||
|
||||
// invisible block to cover space so
|
||||
// hover state can continue from text to bubble
|
||||
&::before {
|
||||
content: "";
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
position: absolute;
|
||||
top: -6px;
|
||||
left: 0;
|
||||
}
|
||||
p {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
&[data-position="top"] {
|
||||
.component__tooltip-wrapper__tip-text {
|
||||
top: auto;
|
||||
bottom: 100%;
|
||||
|
||||
&::before {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import { renderWithSetup } from "test/test-utils";
|
||||
|
||||
import RevealButton from "./RevealButton";
|
||||
|
|
@ -85,7 +85,7 @@ describe("Reveal button", () => {
|
|||
/>
|
||||
);
|
||||
|
||||
await user.hover(screen.getByText(SHOW_TEXT));
|
||||
await fireEvent.mouseEnter(screen.getByText(SHOW_TEXT));
|
||||
|
||||
expect(screen.getByText(TOOLTIP_HTML)).toBeInTheDocument();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export interface IFormFieldProps {
|
|||
label: Array<any> | JSX.Element | string;
|
||||
name: string;
|
||||
type: string;
|
||||
tooltip?: string;
|
||||
tooltip?: React.ReactNode;
|
||||
}
|
||||
|
||||
const FormField = ({
|
||||
|
|
|
|||
|
|
@ -57,11 +57,14 @@ class UserSettingsForm extends Component {
|
|||
hint={renderEmailHint()}
|
||||
disabled={!smtpConfigured}
|
||||
tooltip={
|
||||
"\
|
||||
Editing your email address requires that SMTP or SES is configured in order to send a validation email.\
|
||||
<br /><br /> \
|
||||
Users with Admin role can configure SMTP in <strong>Settings > Organization settings</strong>.\
|
||||
"
|
||||
<>
|
||||
Editing your email address requires that SMTP or SES is
|
||||
configured in order to send a validation email.
|
||||
<br />
|
||||
<br />
|
||||
Users with Admin role can configure SMTP in{" "}
|
||||
<strong>Settings > Organization settings</strong>.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ export interface ICheckboxProps {
|
|||
wrapperClassName?: string;
|
||||
indeterminate?: boolean;
|
||||
parseTarget?: boolean;
|
||||
tooltip?: string;
|
||||
tooltipContent?: React.ReactNode;
|
||||
isLeftLabel?: boolean;
|
||||
}
|
||||
|
||||
|
|
@ -35,7 +35,7 @@ const Checkbox = (props: ICheckboxProps) => {
|
|||
wrapperClassName,
|
||||
indeterminate,
|
||||
parseTarget,
|
||||
tooltip,
|
||||
tooltipContent,
|
||||
isLeftLabel,
|
||||
} = props;
|
||||
|
||||
|
|
@ -78,9 +78,9 @@ const Checkbox = (props: ICheckboxProps) => {
|
|||
type="checkbox"
|
||||
/>
|
||||
<span className={checkBoxTickClass} />
|
||||
{tooltip ? (
|
||||
{tooltipContent ? (
|
||||
<span className={`${baseClass}__label-tooltip tooltip`}>
|
||||
<TooltipWrapper tipContent={tooltip}>
|
||||
<TooltipWrapper tipContent={tooltipContent}>
|
||||
{children as string}
|
||||
</TooltipWrapper>
|
||||
</span>
|
||||
|
|
|
|||
|
|
@ -45,7 +45,7 @@ class InputFieldWithIcon extends InputField {
|
|||
data-has-tooltip={!!tooltip}
|
||||
>
|
||||
{tooltip && !error ? (
|
||||
<TooltipWrapper position="top" tipContent={tooltip}>
|
||||
<TooltipWrapper position="top-start" tipContent={tooltip}>
|
||||
{label}
|
||||
</TooltipWrapper>
|
||||
) : (
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import { noop } from "lodash";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
import userEvent from "@testing-library/user-event";
|
||||
|
||||
import Radio from "./Radio";
|
||||
|
|
@ -76,7 +76,7 @@ describe("Radio - component", () => {
|
|||
expect(radioComponent).toHaveClass("disabled");
|
||||
});
|
||||
|
||||
it("render a tooltip from the tooltip prop", () => {
|
||||
it("render a tooltip from the tooltip prop", async () => {
|
||||
render(
|
||||
<Radio
|
||||
disabled
|
||||
|
|
@ -88,6 +88,7 @@ describe("Radio - component", () => {
|
|||
/>
|
||||
);
|
||||
|
||||
await fireEvent.mouseEnter(screen.getByText("Radio Label"));
|
||||
const tooltip = screen.getByText("A Test Radio Tooltip");
|
||||
expect(tooltip).toBeInTheDocument();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ export interface IRadioProps {
|
|||
name?: string;
|
||||
className?: string;
|
||||
disabled?: boolean;
|
||||
tooltip?: string;
|
||||
tooltip?: React.ReactNode;
|
||||
testId?: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -152,7 +152,17 @@ const generateTableHeaders = (
|
|||
Header: () => {
|
||||
return (
|
||||
<div>
|
||||
<TooltipWrapper tipContent="This is the average performance<br />impact across all hosts where<br />this query was scheduled.">
|
||||
<TooltipWrapper
|
||||
tipContent={
|
||||
<>
|
||||
This is the average performance
|
||||
<br />
|
||||
impact across all hosts where
|
||||
<br />
|
||||
this query was scheduled.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Performance impact
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -101,8 +101,13 @@ const QuertResultsHeading = ({
|
|||
<span>
|
||||
({`${percentResponded}% `}
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
Hosts that respond may<br /> return results, errors, or <br />no results`}
|
||||
tipContent={
|
||||
<>
|
||||
Hosts that respond may
|
||||
<br /> return results, errors, or <br />
|
||||
no results
|
||||
</>
|
||||
}
|
||||
>
|
||||
responded
|
||||
</TooltipWrapper>
|
||||
|
|
@ -120,7 +125,12 @@ const QuertResultsHeading = ({
|
|||
{!isQueryFinished && (
|
||||
<div className={`${baseClass}__tooltip`}>
|
||||
<TooltipWrapper
|
||||
tipContent={`The hosts’ distributed interval can <br/>impact live query response times.`}
|
||||
tipContent={
|
||||
<>
|
||||
The hosts’ distributed interval can <br />
|
||||
impact live query response times.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Taking longer than 15 seconds?
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
import { noop } from "lodash";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { render, screen, fireEvent } from "@testing-library/react";
|
||||
|
||||
import createMockOsqueryTable from "__mocks__/osqueryTableMock";
|
||||
import QuerySidePanel from "./QuerySidePanel";
|
||||
|
|
@ -10,7 +10,7 @@ describe("QuerySidePanel - component", () => {
|
|||
render(
|
||||
<QuerySidePanel
|
||||
selectedOsqueryTable={createMockOsqueryTable()}
|
||||
onOsqueryTableSelect={(tableName: string) => noop}
|
||||
onOsqueryTableSelect={() => noop}
|
||||
onClose={noop}
|
||||
/>
|
||||
);
|
||||
|
|
@ -23,7 +23,7 @@ describe("QuerySidePanel - component", () => {
|
|||
const { container } = render(
|
||||
<QuerySidePanel
|
||||
selectedOsqueryTable={createMockOsqueryTable()}
|
||||
onOsqueryTableSelect={(tableName: string) => noop}
|
||||
onOsqueryTableSelect={() => noop}
|
||||
onClose={noop}
|
||||
/>
|
||||
);
|
||||
|
|
@ -42,7 +42,7 @@ describe("QuerySidePanel - component", () => {
|
|||
const { container } = render(
|
||||
<QuerySidePanel
|
||||
selectedOsqueryTable={createMockOsqueryTable()}
|
||||
onOsqueryTableSelect={(tableName: string) => noop}
|
||||
onOsqueryTableSelect={() => noop}
|
||||
onClose={noop}
|
||||
/>
|
||||
);
|
||||
|
|
@ -51,14 +51,15 @@ describe("QuerySidePanel - component", () => {
|
|||
expect(platformList.length).toBe(11); // 2 columns are set to hidden
|
||||
});
|
||||
|
||||
it("renders the platform specific column tooltip", () => {
|
||||
it("renders the platform specific column tooltip", async () => {
|
||||
render(
|
||||
<QuerySidePanel
|
||||
selectedOsqueryTable={createMockOsqueryTable()}
|
||||
onOsqueryTableSelect={(tableName: string) => noop}
|
||||
onOsqueryTableSelect={() => noop}
|
||||
onClose={noop}
|
||||
/>
|
||||
);
|
||||
await fireEvent.mouseEnter(screen.getByText("email"));
|
||||
|
||||
const tooltip = screen.getByText(/only available on chrome/i);
|
||||
expect(tooltip).toBeInTheDocument();
|
||||
|
|
@ -68,7 +69,7 @@ describe("QuerySidePanel - component", () => {
|
|||
render(
|
||||
<QuerySidePanel
|
||||
selectedOsqueryTable={createMockOsqueryTable()}
|
||||
onOsqueryTableSelect={(tableName: string) => noop}
|
||||
onOsqueryTableSelect={() => noop}
|
||||
onClose={noop}
|
||||
/>
|
||||
);
|
||||
|
|
@ -87,7 +88,7 @@ describe("QuerySidePanel - component", () => {
|
|||
selectedOsqueryTable={createMockOsqueryTable({
|
||||
notes: "This table is being used for testing.",
|
||||
})}
|
||||
onOsqueryTableSelect={(tableName: string) => noop}
|
||||
onOsqueryTableSelect={() => noop}
|
||||
onClose={noop}
|
||||
/>
|
||||
);
|
||||
|
|
@ -102,7 +103,7 @@ describe("QuerySidePanel - component", () => {
|
|||
render(
|
||||
<QuerySidePanel
|
||||
selectedOsqueryTable={createMockOsqueryTable()}
|
||||
onOsqueryTableSelect={(tableName: string) => noop}
|
||||
onOsqueryTableSelect={() => noop}
|
||||
onClose={noop}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -2,9 +2,9 @@ import React from "react";
|
|||
import classnames from "classnames";
|
||||
|
||||
import { ColumnType, IQueryTableColumn } from "interfaces/osquery_table";
|
||||
import { PLATFORM_DISPLAY_NAMES } from "utilities/constants";
|
||||
import TooltipWrapper from "components/TooltipWrapper";
|
||||
import { buildQueryStringFromParams } from "utilities/url";
|
||||
import { OsqueryPlatform } from "interfaces/platform";
|
||||
|
||||
interface IColumnListItemProps {
|
||||
column: IQueryTableColumn;
|
||||
|
|
@ -24,22 +24,11 @@ const FOOTNOTES = {
|
|||
* current tooltip only supports strings. we can change this when it support ReactNodes
|
||||
* in the future.
|
||||
*/
|
||||
const createTooltipHtml = (
|
||||
const renderTooltip = (
|
||||
column: IQueryTableColumn,
|
||||
selectedTableName: string
|
||||
) => {
|
||||
const toolTipHtml = [];
|
||||
|
||||
const descriptionHtml = `<span class="${baseClass}__column-description">${column.description}</span>`;
|
||||
toolTipHtml.push(descriptionHtml);
|
||||
|
||||
if (column.required) {
|
||||
toolTipHtml.push(
|
||||
`<span class="${baseClass}__footnote">${FOOTNOTES.required}</span>`
|
||||
);
|
||||
}
|
||||
|
||||
if (column.requires_user_context) {
|
||||
const renderUserContextFootnote = () => {
|
||||
const queryString = buildQueryStringFromParams({
|
||||
utm_source: "fleet-ui",
|
||||
utm_table: `table-${selectedTableName}`,
|
||||
|
|
@ -51,37 +40,47 @@ const createTooltipHtml = (
|
|||
`${baseClass}__footnote-link`
|
||||
);
|
||||
|
||||
toolTipHtml.push(
|
||||
`<a href="${href}" target="__blank" class="${classNames}">${FOOTNOTES.requires_user_context}</a>`
|
||||
return (
|
||||
<a href={href} target="__blank" className={classNames}>
|
||||
${FOOTNOTES.requires_user_context}
|
||||
</a>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if (column.platforms?.length === 1) {
|
||||
const platform = column.platforms[0];
|
||||
toolTipHtml.push(
|
||||
`<span class="${baseClass}__footnote">${FOOTNOTES.platform} ${platform}</span>`
|
||||
const renderPlatformFootnotes = (columnPlatforms: OsqueryPlatform[]) => {
|
||||
let platformsCopy;
|
||||
switch (columnPlatforms.length) {
|
||||
case 1:
|
||||
platformsCopy = columnPlatforms[0];
|
||||
break;
|
||||
case 2:
|
||||
platformsCopy = `${columnPlatforms[0]} and ${columnPlatforms[1]}`;
|
||||
break;
|
||||
case 3:
|
||||
platformsCopy = `${columnPlatforms[0]}, ${columnPlatforms[1]}, and ${columnPlatforms[2]}`;
|
||||
break;
|
||||
default:
|
||||
platformsCopy = columnPlatforms.join(", ");
|
||||
}
|
||||
return (
|
||||
<span className={`${baseClass}__footnote`}>
|
||||
{FOOTNOTES.platform} {platformsCopy}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
if (column.platforms?.length === 2) {
|
||||
const platform1 = PLATFORM_DISPLAY_NAMES[column.platforms[0]];
|
||||
const platform2 = PLATFORM_DISPLAY_NAMES[column.platforms[1]];
|
||||
toolTipHtml.push(
|
||||
`<span class="${baseClass}__footnote">${FOOTNOTES.platform} ${platform1} and ${platform2}.</span>`
|
||||
);
|
||||
}
|
||||
|
||||
if (column.platforms?.length === 3) {
|
||||
const platform1 = PLATFORM_DISPLAY_NAMES[column.platforms[0]];
|
||||
const platform2 = PLATFORM_DISPLAY_NAMES[column.platforms[1]];
|
||||
const platform3 = PLATFORM_DISPLAY_NAMES[column.platforms[2]];
|
||||
toolTipHtml.push(
|
||||
`<span class="${baseClass}__footnote">${FOOTNOTES.platform} ${platform1}, ${platform2}, and ${platform3}.</span>`
|
||||
);
|
||||
}
|
||||
|
||||
const tooltip = toolTipHtml.join("");
|
||||
return tooltip;
|
||||
return (
|
||||
<>
|
||||
<span className={`${baseClass}__column-description`}>
|
||||
{column.description}
|
||||
</span>
|
||||
{column.required && (
|
||||
<span className={`${baseClass}__footnote`}>{FOOTNOTES.required}</span>
|
||||
)}
|
||||
{column.requires_user_context && renderUserContextFootnote()}
|
||||
{column.platforms && renderPlatformFootnotes(column.platforms)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
const hasFootnotes = (column: IQueryTableColumn) => {
|
||||
|
|
@ -113,7 +112,7 @@ const ColumnListItem = ({
|
|||
<div className={`${baseClass}__name-wrapper`}>
|
||||
<span className={columnNameClasses}>
|
||||
<TooltipWrapper
|
||||
tipContent={createTooltipHtml(column, selectedTableName)}
|
||||
tipContent={renderTooltip(column, selectedTableName)}
|
||||
className={`${baseClass}__tooltip`}
|
||||
>
|
||||
{column.name}
|
||||
|
|
|
|||
|
|
@ -52,7 +52,7 @@
|
|||
margin: $pad-small 0;
|
||||
display: block;
|
||||
|
||||
&:last-child {
|
||||
&:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ export type IDataColumn = Column & {
|
|||
title?: string;
|
||||
disableHidden?: boolean;
|
||||
disableSortBy?: boolean;
|
||||
isLastColumn?: boolean;
|
||||
filterValue?: any;
|
||||
preFilteredRows?: any;
|
||||
setFilter?: any;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import React from "react";
|
||||
|
||||
import { render, screen } from "@testing-library/react";
|
||||
import { fireEvent, render, screen } from "@testing-library/react";
|
||||
import { renderWithSetup } from "test/test-utils";
|
||||
import paths from "router/paths";
|
||||
import SummaryTile from "./SummaryTile";
|
||||
|
|
@ -102,7 +102,7 @@ describe("SummaryTile - component", () => {
|
|||
/>
|
||||
);
|
||||
|
||||
await user.hover(screen.getByText("Windows hosts"));
|
||||
await fireEvent.mouseEnter(screen.getByText("Windows hosts"));
|
||||
|
||||
expect(screen.getByText("Hosts on any Windows device")).toBeInTheDocument();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -2,12 +2,12 @@ import React from "react";
|
|||
import { Link } from "react-router";
|
||||
import { kebabCase } from "lodash";
|
||||
|
||||
import TooltipWrapper from "components/TooltipWrapper";
|
||||
import Icon from "components/Icon";
|
||||
import { IconNames } from "components/icons";
|
||||
import PremiumFeatureIconWithTooltip from "components/PremiumFeatureIconWithTooltip";
|
||||
import classnames from "classnames";
|
||||
import { Colors } from "styles/var/colors";
|
||||
import TooltipWrapper from "components/TooltipWrapper";
|
||||
|
||||
interface ISummaryTileProps {
|
||||
count: number;
|
||||
|
|
@ -52,7 +52,6 @@ const SummaryTile = ({
|
|||
const classes = classnames(`${baseClass}__tile`, `${kebabCase(title)}-tile`, {
|
||||
[`${baseClass}__not-supported`]: notSupported,
|
||||
});
|
||||
|
||||
const tile = (
|
||||
<>
|
||||
<div className={circledIcon ? `${baseClass}__circled-icon` : ""}>
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ export const generateStatusTableHeaders = (teamId?: number): IDataColumn[] => [
|
|||
accessor: "status",
|
||||
Cell: (cellProps: IStringCellProps) => (
|
||||
<TooltipWrapper
|
||||
position="top"
|
||||
position="top-start"
|
||||
tipContent={MDM_STATUS_TOOLTIP[cellProps.cell.value]}
|
||||
>
|
||||
{cellProps.cell.value}
|
||||
|
|
|
|||
|
|
@ -41,9 +41,9 @@ const generateMunkiIssuesTableHeaders = (teamId?: number): IDataColumn[] => [
|
|||
Header: (): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
Issues reported the last time Munki ran on each host.
|
||||
`}
|
||||
tipContent={
|
||||
<>Issues reported the last time Munki ran on each host.</>
|
||||
}
|
||||
>
|
||||
Issue
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -201,7 +201,7 @@ const AppleBusinessManagerSection = ({
|
|||
<div className={`${baseClass}__section-information`}>
|
||||
<h4>
|
||||
<TooltipWrapper
|
||||
position="top"
|
||||
position="top-start"
|
||||
tipContent="macOS hosts will be added to this team when they’re first unboxed."
|
||||
>
|
||||
Team
|
||||
|
|
|
|||
|
|
@ -226,12 +226,13 @@ const IntegrationForm = ({
|
|||
parseTarget
|
||||
value={projectKey}
|
||||
tooltip={
|
||||
"\
|
||||
To find the Jira project key, head to your project in <br /> \
|
||||
Jira. Your project key is located in the URL. For example, in <br /> \
|
||||
“jira.example.com/projects/JRAEXAMPLE,” <br /> \
|
||||
“JRAEXAMPLE” is your project key. \
|
||||
"
|
||||
<>
|
||||
To find the Jira project key, head to your project in <br />
|
||||
Jira. Your project key is located in the URL. For example, in{" "}
|
||||
<br />
|
||||
“jira.example.com/projects/JRAEXAMPLE,” <br />
|
||||
“JRAEXAMPLE” is your project key.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
) : (
|
||||
|
|
@ -244,11 +245,15 @@ const IntegrationForm = ({
|
|||
parseTarget
|
||||
value={groupId === 0 ? null : groupId}
|
||||
tooltip={
|
||||
"\
|
||||
To find the Zendesk group ID, select <b>Admin > <br /> \
|
||||
People > Groups</b>. Find the group and select it. <br /> \
|
||||
The group ID will appear in the search field. \
|
||||
"
|
||||
<>
|
||||
To find the Zendesk group ID, select{" "}
|
||||
<b>
|
||||
Admin > <br />
|
||||
People > Groups
|
||||
</b>
|
||||
. Find the group and select it. <br />
|
||||
The group ID will appear in the search field.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -115,7 +115,13 @@ const Advanced = ({
|
|||
value={domain}
|
||||
parseTarget
|
||||
tooltip={
|
||||
'<p>If you need to specify a HELO domain, <br />you can do it here <em className="hint hint--brand">(Default: <strong>Blank</strong>)</em></p>'
|
||||
<p>
|
||||
If you need to specify a HELO domain, <br />
|
||||
you can do it here{" "}
|
||||
<em className="hint hint--brand">
|
||||
(Default: <strong>Blank</strong>)
|
||||
</em>
|
||||
</p>
|
||||
}
|
||||
/>
|
||||
<Checkbox
|
||||
|
|
@ -123,8 +129,15 @@ const Advanced = ({
|
|||
name="verifySSLCerts"
|
||||
value={verifySSLCerts}
|
||||
parseTarget
|
||||
tooltip={
|
||||
'<p>Turn this off (not recommended) <br />if you use a self-signed certificate <em className="hint hint--brand"><br />(Default: <strong>On</strong>)</em></p>'
|
||||
tooltipContent={
|
||||
<p>
|
||||
Turn this off (not recommended) <br />
|
||||
if you use a self-signed certificate{" "}
|
||||
<em className="hint hint--brand">
|
||||
<br />
|
||||
(Default: <strong>On</strong>)
|
||||
</em>
|
||||
</p>
|
||||
}
|
||||
>
|
||||
Verify SSL certs
|
||||
|
|
@ -134,8 +147,15 @@ const Advanced = ({
|
|||
name="enableStartTLS"
|
||||
value={enableStartTLS}
|
||||
parseTarget
|
||||
tooltip={
|
||||
'<p>Detects if STARTTLS is enabled <br />in your SMTP server and starts <br />to use it. <em className="hint hint--brand">(Default: <strong>On</strong>)</em></p>'
|
||||
tooltipContent={
|
||||
<p>
|
||||
Detects if STARTTLS is enabled <br />
|
||||
in your SMTP server and starts <br />
|
||||
to use it.{" "}
|
||||
<em className="hint hint--brand">
|
||||
(Default: <strong>On</strong>)
|
||||
</em>
|
||||
</p>
|
||||
}
|
||||
>
|
||||
Enable STARTTLS
|
||||
|
|
@ -145,8 +165,15 @@ const Advanced = ({
|
|||
name="enableHostExpiry"
|
||||
value={enableHostExpiry}
|
||||
parseTarget
|
||||
tooltip={
|
||||
'<p>When enabled, allows automatic cleanup <br />of hosts that have not communicated with Fleet <br />in some number of days. <em className="hint hint--brand">(Default: <strong>Off</strong>)</em></p>'
|
||||
tooltipContent={
|
||||
<p>
|
||||
When enabled, allows automatic cleanup <br />
|
||||
of hosts that have not communicated with Fleet <br />
|
||||
in some number of days.{" "}
|
||||
<em className="hint hint--brand">
|
||||
(Default: <strong>Off</strong>)
|
||||
</em>
|
||||
</p>
|
||||
}
|
||||
>
|
||||
Host expiry
|
||||
|
|
@ -161,8 +188,11 @@ const Advanced = ({
|
|||
parseTarget
|
||||
onBlur={validateForm}
|
||||
error={formErrors.host_expiry_window}
|
||||
tooltip={
|
||||
"<p>If a host has not communicated with Fleet in the specified number of days, it will be removed.</p>"
|
||||
tooltipContent={
|
||||
<p>
|
||||
If a host has not communicated with Fleet in the specified
|
||||
number of days, it will be removed.
|
||||
</p>
|
||||
}
|
||||
/>
|
||||
<Checkbox
|
||||
|
|
@ -170,8 +200,15 @@ const Advanced = ({
|
|||
name="disableLiveQuery"
|
||||
value={disableLiveQuery}
|
||||
parseTarget
|
||||
tooltip={
|
||||
'<p>When enabled, disables the ability to run live queries <br />(ad hoc queries executed via the UI or fleetctl). <em className="hint hint--brand">(Default: <strong>Off</strong>)</em></p>'
|
||||
tooltipContent={
|
||||
<p>
|
||||
When enabled, disables the ability to run live queries{" "}
|
||||
<br />
|
||||
(ad hoc queries executed via the UI or fleetctl).{" "}
|
||||
<em className="hint hint--brand">
|
||||
(Default: <strong>Off</strong>)
|
||||
</em>
|
||||
</p>
|
||||
}
|
||||
>
|
||||
Disable live queries
|
||||
|
|
@ -181,15 +218,23 @@ const Advanced = ({
|
|||
name="disableQueryReports"
|
||||
value={disableQueryReports}
|
||||
parseTarget
|
||||
// TODO - update to JSX once tooltip wrapper refactor is merged
|
||||
// TODO - once refactor is merged, have this and bove tooltips disappear more
|
||||
// quickly to get out of users' way
|
||||
tooltip={
|
||||
'<p>Disabling query reports will decrease database usage, <br />\
|
||||
but will prevent you from accessing query results in<br /> \
|
||||
Fleet and will delete existing reports. This can also be<br />\
|
||||
disabled on a per-query basis by enabling "Discard <br />\
|
||||
data". <em>(Default: <b>Off</b>)</em></p>'
|
||||
tooltipContent={
|
||||
<>
|
||||
<p>
|
||||
Disabling query reports will decrease database usage,{" "}
|
||||
<br />\ but will prevent you from accessing query results
|
||||
in
|
||||
<br /> \ Fleet and will delete existing reports. This can
|
||||
also be
|
||||
<br />\ disabled on a per-query basis by enabling
|
||||
"Discard <br />\ data".{" "}
|
||||
<em>
|
||||
(Default: <b>Off</b>)
|
||||
</em>
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
>
|
||||
Disable query reports
|
||||
|
|
|
|||
|
|
@ -181,9 +181,10 @@ const HostStatusWebhook = ({
|
|||
onBlur={validateForm}
|
||||
error={formErrors.destination_url}
|
||||
tooltip={
|
||||
"\
|
||||
<p>Provide a URL to deliver <br/>the webhook request to.</p>\
|
||||
"
|
||||
<p>
|
||||
Provide a URL to deliver <br />
|
||||
the webhook request to.
|
||||
</p>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -197,9 +198,13 @@ const HostStatusWebhook = ({
|
|||
parseTarget
|
||||
onBlur={validateForm}
|
||||
tooltip={
|
||||
"\
|
||||
<p>Select the minimum percentage of hosts that<br/>must fail to check into Fleet in order to trigger<br/>the webhook request.</p>\
|
||||
"
|
||||
<p>
|
||||
Select the minimum percentage of hosts that
|
||||
<br />
|
||||
must fail to check into Fleet in order to trigger
|
||||
<br />
|
||||
the webhook request.
|
||||
</p>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
|
@ -213,9 +218,15 @@ const HostStatusWebhook = ({
|
|||
parseTarget
|
||||
onBlur={validateForm}
|
||||
tooltip={
|
||||
"\
|
||||
<p>Select the minimum number of days that the<br/>configured <b>Percentage of hosts</b> must fail to<br/>check into Fleet in order to trigger the<br/>webhook request.</p>\
|
||||
"
|
||||
<p>
|
||||
Select the minimum number of days that the
|
||||
<br />
|
||||
configured <b>Percentage of hosts</b> must fail to
|
||||
<br />
|
||||
check into Fleet in order to trigger the
|
||||
<br />
|
||||
webhook request.
|
||||
</p>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -248,11 +248,21 @@ const Smtp = ({
|
|||
value={smtpAuthenticationType}
|
||||
parseTarget
|
||||
tooltip={
|
||||
"\
|
||||
<p>If your mail server requires authentication, you need to specify the authentication type here.</p> \
|
||||
<p><strong>No Authentication</strong> - Select this if your SMTP is open.</p> \
|
||||
<p><strong>Username & Password</strong> - Select this if your SMTP server requires authentication with a username and password.</p>\
|
||||
"
|
||||
<>
|
||||
<p>
|
||||
If your mail server requires authentication, you need to
|
||||
specify the authentication type here.
|
||||
</p>
|
||||
<p>
|
||||
<strong>No Authentication</strong> - Select this if your SMTP
|
||||
is open.
|
||||
</p>
|
||||
<p>
|
||||
<strong>Username & Password</strong> - Select this if your
|
||||
SMTP server requires authentication with a username and
|
||||
password.
|
||||
</p>
|
||||
</>
|
||||
}
|
||||
/>
|
||||
{renderSmtpSection()}
|
||||
|
|
|
|||
|
|
@ -171,7 +171,8 @@ const Sso = ({
|
|||
parseTarget
|
||||
onBlur={validateForm}
|
||||
error={formErrors.idp_image_url}
|
||||
tooltip="An optional link to an image such <br/>as a logo for the identity provider."
|
||||
tooltip={`An optional link to an image such
|
||||
as a logo for the identity provider.`}
|
||||
/>
|
||||
</div>
|
||||
<div className={`${baseClass}__inputs`}>
|
||||
|
|
@ -184,7 +185,8 @@ const Sso = ({
|
|||
parseTarget
|
||||
onBlur={validateForm}
|
||||
error={formErrors.metadata}
|
||||
tooltip="Metadata provided by the identity provider. Either<br/> metadata or a metadata url must be provided."
|
||||
tooltip={`Metadata provided by the identity provider. Either
|
||||
metadata or a metadata url must be provided.`}
|
||||
/>
|
||||
</div>
|
||||
<div className={`${baseClass}__inputs`}>
|
||||
|
|
|
|||
|
|
@ -125,12 +125,16 @@ const generateTableHeaders = (
|
|||
if (cellProps.cell.value === "GitOps") {
|
||||
return (
|
||||
<TooltipWrapper
|
||||
position="top"
|
||||
tipContent={`
|
||||
The GitOps role is only available on the command-line<br/>
|
||||
when creating an API-only user. This user has no<br/>
|
||||
access to the UI.
|
||||
`}
|
||||
position="top-start"
|
||||
tipContent={
|
||||
<>
|
||||
The GitOps role is only available on the command-line
|
||||
<br />
|
||||
when creating an API-only user. This user has no
|
||||
<br />
|
||||
access to the UI.
|
||||
</>
|
||||
}
|
||||
>
|
||||
GitOps
|
||||
</TooltipWrapper>
|
||||
|
|
@ -139,12 +143,16 @@ const generateTableHeaders = (
|
|||
if (cellProps.cell.value === "Observer+") {
|
||||
return (
|
||||
<TooltipWrapper
|
||||
position="top"
|
||||
tipContent={`
|
||||
Users with the Observer+ role have access to all of<br/>
|
||||
the same functions as an Observer, with the added<br/>
|
||||
ability to run any live query against all hosts.
|
||||
`}
|
||||
position="top-start"
|
||||
tipContent={
|
||||
<>
|
||||
Users with the Observer+ role have access to all of
|
||||
<br />
|
||||
the same functions as an Observer, with the added
|
||||
<br />
|
||||
ability to run any live query against all hosts.
|
||||
</>
|
||||
}
|
||||
>
|
||||
{cellProps.cell.value}
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,6 @@ import PATHS from "router/paths";
|
|||
import { NotificationContext } from "context/notification";
|
||||
import { ITeam } from "interfaces/team";
|
||||
import { IUserFormErrors, UserRole } from "interfaces/user";
|
||||
import { IRole } from "interfaces/role";
|
||||
|
||||
import Button from "components/buttons/Button";
|
||||
import validatePresence from "components/forms/validators/validate_presence";
|
||||
|
|
@ -398,11 +397,14 @@ const UserForm = ({
|
|||
value={formData.email || ""}
|
||||
disabled={!isNewUser && !(smtpConfigured || sesConfigured)}
|
||||
tooltip={
|
||||
"\
|
||||
Editing an email address requires that SMTP or SES is configured in order to send a validation email. \
|
||||
<br /><br /> \
|
||||
Users with Admin role can configure SMTP in <strong>Settings > Organization settings</strong>. \
|
||||
"
|
||||
<>
|
||||
Editing an email address requires that SMTP or SES is configured in
|
||||
order to send a validation email.
|
||||
<br />
|
||||
<br />
|
||||
Users with Admin role can configure SMTP in{" "}
|
||||
<strong>Settings > Organization settings</strong>.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
{!isNewUser &&
|
||||
|
|
@ -434,11 +436,16 @@ const UserForm = ({
|
|||
value={canUseSso && formData.sso_enabled}
|
||||
disabled={!canUseSso}
|
||||
wrapperClassName={`${baseClass}__invite-admin`}
|
||||
tooltip={`
|
||||
Enabling single sign-on for a user requires that SSO is first enabled for the organization.
|
||||
<br /><br />
|
||||
Users with Admin role can configure SSO in <strong>Settings > Organization settings</strong>.
|
||||
`}
|
||||
tooltipContent={
|
||||
<>
|
||||
Enabling single sign-on for a user requires that SSO is first
|
||||
enabled for the organization.
|
||||
<br />
|
||||
<br />
|
||||
Users with Admin role can configure SSO in{" "}
|
||||
<strong>Settings > Organization settings</strong>.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Enable single sign-on
|
||||
</Checkbox>
|
||||
|
|
@ -470,14 +477,18 @@ const UserForm = ({
|
|||
name={"newUserType"}
|
||||
onChange={onRadioChange("newUserType")}
|
||||
tooltip={
|
||||
smtpConfigured || sesConfigured
|
||||
? ""
|
||||
: `
|
||||
The "Invite user" feature requires that SMTP or SES
|
||||
is configured in order to send invitation emails.
|
||||
<br /><br />
|
||||
SMTP can be configured in Settings > Organization settings.
|
||||
`
|
||||
smtpConfigured || sesConfigured ? (
|
||||
""
|
||||
) : (
|
||||
<>
|
||||
The "Invite user" feature requires that SMTP
|
||||
or SES is configured in order to send invitation emails.
|
||||
<br />
|
||||
<br />
|
||||
SMTP can be configured in Settings > Organization
|
||||
settings.
|
||||
</>
|
||||
)
|
||||
}
|
||||
/>
|
||||
</>
|
||||
|
|
@ -506,10 +517,16 @@ const UserForm = ({
|
|||
"Must include 12 characters, at least 1 number (e.g. 0 - 9), and at least 1 symbol (e.g. &*#)",
|
||||
]}
|
||||
blockAutoComplete
|
||||
tooltip={`\
|
||||
This password is temporary. This user will be asked to set a new password after logging in to the Fleet UI.<br /><br />\
|
||||
This user will not be asked to set a new password after logging in to fleetctl or the Fleet API.\
|
||||
`}
|
||||
tooltip={
|
||||
<>
|
||||
This password is temporary. This user will be asked to
|
||||
set a new password after logging in to the Fleet UI.
|
||||
<br />
|
||||
<br />
|
||||
This user will not be asked to set a new password after
|
||||
logging in to fleetctl or the Fleet API.
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</>
|
||||
|
|
|
|||
|
|
@ -131,12 +131,16 @@ const generateTableHeaders = (
|
|||
if (cellProps.cell.value === "GitOps") {
|
||||
return (
|
||||
<TooltipWrapper
|
||||
position="top"
|
||||
tipContent={`
|
||||
The GitOps role is only available on the command-line<br/>
|
||||
when creating an API-only user. This user has no<br/>
|
||||
access to the UI.
|
||||
`}
|
||||
position="top-start"
|
||||
tipContent={
|
||||
<>
|
||||
The GitOps role is only available on the command-line
|
||||
<br />
|
||||
when creating an API-only user. This user has no
|
||||
<br />
|
||||
access to the UI.
|
||||
</>
|
||||
}
|
||||
>
|
||||
GitOps
|
||||
</TooltipWrapper>
|
||||
|
|
@ -145,12 +149,16 @@ const generateTableHeaders = (
|
|||
if (cellProps.cell.value === "Observer+") {
|
||||
return (
|
||||
<TooltipWrapper
|
||||
position="top"
|
||||
tipContent={`
|
||||
Users with the Observer+ role have access to all of<br/>
|
||||
the same functions as an Observer, with the added<br/>
|
||||
ability to run any live query against all hosts.
|
||||
`}
|
||||
position="top-start"
|
||||
tipContent={
|
||||
<>
|
||||
Users with the Observer+ role have access to all of
|
||||
<br />
|
||||
the same functions as an Observer, with the added
|
||||
<br />
|
||||
ability to run any live query against all hosts.
|
||||
</>
|
||||
}
|
||||
>
|
||||
{cellProps.cell.value}
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -47,7 +47,6 @@ interface IHeaderProps {
|
|||
column: {
|
||||
title: string;
|
||||
isSortedDesc: boolean;
|
||||
isLastColumn?: boolean;
|
||||
};
|
||||
getToggleAllRowsSelectedProps: () => IGetToggleAllRowsSelectedProps;
|
||||
toggleAllRowsSelected: () => void;
|
||||
|
|
@ -149,7 +148,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "display_name",
|
||||
|
|
@ -208,7 +206,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "hostname",
|
||||
|
|
@ -220,7 +217,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "computer_name",
|
||||
|
|
@ -232,7 +228,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "team_name",
|
||||
|
|
@ -245,11 +240,13 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
Header: (cellProps: IHeaderProps): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
Online hosts will respond to a live query. Offline<br/>
|
||||
hosts won’t respond to a live query because<br/>
|
||||
they may be shut down, asleep, or not<br/>
|
||||
connected to the internet.`}
|
||||
tipContent={
|
||||
<>
|
||||
Online hosts will respond to a live query. Offline hosts won’t
|
||||
respond to a live query because they may be shut down, asleep, or
|
||||
not connected to the internet.
|
||||
</>
|
||||
}
|
||||
className="status-header"
|
||||
>
|
||||
Status
|
||||
|
|
@ -259,7 +256,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.rows.length === 1 ? "Status" : titleWithToolTip}
|
||||
disableSortBy
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
|
@ -291,7 +287,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "gigs_disk_space_available",
|
||||
|
|
@ -321,7 +316,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "os_version",
|
||||
|
|
@ -382,7 +376,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "primary_ip",
|
||||
|
|
@ -393,21 +386,18 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
Header: (cellProps: IHeaderProps): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
Settings can be updated remotely on hosts with MDM turned<br/>
|
||||
on. To filter by MDM status, head to the Dashboard page.
|
||||
`}
|
||||
tipContent={
|
||||
<>
|
||||
Settings can be updated remotely on hosts with MDM turned
|
||||
<br />
|
||||
on. To filter by MDM status, head to the Dashboard page.
|
||||
</>
|
||||
}
|
||||
>
|
||||
MDM status
|
||||
</TooltipWrapper>
|
||||
);
|
||||
return (
|
||||
<HeaderCell
|
||||
value={titleWithToolTip}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
disableSortBy
|
||||
/>
|
||||
);
|
||||
return <HeaderCell value={titleWithToolTip} disableSortBy />;
|
||||
},
|
||||
disableSortBy: true,
|
||||
accessor: "mdm.enrollment_status",
|
||||
|
|
@ -427,21 +417,18 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
Header: (cellProps: IHeaderProps): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
The MDM server that updates settings on the host. To<br/>
|
||||
filter by MDM server URL, head to the Dashboard page.
|
||||
`}
|
||||
tipContent={
|
||||
<>
|
||||
The MDM server that updates settings on the host. To
|
||||
<br />
|
||||
filter by MDM server URL, head to the Dashboard page.
|
||||
</>
|
||||
}
|
||||
>
|
||||
MDM server URL
|
||||
</TooltipWrapper>
|
||||
);
|
||||
return (
|
||||
<HeaderCell
|
||||
value={titleWithToolTip}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
disableSortBy
|
||||
/>
|
||||
);
|
||||
return <HeaderCell value={titleWithToolTip} disableSortBy />;
|
||||
},
|
||||
disableSortBy: true,
|
||||
accessor: "mdm.server_url",
|
||||
|
|
@ -462,7 +449,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "public_ip",
|
||||
|
|
@ -506,9 +492,12 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
Header: (cellProps: IHeaderProps): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
The last time the host<br/> reported vitals.
|
||||
`}
|
||||
tipContent={
|
||||
<>
|
||||
The last time the host
|
||||
<br /> reported vitals.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Last fetched
|
||||
</TooltipWrapper>
|
||||
|
|
@ -517,7 +506,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={titleWithToolTip}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
|
@ -534,9 +522,12 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
Header: (cellProps: IHeaderProps): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
The last time the <br/>host was online.
|
||||
`}
|
||||
tipContent={
|
||||
<>
|
||||
The last time the <br />
|
||||
host was online.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Last seen
|
||||
</TooltipWrapper>
|
||||
|
|
@ -545,7 +536,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={titleWithToolTip}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
);
|
||||
},
|
||||
|
|
@ -563,7 +553,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "uuid",
|
||||
|
|
@ -577,7 +566,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "uptime",
|
||||
|
|
@ -610,7 +598,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "memory",
|
||||
|
|
@ -624,7 +611,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "primary_mac",
|
||||
|
|
@ -636,7 +622,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "hardware_serial",
|
||||
|
|
@ -648,7 +633,6 @@ const allHostTableHeaders: IDataColumn[] = [
|
|||
<HeaderCell
|
||||
value={cellProps.column.title}
|
||||
isSortedDesc={cellProps.column.isSortedDesc}
|
||||
isLastColumn={cellProps.column.isLastColumn}
|
||||
/>
|
||||
),
|
||||
accessor: "hardware_model",
|
||||
|
|
|
|||
|
|
@ -1412,12 +1412,6 @@ const ManageHostsPage = ({
|
|||
isOnlyObserver || (!isOnGlobalTeam && !isTeamMaintainerOrTeamAdmin),
|
||||
});
|
||||
|
||||
// Update last column
|
||||
tableColumns.forEach((dataColumn) => {
|
||||
dataColumn.isLastColumn = false;
|
||||
});
|
||||
tableColumns[tableColumns.length - 1].isLastColumn = true;
|
||||
|
||||
const emptyState = () => {
|
||||
const emptyHosts: IEmptyTableProps = {
|
||||
header: "No hosts match the current criteria",
|
||||
|
|
|
|||
|
|
@ -200,24 +200,6 @@
|
|||
overflow-x: scroll;
|
||||
}
|
||||
&__table {
|
||||
thead {
|
||||
tr {
|
||||
th {
|
||||
.last-col-header-with-tip {
|
||||
min-width: 90px;
|
||||
.component__tooltip-wrapper__tip-text {
|
||||
left: -126px;
|
||||
}
|
||||
}
|
||||
.status-header {
|
||||
.component__tooltip-wrapper__tip-text {
|
||||
left: -220px;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tbody {
|
||||
.issues {
|
||||
&__cell {
|
||||
|
|
|
|||
|
|
@ -103,7 +103,6 @@ const About = ({
|
|||
<span className="info-grid__header">MDM status</span>
|
||||
<span className="info-grid__data">
|
||||
<TooltipWrapper
|
||||
position="bottom"
|
||||
tipContent={MDM_STATUS_TOOLTIP[mdm.enrollment_status]}
|
||||
>
|
||||
{mdm.enrollment_status}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,6 @@ const AgentOptions = ({
|
|||
{isChromeOS ? (
|
||||
<TooltipWrapper
|
||||
tipContent={CHROMEOS_AGENT_OPTIONS_TOOLTIP_MESSAGE}
|
||||
position="bottom"
|
||||
className="section__header"
|
||||
>
|
||||
Agent options
|
||||
|
|
|
|||
|
|
@ -176,7 +176,7 @@ const HostSummary = ({
|
|||
return (
|
||||
<div className="info-flex__item info-flex__item--title">
|
||||
<span className="info-flex__header">Disk encryption</span>
|
||||
<TooltipWrapper tipContent={tooltipMessage} position="bottom">
|
||||
<TooltipWrapper tipContent={tooltipMessage}>
|
||||
{statusText}
|
||||
</TooltipWrapper>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -60,9 +60,9 @@ export const munkiIssuesTableHeaders: IDataColumn[] = [
|
|||
Header: (headerProps: IHeaderProps): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
Issues reported the last time Munki ran on each host.
|
||||
`}
|
||||
tipContent={
|
||||
<>Issues reported the last time Munki ran on each host.</>
|
||||
}
|
||||
>
|
||||
Issue
|
||||
</TooltipWrapper>
|
||||
|
|
@ -95,9 +95,7 @@ export const munkiIssuesTableHeaders: IDataColumn[] = [
|
|||
Header: (headerProps: IHeaderProps): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
The first time Munki reported this issue.
|
||||
`}
|
||||
tipContent={<>The first time Munki reported this issue.</>}
|
||||
>
|
||||
Time
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -79,7 +79,16 @@ const generatePackTableHeaders = (): IDataColumn[] => {
|
|||
{
|
||||
Header: () => {
|
||||
return (
|
||||
<TooltipWrapper tipContent="The last time the query ran<br/>since the last time osquery <br/>started on this host.">
|
||||
<TooltipWrapper
|
||||
tipContent={
|
||||
<>
|
||||
The last time the query ran
|
||||
<br />
|
||||
since the last time osquery <br />
|
||||
started on this host.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Last run
|
||||
</TooltipWrapper>
|
||||
);
|
||||
|
|
@ -93,7 +102,14 @@ const generatePackTableHeaders = (): IDataColumn[] => {
|
|||
{
|
||||
Header: () => {
|
||||
return (
|
||||
<TooltipWrapper tipContent="This is the performance <br />impact on this host.">
|
||||
<TooltipWrapper
|
||||
tipContent={
|
||||
<>
|
||||
This is the performance <br />
|
||||
impact on this host.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Performance impact
|
||||
</TooltipWrapper>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -76,7 +76,14 @@ const generateTableHeaders = (): IDataColumn[] => {
|
|||
{
|
||||
Header: () => {
|
||||
return (
|
||||
<TooltipWrapper tipContent="This is the performance <br />impact on this host.">
|
||||
<TooltipWrapper
|
||||
tipContent={
|
||||
<>
|
||||
This is the performance <br />
|
||||
impact on this host.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Performance impact
|
||||
</TooltipWrapper>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@ import TooltipWrapper from "components/TooltipWrapper";
|
|||
import ViewAllHostsLink from "components/ViewAllHostsLink";
|
||||
import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants";
|
||||
import { COLORS } from "styles/var/colors";
|
||||
import { getSoftwareBundleTooltipMarkup } from "utilities/helpers";
|
||||
import { getSoftwareBundleTooltipJSX } from "utilities/helpers";
|
||||
|
||||
interface IHeaderProps {
|
||||
column: {
|
||||
|
|
@ -106,14 +106,13 @@ const condenseVulnerabilities = (vulns: string[]): string[] => {
|
|||
const renderBundleTooltip = (name: string, bundle: string) => (
|
||||
<span className="name-container">
|
||||
<TooltipWrapper
|
||||
position="top"
|
||||
tipContent={`
|
||||
position="top-start"
|
||||
tipContent={
|
||||
<span>
|
||||
<b>Bundle identifier: </b>
|
||||
<br />
|
||||
${bundle}
|
||||
<br />${bundle}
|
||||
</span>
|
||||
`}
|
||||
}
|
||||
>
|
||||
{name}
|
||||
</TooltipWrapper>
|
||||
|
|
@ -221,7 +220,7 @@ export const generateSoftwareTableHeaders = ({
|
|||
customOnClick={onClickSoftware}
|
||||
value={name}
|
||||
tooltipContent={
|
||||
bundle ? getSoftwareBundleTooltipMarkup(bundle) : undefined
|
||||
bundle ? getSoftwareBundleTooltipJSX(bundle) : undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
|
@ -356,7 +355,14 @@ export const generateSoftwareTableHeaders = ({
|
|||
title: "File path",
|
||||
Header: () => {
|
||||
return (
|
||||
<TooltipWrapper tipContent="This is where the software is <br />located on this host.">
|
||||
<TooltipWrapper
|
||||
tipContent={
|
||||
<>
|
||||
This is where the software is <br />
|
||||
located on this host.
|
||||
</>
|
||||
}
|
||||
>
|
||||
File path
|
||||
</TooltipWrapper>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -49,7 +49,17 @@ const generateUsersTableHeaders = (): IDataColumn[] => {
|
|||
{
|
||||
Header: () => {
|
||||
return (
|
||||
<TooltipWrapper tipContent="The command line shell, such as bash,<br />that this user is equipped with by<br />default when they log in to the system.">
|
||||
<TooltipWrapper
|
||||
tipContent={
|
||||
<>
|
||||
The command line shell, such as bash,
|
||||
<br />
|
||||
that this user is equipped with by
|
||||
<br />
|
||||
default when they log in to the system.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Shell
|
||||
</TooltipWrapper>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -767,9 +767,9 @@ const ManagePolicyPage = ({
|
|||
globalPoliciesCount
|
||||
)}
|
||||
caretPosition={"before"}
|
||||
tooltipHtml={
|
||||
'"All teams" policies are checked <br/> for this team’s hosts.'
|
||||
}
|
||||
tooltipHtml={`"All teams" policies are checked ${(
|
||||
<br />
|
||||
)} for this team's hosts.`}
|
||||
onClick={toggleShowInheritedPolicies}
|
||||
/>
|
||||
)}
|
||||
|
|
|
|||
|
|
@ -130,7 +130,7 @@ describe("PolicyForm - component", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("disables run button with tooltip for globally disabled queries", async () => {
|
||||
it("disables run button with tooltip when live queries are globally disabled", async () => {
|
||||
const render = createCustomRenderer({
|
||||
context: {
|
||||
policy: {
|
||||
|
|
|
|||
|
|
@ -460,9 +460,11 @@ const PolicyForm = ({
|
|||
>
|
||||
<TooltipWrapper
|
||||
tipContent={
|
||||
"<p>If automations are turned on, this<br/> information is included.</p>"
|
||||
<p>
|
||||
If automations are turned on, this
|
||||
<br /> information is included.
|
||||
</p>
|
||||
}
|
||||
isDelayed
|
||||
>
|
||||
Critical:
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -153,9 +153,11 @@ const SaveNewPolicyModal = ({
|
|||
>
|
||||
<TooltipWrapper
|
||||
tipContent={
|
||||
"<p>If automations are turned on, this<br/> information is included.</p>"
|
||||
<p>
|
||||
If automations are turned on, this
|
||||
<br /> information is included.
|
||||
</p>
|
||||
}
|
||||
isDelayed
|
||||
>
|
||||
Critical:
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -39,7 +39,12 @@ const PreviewDataModal = ({
|
|||
<div className={`${baseClass}__preview-modal`}>
|
||||
<p>
|
||||
<TooltipWrapper
|
||||
tipContent={`The "snapshot" key includes the query's results. These will be unique to your query.`}
|
||||
tipContent={
|
||||
<>
|
||||
The "snapshot" key includes the query's results.
|
||||
These will be unique to your query.
|
||||
</>
|
||||
}
|
||||
>
|
||||
The data sent to your configured log destination will look similar
|
||||
to the following JSON:
|
||||
|
|
|
|||
|
|
@ -197,9 +197,12 @@ const generateTableHeaders = ({
|
|||
return (
|
||||
<div>
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
This is the average performance impact across <br />
|
||||
all hosts where this query was scheduled.`}
|
||||
tipContent={
|
||||
<>
|
||||
This is the average performance impact across <br />
|
||||
all hosts where this query was scheduled.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Performance impact
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -255,8 +255,15 @@ const QueryDetailsPage = ({
|
|||
<div className={`${baseClass}__settings`}>
|
||||
<div className={`${baseClass}__automations`}>
|
||||
<TooltipWrapper
|
||||
// TODO - change to JSX after tooltip refactor
|
||||
tipContent={`Query automations let you send data to your log <br />destination on a schedule. When automations are <b>on</b>, <br />data is sent according to a query’s frequency.`}
|
||||
tipContent={
|
||||
<>
|
||||
Query automations let you send data to your log <br />
|
||||
destination on a schedule. When automations are <b>
|
||||
on
|
||||
</b>, <br />
|
||||
data is sent according to a query's frequency.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Automations:
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -38,10 +38,6 @@
|
|||
display: flex;
|
||||
gap: $pad-large;
|
||||
font-size: $x-small;
|
||||
// TODO - remove once refactored tooltip wrapper is merged
|
||||
.component__tooltip-wrapper__element__underline::after {
|
||||
bottom: 0px;
|
||||
}
|
||||
}
|
||||
|
||||
&__automations,
|
||||
|
|
|
|||
|
|
@ -67,18 +67,50 @@ const NoResults = ({
|
|||
// In order of empty page priority
|
||||
if (disabledCaching) {
|
||||
const tipContent = () => {
|
||||
// TODO - change to JSX with refactor tooltipwrapper merge
|
||||
if (disabledCachingGlobally) {
|
||||
return `<div>The following setting prevents saving this query's results in Fleet:</div>\
|
||||
<div> • Query reports are globally disabled in organization settings.</div>`;
|
||||
return (
|
||||
<>
|
||||
{" "}
|
||||
<div>
|
||||
The following setting prevents saving this query's results
|
||||
in Fleet:
|
||||
</div>
|
||||
\
|
||||
<div>
|
||||
• Query reports are globally disabled in organization
|
||||
settings.
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (discardDataEnabled) {
|
||||
return `<div>The following setting prevents saving this query's results in Fleet:</div>\
|
||||
<div> • This query has <b>Discard data</b> enabled.</div>`;
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
The following setting prevents saving this query's results
|
||||
in Fleet:
|
||||
</div>
|
||||
\
|
||||
<div>
|
||||
• This query has <b>Discard data</b> enabled.
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
if (!loggingSnapshot) {
|
||||
return `<div>The following setting prevents saving this query's results in Fleet:</div>\
|
||||
<div> • The logging setting for this query is not <b>Snapshot</b>.</div>`;
|
||||
return (
|
||||
<>
|
||||
<div>
|
||||
The following setting prevents saving this query's results
|
||||
in Fleet:
|
||||
</div>
|
||||
\
|
||||
<div>
|
||||
• The logging setting for this query is not{" "}
|
||||
<b>Snapshot</b>.
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
return "Unknown";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -114,10 +114,16 @@ const QueryReport = ({
|
|||
return (
|
||||
<div className={`${baseClass}__count `}>
|
||||
<TooltipWrapper
|
||||
tipContent={`Fleet has retained a sample of early results for
|
||||
reference. Reporting is paused until existing data is deleted. <br/><br/>
|
||||
You can reset this report by updating the query's SQL, or by
|
||||
temporarily enabling the <b>discard data</b> setting and disabling it again.`}
|
||||
tipContent={
|
||||
<>
|
||||
Fleet has retained a sample of early results for reference.
|
||||
Reporting is paused until existing data is deleted. <br />
|
||||
<br />
|
||||
You can reset this report by updating the query's SQL, or
|
||||
by temporarily enabling the <b>discard data</b> setting and
|
||||
disabling it again.
|
||||
</>
|
||||
}
|
||||
>
|
||||
{`${count} result${count === 1 ? "" : "s"}`}
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -30,10 +30,6 @@ describe("DiscardDataOption component", () => {
|
|||
|
||||
expect(screen.getByText(/Discard data/)).toBeInTheDocument();
|
||||
expect(screen.getByText(/This setting is ignored/)).toBeInTheDocument();
|
||||
|
||||
await fireEvent.mouseOver(screen.getByText(/globally disabled/));
|
||||
|
||||
expect(screen.getByText(/A Fleet administrator/)).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('Restores normal help text when disabled and then "Edit anyway" is clicked', async () => {
|
||||
|
|
|
|||
|
|
@ -32,12 +32,16 @@ const DiscardDataOption = ({
|
|||
<>
|
||||
This setting is ignored because query reports in Fleet have been{" "}
|
||||
<TooltipWrapper
|
||||
// TODO - use JSX once new tooltipwrapper is merged
|
||||
tipContent={
|
||||
"A Fleet administrator can enable query reports under <br />\
|
||||
<b>Organization settings > Advanced options > Disable query reports</b>."
|
||||
<>
|
||||
A Fleet administrator can enable query reports under <br />
|
||||
<b>
|
||||
Organization settings > Advanced options > Disable query
|
||||
reports
|
||||
</b>
|
||||
.
|
||||
</>
|
||||
}
|
||||
position="bottom"
|
||||
>
|
||||
{"globally disabled."}
|
||||
</TooltipWrapper>{" "}
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import { IVulnerability } from "interfaces/vulnerability";
|
|||
import PATHS from "router/paths";
|
||||
import {
|
||||
formatFloatAsPercentage,
|
||||
getSoftwareBundleTooltipMarkup,
|
||||
getSoftwareBundleTooltipJSX,
|
||||
} from "utilities/helpers";
|
||||
import { DEFAULT_EMPTY_CELL_VALUE } from "utilities/constants";
|
||||
|
||||
|
|
@ -79,13 +79,15 @@ const generateEPSSColumnHeader = (isSandboxMode = false) => {
|
|||
Header: (headerProps: IHeaderProps): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
The probability that this software will be exploited
|
||||
<br />
|
||||
in the next 30 days (EPSS probability). This data is
|
||||
<br />
|
||||
reported by FIRST.org.
|
||||
`}
|
||||
tipContent={
|
||||
<>
|
||||
The probability that this software will be exploited
|
||||
<br />
|
||||
in the next 30 days (EPSS probability). This data is
|
||||
<br />
|
||||
reported by FIRST.org.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Probability of exploit
|
||||
</TooltipWrapper>
|
||||
|
|
@ -205,7 +207,7 @@ const generateTableHeaders = (
|
|||
customOnClick={onClickSoftware}
|
||||
value={name}
|
||||
tooltipContent={
|
||||
bundle ? getSoftwareBundleTooltipMarkup(bundle) : undefined
|
||||
bundle ? getSoftwareBundleTooltipJSX(bundle) : undefined
|
||||
}
|
||||
/>
|
||||
);
|
||||
|
|
|
|||
|
|
@ -92,10 +92,14 @@ const generateVulnTableHeaders = (
|
|||
Header: (headerProps: IHeaderProps): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
The probability that this vulnerability will be exploited in the next 30 days (EPSS probability).<br />
|
||||
This data is reported by FIRST.org.
|
||||
`}
|
||||
tipContent={
|
||||
<>
|
||||
The probability that this vulnerability will be exploited in the
|
||||
next 30 days (EPSS probability).
|
||||
<br />
|
||||
This data is reported by FIRST.org.
|
||||
</>
|
||||
}
|
||||
>
|
||||
Probability of exploit
|
||||
</TooltipWrapper>
|
||||
|
|
@ -121,10 +125,15 @@ const generateVulnTableHeaders = (
|
|||
Header: (headerProps: IHeaderProps): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
The worst case impact across different environments (CVSS base score).<br />
|
||||
This data is reported by the National Vulnerability Database (NVD).
|
||||
`}
|
||||
tipContent={
|
||||
<>
|
||||
The worst case impact across different environments (CVSS base
|
||||
score).
|
||||
<br />
|
||||
This data is reported by the National Vulnerability Database
|
||||
(NVD).
|
||||
</>
|
||||
}
|
||||
>
|
||||
Severity
|
||||
</TooltipWrapper>
|
||||
|
|
@ -151,10 +160,13 @@ const generateVulnTableHeaders = (
|
|||
Header: (headerProps: IHeaderProps): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`
|
||||
The vulnerability has been actively exploited in the wild. This data is reported by
|
||||
the Cybersecurity and Infrustructure Security Agency (CISA).
|
||||
`}
|
||||
tipContent={
|
||||
<>
|
||||
The vulnerability has been actively exploited in the wild. This
|
||||
data is reported by the Cybersecurity and Infrustructure
|
||||
Security Agency (CISA).
|
||||
</>
|
||||
}
|
||||
>
|
||||
Known exploit
|
||||
</TooltipWrapper>
|
||||
|
|
@ -181,7 +193,12 @@ const generateVulnTableHeaders = (
|
|||
Header: (headerProps: IHeaderProps): JSX.Element => {
|
||||
const titleWithToolTip = (
|
||||
<TooltipWrapper
|
||||
tipContent={`The date this vulnerability was published in the National Vulnerability Database (NVD).`}
|
||||
tipContent={
|
||||
<>
|
||||
The date this vulnerability was published in the National
|
||||
Vulnerability Database (NVD).
|
||||
</>
|
||||
}
|
||||
>
|
||||
Published
|
||||
</TooltipWrapper>
|
||||
|
|
|
|||
|
|
@ -24,6 +24,7 @@ $ui-shadow: #e9e9e9;
|
|||
$ui-vibrant-blue-50: rgba(106, 103, 254, 0.5);
|
||||
$ui-vibrant-blue-25: #d9d9fe;
|
||||
$ui-vibrant-blue-10: #f1f0ff; // rgba(241, 240, 255, 1)
|
||||
$tooltip-bg: #3e4771;
|
||||
|
||||
// Notifications & status & specific messages
|
||||
$ui-offline: #8b8fa2;
|
||||
|
|
|
|||
|
|
@ -2,6 +2,14 @@ import "@testing-library/jest-dom";
|
|||
|
||||
import mockServer from "./mock-server";
|
||||
|
||||
// Needed for testing react-tooltip-5
|
||||
window.CSS.supports = jest.fn();
|
||||
global.ResizeObserver = jest.fn().mockImplementation(() => ({
|
||||
observe: jest.fn(),
|
||||
unobserve: jest.fn(),
|
||||
disconnect: jest.fn(),
|
||||
}));
|
||||
|
||||
// Mock server setup
|
||||
beforeAll(() => mockServer.listen());
|
||||
afterEach(() => mockServer.resetHandlers());
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import React from "react";
|
||||
import {
|
||||
isEmpty,
|
||||
flatMap,
|
||||
|
|
@ -34,8 +35,8 @@ import {
|
|||
ISelectedTargetsForApi,
|
||||
IPackTargets,
|
||||
} from "interfaces/target";
|
||||
import { ITeam, ITeamSummary } from "interfaces/team";
|
||||
import { IUser, UserRole } from "interfaces/user";
|
||||
import { ITeam } from "interfaces/team";
|
||||
import { UserRole } from "interfaces/user";
|
||||
|
||||
import stringUtils from "utilities/strings";
|
||||
import sortUtils from "utilities/sort";
|
||||
|
|
@ -92,40 +93,6 @@ const labelSlug = (label: ILabel): string => {
|
|||
return `labels/${id}`;
|
||||
};
|
||||
|
||||
const statusKey = [
|
||||
{
|
||||
id: "new",
|
||||
count: 0,
|
||||
description: "Hosts that have been enrolled to Fleet in the last 24 hours.",
|
||||
display_text: "New",
|
||||
title_description: "(added in last 24hrs)",
|
||||
type: "status",
|
||||
},
|
||||
{
|
||||
id: "online",
|
||||
count: 0,
|
||||
description: "Hosts that have recently checked-in to Fleet.",
|
||||
display_text: "Online",
|
||||
type: "status",
|
||||
},
|
||||
{
|
||||
id: "missing",
|
||||
count: 0,
|
||||
description: "Hosts that have not been online in 30 days or more.",
|
||||
display_text: "Missing",
|
||||
slug: "missing",
|
||||
statusLabelKey: "missing_count",
|
||||
type: "status",
|
||||
},
|
||||
{
|
||||
id: "offline",
|
||||
count: 0,
|
||||
description: "Hosts that have not checked-in to Fleet recently.",
|
||||
display_text: "Offline",
|
||||
type: "status",
|
||||
},
|
||||
];
|
||||
|
||||
const isLabel = (target: ISelectTargetsEntity) => {
|
||||
return "label_type" in target;
|
||||
};
|
||||
|
|
@ -801,7 +768,7 @@ export const syntaxHighlight = (json: any): string => {
|
|||
/* eslint-disable no-useless-escape */
|
||||
return jsonStr.replace(
|
||||
/("(\\u[a-zA-Z0-9]{4}|\\[^u]|[^\\"])*"(\s*:)?|\b(true|false|null)\b|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?)/g,
|
||||
function (match) {
|
||||
(match) => {
|
||||
let cls = "number";
|
||||
if (/^"/.test(match)) {
|
||||
if (/:$/.test(match)) {
|
||||
|
|
@ -900,15 +867,13 @@ export const getNextLocationPath = ({
|
|||
return queryString ? `/${nextLocation}?${queryString}` : `/${nextLocation}`;
|
||||
};
|
||||
|
||||
export const getSoftwareBundleTooltipMarkup = (bundle: string) => {
|
||||
return `
|
||||
<span>
|
||||
<b>Bundle identifier: </b>
|
||||
<br />
|
||||
${bundle}
|
||||
</span>
|
||||
`;
|
||||
};
|
||||
export const getSoftwareBundleTooltipJSX = (bundle: string) => (
|
||||
<span>
|
||||
<b>Bundle identifier: </b>
|
||||
<br />
|
||||
{bundle}
|
||||
</span>
|
||||
);
|
||||
|
||||
export const TAGGED_TEMPLATES = {
|
||||
queryByHostRoute: (hostId: number | undefined | null) => {
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
import { flatMap, map } from "lodash";
|
||||
import { flatMap } from "lodash";
|
||||
|
||||
import { IOsQueryTable, IQueryTableColumn } from "interfaces/osquery_table";
|
||||
import { IOsQueryTable } from "interfaces/osquery_table";
|
||||
|
||||
import osqueryFleetTablesJSON from "../../schema/osquery_fleet_schema.json";
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@
|
|||
"react-table": "7.7.0",
|
||||
"react-tabs": "3.2.3",
|
||||
"react-tooltip": "4.2.21",
|
||||
"react-tooltip-5": "npm:react-tooltip@5.21.3",
|
||||
"remark-gfm": "3.0.1",
|
||||
"select": "1.1.2",
|
||||
"sockjs-client": "1.6.1",
|
||||
|
|
|
|||
15
yarn.lock
15
yarn.lock
|
|
@ -2665,7 +2665,7 @@
|
|||
dependencies:
|
||||
"@floating-ui/utils" "^0.1.3"
|
||||
|
||||
"@floating-ui/dom@^1.5.1":
|
||||
"@floating-ui/dom@^1.0.0", "@floating-ui/dom@^1.5.1":
|
||||
version "1.5.3"
|
||||
resolved "https://registry.yarnpkg.com/@floating-ui/dom/-/dom-1.5.3.tgz#54e50efcb432c06c23cd33de2b575102005436fa"
|
||||
integrity sha512-ClAbQnEqJAKCJOEbbLo5IUlZHkNszqhuxS4fHAVxRPXPya6Ysf2G8KypnYcOTpx6I8xcgF9bbHb6g/2KpbV8qA==
|
||||
|
|
@ -7271,6 +7271,11 @@ classnames@^2.2.4:
|
|||
resolved "https://registry.npmjs.org/classnames/-/classnames-2.3.1.tgz"
|
||||
integrity sha512-OlQdbZ7gLfGarSqxesMesDa5uz7KFbID8Kpq/SxIoNGDqY8lSYs0D+hhtBXhcdB3rcbXArFr7vlHheLk1voeNA==
|
||||
|
||||
classnames@^2.3.0:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/classnames/-/classnames-2.3.2.tgz#351d813bf0137fcc6a76a16b88208d2560a0d924"
|
||||
integrity sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==
|
||||
|
||||
clean-css@^5.2.2:
|
||||
version "5.3.2"
|
||||
resolved "https://registry.yarnpkg.com/clean-css/-/clean-css-5.3.2.tgz#70ecc7d4d4114921f5d298349ff86a31a9975224"
|
||||
|
|
@ -15294,6 +15299,14 @@ react-tabs@3.2.3:
|
|||
clsx "^1.1.0"
|
||||
prop-types "^15.5.0"
|
||||
|
||||
"react-tooltip-5@npm:react-tooltip@5.21.3":
|
||||
version "5.21.3"
|
||||
resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-5.21.3.tgz#131d578c7ea69f96c65dbd09f071880c34b4f83d"
|
||||
integrity sha512-z3Q+Uka4D6uYxfsssPqfx1W8vw7NIHyC2ZMq+NJkWg4EpUD3w7Fwz/o+dezyUQMCHL7nO/2sFbtWIrkyxktq2Q==
|
||||
dependencies:
|
||||
"@floating-ui/dom" "^1.0.0"
|
||||
classnames "^2.3.0"
|
||||
|
||||
react-tooltip@*, react-tooltip@4.2.21:
|
||||
version "4.2.21"
|
||||
resolved "https://registry.yarnpkg.com/react-tooltip/-/react-tooltip-4.2.21.tgz#840123ed86cf33d50ddde8ec8813b2960bfded7f"
|
||||
|
|
|
|||
Loading…
Reference in a new issue