Skip to content

Commit 1f8b5db

Browse files
committed
Refactor loader functions to improve error handling and simplify response structure in package source tab
1 parent de2572f commit 1f8b5db

File tree

1 file changed

+60
-102
lines changed

1 file changed

+60
-102
lines changed

apps/cyberstorm-remix/app/p/tabs/Source/Source.tsx

Lines changed: 60 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -1,151 +1,105 @@
11
import { faClock, faDownload } from "@fortawesome/free-solid-svg-icons";
22
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
33
import {
4-
getPublicEnvVariables,
5-
getSessionTools,
6-
} from "cyberstorm/security/publicEnvVariables";
4+
NimbusAwaitErrorElement,
5+
NimbusDefaultRouteErrorBoundary,
6+
} from "cyberstorm/utils/errors/NimbusErrorBoundary";
7+
import { handleLoaderError } from "cyberstorm/utils/errors/handleLoaderError";
8+
import { createNotFoundMapping } from "cyberstorm/utils/errors/loaderMappings";
9+
import { throwUserFacingPayloadResponse } from "cyberstorm/utils/errors/userFacingErrorResponse";
10+
import { getLoaderTools } from "cyberstorm/utils/getLoaderTools";
711
import { Suspense } from "react";
8-
import { Await, type LoaderFunctionArgs, useOutletContext } from "react-router";
9-
import { useLoaderData } from "react-router";
12+
import {
13+
Await,
14+
type LoaderFunctionArgs,
15+
useLoaderData,
16+
useOutletContext,
17+
} from "react-router";
1018
import ago from "s-ago";
11-
import { type OutletContextShape } from "~/root";
19+
import { CodeBoxHTML } from "~/commonComponents/CodeBoxHTML/CodeBoxHTML";
20+
import type { OutletContextShape } from "~/root";
1221

1322
import {
14-
NewAlert as Alert,
1523
Heading,
24+
NewAlert,
1625
NewButton,
1726
NewIcon,
1827
SkeletonBox,
1928
TooltipWrapper,
2029
} from "@thunderstore/cyberstorm";
21-
import { DapperTs, getPackageSource } from "@thunderstore/dapper-ts";
22-
import { isApiError } from "@thunderstore/thunderstore-api";
2330

24-
import { CodeBoxHTML } from "../../../commonComponents/CodeBoxHTML/CodeBoxHTML";
2531
import "./Source.css";
2632

2733
type PackageListingOutletContext = OutletContextShape & {
2834
packageDownloadUrl?: string;
2935
};
3036

31-
type ResultType = {
32-
status: string | null;
33-
message?: string;
34-
source?:
35-
| Awaited<ReturnType<typeof getPackageSource>>
36-
| ReturnType<typeof getPackageSource>;
37-
};
38-
3937
export async function loader({ params }: LoaderFunctionArgs) {
4038
if (params.namespaceId && params.packageId) {
41-
const publicEnvVariables = getPublicEnvVariables(["VITE_API_URL"]);
42-
const dapper = new DapperTs(() => {
43-
return {
44-
apiHost: publicEnvVariables.VITE_API_URL,
45-
sessionId: undefined,
46-
};
47-
});
48-
let result: ResultType = {
49-
status: null,
50-
source: undefined,
51-
message: undefined,
52-
};
39+
const { dapper } = getLoaderTools();
5340
try {
5441
const source = await dapper.getPackageSource(
5542
params.namespaceId,
5643
params.packageId
5744
);
58-
result = {
59-
status: null,
60-
source: source,
61-
message: undefined,
45+
46+
return {
47+
source,
6248
};
6349
} catch (error) {
64-
if (isApiError(error)) {
65-
if (error.response.status > 400) {
66-
result = {
67-
status: "error",
68-
source: undefined,
69-
message: `Failed to load source: ${error.message}`,
70-
};
71-
} else {
72-
throw error;
73-
}
74-
} else {
75-
throw error;
76-
}
50+
handleLoaderError(error, {
51+
mappings: [
52+
createNotFoundMapping(
53+
"Source not available.",
54+
"We could not find the requested package source."
55+
),
56+
],
57+
});
7758
}
78-
return result;
7959
}
80-
return {
81-
status: "error",
82-
message: "Failed to load source",
83-
source: undefined,
84-
};
60+
throwUserFacingPayloadResponse({
61+
headline: "Source not available.",
62+
description: "We could not find the requested package source.",
63+
category: "not_found",
64+
status: 404,
65+
});
8566
}
8667

87-
export async function clientLoader({ params }: LoaderFunctionArgs) {
68+
export function clientLoader({ params }: LoaderFunctionArgs) {
8869
if (params.namespaceId && params.packageId) {
89-
const tools = getSessionTools();
90-
const dapper = new DapperTs(() => {
91-
return {
92-
apiHost: tools.getConfig().apiHost,
93-
sessionId: tools.getConfig().sessionId,
94-
};
95-
});
96-
let result: ResultType = {
97-
status: null,
98-
source: undefined,
99-
message: undefined,
70+
const { dapper } = getLoaderTools();
71+
const source = dapper.getPackageSource(
72+
params.namespaceId,
73+
params.packageId
74+
);
75+
76+
return {
77+
source,
10078
};
101-
try {
102-
const source = dapper.getPackageSource(
103-
params.namespaceId,
104-
params.packageId
105-
);
106-
result = {
107-
status: null,
108-
source: source,
109-
message: undefined,
110-
};
111-
} catch (error) {
112-
result = {
113-
status: "error",
114-
source: undefined,
115-
message: "Failed to load source",
116-
};
117-
throw error;
118-
}
119-
return result;
12079
}
121-
return {
122-
status: "error",
123-
message: "Failed to load source",
124-
source: undefined,
125-
};
80+
throwUserFacingPayloadResponse({
81+
headline: "Source not available.",
82+
description: "We could not find the requested package source.",
83+
category: "not_found",
84+
status: 404,
85+
});
12686
}
12787

12888
export default function Source() {
129-
const { status, message, source } = useLoaderData<
130-
typeof loader | typeof clientLoader
131-
>();
89+
const { source } = useLoaderData<typeof loader | typeof clientLoader>();
13290
const outletContext = useOutletContext() as PackageListingOutletContext;
13391

134-
if (status === "error") {
135-
return <div>{message}</div>;
136-
}
13792
return (
13893
<Suspense fallback={<SkeletonBox className="package-source__skeleton" />}>
139-
<Await
140-
resolve={source}
141-
errorElement={<div>Error occurred while loading source</div>}
142-
>
94+
<Await resolve={source} errorElement={<NimbusAwaitErrorElement />}>
14395
{(resolvedValue) => {
14496
const decompilations = resolvedValue?.decompilations ?? [];
14597
const lastDecompilationDate = resolvedValue?.last_decompilation_date;
14698
if (decompilations.length === 0) {
14799
return (
148-
<Alert csVariant="info">Decompiled source not available.</Alert>
100+
<NewAlert csVariant="info">
101+
Decompiled source not available.
102+
</NewAlert>
149103
);
150104
}
151105
return decompilations.map((decompilation) => {
@@ -171,10 +125,10 @@ export default function Source() {
171125
/>
172126
</div>
173127
{decompilation.is_truncated && (
174-
<Alert csVariant="warning">
128+
<NewAlert csVariant="warning">
175129
The result has been truncated due to the large size,
176130
download it to view the full contents!
177-
</Alert>
131+
</NewAlert>
178132
)}
179133
<div
180134
className="package-source__decompilations-file"
@@ -191,6 +145,10 @@ export default function Source() {
191145
);
192146
}
193147

148+
export function ErrorBoundary() {
149+
return <NimbusDefaultRouteErrorBoundary />;
150+
}
151+
194152
const DecompilationDateDisplay = (props: {
195153
lastDecompilationDate: string | null | undefined;
196154
}) => {

0 commit comments

Comments
 (0)