Skip to content

Commit d18a5ae

Browse files
committed
Refactor view API to use shared fetch helper and add URL encoding
1 parent 6afa16e commit d18a5ae

File tree

4 files changed

+34
-53
lines changed

4 files changed

+34
-53
lines changed

src/api/services/views.ts

Lines changed: 21 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -69,16 +69,16 @@ export const getAllViews = (
6969
/**
7070
* Get the data for a view by its id.
7171
*/
72-
export const getViewDataById = async (
73-
viewId: string,
72+
const fetchViewData = async (
73+
path: string,
7474
variables?: Record<string, string>,
7575
headers?: Record<string, string>
7676
): Promise<ViewResult> => {
7777
const body: { variables?: Record<string, string> } = {
78-
variables: variables
78+
variables
7979
};
8080

81-
const response = await fetch(`/api/view/${viewId}`, {
81+
const response = await fetch(path, {
8282
method: "POST",
8383
credentials: "include",
8484
headers: {
@@ -98,34 +98,29 @@ export const getViewDataById = async (
9898
return response.json();
9999
};
100100

101+
export const getViewDataById = async (
102+
viewId: string,
103+
variables?: Record<string, string>,
104+
headers?: Record<string, string>
105+
): Promise<ViewResult> => {
106+
return fetchViewData(
107+
`/api/view/${encodeURIComponent(viewId)}`,
108+
variables,
109+
headers
110+
);
111+
};
112+
101113
export const getViewDataByNamespace = async (
102114
namespace: string,
103115
name: string,
104116
variables?: Record<string, string>,
105117
headers?: Record<string, string>
106118
): Promise<ViewResult> => {
107-
const body: { variables?: Record<string, string> } = {
108-
variables: variables
109-
};
110-
111-
const response = await fetch(`/api/view/${namespace}/${name}`, {
112-
method: "POST",
113-
credentials: "include",
114-
headers: {
115-
"Content-Type": "application/json",
116-
...headers
117-
},
118-
body: JSON.stringify(body)
119-
});
120-
121-
if (!response.ok) {
122-
const errorData = await response.json();
123-
throw new Error(
124-
errorData.error || `HTTP ${response.status}: ${response.statusText}`
125-
);
126-
}
127-
128-
return response.json();
119+
return fetchViewData(
120+
`/api/view/${encodeURIComponent(namespace)}/${encodeURIComponent(name)}`,
121+
variables,
122+
headers
123+
);
129124
};
130125

131126
/**

src/pages/views/components/SingleView.tsx

Lines changed: 10 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import { useAggregatedViewVariables } from "../hooks/useAggregatedViewVariables"
99
import GlobalFiltersForm from "../../audit-report/components/View/GlobalFiltersForm";
1010
import GlobalFilters from "../../audit-report/components/View/GlobalFilters";
1111
import { VIEW_VAR_PREFIX } from "../constants";
12+
import type { ViewRef } from "../../audit-report/types";
1213

1314
interface SingleViewProps {
1415
id: string;
@@ -41,13 +42,11 @@ const SingleView: React.FC<SingleViewProps> = ({ id }) => {
4142

4243
// Collect all section refs (main view + additional sections)
4344
// Must be called before early returns to satisfy React hooks rules
44-
const allSectionRefs = useMemo(() => {
45+
const allSectionRefs = useMemo<ViewRef[]>(() => {
4546
if (!viewResult?.namespace || !viewResult?.name) {
4647
return [];
4748
}
48-
const refs = [
49-
{ namespace: viewResult.namespace || "", name: viewResult.name }
50-
];
49+
const refs = [{ namespace: viewResult.namespace, name: viewResult.name }];
5150
if (viewResult?.sections) {
5251
viewResult.sections.forEach((section) => {
5352
refs.push({
@@ -91,27 +90,17 @@ const SingleView: React.FC<SingleViewProps> = ({ id }) => {
9190
await queryClient.invalidateQueries({ queryKey: ["view-result", id] });
9291

9392
await Promise.all(
94-
sectionsToRefresh.map((section) =>
93+
sectionsToRefresh.flatMap((section) => [
9594
queryClient.invalidateQueries({
9695
queryKey: ["view-result", section.namespace, section.name]
97-
})
98-
)
99-
);
100-
101-
await Promise.all(
102-
sectionsToRefresh.map((section) =>
96+
}),
10397
queryClient.invalidateQueries({
10498
queryKey: ["view-table", section.namespace, section.name]
105-
})
106-
)
107-
);
108-
109-
await Promise.all(
110-
sectionsToRefresh.map((section) =>
99+
}),
111100
queryClient.invalidateQueries({
112101
queryKey: ["view-variables", section.namespace, section.name]
113102
})
114-
)
103+
])
115104
);
116105
};
117106

@@ -171,12 +160,12 @@ const SingleView: React.FC<SingleViewProps> = ({ id }) => {
171160

172161
const { icon, title, namespace, name } = viewResult;
173162

174-
// Render the main view as a section as well.
175-
// Doing this due to some CSS issues that I couldn't solve.
163+
// Render the main view through ViewSection to reuse its spacing/scroll styling;
164+
// rendering the raw View here caused padding/overflow glitches alongside sections.
176165
const mySection = {
177166
title: "",
178167
viewRef: {
179-
namespace: namespace || "",
168+
namespace: namespace!,
180169
name: name
181170
}
182171
};

src/pages/views/hooks/useAggregatedViewVariables.ts

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@ import { getViewDataByNamespace } from "../../../api/services/views";
44
import { aggregateVariables } from "../utils/aggregateVariables";
55
import { usePrefixedSearchParams } from "../../../hooks/usePrefixedSearchParams";
66
import { VIEW_VAR_PREFIX } from "../constants";
7-
8-
interface ViewRef {
9-
namespace: string;
10-
name: string;
11-
}
7+
import type { ViewRef } from "../../audit-report/types";
128

139
export function useAggregatedViewVariables(sections: ViewRef[]) {
1410
const [viewVarParams] = usePrefixedSearchParams(VIEW_VAR_PREFIX, false);

src/pages/views/utils/aggregateVariables.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,8 @@ import { ViewVariable } from "../../audit-report/types";
22

33
/**
44
* Aggregates variables from multiple views, deduplicating by key.
5-
* When same key appears multiple times, merges options arrays (union).
5+
* When same key appears multiple times, merges options arrays (union) and keeps
6+
* the first definition for other fields to avoid silently overriding labels or defaults.
67
*/
78
export function aggregateVariables(
89
variableArrays: (ViewVariable[] | undefined)[]

0 commit comments

Comments
 (0)