mirror of
https://github.com/prymitive/karma
synced 2026-05-05 03:16:51 +00:00
fix(ui): enable reactionRequiresObservable
This commit is contained in:
committed by
Łukasz Mierzwa
parent
c67d2f6e1d
commit
9aa2f93e00
@@ -1,4 +1,4 @@
|
||||
import { Ref, CSSProperties, useRef, useState, useCallback } from "react";
|
||||
import { FC, Ref, CSSProperties, useRef, useState, useCallback } from "react";
|
||||
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
@@ -180,59 +180,63 @@ interface AlertMenuProps {
|
||||
setIsMenuOpen: (isOpen: boolean) => void;
|
||||
}
|
||||
|
||||
const AlertMenu = observer<AlertMenuProps>(
|
||||
({ group, alert, alertStore, silenceFormStore, setIsMenuOpen }) => {
|
||||
const [isHidden, setIsHidden] = useState<boolean>(true);
|
||||
const AlertMenu: FC<AlertMenuProps> = ({
|
||||
group,
|
||||
alert,
|
||||
alertStore,
|
||||
silenceFormStore,
|
||||
setIsMenuOpen,
|
||||
}) => {
|
||||
const [isHidden, setIsHidden] = useState<boolean>(true);
|
||||
|
||||
const toggle = useCallback(() => {
|
||||
setIsMenuOpen(isHidden);
|
||||
setIsHidden(!isHidden);
|
||||
}, [isHidden, setIsMenuOpen]);
|
||||
const toggle = useCallback(() => {
|
||||
setIsMenuOpen(isHidden);
|
||||
setIsHidden(!isHidden);
|
||||
}, [isHidden, setIsMenuOpen]);
|
||||
|
||||
const hide = useCallback(() => {
|
||||
setIsHidden(true);
|
||||
setIsMenuOpen(false);
|
||||
}, [setIsMenuOpen]);
|
||||
const hide = useCallback(() => {
|
||||
setIsHidden(true);
|
||||
setIsMenuOpen(false);
|
||||
}, [setIsMenuOpen]);
|
||||
|
||||
const rootRef = useRef<HTMLSpanElement | null>(null);
|
||||
useOnClickOutside(rootRef, hide, !isHidden);
|
||||
const rootRef = useRef<HTMLSpanElement | null>(null);
|
||||
useOnClickOutside(rootRef, hide, !isHidden);
|
||||
|
||||
const { x, y, refs, strategy } = useFloating({
|
||||
placement: "bottom-start",
|
||||
middleware: [shift(), offset(5)],
|
||||
});
|
||||
const { x, y, refs, strategy } = useFloating({
|
||||
placement: "bottom-start",
|
||||
middleware: [shift(), offset(5)],
|
||||
});
|
||||
|
||||
return (
|
||||
<span ref={rootRef}>
|
||||
<span
|
||||
className="components-label components-label-with-hover px-1 me-1 badge bg-secondary cursor-pointer"
|
||||
ref={refs.setReference}
|
||||
onClick={toggle}
|
||||
data-toggle="dropdown"
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
className="pe-1"
|
||||
style={{ width: "0.8rem" }}
|
||||
icon={faCaretDown}
|
||||
/>
|
||||
<DateFromNow timestamp={alert.startsAt} />
|
||||
</span>
|
||||
<DropdownSlide in={!isHidden} unmountOnExit>
|
||||
<MenuContent
|
||||
group={group}
|
||||
alert={alert}
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
afterClick={hide}
|
||||
x={x}
|
||||
y={y}
|
||||
floating={refs.setFloating}
|
||||
strategy={strategy}
|
||||
/>
|
||||
</DropdownSlide>
|
||||
return (
|
||||
<span ref={rootRef}>
|
||||
<span
|
||||
className="components-label components-label-with-hover px-1 me-1 badge bg-secondary cursor-pointer"
|
||||
ref={refs.setReference}
|
||||
onClick={toggle}
|
||||
data-toggle="dropdown"
|
||||
>
|
||||
<FontAwesomeIcon
|
||||
className="pe-1"
|
||||
style={{ width: "0.8rem" }}
|
||||
icon={faCaretDown}
|
||||
/>
|
||||
<DateFromNow timestamp={alert.startsAt} />
|
||||
</span>
|
||||
);
|
||||
},
|
||||
);
|
||||
<DropdownSlide in={!isHidden} unmountOnExit>
|
||||
<MenuContent
|
||||
group={group}
|
||||
alert={alert}
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
afterClick={hide}
|
||||
x={x}
|
||||
y={y}
|
||||
floating={refs.setFloating}
|
||||
strategy={strategy}
|
||||
/>
|
||||
</DropdownSlide>
|
||||
</span>
|
||||
);
|
||||
};
|
||||
|
||||
export { AlertMenu, MenuContent };
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import type { FC, MouseEvent } from "react";
|
||||
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
import type { APIAlertGroupT } from "Models/APITypes";
|
||||
import type { AlertStore } from "Stores/AlertStore";
|
||||
import type { SilenceFormStore } from "Stores/SilenceFormStore";
|
||||
@@ -116,4 +114,4 @@ const GroupHeader: FC<{
|
||||
);
|
||||
};
|
||||
|
||||
export default observer(GroupHeader);
|
||||
export default GroupHeader;
|
||||
|
||||
@@ -8,8 +8,6 @@ import {
|
||||
useCallback,
|
||||
} from "react";
|
||||
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
import { useFloating, shift, offset } from "@floating-ui/react-dom";
|
||||
|
||||
import type { OnChangeValue } from "react-select";
|
||||
@@ -134,7 +132,7 @@ const GridLabelSelect: FC<{
|
||||
alertStore: AlertStore;
|
||||
settingsStore: Settings;
|
||||
grid: APIGridT;
|
||||
}> = observer(({ alertStore, settingsStore, grid }) => {
|
||||
}> = ({ alertStore, settingsStore, grid }) => {
|
||||
const [isVisible, setIsVisible] = useState<boolean>(false);
|
||||
const hide = useCallback(() => setIsVisible(false), []);
|
||||
const toggle = useCallback(() => {
|
||||
@@ -172,6 +170,6 @@ const GridLabelSelect: FC<{
|
||||
</DropdownSlide>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export { GridLabelSelect };
|
||||
|
||||
@@ -57,8 +57,6 @@ const FilteringCounterBadge: FC<{
|
||||
[alertStore.filters, name, value, isAppend],
|
||||
);
|
||||
|
||||
if (!alwaysVisible && counter === 0) return null;
|
||||
|
||||
const cs = GetClassAndStyle(
|
||||
alertStore,
|
||||
name,
|
||||
@@ -66,6 +64,8 @@ const FilteringCounterBadge: FC<{
|
||||
"rounded-pill components-label-with-hover",
|
||||
);
|
||||
|
||||
if (!alwaysVisible && counter === 0) return null;
|
||||
|
||||
return (
|
||||
<TooltipWrapper
|
||||
title={`Click to only show ${name}=${value} alerts or Alt+Click to hide them`}
|
||||
|
||||
@@ -17,7 +17,7 @@ import { StaticLabels } from "Common/Query";
|
||||
|
||||
const SilenceProgress: FC<{
|
||||
silence: APISilenceT;
|
||||
}> = observer(({ silence }) => {
|
||||
}> = ({ silence }) => {
|
||||
const diff = differenceInSeconds(parseISO(silence.endsAt), new Date());
|
||||
if (diff <= 0) {
|
||||
return (
|
||||
@@ -35,7 +35,7 @@ const SilenceProgress: FC<{
|
||||
Expires <DateFromNow timestamp={silence.endsAt} />
|
||||
</span>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
const SilenceComment: FC<{
|
||||
cluster: string;
|
||||
@@ -68,6 +68,9 @@ const SilenceComment: FC<{
|
||||
),
|
||||
);
|
||||
|
||||
const hasMultipleClusters =
|
||||
Object.keys(alertStore.data.upstreams.clusters).length > 1;
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className="d-flex flex-row">
|
||||
@@ -93,8 +96,7 @@ const SilenceComment: FC<{
|
||||
{collapsed ? (
|
||||
<div className="d-flex flex-row justify-content-end flex-grow-1">
|
||||
<SilenceProgress silence={silence} />
|
||||
{Object.keys(alertStore.data.upstreams.clusters).length >
|
||||
1 ? (
|
||||
{hasMultipleClusters ? (
|
||||
<span className="badge bg-secondary mx-1 components-label">
|
||||
{cluster}
|
||||
</span>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { FC, useEffect, useState } from "react";
|
||||
|
||||
import { action } from "mobx";
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
import { parseISO } from "date-fns/parseISO";
|
||||
import { getUnixTime } from "date-fns/getUnixTime";
|
||||
@@ -38,89 +37,86 @@ const ManagedSilence: FC<{
|
||||
isOpen?: boolean;
|
||||
onDidUpdate?: () => void;
|
||||
isNested?: boolean;
|
||||
}> = observer(
|
||||
({
|
||||
cluster,
|
||||
alertCount,
|
||||
alertCountAlwaysVisible,
|
||||
silence,
|
||||
alertStore,
|
||||
silenceFormStore,
|
||||
isOpen = false,
|
||||
onDidUpdate,
|
||||
isNested = false,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
if (onDidUpdate) onDidUpdate();
|
||||
});
|
||||
}> = ({
|
||||
cluster,
|
||||
alertCount,
|
||||
alertCountAlwaysVisible,
|
||||
silence,
|
||||
alertStore,
|
||||
silenceFormStore,
|
||||
isOpen = false,
|
||||
onDidUpdate,
|
||||
isNested = false,
|
||||
}) => {
|
||||
useEffect(() => {
|
||||
if (onDidUpdate) onDidUpdate();
|
||||
});
|
||||
|
||||
const [showDetails, setShowDetails] = useState<boolean>(isOpen);
|
||||
const [showDetails, setShowDetails] = useState<boolean>(isOpen);
|
||||
|
||||
const onEditSilence = action(() => {
|
||||
const alertmanager = GetAlertmanager(alertStore, cluster);
|
||||
const onEditSilence = action(() => {
|
||||
const alertmanager = GetAlertmanager(alertStore, cluster);
|
||||
|
||||
silenceFormStore.data.fillFormFromSilence(alertmanager, silence);
|
||||
silenceFormStore.data.resetProgress();
|
||||
silenceFormStore.tab.setTab("editor");
|
||||
silenceFormStore.toggle.show();
|
||||
});
|
||||
silenceFormStore.data.fillFormFromSilence(alertmanager, silence);
|
||||
silenceFormStore.data.resetProgress();
|
||||
silenceFormStore.tab.setTab("editor");
|
||||
silenceFormStore.toggle.show();
|
||||
});
|
||||
|
||||
const [progress, setProgress] = useState<number>(() =>
|
||||
calculatePercent(silence.startsAt, silence.endsAt),
|
||||
);
|
||||
const [progress, setProgress] = useState<number>(() =>
|
||||
calculatePercent(silence.startsAt, silence.endsAt),
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setProgress(calculatePercent(silence.startsAt, silence.endsAt));
|
||||
}, 30 * 1000);
|
||||
return () => clearInterval(timer);
|
||||
}, [silence.startsAt, silence.endsAt]);
|
||||
useEffect(() => {
|
||||
const timer = setInterval(() => {
|
||||
setProgress(calculatePercent(silence.startsAt, silence.endsAt));
|
||||
}, 30 * 1000);
|
||||
return () => clearInterval(timer);
|
||||
}, [silence.startsAt, silence.endsAt]);
|
||||
|
||||
return (
|
||||
<div className="card my-1 components-managed-silence w-100">
|
||||
<div className="card-header rounded-0 border-bottom-0 px-2">
|
||||
<SilenceComment
|
||||
alertStore={alertStore}
|
||||
return (
|
||||
<div className="card my-1 components-managed-silence w-100">
|
||||
<div className="card-header rounded-0 border-bottom-0 px-2">
|
||||
<SilenceComment
|
||||
alertStore={alertStore}
|
||||
cluster={cluster}
|
||||
silence={silence}
|
||||
alertCount={alertCount}
|
||||
alertCountAlwaysVisible={alertCountAlwaysVisible}
|
||||
collapsed={!showDetails}
|
||||
collapseToggle={() => setShowDetails(!showDetails)}
|
||||
/>
|
||||
</div>
|
||||
{showDetails ? (
|
||||
<div className="card-body pt-0 px-2">
|
||||
<SilenceDetails
|
||||
cluster={cluster}
|
||||
silence={silence}
|
||||
alertCount={alertCount}
|
||||
alertCountAlwaysVisible={alertCountAlwaysVisible}
|
||||
collapsed={!showDetails}
|
||||
collapseToggle={() => setShowDetails(!showDetails)}
|
||||
/>
|
||||
</div>
|
||||
{showDetails ? (
|
||||
<div className="card-body pt-0 px-2">
|
||||
<SilenceDetails
|
||||
cluster={cluster}
|
||||
silence={silence}
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
onEditSilence={onEditSilence}
|
||||
isUpper={isNested}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="progress silence-progress mx-2 mb-1">
|
||||
<div
|
||||
className={
|
||||
progress > 90
|
||||
? "progress-bar bg-danger"
|
||||
: progress > 75
|
||||
? "progress-bar bg-warning"
|
||||
: "progress-bar bg-success"
|
||||
}
|
||||
role="progressbar"
|
||||
style={{ width: progress + "%" }}
|
||||
aria-valuenow={progress}
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={100}
|
||||
alertStore={alertStore}
|
||||
silenceFormStore={silenceFormStore}
|
||||
onEditSilence={onEditSilence}
|
||||
isUpper={isNested}
|
||||
/>
|
||||
</div>
|
||||
) : null}
|
||||
<div className="progress silence-progress mx-2 mb-1">
|
||||
<div
|
||||
className={
|
||||
progress > 90
|
||||
? "progress-bar bg-danger"
|
||||
: progress > 75
|
||||
? "progress-bar bg-warning"
|
||||
: "progress-bar bg-success"
|
||||
}
|
||||
role="progressbar"
|
||||
style={{ width: progress + "%" }}
|
||||
aria-valuenow={progress}
|
||||
aria-valuemin={0}
|
||||
aria-valuemax={100}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
ManagedSilence.displayName = "ManagedSilence";
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { ManagedSilence, GetAlertmanager };
|
||||
|
||||
@@ -64,7 +64,7 @@ const LabelsTable: FC<{
|
||||
counters: CountersResponseT;
|
||||
showAllLabels: boolean;
|
||||
toggleAllLabels: () => void;
|
||||
}> = observer(({ alertStore, counters, showAllLabels, toggleAllLabels }) => (
|
||||
}> = ({ alertStore, counters, showAllLabels, toggleAllLabels }) => (
|
||||
<>
|
||||
<table
|
||||
className="table table-borderless top-labels"
|
||||
@@ -104,7 +104,7 @@ const LabelsTable: FC<{
|
||||
</tbody>
|
||||
</table>
|
||||
</>
|
||||
));
|
||||
);
|
||||
|
||||
const NothingToShow: FC = () => (
|
||||
<div className="px-2 py-5 bg-transparent">
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { FC, useEffect, useRef } from "react";
|
||||
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faAngleUp } from "@fortawesome/free-solid-svg-icons/faAngleUp";
|
||||
import { faAngleDown } from "@fortawesome/free-solid-svg-icons/faAngleDown";
|
||||
@@ -11,7 +9,7 @@ const Duration: FC<{
|
||||
label: string;
|
||||
onInc: () => void;
|
||||
onDec: () => void;
|
||||
}> = observer(({ value, label, onInc, onDec }) => {
|
||||
}> = ({ value, label, onInc, onDec }) => {
|
||||
const rootRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
@@ -78,6 +76,6 @@ const Duration: FC<{
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export { Duration };
|
||||
|
||||
@@ -1,7 +1,5 @@
|
||||
import { FC, useEffect, useRef, MouseEvent, WheelEvent } from "react";
|
||||
|
||||
import { observer } from "mobx-react-lite";
|
||||
|
||||
import type { IconDefinition } from "@fortawesome/fontawesome-svg-core";
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faAngleUp } from "@fortawesome/free-solid-svg-icons/faAngleUp";
|
||||
@@ -30,94 +28,92 @@ const HourMinute: FC<{
|
||||
onHourDec: () => void;
|
||||
onMinuteInc: () => void;
|
||||
onMinuteDec: () => void;
|
||||
}> = observer(
|
||||
({ dateValue, onHourInc, onHourDec, onMinuteInc, onMinuteDec }) => {
|
||||
const rootRef = useRef<HTMLDivElement | null>(null);
|
||||
}> = ({ dateValue, onHourInc, onHourDec, onMinuteInc, onMinuteDec }) => {
|
||||
const rootRef = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
useEffect(() => {
|
||||
const cancelWheel = (event: Event) => event.preventDefault();
|
||||
useEffect(() => {
|
||||
const cancelWheel = (event: Event) => event.preventDefault();
|
||||
|
||||
const elem = rootRef.current as HTMLDivElement;
|
||||
const elem = rootRef.current as HTMLDivElement;
|
||||
|
||||
elem.addEventListener("wheel", cancelWheel, { passive: false });
|
||||
elem.addEventListener("wheel", cancelWheel, { passive: false });
|
||||
|
||||
return () => {
|
||||
elem.removeEventListener("wheel", cancelWheel);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onHourWheel = (event: WheelEvent) => {
|
||||
if (event.deltaY < 0) {
|
||||
onHourInc();
|
||||
} else {
|
||||
onHourDec();
|
||||
}
|
||||
return () => {
|
||||
elem.removeEventListener("wheel", cancelWheel);
|
||||
};
|
||||
}, []);
|
||||
|
||||
const onMinuteWheel = (event: WheelEvent) => {
|
||||
if (event.deltaY < 0) {
|
||||
onMinuteInc();
|
||||
} else {
|
||||
onMinuteDec();
|
||||
}
|
||||
};
|
||||
const onHourWheel = (event: WheelEvent) => {
|
||||
if (event.deltaY < 0) {
|
||||
onHourInc();
|
||||
} else {
|
||||
onHourDec();
|
||||
}
|
||||
};
|
||||
|
||||
const hour = dateValue.getHours();
|
||||
const minute = dateValue.getMinutes();
|
||||
const onMinuteWheel = (event: WheelEvent) => {
|
||||
if (event.deltaY < 0) {
|
||||
onMinuteInc();
|
||||
} else {
|
||||
onMinuteDec();
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={rootRef}
|
||||
className="d-flex justify-content-center align-items-center components-hour-minute"
|
||||
>
|
||||
<table className="text-center border-0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<IconTd
|
||||
icon={faAngleUp}
|
||||
onClick={onHourInc}
|
||||
onWheel={onHourWheel}
|
||||
className="components-hour-up with-click"
|
||||
/>
|
||||
<td />
|
||||
<IconTd
|
||||
icon={faAngleUp}
|
||||
onClick={onMinuteInc}
|
||||
onWheel={onMinuteWheel}
|
||||
className="components-minute-up with-click"
|
||||
/>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="components-hour" onWheel={onHourWheel}>
|
||||
<h2>{hour > 9 ? hour : `0${hour}`}</h2>
|
||||
</td>
|
||||
<td>
|
||||
<h2 className="mx-2">:</h2>
|
||||
</td>
|
||||
<td className="components-minute" onWheel={onMinuteWheel}>
|
||||
<h2>{minute > 9 ? minute : `0${minute}`}</h2>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<IconTd
|
||||
icon={faAngleDown}
|
||||
onClick={onHourDec}
|
||||
onWheel={onHourWheel}
|
||||
className="components-hour-down with-click"
|
||||
/>
|
||||
<td />
|
||||
<IconTd
|
||||
icon={faAngleDown}
|
||||
onClick={onMinuteDec}
|
||||
onWheel={onMinuteWheel}
|
||||
className="components-minute-down with-click"
|
||||
/>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
);
|
||||
const hour = dateValue.getHours();
|
||||
const minute = dateValue.getMinutes();
|
||||
|
||||
return (
|
||||
<div
|
||||
ref={rootRef}
|
||||
className="d-flex justify-content-center align-items-center components-hour-minute"
|
||||
>
|
||||
<table className="text-center border-0">
|
||||
<tbody>
|
||||
<tr>
|
||||
<IconTd
|
||||
icon={faAngleUp}
|
||||
onClick={onHourInc}
|
||||
onWheel={onHourWheel}
|
||||
className="components-hour-up with-click"
|
||||
/>
|
||||
<td />
|
||||
<IconTd
|
||||
icon={faAngleUp}
|
||||
onClick={onMinuteInc}
|
||||
onWheel={onMinuteWheel}
|
||||
className="components-minute-up with-click"
|
||||
/>
|
||||
</tr>
|
||||
<tr>
|
||||
<td className="components-hour" onWheel={onHourWheel}>
|
||||
<h2>{hour > 9 ? hour : `0${hour}`}</h2>
|
||||
</td>
|
||||
<td>
|
||||
<h2 className="mx-2">:</h2>
|
||||
</td>
|
||||
<td className="components-minute" onWheel={onMinuteWheel}>
|
||||
<h2>{minute > 9 ? minute : `0${minute}`}</h2>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<IconTd
|
||||
icon={faAngleDown}
|
||||
onClick={onHourDec}
|
||||
onWheel={onHourWheel}
|
||||
className="components-hour-down with-click"
|
||||
/>
|
||||
<td />
|
||||
<IconTd
|
||||
icon={faAngleDown}
|
||||
onClick={onMinuteDec}
|
||||
onWheel={onMinuteWheel}
|
||||
className="components-minute-down with-click"
|
||||
/>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export { HourMinute };
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
import { use, FC } from "react";
|
||||
|
||||
import { action } from "mobx";
|
||||
|
||||
import Creatable from "react-select/creatable";
|
||||
|
||||
import { FormatBackendURI } from "Stores/AlertStore";
|
||||
@@ -11,6 +13,12 @@ import { AnimatedMenu } from "Components/Select";
|
||||
import { NewLabelName, OptionT, StringToOption } from "Common/Select";
|
||||
import { OnChangeValue } from "react-select";
|
||||
|
||||
const setMatcherName = action(
|
||||
(matcher: MatcherWithIDT, option: OnChangeValue<OptionT, false>) => {
|
||||
matcher.name = (option as OptionT).value;
|
||||
},
|
||||
);
|
||||
|
||||
const LabelNameInput: FC<{
|
||||
matcher: MatcherWithIDT;
|
||||
isValid: boolean;
|
||||
@@ -32,10 +40,9 @@ const LabelNameInput: FC<{
|
||||
response ? response.map((value: string) => StringToOption(value)) : []
|
||||
}
|
||||
placeholder={isValid ? "Label name" : <ValidationError />}
|
||||
onChange={(option: OnChangeValue<OptionT, false>) => {
|
||||
// eslint-disable-next-line react-compiler/react-compiler -- intentional MobX observable mutation
|
||||
matcher.name = (option as OptionT).value;
|
||||
}}
|
||||
onChange={(option: OnChangeValue<OptionT, false>) =>
|
||||
setMatcherName(matcher, option)
|
||||
}
|
||||
hideSelectedOptions
|
||||
components={{ Menu: AnimatedMenu }}
|
||||
/>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { use, FC, useEffect } from "react";
|
||||
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { action } from "mobx";
|
||||
|
||||
import {
|
||||
ActionMeta,
|
||||
@@ -21,6 +21,23 @@ import { ThemeContext } from "Components/Theme";
|
||||
import { AnimatedMenuMultiple } from "Components/Select";
|
||||
import { MatchCounter } from "./MatchCounter";
|
||||
|
||||
const updateMatcherValues = action(
|
||||
(
|
||||
matcher: MatcherWithIDT,
|
||||
newValue: OnChangeValue<OptionT, true>,
|
||||
meta: ActionMeta<OptionT>,
|
||||
) => {
|
||||
matcher.values = newValue as OptionT[];
|
||||
// force regex if we have multiple values
|
||||
if (matcher.values.length > 1 && matcher.isRegex === false) {
|
||||
matcher.isRegex = true;
|
||||
}
|
||||
if (meta.action === "create-option") {
|
||||
matcher.values[matcher.values.length - 1].wasCreated = true;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const GenerateHashFromMatchers = (
|
||||
silenceFormStore: SilenceFormStore,
|
||||
matcher: MatcherWithIDT,
|
||||
@@ -66,7 +83,7 @@ const LabelValueInput: FC<{
|
||||
silenceFormStore: SilenceFormStore;
|
||||
matcher: MatcherWithIDT;
|
||||
isValid: boolean;
|
||||
}> = observer(({ silenceFormStore, matcher, isValid }) => {
|
||||
}> = ({ silenceFormStore, matcher, isValid }) => {
|
||||
const { response, get, cancelGet } = useFetchGet<string[]>(
|
||||
FormatBackendURI(`labelValues.json?name=${matcher.name}`),
|
||||
{ autorun: false },
|
||||
@@ -97,16 +114,7 @@ const LabelValueInput: FC<{
|
||||
onChange={(
|
||||
newValue: OnChangeValue<OptionT, true>,
|
||||
meta: ActionMeta<OptionT>,
|
||||
) => {
|
||||
matcher.values = newValue as OptionT[];
|
||||
// force regex if we have multiple values
|
||||
if (matcher.values.length > 1 && matcher.isRegex === false) {
|
||||
matcher.isRegex = true;
|
||||
}
|
||||
if (meta.action === "create-option") {
|
||||
matcher.values[matcher.values.length - 1].wasCreated = true;
|
||||
}
|
||||
}}
|
||||
) => updateMatcherValues(matcher, newValue, meta)}
|
||||
hideSelectedOptions
|
||||
isMulti
|
||||
components={{
|
||||
@@ -116,6 +124,6 @@ const LabelValueInput: FC<{
|
||||
}}
|
||||
/>
|
||||
);
|
||||
});
|
||||
};
|
||||
|
||||
export { LabelValueInput };
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { FC } from "react";
|
||||
|
||||
import { observer } from "mobx-react-lite";
|
||||
import { action } from "mobx";
|
||||
|
||||
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
|
||||
import { faTrash } from "@fortawesome/free-solid-svg-icons/faTrash";
|
||||
@@ -10,6 +10,20 @@ import { TooltipWrapper } from "Components/TooltipWrapper";
|
||||
import { LabelNameInput } from "./LabelNameInput";
|
||||
import { LabelValueInput } from "./LabelValueInput";
|
||||
|
||||
const setMatcherIsEqual = action(
|
||||
(matcher: MatcherWithIDT, checked: boolean) => {
|
||||
matcher.isEqual = checked;
|
||||
},
|
||||
);
|
||||
|
||||
const setMatcherIsRegex = action(
|
||||
(matcher: MatcherWithIDT, checked: boolean) => {
|
||||
if (matcher.values.length <= 1) {
|
||||
matcher.isRegex = checked;
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
const SilenceMatch: FC<{
|
||||
silenceFormStore: SilenceFormStore;
|
||||
matcher: MatcherWithIDT;
|
||||
@@ -48,10 +62,9 @@ const SilenceMatch: FC<{
|
||||
type="checkbox"
|
||||
value=""
|
||||
checked={matcher.isEqual}
|
||||
onChange={(event) => {
|
||||
// eslint-disable-next-line react-compiler/react-compiler -- intentional MobX observable mutation
|
||||
matcher.isEqual = event.target.checked;
|
||||
}}
|
||||
onChange={(event) =>
|
||||
setMatcherIsEqual(matcher, event.target.checked)
|
||||
}
|
||||
/>
|
||||
<label
|
||||
className="form-check-label cursor-pointer me-3"
|
||||
@@ -67,11 +80,9 @@ const SilenceMatch: FC<{
|
||||
type="checkbox"
|
||||
value=""
|
||||
checked={matcher.isRegex}
|
||||
onChange={(event) => {
|
||||
if (matcher.values.length <= 1) {
|
||||
matcher.isRegex = event.target.checked;
|
||||
}
|
||||
}}
|
||||
onChange={(event) =>
|
||||
setMatcherIsRegex(matcher, event.target.checked)
|
||||
}
|
||||
disabled={matcher.values.length > 1}
|
||||
/>
|
||||
<label
|
||||
@@ -99,4 +110,4 @@ const SilenceMatch: FC<{
|
||||
);
|
||||
};
|
||||
|
||||
export default observer(SilenceMatch);
|
||||
export default SilenceMatch;
|
||||
|
||||
@@ -24,7 +24,7 @@ fetchMock.mockGlobal();
|
||||
configure({
|
||||
enforceActions: "observed",
|
||||
computedRequiresReaction: true,
|
||||
// reactionRequiresObservable: true,
|
||||
reactionRequiresObservable: true,
|
||||
// observableRequiresReaction: true,
|
||||
});
|
||||
|
||||
|
||||
Reference in New Issue
Block a user