Skip to content

Commit

Permalink
🐛 Shows client side loading state for jira tracker (#1409)
Browse files Browse the repository at this point in the history
Closes [False 'not connected' status for new Jira
instance](https://issues.redhat.com/browse/MTA-1019)

---------

Signed-off-by: ibolton336 <ibolton@redhat.com>
  • Loading branch information
ibolton336 authored Oct 5, 2023
1 parent 7690380 commit fae624b
Show file tree
Hide file tree
Showing 5 changed files with 89 additions and 23 deletions.
21 changes: 15 additions & 6 deletions client/src/app/pages/external/jira/components/tracker-status.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import "./tracker-status.css";
import React, { useState } from "react";

import spacing from "@patternfly/react-styles/css/utilities/Spacing/spacing";
import { useTranslation } from "react-i18next";
import {
Expand All @@ -10,26 +10,33 @@ import {
Popover,
Text,
TextContent,
Spinner,
} from "@patternfly/react-core";
import ExclamationCircleIcon from "@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon";

import { IconedStatus } from "@app/components/IconedStatus";
import "./tracker-status.css";

interface ITrackerStatusProps {
name: string;
connected: boolean;
message: string;
isTrackerUpdating?: boolean;
}
const TrackerStatus = ({ name, connected, message }: ITrackerStatusProps) => {
const TrackerStatus = ({
name,
connected,
message,
isTrackerUpdating,
}: ITrackerStatusProps) => {
const { t } = useTranslation();

const [isExpanded, setIsExpanded] = useState(false);
const needsExpanding = message.length > 300;
const messageFirst = message.slice(0, 300);
const messageRest = message.slice(300);

return (
return isTrackerUpdating ? (
<Spinner size="sm" />
) : (
<>
<IconedStatus
preset={connected ? "Ok" : "Error"}
Expand All @@ -42,7 +49,9 @@ const TrackerStatus = ({ name, connected, message }: ITrackerStatusProps) => {
aria-label="More information about no connection"
alertSeverityVariant="danger"
headerIcon={<ExclamationCircleIcon />}
headerContent={t("composed.error", { what: t("terms.instance") })}
headerContent={t("composed.error", {
what: t("terms.instance"),
})}
hasAutoWidth
onHidden={() => setIsExpanded(false)}
bodyContent={
Expand Down
36 changes: 22 additions & 14 deletions client/src/app/pages/external/jira/tracker-form.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,49 +57,59 @@ interface FormValues {
}

export interface TrackerFormProps {
tracker?: Tracker;
onClose: () => void;
addUpdatingTrackerId: (id: number) => void;
tracker?: Tracker;
}

export const TrackerForm: React.FC<TrackerFormProps> = ({
tracker,
onClose,
addUpdatingTrackerId,
}) => {
const { t } = useTranslation();

const [axiosError, setAxiosError] = useState<AxiosError>();
const [isLoading, setIsLoading] = useState(false);

const { trackers: trackers } = useFetchTrackers();
const { identities } = useFetchIdentities();

const { pushNotification } = React.useContext(NotificationsContext);

const onCreateTrackerSuccess = (_: AxiosResponse<Tracker>) =>
const onCreateTrackerSuccess = (_: AxiosResponse<Tracker>) => {
pushNotification({
title: t("toastr.success.save", {
type: t("terms.instance"),
}),
variant: "success",
});

const onCreateUpdatetrackerError = (error: AxiosError) => {
setAxiosError(error);
addUpdatingTrackerId(_.data.id);
};

const { mutate: createTracker } = useCreateTrackerMutation(
onCreateTrackerSuccess,
onCreateUpdatetrackerError
);

const onUpdateTrackerSuccess = (_: AxiosResponse<Tracker>) =>
const onUpdateTrackerSuccess = (
_: AxiosResponse<Tracker>,
tracker: Tracker
) => {
pushNotification({
title: t("toastr.success.save", {
type: t("terms.instance"),
}),
variant: "success",
});

addUpdatingTrackerId(tracker.id);
};

const onCreateUpdatetrackerError = (error: AxiosError) => {
setAxiosError(error);
};

const { mutate: createTracker } = useCreateTrackerMutation(
onCreateTrackerSuccess,
onCreateUpdatetrackerError
);

const { mutate: updateTracker } = useUpdateTrackerMutation(
onUpdateTrackerSuccess,
onCreateUpdatetrackerError
Expand Down Expand Up @@ -311,9 +321,7 @@ export const TrackerForm: React.FC<TrackerFormProps> = ({
aria-label="submit"
id="submit"
variant={ButtonVariant.primary}
isDisabled={
!isValid || isSubmitting || isValidating || isLoading || !isDirty
}
isDisabled={!isValid || isSubmitting || isValidating || !isDirty}
>
{!tracker ? "Create" : "Save"}
</Button>
Expand Down
7 changes: 7 additions & 0 deletions client/src/app/pages/external/jira/trackers.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ import { ConditionalRender } from "@app/components/ConditionalRender";
import { AppPlaceholder } from "@app/components/AppPlaceholder";
import { ConfirmDialog } from "@app/components/ConfirmDialog";
import { AppTableActionButtons } from "@app/components/AppTableActionButtons";
import useUpdatingTrackerIds from "./useUpdatingTrackerIds";

export const JiraTrackers: React.FC = () => {
const { t } = useTranslation();
Expand Down Expand Up @@ -147,6 +148,8 @@ export const JiraTrackers: React.FC = () => {
},
} = tableControls;

const [updatingTrackerIds, addUpdatingTrackerId] = useUpdatingTrackerIds();

return (
<>
<PageSection variant={PageSectionVariants.light}>
Expand Down Expand Up @@ -263,6 +266,9 @@ export const JiraTrackers: React.FC = () => {
name={tracker.name}
connected={tracker.connected}
message={tracker.message}
isTrackerUpdating={updatingTrackerIds.has(
tracker.id
)}
/>
</Td>
<Td width={20}>
Expand Down Expand Up @@ -307,6 +313,7 @@ export const JiraTrackers: React.FC = () => {
>
<TrackerForm
tracker={trackerToUpdate ? trackerToUpdate : undefined}
addUpdatingTrackerId={addUpdatingTrackerId}
onClose={() => setTrackerModalState(null)}
/>
</Modal>
Expand Down
42 changes: 42 additions & 0 deletions client/src/app/pages/external/jira/useUpdatingTrackerIds.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { useState } from "react";
import dayjs from "dayjs";

export type UpdatableId = {
id: number;
expirationTime: dayjs.ConfigType;
};

const useUpdatingTrackerIds = () => {
const [updatingTrackerIds, setUpdatingTrackerIds] = useState<
Map<number, dayjs.Dayjs>
>(new Map());

const addUpdatingTrackerId = (id: number) => {
const now = dayjs();
const existingExpiry = updatingTrackerIds.get(id);

if (!existingExpiry || existingExpiry.isBefore(now)) {
const expiryDate = dayjs().add(8, "seconds");

setUpdatingTrackerIds((prevMap) => {
const updatedMap = new Map(prevMap);
updatedMap.set(id, expiryDate);
return updatedMap;
});

const timeRemaining = expiryDate.diff(now);

setTimeout(() => {
setUpdatingTrackerIds((prevMap) => {
const updatedMap = new Map(prevMap);
updatedMap.delete(id);
return updatedMap;
});
}, timeRemaining);
}
};

return [updatingTrackerIds, addUpdatingTrackerId] as const;
};

export default useUpdatingTrackerIds;
6 changes: 3 additions & 3 deletions client/src/app/queries/trackers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@ export const useCreateTrackerMutation = (
};

export const useUpdateTrackerMutation = (
onSuccess: (res: any) => void,
onSuccess: (res: any, tracker: Tracker) => void,
onError: (err: AxiosError) => void
) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: updateTracker,
onSuccess: (res) => {
onSuccess(res);
onSuccess: (res, tracker) => {
onSuccess(res, tracker);
queryClient.invalidateQueries([TrackersQueryKey]);
},
onError: onError,
Expand Down

0 comments on commit fae624b

Please sign in to comment.