refactor: improve perf by calling api in parallel in clientLoaders (#312)
* refactor: improve perf by calling api in parallel in clientLoaders * fix: dependent api calls
This commit is contained in:
parent
13428224e8
commit
f0e956783a
7 changed files with 59 additions and 25 deletions
|
|
@ -21,11 +21,13 @@ import { StatusDot } from "~/client/components/status-dot";
|
||||||
import { formatDistanceToNow } from "date-fns";
|
import { formatDistanceToNow } from "date-fns";
|
||||||
import { Link } from "react-router";
|
import { Link } from "react-router";
|
||||||
import { cn } from "~/client/lib/utils";
|
import { cn } from "~/client/lib/utils";
|
||||||
|
import type { GetScheduleMirrorsResponse } from "~/client/api-client";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
scheduleId: number;
|
scheduleId: number;
|
||||||
primaryRepositoryId: string;
|
primaryRepositoryId: string;
|
||||||
repositories: Repository[];
|
repositories: Repository[];
|
||||||
|
initialData: GetScheduleMirrorsResponse;
|
||||||
};
|
};
|
||||||
|
|
||||||
type MirrorAssignment = {
|
type MirrorAssignment = {
|
||||||
|
|
@ -36,13 +38,14 @@ type MirrorAssignment = {
|
||||||
lastCopyError: string | null;
|
lastCopyError: string | null;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ScheduleMirrorsConfig = ({ scheduleId, primaryRepositoryId, repositories }: Props) => {
|
export const ScheduleMirrorsConfig = ({ scheduleId, primaryRepositoryId, repositories, initialData }: Props) => {
|
||||||
const [assignments, setAssignments] = useState<Map<string, MirrorAssignment>>(new Map());
|
const [assignments, setAssignments] = useState<Map<string, MirrorAssignment>>(new Map());
|
||||||
const [hasChanges, setHasChanges] = useState(false);
|
const [hasChanges, setHasChanges] = useState(false);
|
||||||
const [isAddingNew, setIsAddingNew] = useState(false);
|
const [isAddingNew, setIsAddingNew] = useState(false);
|
||||||
|
|
||||||
const { data: currentMirrors } = useQuery({
|
const { data: currentMirrors } = useQuery({
|
||||||
...getScheduleMirrorsOptions({ path: { scheduleId: scheduleId.toString() } }),
|
...getScheduleMirrorsOptions({ path: { scheduleId: scheduleId.toString() } }),
|
||||||
|
initialData,
|
||||||
});
|
});
|
||||||
|
|
||||||
const { data: compatibility } = useQuery({
|
const { data: compatibility } = useQuery({
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,12 @@ import {
|
||||||
} from "~/client/api-client/@tanstack/react-query.gen";
|
} from "~/client/api-client/@tanstack/react-query.gen";
|
||||||
import { parseError } from "~/client/lib/errors";
|
import { parseError } from "~/client/lib/errors";
|
||||||
import type { NotificationDestination } from "~/client/lib/types";
|
import type { NotificationDestination } from "~/client/lib/types";
|
||||||
|
import type { GetScheduleNotificationsResponse } from "~/client/api-client";
|
||||||
|
|
||||||
type Props = {
|
type Props = {
|
||||||
scheduleId: number;
|
scheduleId: number;
|
||||||
destinations: NotificationDestination[];
|
destinations: NotificationDestination[];
|
||||||
|
initialData: GetScheduleNotificationsResponse;
|
||||||
};
|
};
|
||||||
|
|
||||||
type NotificationAssignment = {
|
type NotificationAssignment = {
|
||||||
|
|
@ -28,13 +30,14 @@ type NotificationAssignment = {
|
||||||
notifyOnFailure: boolean;
|
notifyOnFailure: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const ScheduleNotificationsConfig = ({ scheduleId, destinations }: Props) => {
|
export const ScheduleNotificationsConfig = ({ scheduleId, destinations, initialData }: Props) => {
|
||||||
const [assignments, setAssignments] = useState<Map<number, NotificationAssignment>>(new Map());
|
const [assignments, setAssignments] = useState<Map<number, NotificationAssignment>>(new Map());
|
||||||
const [hasChanges, setHasChanges] = useState(false);
|
const [hasChanges, setHasChanges] = useState(false);
|
||||||
const [isAddingNew, setIsAddingNew] = useState(false);
|
const [isAddingNew, setIsAddingNew] = useState(false);
|
||||||
|
|
||||||
const { data: currentAssignments } = useQuery({
|
const { data: currentAssignments } = useQuery({
|
||||||
...getScheduleNotificationsOptions({ path: { scheduleId: scheduleId.toString() } }),
|
...getScheduleNotificationsOptions({ path: { scheduleId: scheduleId.toString() } }),
|
||||||
|
initialData,
|
||||||
});
|
});
|
||||||
|
|
||||||
const updateNotifications = useMutation({
|
const updateNotifications = useMutation({
|
||||||
|
|
|
||||||
|
|
@ -30,7 +30,13 @@ import { ScheduleSummary } from "../components/schedule-summary";
|
||||||
import type { Route } from "./+types/backup-details";
|
import type { Route } from "./+types/backup-details";
|
||||||
import { SnapshotFileBrowser } from "../components/snapshot-file-browser";
|
import { SnapshotFileBrowser } from "../components/snapshot-file-browser";
|
||||||
import { SnapshotTimeline } from "../components/snapshot-timeline";
|
import { SnapshotTimeline } from "../components/snapshot-timeline";
|
||||||
import { getBackupSchedule, listNotificationDestinations, listRepositories } from "~/client/api-client";
|
import {
|
||||||
|
getBackupSchedule,
|
||||||
|
getScheduleMirrors,
|
||||||
|
getScheduleNotifications,
|
||||||
|
listNotificationDestinations,
|
||||||
|
listRepositories,
|
||||||
|
} from "~/client/api-client";
|
||||||
import { ScheduleNotificationsConfig } from "../components/schedule-notifications-config";
|
import { ScheduleNotificationsConfig } from "../components/schedule-notifications-config";
|
||||||
import { ScheduleMirrorsConfig } from "../components/schedule-mirrors-config";
|
import { ScheduleMirrorsConfig } from "../components/schedule-mirrors-config";
|
||||||
import { cn } from "~/client/lib/utils";
|
import { cn } from "~/client/lib/utils";
|
||||||
|
|
@ -53,13 +59,23 @@ export function meta(_: Route.MetaArgs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const clientLoader = async ({ params }: Route.LoaderArgs) => {
|
export const clientLoader = async ({ params }: Route.LoaderArgs) => {
|
||||||
const schedule = await getBackupSchedule({ path: { scheduleId: params.id } });
|
const [schedule, notifs, repos, scheduleNotifs, mirrors] = await Promise.all([
|
||||||
const notifs = await listNotificationDestinations();
|
getBackupSchedule({ path: { scheduleId: params.id } }),
|
||||||
const repos = await listRepositories();
|
listNotificationDestinations(),
|
||||||
|
listRepositories(),
|
||||||
|
getScheduleNotifications({ path: { scheduleId: params.id } }),
|
||||||
|
getScheduleMirrors({ path: { scheduleId: params.id } }),
|
||||||
|
]);
|
||||||
|
|
||||||
if (!schedule.data) return redirect("/backups");
|
if (!schedule.data) return redirect("/backups");
|
||||||
|
|
||||||
return { schedule: schedule.data, notifs: notifs.data, repos: repos.data };
|
return {
|
||||||
|
schedule: schedule.data,
|
||||||
|
notifs: notifs.data,
|
||||||
|
repos: repos.data,
|
||||||
|
scheduleNotifs: scheduleNotifs.data,
|
||||||
|
scheduleMirrors: mirrors.data,
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export default function ScheduleDetailsPage({ params, loaderData }: Route.ComponentProps) {
|
export default function ScheduleDetailsPage({ params, loaderData }: Route.ComponentProps) {
|
||||||
|
|
@ -240,13 +256,18 @@ export default function ScheduleDetailsPage({ params, loaderData }: Route.Compon
|
||||||
schedule={schedule}
|
schedule={schedule}
|
||||||
/>
|
/>
|
||||||
<div className={cn({ hidden: !loaderData.notifs?.length })}>
|
<div className={cn({ hidden: !loaderData.notifs?.length })}>
|
||||||
<ScheduleNotificationsConfig scheduleId={schedule.id} destinations={loaderData.notifs ?? []} />
|
<ScheduleNotificationsConfig
|
||||||
|
scheduleId={schedule.id}
|
||||||
|
destinations={loaderData.notifs ?? []}
|
||||||
|
initialData={loaderData.scheduleNotifs ?? []}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className={cn({ hidden: !loaderData.repos?.length || loaderData.repos.length < 2 })}>
|
<div className={cn({ hidden: !loaderData.repos?.length || loaderData.repos.length < 2 })}>
|
||||||
<ScheduleMirrorsConfig
|
<ScheduleMirrorsConfig
|
||||||
scheduleId={schedule.id}
|
scheduleId={schedule.id}
|
||||||
primaryRepositoryId={schedule.repositoryId}
|
primaryRepositoryId={schedule.repositoryId}
|
||||||
repositories={loaderData.repos ?? []}
|
repositories={loaderData.repos ?? []}
|
||||||
|
initialData={loaderData.scheduleMirrors ?? []}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<SnapshotTimeline
|
<SnapshotTimeline
|
||||||
|
|
|
||||||
|
|
@ -33,8 +33,7 @@ export function meta(_: Route.MetaArgs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const clientLoader = async () => {
|
export const clientLoader = async () => {
|
||||||
const volumes = await listVolumes();
|
const [volumes, repositories] = await Promise.all([listVolumes(), listRepositories()]);
|
||||||
const repositories = await listRepositories();
|
|
||||||
|
|
||||||
if (volumes.data && repositories.data) return { volumes: volumes.data, repositories: repositories.data };
|
if (volumes.data && repositories.data) return { volumes: volumes.data, repositories: repositories.data };
|
||||||
return { volumes: [], repositories: [] };
|
return { volumes: [], repositories: [] };
|
||||||
|
|
|
||||||
|
|
@ -24,15 +24,20 @@ export function meta({ params }: Route.MetaArgs) {
|
||||||
|
|
||||||
export const clientLoader = async ({ params }: Route.ClientLoaderArgs) => {
|
export const clientLoader = async ({ params }: Route.ClientLoaderArgs) => {
|
||||||
const schedule = await getBackupSchedule({ path: { scheduleId: params.id } });
|
const schedule = await getBackupSchedule({ path: { scheduleId: params.id } });
|
||||||
|
|
||||||
if (!schedule.data) return redirect("/backups");
|
if (!schedule.data) return redirect("/backups");
|
||||||
|
|
||||||
const repositoryId = schedule.data.repository.id;
|
const [snapshot, repository] = await Promise.all([
|
||||||
const snapshot = await getSnapshotDetails({
|
getSnapshotDetails({
|
||||||
path: { id: repositoryId, snapshotId: params.snapshotId },
|
path: {
|
||||||
});
|
id: schedule.data.repositoryId,
|
||||||
if (!snapshot.data) return redirect(`/backups/${params.id}`);
|
snapshotId: params.snapshotId,
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
getRepository({ path: { id: schedule.data.repositoryId } }),
|
||||||
|
]);
|
||||||
|
|
||||||
const repository = await getRepository({ path: { id: repositoryId } });
|
if (!snapshot.data) return redirect(`/backups/${params.id}`);
|
||||||
if (!repository.data) return redirect(`/backups/${params.id}`);
|
if (!repository.data) return redirect(`/backups/${params.id}`);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
|
|
||||||
|
|
@ -23,12 +23,12 @@ export function meta({ params }: Route.MetaArgs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const clientLoader = async ({ params }: Route.ClientLoaderArgs) => {
|
export const clientLoader = async ({ params }: Route.ClientLoaderArgs) => {
|
||||||
const snapshot = await getSnapshotDetails({
|
const [snapshot, repository] = await Promise.all([
|
||||||
path: { id: params.id, snapshotId: params.snapshotId },
|
getSnapshotDetails({ path: { id: params.id, snapshotId: params.snapshotId } }),
|
||||||
});
|
getRepository({ path: { id: params.id } }),
|
||||||
if (!snapshot.data) return redirect("/repositories");
|
]);
|
||||||
|
|
||||||
const repository = await getRepository({ path: { id: params.id } });
|
if (!snapshot.data) return redirect("/repositories");
|
||||||
if (!repository.data) return redirect(`/repositories`);
|
if (!repository.data) return redirect(`/repositories`);
|
||||||
|
|
||||||
return { snapshot: snapshot.data, id: params.id, repository: repository.data, snapshotId: params.snapshotId };
|
return { snapshot: snapshot.data, id: params.id, repository: repository.data, snapshotId: params.snapshotId };
|
||||||
|
|
|
||||||
|
|
@ -26,11 +26,14 @@ export function meta({ params }: Route.MetaArgs) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export const clientLoader = async ({ params }: Route.ClientLoaderArgs) => {
|
export const clientLoader = async ({ params }: Route.ClientLoaderArgs) => {
|
||||||
const snapshot = getSnapshotDetails({
|
const [snapshot, repository] = await Promise.all([
|
||||||
path: { id: params.id, snapshotId: params.snapshotId },
|
getSnapshotDetails({
|
||||||
});
|
path: { id: params.id, snapshotId: params.snapshotId },
|
||||||
|
}),
|
||||||
|
getRepository({ path: { id: params.id } }),
|
||||||
|
]);
|
||||||
|
|
||||||
const repository = await getRepository({ path: { id: params.id } });
|
if (!snapshot.data) return redirect(`/repositories/${params.id}`);
|
||||||
if (!repository.data) return redirect("/repositories");
|
if (!repository.data) return redirect("/repositories");
|
||||||
|
|
||||||
return { snapshot: snapshot, repository: repository.data };
|
return { snapshot: snapshot, repository: repository.data };
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue