mirror of
https://github.com/prymitive/karma
synced 2026-05-09 03:36:44 +00:00
feat(ui): show only common labels in the overview modal by default
This commit is contained in:
@@ -2,53 +2,97 @@ import React, { Component } from "react";
|
||||
import PropTypes from "prop-types";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import { observable, action } from "mobx";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faChevronUp } from "@fortawesome/free-solid-svg-icons/faChevronUp";
|
||||
import { faChevronDown } from "@fortawesome/free-solid-svg-icons/faChevronDown";
|
||||
|
||||
import { AlertStore } from "Stores/AlertStore";
|
||||
import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { LabelWithPercent } from "Components/Labels/LabelWithPercent";
|
||||
|
||||
const LabelsTable = observer(({ alertStore }) => (
|
||||
<table
|
||||
className="table table-borderless top-labels"
|
||||
style={{ tableLayout: "fixed" }}
|
||||
>
|
||||
<tbody className="mw-100">
|
||||
{alertStore.data.counters.map(nameStats => (
|
||||
<tr key={nameStats.name}>
|
||||
<td width="25%" className="text-nowrap mw-100 p-1">
|
||||
<span className="badge badge-light components-label mx-0 my-1 pl-0 text-left">
|
||||
<span className="bg-primary text-white mr-1 px-1 components-labelWithPercent-percent">
|
||||
{nameStats.hits}
|
||||
</span>
|
||||
{nameStats.name}
|
||||
</span>
|
||||
</td>
|
||||
<td width="75%" className="mw-100 p-1">
|
||||
{nameStats.values.slice(0, 9).map((valueStats, i) => (
|
||||
<LabelWithPercent
|
||||
key={valueStats.value}
|
||||
name={nameStats.name}
|
||||
value={valueStats.value}
|
||||
hits={valueStats.hits}
|
||||
percent={valueStats.percent}
|
||||
offset={valueStats.offset}
|
||||
isActive={
|
||||
alertStore.filters.values.filter(
|
||||
f => f.raw === valueStats.raw
|
||||
).length > 0
|
||||
}
|
||||
/>
|
||||
))}
|
||||
{nameStats.values.length > 9 ? (
|
||||
<div className="components-label badge my-2 text-muted mw-100">
|
||||
+{nameStats.values.length - 9} more
|
||||
</div>
|
||||
) : null}
|
||||
</td>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
));
|
||||
const TableRows = observer(({ alertStore, nameStats }) =>
|
||||
nameStats.map(nameStats => (
|
||||
<tr key={nameStats.name}>
|
||||
<td width="25%" className="text-nowrap mw-100 p-1">
|
||||
<span className="badge badge-light components-label mx-0 my-1 pl-0 text-left">
|
||||
<span className="bg-primary text-white mr-1 px-1 components-labelWithPercent-percent">
|
||||
{nameStats.hits}
|
||||
</span>
|
||||
{nameStats.name}
|
||||
</span>
|
||||
</td>
|
||||
<td width="75%" className="mw-100 p-1">
|
||||
{nameStats.values.slice(0, 9).map((valueStats, i) => (
|
||||
<LabelWithPercent
|
||||
key={valueStats.value}
|
||||
name={nameStats.name}
|
||||
value={valueStats.value}
|
||||
hits={valueStats.hits}
|
||||
percent={valueStats.percent}
|
||||
offset={valueStats.offset}
|
||||
isActive={
|
||||
alertStore.filters.values.filter(f => f.raw === valueStats.raw)
|
||||
.length > 0
|
||||
}
|
||||
/>
|
||||
))}
|
||||
{nameStats.values.length > 9 ? (
|
||||
<div className="components-label badge my-2 text-muted mw-100">
|
||||
+{nameStats.values.length - 9} more
|
||||
</div>
|
||||
) : null}
|
||||
</td>
|
||||
</tr>
|
||||
))
|
||||
);
|
||||
|
||||
const LabelsTable = observer(
|
||||
({ alertStore, showAllLabels, toggleAllLabels }) => (
|
||||
<React.Fragment>
|
||||
<table
|
||||
className="table table-borderless top-labels"
|
||||
style={{ tableLayout: "fixed" }}
|
||||
>
|
||||
<tbody className="mw-100">
|
||||
<TableRows
|
||||
alertStore={alertStore}
|
||||
nameStats={alertStore.data.counters.filter(
|
||||
nameStats => nameStats.hits >= alertStore.info.totalAlerts
|
||||
)}
|
||||
></TableRows>
|
||||
{alertStore.data.counters.filter(
|
||||
nameStats => nameStats.hits < alertStore.info.totalAlerts
|
||||
).length > 0 ? (
|
||||
<tr>
|
||||
<td colSpan="2" className="px-1 py-0">
|
||||
<TooltipWrapper
|
||||
title="Toggle all / only common labels"
|
||||
delay={[3000, 100]}
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
icon={showAllLabels ? faChevronDown : faChevronUp}
|
||||
className="cursor-pointer text-muted"
|
||||
onClick={toggleAllLabels}
|
||||
/>
|
||||
</TooltipWrapper>
|
||||
</td>
|
||||
</tr>
|
||||
) : null}
|
||||
{showAllLabels ? (
|
||||
<TableRows
|
||||
alertStore={alertStore}
|
||||
nameStats={alertStore.data.counters.filter(
|
||||
nameStats => nameStats.hits < alertStore.info.totalAlerts
|
||||
)}
|
||||
></TableRows>
|
||||
) : null}
|
||||
</tbody>
|
||||
</table>
|
||||
</React.Fragment>
|
||||
)
|
||||
);
|
||||
|
||||
const NothingToShow = () => (
|
||||
<div className="jumbotron bg-white">
|
||||
@@ -65,6 +109,18 @@ const OverviewModalContent = observer(
|
||||
onHide: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
allLabels = observable(
|
||||
{
|
||||
show: false,
|
||||
toggle() {
|
||||
this.show = !this.show;
|
||||
}
|
||||
},
|
||||
{
|
||||
toggle: action.bound
|
||||
}
|
||||
);
|
||||
|
||||
render() {
|
||||
const { alertStore, onHide } = this.props;
|
||||
|
||||
@@ -80,7 +136,11 @@ const OverviewModalContent = observer(
|
||||
{alertStore.data.counters.length === 0 ? (
|
||||
<NothingToShow />
|
||||
) : (
|
||||
<LabelsTable alertStore={alertStore} />
|
||||
<LabelsTable
|
||||
alertStore={alertStore}
|
||||
showAllLabels={this.allLabels.show}
|
||||
toggleAllLabels={this.allLabels.toggle}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</React.Fragment>
|
||||
|
||||
@@ -21,6 +21,18 @@ afterEach(() => {
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
const MountedOverviewModalContent = () =>
|
||||
// we have multiple fragments and enzyme only renders the first one
|
||||
// in html() and text(), debug() would work but it's noisy
|
||||
// https://github.com/airbnb/enzyme/issues/1213
|
||||
mount(
|
||||
<span>
|
||||
<Provider alertStore={alertStore}>
|
||||
<OverviewModalContent alertStore={alertStore} onHide={onHide} />
|
||||
</Provider>
|
||||
</span>
|
||||
);
|
||||
|
||||
describe("<OverviewModalContent />", () => {
|
||||
it("matches snapshot with labels to show", () => {
|
||||
alertStore.filters.values = [
|
||||
@@ -63,32 +75,70 @@ describe("<OverviewModalContent />", () => {
|
||||
}
|
||||
];
|
||||
|
||||
// we have multiple fragments and enzyme only renders the first one
|
||||
// in html() and text(), debug() would work but it's noisy
|
||||
// https://github.com/airbnb/enzyme/issues/1213
|
||||
const tree = mount(
|
||||
<span>
|
||||
<Provider alertStore={alertStore}>
|
||||
<OverviewModalContent alertStore={alertStore} onHide={onHide} />
|
||||
</Provider>
|
||||
</span>
|
||||
);
|
||||
const tree = MountedOverviewModalContent();
|
||||
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("matches snapshot with no labels to show", () => {
|
||||
alertStore.data.counters = [];
|
||||
|
||||
// we have multiple fragments and enzyme only renders the first one
|
||||
// in html() and text(), debug() would work but it's noisy
|
||||
// https://github.com/airbnb/enzyme/issues/1213
|
||||
const tree = mount(
|
||||
<span>
|
||||
<Provider alertStore={alertStore}>
|
||||
<OverviewModalContent alertStore={alertStore} onHide={onHide} />
|
||||
</Provider>
|
||||
</span>
|
||||
);
|
||||
const tree = MountedOverviewModalContent();
|
||||
expect(toDiffableHtml(tree.html())).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("renders all labels after expand button click", () => {
|
||||
alertStore.info.totalAlerts = 5;
|
||||
alertStore.data.counters = [
|
||||
{
|
||||
name: "foo",
|
||||
hits: 5,
|
||||
values: [
|
||||
{ value: "bar", raw: "foo=bar", hits: 5, percent: 100, offset: 0 }
|
||||
]
|
||||
},
|
||||
{
|
||||
name: "bar",
|
||||
hits: 3,
|
||||
values: [
|
||||
{
|
||||
value: "foo",
|
||||
raw: "bar=foo",
|
||||
hits: 3,
|
||||
percent: 100,
|
||||
offset: 0
|
||||
}
|
||||
]
|
||||
}
|
||||
];
|
||||
const tree = MountedOverviewModalContent();
|
||||
|
||||
expect(tree.find("span.components-label")).toHaveLength(2);
|
||||
expect(
|
||||
tree
|
||||
.find("span.components-label")
|
||||
.at(0)
|
||||
.text()
|
||||
).toBe("5foo");
|
||||
expect(
|
||||
tree
|
||||
.find("span.components-label")
|
||||
.at(1)
|
||||
.text()
|
||||
).toBe("5foo: bar");
|
||||
|
||||
tree.find("svg.cursor-pointer").simulate("click");
|
||||
|
||||
expect(tree.find("span.components-label")).toHaveLength(4);
|
||||
expect(
|
||||
tree
|
||||
.find("span.components-label")
|
||||
.at(2)
|
||||
.text()
|
||||
).toBe("3bar");
|
||||
expect(
|
||||
tree
|
||||
.find("span.components-label")
|
||||
.at(3)
|
||||
.text()
|
||||
).toBe("3bar: foo");
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user