Skip to content

Commit c13450d

Browse files
fix HashRoute issues
Signed-off-by: Carlos Feria <2582866+carlosthe19916@users.noreply.github.com>
1 parent a7a9356 commit c13450d

13 files changed

Lines changed: 141 additions & 65 deletions

File tree

client/openapi/trustd.yaml

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2856,12 +2856,8 @@ paths:
28562856
operationId: generateSbomStaticReport
28572857
requestBody:
28582858
content:
2859-
application/x-www-form-urlencoded:
2860-
schema:
2861-
type: object
2862-
additionalProperties: {}
2863-
propertyNames:
2864-
type: string
2859+
application/json:
2860+
schema: {}
28652861
required: true
28662862
responses:
28672863
'200':

client/rsbuild.static-report.config.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,14 @@ export default defineConfig({
7979
from: brandingPath,
8080
to: "branding",
8181
},
82+
...(process.env.NODE_ENV === "development"
83+
? [
84+
{
85+
from: "src/static-report/data.js",
86+
to: ".",
87+
},
88+
]
89+
: []),
8290
],
8391
sourceMap: process.env.NODE_ENV === "development",
8492
},

client/src/app/Constants.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ export const isAuthRequired = ENV.AUTH_REQUIRED !== "false";
2929
export const isAuthServerEmbedded = ENV.OIDC_SERVER_IS_EMBEDDED === "true";
3030
export const uploadLimit = "500m";
3131

32+
export const isMockDisabled = ENV.MOCK === "off";
33+
3234
/**
3335
* The name of the client generated id field inserted in a object marked with mixin type
3436
* `WithUiId`.

client/src/app/api/rest.ts

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -86,16 +86,12 @@ export const downloadSbomLicense = (sbomId: string) => {
8686
};
8787

8888
export const generateStaticReport = (formData: FormData) => {
89-
return axios.post<Blob>(
90-
"/api/v2/ui/generate-sbom-static-report",
91-
formData,
92-
{
93-
responseType: "arraybuffer",
94-
headers: {
95-
"Content-Type": "multipart/form-data",
96-
Accept: "text/plain",
97-
responseType: "blob",
98-
},
89+
return axios.post<Blob>("/api/v2/ui/generate-sbom-static-report", formData, {
90+
responseType: "arraybuffer",
91+
headers: {
92+
"Content-Type": "multipart/form-data",
93+
Accept: "text/plain",
94+
responseType: "blob",
9995
},
100-
);
96+
});
10197
};

client/src/app/hooks/useUrlParams.ts

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import { isMockDisabled } from "@app/Constants";
12
import type { DisallowCharacters } from "@app/utils/type-utils";
23
import { objectKeys } from "@app/utils/utils";
34
import React from "react";
@@ -78,11 +79,42 @@ export const useUrlParams = <
7879
)
7980
: (serializedParams as TSerializedParams<TPrefixedURLParamKey>);
8081

82+
/**
83+
* Generates hash, pathname, and search valid for BrowserRoute as well as HashRoute
84+
*/
85+
const getLocation = ({
86+
hash,
87+
pathname,
88+
search,
89+
}: {
90+
hash: string;
91+
pathname: string;
92+
search: string;
93+
}) => {
94+
if (isMockDisabled) {
95+
return {
96+
pathname,
97+
search,
98+
};
99+
}
100+
101+
const array = hash.replace(/^#/, "").split("?");
102+
return {
103+
pathname: array[0],
104+
search: array[1] ?? "",
105+
};
106+
};
107+
81108
const setParams = (newParams: Partial<TDeserializedParams>) => {
82109
// In case setParams is called multiple times synchronously from the same rendered instance,
83110
// we use document.location here as the current params so these calls never overwrite each other.
84111
// This also retains any unrelated params that might be present and allows newParams to be a partial update.
85-
const { pathname, search } = document.location;
112+
const { search, pathname } = getLocation({
113+
hash: document.location.hash,
114+
pathname: document.location.pathname,
115+
search: document.location.search,
116+
});
117+
86118
const existingSearchParams = new URLSearchParams(search);
87119
// We prefix the params object here so the serialize function doesn't have to care about the keyPrefix.
88120
const newPrefixedSerializedParams = withPrefixes(serialize(newParams));
@@ -99,7 +131,13 @@ export const useUrlParams = <
99131
};
100132

101133
// We use useLocation here so we are re-rendering when the params change.
102-
const urlParams = new URLSearchParams(useLocation().search);
134+
const location = useLocation();
135+
const { search } = getLocation({
136+
hash: location.hash,
137+
pathname: location.pathname,
138+
search: location.search,
139+
});
140+
const urlParams = new URLSearchParams(search);
103141
// We un-prefix the params object here so the deserialize function doesn't have to care about the keyPrefix.
104142

105143
let allParamsEmpty = true;

client/src/app/pages/sbom-scan/sbom-scan.tsx

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,19 @@ import {
1818
EmptyStateFooter,
1919
EmptyStateVariant,
2020
MenuToggle,
21-
type MenuToggleElement,
2221
PageSection,
2322
Split,
2423
SplitItem,
2524
Stack,
2625
StackItem,
26+
type MenuToggleElement,
2727
} from "@patternfly/react-core";
2828

2929
import ExclamationCircleIcon from "@patternfly/react-icons/dist/esm/icons/exclamation-circle-icon";
3030
import InProgressIcon from "@patternfly/react-icons/dist/esm/icons/in-progress-icon";
3131

32-
import { generateSbomStaticReport, type ExtractResult } from "@app/client";
32+
import { generateStaticReport } from "@app/api/rest";
33+
import type { ExtractResult } from "@app/client";
3334
import { useUploadAndAnalyzeSBOM } from "@app/queries/sboms-analysis";
3435
import { Paths } from "@app/Routes";
3536

@@ -38,8 +39,6 @@ import { VulnerabilityMetrics } from "@static-report/pages/vulnerabilities/compo
3839
import { VulnerabilityTable } from "@static-report/pages/vulnerabilities/components/VulnerabilityTable";
3940

4041
import { UploadFileForAnalysis } from "./components/UploadFileForAnalysis";
41-
import { generateStaticReport } from "@app/api/rest";
42-
import { WINDOW_ANALYSIS_RESPONSE, WINDOW_PURLS } from "@app/Constants";
4342

4443
export const SbomScan: React.FC = () => {
4544
// Actions dropdown

client/src/app/queries/helpers.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import ENV from "@app/env";
1+
import { isMockDisabled } from "@app/Constants";
22
import { type UseQueryOptions, useQuery } from "@tanstack/react-query";
33

44
const defaultTimeout = 1000;
@@ -29,6 +29,6 @@ export const useMockableQuery = <
2929
) => {
3030
return useQuery<TQueryFnData, TError, TData>({
3131
...params,
32-
queryFn: ENV.MOCK === "off" ? params.queryFn : () => mockPromise(mockData),
32+
queryFn: isMockDisabled ? params.queryFn : () => mockPromise(mockData),
3333
});
3434
};

client/src/app/queries/vulnerabilities.ts

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,7 @@ import {
1111
getVulnerability,
1212
listVulnerabilities,
1313
} from "@app/client";
14-
import { WINDOW_ANALYSIS_RESPONSE } from "@app/Constants";
15-
import ENV from "@app/env";
14+
import { isMockDisabled, WINDOW_ANALYSIS_RESPONSE } from "@app/Constants";
1615
import { requestParamsQuery } from "@app/hooks/table-controls";
1716

1817
import { mockPromise } from "./helpers";
@@ -46,35 +45,34 @@ export const useFetchVulnerabilities = (
4645
};
4746

4847
export const useFetchVulnerabilitiesByPackageIds = (ids: string[]) => {
49-
const chunks =
50-
ENV.MOCK === "off"
51-
? {
52-
ids: ids.reduce<string[][]>((chunks, item, index) => {
53-
if (index % 100 === 0) {
54-
chunks.push([item]);
55-
} else {
56-
chunks[chunks.length - 1].push(item);
57-
}
58-
return chunks;
59-
}, []),
60-
dataResolver: async (ids: string[]) => {
61-
const response = await analyze({
62-
client,
63-
body: { purls: ids },
64-
});
65-
return response.data;
66-
},
67-
}
68-
: {
69-
ids: [ids],
70-
dataResolver: (_ids: string[]) => {
71-
return mockPromise(
72-
// biome-ignore lint/suspicious/noExplicitAny: allowed
73-
((window as any)[WINDOW_ANALYSIS_RESPONSE] as AnalysisResponse) ??
74-
{},
75-
);
76-
},
77-
};
48+
const chunks = isMockDisabled
49+
? {
50+
ids: ids.reduce<string[][]>((chunks, item, index) => {
51+
if (index % 100 === 0) {
52+
chunks.push([item]);
53+
} else {
54+
chunks[chunks.length - 1].push(item);
55+
}
56+
return chunks;
57+
}, []),
58+
dataResolver: async (ids: string[]) => {
59+
const response = await analyze({
60+
client,
61+
body: { purls: ids },
62+
});
63+
return response.data;
64+
},
65+
}
66+
: {
67+
ids: [ids],
68+
dataResolver: (_ids: string[]) => {
69+
return mockPromise(
70+
// biome-ignore lint/suspicious/noExplicitAny: allowed
71+
((window as any)[WINDOW_ANALYSIS_RESPONSE] as AnalysisResponse) ??
72+
{},
73+
);
74+
},
75+
};
7876

7977
const userQueries = useQueries({
8078
queries: chunks.ids.map((ids) => {

client/src/static-report/README.md

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
## Static report
2+
3+
Static Report is a user interface for the Scan SBOM. As the name suggests, it's completely static in nature, and does not talk to any external APIs.
4+
5+
## Developing / Contributing
6+
7+
### How it works?
8+
9+
As stated in the introduction, the interface is completely static in nature. All of the data displayed in the UI resides in `client/src/static-report/data.js` file. It is empty by default when you build the project. In order to display actual output of an analysis, `data.js` must contain data generated from an analysis.
10+
11+
The `data.js` should be populated by the output of `POST /api/v2/vulnerability/analyze`
12+
13+
### Running in developtment mode
14+
15+
At the **root** of the entire project.
16+
17+
- Install dependencies:
18+
19+
```shell
20+
npm ci
21+
```
22+
23+
- Run the project:
24+
25+
```shell
26+
npm run start:dev:static-report
27+
```
28+
29+
This will serve the report at http://localhost:3000 and will render the data that lives in `client/src/static-report/data.js`
30+
31+
### Running in production mode
32+
33+
- Build the project:
34+
35+
```shell
36+
npm run build
37+
```
38+
39+
This will generate a `client/dist/static-report` directory. It serves as a template; therefore, It doesn't contain the `data.js` file as it must be generated manually or by other tool like the backend.

client/src/static-report/data.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
// Populate it with POST /api/v2/vulnerability/analyze
2+
window.__analysisResponse = {};

0 commit comments

Comments
 (0)