Frontend: New CustomLink component (#8375)

This commit is contained in:
RachelElysia
2022-10-27 14:06:57 -04:00
committed by GitHub
parent ef1be16a68
commit 82ff4ab6e3
41 changed files with 349 additions and 387 deletions
@@ -1,7 +1,6 @@
import React from "react";
import { browserHistory, Link } from "react-router";
import Icon from "components/Icon";
import Button from "components/buttons/Button";
import classnames from "classnames";
interface IBackLinkProps {
@@ -0,0 +1,65 @@
import React from "react";
import Icon from "components/Icon";
import classnames from "classnames";
interface ICustomLinkProps {
url: string;
text: string;
className?: string;
newTab?: boolean;
/** Icon wraps on new line with last word */
multiline?: boolean;
}
const baseClass = "custom-link";
const CustomLink = ({
url,
text,
className,
newTab = false,
multiline = false,
}: ICustomLinkProps): JSX.Element => {
const customLinkClass = classnames(baseClass, className);
const target = newTab ? "_blank" : "";
const multilineText = text.substring(0, text.lastIndexOf(" ") + 1);
const lastWord = text.substring(text.lastIndexOf(" ") + 1, text.length);
const content = multiline ? (
<>
{multilineText}
<span className={`${baseClass}__no-wrap`}>
{lastWord}
{newTab && (
<Icon
name="external-link"
className={`${baseClass}__external-icon`}
/>
)}
</span>
</>
) : (
<>
{text}
{newTab && (
<Icon name="external-link" className={`${baseClass}__external-icon`} />
)}
</>
);
return (
<a
href={url}
target={target}
rel="noopener noreferrer"
className={customLinkClass}
>
{content}
</a>
);
};
export default CustomLink;
@@ -0,0 +1,10 @@
.custom-link {
&__no-wrap {
white-space: nowrap;
}
&__external-icon {
display: inline;
margin-left: $pad-xsmall;
}
}
+1
View File
@@ -0,0 +1 @@
export { default } from "./CustomLink";
+6 -9
View File
@@ -1,6 +1,6 @@
import React from "react";
import ExternalLinkIcon from "../../../assets/images/icon-external-link-12x12@2x.png";
import CustomLink from "components/CustomLink";
import ErrorIcon from "../../../assets/images/icon-error-16x16@2x.png";
const baseClass = "data-error";
@@ -21,14 +21,11 @@ const DataError = ({ card }: IDataErrorProps): JSX.Element => {
<span className="info__data">Refresh the page or log in again.</span>
<span className="info__data">
If this keeps happening, please&nbsp;
<a
href="https://github.com/fleetdm/fleet/issues/new/choose"
target="_blank"
rel="noopener noreferrer"
>
file an issue
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://github.com/fleetdm/fleet/issues/new/choose"
text="file an issue"
newTab
/>
</span>
</div>
</div>
@@ -6,24 +6,7 @@ import { IAceEditor } from "react-ace/lib/types";
import { noop } from "lodash";
import FleetAce from "components/FleetAce";
import ExternalLinkIcon from "../../../assets/images/icon-external-link-12x12@2x.png";
interface ICustomLinkProps {
text: React.ReactNode;
href: string;
newTab?: boolean;
}
const CustomLink = ({ text, href, newTab = false }: ICustomLinkProps) => {
const target = newTab ? "__blank" : "";
return (
<a href={href} target={target} rel="noopener noreferrer">
{text}
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
);
};
import CustomLink from "components/CustomLink";
interface IFleetMarkdownProps {
markdown: string;
@@ -46,7 +29,9 @@ const FleetMarkdown = ({ markdown, className }: IFleetMarkdownProps) => {
remarkPlugins={[remarkGfm]}
components={{
a: ({ href = "", children }) => {
return <CustomLink text={children} href={href} newTab />;
return (
<CustomLink text={String(children)} url={href} newTab multiline />
);
},
// Overrides code display to use FleetAce with Readonly overrides.
+9 -3
View File
@@ -7,22 +7,28 @@ interface IIconProps {
color?: "coreVibrantBlue" | "coreFleetBlack";
direction?: "up" | "down" | "left" | "right";
className?: string;
size?: "small" | "medium";
}
const baseClass = "icon";
const Icon = ({ name, color, direction, className }: IIconProps) => {
const Icon = ({ name, color, direction, className, size }: IIconProps) => {
const classNames = classnames(baseClass, className);
// createPassedProps creates a props object that we pass to the specific icon
// for values that are not null or undefined
const props = useMemo(() => {
const createPassedProps = () => {
return Object.assign({}, { color, direction });
return Object.assign(
{},
color === undefined ? undefined : { color },
direction === undefined ? undefined : { direction },
size === undefined ? undefined : { size }
);
};
return createPassedProps();
}, [color, direction]);
}, [color, direction, size]);
const IconComponent = ICON_MAP[name];
@@ -1,7 +1,7 @@
import classnames from "classnames";
import React from "react";
import ExternalLinkIcon from "../../../../assets/images/icon-external-link-12x12@2x.png";
import CustomLink from "components/CustomLink";
interface ISandboxDemoMessageProps {
/** message to display in the sandbox error */
@@ -24,15 +24,12 @@ const SandboxDemoMessage = ({
<div className={classes}>
<h2 className={`${baseClass}__message`}>{message}</h2>
<p className={`${baseClass}__link-message`}>
Want to learn more?
<a
href={`https://calendly.com/fleetdm/demo?utm_source=${utmSource}`}
target="_blank"
rel="noreferrer"
>
Schedule a demo
<img alt="Open external link" src={ExternalLinkIcon} />
</a>
Want to learn more?{" "}
<CustomLink
url={`https://calendly.com/fleetdm/demo?utm_source=${utmSource}`}
text={"Schedule a demo"}
newTab
/>
</p>
</div>
);
@@ -0,0 +1,31 @@
import React from "react";
interface IExternalLinkProps {
size: "small" | "medium";
}
const SIZE_MAP = {
small: "12",
medium: "16",
};
const ExternalLink = ({ size = "small" }: IExternalLinkProps) => {
return (
<svg
width={SIZE_MAP[size]}
height={SIZE_MAP[size]}
fill="none"
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 16 16"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M7.33 1.993c.593 0 1.073.473 1.073 1.057 0 .57-.457 1.035-1.029 1.057h-5.23v9.778h9.905v-5.12c0-.57.457-1.035 1.029-1.058h.043c.577 0 1.048.45 1.07 1.015l.001.042v6.178c0 .57-.456 1.035-1.028 1.057L13.12 16H1.07c-.577 0-1.048-.45-1.07-1.015L0 3.05c0-.57.457-1.034 1.029-1.056l.043-.001H7.33ZM14.929 0c.578 0 1.048.45 1.071 1.015L16 5.523c0 .584-.48 1.058-1.072 1.058-.577 0-1.048-.45-1.07-1.015l-.001-.043-.001-1.777-5.854 5.848a1.082 1.082 0 0 1-1.515.009 1.048 1.048 0 0 1-.043-1.46l.033-.036 6-5.992h-2.105c-.577 0-1.048-.45-1.07-1.015L9.3 1.058C9.3.488 9.757.023 10.329 0L14.93 0Z"
fill="#6A67FE"
/>
</svg>
);
};
export default ExternalLink;
+2
View File
@@ -8,6 +8,7 @@ import LowDiskSpaceHosts from "./LowDiskSpaceHosts";
import ApplePurple from "./ApplePurple";
import LinuxGreen from "./LinuxGreen";
import WindowsBlue from "./WindowsBlue";
import ExternalLink from "./ExternalLink";
// a mapping of the usable names of icons to the icon source.
export const ICON_MAP = {
@@ -24,6 +25,7 @@ export const ICON_MAP = {
"linux-green": LinuxGreen,
"missing-hosts": MissingHosts,
"low-disk-space-hosts": LowDiskSpaceHosts,
"external-link": ExternalLink,
};
export type IconNames = keyof typeof ICON_MAP;
@@ -1,8 +1,9 @@
import React from "react";
import CustomLink from "components/CustomLink";
import DifferentialIcon from "../../../../assets/images/icon-plus-minus-black-16x16@2x.png";
import SnapshotIcon from "../../../../assets/images/icon-snapshot-black-16x14@2x.png";
import ExternalLinkIcon from "../../../../assets/images/icon-external-link-12x12@2x.png";
const baseClass = "pack-info-side-panel";
@@ -55,18 +56,11 @@ const PackInfoSidePanel = () => {
</ul>
<p>
Learn more about log aggregation in the{" "}
<a
href="https://osquery.readthedocs.io/en/stable/deployment/log-aggregation/"
target="_blank"
rel="noopener noreferrer"
>
documentation
<img
src={ExternalLinkIcon}
alt="Open external link"
id="new-tab-icon"
/>
</a>
<CustomLink
url="https://osquery.readthedocs.io/en/stable/deployment/log-aggregation/"
text="documentation"
newTab
/>
</p>
</div>
);
+7 -9
View File
@@ -8,9 +8,9 @@ import paths from "router/paths";
import useDeepEffect from "hooks/useDeepEffect";
import FlashMessage from "components/FlashMessage";
import SiteTopNav from "components/top_nav/SiteTopNav";
import CustomLink from "components/CustomLink";
import { INotification } from "interfaces/notification";
import { licenseExpirationWarning } from "utilities/helpers";
import ExternalLinkIcon from "../../../assets/images/icon-external-link-12x12@2x.png";
import smallScreenImage from "../../../assets/images/small-screen-160x80@2x.png";
@@ -23,14 +23,12 @@ const expirationMessage = (
<>
Your license for Fleet Premium is about to expire. If youd like to renew or
have questions about downgrading,{" "}
<a
href="https://fleetdm.com/docs/using-fleet/faq#how-do-i-downgrade-from-fleet-premium-to-fleet-free"
target="_blank"
rel="noopener noreferrer"
>
please head to the Fleet documentation
<img src={ExternalLinkIcon} alt="Open external link" id="new-tab-icon" />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/faq#how-do-i-downgrade-from-fleet-premium-to-fleet-free"
text="please head to the Fleet documentation"
newTab
multiline
/>
</>
);
+11 -17
View File
@@ -33,6 +33,7 @@ import { ITableQueryData } from "components/TableContainer";
import TeamsDropdown from "components/TeamsDropdown";
import Spinner from "components/Spinner";
import CustomLink from "components/CustomLink";
// @ts-ignore
import Dropdown from "components/forms/fields/Dropdown";
import MainContent from "components/MainContent";
@@ -49,7 +50,6 @@ import Mdm from "./cards/MDM";
import Munki from "./cards/Munki";
import OperatingSystems from "./cards/OperatingSystems";
import AddHostsModal from "../../components/AddHostsModal";
import ExternalLinkIcon from "../../../assets/images/icon-external-link-12x12@2x.png";
const baseClass = "dashboard-page";
@@ -476,14 +476,11 @@ const DashboardPage = (): JSX.Element => {
description: (
<p>
Munki is a tool for managing software on macOS devices.{" "}
<a
href="https://www.munki.org/munki/"
target="_blank"
rel="noopener noreferrer"
>
Learn about Munki
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://www.munki.org/munki/"
text="Learn about Munki"
newTab
/>
</p>
),
children: (
@@ -503,14 +500,11 @@ const DashboardPage = (): JSX.Element => {
description: (
<p>
MDM is used to manage configuration on macOS devices.{" "}
<a
href="https://support.apple.com/guide/deployment/intro-to-mdm-depc0aadd3fe/web"
target="_blank"
rel="noopener noreferrer"
>
Learn about MDM
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://support.apple.com/guide/deployment/intro-to-mdm-depc0aadd3fe/web"
text="Learn about MDM"
newTab
/>
</p>
),
children: (
@@ -18,8 +18,7 @@ import TableContainer from "components/TableContainer";
import Spinner from "components/Spinner";
import TableDataError from "components/DataError";
import LastUpdatedText from "components/LastUpdatedText";
import ExternalLinkIcon from "../../../../../assets/images/icon-external-link-12x12@2x.png";
import CustomLink from "components/CustomLink";
import generateTableHeaders from "./OperatingSystemsTableConfig";
@@ -89,17 +88,12 @@ const OperatingSystems = ({
<p>
{OS_VENDOR_BY_PLATFORM[selectedPlatform]} releases updates and fixes for
supported operating systems.{" "}
<a
href={OS_END_OF_LIFE_LINK_BY_PLATFORM[selectedPlatform]}
target="_blank"
rel="noreferrer noopener"
>
See supported operating{" "}
<span className="no-wrap">
systems
<img alt="Open external link" src={ExternalLinkIcon} />
</span>
</a>
<CustomLink
url={OS_END_OF_LIFE_LINK_BY_PLATFORM[selectedPlatform]}
text="See supported operating systems"
newTab
multiline
/>
</p>
) : null;
@@ -10,7 +10,7 @@ import ForgotPasswordForm from "components/forms/ForgotPasswordForm";
import StackedWhiteBoxes from "components/StackedWhiteBoxes";
import AuthenticationFormWrapper from "components/AuthenticationFormWrapper";
import Spinner from "components/Spinner";
import ExternalLinkIcon from "../../../assets/images/icon-external-link-12x12@2x.png";
import CustomLink from "components/CustomLink";
const ForgotPasswordPage = () => {
const [email, setEmail] = useState("");
@@ -54,15 +54,11 @@ const ForgotPasswordPage = () => {
<br />
<br />
You can find more information on resetting passwords at the{" "}
<a
href="https://fleetdm.com/docs/using-fleet/fleetctl-cli#using-fleetctl-with-an-api-only-user?utm_medium=fleetui&utm_campaign=get-api-token"
target="_blank"
rel="noopener noreferrer"
className="external-link"
>
Password reset FAQ
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/fleetctl-cli#using-fleetctl-with-an-api-only-user?utm_medium=fleetui&utm_campaign=get-api-token"
text="Password reset FAQ"
newTab
/>
</p>
</div>
);
@@ -25,9 +25,9 @@ import SandboxGate from "components/Sandbox/SandboxGate";
import SandboxDemoMessage from "components/Sandbox/SandboxDemoMessage";
import MainContent from "components/MainContent";
import SidePanelContent from "components/SidePanelContent";
import CustomLink from "components/CustomLink";
import UserSidePanel from "./UserSidePanel";
import ExternalLinkIcon from "../../../assets/images/icon-external-link-12x12@2x.png";
const baseClass = "user-settings";
@@ -188,14 +188,11 @@ const UserSettingsPage = ({
<p>
<strong>This token expires.</strong> If you want an API key for a
permanent integration, create an&nbsp;
<a
href="https://fleetdm.com/docs/using-fleet/fleetctl-cli#using-fleetctl-with-an-api-only-user?utm_medium=fleetui&utm_campaign=get-api-token"
target="_blank"
rel="noopener noreferrer"
>
API-only user
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/fleetctl-cli#using-fleetctl-with-an-api-only-user?utm_medium=fleetui&utm_campaign=get-api-token"
text="API-only user"
newTab
/>
&nbsp;instead.
</p>
</InfoBanner>
@@ -205,14 +202,11 @@ const UserSettingsPage = ({
<p className="token-message">
This token is intended for SSO users to authenticate in the fleetctl
CLI. It expires based on the{" "}
<a
href="https://fleetdm.com/docs/deploying/configuration#session-duration?utm_medium=fleetui&utm_campaign=get-api-token"
target="_blank"
rel="noopener noreferrer"
>
session duration configuration
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/deploying/configuration#session-duration?utm_medium=fleetui&utm_campaign=get-api-token"
text="session duration configuration"
newTab
/>
</p>
<div className="modal-cta-wrap">
<Button onClick={onToggleApiTokenModal} type="button">
@@ -10,7 +10,8 @@ import validateYaml from "components/forms/validators/validate_yaml";
import InfoBanner from "components/InfoBanner/InfoBanner";
// @ts-ignore
import YamlAce from "components/YamlAce";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
import CustomLink from "components/CustomLink";
import { IAppConfigFormProps, IAppConfigFormErrors } from "../constants";
const baseClass = "app-config-form";
@@ -73,16 +74,13 @@ const Agents = ({
<p className={`${baseClass}__section-description`}>
Agent options configure the osquery agent. When you update agent
options, they will be applied the next time a host checks in to
Fleet.
<br />
<a
href="https://fleetdm.com/docs/using-fleet/fleet-ui#configuring-agent-options"
target="_blank"
rel="noopener noreferrer"
>
Learn more about agent options
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
Fleet.{" "}
<CustomLink
url="https://fleetdm.com/docs/using-fleet/fleet-ui#configuring-agent-options"
text="Learn more about agent options"
newTab
multiline
/>
</p>
{isPremiumTier ? (
<InfoBanner>
@@ -93,17 +91,11 @@ const Agents = ({
) : (
<InfoBanner>
Want some hosts to have different options?&nbsp;
<a
href="https://fleetdm.com/docs/using-fleet/teams"
target="_blank"
rel="noopener noreferrer"
>
Learn more about{" "}
<span className="no-wrap">
teams
<img alt="Open external link" src={ExternalLinkIcon} />
</span>
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/teams"
text="Learn more about teams"
newTab
/>
</InfoBanner>
)}
<p className={`${baseClass}__component-label`}>
@@ -7,8 +7,7 @@ import Button from "components/buttons/Button";
import InputField from "components/forms/fields/InputField";
import validUrl from "components/forms/validators/valid_url";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
import CustomLink from "components/CustomLink";
import {
DEFAULT_TRANSPARENCY_URL,
IAppConfigFormProps,
@@ -84,15 +83,12 @@ const FleetDesktop = ({
<p className={`${baseClass}__component-label`}>
When an end user clicks Transparency in the Fleet Desktop menu, by
default they are taken to{" "}
<a
className="no-wrap"
href="https://fleetdm.com/transparency"
target="_blank"
rel="noopener noreferrer"
>
https://fleetdm.com/transparency
<img src={ExternalLinkIcon} alt="Open external link" />
</a>{" "}
<CustomLink
url="https://fleetdm.com/transparency"
text="https://fleetdm.com/transparency"
newTab
multiline
/>{" "}
. You can override the URL to take them to a resource of your
choice.
</p>
@@ -2,6 +2,7 @@ import React, { useState, useEffect } from "react";
import Button from "components/buttons/Button";
import Checkbox from "components/forms/fields/Checkbox";
import CustomLink from "components/CustomLink";
// @ts-ignore
import InputField from "components/forms/fields/InputField";
import validUrl from "components/forms/validators/valid_url";
@@ -12,8 +13,6 @@ import {
IAppConfigFormErrors,
} from "../constants";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
const baseClass = "app-config-form";
interface ISsoFormData {
@@ -234,14 +233,11 @@ const Sso = ({
>
<>
Automatically create Observer user on login{" "}
<a
href="https://fleetdm.com/docs/deploying/configuration?utm_medium=fleetui&utm_source=sso-settings#just-in-time-jit-user-provisioning"
target="_blank"
rel="noopener noreferrer"
>
Learn more
<img alt="Open external link" src={ExternalLinkIcon} />
</a>
<CustomLink
url="https://fleetdm.com/docs/deploying/configuration?utm_medium=fleetui&utm_source=sso-settings#just-in-time-jit-user-provisioning"
text="Learn more"
newTab
/>
</>
</Checkbox>
</div>
@@ -5,7 +5,7 @@ import Button from "components/buttons/Button";
import Checkbox from "components/forms/fields/Checkbox";
import Modal from "components/Modal";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
import CustomLink from "components/CustomLink";
import {
IAppConfigFormProps,
IFormField,
@@ -95,14 +95,11 @@ const Statistics = ({
we can make better product decisions.
<br />
<br />
<a
href="https://fleetdm.com/docs/using-fleet/usage-statistics#usage-statistics"
target="_blank"
rel="noopener noreferrer"
>
Learn more about usage statistics
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/usage-statistics#usage-statistics"
text="Learn more about usage statistics"
newTab
/>
</p>
<div className={`${baseClass}__inputs ${baseClass}__inputs--usage`}>
<Checkbox
@@ -20,10 +20,11 @@ import configAPI from "services/entities/config";
import TableContainer from "components/TableContainer";
import TableDataError from "components/DataError";
import CustomLink from "components/CustomLink";
import AddIntegrationModal from "./components/AddIntegrationModal";
import DeleteIntegrationModal from "./components/DeleteIntegrationModal";
import EditIntegrationModal from "./components/EditIntegrationModal";
import ExternalLinkIcon from "../../../../assets/images/icon-external-link-12x12@2x.png";
import {
generateTableHeaders,
@@ -372,14 +373,11 @@ const IntegrationsPage = (): JSX.Element => {
</p>
<p>
Want to learn more?&nbsp;
<a
href="https://fleetdm.com/docs/using-fleet/automations"
target="_blank"
rel="noopener noreferrer"
>
Read about automations
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/automations"
text="Read about automations"
newTab
/>
</p>
<Button
variant="brand"
@@ -3,9 +3,9 @@ import React, { useState, useEffect } from "react";
import Modal from "components/Modal";
// @ts-ignore
import Dropdown from "components/forms/fields/Dropdown";
import CustomLink from "components/CustomLink";
import { IIntegration, IIntegrations } from "interfaces/integration";
import IntegrationForm from "../IntegrationForm";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
const baseClass = "add-integration-modal";
@@ -60,14 +60,11 @@ const AddIntegrationModal = ({
classname={`${baseClass}__destination-dropdown`}
wrapperClassName={`${baseClass}__form-field ${baseClass}__form-field--platform`}
/>
<a
href="https://github.com/fleetdm/fleet/issues/new?assignees=&labels=idea&template=feature-request.md&title="
target="_blank"
rel="noopener noreferrer"
>
Suggest a new destination
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://github.com/fleetdm/fleet/issues/new?assignees=&labels=idea&template=feature-request.md&title="
text="Suggest a new destination"
newTab
/>
</div>
)}
<IntegrationForm
@@ -17,9 +17,9 @@ import osqueryOptionsAPI from "services/entities/osquery_options";
import validateYaml from "components/forms/validators/validate_yaml";
import Button from "components/buttons/Button";
import Spinner from "components/Spinner";
import CustomLink from "components/CustomLink";
// @ts-ignore
import YamlAce from "components/YamlAce";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
const baseClass = "agent-options";
@@ -129,17 +129,12 @@ const AgentOptionsPage = ({
Agent options configure the osquery agent. When you update agent
options, they will be applied the next time a host checks in to Fleet.
<br />
<a
href="https://fleetdm.com/docs/using-fleet/fleet-ui#configuring-agent-options"
target="_blank"
rel="noopener noreferrer"
>
Learn more about agent{" "}
<span className="no-wrap">
options
<img alt="Open external link" src={ExternalLinkIcon} />
</span>
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/fleet-ui#configuring-agent-options"
text="Learn more about agent options"
newTab
multiline
/>
</p>
{isFetchingTeamOptions ? (
<Spinner />
@@ -13,11 +13,12 @@ import teamsAPI, {
import Button from "components/buttons/Button";
import TableContainer from "components/TableContainer";
import TableDataError from "components/DataError";
import CustomLink from "components/CustomLink";
import CreateTeamModal from "./components/CreateTeamModal";
import DeleteTeamModal from "./components/DeleteTeamModal";
import EditTeamModal from "./components/EditTeamModal";
import { generateTableHeaders, generateDataSet } from "./TeamTableConfig";
import ExternalLinkIcon from "../../../../assets/images/icon-external-link-12x12@2x.png";
const baseClass = "team-management";
const noTeamsClass = "no-teams";
@@ -203,14 +204,11 @@ const TeamManagementPage = (): JSX.Element => {
</p>
<p>
Want to learn more?&nbsp;
<a
href="https://fleetdm.com/docs/using-fleet/teams"
target="_blank"
rel="noopener noreferrer"
>
Read about teams
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/teams"
text="Read about teams"
newTab
/>
</p>
<Button
variant="brand"
@@ -18,9 +18,9 @@ import Checkbox from "components/forms/fields/Checkbox";
import Dropdown from "components/forms/fields/Dropdown";
import Radio from "components/forms/fields/Radio";
import InfoBanner from "components/InfoBanner/InfoBanner";
import CustomLink from "components/CustomLink";
import SelectedTeamsForm from "../SelectedTeamsForm/SelectedTeamsForm";
import SelectRoleForm from "../SelectRoleForm/SelectRoleForm";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
const baseClass = "create-user-form";
@@ -295,14 +295,11 @@ const UserForm = ({
Global users can only be members of the top level team and can
manage or observe all users, entities, and settings in Fleet.
</p>
<a
href="https://fleetdm.com/docs/using-fleet/permissions#user-permissions"
target="_blank"
rel="noopener noreferrer"
>
Learn more about user permissions
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/permissions#user-permissions"
text="Learn more about user permissions"
newTab
/>
</InfoBanner>
)}
<Dropdown
@@ -350,14 +347,11 @@ const UserForm = ({
Users can be members of multiple teams and can only manage or
observe team-specific users, entities, and settings in Fleet.
</p>
<a
href="https://fleetdm.com/docs/using-fleet/permissions#team-member-permissions"
target="_blank"
rel="noopener noreferrer"
>
Learn more about user permissions
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/permissions#team-member-permissions"
text="Learn more about user permissions"
newTab
/>
</InfoBanner>
<SelectedTeamsForm
availableTeams={availableTeams}
@@ -2,8 +2,7 @@ import React from "react";
import Button from "components/buttons/Button";
import Modal from "components/Modal";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
import CustomLink from "components/CustomLink";
export interface IInfoModalProps {
onCancel: () => void;
@@ -26,21 +25,12 @@ const InfoModal = ({ onCancel }: IInfoModalProps): JSX.Element => {
<p>With Fleet, you and your team can secure your device, together.</p>
<p>
Want to know what your organization can see?&nbsp;
<a
href="https://fleetdm.com/transparency"
target="_blank"
rel="noopener noreferrer"
>
Read about{" "}
<span className="no-wrap">
transparency
<img
className="external-link-icon"
src={ExternalLinkIcon}
alt="Open external link"
/>
</span>
</a>
<CustomLink
url="https://fleetdm.com/transparency"
text="Read about transparency"
newTab
multiline
/>
</p>
<div className="modal-cta-wrap">
<Button type="button" onClick={onCancel} variant="brand">
@@ -1,6 +1,6 @@
import React from "react";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
import CustomLink from "components/CustomLink";
const baseClass = "empty-state";
@@ -38,14 +38,11 @@ const EmptyState = ({ title, reason }: IEmptyStateProps): JSX.Element => {
<h2>{formalTitle()} has been disabled.</h2>
<p>
Check out the Fleet documentation for{" "}
<a
href="https://fleetdm.com/docs/using-fleet/configuration-files#features"
target="_blank"
rel="noopener noreferrer"
>
steps to enable this feature
<img alt="External link" src={ExternalLinkIcon} />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/configuration-files#features"
text="steps to enable this feature"
newTab
/>
</p>
</div>
);
@@ -3,13 +3,14 @@ import React from "react";
import { IHostPolicy } from "interfaces/policy";
import InfoBanner from "components/InfoBanner";
import TableContainer from "components/TableContainer";
import CustomLink from "components/CustomLink";
import {
generatePolicyTableHeaders,
generatePolicyDataSet,
} from "./HostPoliciesTable/HostPoliciesTableConfig";
import PolicyFailingCount from "./HostPoliciesTable/PolicyFailingCount";
import { isValidPolicyResponse } from "../../../ManageHostsPage/helpers";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
interface IPoliciesProps {
policies: IHostPolicy[];
@@ -69,17 +70,12 @@ const Policies = ({
<p>
This host is not updating the response for some policies. Check
out the Fleet documentation on&nbsp;
<a
href="https://fleetdm.com/docs/using-fleet/faq#why-is-my-host-not-updating-a-policys-response"
target="_blank"
rel="noopener noreferrer"
>
why the response might not be{" "}
<span className="no-wrap">
updating
<img src={ExternalLinkIcon} alt="Open external link" />
</span>
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/faq#why-is-my-host-not-updating-a-policys-response"
text="why the response might not be updating"
newTab
multiline
/>
</p>
</InfoBanner>
)}
@@ -3,7 +3,7 @@ import { syntaxHighlight } from "utilities/helpers";
import Modal from "components/Modal";
import Button from "components/buttons/Button";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
import CustomLink from "components/CustomLink";
const baseClass = "preview-data-modal";
@@ -52,14 +52,11 @@ const PreviewPayloadModal = ({
<div className={`${baseClass}__preview-modal`}>
<p>
Want to learn more about how automations in Fleet work?{" "}
<a
href="https://fleetdm.com/docs/using-fleet/automations"
target="_blank"
rel="noopener noreferrer"
>
Check out the Fleet documentation
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/automations"
text="Check out the Fleet documentation"
newTab
/>
</p>
<div className={`${baseClass}__payload-request-preview`}>
<pre>POST https://server.com/example</pre>
@@ -2,8 +2,8 @@ import React from "react";
import Modal from "components/Modal";
import Button from "components/buttons/Button";
import CustomLink from "components/CustomLink";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
import JiraTicket from "../../../../../../assets/images/ticket-policies-jira-screenshot-400x419@2x.png";
import ZendeskTicket from "../../../../../../assets/images/ticket-policies-zendesk-screenshot-400x515@2x.png";
@@ -23,14 +23,11 @@ const PreviewTicketModal = ({
<div className={`${baseClass}`}>
<p>
Want to learn more about how automations in Fleet work?{" "}
<a
href="https://fleetdm.com/docs/using-fleet/automations"
target="_blank"
rel="noopener noreferrer"
>
Check out the Fleet documentation
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/automations"
text=" Check out the Fleet documentation"
newTab
/>
</p>
<div className={`${baseClass}__example`}>
<img
@@ -22,8 +22,8 @@ import QueryEditor from "pages/policies/PolicyPage/screens/QueryEditor";
import SelectTargets from "components/LiveQuery/SelectTargets";
import MainContent from "components/MainContent";
import SidePanelContent from "components/SidePanelContent";
import CustomLink from "components/CustomLink";
import RunQuery from "pages/policies/PolicyPage/screens/RunQuery";
import ExternalLinkIcon from "../../../../assets/images/icon-external-link-12x12@2x.png";
interface IPolicyPageProps {
router: InjectedRouter;
@@ -194,14 +194,11 @@ const PolicyPage = ({
<p>
Fleet is unable to run a live query. Refresh the page or log in
again. If this keeps happening please{" "}
<a
target="_blank"
rel="noopener noreferrer"
href="https://github.com/fleetdm/fleet/issues/new/choose"
>
file an issue
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://github.com/fleetdm/fleet/issues/new/choose"
text="file an issue"
newTab
/>
</p>
</div>
</div>
@@ -7,9 +7,9 @@ import { ITableQueryData } from "components/TableContainer/TableContainer";
import Button from "components/buttons/Button";
import TableContainer from "components/TableContainer";
import generateTableHeaders from "./QueriesTableConfig";
import CustomLink from "components/CustomLink";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
import generateTableHeaders from "./QueriesTableConfig";
const baseClass = "queries-table";
const noQueriesClass = "no-queries";
@@ -66,18 +66,11 @@ const QueriesTable = ({
<>
<p>
Create a new query, or{" "}
<a
href="https://fleetdm.com/docs/using-fleet/standard-query-library"
target="_blank"
rel="noopener noreferrer"
>
import Fleets standard query library
<img
src={ExternalLinkIcon}
alt="Open external link"
id="new-tab-icon"
/>
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/standard-query-library"
text="import Fleets standard query library"
newTab
/>
</p>
<Button
variant="brand"
@@ -19,10 +19,10 @@ import QuerySidePanel from "components/side_panels/QuerySidePanel";
import MainContent from "components/MainContent";
import SidePanelContent from "components/SidePanelContent";
import SelectTargets from "components/LiveQuery/SelectTargets";
import CustomLink from "components/CustomLink";
import QueryEditor from "pages/queries/QueryPage/screens/QueryEditor";
import RunQuery from "pages/queries/QueryPage/screens/RunQuery";
import ExternalLinkIcon from "../../../../assets/images/icon-external-link-12x12@2x.png";
interface IQueryPageProps {
router: InjectedRouter;
@@ -171,14 +171,11 @@ const QueryPage = ({
<p>
Fleet is unable to run a live query. Refresh the page or log in
again. If this keeps happening please{" "}
<a
href="https://github.com/fleetdm/fleet/issues/new/choose"
target="_blank"
rel="noopener noreferrer"
>
file an issue
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://github.com/fleetdm/fleet/issues/new/choose"
text="file an issue"
newTab
/>
</p>
</div>
</div>
@@ -15,6 +15,7 @@ import InfoBanner from "components/InfoBanner/InfoBanner";
import Dropdown from "components/forms/fields/Dropdown";
// @ts-ignore
import InputField from "components/forms/fields/InputField";
import CustomLink from "components/CustomLink";
import {
FREQUENCY_DROPDOWN_OPTIONS,
PLATFORM_DROPDOWN_OPTIONS,
@@ -23,7 +24,6 @@ import {
} from "utilities/constants";
import PreviewDataModal from "../PreviewDataModal";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
const baseClass = "schedule-editor-modal";
@@ -263,14 +263,11 @@ const ScheduleEditorModal = ({
</p>
<p>
Check out the Fleet documentation on&nbsp;
<a
href="https://fleetdm.com/docs/deploying/configuration#osquery-result-log-plugin"
target="_blank"
rel="noopener noreferrer"
>
how to configure a different log destination
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/deploying/configuration#osquery-result-log-plugin"
text="how to configure a different log destination"
newTab
/>
.
</p>
</InfoBanner>
@@ -45,11 +45,11 @@ import TeamsDropdownHeader, {
} from "components/PageHeader/TeamsDropdownHeader";
import LastUpdatedText from "components/LastUpdatedText";
import MainContent from "components/MainContent";
import CustomLink from "components/CustomLink";
import generateSoftwareTableHeaders from "./SoftwareTableConfig";
import ManageAutomationsModal from "./components/ManageAutomationsModal";
import EmptySoftware from "../components/EmptySoftware";
import ExternalLinkIcon from "../../../../assets/images/icon-external-link-12x12@2x.png";
interface IManageSoftwarePageProps {
router: InjectedRouter;
@@ -484,14 +484,11 @@ const ManageSoftwarePage = ({
return (
<div>
Seeing unexpected software or vulnerabilities?{" "}
<a
href={GITHUB_NEW_ISSUE_LINK}
target="_blank"
rel="noopener noreferrer"
>
File an issue on GitHub
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url={GITHUB_NEW_ISSUE_LINK}
text="File an issue on GitHub"
newTab
/>
</div>
);
};
@@ -5,7 +5,7 @@ import { AppContext } from "context/app";
import { IVulnerability } from "interfaces/vulnerability";
import Modal from "components/Modal";
import Button from "components/buttons/Button";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
import CustomLink from "components/CustomLink";
const baseClass = "preview-data-modal";
@@ -62,14 +62,11 @@ const PreviewPayloadModal = ({
<div className={`${baseClass}__preview-modal`}>
<p>
Want to learn more about how automations in Fleet work?{" "}
<a
href="https://fleetdm.com/docs/using-fleet/automations"
target="_blank"
rel="noopener noreferrer"
>
Check out the Fleet documentation
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/automations"
text="Check out the Fleet documentation"
newTab
/>
</p>
<div className={`${baseClass}__payload-request-preview`}>
<pre>POST https://server.com/example</pre>
@@ -4,8 +4,8 @@ import { AppContext } from "context/app";
import { IIntegrationType } from "interfaces/integration";
import Modal from "components/Modal";
import Button from "components/buttons/Button";
import CustomLink from "components/CustomLink";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
import JiraTicketScreenshot from "../../../../../../assets/images/jira-screenshot-400x517@2x.png";
import ZendeskTicketScreenshot from "../../../../../../assets/images/zendesk-screenshot-400x455@2x.png";
import JiraTicketPremiumScreenshot from "../../../../../../assets/images/jira-screenshot-premium-400x517@2x.png";
@@ -52,14 +52,11 @@ const PreviewTicketModal = ({
<>
<p>
Want to learn more about how automations in Fleet work?{" "}
<a
href="https://fleetdm.com/docs/using-fleet/automations"
target="_blank"
rel="noopener noreferrer"
>
Check out the Fleet documentation
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/automations"
text="Check out the Fleet documentation"
newTab
/>
</p>
<div className={`${baseClass}__example`}>{screenshot}</div>
<div className="modal-cta-wrap">
@@ -6,7 +6,7 @@ import { formatFloatAsPercentage } from "utilities/helpers";
import HeaderCell from "components/TableContainer/DataTable/HeaderCell/HeaderCell";
import TextCell from "components/TableContainer/DataTable/TextCell";
import TooltipWrapper from "components/TooltipWrapper";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
import CustomLink from "components/CustomLink";
interface IHeaderProps {
column: {
@@ -68,17 +68,11 @@ const generateVulnTableHeaders = (isPremiumTier: boolean): IDataColumn[] => {
Header: "Vulnerability",
Cell: ({ cell: { value }, row }: ITextCellProps) => {
return (
<a
className="text-link"
href={row.original.details_link}
target="_blank"
rel="noopener noreferrer"
>
<span>
{value}
<img src={ExternalLinkIcon} alt={`link to ${value}`} />
</span>
</a>
<CustomLink
url={row.original.details_link}
text={value.toString()}
newTab
/>
);
},
},
@@ -4,9 +4,9 @@ import { ISoftware } from "interfaces/software";
import { GITHUB_NEW_ISSUE_LINK } from "utilities/constants";
import TableContainer from "components/TableContainer";
import CustomLink from "components/CustomLink";
import generateVulnTableHeaders from "./VulnTableConfig";
import ExternalLinkIcon from "../../../../../../assets/images/icon-external-link-12x12@2x.png";
const baseClass = "vulnerabilities";
@@ -23,14 +23,11 @@ const NoVulnsDetected = (): JSX.Element => {
<h1>No vulnerabilities detected for this software item.</h1>
<p>
Expecting to see vulnerabilities?{" "}
<a
href={GITHUB_NEW_ISSUE_LINK}
target="_blank"
rel="noopener noreferrer"
>
File an issue on GitHub
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url={GITHUB_NEW_ISSUE_LINK}
text="File an issue on GitHub"
newTab
/>
</p>
</div>
</div>
@@ -2,7 +2,7 @@
import React from "react";
import ExternalLinkIcon from "../../../../assets/images/icon-external-link-12x12@2x.png";
import CustomLink from "components/CustomLink";
const baseClass = "manage-software-page";
@@ -17,14 +17,11 @@ const EmptySoftware = (message: IEmptySoftware): JSX.Element => {
<h1>Software inventory is disabled.</h1>
<p>
Check out the Fleet documentation on{" "}
<a
href="https://fleetdm.com/docs/using-fleet/vulnerability-processing#configuration"
target="_blank"
rel="noopener noreferrer"
>
how to configure software inventory
<img src={ExternalLinkIcon} alt="Open external link" />
</a>
<CustomLink
url="https://fleetdm.com/docs/using-fleet/vulnerability-processing#configuration"
text="how to configure software inventory"
newTab
/>
</p>
</div>
</div>
-4
View File
@@ -46,10 +46,6 @@ a {
text-decoration: none;
}
.no-wrap {
white-space: nowrap;
}
.body-wrap {
padding: $pad-xlarge;
border-radius: 3px;