mirror of
https://github.com/logto-io/logto.git
synced 2025-01-20 21:32:31 -05:00
Merge pull request #468 from logto-io/sijie--log-1975-table-scroll
feat(console): table scroll
This commit is contained in:
commit
c9a8855c0d
4 changed files with 104 additions and 72 deletions
|
@ -1,5 +1,11 @@
|
||||||
@use '@/scss/underscore' as _;
|
@use '@/scss/underscore' as _;
|
||||||
|
|
||||||
|
.card {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
.headline {
|
.headline {
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
@ -10,21 +16,21 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.table {
|
.table {
|
||||||
margin-top: _.unit(4);
|
flex: 1;
|
||||||
|
|
||||||
tbody {
|
tr.clickable {
|
||||||
max-height: calc(100vh - _.unit(64));
|
cursor: pointer;
|
||||||
|
|
||||||
tr.clickable {
|
&:hover {
|
||||||
cursor: pointer;
|
background: var(--color-table-row-selected);
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background: var(--color-table-row-selected);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.pagination {
|
||||||
|
min-height: 64px;
|
||||||
|
}
|
||||||
|
|
||||||
.userName {
|
.userName {
|
||||||
width: 360px;
|
width: 360px;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { User } from '@logto/schemas';
|
import { User } from '@logto/schemas';
|
||||||
import { conditionalString } from '@silverhand/essentials';
|
import { conditionalString } from '@silverhand/essentials';
|
||||||
|
import classNames from 'classnames';
|
||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
import { useTranslation } from 'react-i18next';
|
import { useTranslation } from 'react-i18next';
|
||||||
import Modal from 'react-modal';
|
import Modal from 'react-modal';
|
||||||
|
@ -18,6 +19,7 @@ import TableError from '@/components/Table/TableError';
|
||||||
import TableLoading from '@/components/Table/TableLoading';
|
import TableLoading from '@/components/Table/TableLoading';
|
||||||
import { RequestError } from '@/hooks/use-api';
|
import { RequestError } from '@/hooks/use-api';
|
||||||
import * as modalStyles from '@/scss/modal.module.scss';
|
import * as modalStyles from '@/scss/modal.module.scss';
|
||||||
|
import * as tableStyles from '@/scss/table.module.scss';
|
||||||
|
|
||||||
import CreateForm from './components/CreateForm';
|
import CreateForm from './components/CreateForm';
|
||||||
import * as styles from './index.module.scss';
|
import * as styles from './index.module.scss';
|
||||||
|
@ -39,7 +41,7 @@ const Users = () => {
|
||||||
const [users, totalCount] = data ?? [];
|
const [users, totalCount] = data ?? [];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Card>
|
<Card className={styles.card}>
|
||||||
<div className={styles.headline}>
|
<div className={styles.headline}>
|
||||||
<CardTitle title="users.title" subtitle="users.subtitle" />
|
<CardTitle title="users.title" subtitle="users.subtitle" />
|
||||||
<Button
|
<Button
|
||||||
|
@ -68,68 +70,72 @@ const Users = () => {
|
||||||
<div className={styles.filter}>
|
<div className={styles.filter}>
|
||||||
<Search defaultValue={keyword} onSearch={setKeyword} />
|
<Search defaultValue={keyword} onSearch={setKeyword} />
|
||||||
</div>
|
</div>
|
||||||
<table className={styles.table}>
|
<div className={classNames(styles.table, tableStyles.scrollable)}>
|
||||||
<colgroup>
|
<table>
|
||||||
<col className={styles.userName} />
|
<colgroup>
|
||||||
<col />
|
<col className={styles.userName} />
|
||||||
<col />
|
<col />
|
||||||
</colgroup>
|
<col />
|
||||||
<thead>
|
</colgroup>
|
||||||
<tr>
|
<thead>
|
||||||
<th>{t('users.user_name')}</th>
|
<tr>
|
||||||
<th>{t('users.application_name')}</th>
|
<th>{t('users.user_name')}</th>
|
||||||
<th>{t('users.latest_sign_in')}</th>
|
<th>{t('users.application_name')}</th>
|
||||||
</tr>
|
<th>{t('users.latest_sign_in')}</th>
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{error && (
|
|
||||||
<TableError
|
|
||||||
columns={3}
|
|
||||||
content={error.body.message}
|
|
||||||
onRetry={async () => mutate(undefined, true)}
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
{isLoading && <TableLoading columns={3} />}
|
|
||||||
{users?.length === 0 && (
|
|
||||||
<TableEmpty columns={3}>
|
|
||||||
<Button
|
|
||||||
title="admin_console.users.create"
|
|
||||||
type="outline"
|
|
||||||
onClick={() => {
|
|
||||||
setIsCreateFormOpen(true);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
</TableEmpty>
|
|
||||||
)}
|
|
||||||
{users?.map(({ id, name, username }) => (
|
|
||||||
<tr
|
|
||||||
key={id}
|
|
||||||
className={styles.clickable}
|
|
||||||
onClick={() => {
|
|
||||||
navigate(`/users/${id}`);
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<td>
|
|
||||||
<ItemPreview
|
|
||||||
title={name ?? '-'}
|
|
||||||
subtitle={username ?? '-'}
|
|
||||||
icon={<ImagePlaceholder />}
|
|
||||||
to={`/users/${id}`}
|
|
||||||
/>
|
|
||||||
</td>
|
|
||||||
<td>Application</td>
|
|
||||||
<td>Last sign in</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{error && (
|
||||||
{totalCount !== undefined && totalCount > 0 && (
|
<TableError
|
||||||
<Pagination
|
columns={3}
|
||||||
pageCount={Math.ceil(totalCount / pageSize)}
|
content={error.body.message}
|
||||||
pageIndex={pageIndex}
|
onRetry={async () => mutate(undefined, true)}
|
||||||
onChange={setPageIndex}
|
/>
|
||||||
/>
|
)}
|
||||||
)}
|
{isLoading && <TableLoading columns={3} />}
|
||||||
|
{users?.length === 0 && (
|
||||||
|
<TableEmpty columns={3}>
|
||||||
|
<Button
|
||||||
|
title="admin_console.users.create"
|
||||||
|
type="outline"
|
||||||
|
onClick={() => {
|
||||||
|
setIsCreateFormOpen(true);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</TableEmpty>
|
||||||
|
)}
|
||||||
|
{users?.map(({ id, name, username }) => (
|
||||||
|
<tr
|
||||||
|
key={id}
|
||||||
|
className={styles.clickable}
|
||||||
|
onClick={() => {
|
||||||
|
navigate(`/users/${id}`);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
<td>
|
||||||
|
<ItemPreview
|
||||||
|
title={name ?? '-'}
|
||||||
|
subtitle={username ?? '-'}
|
||||||
|
icon={<ImagePlaceholder />}
|
||||||
|
to={`/users/${id}`}
|
||||||
|
/>
|
||||||
|
</td>
|
||||||
|
<td>Application</td>
|
||||||
|
<td>Last sign in</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<div className={styles.pagination}>
|
||||||
|
{totalCount !== undefined && totalCount > 0 && (
|
||||||
|
<Pagination
|
||||||
|
pageCount={Math.ceil(totalCount / pageSize)}
|
||||||
|
pageIndex={pageIndex}
|
||||||
|
onChange={setPageIndex}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,7 +25,6 @@ table {
|
||||||
border-spacing: 0;
|
border-spacing: 0;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
table-layout: fixed;
|
table-layout: fixed;
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
thead {
|
thead {
|
||||||
th {
|
th {
|
||||||
|
|
21
packages/console/src/scss/table.module.scss
Normal file
21
packages/console/src/scss/table.module.scss
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
@use '@/scss/underscore' as _;
|
||||||
|
|
||||||
|
.scrollable {
|
||||||
|
margin-top: _.unit(4);
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid var(--color-neutral-90);
|
||||||
|
border-radius: _.unit(2);
|
||||||
|
|
||||||
|
table {
|
||||||
|
border: none;
|
||||||
|
|
||||||
|
thead tr {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
|
||||||
|
th {
|
||||||
|
background: var(--color-on-primary);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue