mirror of
https://github.com/prymitive/karma
synced 2026-08-28 11:17:28 +00:00
Merge pull request #128 from prymitive/silence-delete
feat(ui): add tooltips to clickable components
This commit is contained in:
@@ -43,6 +43,7 @@
|
||||
"react-resize-detector": "3.1.3",
|
||||
"react-scripts": "2.0.4",
|
||||
"react-select": "2.1.0",
|
||||
"react-tippy": "1.2.3",
|
||||
"react-transition-group": "2.5.0",
|
||||
"whatwg-fetch": "3.0.0"
|
||||
},
|
||||
|
||||
@@ -63,12 +63,26 @@ exports[`<Alert /> matches snapshot with showAlertmanagers=false showReceiver=fa
|
||||
a day ago
|
||||
</time>
|
||||
</span>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
job: node_exporter
|
||||
</span>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
cluster: dev
|
||||
</span>
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-1\\"
|
||||
data-original-title=\\"Click to only show alerts with this label\\"
|
||||
>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
job: node_exporter
|
||||
</span>
|
||||
</div>
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-2\\"
|
||||
data-original-title=\\"Click to only show alerts with this label\\"
|
||||
>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
cluster: dev
|
||||
</span>
|
||||
</div>
|
||||
<a href=\\"http://localhost\\"
|
||||
target=\\"_blank\\"
|
||||
rel=\\"noopener noreferrer\\"
|
||||
|
||||
+40
-12
@@ -42,18 +42,46 @@ exports[`<GroupFooter /> matches snapshot 1`] = `
|
||||
hidden
|
||||
</div>
|
||||
</div>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
label1: foo
|
||||
</span>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
label2: bar
|
||||
</span>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
@alertmanager: default
|
||||
</span>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
@receiver: by-name
|
||||
</span>
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-1\\"
|
||||
data-original-title=\\"Click to only show alerts with this label\\"
|
||||
>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
label1: foo
|
||||
</span>
|
||||
</div>
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-2\\"
|
||||
data-original-title=\\"Click to only show alerts with this label\\"
|
||||
>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
label2: bar
|
||||
</span>
|
||||
</div>
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-3\\"
|
||||
data-original-title=\\"Click to only show alerts with this label\\"
|
||||
>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
@alertmanager: default
|
||||
</span>
|
||||
</div>
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-4\\"
|
||||
data-original-title=\\"Click to only show alerts with this label\\"
|
||||
>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
@receiver: by-name
|
||||
</span>
|
||||
</div>
|
||||
<a href=\\"http://link.example.com\\"
|
||||
target=\\"_blank\\"
|
||||
rel=\\"noopener noreferrer\\"
|
||||
|
||||
@@ -11,6 +11,7 @@ import { APIGroup } from "Models/API";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { FilteringLabel } from "Components/Labels/FilteringLabel";
|
||||
import { FilteringCounterBadge } from "Components/Labels/FilteringCounterBadge";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { GroupMenu } from "./GroupMenu";
|
||||
|
||||
const GroupHeader = observer(
|
||||
@@ -52,9 +53,11 @@ const GroupHeader = observer(
|
||||
className="text-muted cursor-pointer badge text-nowrap text-truncate pr-0"
|
||||
onClick={collapseStore.toggle}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={collapseStore.value ? faChevronUp : faChevronDown}
|
||||
/>
|
||||
<TooltipWrapper title="Toggle group details">
|
||||
<FontAwesomeIcon
|
||||
icon={collapseStore.value ? faChevronUp : faChevronDown}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</span>
|
||||
</span>
|
||||
<span>
|
||||
|
||||
+46
-25
@@ -18,19 +18,26 @@ exports[`<Silence /> matches snapshot when data is present in alertStore 1`] = `
|
||||
Fake silence
|
||||
<span class=\\"blockquote-footer pt-1\\">
|
||||
<span class=\\"float-right cursor-pointer\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"chevron-up\\"
|
||||
class=\\"svg-inline--fa fa-chevron-up fa-w-14 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 448 512\\"
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-1\\"
|
||||
data-original-title=\\"Toggle silence details\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M240.971 130.524l194.343 194.343c9.373 9.373 9.373 24.569 0 33.941l-22.667 22.667c-9.357 9.357-24.522 9.375-33.901.04L224 227.495 69.255 381.516c-9.379 9.335-24.544 9.317-33.901-.04l-22.667-22.667c-9.373-9.373-9.373-24.569 0-33.941L207.03 130.525c9.372-9.373 24.568-9.373 33.941-.001z\\"
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"chevron-up\\"
|
||||
class=\\"svg-inline--fa fa-chevron-up fa-w-14 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 448 512\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M240.971 130.524l194.343 194.343c9.373 9.373 9.373 24.569 0 33.941l-22.667 22.667c-9.357 9.357-24.522 9.375-33.901.04L224 227.495 69.255 381.516c-9.379 9.335-24.544 9.317-33.901-.04l-22.667-22.667c-9.373-9.373-9.373-24.569 0-33.941L207.03 130.525c9.372-9.373 24.568-9.373 33.941-.001z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
</span>
|
||||
<cite class=\\"components-grid-alertgroup-silences mr-2\\">
|
||||
me@example.com
|
||||
@@ -66,19 +73,26 @@ exports[`<Silence /> matches snapshot with expaned details 1`] = `
|
||||
Fake silence
|
||||
<span class=\\"blockquote-footer pt-1\\">
|
||||
<span class=\\"float-right cursor-pointer\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"chevron-down\\"
|
||||
class=\\"svg-inline--fa fa-chevron-down fa-w-14 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 448 512\\"
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-5\\"
|
||||
data-original-title=\\"Toggle silence details\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z\\"
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"chevron-down\\"
|
||||
class=\\"svg-inline--fa fa-chevron-down fa-w-14 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 448 512\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M207.029 381.476L12.686 187.132c-9.373-9.373-9.373-24.569 0-33.941l22.667-22.667c9.357-9.357 24.522-9.375 33.901-.04L224 284.505l154.745-154.021c9.379-9.335 24.544-9.317 33.901.04l22.667 22.667c9.373 9.373 9.373 24.569 0 33.941L240.971 381.476c-9.373 9.372-24.569 9.372-33.942 0z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
</div>
|
||||
</span>
|
||||
<cite class=\\"components-grid-alertgroup-silences mr-2\\">
|
||||
me@example.com
|
||||
@@ -88,9 +102,16 @@ exports[`<Silence /> matches snapshot with expaned details 1`] = `
|
||||
</div>
|
||||
<div class=\\"mt-1\\">
|
||||
<div>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
@alertmanager: default
|
||||
</span>
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-6\\"
|
||||
data-original-title=\\"Click to only show alerts with this label\\"
|
||||
>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
@alertmanager: default
|
||||
</span>
|
||||
</div>
|
||||
<a href=\\"file:///mock/#/silences/4cf5fd82-1edd-4169-99d1-ff8415e72179\\"
|
||||
target=\\"_blank\\"
|
||||
rel=\\"noopener noreferrer\\"
|
||||
|
||||
@@ -27,6 +27,7 @@ import { AlertStore } from "Stores/AlertStore";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { StaticLabels, QueryOperators } from "Common/Query";
|
||||
import { FilteringLabel } from "Components/Labels/FilteringLabel";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { RenderLinkAnnotation } from "../Annotation";
|
||||
|
||||
import "./index.css";
|
||||
@@ -299,9 +300,11 @@ const Silence = inject("alertStore")(
|
||||
className="float-right cursor-pointer"
|
||||
onClick={this.collapse.toggle}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={this.collapse.value ? faChevronUp : faChevronDown}
|
||||
/>
|
||||
<TooltipWrapper title="Toggle silence details">
|
||||
<FontAwesomeIcon
|
||||
icon={this.collapse.value ? faChevronUp : faChevronDown}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</span>
|
||||
<cite className="components-grid-alertgroup-silences mr-2">
|
||||
{silence.createdBy}
|
||||
|
||||
@@ -11,23 +11,31 @@ import { faPlus } from "@fortawesome/free-solid-svg-icons/faPlus";
|
||||
import { faMinus } from "@fortawesome/free-solid-svg-icons/faMinus";
|
||||
|
||||
import { APIGroup } from "Models/API";
|
||||
import { MountFade } from "Components/Animations/MountFade";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { MountFade } from "Components/Animations/MountFade";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { GroupHeader } from "./GroupHeader";
|
||||
import { Alert } from "./Alert";
|
||||
import { GroupFooter } from "./GroupFooter";
|
||||
|
||||
const LoadButton = ({ icon, action }) => {
|
||||
const LoadButton = ({ icon, action, tooltip }) => {
|
||||
return (
|
||||
<button type="button" className="btn btn-sm py-0 bg-white" onClick={action}>
|
||||
<FontAwesomeIcon className="text-muted" icon={icon} />
|
||||
</button>
|
||||
<TooltipWrapper title={tooltip}>
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-sm py-0 bg-white"
|
||||
onClick={action}
|
||||
>
|
||||
<FontAwesomeIcon className="text-muted" icon={icon} />
|
||||
</button>
|
||||
</TooltipWrapper>
|
||||
);
|
||||
};
|
||||
LoadButton.propTypes = {
|
||||
icon: FontAwesomeIcon.propTypes.icon.isRequired,
|
||||
action: PropTypes.func.isRequired
|
||||
action: PropTypes.func.isRequired,
|
||||
tooltip: PropTypes.node.isRequired
|
||||
};
|
||||
|
||||
const AllAlertsAreUsingSameAlertmanagers = alerts => {
|
||||
@@ -183,13 +191,21 @@ const AlertGroup = observer(
|
||||
))}
|
||||
{group.alerts.length > this.defaultRenderCount ? (
|
||||
<li className="list-group-item border-0 p-0 text-center">
|
||||
<LoadButton icon={faMinus} action={this.loadLess} />
|
||||
<LoadButton
|
||||
icon={faMinus}
|
||||
action={this.loadLess}
|
||||
tooltip="Show fewer alerts in this group"
|
||||
/>
|
||||
<small className="text-muted mx-2">
|
||||
{this.renderConfig.alertsToRender}
|
||||
{" of "}
|
||||
{group.alerts.length}
|
||||
</small>
|
||||
<LoadButton icon={faPlus} action={this.loadMore} />
|
||||
<LoadButton
|
||||
icon={faPlus}
|
||||
action={this.loadMore}
|
||||
tooltip="Show more alerts in this group"
|
||||
/>
|
||||
</li>
|
||||
) : null}
|
||||
</ul>
|
||||
|
||||
@@ -12,6 +12,7 @@ import { faSpinner } from "@fortawesome/free-solid-svg-icons/faSpinner";
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { DefaultLabelClass } from "Common/Colors";
|
||||
import { QueryOperators } from "Common/Query";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { BaseLabel } from "Components/Labels/BaseLabel";
|
||||
|
||||
import "./index.css";
|
||||
@@ -93,13 +94,15 @@ const FilterInputLabel = observer(
|
||||
<FontAwesomeIcon icon={faExclamationCircle} />
|
||||
</span>
|
||||
)}
|
||||
<RIEInput
|
||||
defaultValue=""
|
||||
value={filter.raw}
|
||||
propName="raw"
|
||||
change={this.onChange}
|
||||
classEditing="py-0 border-0 bg-light"
|
||||
/>
|
||||
<TooltipWrapper title="Click to edit this filter">
|
||||
<RIEInput
|
||||
defaultValue=""
|
||||
value={filter.raw}
|
||||
propName="raw"
|
||||
change={this.onChange}
|
||||
classEditing="py-0 border-0 bg-light"
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</span>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -4,6 +4,7 @@ import PropTypes from "prop-types";
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { BaseLabel } from "Components/Labels/BaseLabel";
|
||||
|
||||
// Same as FilteringLabel but for labels that are counters (usually @state)
|
||||
@@ -25,16 +26,18 @@ const FilteringCounterBadge = inject("alertStore")(
|
||||
if (counter === 0) return null;
|
||||
|
||||
return (
|
||||
<span
|
||||
className={`components-label components-label-with-hover text-nowrap text-truncate badge badge-${this.getColorClass(
|
||||
name,
|
||||
value
|
||||
)} badge-pill`}
|
||||
style={this.getColorStyle(name, value)}
|
||||
onClick={e => this.handleClick(e)}
|
||||
>
|
||||
{counter}
|
||||
</span>
|
||||
<TooltipWrapper title={`Click to only show ${value} alerts`}>
|
||||
<span
|
||||
className={`components-label components-label-with-hover text-nowrap text-truncate badge badge-${this.getColorClass(
|
||||
name,
|
||||
value
|
||||
)} badge-pill`}
|
||||
style={this.getColorStyle(name, value)}
|
||||
onClick={e => this.handleClick(e)}
|
||||
>
|
||||
{counter}
|
||||
</span>
|
||||
</TooltipWrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -45,7 +45,7 @@ const validateOnClick = value => {
|
||||
counter={1}
|
||||
/>
|
||||
);
|
||||
tree.simulate("click");
|
||||
tree.find(".components-label").simulate("click");
|
||||
expect(alertStore.filters.values).toHaveLength(1);
|
||||
expect(alertStore.filters.values).toContainEqual(
|
||||
NewUnappliedFilter(`@state=${value}`)
|
||||
|
||||
@@ -2,8 +2,15 @@
|
||||
|
||||
exports[`<FilteringLabel /> matches snapshot 1`] = `
|
||||
"
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
foo: bar
|
||||
</span>
|
||||
<div class
|
||||
style=\\"display: inline;\\"
|
||||
data-tooltipped
|
||||
aria-describedby=\\"tippy-tooltip-1\\"
|
||||
data-original-title=\\"Click to only show alerts with this label\\"
|
||||
>
|
||||
<span class=\\"components-label components-label-with-hover text-nowrap text-truncate badge badge-warning mw-100\\">
|
||||
foo: bar
|
||||
</span>
|
||||
</div>
|
||||
"
|
||||
`;
|
||||
|
||||
@@ -2,6 +2,7 @@ import React from "react";
|
||||
|
||||
import { inject, observer } from "mobx-react";
|
||||
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { BaseLabel } from "Components/Labels/BaseLabel";
|
||||
|
||||
// Renders a label element that after clicking adds current label as a filter
|
||||
@@ -11,16 +12,18 @@ const FilteringLabel = inject("alertStore")(
|
||||
render() {
|
||||
const { name, value } = this.props;
|
||||
return (
|
||||
<span
|
||||
className={`components-label components-label-with-hover text-nowrap text-truncate badge badge-${this.getColorClass(
|
||||
name,
|
||||
value
|
||||
)} mw-100`}
|
||||
style={this.getColorStyle(name, value)}
|
||||
onClick={e => this.handleClick(e)}
|
||||
>
|
||||
{name}: {value}
|
||||
</span>
|
||||
<TooltipWrapper title="Click to only show alerts with this label">
|
||||
<span
|
||||
className={`components-label components-label-with-hover text-nowrap text-truncate badge badge-${this.getColorClass(
|
||||
name,
|
||||
value
|
||||
)} mw-100`}
|
||||
style={this.getColorStyle(name, value)}
|
||||
onClick={e => this.handleClick(e)}
|
||||
>
|
||||
{name}: {value}
|
||||
</span>
|
||||
</TooltipWrapper>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ const RenderAndClick = (name, value) => {
|
||||
const tree = mount(
|
||||
<FilteringLabel alertStore={alertStore} name={name} value={value} />
|
||||
);
|
||||
tree.simulate("click");
|
||||
tree.find(".components-label").simulate("click");
|
||||
};
|
||||
|
||||
describe("<FilteringLabel />", () => {
|
||||
|
||||
@@ -10,6 +10,7 @@ import { faCog } from "@fortawesome/free-solid-svg-icons/faCog";
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { MountModal } from "Components/Animations/MountModal";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { MainModalContent } from "./MainModalContent";
|
||||
|
||||
const MainModal = observer(
|
||||
@@ -46,12 +47,14 @@ const MainModal = observer(
|
||||
return (
|
||||
<React.Fragment>
|
||||
<li className="nav-item">
|
||||
<span
|
||||
className="nav-link cursor-pointer"
|
||||
onClick={this.toggle.toggle}
|
||||
>
|
||||
<FontAwesomeIcon icon={faCog} />
|
||||
</span>
|
||||
<TooltipWrapper title="Settings">
|
||||
<span
|
||||
className="nav-link cursor-pointer"
|
||||
onClick={this.toggle.toggle}
|
||||
>
|
||||
<FontAwesomeIcon icon={faCog} />
|
||||
</span>
|
||||
</TooltipWrapper>
|
||||
</li>
|
||||
<MountModal in={this.toggle.show} unmountOnExit>
|
||||
<MainModalContent
|
||||
|
||||
@@ -25,38 +25,48 @@ exports[`<NavBar /> matches snapshot with 0 alerts 1`] = `
|
||||
</span>
|
||||
<ul class=\\"navbar-nav float-right d-flex flex-row\\">
|
||||
<li class=\\"nav-item\\">
|
||||
<span class=\\"nav-link cursor-pointer\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"bell-slash\\"
|
||||
class=\\"svg-inline--fa fa-bell-slash fa-w-20 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 640 512\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M633.82 458.1l-90.62-70.05c.19-1.38.8-2.66.8-4.06.05-7.55-2.61-15.27-8.61-21.71-19.32-20.76-55.47-51.99-55.47-154.29 0-77.7-54.48-139.9-127.94-155.16V32c0-17.67-14.32-32-31.98-32s-31.98 14.33-31.98 32v20.84c-40.33 8.38-74.66 31.07-97.59 62.57L45.47 3.37C38.49-2.05 28.43-.8 23.01 6.18L3.37 31.45C-2.05 38.42-.8 48.47 6.18 53.9l588.35 454.73c6.98 5.43 17.03 4.17 22.46-2.81l19.64-25.27c5.42-6.97 4.17-17.02-2.81-22.45zM157.23 251.54c-8.61 67.96-36.41 93.33-52.62 110.75-6 6.45-8.66 14.16-8.61 21.71.11 16.4 12.98 32 32.1 32h241.92L157.23 251.54zM320 512c35.32 0 63.97-28.65 63.97-64H256.03c0 35.35 28.65 64 63.97 64z\\"
|
||||
<div title=\\"Add new silence\\"
|
||||
class
|
||||
style=\\"display:inline\\"
|
||||
>
|
||||
<span class=\\"nav-link cursor-pointer\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"bell-slash\\"
|
||||
class=\\"svg-inline--fa fa-bell-slash fa-w-20 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 640 512\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
</span>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M633.82 458.1l-90.62-70.05c.19-1.38.8-2.66.8-4.06.05-7.55-2.61-15.27-8.61-21.71-19.32-20.76-55.47-51.99-55.47-154.29 0-77.7-54.48-139.9-127.94-155.16V32c0-17.67-14.32-32-31.98-32s-31.98 14.33-31.98 32v20.84c-40.33 8.38-74.66 31.07-97.59 62.57L45.47 3.37C38.49-2.05 28.43-.8 23.01 6.18L3.37 31.45C-2.05 38.42-.8 48.47 6.18 53.9l588.35 454.73c6.98 5.43 17.03 4.17 22.46-2.81l19.64-25.27c5.42-6.97 4.17-17.02-2.81-22.45zM157.23 251.54c-8.61 67.96-36.41 93.33-52.62 110.75-6 6.45-8.66 14.16-8.61 21.71.11 16.4 12.98 32 32.1 32h241.92L157.23 251.54zM320 512c35.32 0 63.97-28.65 63.97-64H256.03c0 35.35 28.65 64 63.97 64z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class=\\"nav-item\\">
|
||||
<span class=\\"nav-link cursor-pointer\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"cog\\"
|
||||
class=\\"svg-inline--fa fa-cog fa-w-16 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 512 512\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M444.788 291.1l42.616 24.599c4.867 2.809 7.126 8.618 5.459 13.985-11.07 35.642-29.97 67.842-54.689 94.586a12.016 12.016 0 0 1-14.832 2.254l-42.584-24.595a191.577 191.577 0 0 1-60.759 35.13v49.182a12.01 12.01 0 0 1-9.377 11.718c-34.956 7.85-72.499 8.256-109.219.007-5.49-1.233-9.403-6.096-9.403-11.723v-49.184a191.555 191.555 0 0 1-60.759-35.13l-42.584 24.595a12.016 12.016 0 0 1-14.832-2.254c-24.718-26.744-43.619-58.944-54.689-94.586-1.667-5.366.592-11.175 5.459-13.985L67.212 291.1a193.48 193.48 0 0 1 0-70.199l-42.616-24.599c-4.867-2.809-7.126-8.618-5.459-13.985 11.07-35.642 29.97-67.842 54.689-94.586a12.016 12.016 0 0 1 14.832-2.254l42.584 24.595a191.577 191.577 0 0 1 60.759-35.13V25.759a12.01 12.01 0 0 1 9.377-11.718c34.956-7.85 72.499-8.256 109.219-.007 5.49 1.233 9.403 6.096 9.403 11.723v49.184a191.555 191.555 0 0 1 60.759 35.13l42.584-24.595a12.016 12.016 0 0 1 14.832 2.254c24.718 26.744 43.619 58.944 54.689 94.586 1.667 5.366-.592 11.175-5.459 13.985L444.788 220.9a193.485 193.485 0 0 1 0 70.2zM336 256c0-44.112-35.888-80-80-80s-80 35.888-80 80 35.888 80 80 80 80-35.888 80-80z\\"
|
||||
<div title=\\"Settings\\"
|
||||
class
|
||||
style=\\"display:inline\\"
|
||||
>
|
||||
<span class=\\"nav-link cursor-pointer\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"cog\\"
|
||||
class=\\"svg-inline--fa fa-cog fa-w-16 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 512 512\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
</span>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M444.788 291.1l42.616 24.599c4.867 2.809 7.126 8.618 5.459 13.985-11.07 35.642-29.97 67.842-54.689 94.586a12.016 12.016 0 0 1-14.832 2.254l-42.584-24.595a191.577 191.577 0 0 1-60.759 35.13v49.182a12.01 12.01 0 0 1-9.377 11.718c-34.956 7.85-72.499 8.256-109.219.007-5.49-1.233-9.403-6.096-9.403-11.723v-49.184a191.555 191.555 0 0 1-60.759-35.13l-42.584 24.595a12.016 12.016 0 0 1-14.832-2.254c-24.718-26.744-43.619-58.944-54.689-94.586-1.667-5.366.592-11.175 5.459-13.985L67.212 291.1a193.48 193.48 0 0 1 0-70.199l-42.616-24.599c-4.867-2.809-7.126-8.618-5.459-13.985 11.07-35.642 29.97-67.842 54.689-94.586a12.016 12.016 0 0 1 14.832-2.254l42.584 24.595a191.577 191.577 0 0 1 60.759-35.13V25.759a12.01 12.01 0 0 1 9.377-11.718c34.956-7.85 72.499-8.256 109.219-.007 5.49 1.233 9.403 6.096 9.403 11.723v49.184a191.555 191.555 0 0 1 60.759 35.13l42.584-24.595a12.016 12.016 0 0 1 14.832 2.254c24.718 26.744 43.619 58.944 54.689 94.586 1.667 5.366-.592 11.175-5.459 13.985L444.788 220.9a193.485 193.485 0 0 1 0 70.2zM336 256c0-44.112-35.888-80-80-80s-80 35.888-80 80 35.888 80 80 80 80-35.888 80-80z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<form class=\\"form-inline mw-100\\"
|
||||
@@ -156,38 +166,48 @@ exports[`<NavBar /> matches snapshot with 5 alerts 1`] = `
|
||||
</span>
|
||||
<ul class=\\"navbar-nav float-right d-flex flex-row\\">
|
||||
<li class=\\"nav-item\\">
|
||||
<span class=\\"nav-link cursor-pointer\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"bell-slash\\"
|
||||
class=\\"svg-inline--fa fa-bell-slash fa-w-20 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 640 512\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M633.82 458.1l-90.62-70.05c.19-1.38.8-2.66.8-4.06.05-7.55-2.61-15.27-8.61-21.71-19.32-20.76-55.47-51.99-55.47-154.29 0-77.7-54.48-139.9-127.94-155.16V32c0-17.67-14.32-32-31.98-32s-31.98 14.33-31.98 32v20.84c-40.33 8.38-74.66 31.07-97.59 62.57L45.47 3.37C38.49-2.05 28.43-.8 23.01 6.18L3.37 31.45C-2.05 38.42-.8 48.47 6.18 53.9l588.35 454.73c6.98 5.43 17.03 4.17 22.46-2.81l19.64-25.27c5.42-6.97 4.17-17.02-2.81-22.45zM157.23 251.54c-8.61 67.96-36.41 93.33-52.62 110.75-6 6.45-8.66 14.16-8.61 21.71.11 16.4 12.98 32 32.1 32h241.92L157.23 251.54zM320 512c35.32 0 63.97-28.65 63.97-64H256.03c0 35.35 28.65 64 63.97 64z\\"
|
||||
<div title=\\"Add new silence\\"
|
||||
class
|
||||
style=\\"display:inline\\"
|
||||
>
|
||||
<span class=\\"nav-link cursor-pointer\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"bell-slash\\"
|
||||
class=\\"svg-inline--fa fa-bell-slash fa-w-20 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 640 512\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
</span>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M633.82 458.1l-90.62-70.05c.19-1.38.8-2.66.8-4.06.05-7.55-2.61-15.27-8.61-21.71-19.32-20.76-55.47-51.99-55.47-154.29 0-77.7-54.48-139.9-127.94-155.16V32c0-17.67-14.32-32-31.98-32s-31.98 14.33-31.98 32v20.84c-40.33 8.38-74.66 31.07-97.59 62.57L45.47 3.37C38.49-2.05 28.43-.8 23.01 6.18L3.37 31.45C-2.05 38.42-.8 48.47 6.18 53.9l588.35 454.73c6.98 5.43 17.03 4.17 22.46-2.81l19.64-25.27c5.42-6.97 4.17-17.02-2.81-22.45zM157.23 251.54c-8.61 67.96-36.41 93.33-52.62 110.75-6 6.45-8.66 14.16-8.61 21.71.11 16.4 12.98 32 32.1 32h241.92L157.23 251.54zM320 512c35.32 0 63.97-28.65 63.97-64H256.03c0 35.35 28.65 64 63.97 64z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
<li class=\\"nav-item\\">
|
||||
<span class=\\"nav-link cursor-pointer\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"cog\\"
|
||||
class=\\"svg-inline--fa fa-cog fa-w-16 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 512 512\\"
|
||||
>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M444.788 291.1l42.616 24.599c4.867 2.809 7.126 8.618 5.459 13.985-11.07 35.642-29.97 67.842-54.689 94.586a12.016 12.016 0 0 1-14.832 2.254l-42.584-24.595a191.577 191.577 0 0 1-60.759 35.13v49.182a12.01 12.01 0 0 1-9.377 11.718c-34.956 7.85-72.499 8.256-109.219.007-5.49-1.233-9.403-6.096-9.403-11.723v-49.184a191.555 191.555 0 0 1-60.759-35.13l-42.584 24.595a12.016 12.016 0 0 1-14.832-2.254c-24.718-26.744-43.619-58.944-54.689-94.586-1.667-5.366.592-11.175 5.459-13.985L67.212 291.1a193.48 193.48 0 0 1 0-70.199l-42.616-24.599c-4.867-2.809-7.126-8.618-5.459-13.985 11.07-35.642 29.97-67.842 54.689-94.586a12.016 12.016 0 0 1 14.832-2.254l42.584 24.595a191.577 191.577 0 0 1 60.759-35.13V25.759a12.01 12.01 0 0 1 9.377-11.718c34.956-7.85 72.499-8.256 109.219-.007 5.49 1.233 9.403 6.096 9.403 11.723v49.184a191.555 191.555 0 0 1 60.759 35.13l42.584-24.595a12.016 12.016 0 0 1 14.832 2.254c24.718 26.744 43.619 58.944 54.689 94.586 1.667 5.366-.592 11.175-5.459 13.985L444.788 220.9a193.485 193.485 0 0 1 0 70.2zM336 256c0-44.112-35.888-80-80-80s-80 35.888-80 80 35.888 80 80 80 80-35.888 80-80z\\"
|
||||
<div title=\\"Settings\\"
|
||||
class
|
||||
style=\\"display:inline\\"
|
||||
>
|
||||
<span class=\\"nav-link cursor-pointer\\">
|
||||
<svg aria-hidden=\\"true\\"
|
||||
data-prefix=\\"fas\\"
|
||||
data-icon=\\"cog\\"
|
||||
class=\\"svg-inline--fa fa-cog fa-w-16 \\"
|
||||
role=\\"img\\"
|
||||
xmlns=\\"http://www.w3.org/2000/svg\\"
|
||||
viewbox=\\"0 0 512 512\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
</span>
|
||||
<path fill=\\"currentColor\\"
|
||||
d=\\"M444.788 291.1l42.616 24.599c4.867 2.809 7.126 8.618 5.459 13.985-11.07 35.642-29.97 67.842-54.689 94.586a12.016 12.016 0 0 1-14.832 2.254l-42.584-24.595a191.577 191.577 0 0 1-60.759 35.13v49.182a12.01 12.01 0 0 1-9.377 11.718c-34.956 7.85-72.499 8.256-109.219.007-5.49-1.233-9.403-6.096-9.403-11.723v-49.184a191.555 191.555 0 0 1-60.759-35.13l-42.584 24.595a12.016 12.016 0 0 1-14.832-2.254c-24.718-26.744-43.619-58.944-54.689-94.586-1.667-5.366.592-11.175 5.459-13.985L67.212 291.1a193.48 193.48 0 0 1 0-70.199l-42.616-24.599c-4.867-2.809-7.126-8.618-5.459-13.985 11.07-35.642 29.97-67.842 54.689-94.586a12.016 12.016 0 0 1 14.832-2.254l42.584 24.595a191.577 191.577 0 0 1 60.759-35.13V25.759a12.01 12.01 0 0 1 9.377-11.718c34.956-7.85 72.499-8.256 109.219-.007 5.49 1.233 9.403 6.096 9.403 11.723v49.184a191.555 191.555 0 0 1 60.759 35.13l42.584-24.595a12.016 12.016 0 0 1 14.832 2.254c24.718 26.744 43.619 58.944 54.689 94.586 1.667 5.366-.592 11.175-5.459 13.985L444.788 220.9a193.485 193.485 0 0 1 0 70.2zM336 256c0-44.112-35.888-80-80-80s-80 35.888-80 80 35.888 80 80 80 80-35.888 80-80z\\"
|
||||
>
|
||||
</path>
|
||||
</svg>
|
||||
</span>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
<form class=\\"form-inline mw-100\\"
|
||||
|
||||
@@ -16,6 +16,7 @@ import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { SilenceFormStore, SilenceFormStage } from "Stores/SilenceFormStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { AlertManagerInput } from "./AlertManagerInput";
|
||||
import { SilenceMatch } from "./SilenceMatch";
|
||||
import { DateTimeSelect } from "./DateTimeSelect";
|
||||
@@ -150,13 +151,15 @@ const SilenceForm = observer(
|
||||
isValid={!silenceFormStore.data.wasValidated}
|
||||
/>
|
||||
))}
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-secondary mb-3"
|
||||
onClick={this.addMore}
|
||||
>
|
||||
<FontAwesomeIcon icon={faPlus} />
|
||||
</button>
|
||||
<TooltipWrapper title="Add a matcher">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-secondary mb-3"
|
||||
onClick={this.addMore}
|
||||
>
|
||||
<FontAwesomeIcon icon={faPlus} />
|
||||
</button>
|
||||
</TooltipWrapper>
|
||||
<DateTimeSelect silenceFormStore={silenceFormStore} />
|
||||
<IconInput
|
||||
type="email"
|
||||
|
||||
@@ -8,6 +8,7 @@ import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons/faTrash";
|
||||
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { SilenceFormMatcher } from "Models/SilenceForm";
|
||||
import { LabelNameInput } from "./LabelNameInput";
|
||||
import { LabelValueInput } from "./LabelValueInput";
|
||||
@@ -71,13 +72,15 @@ const SilenceMatch = observer(
|
||||
</label>
|
||||
</span>
|
||||
{showDelete ? (
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-danger"
|
||||
onClick={onDelete}
|
||||
>
|
||||
<FontAwesomeIcon icon={faTrash} />
|
||||
</button>
|
||||
<TooltipWrapper title="Remove this matcher">
|
||||
<button
|
||||
type="button"
|
||||
className="btn btn-outline-danger"
|
||||
onClick={onDelete}
|
||||
>
|
||||
<FontAwesomeIcon icon={faTrash} />
|
||||
</button>
|
||||
</TooltipWrapper>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -10,6 +10,7 @@ import { AlertStore } from "Stores/AlertStore";
|
||||
import { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
import { Settings } from "Stores/Settings";
|
||||
import { MountModal } from "Components/Animations/MountModal";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { SilenceModalContent } from "./SilenceModalContent";
|
||||
|
||||
import "./index.css";
|
||||
@@ -53,12 +54,14 @@ const SilenceModal = observer(
|
||||
return (
|
||||
<React.Fragment>
|
||||
<li className="nav-item">
|
||||
<span
|
||||
className="nav-link cursor-pointer"
|
||||
onClick={this.toggleModal}
|
||||
>
|
||||
<FontAwesomeIcon icon={faBellSlash} />
|
||||
</span>
|
||||
<TooltipWrapper title="Add new silence">
|
||||
<span
|
||||
className="nav-link cursor-pointer"
|
||||
onClick={this.toggleModal}
|
||||
>
|
||||
<FontAwesomeIcon icon={faBellSlash} />
|
||||
</span>
|
||||
</TooltipWrapper>
|
||||
</li>
|
||||
<MountModal in={silenceFormStore.toggle.visible} unmountOnExit>
|
||||
<SilenceModalContent
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
import React from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { Tooltip } from "react-tippy";
|
||||
|
||||
import "react-tippy/dist/tippy.css";
|
||||
|
||||
const TooltipWrapper = ({ children, ...props }) => (
|
||||
<Tooltip delay={[1000, 100]} size="small" touchHold={true} {...props}>
|
||||
{children}
|
||||
</Tooltip>
|
||||
);
|
||||
Tooltip.propTypes = {
|
||||
children: PropTypes.node.isRequired
|
||||
};
|
||||
|
||||
export { TooltipWrapper };
|
||||
@@ -148,6 +148,9 @@ class SilenceFormStore {
|
||||
}
|
||||
|
||||
this.matchers = matchers;
|
||||
// ensure that silenceID is nulled, since it's used to edit silences
|
||||
// and this is used to silence groups
|
||||
this.silenceID = null;
|
||||
},
|
||||
|
||||
fillFormFromSilence(alertmanager, silence) {
|
||||
|
||||
@@ -187,6 +187,13 @@ describe("SilenceFormStore.data", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("fillMatchersFromGroup() resets silenceID if set", () => {
|
||||
store.data.silenceID = "12345";
|
||||
const group = MockGroup();
|
||||
store.data.fillMatchersFromGroup(group, [group.alerts[0]]);
|
||||
expect(store.data.silenceID).toBeNull();
|
||||
});
|
||||
|
||||
it("fillFormFromSilence() sets silenceID", () => {
|
||||
const alertmanager = MockAlertmanager();
|
||||
const silence = MockSilence();
|
||||
|
||||
+8
-1
@@ -8135,7 +8135,7 @@ pnp-webpack-plugin@1.1.0:
|
||||
resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.1.0.tgz#947a96d1db94bb5a1fc014d83b581e428699ac8c"
|
||||
integrity sha512-CPCdcFxx7fEcDMWTDjXe2Wypt4JuMt4q5Q2UrpTcyBBkLiCIyPEh/mCGmUWIcNkKGyXwQ9Y2wVhlKm6ketiBNQ==
|
||||
|
||||
popper.js@^1.14.1:
|
||||
popper.js@^1.11.1, popper.js@^1.14.1:
|
||||
version "1.14.4"
|
||||
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.4.tgz#8eec1d8ff02a5a3a152dd43414a15c7b79fd69b6"
|
||||
integrity sha1-juwdj/AqWjoVLdQ0FKFce3n9abY=
|
||||
@@ -9324,6 +9324,13 @@ react-themeable@^1.1.0:
|
||||
dependencies:
|
||||
object-assign "^3.0.0"
|
||||
|
||||
react-tippy@1.2.3:
|
||||
version "1.2.3"
|
||||
resolved "https://registry.yarnpkg.com/react-tippy/-/react-tippy-1.2.3.tgz#8aef183ec4986ca7c5c556465013d95196fecfd8"
|
||||
integrity sha512-cEmhw29DbVP33n9ayo0nLzibuSz6o0A77cZtzno7zGsfOH8tUEGai/8a7TXRIKHPYDooW8iJkJBIPDnxmEu00g==
|
||||
dependencies:
|
||||
popper.js "^1.11.1"
|
||||
|
||||
react-transition-group@2.5.0, react-transition-group@^2.2.1:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.5.0.tgz#70bca0e3546102c4dc5cf3f5f57f73447cce6874"
|
||||
|
||||
Reference in New Issue
Block a user