Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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: 1 addition & 0 deletions frontend/src/hooks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export { useConfirmationDialog } from './useConfirmationDialog';
export { useHelpPanel } from './useHelpPanel';
export { usePermissionGuard } from './usePermissionGuard';
export { useInfiniteScroll } from './useInfiniteScroll';
export { useLocalStorageState } from './useLocalStorageState';

// cloudscape
export { useCollection } from '@cloudscape-design/collection-hooks';
115 changes: 68 additions & 47 deletions frontend/src/pages/Runs/List/hooks/useFilters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,10 @@ import { ToggleProps } from '@cloudscape-design/components';

import type { PropertyFilterProps } from 'components';

import { useProjectFilter } from 'hooks/useProjectFilter';
import { useLocalStorageState } from 'hooks';
import { EMPTY_QUERY, requestParamsToTokens, tokensToRequestParams, tokensToSearchParams } from 'libs/filters';
import { useGetUserListQuery } from 'services/user';

type Args = {
localStorePrefix: string;
};
import { useLazyGetProjectsQuery } from 'services/project';
import { useLazyGetUserListQuery } from 'services/user';

type RequestParamsKeys = keyof Pick<TRunsRequestParams, 'only_active' | 'project_name' | 'username'>;

Expand All @@ -19,56 +16,40 @@ const filterKeys: Record<string, RequestParamsKeys> = {
USER_NAME: 'username',
};

export const useFilters = ({ localStorePrefix }: Args) => {
export const useFilters = () => {
const [searchParams, setSearchParams] = useSearchParams();
const [onlyActive, setOnlyActive] = useState(() => searchParams.get('only_active') === 'true');
const { projectOptions } = useProjectFilter({ localStorePrefix });
const { data: usersData } = useGetUserListQuery({});
const [onlyActive, setOnlyActive] = useLocalStorageState('run-list-filter-only-active', true);
const [filteringOptions, setFilteringOptions] = useState<PropertyFilterProps.FilteringOption[]>([]);
const [filteringStatusType, setFilteringStatusType] = useState<PropertyFilterProps.StatusType | undefined>();
const [getProjects] = useLazyGetProjectsQuery();
const [getUsers] = useLazyGetUserListQuery();

const [propertyFilterQuery, setPropertyFilterQuery] = useState<PropertyFilterProps.Query>(() =>
requestParamsToTokens<RequestParamsKeys>({ searchParams, filterKeys }),
);

const clearFilter = () => {
setSearchParams({});
setOnlyActive(false);
setPropertyFilterQuery(EMPTY_QUERY);
};

const filteringOptions = useMemo(() => {
const options: PropertyFilterProps.FilteringOption[] = [];

projectOptions.forEach(({ value }) => {
if (value)
options.push({
propertyKey: filterKeys.PROJECT_NAME,
value,
});
});

usersData?.data?.forEach(({ username }) => {
options.push({
propertyKey: filterKeys.USER_NAME,
value: username,
});
});

return options;
}, [projectOptions, usersData]);

const filteringProperties = [
{
key: filterKeys.PROJECT_NAME,
operators: ['='],
propertyLabel: 'Project',
groupValuesLabel: 'Project values',
},
{
key: filterKeys.USER_NAME,
operators: ['='],
propertyLabel: 'User',
},
];
const filteringProperties = useMemo<PropertyFilterProps.FilteringProperty[]>(
() => [
{
key: filterKeys.PROJECT_NAME,
operators: ['='],
propertyLabel: 'Project',
groupValuesLabel: 'Project values',
},
{
key: filterKeys.USER_NAME,
operators: ['='],
propertyLabel: 'User',
groupValuesLabel: 'User values',
},
],
[],
);

const onChangePropertyFilter: PropertyFilterProps['onChange'] = ({ detail }) => {
const { tokens, operation } = detail;
Expand All @@ -87,8 +68,6 @@ export const useFilters = ({ localStorePrefix }: Args) => {

const onChangeOnlyActive: ToggleProps['onChange'] = ({ detail }) => {
setOnlyActive(detail.checked);

setSearchParams(tokensToSearchParams<RequestParamsKeys>(propertyFilterQuery.tokens, detail.checked));
};

const filteringRequestParams = useMemo(() => {
Expand All @@ -102,6 +81,46 @@ export const useFilters = ({ localStorePrefix }: Args) => {
} as Partial<TRunsRequestParams>;
}, [propertyFilterQuery, onlyActive]);

const handleLoadItems: PropertyFilterProps['onLoadItems'] = async ({
detail: { filteringProperty, filteringText, firstPage, ...other },
}) => {
console.log({ filteringProperty, filteringText, firstPage, other });

setFilteringOptions([]);

if (!filteringText.length) {
return Promise.resolve();
}

setFilteringStatusType('loading');

if (filteringProperty?.key === filterKeys.PROJECT_NAME) {
await getProjects({ name_pattern: filteringText })
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.

The UI should set some sensible limit in filters, e.g. 100 – the default server limit is large (2000) for backward compatibility.

.unwrap()
.then(({ data }) =>
data.map(({ project_name }) => ({
propertyKey: filterKeys.PROJECT_NAME,
value: project_name,
})),
)
.then(setFilteringOptions);
}

if (filteringProperty?.key === filterKeys.USER_NAME) {
await getUsers({ name_pattern: filteringText })
.unwrap()
.then(({ data }) =>
data.map(({ username }) => ({
propertyKey: filterKeys.USER_NAME,
value: username,
})),
)
.then(setFilteringOptions);
}

setFilteringStatusType(undefined);
};

return {
filteringRequestParams,
clearFilter,
Expand All @@ -111,5 +130,7 @@ export const useFilters = ({ localStorePrefix }: Args) => {
filteringProperties,
onlyActive,
onChangeOnlyActive,
filteringStatusType,
handleLoadItems,
} as const;
};
9 changes: 6 additions & 3 deletions frontend/src/pages/Runs/List/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -47,9 +47,9 @@ export const RunList: React.FC = () => {
filteringRequestParams,
onlyActive,
onChangeOnlyActive,
} = useFilters({
localStorePrefix: 'administration-run-list-page',
});
filteringStatusType,
handleLoadItems,
} = useFilters();

const projectHavingFleetMap = useCheckingForFleetsInProjects({});

Expand Down Expand Up @@ -188,9 +188,12 @@ export const RunList: React.FC = () => {
filteringAriaLabel: t('projects.run.filter_property_placeholder'),
filteringPlaceholder: t('projects.run.filter_property_placeholder'),
operationAndText: 'and',
enteredTextLabel: (value) => `Use: ${value}`,
}}
filteringOptions={filteringOptions}
filteringProperties={filteringProperties}
filteringStatusType={filteringStatusType}
onLoadItems={handleLoadItems}
/>
</div>

Expand Down