Skip to content

Commit 4df2bd9

Browse files
committed
refactor(frontend): Restructure BaseImageCollection
- Refactor BaseImagesTable into a stateless, presentational component - Move Relay pagination, search, and filtering logic to BaseImageCollection page Signed-off-by: ArnelaL <arnela.lisic@secomind.com>
1 parent 2f37429 commit 4df2bd9

2 files changed

Lines changed: 198 additions & 157 deletions

File tree

frontend/src/components/BaseImagesTable.tsx

Lines changed: 54 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -1,65 +1,55 @@
1-
/*
2-
* This file is part of Edgehog.
3-
*
4-
* Copyright 2023-2025 SECO Mind Srl
5-
*
6-
* Licensed under the Apache License, Version 2.0 (the "License");
7-
* you may not use this file except in compliance with the License.
8-
* You may obtain a copy of the License at
9-
*
10-
* http://www.apache.org/licenses/LICENSE-2.0
11-
*
12-
* Unless required by applicable law or agreed to in writing, software
13-
* distributed under the License is distributed on an "AS IS" BASIS,
14-
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15-
* See the License for the specific language governing permissions and
16-
* limitations under the License.
17-
*
18-
* SPDX-License-Identifier: Apache-2.0
19-
*/
1+
// This file is part of Edgehog.
2+
//
3+
// Copyright 2023-2026 SECO Mind Srl
4+
//
5+
// Licensed under the Apache License, Version 2.0 (the "License");
6+
// you may not use this file except in compliance with the License.
7+
// You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing, software
12+
// distributed under the License is distributed on an "AS IS" BASIS,
13+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
// See the License for the specific language governing permissions and
15+
// limitations under the License.
16+
//
17+
// SPDX-License-Identifier: Apache-2.0
2018

21-
import { useCallback, useEffect, useMemo, useState } from "react";
22-
import { FormattedMessage } from "react-intl";
23-
import { graphql, usePaginationFragment } from "react-relay/hooks";
2419
import _ from "lodash";
20+
import { useMemo } from "react";
21+
import { FormattedMessage } from "react-intl";
22+
import { graphql, useFragment } from "react-relay/hooks";
2523

26-
import type { BaseImagesTable_PaginationQuery } from "@/api/__generated__/BaseImagesTable_PaginationQuery.graphql";
2724
import type {
28-
BaseImagesTable_BaseImagesFragment$data,
29-
BaseImagesTable_BaseImagesFragment$key,
30-
} from "@/api/__generated__/BaseImagesTable_BaseImagesFragment.graphql";
25+
BaseImagesTable_BaseImageEdgeFragment$data,
26+
BaseImagesTable_BaseImageEdgeFragment$key,
27+
} from "@/api/__generated__/BaseImagesTable_BaseImageEdgeFragment.graphql";
3128

32-
import { createColumnHelper } from "@/components/Table";
3329
import InfiniteTable from "@/components/InfiniteTable";
30+
import { createColumnHelper } from "@/components/Table";
3431
import { Link, Route } from "@/Navigation";
35-
import { RECORDS_TO_LOAD_FIRST, RECORDS_TO_LOAD_NEXT } from "@/constants";
3632

3733
// We use graphql fields below in columns configuration
3834
/* eslint-disable relay/unused-fields */
3935
const BASE_IMAGES_TABLE_FRAGMENT = graphql`
40-
fragment BaseImagesTable_BaseImagesFragment on BaseImageCollection
41-
@refetchable(queryName: "BaseImagesTable_PaginationQuery")
42-
@argumentDefinitions(filter: { type: "BaseImageFilterInput" }) {
43-
id
44-
baseImages(first: $first, after: $after, filter: $filter)
45-
@connection(key: "BaseImagesTable_baseImages") {
46-
edges {
47-
node {
48-
id
49-
version
50-
startingVersionRequirement
51-
localizedReleaseDisplayNames {
52-
value
53-
languageTag
54-
}
36+
fragment BaseImagesTable_BaseImageEdgeFragment on BaseImageConnection {
37+
edges {
38+
node {
39+
id
40+
version
41+
startingVersionRequirement
42+
localizedReleaseDisplayNames {
43+
value
44+
languageTag
5545
}
5646
}
5747
}
5848
}
5949
`;
6050

6151
type TableRecord = NonNullable<
62-
NonNullable<BaseImagesTable_BaseImagesFragment$data["baseImages"]>["edges"]
52+
NonNullable<BaseImagesTable_BaseImageEdgeFragment$data>["edges"]
6353
>[number]["node"];
6454

6555
const columnHelper = createColumnHelper<TableRecord>();
@@ -113,99 +103,40 @@ const getColumnsDefinition = (baseImageCollectionId: string) => [
113103

114104
type Props = {
115105
className?: string;
116-
baseImageCollectionRef: BaseImagesTable_BaseImagesFragment$key;
117-
hideSearch?: boolean;
106+
baseImagesRef: BaseImagesTable_BaseImageEdgeFragment$key;
107+
baseImageCollectionId: string;
108+
loading?: boolean;
109+
onLoadMore?: () => void;
118110
};
119111

120112
const BaseImagesTable = ({
121113
className,
122-
baseImageCollectionRef,
123-
hideSearch = false,
114+
baseImagesRef,
115+
baseImageCollectionId,
116+
loading = false,
117+
onLoadMore,
124118
}: Props) => {
125-
const {
126-
data: paginationData,
127-
loadNext,
128-
hasNext,
129-
isLoadingNext,
130-
refetch,
131-
} = usePaginationFragment<
132-
BaseImagesTable_PaginationQuery,
133-
BaseImagesTable_BaseImagesFragment$key
134-
>(BASE_IMAGES_TABLE_FRAGMENT, baseImageCollectionRef);
135-
136-
const [searchText, setSearchText] = useState<string | null>(null);
137-
138-
const columns = useMemo(
139-
() => getColumnsDefinition(paginationData.id),
140-
[paginationData.id],
119+
const baseImagesFragment = useFragment(
120+
BASE_IMAGES_TABLE_FRAGMENT,
121+
baseImagesRef || null,
141122
);
123+
const baseImages = useMemo<TableRecord[]>(() => {
124+
return _.compact(baseImagesFragment?.edges?.map((e) => e?.node)) ?? [];
125+
}, [baseImagesFragment]);
142126

143-
const debounceRefetch = useMemo(
144-
() =>
145-
_.debounce((text: string) => {
146-
if (text === "") {
147-
refetch(
148-
{
149-
first: RECORDS_TO_LOAD_FIRST,
150-
},
151-
{ fetchPolicy: "network-only" },
152-
);
153-
} else {
154-
refetch(
155-
{
156-
first: RECORDS_TO_LOAD_FIRST,
157-
filter: {
158-
or: [
159-
{ version: { ilike: `%${text}%` } },
160-
{ url: { ilike: `%${text}%` } },
161-
{
162-
startingVersionRequirement: {
163-
ilike: `%${text}%`,
164-
},
165-
},
166-
],
167-
},
168-
},
169-
{ fetchPolicy: "network-only" },
170-
);
171-
}
172-
}, 500),
173-
[refetch],
127+
const columns = useMemo(
128+
() => getColumnsDefinition(baseImageCollectionId),
129+
[baseImageCollectionId],
174130
);
175131

176-
useEffect(() => {
177-
if (searchText !== null) {
178-
debounceRefetch(searchText);
179-
}
180-
}, [debounceRefetch, searchText]);
181-
182-
const loadNextBaseImageCollections = useCallback(() => {
183-
if (hasNext && !isLoadingNext) {
184-
loadNext(RECORDS_TO_LOAD_NEXT);
185-
}
186-
}, [hasNext, isLoadingNext, loadNext]);
187-
188-
const baseImages = useMemo(() => {
189-
return (
190-
paginationData.baseImages?.edges
191-
?.map((edge) => edge?.node)
192-
.filter((node): node is TableRecord => node != null) ?? []
193-
);
194-
}, [paginationData]);
195-
196-
if (!paginationData.baseImages) {
197-
return null;
198-
}
199-
200132
return (
201133
<InfiniteTable
202134
className={className}
203135
columns={columns}
204136
data={baseImages}
205-
loading={isLoadingNext}
206-
onLoadMore={hasNext ? loadNextBaseImageCollections : undefined}
207-
setSearchText={setSearchText}
208-
hideSearch={hideSearch}
137+
loading={loading}
138+
onLoadMore={onLoadMore}
139+
hideSearch
209140
/>
210141
);
211142
};

0 commit comments

Comments
 (0)