Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 23 additions & 35 deletions src/components/Errors/GlobalErrorsList/index.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
import { useEffect, useMemo, useRef, useState } from "react";
import { dispatcher } from "../../../dispatcher";
import { getFeatureFlagValue } from "../../../featureFlags";
import {
Expand Down Expand Up @@ -50,20 +49,8 @@ export const GlobalErrorsList = () => {
const { goTo } = useHistory();
const [isSortingMenuOpen, setIsSortingMenuOpen] = useState(false);
const listContainerRef = useRef<HTMLDivElement | null>(null);
const [parent, toggleAnimations] = useAutoAnimate({
duration: PIN_UNPIN_ANIMATION_DURATION
});
const [latestPinChangedId, setLatestPinChangedId] = useState<string>();

// useAutoAnimate requires to memoize callback
const getListContainerRef = useCallback(
(el: HTMLDivElement | null) => {
listContainerRef.current = el;
parent(el);
},
[parent, listContainerRef]
);

const [areAnimationsEnabled, setAreAnimationsEnabled] = useState(false);
const { environment, backendInfo } = useConfigSelector();
const isDismissEnabled = getFeatureFlagValue(
backendInfo,
Expand Down Expand Up @@ -191,9 +178,8 @@ export const GlobalErrorsList = () => {
};
}, [getData]);

// Cleanup errors store slice on unmount
useMount(() => {
toggleAnimations(false);

return () => {
resetGlobalErrors();
};
Expand All @@ -219,14 +205,14 @@ export const GlobalErrorsList = () => {

if (isLatestChangedIdInList) {
setTimeout(() => {
toggleAnimations(false);
setAreAnimationsEnabled(false);
}, PIN_UNPIN_ANIMATION_DURATION);
} else {
toggleAnimations(false);
setAreAnimationsEnabled(false);
}
setLatestPinChangedId(undefined);
}
}, [previousList, list, latestPinChangedId, toggleAnimations]);
}, [previousList, list, latestPinChangedId]);

// Reset page on filters change
useEffect(() => {
Expand Down Expand Up @@ -305,7 +291,7 @@ export const GlobalErrorsList = () => {
};

const handlePinStatusToggle = () => {
toggleAnimations(true);
setAreAnimationsEnabled(true);
};

const handlePinStatusChange = (errorId: string) => {
Expand Down Expand Up @@ -389,20 +375,22 @@ export const GlobalErrorsList = () => {
</NewPopover>
</s.ToolbarContainer>
{list.length > 0 ? (
<>
<s.ListContainer ref={getListContainerRef}>
{list.map((x) => (
<NewErrorCard
key={x.id}
data={x}
onSourceLinkClick={handleErrorSourceLinkClick}
onPinStatusChange={handlePinStatusChange}
onPinStatusToggle={handlePinStatusToggle}
onDismissStatusChange={handleDismissalStatusChange}
/>
))}
</s.ListContainer>
</>
<s.ListContainer
ref={listContainerRef}
isAnimationEnabled={areAnimationsEnabled}
animationOptions={{ duration: PIN_UNPIN_ANIMATION_DURATION }}
>
{list.map((x) => (
<NewErrorCard
key={x.id}
data={x}
onSourceLinkClick={handleErrorSourceLinkClick}
onPinStatusChange={handlePinStatusChange}
onPinStatusToggle={handlePinStatusToggle}
onDismissStatusChange={handleDismissalStatusChange}
/>
))}
</s.ListContainer>
) : areAnyFiltersApplied ? (
<NewEmptyState
icon={CardsColoredIcon}
Expand Down
3 changes: 2 additions & 1 deletion src/components/Errors/GlobalErrorsList/styles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import {
subscriptMediumTypography,
subscriptRegularTypography
} from "../../common/App/typographies";
import { AutoAnimatedContainer } from "../../common/AutoAnimatedContainer";
import { EyeIcon } from "../../common/icons/16px/EyeIcon";
import { DismissBtnIconProps } from "./types";

Expand Down Expand Up @@ -64,7 +65,7 @@ export const ToolbarContainer = styled.div`
gap: 4px;
`;

export const ListContainer = styled.div`
export const ListContainer = styled(AutoAnimatedContainer)`
display: flex;
flex-direction: column;
gap: 8px;
Expand Down
29 changes: 18 additions & 11 deletions src/components/Errors/NewErrorCard/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const NewErrorCard = ({
const [isHistogramVisible, setIsHistogramVisible] = useState(false);
const chartContainerRef = useRef<HTMLDivElement>(null);
const { backendInfo } = useConfigSelector();
const [isPinned, setIsPinned] = useState(Boolean(data.pinnedAt));

const isOccurrenceChartEnabled = getFeatureFlagValue(
backendInfo,
Expand All @@ -54,15 +55,6 @@ export const NewErrorCard = ({
FeatureFlag.IS_GLOBAL_ERROR_DISMISS_ENABLED
);

const {
pin,
unpin,
data: pinUnpinResponse,
isInProgress: isPinUnpinInProgress
} = usePinning(data.id);

const previousPinUnpinResponse = usePrevious(pinUnpinResponse);

const {
id,
affectedEndpoints,
Expand All @@ -73,8 +65,19 @@ export const NewErrorCard = ({
status,
firstDetected,
lastDetected,
isDismissed
isDismissed,
pinnedAt
} = data;

const {
pin,
unpin,
data: pinUnpinResponse,
isInProgress: isPinUnpinInProgress
} = usePinning(id);

const previousPinUnpinResponse = usePrevious(pinUnpinResponse);

const statusTagType = getTagType(score.score);
const {
isDismissalChangeInProgress,
Expand Down Expand Up @@ -125,6 +128,10 @@ export const NewErrorCard = ({
}
}, [onPinStatusChange, pinUnpinResponse, previousPinUnpinResponse]);

useEffect(() => {
setIsPinned(Boolean(pinnedAt));
}, [pinnedAt]);

const handleLinkClick = () => {
sendUserActionTrackingEvent(trackingEvents.ERROR_CARD_SOURCE_LINK_CLICKED);
onSourceLinkClick(id);
Expand Down Expand Up @@ -180,6 +187,7 @@ export const NewErrorCard = ({
unpin();
}

setIsPinned(value);
onPinStatusToggle();
};

Expand All @@ -198,7 +206,6 @@ export const NewErrorCard = ({
};

const isCritical = score.score > HIGH_SEVERITY_SCORE_THRESHOLD;
const isPinned = Boolean(data.pinnedAt);

const selectorValue = selectedEndpoint
? getEndpointKey(selectedEndpoint)
Expand Down
46 changes: 46 additions & 0 deletions src/components/common/AutoAnimatedContainer/index.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { useAutoAnimate } from "@formkit/auto-animate/react";
import { ForwardedRef, forwardRef, useCallback, useEffect } from "react";
import { useMount } from "../../../hooks/useMount";
import { AutoAnimatedContainerProps } from "./types";

export const AutoAnimatedContainerComponent = (
{
children,
isAnimationEnabled,
animationOptions,
className
}: AutoAnimatedContainerProps,
ref: ForwardedRef<HTMLDivElement>
) => {
const [parent, enable] = useAutoAnimate<HTMLDivElement>(animationOptions);

// Memoization is required to avoid React "Maximum update depth exceeded" error
// More info: https://github.com/formkit/auto-animate/issues/166
const getRef = useCallback(
(element: HTMLDivElement | null) => {
if (typeof ref === "function") {
ref(element);
} else if (ref) {
ref.current = element;
}
parent(element);
},
[parent, ref]
);

useMount(() => {
enable(isAnimationEnabled);
});

useEffect(() => {
enable(isAnimationEnabled);
}, [enable, isAnimationEnabled]);

return (
<div className={className} ref={getRef}>
{children}
</div>
);
};

export const AutoAnimatedContainer = forwardRef(AutoAnimatedContainerComponent);
9 changes: 9 additions & 0 deletions src/components/common/AutoAnimatedContainer/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { AutoAnimateOptions } from "@formkit/auto-animate";
import { ReactNode } from "react";

export interface AutoAnimatedContainerProps {
isAnimationEnabled: boolean;
children: ReactNode;
animationOptions?: Partial<AutoAnimateOptions>;
className?: string;
}
Loading