Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion apps/ocp-plugin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,6 @@
"@patternfly/react-table": "^6.4.0",
"@types/react-redux": "^7.1.33",
"formik": "^2.4.9",
"fuzzysearch": "^1.0.3",
"i18next": "^21.8.14",
"js-yaml": "^4.1.1",
"monaco-editor": "^0.51.0",
Expand Down
1 change: 0 additions & 1 deletion apps/standalone/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,6 @@
"@patternfly/react-styles": "^6.4.0",
"@patternfly/react-table": "^6.4.0",
"formik": "^2.4.5",
"fuzzysearch": "^1.0.3",
"i18next": "^21.8.14",
"i18next-browser-languagedetector": "^7.2.1",
"i18next-http-backend": "^2.5.0",
Expand Down
1 change: 0 additions & 1 deletion libs/ui-components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@
"@xterm/xterm": "^5.5.0",
"file-saver": "^2.0.2",
"formik": "^2.4.5",
"fuzzysearch": "^1.0.3",
"js-yaml": "^4.1.1",
"percent-round": "^2.3.1",
"react-markdown": "^8.0.7",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ const CreateRepository = () => {
const navigate = useNavigate();

React.useEffect(() => {
const fetchResources = async () => {
const fetchResources = async (id: string) => {
setIsLoading(true);
try {
const results = await Promise.allSettled([
get<Repository>(`repositories/${repositoryId}`),
get<ResourceSyncList>(commonQueries.getResourceSyncsByRepo(repositoryId as string)),
get<Repository>(`repositories/${id}`),
get<ResourceSyncList>(commonQueries.getResourceSyncsByRepo({ repositoryId: id })),
]);

if (isPromiseFulfilled(results[0])) {
Expand All @@ -66,16 +66,16 @@ const CreateRepository = () => {
}
};
if (repositoryId) {
void fetchResources();
void fetchResources(repositoryId);
}
}, [get, repositoryId]);

const reloadResourceSyncs = React.useCallback(() => {
const reload = async () => {
const reload = async (id: string) => {
try {
setIsLoading(true);

const rsList = await get<ResourceSyncList>(commonQueries.getResourceSyncsByRepo(repositoryId as string));
const rsList = await get<ResourceSyncList>(commonQueries.getResourceSyncsByRepo({ repositoryId: id }));
setResourceSyncs(rsList.items);
setRsError(undefined);
} catch (e) {
Expand All @@ -84,7 +84,9 @@ const CreateRepository = () => {
setIsLoading(false);
}
};
void reload();
if (repositoryId) {
void reload(repositoryId);
}
}, [get, repositoryId]);

let content: React.ReactNode;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ const DeleteRepositoryModal = ({ repositoryId, onClose, onDeleteSuccess }: Delet

const loadRS = React.useCallback(async () => {
try {
const resourceSyncs = await get<ResourceSyncList>(commonQueries.getResourceSyncsByRepo(repositoryId));
const resourceSyncs = await get<ResourceSyncList>(commonQueries.getResourceSyncsByRepo({ repositoryId }));
setResourceSyncIds(resourceSyncs.items.map((rs) => rs.metadata.name || ''));
setRsError(undefined);
} catch (e) {
Expand Down
21 changes: 9 additions & 12 deletions libs/ui-components/src/components/Repository/RepositoryList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import { Repository } from '@flightctl/types';
import ListPageBody from '../ListPage/ListPageBody';
import ListPage from '../ListPage/ListPage';
import { getLastTransitionTimeText } from '../../utils/status/repository';
import { useTableTextSearch } from '../../hooks/useTableTextSearch';
import DeleteRepositoryModal from './RepositoryDetails/DeleteRepositoryModal';
import TableTextSearch from '../Table/TableTextSearch';
import Table, { TableColumn } from '../Table/Table';
Expand Down Expand Up @@ -86,8 +85,6 @@ const getColumns = (t: TFunction): TableColumn<Repository>[] => [
},
];

const getSearchText = (repo: Repository) => [repo.metadata.name];

const RepositoryTableRow = ({
repository,
canDelete,
Expand Down Expand Up @@ -160,7 +157,8 @@ const repositoryTablePermissions = [
];
const RepositoryTable = () => {
const { t } = useTranslation();
const [repositories, loading, error, isUpdating, refetch, pagination] = useRepositories();
const [nameSearch, setNameSearch] = React.useState('');
const [repositories, loading, error, isUpdating, refetch, pagination] = useRepositories(nameSearch);
const [deleteModalRepoId, setDeleteModalRepoId] = React.useState<string>();
const [isMassDeleteModalOpen, setIsMassDeleteModalOpen] = React.useState(false);

Expand All @@ -169,7 +167,6 @@ const RepositoryTable = () => {
refetch();
};

const { search, setSearch, filteredData } = useTableTextSearch(repositories, getSearchText);
const columns = React.useMemo(() => getColumns(t), [t]);

const { hasSelectedRows, isAllSelected, isRowSelected, setAllSelected, onRowSelect } = useTableSelect<Repository>();
Expand All @@ -183,7 +180,7 @@ const RepositoryTable = () => {
<ToolbarContent>
<ToolbarGroup>
<ToolbarItem>
<TableTextSearch value={search} setValue={setSearch} />
<TableTextSearch value={nameSearch} setValue={setNameSearch} placeholder={t('Search by name')} />
</ToolbarItem>
</ToolbarGroup>
<ToolbarItem>
Expand All @@ -207,15 +204,15 @@ const RepositoryTable = () => {
data-testid="repositories-table"
aria-label={t('Repositories table')}
loading={isUpdating}
hasFilters={!!search}
emptyData={filteredData.length === 0}
clearFilters={() => setSearch('')}
hasFilters={!!nameSearch}
emptyData={repositories.length === 0}
clearFilters={() => setNameSearch('')}
isAllSelected={isAllSelected}
onSelectAll={setAllSelected}
columns={columns}
>
<Tbody>
{filteredData.map((repository, rowIndex) => (
{repositories.map((repository, rowIndex) => (
<RepositoryTableRow
key={repository.metadata.name}
repository={repository}
Expand All @@ -231,7 +228,7 @@ const RepositoryTable = () => {
</Table>
<TablePagination isUpdating={isUpdating} pagination={pagination} />

{repositories.length === 0 && <RepositoryEmptyState />}
{!isUpdating && repositories.length === 0 && !nameSearch && <RepositoryEmptyState />}
{!!deleteModalRepoId && (
<DeleteRepositoryModal
onClose={() => setDeleteModalRepoId(undefined)}
Expand All @@ -247,7 +244,7 @@ const RepositoryTable = () => {
setAllSelected(false);
refetch();
}}
repositories={filteredData.filter(isRowSelected)}
repositories={repositories.filter(isRowSelected)}
/>
)}
</ListPageBody>
Expand Down
21 changes: 18 additions & 3 deletions libs/ui-components/src/components/Repository/useRepositories.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,18 @@ import { PaginationDetails, useTablePagination } from '../../hooks/useTablePagin
import { PAGE_SIZE } from '../../constants';

type RepositoriesEndpointArgs = {
name?: string;
nextContinue?: string;
};

const getRepositoriesEndpoint = ({ nextContinue }: RepositoriesEndpointArgs) => {
const getRepositoriesEndpoint = ({ name, nextContinue }: RepositoriesEndpointArgs) => {
const params = new URLSearchParams();
if (nextContinue !== undefined) {
params.set('limit', `${PAGE_SIZE}`);
}
if (name) {
params.set('fieldSelector', `metadata.name contains ${name}`);
}
if (nextContinue) {
params.set('continue', nextContinue);
}
Expand All @@ -29,7 +33,9 @@ export const useRepositoriesEndpoint = (args: RepositoriesEndpointArgs): [string
return [repositoriesEndpointDebounced, endpoint !== repositoriesEndpointDebounced];
};

export const useRepositories = (): [
export const useRepositories = (
name: string | undefined,
): [
Repository[],
boolean,
unknown,
Expand All @@ -38,7 +44,16 @@ export const useRepositories = (): [
Pick<PaginationDetails<RepositoryList>, 'currentPage' | 'setCurrentPage' | 'itemCount'>,
] => {
const { currentPage, setCurrentPage, itemCount, nextContinue, onPageFetched } = useTablePagination<RepositoryList>();
const [repoEndpoint, isDebouncing] = useRepositoriesEndpoint({ nextContinue });

const prevNameRef = React.useRef(name);
React.useEffect(() => {
if (prevNameRef.current !== name) {
prevNameRef.current = name;
setCurrentPage(1);
}
}, [name, setCurrentPage]);
Comment on lines +48 to +54
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why are you using name Ref ? Would this be sufficient ?

Suggested change
const prevNameRef = React.useRef(name);
React.useEffect(() => {
if (prevNameRef.current !== name) {
prevNameRef.current = name;
setCurrentPage(1);
}
}, [name, setCurrentPage]);
React.useEffect(() => {
setCurrentPage(1);
}, [name, setCurrentPage]);

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only difference is that with the ref we avoid a re-render in the first mount.
I can remove it, since it's not very clear in any case.


const [repoEndpoint, isDebouncing] = useRepositoriesEndpoint({ name, nextContinue });

const [repoList, isLoading, error, refetch] = useFetchPeriodically<RepositoryList>(
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@ import { ResourceSync, ResourceSyncList, ResourceSyncType } from '@flightctl/typ
import { getObservedHash } from '../../utils/status/repository';
import { useDeleteListAction } from '../ListPage/ListPageActions';
import Table, { TableColumn } from '../Table/Table';
import { useTableTextSearch } from '../../hooks/useTableTextSearch';
import TableTextSearch from '../Table/TableTextSearch';
import { useTableSelect } from '../../hooks/useTableSelect';

Expand Down Expand Up @@ -79,8 +78,6 @@ const getColumns = (t: TFunction): TableColumn<ResourceSync>[] => [
},
];

const getSearchText = (resourceSync: ResourceSync) => [resourceSync.metadata.name];

const ResourceSyncEmptyState = ({ addResourceSync }: { addResourceSync?: VoidFunction }) => {
const { t } = useTranslation();
return (
Expand Down Expand Up @@ -177,16 +174,15 @@ const repositoryResourceSyncListPermissions = [
];

const RepositoryResourceSyncList = ({ repositoryId }: { repositoryId: string }) => {
const [nameSearch, setNameSearch] = React.useState('');
const [rsList, isLoading, error, refetch] = useFetchPeriodically<ResourceSyncList>({
endpoint: commonQueries.getResourceSyncsByRepo(repositoryId),
endpoint: commonQueries.getResourceSyncsByRepo({ repositoryId, rsName: nameSearch }),
});

const resourceSyncs = rsList?.items || [];

const { t } = useTranslation();
const { remove } = useFetch();
const { filteredData, search, setSearch } = useTableTextSearch(resourceSyncs, getSearchText);

const columns = React.useMemo(() => getColumns(t), [t]);

const { onRowSelect, hasSelectedRows, isAllSelected, isRowSelected, setAllSelected } = useTableSelect();
Expand All @@ -210,7 +206,7 @@ const RepositoryResourceSyncList = ({ repositoryId }: { repositoryId: string })
<ToolbarContent>
<ToolbarGroup>
<ToolbarItem>
<TableTextSearch value={search} setValue={setSearch} placeholder={t('Search by name')} />
<TableTextSearch value={nameSearch} setValue={setNameSearch} placeholder={t('Search by name')} />
</ToolbarItem>
</ToolbarGroup>
{canDelete && (
Expand Down Expand Up @@ -242,12 +238,12 @@ const RepositoryResourceSyncList = ({ repositoryId }: { repositoryId: string })
isAllSelected={isAllSelected}
onSelectAll={setAllSelected}
columns={columns}
hasFilters={!!search}
emptyData={filteredData.length === 0}
clearFilters={() => setSearch('')}
hasFilters={!!nameSearch}
emptyData={resourceSyncs.length === 0}
clearFilters={() => setNameSearch('')}
>
<Tbody>
{filteredData.map((resourceSync, rowIndex) => {
{resourceSyncs.map((resourceSync, rowIndex) => {
const rsName = resourceSync.metadata.name as string;
const isSelected = isRowSelected(resourceSync);
return (
Expand Down Expand Up @@ -277,7 +273,7 @@ const RepositoryResourceSyncList = ({ repositoryId }: { repositoryId: string })
})}
</Tbody>
</Table>
{resourceSyncs.length === 0 && (
{!isLoading && resourceSyncs.length === 0 && !nameSearch && (
<ResourceSyncEmptyState
addResourceSync={
canCreate
Expand All @@ -292,7 +288,7 @@ const RepositoryResourceSyncList = ({ repositoryId }: { repositoryId: string })
{isMassDeleteModalOpen && (
<MassDeleteResourceSyncModal
onClose={() => setIsMassDeleteModalOpen(false)}
resources={filteredData.filter(isRowSelected)}
resources={resourceSyncs.filter(isRowSelected)}
onDeleteSuccess={() => {
setIsMassDeleteModalOpen(false);
setAllSelected(false);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ const MassDeleteRepositoryModal: React.FC<MassDeleteRepositoryModalProps> = ({
const promises = repositories.map(async (r) => {
const repositoryId = r.metadata.name || '';
const resourceSyncs = await get<ResourceSyncList>(
commonQueries.getResourceSyncsByRepo(repositoryId, { limit: 1 }),
commonQueries.getResourceSyncsByRepo({ repositoryId, options: { limit: 1 } }),
);
rsCount[repositoryId] = getApiListCount(resourceSyncs);
});
Expand All @@ -68,7 +68,7 @@ const MassDeleteRepositoryModal: React.FC<MassDeleteRepositoryModalProps> = ({
setProgress(0);
const promises = repositories.map(async (r) => {
const repositoryId = r.metadata.name || '';
const resourceSyncs = await get<ResourceSyncList>(commonQueries.getResourceSyncsByRepo(repositoryId));
const resourceSyncs = await get<ResourceSyncList>(commonQueries.getResourceSyncsByRepo({ repositoryId }));
const rsyncPromises = resourceSyncs.items.map((rsync) => remove(`resourcesyncs/${rsync.metadata.name}`));
const rsyncResults = await Promise.allSettled(rsyncPromises);
const rejectedResults = rsyncResults.filter(isPromiseRejected);
Expand Down
23 changes: 0 additions & 23 deletions libs/ui-components/src/hooks/useTableTextSearch.ts

This file was deleted.

18 changes: 15 additions & 3 deletions libs/ui-components/src/utils/query.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,22 @@ export const commonQueries = {
}
return `fleets?${searchParams.toString()}`;
},
getResourceSyncsByRepo: (repositoryId: string, options?: CommonQueryOptions) => {
const searchParams = new URLSearchParams();
searchParams.set('fieldSelector', `spec.repository=${repositoryId}`);
getResourceSyncsByRepo: ({
repositoryId,
rsName,
options,
}: {
repositoryId: string;
rsName?: string;
options?: CommonQueryOptions;
}) => {
const selectors: string[] = [`spec.repository=${repositoryId}`];
if (rsName) {
selectors.push(`metadata.name contains ${rsName}`);
}

const searchParams = new URLSearchParams();
searchParams.set('fieldSelector', selectors.join(','));
if (options?.limit) {
searchParams.set('limit', `${options.limit}`);
}
Expand Down
9 changes: 0 additions & 9 deletions libs/ui-components/src/utils/search.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,8 @@
import fuzzy from 'fuzzysearch';
import { ApiVersion } from '@flightctl/types';

// Must be an even number for "getSearchResultsCount" to work
export const MAX_TOTAL_SEARCH_RESULTS = 10;

export const fuzzySeach = (filter: string | undefined, value?: string): boolean => {
if (!filter) {
return true;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
return fuzzy(filter.toLowerCase(), value ? value.toLowerCase() : value) as boolean;
};

export const getSearchResultsCount = (labelCount: number, fleetCount: number) => {
if (labelCount + fleetCount <= MAX_TOTAL_SEARCH_RESULTS) {
return [labelCount, fleetCount];
Expand Down
Loading
Loading