mirror of
https://github.com/logto-io/logto.git
synced 2024-12-16 20:26:19 -05:00
Merge pull request #2462 from logto-io/feature/ac-layout
refactor(console): ac layout
This commit is contained in:
commit
b35d422e1d
24 changed files with 115 additions and 128 deletions
|
@ -21,7 +21,7 @@
|
|||
|
||||
.main {
|
||||
flex-grow: 1;
|
||||
padding-right: _.unit(6);
|
||||
padding: 0 _.unit(3) 0 _.unit(2);
|
||||
overflow-y: scroll;
|
||||
|
||||
> * {
|
||||
|
|
|
@ -21,10 +21,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.table {
|
||||
margin-top: _.unit(4);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.pagination {
|
||||
margin-top: _.unit(4);
|
||||
|
|
|
@ -13,6 +13,7 @@ import TableError from '@/components/Table/TableError';
|
|||
import TableLoading from '@/components/Table/TableLoading';
|
||||
import UserName from '@/components/UserName';
|
||||
import type { RequestError } from '@/hooks/use-api';
|
||||
import * as resourcesStyles from '@/scss/resources.module.scss';
|
||||
import * as tableStyles from '@/scss/table.module.scss';
|
||||
|
||||
import ApplicationSelector from './components/ApplicationSelector';
|
||||
|
@ -85,7 +86,7 @@ const AuditLogTable = ({ userId }: Props) => {
|
|||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className={classNames(styles.table, tableStyles.scrollable)}>
|
||||
<div className={classNames(resourcesStyles.table, tableStyles.scrollable)}>
|
||||
<table className={classNames(logs?.length === 0 && tableStyles.empty)}>
|
||||
<colgroup>
|
||||
<col className={styles.eventName} />
|
||||
|
@ -141,8 +142,9 @@ const AuditLogTable = ({ userId }: Props) => {
|
|||
<div className={styles.pagination}>
|
||||
{!!totalCount && (
|
||||
<Pagination
|
||||
pageCount={Math.ceil(totalCount / pageSize)}
|
||||
pageIndex={pageIndex}
|
||||
totalCount={totalCount}
|
||||
pageSize={pageSize}
|
||||
onChange={(page) => {
|
||||
updateQuery('page', String(page));
|
||||
}}
|
||||
|
|
|
@ -1,9 +1,21 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.container {
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.positionInfo {
|
||||
align-self: flex-end;
|
||||
font: var(--font-body-medium);
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
.pagination {
|
||||
display: flex;
|
||||
justify-content: right;
|
||||
margin: 0;
|
||||
padding-inline-start: _.unit(4);
|
||||
|
||||
li {
|
||||
list-style: none;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import classNames from 'classnames';
|
||||
import { useTranslation } from 'react-i18next';
|
||||
import ReactPaginate from 'react-paginate';
|
||||
|
||||
import Button from '../Button';
|
||||
|
@ -9,34 +10,46 @@ import * as styles from './index.module.scss';
|
|||
|
||||
type Props = {
|
||||
pageIndex: number;
|
||||
pageCount: number;
|
||||
totalCount: number;
|
||||
pageSize: number;
|
||||
onChange?: (pageIndex: number) => void;
|
||||
};
|
||||
|
||||
const Pagination = ({ pageIndex, pageCount, onChange }: Props) => {
|
||||
const Pagination = ({ pageIndex, totalCount, pageSize, onChange }: Props) => {
|
||||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' });
|
||||
const pageCount = Math.ceil(totalCount / pageSize);
|
||||
|
||||
const min = (pageIndex - 1) * pageSize + 1;
|
||||
const max = pageIndex * pageSize;
|
||||
|
||||
return (
|
||||
<ReactPaginate
|
||||
className={styles.pagination}
|
||||
pageCount={pageCount}
|
||||
forcePage={pageIndex - 1}
|
||||
pageLabelBuilder={(page: number) => (
|
||||
<Button
|
||||
type={page === pageIndex ? 'outline' : 'default'}
|
||||
className={classNames(styles.button, page === pageIndex && styles.active)}
|
||||
size="small"
|
||||
title={<DangerousRaw>{page}</DangerousRaw>}
|
||||
/>
|
||||
)}
|
||||
previousLabel={<Button className={styles.button} size="small" icon={<Previous />} />}
|
||||
nextLabel={<Button className={styles.button} size="small" icon={<Next />} />}
|
||||
breakLabel={
|
||||
<Button className={styles.button} size="small" title={<DangerousRaw>...</DangerousRaw>} />
|
||||
}
|
||||
disabledClassName={styles.disabled}
|
||||
onPageChange={({ selected }) => {
|
||||
onChange?.(selected + 1);
|
||||
}}
|
||||
/>
|
||||
<div className={styles.container}>
|
||||
<div className={styles.positionInfo}>
|
||||
{t('general.page_info', { min, max, total: totalCount })}
|
||||
</div>
|
||||
<ReactPaginate
|
||||
className={styles.pagination}
|
||||
pageCount={pageCount}
|
||||
forcePage={pageIndex - 1}
|
||||
pageLabelBuilder={(page: number) => (
|
||||
<Button
|
||||
type={page === pageIndex ? 'outline' : 'default'}
|
||||
className={classNames(styles.button, page === pageIndex && styles.active)}
|
||||
size="small"
|
||||
title={<DangerousRaw>{page}</DangerousRaw>}
|
||||
/>
|
||||
)}
|
||||
previousLabel={<Button className={styles.button} size="small" icon={<Previous />} />}
|
||||
nextLabel={<Button className={styles.button} size="small" icon={<Next />} />}
|
||||
breakLabel={
|
||||
<Button className={styles.button} size="small" title={<DangerousRaw>...</DangerousRaw>} />
|
||||
}
|
||||
disabledClassName={styles.disabled}
|
||||
onPageChange={({ selected }) => {
|
||||
onChange?.(selected + 1);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,19 +1,5 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.card {
|
||||
@include _.flex-column;
|
||||
}
|
||||
|
||||
.headline {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.table {
|
||||
margin-top: _.unit(4);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
|
|
@ -12,7 +12,6 @@ import ApiResourceDark from '@/assets/images/api-resource-dark.svg';
|
|||
import ApiResource from '@/assets/images/api-resource.svg';
|
||||
import Plus from '@/assets/images/plus.svg';
|
||||
import Button from '@/components/Button';
|
||||
import Card from '@/components/Card';
|
||||
import CardTitle from '@/components/CardTitle';
|
||||
import CopyToClipboard from '@/components/CopyToClipboard';
|
||||
import ItemPreview from '@/components/ItemPreview';
|
||||
|
@ -23,6 +22,7 @@ import TableLoading from '@/components/Table/TableLoading';
|
|||
import type { RequestError } from '@/hooks/use-api';
|
||||
import { useTheme } from '@/hooks/use-theme';
|
||||
import * as modalStyles from '@/scss/modal.module.scss';
|
||||
import * as resourcesStyles from '@/scss/resources.module.scss';
|
||||
import * as tableStyles from '@/scss/table.module.scss';
|
||||
|
||||
import CreateForm from './components/CreateForm';
|
||||
|
@ -46,8 +46,8 @@ const ApiResources = () => {
|
|||
const [apiResources, totalCount] = data ?? [];
|
||||
|
||||
return (
|
||||
<Card className={styles.card}>
|
||||
<div className={styles.headline}>
|
||||
<div className={resourcesStyles.container}>
|
||||
<div className={resourcesStyles.headline}>
|
||||
<CardTitle title="api_resources.title" subtitle="api_resources.subtitle" />
|
||||
<Button
|
||||
title="api_resources.create"
|
||||
|
@ -77,7 +77,7 @@ const ApiResources = () => {
|
|||
/>
|
||||
</Modal>
|
||||
</div>
|
||||
<div className={classNames(styles.table, tableStyles.scrollable)}>
|
||||
<div className={classNames(resourcesStyles.table, tableStyles.scrollable)}>
|
||||
<table className={classNames(!data && tableStyles.empty)}>
|
||||
<colgroup>
|
||||
<col className={styles.apiResourceName} />
|
||||
|
@ -140,15 +140,16 @@ const ApiResources = () => {
|
|||
<div className={styles.pagination}>
|
||||
{!!totalCount && (
|
||||
<Pagination
|
||||
pageCount={Math.ceil(totalCount / pageSize)}
|
||||
pageIndex={pageIndex}
|
||||
totalCount={totalCount}
|
||||
pageSize={pageSize}
|
||||
onChange={(page) => {
|
||||
setQuery({ page: String(page) });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,19 +1,5 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.card {
|
||||
@include _.flex-column;
|
||||
}
|
||||
|
||||
.headline {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.table {
|
||||
margin-top: _.unit(4);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.icon {
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,6 @@ import useSWR from 'swr';
|
|||
import Plus from '@/assets/images/plus.svg';
|
||||
import ApplicationIcon from '@/components/ApplicationIcon';
|
||||
import Button from '@/components/Button';
|
||||
import Card from '@/components/Card';
|
||||
import CardTitle from '@/components/CardTitle';
|
||||
import CopyToClipboard from '@/components/CopyToClipboard';
|
||||
import ItemPreview from '@/components/ItemPreview';
|
||||
|
@ -19,6 +18,7 @@ import TableError from '@/components/Table/TableError';
|
|||
import TableLoading from '@/components/Table/TableLoading';
|
||||
import type { RequestError } from '@/hooks/use-api';
|
||||
import * as modalStyles from '@/scss/modal.module.scss';
|
||||
import * as resourcesStyles from '@/scss/resources.module.scss';
|
||||
import * as tableStyles from '@/scss/table.module.scss';
|
||||
import { applicationTypeI18nKey } from '@/types/applications';
|
||||
|
||||
|
@ -41,8 +41,8 @@ const Applications = () => {
|
|||
const [applications, totalCount] = data ?? [];
|
||||
|
||||
return (
|
||||
<Card className={styles.card}>
|
||||
<div className={styles.headline}>
|
||||
<div className={resourcesStyles.container}>
|
||||
<div className={resourcesStyles.headline}>
|
||||
<CardTitle title="applications.title" subtitle="applications.subtitle" />
|
||||
<Button
|
||||
icon={<Plus />}
|
||||
|
@ -69,19 +69,21 @@ const Applications = () => {
|
|||
}}
|
||||
/>
|
||||
</Modal>
|
||||
</div>
|
||||
<div className={classNames(styles.table, tableStyles.scrollable)}>
|
||||
</div>{' '}
|
||||
<div className={classNames(resourcesStyles.table, tableStyles.scrollable)}>
|
||||
<table className={classNames(!data && tableStyles.empty)}>
|
||||
<colgroup>
|
||||
<col className={styles.applicationName} />
|
||||
<col />
|
||||
</colgroup>
|
||||
|
||||
<thead>
|
||||
<tr>
|
||||
<th>{t('applications.application_name')}</th>
|
||||
<th>{t('applications.app_id')}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
{!data && error && (
|
||||
<TableError
|
||||
|
@ -129,15 +131,16 @@ const Applications = () => {
|
|||
<div className={styles.pagination}>
|
||||
{!!totalCount && (
|
||||
<Pagination
|
||||
pageCount={Math.ceil(totalCount / pageSize)}
|
||||
pageIndex={pageIndex}
|
||||
totalCount={totalCount}
|
||||
pageSize={pageSize}
|
||||
onChange={(page) => {
|
||||
setQuery({ page: String(page) });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,10 +0,0 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.card {
|
||||
@include _.flex-column;
|
||||
}
|
||||
|
||||
.headline {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
|
@ -1,17 +1,15 @@
|
|||
import AuditLogTable from '@/components/AuditLogTable';
|
||||
import Card from '@/components/Card';
|
||||
import CardTitle from '@/components/CardTitle';
|
||||
|
||||
import * as styles from './index.module.scss';
|
||||
import * as resourcesStyles from '@/scss/resources.module.scss';
|
||||
|
||||
const AuditLogs = () => {
|
||||
return (
|
||||
<Card className={styles.card}>
|
||||
<div className={styles.headline}>
|
||||
<div className={resourcesStyles.container}>
|
||||
<div className={resourcesStyles.headline}>
|
||||
<CardTitle title="logs.title" subtitle="logs.subtitle" />
|
||||
</div>
|
||||
<AuditLogTable />
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -1,24 +1,9 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.card {
|
||||
@include _.flex-column;
|
||||
}
|
||||
|
||||
.headline {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tabs {
|
||||
margin-top: _.unit(4);
|
||||
}
|
||||
|
||||
.table {
|
||||
margin-top: _.unit(4);
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.connectorName {
|
||||
width: 360px;
|
||||
}
|
||||
|
|
|
@ -8,7 +8,6 @@ import Plus from '@/assets/images/plus.svg';
|
|||
import SocialConnectorEmptyDark from '@/assets/images/social-connector-empty-dark.svg';
|
||||
import SocialConnectorEmpty from '@/assets/images/social-connector-empty.svg';
|
||||
import Button from '@/components/Button';
|
||||
import Card from '@/components/Card';
|
||||
import CardTitle from '@/components/CardTitle';
|
||||
import TabNav, { TabNavItem } from '@/components/TabNav';
|
||||
import TableEmpty from '@/components/Table/TableEmpty';
|
||||
|
@ -16,6 +15,7 @@ import TableError from '@/components/Table/TableError';
|
|||
import TableLoading from '@/components/Table/TableLoading';
|
||||
import useConnectorGroups from '@/hooks/use-connector-groups';
|
||||
import { useTheme } from '@/hooks/use-theme';
|
||||
import * as resourcesStyles from '@/scss/resources.module.scss';
|
||||
import * as tableStyles from '@/scss/table.module.scss';
|
||||
|
||||
import ConnectorRow from './components/ConnectorRow';
|
||||
|
@ -60,8 +60,8 @@ const Connectors = () => {
|
|||
|
||||
return (
|
||||
<>
|
||||
<Card className={styles.card}>
|
||||
<div className={styles.headline}>
|
||||
<div className={resourcesStyles.container}>
|
||||
<div className={resourcesStyles.headline}>
|
||||
<CardTitle title="connectors.title" subtitle="connectors.subtitle" />
|
||||
{isSocial && (
|
||||
<Button
|
||||
|
@ -80,7 +80,7 @@ const Connectors = () => {
|
|||
<TabNavItem href="/connectors">{t('connectors.tab_email_sms')}</TabNavItem>
|
||||
<TabNavItem href="/connectors/social">{t('connectors.tab_social')}</TabNavItem>
|
||||
</TabNav>
|
||||
<div className={classNames(styles.table, tableStyles.scrollable)}>
|
||||
<div className={classNames(resourcesStyles.table, tableStyles.scrollable)}>
|
||||
<table className={classNames(!data && tableStyles.empty)}>
|
||||
<colgroup>
|
||||
<col className={styles.connectorName} />
|
||||
|
@ -145,7 +145,7 @@ const Connectors = () => {
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
<CreateForm
|
||||
isOpen={Boolean(createType)}
|
||||
type={createType}
|
||||
|
|
|
@ -1,25 +1,17 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.card {
|
||||
@include _.flex-column;
|
||||
}
|
||||
|
||||
.headline {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.filter {
|
||||
margin: _.unit(4) 0;
|
||||
}
|
||||
|
||||
.tableContainer {
|
||||
flex: 1;
|
||||
background-color: var(--color-layer-1);
|
||||
|
||||
>table {
|
||||
>tbody {
|
||||
>tr {
|
||||
>td {
|
||||
> table {
|
||||
> tbody {
|
||||
> tr {
|
||||
> td {
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
|
|
|
@ -10,7 +10,6 @@ import useSWR from 'swr';
|
|||
import Plus from '@/assets/images/plus.svg';
|
||||
import ApplicationName from '@/components/ApplicationName';
|
||||
import Button from '@/components/Button';
|
||||
import Card from '@/components/Card';
|
||||
import CardTitle from '@/components/CardTitle';
|
||||
import DateTime from '@/components/DateTime';
|
||||
import ItemPreview from '@/components/ItemPreview';
|
||||
|
@ -23,6 +22,7 @@ import { generatedPasswordStorageKey } from '@/consts';
|
|||
import { generateAvatarPlaceHolderById } from '@/consts/avatars';
|
||||
import type { RequestError } from '@/hooks/use-api';
|
||||
import * as modalStyles from '@/scss/modal.module.scss';
|
||||
import * as resourcesStyles from '@/scss/resources.module.scss';
|
||||
import * as tableStyles from '@/scss/table.module.scss';
|
||||
|
||||
import CreateForm from './components/CreateForm';
|
||||
|
@ -46,8 +46,8 @@ const Users = () => {
|
|||
const [users, totalCount] = data ?? [];
|
||||
|
||||
return (
|
||||
<Card className={styles.card}>
|
||||
<div className={styles.headline}>
|
||||
<div className={resourcesStyles.container}>
|
||||
<div className={resourcesStyles.headline}>
|
||||
<CardTitle title="users.title" subtitle="users.subtitle" />
|
||||
<Button
|
||||
title="users.create"
|
||||
|
@ -156,15 +156,16 @@ const Users = () => {
|
|||
<div className={styles.pagination}>
|
||||
{!!totalCount && (
|
||||
<Pagination
|
||||
pageCount={Math.ceil(totalCount / pageSize)}
|
||||
pageIndex={pageIndex}
|
||||
totalCount={totalCount}
|
||||
pageSize={pageSize}
|
||||
onChange={(page) => {
|
||||
setQuery({ page: String(page), ...conditional(keyword && { search: keyword }) });
|
||||
}}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</Card>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
|
|
|
@ -5,9 +5,7 @@
|
|||
}
|
||||
|
||||
@mixin main-content-width {
|
||||
max-width: 1168px;
|
||||
min-width: 604px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
@mixin flex-column {
|
||||
|
|
17
packages/console/src/scss/resources.module.scss
Normal file
17
packages/console/src/scss/resources.module.scss
Normal file
|
@ -0,0 +1,17 @@
|
|||
@use '@/scss/underscore' as _;
|
||||
|
||||
.container {
|
||||
width: 100%;
|
||||
@include _.flex-column;
|
||||
|
||||
.headline {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.table {
|
||||
flex: 1;
|
||||
margin-top: _.unit(4);
|
||||
background-color: var(--color-layer-1);
|
||||
}
|
||||
}
|
|
@ -38,6 +38,7 @@ const general = {
|
|||
stay_on_page: 'Auf Seite bleiben',
|
||||
type_to_search: 'Tippe um zu suchen',
|
||||
got_it: 'Got it', // UNTRANSLATED
|
||||
page_info: '{{min, number}}-{{max, number}} of {{total, number}}', // UNTRANSLATED
|
||||
};
|
||||
|
||||
export default general;
|
||||
|
|
|
@ -37,6 +37,7 @@ const general = {
|
|||
stay_on_page: 'Stay on Page',
|
||||
type_to_search: 'Type to search',
|
||||
got_it: 'Got it',
|
||||
page_info: '{{min, number}}-{{max, number}} of {{total, number}}',
|
||||
};
|
||||
|
||||
export default general;
|
||||
|
|
|
@ -38,6 +38,7 @@ const general = {
|
|||
stay_on_page: 'Rester sur la page',
|
||||
type_to_search: 'Type to search', // UNTRANSLATED
|
||||
got_it: 'Got it', // UNTRANSLATED
|
||||
page_info: '{{min, number}}-{{max, number}} of {{total, number}}', // UNTRANSLATED
|
||||
};
|
||||
|
||||
export default general;
|
||||
|
|
|
@ -37,6 +37,7 @@ const general = {
|
|||
stay_on_page: '페이지 유지하기',
|
||||
type_to_search: 'Type to search', // UNTRANSLATED
|
||||
got_it: 'Got it', // UNTRANSLATED
|
||||
page_info: '{{min, number}}-{{max, number}} of {{total, number}}', // UNTRANSLATED
|
||||
};
|
||||
|
||||
export default general;
|
||||
|
|
|
@ -37,6 +37,7 @@ const general = {
|
|||
stay_on_page: 'Ficar na página',
|
||||
type_to_search: 'Type to search', // UNTRANSLATED
|
||||
got_it: 'Got it', // UNTRANSLATED
|
||||
page_info: '{{min, number}}-{{max, number}} of {{total, number}}', // UNTRANSLATED
|
||||
};
|
||||
|
||||
export default general;
|
||||
|
|
|
@ -38,6 +38,7 @@ const general = {
|
|||
stay_on_page: 'Bu sayfada kal',
|
||||
type_to_search: 'Type to search', // UNTRANSLATED
|
||||
got_it: 'Got it', // UNTRANSLATED
|
||||
page_info: '{{min, number}}-{{max, number}} of {{total, number}}', // UNTRANSLATED
|
||||
};
|
||||
|
||||
export default general;
|
||||
|
|
|
@ -37,6 +37,7 @@ const general = {
|
|||
stay_on_page: '留在此页',
|
||||
type_to_search: '输入搜索',
|
||||
got_it: 'Got it', // UNTRANSLATED
|
||||
page_info: '{{min, number}}-{{max, number}} 共 {{total, number}} 条', // UNTRANSLATED
|
||||
};
|
||||
|
||||
export default general;
|
||||
|
|
Loading…
Reference in a new issue