mirror of
https://github.com/prymitive/karma
synced 2026-08-23 11:56:20 +00:00
fix(ui): move static & valueOnly label information to a map
This commit is contained in:
committed by
Łukasz Mierzwa
parent
c90a5063ef
commit
4fcab63639
@@ -86,7 +86,11 @@ describe("<FilterInputLabel /> className", () => {
|
||||
it("applied filter included in staticColorLabels with '=' matcher should use 'btn-info' class", () => {
|
||||
alertStore.settings.setValues({
|
||||
...alertStore.settings.values,
|
||||
...{ staticColorLabels: ["foo"] },
|
||||
...{
|
||||
labels: {
|
||||
foo: { isStatic: true, isValueOnly: false },
|
||||
},
|
||||
},
|
||||
});
|
||||
ValidateClass("=", true, "btn-info");
|
||||
});
|
||||
@@ -94,7 +98,11 @@ describe("<FilterInputLabel /> className", () => {
|
||||
it("applied filter included in staticColorLabels with any matcher other than '=' should use 'btn-default' class", () => {
|
||||
alertStore.settings.setValues({
|
||||
...alertStore.settings.values,
|
||||
...{ staticColorLabels: ["foo"] },
|
||||
...{
|
||||
labels: {
|
||||
foo: { isStatic: true, isValueOnly: false },
|
||||
},
|
||||
},
|
||||
});
|
||||
for (const matcher of NonEqualMatchers) {
|
||||
ValidateClass(matcher, true, "btn-default");
|
||||
|
||||
@@ -84,7 +84,11 @@ describe("<FilteringLabel />", () => {
|
||||
it("doesn't render the name if it's included in valueOnlyLabels", () => {
|
||||
alertStore.settings.setValues({
|
||||
...alertStore.settings.values,
|
||||
valueOnlyLabels: ["foo"],
|
||||
...{
|
||||
labels: {
|
||||
foo: { isStatic: false, isValueOnly: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
const tree = mount(
|
||||
<FilteringLabel alertStore={alertStore} name="foo" value="bar" />
|
||||
@@ -95,45 +99,15 @@ describe("<FilteringLabel />", () => {
|
||||
it("renders the name if it's not included in valueOnlyLabels", () => {
|
||||
alertStore.settings.setValues({
|
||||
...alertStore.settings.values,
|
||||
valueOnlyLabels: ["bar"],
|
||||
...{
|
||||
labels: {
|
||||
bar: { isStatic: false, isValueOnly: true },
|
||||
},
|
||||
},
|
||||
});
|
||||
const tree = mount(
|
||||
<FilteringLabel alertStore={alertStore} name="foo" value="bar" />
|
||||
);
|
||||
expect(tree.text()).toBe("foo: bar");
|
||||
});
|
||||
|
||||
it("doesn't render the name if it matches a regex in valueOnlyRegexLabels", () => {
|
||||
alertStore.settings.setValues({
|
||||
...alertStore.settings.values,
|
||||
valueOnlyRegexLabels: ["^fo*$"],
|
||||
});
|
||||
const tree = mount(
|
||||
<FilteringLabel alertStore={alertStore} name="foo" value="bar" />
|
||||
);
|
||||
expect(tree.text()).toBe("bar");
|
||||
});
|
||||
|
||||
it("renders the name if it does not match any regex in valueOnlyRegexLabels", () => {
|
||||
alertStore.settings.setValues({
|
||||
...alertStore.settings.values,
|
||||
valueOnlyRegexLabels: ["^[^o]*$"],
|
||||
});
|
||||
const tree = mount(
|
||||
<FilteringLabel alertStore={alertStore} name="foo" value="bar" />
|
||||
);
|
||||
expect(tree.text()).toBe("foo: bar");
|
||||
});
|
||||
|
||||
it("renders the name if valueOnlyRegexLabels provides invalid regex", () => {
|
||||
alertStore.settings.setValues({
|
||||
...alertStore.settings.values,
|
||||
valueOnlyRegexLabels: ["^fo**$"],
|
||||
});
|
||||
jest.spyOn(global.console, "error").mockImplementation(() => {});
|
||||
const tree = mount(
|
||||
<FilteringLabel alertStore={alertStore} name="foo" value="bar" />
|
||||
);
|
||||
expect(tree.text()).toBe("foo: bar");
|
||||
});
|
||||
});
|
||||
|
||||
@@ -33,23 +33,10 @@ const FilteringLabel: FC<{
|
||||
"components-label-with-hover"
|
||||
);
|
||||
|
||||
function isRegex(value: string): boolean {
|
||||
try {
|
||||
RegExp(value);
|
||||
return true;
|
||||
} catch {
|
||||
console.error(`Invalid regex '${value}'`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<TooltipWrapper title="Click to only show alerts with this label or Alt+Click to hide them">
|
||||
<span className={cs.className} style={cs.style} onClick={handleClick}>
|
||||
{alertStore.settings.values.valueOnlyLabels.includes(name) ||
|
||||
alertStore.settings.values.valueOnlyRegexLabels.some(
|
||||
(regex) => isRegex(regex) && name.match(regex)
|
||||
) ? null : (
|
||||
{alertStore.settings.values.labels[name]?.isValueOnly ? null : (
|
||||
<>
|
||||
<span className="components-label-name">{name}:</span>{" "}
|
||||
</>
|
||||
|
||||
@@ -17,8 +17,15 @@ describe("<GetClassAndStyle />", () => {
|
||||
it("static label uses StaticColorLabelClassMap.badge", () => {
|
||||
alertStore.settings.setValues({
|
||||
...alertStore.settings.values,
|
||||
...{ staticColorLabels: ["foo", "job", "bar"] },
|
||||
...{
|
||||
labels: {
|
||||
foo: { isStatic: true, isValueOnly: false },
|
||||
job: { isStatic: true, isValueOnly: false },
|
||||
bar: { isStatic: true, isValueOnly: false },
|
||||
},
|
||||
},
|
||||
});
|
||||
expect(alertStore.settings.values.labels.foo.isStatic).toBe(true);
|
||||
const cs = GetClassAndStyle(alertStore, "foo", "bar");
|
||||
expect(cs.colorClassNames).toContain(StaticColorLabelClassMap.badge);
|
||||
});
|
||||
@@ -27,7 +34,9 @@ describe("<GetClassAndStyle />", () => {
|
||||
it(`non-static label doesn't use StaticColorLabelClassMap.${key}`, () => {
|
||||
alertStore.settings.setValues({
|
||||
...alertStore.settings.values,
|
||||
...{ staticColorLabels: [] },
|
||||
...{
|
||||
labels: {},
|
||||
},
|
||||
});
|
||||
const cs = GetClassAndStyle(alertStore, "foo", "bar");
|
||||
expect(cs.colorClassNames).not.toContain(StaticColorLabelClassMap.badge);
|
||||
@@ -73,7 +82,13 @@ describe("<GetClassAndStyle />", () => {
|
||||
it("style prop on a label included in staticColorLabels should be empty", () => {
|
||||
alertStore.settings.setValues({
|
||||
...alertStore.settings.values,
|
||||
...{ staticColorLabels: ["foo", "job", "bar"] },
|
||||
...{
|
||||
labels: {
|
||||
foo: { isStatic: true, isValueOnly: false },
|
||||
job: { isStatic: true, isValueOnly: false },
|
||||
bar: { isStatic: true, isValueOnly: false },
|
||||
},
|
||||
},
|
||||
});
|
||||
const cs = GetClassAndStyle(alertStore, "foo", "bar");
|
||||
expect(cs.style).toEqual({});
|
||||
@@ -82,7 +97,7 @@ describe("<GetClassAndStyle />", () => {
|
||||
it("style prop on a label without any color information should be empty", () => {
|
||||
alertStore.settings.setValues({
|
||||
...alertStore.settings.values,
|
||||
...{ staticColorLabels: [] },
|
||||
...{ labels: {} },
|
||||
});
|
||||
const cs = GetClassAndStyle(alertStore, "foo", "bar");
|
||||
expect(cs.style).toEqual({});
|
||||
|
||||
@@ -33,6 +33,8 @@ const GetClassAndStyle = (
|
||||
colorClassNames: [],
|
||||
};
|
||||
|
||||
const labelSettings = alertStore.settings.values.labels[name];
|
||||
|
||||
if (name === StaticLabels.AlertName) {
|
||||
data.colorClassNames.push(AlertNameLabelClassMap[elementType]);
|
||||
} else if (name === StaticLabels.State) {
|
||||
@@ -41,7 +43,7 @@ const GetClassAndStyle = (
|
||||
? `bg-${StateLabelClassMap[value as AlertStateT]} text-white`
|
||||
: DefaultLabelClassMap[elementType]
|
||||
);
|
||||
} else if (alertStore.settings.values.staticColorLabels.includes(name)) {
|
||||
} else if (labelSettings?.isStatic) {
|
||||
data.colorClassNames.push(StaticColorLabelClassMap[elementType]);
|
||||
} else {
|
||||
const c = alertStore.data.getColorData(name, value);
|
||||
|
||||
@@ -176,10 +176,14 @@ export interface APILabelCounterT {
|
||||
hits: number;
|
||||
}
|
||||
|
||||
export interface APILabelSettingsT {
|
||||
isStatic: boolean;
|
||||
isValueOnly: boolean;
|
||||
}
|
||||
|
||||
export type APILabelsSettingsT = { [key: string]: APILabelSettingsT };
|
||||
|
||||
export interface APISettingsT {
|
||||
staticColorLabels: string[];
|
||||
valueOnlyLabels: string[];
|
||||
valueOnlyRegexLabels: string[];
|
||||
annotationsDefaultHidden: boolean;
|
||||
annotationsHidden: string[];
|
||||
annotationsVisible: string[];
|
||||
@@ -205,6 +209,7 @@ export interface APISettingsT {
|
||||
};
|
||||
historyEnabled: boolean;
|
||||
gridGroupLimit: number;
|
||||
labels: APILabelsSettingsT;
|
||||
}
|
||||
|
||||
export interface APIAlertsResponseT {
|
||||
|
||||
@@ -693,7 +693,12 @@ describe("AlertStore.fetch", () => {
|
||||
store.fetch("", false, "", "", false, {}, 5, {})
|
||||
).resolves.toBeUndefined();
|
||||
expect(store.settings.values).toMatchObject({
|
||||
staticColorLabels: ["job"],
|
||||
labels: {
|
||||
job: {
|
||||
isStatic: true,
|
||||
isValueOnly: false,
|
||||
},
|
||||
},
|
||||
annotationsDefaultHidden: false,
|
||||
annotationsHidden: [],
|
||||
annotationsVisible: [],
|
||||
@@ -705,7 +710,12 @@ describe("AlertStore.fetch", () => {
|
||||
store.fetch("", false, "", "", false, {}, 5, {})
|
||||
).resolves.toBeUndefined();
|
||||
expect(store.settings.values).toMatchObject({
|
||||
staticColorLabels: ["job"],
|
||||
labels: {
|
||||
job: {
|
||||
isStatic: true,
|
||||
isValueOnly: false,
|
||||
},
|
||||
},
|
||||
annotationsDefaultHidden: false,
|
||||
annotationsHidden: [],
|
||||
annotationsVisible: [],
|
||||
|
||||
@@ -461,9 +461,6 @@ class AlertStore {
|
||||
this.settings = observable(
|
||||
{
|
||||
values: {
|
||||
staticColorLabels: [] as string[],
|
||||
valueOnlyLabels: [] as string[],
|
||||
valueOnlyRegexLabels: [] as string[],
|
||||
annotationsDefaultHidden: false as boolean,
|
||||
annotationsHidden: [] as string[],
|
||||
annotationsVisible: [] as string[],
|
||||
@@ -489,6 +486,7 @@ class AlertStore {
|
||||
},
|
||||
historyEnabled: true,
|
||||
gridGroupLimit: 40,
|
||||
labels: {},
|
||||
} as APISettingsT,
|
||||
setValues(v: APISettingsT) {
|
||||
this.values = v;
|
||||
|
||||
@@ -71,15 +71,15 @@ const EmptyAPIResponse = (): APIAlertsResponseT => ({
|
||||
author: "karma / author missing",
|
||||
comment: "ACK! Mock comment",
|
||||
},
|
||||
staticColorLabels: ["job"],
|
||||
valueOnlyLabels: [],
|
||||
valueOnlyRegexLabels: [],
|
||||
annotationsDefaultHidden: false,
|
||||
annotationsHidden: [],
|
||||
annotationsVisible: [],
|
||||
annotationsEnableHTML: false,
|
||||
historyEnabled: true,
|
||||
gridGroupLimit: 40,
|
||||
labels: {
|
||||
job: { isStatic: true, isValueOnly: false },
|
||||
},
|
||||
},
|
||||
authentication: {
|
||||
username: "",
|
||||
@@ -95,10 +95,31 @@ const MockAPIResponse = (): APIAlertsResponseT => {
|
||||
labelValue: "",
|
||||
alertGroups: [
|
||||
MockAlertGroup(
|
||||
[{ name: "alertname", value: "foo" }],
|
||||
[MockAlert([], [{ name: "instance", value: "foo" }], "suppressed")],
|
||||
[
|
||||
{
|
||||
name: "alertname",
|
||||
value: "foo",
|
||||
},
|
||||
],
|
||||
[
|
||||
MockAlert(
|
||||
[],
|
||||
[
|
||||
{
|
||||
name: "instance",
|
||||
value: "foo",
|
||||
},
|
||||
],
|
||||
"suppressed"
|
||||
),
|
||||
],
|
||||
[],
|
||||
[{ name: "cluster", value: "dev" }],
|
||||
[
|
||||
{
|
||||
name: "cluster",
|
||||
value: "dev",
|
||||
},
|
||||
],
|
||||
{}
|
||||
),
|
||||
],
|
||||
|
||||
@@ -64,7 +64,12 @@ const MockGroup = (
|
||||
},
|
||||
]
|
||||
: [],
|
||||
[{ name: "instance", value: `instance${i}` }],
|
||||
[
|
||||
{
|
||||
name: "instance",
|
||||
value: `instance${i}`,
|
||||
},
|
||||
],
|
||||
state
|
||||
);
|
||||
alert.startsAt = subMinutes(new Date(), alertCount).toISOString();
|
||||
@@ -72,7 +77,10 @@ const MockGroup = (
|
||||
}
|
||||
const group = MockAlertGroup(
|
||||
[
|
||||
{ name: "alertname", value: "Fake Alert" },
|
||||
{
|
||||
name: "alertname",
|
||||
value: "Fake Alert",
|
||||
},
|
||||
{ name: "group", value: groupName },
|
||||
],
|
||||
alerts,
|
||||
@@ -174,8 +182,14 @@ const MockGrid = (alertStore: AlertStore): void => {
|
||||
}
|
||||
if (i < 3) {
|
||||
group.shared.labels = [
|
||||
{ name: "cluster", value: `prod${i}` },
|
||||
{ name: "job", value: "textfile_exporter" },
|
||||
{
|
||||
name: "cluster",
|
||||
value: `prod${i}`,
|
||||
},
|
||||
{
|
||||
name: "job",
|
||||
value: "textfile_exporter",
|
||||
},
|
||||
];
|
||||
}
|
||||
if (i < 5) {
|
||||
|
||||
@@ -105,7 +105,16 @@ const useFetchGetMock = (
|
||||
},
|
||||
{
|
||||
re: /^\.\/alertList\.json\?q=/,
|
||||
response: { alerts: [[{ name: "instance", value: "foo" }]] },
|
||||
response: {
|
||||
alerts: [
|
||||
[
|
||||
{
|
||||
name: "instance",
|
||||
value: "foo",
|
||||
},
|
||||
],
|
||||
],
|
||||
},
|
||||
},
|
||||
// silence browser
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user