Add new loading spinner, edit text-icon buttons (spiffier) and rename SiteNavSidePanel (#1684)
- Update icon for "Edit columns" button on **Hosts** page - Update `text-icon` button variant - Add new loading spinner - Rename `SiteNavSidePanel` to `SiteTopNav` - Use `text-icon` button variant where appropriate - Disable pagination on the **Schedule** page
This commit is contained in:
Binary file not shown.
|
Before Width: | Height: | Size: 377 B |
Binary file not shown.
|
After Width: | Height: | Size: 228 B |
@@ -219,13 +219,13 @@ const TableContainer = ({
|
||||
className={`${baseClass}__table-action-button`}
|
||||
>
|
||||
<>
|
||||
{actionButtonText}
|
||||
{actionButtonIcon && (
|
||||
<img
|
||||
src={actionButtonIcon}
|
||||
alt={`${actionButtonText} icon`}
|
||||
/>
|
||||
)}
|
||||
{actionButtonText}
|
||||
</>
|
||||
</Button>
|
||||
)}
|
||||
|
||||
@@ -149,21 +149,20 @@ $base-class: "button";
|
||||
|
||||
&--text-icon {
|
||||
@include button-variant(transparent);
|
||||
padding: 0;
|
||||
border: 0;
|
||||
box-shadow: none;
|
||||
color: $core-fleet-black;
|
||||
color: $core-vibrant-blue;
|
||||
font-size: $x-small;
|
||||
font-weight: $regular;
|
||||
font-weight: $bold;
|
||||
cursor: pointer;
|
||||
|
||||
img {
|
||||
height: 14px;
|
||||
width: 14px;
|
||||
margin-right: $pad-small;
|
||||
transform: scale(0.5);
|
||||
}
|
||||
|
||||
&:active {
|
||||
box-shadow: none;
|
||||
color: $core-vibrant-blue-down;
|
||||
}
|
||||
|
||||
&:focus {
|
||||
@@ -171,9 +170,7 @@ $base-class: "button";
|
||||
}
|
||||
|
||||
&:hover {
|
||||
background-color: transparent;
|
||||
box-shadow: none;
|
||||
text-decoration: underline;
|
||||
color: $core-vibrant-blue-over;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,16 @@
|
||||
import React from "react";
|
||||
|
||||
const baseClass = "kolide-spinner";
|
||||
|
||||
const Spinner = (): JSX.Element => {
|
||||
return <div className={baseClass} />;
|
||||
return (
|
||||
<div className="card">
|
||||
<div className="ring">
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
<div />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Spinner;
|
||||
|
||||
@@ -1,39 +1,50 @@
|
||||
.kolide-spinner {
|
||||
@include size(64px);
|
||||
animation: sk-rotateplane 2.4s infinite ease-in-out;
|
||||
background-color: #ae6ddf;
|
||||
border-radius: 5px;
|
||||
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
|
||||
margin: 30px auto;
|
||||
.card {
|
||||
margin: 120px auto;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: $core-white;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
box-shadow: 0px 4px 16px rgba(0, 0, 0, 0.1);
|
||||
border-radius: 8px;
|
||||
}
|
||||
|
||||
@keyframes sk-rotateplane {
|
||||
.ring {
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
border-radius: 100%;
|
||||
border: 4px solid $core-vibrant-blue;
|
||||
}
|
||||
.ring div {
|
||||
box-sizing: border-box;
|
||||
display: block;
|
||||
position: absolute;
|
||||
width: 32px;
|
||||
height: 32px;
|
||||
margin: -4px;
|
||||
border: 4px solid $core-white;
|
||||
border-radius: 50%;
|
||||
animation: ring 1.2s cubic-bezier(0.5, 0, 0.5, 1) infinite;
|
||||
border-color: $ui-vibrant-blue-25 transparent transparent transparent;
|
||||
}
|
||||
.ring div:nth-child(1) {
|
||||
animation-delay: -0.45s;
|
||||
}
|
||||
.ring div:nth-child(2) {
|
||||
animation-delay: -0.3s;
|
||||
}
|
||||
.ring div:nth-child(3) {
|
||||
animation-delay: -0.15s;
|
||||
}
|
||||
@keyframes ring {
|
||||
0% {
|
||||
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
20% {
|
||||
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
|
||||
background: #ff5850;
|
||||
}
|
||||
|
||||
40% {
|
||||
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
|
||||
background: #ffad00;
|
||||
}
|
||||
|
||||
60% {
|
||||
transform: perspective(120px) rotateX(0deg) rotateY(0deg);
|
||||
background: #4fd061;
|
||||
}
|
||||
|
||||
80% {
|
||||
transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg);
|
||||
background: #4a90e2;
|
||||
}
|
||||
|
||||
100% {
|
||||
transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg);
|
||||
background: #ae6ddf;
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
export { default } from "./SiteNavSidePanel";
|
||||
+8
-3
@@ -14,7 +14,7 @@ import QueriesIcon from "../../../../assets/images/icon-main-queries@2x-16x16@2x
|
||||
import PacksIcon from "../../../../assets/images/icon-main-packs@2x-16x16@2x.png";
|
||||
import AdminIcon from "../../../../assets/images/icon-main-settings@2x-16x16@2x.png";
|
||||
|
||||
class SiteNavSidePanel extends Component {
|
||||
class SiteTopNav extends Component {
|
||||
static propTypes = {
|
||||
onLogoutUser: PropTypes.func,
|
||||
onNavItemClick: PropTypes.func,
|
||||
@@ -86,7 +86,12 @@ class SiteNavSidePanel extends Component {
|
||||
onClick={onNavItemClick(navItem.location.pathname)}
|
||||
>
|
||||
{icon}
|
||||
<span className={`${navItemBaseClass}__name`}>{name}</span>
|
||||
<span
|
||||
className={`${navItemBaseClass}__name`}
|
||||
data-text={navItem.name}
|
||||
>
|
||||
{name}
|
||||
</span>
|
||||
</a>
|
||||
</li>
|
||||
);
|
||||
@@ -119,4 +124,4 @@ class SiteNavSidePanel extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
export default SiteNavSidePanel;
|
||||
export default SiteTopNav;
|
||||
+15
@@ -40,10 +40,25 @@
|
||||
}
|
||||
|
||||
&__name {
|
||||
display: inline-flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
text-decoration: none;
|
||||
vertical-align: middle;
|
||||
font-weight: $regular;
|
||||
font-size: $x-small;
|
||||
|
||||
// Bolding text when the button is active causes a layout shift
|
||||
// so we add a hidden pseudo element with the same text string
|
||||
&:before {
|
||||
content: attr(data-text);
|
||||
height: 0;
|
||||
visibility: hidden;
|
||||
overflow: hidden;
|
||||
user-select: none;
|
||||
pointer-events: none;
|
||||
font-weight: $bold;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
@@ -0,0 +1 @@
|
||||
export { default } from "./SiteTopNav";
|
||||
@@ -7,7 +7,7 @@ import { push } from "react-router-redux";
|
||||
import configInterface from "interfaces/config";
|
||||
import FlashMessage from "components/flash_messages/FlashMessage";
|
||||
import PersistentFlash from "components/flash_messages/PersistentFlash";
|
||||
import SiteNavSidePanel from "components/side_panels/SiteNavSidePanel";
|
||||
import SiteTopNav from "components/side_panels/SiteTopNav";
|
||||
import userInterface from "interfaces/user";
|
||||
import notificationInterface from "interfaces/notification";
|
||||
import { hideFlash } from "redux/nodes/notifications/actions";
|
||||
@@ -92,7 +92,7 @@ export class CoreLayout extends Component {
|
||||
return (
|
||||
<div className="app-wrap">
|
||||
<nav className="site-nav">
|
||||
<SiteNavSidePanel
|
||||
<SiteTopNav
|
||||
config={config}
|
||||
onLogoutUser={onLogoutUser}
|
||||
onNavItemClick={onNavItemClick}
|
||||
|
||||
@@ -317,7 +317,7 @@ export class HostDetailsPage extends Component {
|
||||
{canTransferTeam && (
|
||||
<Button
|
||||
onClick={toggleTransferHostModal()}
|
||||
variant="inverse"
|
||||
variant="text-icon"
|
||||
className={`${baseClass}__transfer-button`}
|
||||
>
|
||||
Transfer <img src={TransferIcon} alt="Transfer host icon" />
|
||||
@@ -326,7 +326,7 @@ export class HostDetailsPage extends Component {
|
||||
<div data-tip data-for="query" data-tip-disable={isOnline}>
|
||||
<Button
|
||||
onClick={toggleQueryHostModal()}
|
||||
variant="inverse"
|
||||
variant="text-icon"
|
||||
disabled={!isOnline}
|
||||
className={`${baseClass}__query-button`}
|
||||
>
|
||||
@@ -344,7 +344,7 @@ export class HostDetailsPage extends Component {
|
||||
You can’t query <br /> an offline host.
|
||||
</span>
|
||||
</ReactTooltip>
|
||||
<Button onClick={toggleDeleteHostModal()} variant="inverse">
|
||||
<Button onClick={toggleDeleteHostModal()} variant="text-icon">
|
||||
Delete <img src={DeleteIcon} alt="Delete host icon" />
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
@@ -41,7 +41,7 @@ import NoHosts from "./components/NoHosts";
|
||||
import EmptyHosts from "./components/EmptyHosts";
|
||||
import EditColumnsModal from "./components/EditColumnsModal/EditColumnsModal";
|
||||
import TransferHostModal from "./components/TransferHostModal";
|
||||
import EditColumnsIcon from "../../../../assets/images/icon-edit-columns-16x12@2x.png";
|
||||
import EditColumnsIcon from "../../../../assets/images/icon-edit-columns-16x16@2x.png";
|
||||
import PencilIcon from "../../../../assets/images/icon-pencil-14x14@2x.png";
|
||||
import TrashIcon from "../../../../assets/images/icon-trash-14x14@2x.png";
|
||||
|
||||
|
||||
+3
-3
@@ -94,14 +94,14 @@ const PacksListWrapper = (props: IPacksListWrapperProps): JSX.Element => {
|
||||
name: "enable",
|
||||
onActionButtonClick: onEnablePackClick,
|
||||
buttonText: "Enable",
|
||||
variant: "text-link",
|
||||
variant: "text-icon",
|
||||
icon: "check",
|
||||
},
|
||||
{
|
||||
name: "disable",
|
||||
onActionButtonClick: onDisablePackClick,
|
||||
buttonText: "Disable",
|
||||
variant: "text-link",
|
||||
variant: "text-icon",
|
||||
icon: "disable",
|
||||
},
|
||||
];
|
||||
@@ -121,7 +121,7 @@ const PacksListWrapper = (props: IPacksListWrapperProps): JSX.Element => {
|
||||
searchable
|
||||
disablePagination
|
||||
onPrimarySelectActionClick={onRemovePackClick}
|
||||
primarySelectActionButtonVariant="text-link"
|
||||
primarySelectActionButtonVariant="text-icon"
|
||||
primarySelectActionButtonIcon="delete"
|
||||
primarySelectActionButtonText={"Delete"}
|
||||
secondarySelectActions={secondarySelectActions}
|
||||
|
||||
+1
-1
@@ -107,7 +107,7 @@ const QueriesListWrapper = (
|
||||
searchable
|
||||
disablePagination
|
||||
onPrimarySelectActionClick={onRemoveQueryClick}
|
||||
primarySelectActionButtonVariant="text-link"
|
||||
primarySelectActionButtonVariant="text-icon"
|
||||
primarySelectActionButtonIcon="delete"
|
||||
primarySelectActionButtonText={"Delete"}
|
||||
emptyComponent={NoQueriesComponent}
|
||||
|
||||
+2
-1
@@ -137,8 +137,9 @@ const ScheduleListWrapper = (props: IScheduleListWrapperProps): JSX.Element => {
|
||||
onQueryChange={onQueryChange}
|
||||
inputPlaceHolder="Search"
|
||||
searchable={false}
|
||||
disablePagination
|
||||
onPrimarySelectActionClick={onRemoveScheduledQueryClick}
|
||||
primarySelectActionButtonVariant="text-link"
|
||||
primarySelectActionButtonVariant="text-icon"
|
||||
primarySelectActionButtonIcon="close"
|
||||
primarySelectActionButtonText={"Remove"}
|
||||
emptyComponent={NoScheduledQueries}
|
||||
|
||||
Reference in New Issue
Block a user