mirror of
https://github.com/umami-software/umami.git
synced 2026-02-06 21:57:16 +01:00
Added useFilterQuery. Converted websites and reports pages.
This commit is contained in:
parent
6846355c63
commit
7e626dcd52
29 changed files with 373 additions and 499 deletions
|
|
@ -1,46 +1,46 @@
|
|||
import { createContext } from 'react';
|
||||
import { SearchField } from 'react-basics';
|
||||
import { useDataTable } from 'components/hooks/useDataTable';
|
||||
import { Banner, Loading, SearchField } from 'react-basics';
|
||||
import { useMessages } from 'components/hooks';
|
||||
import Empty from 'components/common/Empty';
|
||||
import Pager from 'components/common/Pager';
|
||||
import styles from './DataTable.module.css';
|
||||
import classNames from 'classnames';
|
||||
|
||||
const DEFAULT_SEARCH_DELAY = 1000;
|
||||
const DEFAULT_SEARCH_DELAY = 600;
|
||||
|
||||
export const DataTableStyles = styles;
|
||||
|
||||
export const DataTableContext = createContext(null);
|
||||
|
||||
export function DataTable({
|
||||
data = {},
|
||||
params = {},
|
||||
setParams,
|
||||
isLoading,
|
||||
error,
|
||||
searchDelay,
|
||||
showSearch = true,
|
||||
showPaging = true,
|
||||
children,
|
||||
onChange,
|
||||
}) {
|
||||
const { formatMessage, labels, messages } = useMessages();
|
||||
const dataTable = useDataTable();
|
||||
const { query, setQuery, data, pageInfo, setPageInfo } = dataTable;
|
||||
const { page, pageSize, count } = pageInfo || {};
|
||||
const noResults = Boolean(query && data?.length === 0);
|
||||
const { pageSize, count } = data;
|
||||
const { query, page } = params;
|
||||
const hasData = Boolean(!isLoading && data?.data?.length);
|
||||
const noResults = Boolean(!isLoading && query && !hasData);
|
||||
|
||||
const handleChange = value => {
|
||||
onChange?.({ query: value, page });
|
||||
};
|
||||
|
||||
const handleSearch = value => {
|
||||
setQuery(value);
|
||||
handleChange(value);
|
||||
const handleSearch = query => {
|
||||
setParams({ ...params, query });
|
||||
};
|
||||
|
||||
const handlePageChange = page => {
|
||||
setPageInfo(state => ({ ...state, page }));
|
||||
setParams({ ...params, page });
|
||||
};
|
||||
|
||||
if (error) {
|
||||
return <Banner variant="error">{formatMessage(messages.error)}</Banner>;
|
||||
}
|
||||
|
||||
return (
|
||||
<DataTableContext.Provider value={dataTable}>
|
||||
{showSearch && (
|
||||
<>
|
||||
{(hasData || query || isLoading) && showSearch && (
|
||||
<SearchField
|
||||
className={styles.search}
|
||||
value={query}
|
||||
|
|
@ -50,8 +50,16 @@ export function DataTable({
|
|||
placeholder={formatMessage(labels.search)}
|
||||
/>
|
||||
)}
|
||||
{noResults && <Empty message={formatMessage(messages.noResultsFound)} />}
|
||||
<div className={styles.body}>{children}</div>
|
||||
<div
|
||||
className={classNames(styles.body, { [styles.status]: isLoading || noResults || !hasData })}
|
||||
>
|
||||
{hasData && typeof children === 'function' ? children(data) : children}
|
||||
{isLoading && <Loading icon="dots" />}
|
||||
{!isLoading && !hasData && !query && (
|
||||
<Empty message={formatMessage(messages.noDataAvailable)} />
|
||||
)}
|
||||
{noResults && <Empty message={formatMessage(messages.noResultsFound)} />}
|
||||
</div>
|
||||
{showPaging && (
|
||||
<Pager
|
||||
className={styles.pager}
|
||||
|
|
@ -61,7 +69,7 @@ export function DataTable({
|
|||
onPageChange={handlePageChange}
|
||||
/>
|
||||
)}
|
||||
</DataTableContext.Provider>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,12 @@
|
|||
.table {
|
||||
grid-template-rows: repeat(auto-fit, max-content);
|
||||
}
|
||||
|
||||
.table td {
|
||||
align-items: center;
|
||||
max-height: max-content;
|
||||
}
|
||||
|
||||
.search {
|
||||
max-width: 300px;
|
||||
margin: 20px 0;
|
||||
|
|
@ -8,10 +17,22 @@
|
|||
gap: 5px;
|
||||
}
|
||||
|
||||
.body {
|
||||
display: flex;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.body td {
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.pager {
|
||||
margin-top: 20px;
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
.status {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
min-height: 200px;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import classNames from 'classnames';
|
||||
import { Button, Flexbox, Icon, Icons } from 'react-basics';
|
||||
import { Button, Icon, Icons } from 'react-basics';
|
||||
import useMessages from 'components/hooks/useMessages';
|
||||
import styles from './Pager.module.css';
|
||||
|
||||
|
|
@ -25,21 +25,25 @@ export function Pager({ page, pageSize, count, onPageChange, className }) {
|
|||
}
|
||||
|
||||
return (
|
||||
<Flexbox justifyContent="center" className={classNames(styles.container, className)}>
|
||||
<Button onClick={() => handlePageChange(-1)} disabled={firstPage}>
|
||||
<Icon rotate={90}>
|
||||
<Icons.ChevronDown />
|
||||
</Icon>
|
||||
</Button>
|
||||
<Flexbox alignItems="center" className={styles.text}>
|
||||
{formatMessage(labels.pageOf, { current: page, total: maxPage })}
|
||||
</Flexbox>
|
||||
<Button onClick={() => handlePageChange(1)} disabled={lastPage}>
|
||||
<Icon rotate={270}>
|
||||
<Icons.ChevronDown />
|
||||
</Icon>
|
||||
</Button>
|
||||
</Flexbox>
|
||||
<div className={classNames(styles.pager, className)}>
|
||||
<div>{formatMessage(labels.numberOfRecords, { x: count })}</div>
|
||||
<div className={styles.nav}>
|
||||
<Button onClick={() => handlePageChange(-1)} disabled={firstPage}>
|
||||
<Icon rotate={90}>
|
||||
<Icons.ChevronDown />
|
||||
</Icon>
|
||||
</Button>
|
||||
<div className={styles.text}>
|
||||
{formatMessage(labels.pageOf, { current: page, total: maxPage })}
|
||||
</div>
|
||||
<Button onClick={() => handlePageChange(1)} disabled={lastPage}>
|
||||
<Icon rotate={270}>
|
||||
<Icons.ChevronDown />
|
||||
</Icon>
|
||||
</Button>
|
||||
</div>
|
||||
<div></div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,27 @@
|
|||
.pager {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.nav {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.text {
|
||||
font-size: var(--font-size-md);
|
||||
margin: 0 16px;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: 992px) {
|
||||
.pager {
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
}
|
||||
|
||||
.nav {
|
||||
justify-content: end;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue