mirror of
https://github.com/fleetdm/fleet
synced 2026-05-24 09:28:54 +00:00
remove unused code and change copy (#7376)
This commit is contained in:
parent
7b612aa030
commit
9f9cb597fa
12 changed files with 11705 additions and 12841 deletions
|
|
@ -1,137 +0,0 @@
|
|||
import React, { useState, useCallback } from "react";
|
||||
import { filter } from "lodash";
|
||||
|
||||
import { ILabel } from "interfaces/label";
|
||||
import { PLATFORM_LABEL_DISPLAY_ORDER } from "utilities/constants";
|
||||
import { escapeRegEx } from "utilities/regex";
|
||||
|
||||
import Spinner from "components/Spinner";
|
||||
import Button from "components/buttons/Button";
|
||||
// @ts-ignore
|
||||
import InputField from "components/forms/fields/InputField";
|
||||
// @ts-ignore
|
||||
import PanelGroup from "components/side_panels/HostSidePanel/PanelGroup";
|
||||
// @ts-ignore
|
||||
import SecondarySidePanelContainer from "components/side_panels/SecondarySidePanelContainer";
|
||||
|
||||
import PlusIcon from "../../../../assets/images/icon-plus-16x16@2x.png";
|
||||
|
||||
const baseClass = "host-side-panel";
|
||||
|
||||
interface IHostSidePanelProps {
|
||||
labels?: ILabel[];
|
||||
onAddLabelClick: (evt: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
onLabelClick: (
|
||||
selectedLabel: ILabel
|
||||
) => (evt: React.MouseEvent<HTMLButtonElement>) => void;
|
||||
selectedFilter: string | undefined;
|
||||
canAddNewLabel: boolean;
|
||||
isLabelsLoading: boolean;
|
||||
}
|
||||
|
||||
const HostSidePanel = ({
|
||||
labels,
|
||||
onAddLabelClick,
|
||||
onLabelClick,
|
||||
selectedFilter,
|
||||
canAddNewLabel,
|
||||
isLabelsLoading,
|
||||
}: IHostSidePanelProps): JSX.Element => {
|
||||
const [labelFilter, setLabelFilter] = useState<string>("");
|
||||
|
||||
const onFilterLabels = useCallback(
|
||||
(filterString: string): void => {
|
||||
setLabelFilter(filterString.toLowerCase());
|
||||
},
|
||||
[setLabelFilter]
|
||||
);
|
||||
|
||||
if (isLabelsLoading || !labels) {
|
||||
return <Spinner />;
|
||||
}
|
||||
|
||||
const allHostLabels = filter(labels, { type: "all" });
|
||||
|
||||
const hostPlatformLabels = (() => {
|
||||
const unorderedList: ILabel[] = labels.filter(
|
||||
(label) => label.type === "platform"
|
||||
);
|
||||
|
||||
const orderedList: ILabel[] = [];
|
||||
PLATFORM_LABEL_DISPLAY_ORDER.forEach((name) => {
|
||||
const label = unorderedList.find((el) => el.name === name);
|
||||
label && orderedList.push(label);
|
||||
});
|
||||
|
||||
return orderedList.filter(
|
||||
(label) =>
|
||||
["macOS", "MS Windows", "All Linux"].includes(label.name) ||
|
||||
label.count !== 0
|
||||
);
|
||||
})();
|
||||
|
||||
const customLabels = filter(labels, (label) => {
|
||||
const lowerDisplayText = label.display_text.toLowerCase();
|
||||
|
||||
return (
|
||||
label.type === "custom" &&
|
||||
lowerDisplayText.match(escapeRegEx(labelFilter))
|
||||
);
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={baseClass}>
|
||||
<PanelGroup
|
||||
groupItems={allHostLabels}
|
||||
onLabelClick={onLabelClick}
|
||||
selectedFilter={selectedFilter}
|
||||
type="all-hosts"
|
||||
/>
|
||||
|
||||
<h3>Operating systems</h3>
|
||||
<PanelGroup
|
||||
groupItems={hostPlatformLabels}
|
||||
onLabelClick={onLabelClick}
|
||||
selectedFilter={selectedFilter}
|
||||
type="platform"
|
||||
/>
|
||||
<div className="title">
|
||||
<div>
|
||||
<h3>Labels</h3>
|
||||
</div>
|
||||
<div>
|
||||
{canAddNewLabel && (
|
||||
<Button
|
||||
variant="text-icon"
|
||||
onClick={onAddLabelClick}
|
||||
className={`${baseClass}__add-label-btn`}
|
||||
>
|
||||
<span>
|
||||
Add label <img src={PlusIcon} alt="Add label icon" />
|
||||
</span>
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
<div
|
||||
className={`${baseClass}__panel-group-item ${baseClass}__panel-group-item--filter`}
|
||||
>
|
||||
<InputField
|
||||
name="tags-filter"
|
||||
onChange={onFilterLabels}
|
||||
placeholder="Filter labels by name..."
|
||||
value={labelFilter}
|
||||
inputWrapperClass={`${baseClass}__filter-labels`}
|
||||
/>
|
||||
</div>
|
||||
<PanelGroup
|
||||
groupItems={customLabels}
|
||||
onLabelClick={onLabelClick}
|
||||
selectedFilter={selectedFilter}
|
||||
type="label"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default HostSidePanel;
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
import { noop } from "lodash";
|
||||
|
||||
import labelInterface from "interfaces/label";
|
||||
import PanelGroupItem from "components/side_panels/HostSidePanel/PanelGroupItem";
|
||||
import statusLabelsInterface from "interfaces/status_labels";
|
||||
|
||||
class PanelGroup extends Component {
|
||||
static propTypes = {
|
||||
groupItems: PropTypes.arrayOf(labelInterface),
|
||||
onLabelClick: PropTypes.func,
|
||||
selectedFilter: PropTypes.string,
|
||||
statusLabels: statusLabelsInterface,
|
||||
type: PropTypes.string,
|
||||
};
|
||||
|
||||
static defaultProps = {
|
||||
onLabelClick: noop,
|
||||
};
|
||||
|
||||
renderGroupItem = (item) => {
|
||||
const { onLabelClick, selectedFilter, statusLabels, type } = this.props;
|
||||
const selected =
|
||||
(item && item.slug === selectedFilter) || type === selectedFilter;
|
||||
|
||||
return (
|
||||
<PanelGroupItem
|
||||
isSelected={selected}
|
||||
item={item}
|
||||
key={item.display_text}
|
||||
onLabelClick={onLabelClick(item)}
|
||||
statusLabels={statusLabels}
|
||||
type={type}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
render() {
|
||||
const { groupItems, type } = this.props;
|
||||
const { renderGroupItem } = this;
|
||||
const baseClass = "panel-group";
|
||||
|
||||
let multipleLabelsClass = baseClass;
|
||||
if (type === "label" && groupItems.length > 6) {
|
||||
multipleLabelsClass = `${baseClass}__${type}--scroll-labels`;
|
||||
}
|
||||
|
||||
return (
|
||||
<div
|
||||
className={`${baseClass} ${baseClass}__${type} ${multipleLabelsClass}`}
|
||||
>
|
||||
{groupItems.map((item) => {
|
||||
return renderGroupItem(item);
|
||||
})}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export default PanelGroup;
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import React from "react";
|
||||
import { render, screen } from "@testing-library/react";
|
||||
|
||||
import PanelGroup from "./PanelGroup";
|
||||
|
||||
describe("PanelGroup - component", () => {
|
||||
const validPanelGroupItems = [
|
||||
{ type: "all", display_text: "All Hosts", hosts_count: 20 },
|
||||
{ type: "platform", display_text: "MAC OS", hosts_count: 10 },
|
||||
];
|
||||
|
||||
render(<PanelGroup groupItems={validPanelGroupItems} />);
|
||||
|
||||
it("renders a PanelGroupItem for each group item", () => {
|
||||
const panelGroupItems = screen.queryAllByRole("button");
|
||||
|
||||
expect(panelGroupItems.length).toEqual(2);
|
||||
});
|
||||
});
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
.panel-group {
|
||||
&__label {
|
||||
max-height: 280px;
|
||||
overflow-y: auto;
|
||||
position: relative;
|
||||
|
||||
&--scroll-labels {
|
||||
&:before {
|
||||
content: "";
|
||||
position: sticky;
|
||||
display: block;
|
||||
z-index: 1;
|
||||
top: -2px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 17px;
|
||||
// We explicityly use rgba(255,255,255,0) because it's equivalent to transparent for most broswers except Safari.
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
$ui-off-white,
|
||||
rgba(255, 255, 255, 0)
|
||||
);
|
||||
}
|
||||
|
||||
&:after {
|
||||
content: "";
|
||||
position: sticky;
|
||||
display: block;
|
||||
bottom: -1px;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 17px;
|
||||
// We explicityly use rgba(255,255,255,0) because it's equivalent to transparent for most broswers except Safari.
|
||||
background-image: linear-gradient(
|
||||
to bottom,
|
||||
rgba(255, 255, 255, 0),
|
||||
$ui-off-white
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export { default } from "./PanelGroup";
|
||||
|
|
@ -1,77 +0,0 @@
|
|||
import React from "react";
|
||||
import classnames from "classnames";
|
||||
|
||||
import { ILabel } from "interfaces/label";
|
||||
import { PLATFORM_LABEL_DISPLAY_NAMES } from "utilities/constants";
|
||||
import darwinIcon from "../../../../../assets/images/icon-darwin-fleet-black-16x16@2x.png";
|
||||
import linuxIcon from "../../../../../assets/images/icon-linux-fleet-black-16x16@2x.png";
|
||||
import ubuntuIcon from "../../../../../assets/images/icon-ubuntu-fleet-black-16x16@2x.png";
|
||||
import centosIcon from "../../../../../assets/images/icon-centos-fleet-black-16x16@2x.png";
|
||||
import windowsIcon from "../../../../../assets/images/icon-windows-fleet-black-16x16@2x.png";
|
||||
|
||||
const baseClass = "panel-group-item";
|
||||
|
||||
const displayName = (name: string) => {
|
||||
return PLATFORM_LABEL_DISPLAY_NAMES[name] || name;
|
||||
};
|
||||
|
||||
const displayIcon = (name: string) => {
|
||||
switch (name) {
|
||||
case "macOS":
|
||||
return <img src={darwinIcon} alt="Apple icon" />;
|
||||
case "Linux":
|
||||
return <img src={linuxIcon} alt="Linux icon" />;
|
||||
case "Ubuntu Linux":
|
||||
return <img src={ubuntuIcon} alt="Ubuntu icon" />;
|
||||
case "CentOS Linux":
|
||||
return <img src={centosIcon} alt="Centos icon" />;
|
||||
case "Windows":
|
||||
return <img src={windowsIcon} alt="Windows icon" />;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
interface IPanelGroupItemProps {
|
||||
item: ILabel;
|
||||
onLabelClick: () => void;
|
||||
isSelected: boolean;
|
||||
}
|
||||
|
||||
const PanelGroupItem = ({
|
||||
item,
|
||||
onLabelClick,
|
||||
isSelected,
|
||||
}: IPanelGroupItemProps): JSX.Element => {
|
||||
const {
|
||||
count,
|
||||
display_text: displayText,
|
||||
label_type: labelType,
|
||||
name,
|
||||
} = item;
|
||||
|
||||
const wrapperClassName = classnames(
|
||||
baseClass,
|
||||
"button",
|
||||
"button--contextual-nav-item",
|
||||
`${baseClass}__${displayText.toLowerCase().replace(" ", "-")}`,
|
||||
{
|
||||
[`${baseClass}--selected`]: isSelected,
|
||||
}
|
||||
);
|
||||
|
||||
return (
|
||||
<button className={wrapperClassName} onClick={onLabelClick}>
|
||||
<div className={`${baseClass}__flexy`}>
|
||||
<span className={`${baseClass}__name`}>
|
||||
{labelType === "builtin" && displayIcon(displayName(name))}
|
||||
|
||||
{displayName(name)}
|
||||
</span>
|
||||
<span className={`${baseClass}__count`}>{count}</span>
|
||||
</div>
|
||||
</button>
|
||||
);
|
||||
};
|
||||
|
||||
export default PanelGroupItem;
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
$base-class: "panel-group-item";
|
||||
|
||||
.#{$base-class} {
|
||||
transition: color 75ms ease-in-out, background 75ms ease-in-out;
|
||||
width: 100%;
|
||||
font-size: $x-small;
|
||||
font-weight: $regular;
|
||||
color: $core-fleet-black;
|
||||
text-align: left;
|
||||
padding: 10px 0;
|
||||
margin: 2px 0;
|
||||
border-radius: 8px;
|
||||
|
||||
img {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
margin-right: $pad-xsmall;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
&.#{$base-class}--selected {
|
||||
font-weight: $bold;
|
||||
background-color: $ui-vibrant-blue-25;
|
||||
|
||||
.#{$base-class}__count {
|
||||
font-weight: $bold;
|
||||
}
|
||||
}
|
||||
|
||||
&__flexy {
|
||||
width: 100%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
&__name {
|
||||
@include ellipsis(80%);
|
||||
flex-grow: 1;
|
||||
padding-left: $pad-medium;
|
||||
}
|
||||
|
||||
&__description {
|
||||
font-size: 13px;
|
||||
margin-left: $pad-xsmall;
|
||||
text-transform: lowercase;
|
||||
}
|
||||
|
||||
&__count {
|
||||
transition: color 75ms ease-in-out;
|
||||
font-weight: $regular;
|
||||
text-align: right;
|
||||
padding-right: $pad-medium;
|
||||
font-size: $x-small;
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export { default } from "./PanelGroupItem";
|
||||
|
|
@ -1,80 +0,0 @@
|
|||
.host-side-panel {
|
||||
color: $core-fleet-black;
|
||||
|
||||
.loading-spinner {
|
||||
margin-top: 155px; // line up with host table loading spinner
|
||||
}
|
||||
|
||||
.input-icon-field {
|
||||
margin-top: 0;
|
||||
|
||||
&__label {
|
||||
display: none;
|
||||
}
|
||||
|
||||
&__icon {
|
||||
top: 6px;
|
||||
}
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: $x-small;
|
||||
font-weight: $bold;
|
||||
color: $core-fleet-black;
|
||||
margin: $pad-large 0 10px $pad-medium;
|
||||
}
|
||||
|
||||
&__add-label-btn {
|
||||
align-self: right;
|
||||
|
||||
span {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
img {
|
||||
margin-left: $pad-xsmall;
|
||||
}
|
||||
}
|
||||
|
||||
&__panel-group-item {
|
||||
color: $core-fleet-black;
|
||||
width: 100%;
|
||||
|
||||
&--filter {
|
||||
position: relative;
|
||||
|
||||
&::before {
|
||||
display: inline-block;
|
||||
position: absolute;
|
||||
padding: 5px 0 0 0; // centers spin
|
||||
content: url(../assets/images/icon-search-fleet-black-16x16@2x.png);
|
||||
transform: scale(0.5);
|
||||
height: 20px;
|
||||
top: 3px;
|
||||
left: 8px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
font-size: $small;
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
|
||||
button {
|
||||
position: relative;
|
||||
top: 12px;
|
||||
padding: 0 $pad-xsmall;
|
||||
}
|
||||
}
|
||||
|
||||
&__filter-labels {
|
||||
margin-bottom: $pad-medium;
|
||||
|
||||
.input-field {
|
||||
padding-left: 42px;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1 +0,0 @@
|
|||
export { default } from "./HostSidePanel";
|
||||
|
|
@ -151,7 +151,7 @@ const LabelFilterSelect = ({
|
|||
className={classes}
|
||||
classNamePrefix={baseClass}
|
||||
defaultMenuIsOpen={false}
|
||||
placeholder={"Filter by operating system or label"}
|
||||
placeholder={"Filter by platform or label"}
|
||||
formatOptionLabel={OptionLabel}
|
||||
menuIsOpen={shouldOpenMenu}
|
||||
value={selectedLabel}
|
||||
|
|
|
|||
Loading…
Reference in a new issue