Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
# Conflicts:
#	changelog.md
  • Loading branch information
AlekseyManetov committed Sep 1, 2022
2 parents b485a9f + 2c52123 commit 0d67120
Show file tree
Hide file tree
Showing 57 changed files with 800 additions and 338 deletions.
52 changes: 26 additions & 26 deletions app/src/common/sidebar/Sidebar.tsx
Original file line number Diff line number Diff line change
@@ -1,43 +1,43 @@
import * as React from 'react';
import * as css from './Sidebar.scss';
import { ScrollBars, SearchInput } from '@epam/promo';
import { Tree, TreeListItem, TreeNodeProps } from '@epam/uui-components';
import { Tree, TreeListItem } from '@epam/uui-components';
import { SidebarButton } from './SidebarButton';
import { Link, useUuiContext } from "@epam/uui";
import { DataRowProps, DataSourceState, Link, useUuiContext } from "@epam/uui";
import { analyticsEvents } from "../../analyticsEvents";

export interface SidebarProps<TItem extends TreeListItem = TreeListItem> {
value: string;
onValueChange: (newVal: TreeNodeProps<TItem>) => void;
getItemLink?: (item: TreeNodeProps<TItem>) => Link;
onValueChange: (newVal: DataRowProps<TItem, string>) => void;
getItemLink?: (item: DataRowProps<TItem, string>) => Link;
items: TItem[];
renderSearch?: () => React.ReactNode;
}

export function Sidebar<TItem extends TreeListItem>(props: SidebarProps<TItem>) {
const { uuiAnalytics } = useUuiContext();
const [searchValue, setSearchValue] = React.useState<string>('');
const [unfoldedIds, setUnfoldedIds] = React.useState<string[]>([]);
const [value, setValue] = React.useState<DataSourceState>({ search: '', folded: {} });

React.useEffect(() => {
const { parentId } = props.items.find(i => i.id === props.value);
if (!unfoldedIds.includes(parentId) && parentId !== undefined) {
setUnfoldedIds([...unfoldedIds, parentId]);
const { parentId } = props.items.find(i => i.id == props.value);
if (parentId != null) {
const parentKey = JSON.stringify(parentId);
setValue((value) => ({...value, folded: { ...value.folded, [ parentKey ]: false } }));
}
}, [props.value]);

const handleClick = React.useCallback((item: TreeNodeProps) => {
item.isDropdown && item.onClick();
const type = item.isDropdown ? 'folder' : 'document';
uuiAnalytics.sendEvent(analyticsEvents.document.clickDocument(type, item.data.name, item.parentId));
const handleClick = React.useCallback((row: DataRowProps<TItem, string>) => {
row.isFoldable && row.onFold(row);
const type = row.isFoldable ? 'folder' : 'document';
uuiAnalytics.sendEvent(analyticsEvents.document.clickDocument(type, row.value.name, row.parentId));
}, []);

return (
<aside className={ css.root }>
<SearchInput
cx={ css.search }
value={ searchValue }
onValueChange={ setSearchValue }
value={ value.search }
onValueChange={ (search) => setValue(v => ({ ...v, search }))}
autoFocus
placeholder='Search'
getValueChangeAnalyticsEvent={ value => analyticsEvents.document.search(value) }
Expand All @@ -46,18 +46,18 @@ export function Sidebar<TItem extends TreeListItem>(props: SidebarProps<TItem>)
<ScrollBars>
<Tree<TItem>
items={ props.items }
value={ unfoldedIds }
search={ searchValue }
onValueChange={ setUnfoldedIds }
renderRow={ item => (
value={ value }
onValueChange={ setValue }
renderRow={ row => (
<SidebarButton
link={ props.getItemLink(item) }
indent={ item.depth * 12 }
isOpen={ item.isOpen }
isDropdown={ item.isDropdown }
isActive={ item.id === props.value }
caption={ item.data.name }
onClick={ () => handleClick(item) }
key={ row.key }
link={ props.getItemLink(row) }
indent={ (row.depth - 1) * 12 }
isOpen={ !row.isFolded }
isDropdown={ row.isFoldable }
isActive={ row.id === props.value }
caption={ row.value.name }
onClick={ () => handleClick(row) }
/>
) }
/>
Expand Down
31 changes: 31 additions & 0 deletions app/src/demo/tables/filteredTable/FilteredTable.scss
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@
display: flex;
position: relative;
}
.presets-title {
padding-top: 20px;
padding-bottom: 20px;
}

.container {
display: flex;
Expand All @@ -15,6 +19,7 @@
flex-basis: auto;
min-width: 0;
flex-grow: 1;
font-family: $font-sans;

.manager-cell {
font-family: $font-sans;
Expand Down Expand Up @@ -69,3 +74,29 @@
align-self: flex-start;
}
}

.presets-panel {
padding: 0 24px;
display: flex;
overflow-x: auto;
flex-shrink: 0;
background-color: $white;
border-bottom: 1px solid $gray40;


& > *:not(:first-child) {
margin-left: 0;
}

& > * {
flex-shrink: 0;
}

& > *:not(:last-child) {
margin-right: 0;
}

button {
align-self: center;
}
}
80 changes: 58 additions & 22 deletions app/src/demo/tables/filteredTable/FilteredTable.tsx
Original file line number Diff line number Diff line change
@@ -1,66 +1,102 @@
import React, { useMemo } from 'react';
import { Person } from '@epam/uui-docs';
import { useLazyDataSource, useUuiContext, UuiContexts, useTableState } from "@epam/uui-core";
import { DataTable, FiltersToolbar, FlexRow } from '@epam/promo';
import React, { useCallback, useEffect, useMemo, useState } from 'react';
import css from './FilteredTable.scss';
import type { TApi } from '../../../data';
import { DataTable, FiltersToolbar, FlexCell, FlexRow, PresetPanel, Text } from '@epam/promo';
import { getFilters } from './filters';
import { useLazyDataSource, useUuiContext, UuiContexts, useTableState, LazyDataSourceApiRequest, ITablePreset } from "@epam/uui-core";
import { FilteredTableFooter } from "./FilteredTableFooter";
import { Person } from '@epam/uui-docs';
import { personColumns } from './columns';
import { FlexCell } from "@epam/uui-components";
import { SearchInput } from "@epam/uui";
import { TApi } from "../../../data";

export const FilteredTable: React.FC = () => {
const svc = useUuiContext<TApi, UuiContexts>();
const filters = useMemo(getFilters, []);
const tableStateApi = useTableState({ columns: personColumns });
const tableState = tableStateApi.tableState;
const [totalCount, setTotalCount] = useState(0);
const [initialPresets, setInitialPresets] = useState<ITablePreset[]>([]);

const dataSource = useLazyDataSource<Person, number, Person>({
api: request => {
return svc.api.demo.persons(request);
},
useEffect(() => {
svc.api.presets.getPresets()
.then(setInitialPresets)
.catch(console.error);
}, []);

const tableStateApi = useTableState({
columns: personColumns,
initialPresets: initialPresets,
onPresetCreate: svc.api.presets.createPreset,
onPresetUpdate: svc.api.presets.updatePreset,
onPresetDelete: svc.api.presets.deletePreset,
});

const api = useCallback(async (rq: LazyDataSourceApiRequest<{}>) => {
const result = await svc.api.demo.personsPaged({
...rq,
filter: rq.filter || {},
page: rq.page - 1,
pageSize: tableStateApi.tableState.pageSize || rq.pageSize,
});
setTotalCount(() => result.totalCount);
result.count = result.items.length;
result.totalCount = result.items.length;
result.from = 0;
return result;
}, [tableStateApi.tableState.page, tableStateApi.tableState.pageSize]);

const view = dataSource.useView(tableState, tableStateApi.setTableState, {
const dataSource = useLazyDataSource<Person, number, Person>({
api: api,
}, []);

const view = dataSource.useView(tableStateApi.tableState, tableStateApi.setTableState, {
rowOptions: {
checkbox: { isVisible: true },
isSelectable: true,
},
});

const searchHandler = (val: string | undefined) => tableStateApi.setTableState({ ...tableStateApi.tableState, search: val });

const { setTableState, setFilter, setColumnsConfig, setFiltersConfig, ...presetsApi } = tableStateApi;

return (
<div className={ css.container }>
<div className={ css.presetsPanel }>
<Text fontSize="24" cx={ css.presetsTitle }>Profiles Dashboard</Text>
<PresetPanel { ...presetsApi } />
</div>
<FlexRow cx={ css.filterPanelWrapper } background="gray5" borderBottom={ true }>
<FlexRow cx={ css.filterPanel }>
<FiltersToolbar
filters={ filters }
tableState={ tableState }
tableState={ tableStateApi.tableState }
setTableState={ tableStateApi.setTableState }
/>
</FlexRow>
<FlexCell cx={ css.search } width={ 295 }>
<SearchInput
value={ tableState.search }
onValueChange={ (val) => tableStateApi.setTableState({ ...tableState, search: val }) }
value={ tableStateApi.tableState.search }
onValueChange={ searchHandler }
placeholder="Search"
debounceDelay={ 1000 }
/>
</FlexCell>
</FlexRow>

<DataTable
headerTextCase="upper"
headerTextCase={ "upper" as "upper" | "normal" }
getRows={ view.getVisibleRows }
columns={ personColumns }
filters={ filters }
value={ tableState }
value={ tableStateApi.tableState }
onValueChange={ tableStateApi.setTableState }
showColumnsConfig={ true }
allowColumnsResizing
allowColumnsReordering
allowColumnsResizing={ true }
allowColumnsReordering={ true }
{ ...view.getListProps() }
/>
<FilteredTableFooter
tableState={ tableStateApi.tableState }
setTableState={ tableStateApi.setTableState }
totalCount={ totalCount }
/>
</div>
);
};
27 changes: 27 additions & 0 deletions app/src/demo/tables/filteredTable/FilteredTableFooter.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
@use '~@epam/promo/assets/styles/colors' as *;
@use '~@epam/promo/assets/styles/fonts' as *;

.paginator-wrapper {
justify-content: flex-end;
box-shadow: inset 0 1px 0 $gray40;

.items-per-page {
margin-right: 36px;

:global(.uui-input){
max-width: 20px;
}
}

.go-to-page {
:global(.uui-input){
max-width: 18px;
}
}

.go-to-page-button {
margin-right: 36px;
margin-left: 3px;
width: 24px;
}
}
83 changes: 83 additions & 0 deletions app/src/demo/tables/filteredTable/FilteredTableFooter.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import React, { useEffect, useState } from "react";
import css from "./FilteredTableFooter.scss";
import { FlexRow, LabeledInput, PageButton, Paginator, PickerInput, TextInput } from "@epam/promo";
import { DataTableState, useArrayDataSource } from "@epam/uui-core";
import { ReactComponent as ArrowRightIcon_24 } from "@epam/assets/icons/common/navigation-chevron-right-18.svg";

interface IFilteredTableFooterProps {
tableState: DataTableState;
setTableState: (newState: DataTableState) => void;
totalCount: number;
}

export const FilteredTableFooter = (props: IFilteredTableFooterProps) => {
const [goToPage, setGoToPage] = useState('1');
const totalPages = () => props.tableState.pageSize ? Math.ceil(props.totalCount / props.tableState.pageSize) : 0;
const goToPageHandler = () => props.setTableState({ ...props.tableState, page: +goToPage, indexToScroll: 0 });
const paginatorHandler = (newPage: number) => props.setTableState({ ...props.tableState, page: newPage, indexToScroll: 0 });

const itemsPerPageDataSource = useArrayDataSource({
items: [{ id: 40, page: "40" }, { id: 80, page: "80" }, { id: 120, page: "120" }, { id: 160, page: "160" }],
}, []);

useEffect(() => {
setItemsPerPage(40);
}, []);

const setGoToPageHandler = (newValue: string) => {
if (typeof +newValue === 'number' && !isNaN(+newValue) && +newValue <= totalPages() && +newValue > 0) {
setGoToPage(() => newValue);
}
};

const setItemsPerPage = (itemsPerPage: number) => {
props.setTableState({ ...props.tableState, page: 1, pageSize: itemsPerPage });
setGoToPage('1');
};

return (
<FlexRow cx={ css.paginatorWrapper } padding="24" vPadding="12" background="gray5">
<div className={ css.itemsPerPage }>
<LabeledInput size="24" label="Items per page" labelPosition="left">
<PickerInput
size="24"
placeholder="Select items per page"
dataSource={ itemsPerPageDataSource }
value={ props.tableState.pageSize }
onValueChange={ setItemsPerPage }
getName={ item => item.page }
selectionMode="single"
valueType={ 'id' }
sorting={ { field: 'page', direction: 'asc' } }
disableClear
searchPosition="none"
/>
</LabeledInput>
</div>
<div>
<LabeledInput size="24" label="Go to page" labelPosition="left">
<TextInput
cx={ css.goToPage }
size="24"
value={ goToPage }
onValueChange={ setGoToPageHandler }
/>
</LabeledInput>
</div>
<PageButton
cx={ css.goToPageButton }
size="24"
icon={ ArrowRightIcon_24 }
onClick={ goToPageHandler }
fill="white"
color="gray50"
/>
<Paginator
value={ props.tableState.page }
onValueChange={ paginatorHandler }
totalPages={ totalPages() }
size="24"
/>
</FlexRow>
);
};
Loading

0 comments on commit 0d67120

Please sign in to comment.