Skip to content
This repository has been archived by the owner on Jul 12, 2022. It is now read-only.

Commit

Permalink
Merge pull request #864 from ZupIT/feature/modules-pagination
Browse files Browse the repository at this point in the history
Add pagination to Modules menu
  • Loading branch information
monicaribeirozup committed Feb 11, 2021
2 parents 67771ca + a8314d7 commit f62ae97
Show file tree
Hide file tree
Showing 14 changed files with 184 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ class V2ModuleController(
fun findAllModules(
@RequestHeader("x-workspace-id") workspaceId: String,
@RequestParam("name", required = false) name: String?,
pageRequest: PageRequest
@Valid pageRequest: PageRequest
): ResourcePageResponse<ModuleResponse> {
return this.findAllModulesInteractor.execute(workspaceId, name, pageRequest)
}
Expand Down
25 changes: 20 additions & 5 deletions ui/src/core/providers/modules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@ import { DEFAULT_PAGE_SIZE } from 'core/constants/request';
import { buildParams, URLParams } from 'core/utils/query';
import { baseRequest, postRequest } from './base';

const endpoint = '/moove/v2/modules';

export interface Component {
name: string;
errorThreshold: number;
Expand All @@ -31,13 +33,26 @@ export interface ModuleSave {
components: Component[];
}

const endpoint = '/moove/v2/modules';
const initialModulesFilter: ModulesFilter = {
name: '',
page: 0
};

export const findAll = (name: string) => {
const page = `page=0&size=${DEFAULT_PAGE_SIZE}`;
const qs = name ? `${page}&name=${name}` : page;
return baseRequest(`${endpoint}?${qs}`);
export interface ModulesFilter {
name?: string;
page?: number;
}

export const findAll = (filter: ModulesFilter = initialModulesFilter) => {
const params = new URLSearchParams({
size: `${DEFAULT_PAGE_SIZE}`,
name: filter?.name || '',
page: `${filter.page ?? 0}`
});

return baseRequest(`${endpoint}?${params}`);
};

export const findById = (id: string) => baseRequest(`${endpoint}/${id}`);

export const create = (module: ModuleSave) =>
Expand Down
2 changes: 2 additions & 0 deletions ui/src/modules/Modules/Comparation/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,15 @@

import styled from 'styled-components';
import Page from 'core/components/Page';
import { slideInLeft } from 'core/assets/style/animate';

const ScrollX = styled(Page.Content)`
overflow-y: hidden;
overflow-x: auto;
`;

const Wrapper = styled.div`
animation: 0.2s ${slideInLeft} linear;
display: flex;
flex-direction: row;
`;
Expand Down
6 changes: 3 additions & 3 deletions ui/src/modules/Modules/Menu/Loaders/list.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,8 @@ export const Loader: FunctionComponent = () => (
backgroundColor="#3a393c"
foregroundColor="#2c2b2e"
>
<rect x="0" y="0" rx="4" ry="4" width="260" height="15" />
<rect x="0" y="35" rx="4" ry="4" width="260" height="15" />
<rect x="0" y="70" rx="4" ry="4" width="260" height="15" />
<rect x="16" y="0" rx="4" ry="4" width="260" height="15" />
<rect x="16" y="35" rx="4" ry="4" width="260" height="15" />
<rect x="16" y="70" rx="4" ry="4" width="260" height="15" />
</ContentLoader>
);
38 changes: 26 additions & 12 deletions ui/src/modules/Modules/Menu/__tests__/Menu.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,13 @@
*/

import React from 'react';
import { render } from 'unit-test/testUtils';
import { render, screen } from 'unit-test/testUtils';
import * as StateHooks from 'core/state/hooks';
import Menu from '../index';

const mockItem = [
{
const list = {
last: true,
content: [{
id: '4d1cf7a9-d2f5-43b0-852e-e1b583b71c58',
name: 'Module 1',
gitRepositoryAddress: 'git-address-2',
Expand All @@ -38,23 +40,35 @@ const mockItem = [
errorThreshold: '0.6'
}
]
}
];
}]
};

test('render Modules Menu', () => {
const { getByText } = render(
<Menu items={mockItem} isLoading={false} />
);
test('render Modules Menu', async () => {
jest.spyOn(StateHooks, 'useGlobalState').mockImplementation(() => ({ list }));

const moduleName = getByText('Module 1');
render(<Menu />);

const moduleName = await screen.findByText('Module 1');

expect(moduleName).toBeInTheDocument();
});


test('render Modules Menu empty', async () => {
jest.spyOn(StateHooks, 'useGlobalState').mockImplementation(() => ({}));

render(<Menu />);

const moduleName = await screen.findByText('No Modules was found');

expect(moduleName).toBeInTheDocument();
});

test('render Modules Menu on Loading', () => {
const { getByText } = render(<Menu items={mockItem} isLoading />);
jest.spyOn(StateHooks, 'useGlobalState').mockImplementation(() => ({}));
render(<Menu />);

const loading = getByText('Loading...');
const loading = screen.getByText('Loading...');

expect(loading).toBeInTheDocument();
});
82 changes: 56 additions & 26 deletions ui/src/modules/Modules/Menu/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,51 +14,83 @@
* limitations under the License.
*/

import React from 'react';
import React, { Fragment, useCallback, useEffect, useState } from 'react';
import { useHistory } from 'react-router-dom';
import map from 'lodash/map';
import isEmpty from 'lodash/isEmpty';
import Can from 'containers/Can';
import { NEW_TAB } from 'core/components/TabPanel/constants';
import LabeledIcon from 'core/components/LabeledIcon';
import Text from 'core/components/Text';
import { addParam } from 'core/utils/path';
import routes from 'core/constants/routes';
import { isParamExists } from 'core/utils/path';
import InfiniteScroll from 'core/components/InfiniteScroll';
import { useDispatch, useGlobalState } from 'core/state/hooks';
import { resetModulesAction } from '../state/actions';
import { useFindAllModules } from '../hooks/module';
import { Module } from '../interfaces/Module';
import MenuItem from './MenuItem';
import Loader from './Loaders';
import Styled from './styled';

interface MenuProps {
items: Module[];
isLoading?: boolean;
}

const ModuleList = ({ items }: MenuProps) => (
<>
{map(items, item => (
<MenuItem key={item.id} id={item.id} name={item.name} />
))}
</>
);

const ModuleMenu = ({ items, isLoading }: MenuProps) => {
const { getAllModules } = useFindAllModules();
const ModulesMenu = () => {
const dispatch = useDispatch();
const history = useHistory();
const [name, setName] = useState<string>('');
const { getAllModules, loading } = useFindAllModules();
const { list } = useGlobalState(({ modules }) => modules);
const isEmptyList = isEmpty(list?.content) && !loading;

const openNewModule = () => {
if (!isParamExists('module', NEW_TAB)) {
addParam('module', routes.modulesComparation, history, NEW_TAB);
}
};

const onSearch = (search: string) => {
getAllModules(search);
const onChange = useCallback(() => {
const page = 0;
dispatch(resetModulesAction());
getAllModules(name, page);
}, [dispatch, getAllModules, name]);

useEffect(() => {
onChange();
}, [name, onChange]);

const loadMore = (page: number) => {
getAllModules(name, page);
};

const renderItem = ({ id, name }: Module) => (
<MenuItem
key={id}
id={id}
name={name}
/>
);

const renderEmpty = () => (
<Styled.Empty>
<Text.h3 color="dark">No Modules was found</Text.h3>
</Styled.Empty>
);

const renderList = (data: Module[]) =>
map(data, item => renderItem(item))

const renderContent = () => (
<InfiniteScroll
hasMore={!list?.last}
loadMore={loadMore}
isLoading={loading}
loader={<Styled.Loader />}
>
{isEmptyList ? renderEmpty() : renderList(list?.content)}
</InfiniteScroll>
);

return (
<>
<Fragment>
<Styled.Actions>
<Can I="write" a="modules" passThrough>
<Styled.Button onClick={openNewModule}>
Expand All @@ -69,13 +101,11 @@ const ModuleMenu = ({ items, isLoading }: MenuProps) => {
</Can>
</Styled.Actions>
<Styled.Content>
<Styled.SearchInput resume onSearch={onSearch} />
<Styled.List>
{isLoading ? <Loader.List /> : <ModuleList items={items} />}
</Styled.List>
<Styled.SearchInput resume onSearch={setName} />
{renderContent()}
</Styled.Content>
</>
</Fragment>
);
};

export default ModuleMenu;
export default ModulesMenu;
22 changes: 15 additions & 7 deletions ui/src/modules/Modules/Menu/styled.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import ButtonComponent from 'core/components/Button';
import Form from 'core/components/Form';
import Text from 'core/components/Text';
import { COLOR_BLACK_MARLIN } from 'core/assets/colors';
import LoaderMenuComponent from './Loaders';

const SearchInput = styled(SearchInputComponent)`
margin: 15px 0;
Expand All @@ -31,10 +32,6 @@ const List = styled.div`
display: flex;
flex-direction: column;
margin: 0;
> * {
padding: 0 16px;
}
`;

const ListItem = styled(LabeledIcon)`
Expand All @@ -44,14 +41,14 @@ const ListItem = styled(LabeledIcon)`
`;

const Content = styled.div`
height: calc(100vh - 200px);
overflow-y: auto;
height: calc(100vh - 250px);
`;

const Actions = styled.div`
> * + * {
margin-left: 20px;
}
padding: 0 16px;
`;

Expand All @@ -63,6 +60,8 @@ const Link = styled('button')<LinkProps>`
background: none;
border: none;
text-decoration: none;
width: 100%;
padding: 0 16px;
background-color: ${({ isActive }) =>
isActive ? COLOR_BLACK_MARLIN : 'transparent'};
`;
Expand Down Expand Up @@ -103,14 +102,23 @@ const ButtonModal = styled(ButtonComponent.Default)`
margin-top: 20px;
`;

const Loader = styled(LoaderMenuComponent.List)`
margin-left: 16px;
`;

const Empty = styled.div`
padding: 0 16px;
`;

export default {
SearchInput,
List,
ListItem,
Content,
Actions,
// Icon,
Loader,
Link,
Empty,
Button,
Modal: {
Input: ModalInput,
Expand Down
24 changes: 16 additions & 8 deletions ui/src/modules/Modules/hooks/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import { ModulePagination } from 'modules/Modules/interfaces/ModulePagination';
import { Module } from 'modules/Modules/interfaces/Module';
import {
loadModulesAction,
resetModuleAction
resetModulesAction
} from 'modules/Modules/state/actions';

export const useFindAllModules = (): {
Expand All @@ -45,8 +45,8 @@ export const useFindAllModules = (): {
const { response, loading } = modulesData;

const getAllModules = useCallback(
(name: string) => {
getModules(name);
(name: string, page = 0) => {
getModules({ name, page });
},
[getModules]
);
Expand Down Expand Up @@ -98,7 +98,7 @@ export const useSaveModule = (): {
saveModule: Function;
} => {
const [data, saveModule] = useFetch<Module>(create);
const { getAllModules } = useFindAllModules();
const { getAllModules, response: modules } = useFindAllModules();
const { response, error, loading } = data;
const dispatch = useDispatch();

Expand All @@ -107,7 +107,14 @@ export const useSaveModule = (): {
updateUntitledParam('module', response.id);
getAllModules();
}
}, [response, getAllModules]);
}, [response, getAllModules, dispatch]);

useEffect(() => {
if (modules) {
dispatch(resetModulesAction());
dispatch(loadModulesAction(modules));
}
}, [modules, dispatch]);

useEffect(() => {
if (error) {
Expand Down Expand Up @@ -140,15 +147,16 @@ export const useDeleteModule = (
useEffect(() => {
if (response) {
getAllModules();
dispatch(resetModuleAction());
}
}, [response, dispatch, getAllModules, history, module]);
}, [response, getAllModules, history, module]);

useEffect(() => {
if (modules) {
delParam('module', routes.modulesComparation, history, module?.id);
dispatch(resetModulesAction());
dispatch(loadModulesAction(modules));
}
}, [modules, history, module]);
}, [dispatch, modules, history, module]);

useEffect(() => {
if (error) {
Expand Down

0 comments on commit f62ae97

Please sign in to comment.