-
-
Notifications
You must be signed in to change notification settings - Fork 376
Commit
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
@use '@/scss/underscore' as _; | ||
|
||
.filter { | ||
display: flex; | ||
justify-content: space-between; | ||
align-items: center; | ||
|
||
.createButton { | ||
margin-left: _.unit(2); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
import { type OrganizationScope } from '@logto/schemas'; | ||
import { cond } from '@silverhand/essentials'; | ||
import { useTranslation } from 'react-i18next'; | ||
import useSWR from 'swr'; | ||
|
||
import Plus from '@/assets/icons/plus.svg'; | ||
import ActionsButton from '@/components/ActionsButton'; | ||
import Breakable from '@/components/Breakable'; | ||
import Button from '@/ds-components/Button'; | ||
import DynamicT from '@/ds-components/DynamicT'; | ||
import Search from '@/ds-components/Search'; | ||
import Table from '@/ds-components/Table'; | ||
import Tag from '@/ds-components/Tag'; | ||
import { type RequestError } from '@/hooks/use-api'; | ||
import useSearchParametersWatcher from '@/hooks/use-search-parameters-watcher'; | ||
import { buildUrl, formatSearchKeyword } from '@/utils/url'; | ||
|
||
import * as styles from './index.module.scss'; | ||
|
||
function OrgPermissions() { | ||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); | ||
const [{ keyword }, updateSearchParameters] = useSearchParametersWatcher({ | ||
keyword: '', | ||
}); | ||
|
||
const { data, error, mutate, isLoading } = useSWR<OrganizationScope[], RequestError>( | ||
buildUrl('api/organization-scopes', { | ||
...cond(keyword && { q: formatSearchKeyword(keyword) }), | ||
}) | ||
); | ||
|
||
return ( | ||
<Table | ||
rowGroups={[{ key: 'orgPermissions', data }]} | ||
rowIndexKey="id" | ||
columns={[ | ||
{ | ||
title: <DynamicT forKey="organization_template.org_permissions.permission_column" />, | ||
dataIndex: 'name', | ||
colSpan: 7, | ||
render: ({ name }) => { | ||
return ( | ||
<Tag variant="cell"> | ||
<Breakable>{name}</Breakable> | ||
</Tag> | ||
); | ||
}, | ||
}, | ||
{ | ||
title: <DynamicT forKey="organization_template.org_permissions.description_column" />, | ||
dataIndex: 'scopes', | ||
colSpan: 8, | ||
render: ({ description }) => <Breakable>{description ?? '-'}</Breakable>, | ||
}, | ||
{ | ||
title: null, | ||
dataIndex: 'action', | ||
colSpan: 1, | ||
render: (scope) => ( | ||
<ActionsButton | ||
fieldName="organization_template.org_permissions.permission_column" | ||
deleteConfirmation="organizations.organization_permission_delete_confirm" | ||
onEdit={() => { | ||
// Todo @xiaoyijun implement edit | ||
Check warning on line 64 in packages/console/src/pages/OrganizationTemplate/OrgPermissions/index.tsx
|
||
}} | ||
onDelete={async () => { | ||
// Todo @xiaoyijun implement deletion | ||
Check warning on line 67 in packages/console/src/pages/OrganizationTemplate/OrgPermissions/index.tsx
|
||
}} | ||
/> | ||
), | ||
}, | ||
]} | ||
filter={ | ||
<div className={styles.filter}> | ||
<Search | ||
placeholder={t('organization_template.org_roles.search_placeholder')} | ||
defaultValue={keyword} | ||
isClearable={Boolean(keyword)} | ||
onSearch={(keyword) => { | ||
updateSearchParameters({ keyword }); | ||
}} | ||
onClearSearch={() => { | ||
updateSearchParameters({ keyword: '' }); | ||
}} | ||
/> | ||
<Button | ||
title="organization_template.org_roles.create_org_roles" | ||
className={styles.createButton} | ||
type="primary" | ||
size="large" | ||
icon={<Plus />} | ||
onClick={() => { | ||
console.log('Fuck create'); | ||
}} | ||
/> | ||
</div> | ||
} | ||
isLoading={isLoading} | ||
errorMessage={error?.body?.message ?? error?.message} | ||
onRetry={async () => mutate(undefined, true)} | ||
/> | ||
); | ||
} | ||
|
||
export default OrgPermissions; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
@use '@/scss/underscore' as _; | ||
|
||
.permissions { | ||
display: flex; | ||
flex-wrap: wrap; | ||
gap: _.unit(2); | ||
} | ||
|
||
.filter { | ||
display: flex; | ||
flex-direction: row-reverse; | ||
align-items: center; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,97 @@ | ||
import { type OrganizationRoleWithScopes } from '@logto/schemas'; | ||
import useSWR from 'swr'; | ||
|
||
import Plus from '@/assets/icons/plus.svg'; | ||
import OrgRoleIcon from '@/assets/icons/role-feature.svg'; | ||
import Breakable from '@/components/Breakable'; | ||
import ItemPreview from '@/components/ItemPreview'; | ||
import ThemedIcon from '@/components/ThemedIcon'; | ||
import { defaultPageSize } from '@/consts'; | ||
import Button from '@/ds-components/Button'; | ||
import DynamicT from '@/ds-components/DynamicT'; | ||
import Table from '@/ds-components/Table'; | ||
import Tag from '@/ds-components/Tag'; | ||
import { type RequestError } from '@/hooks/use-api'; | ||
import useSearchParametersWatcher from '@/hooks/use-search-parameters-watcher'; | ||
import { buildUrl } from '@/utils/url'; | ||
|
||
import * as styles from './index.module.scss'; | ||
|
||
function OrgRoles() { | ||
const [{ page }, updateSearchParameters] = useSearchParametersWatcher({ | ||
page: 1, | ||
}); | ||
|
||
const { data, error, mutate, isLoading } = useSWR< | ||
[OrganizationRoleWithScopes[], number], | ||
RequestError | ||
>( | ||
buildUrl('api/organization-roles', { | ||
page: String(page), | ||
page_size: String(defaultPageSize), | ||
}) | ||
); | ||
|
||
const [orgRoles, totalCount] = data ?? []; | ||
|
||
return ( | ||
<Table | ||
rowGroups={[{ key: 'orgRoles', data: orgRoles }]} | ||
rowIndexKey="id" | ||
columns={[ | ||
{ | ||
title: <DynamicT forKey="organization_template.org_roles.org_role_column" />, | ||
dataIndex: 'name', | ||
colSpan: 4, | ||
render: ({ name }) => { | ||
return <ItemPreview title={name} icon={<ThemedIcon for={OrgRoleIcon} />} />; | ||
}, | ||
}, | ||
{ | ||
title: <DynamicT forKey="organization_template.org_roles.permissions_column" />, | ||
dataIndex: 'scopes', | ||
colSpan: 12, | ||
render: ({ scopes }) => { | ||
return scopes.length === 0 ? ( | ||
'-' | ||
) : ( | ||
<div className={styles.permissions}> | ||
{scopes.map(({ id, name }) => ( | ||
<Tag key={id} variant="cell"> | ||
<Breakable>{name}</Breakable> | ||
</Tag> | ||
))} | ||
</div> | ||
); | ||
}, | ||
}, | ||
]} | ||
filter={ | ||
<div className={styles.filter}> | ||
<Button | ||
title="organization_template.org_roles.create_org_roles" | ||
type="primary" | ||
size="large" | ||
icon={<Plus />} | ||
onClick={() => { | ||
// Todo @xiaoyijun implment create org role | ||
Check warning on line 77 in packages/console/src/pages/OrganizationTemplate/OrgRoles/index.tsx
|
||
}} | ||
/> | ||
</div> | ||
} | ||
pagination={{ | ||
page, | ||
totalCount, | ||
pageSize: defaultPageSize, | ||
onChange: (page) => { | ||
updateSearchParameters({ page }); | ||
}, | ||
}} | ||
isLoading={isLoading} | ||
errorMessage={error?.body?.message ?? error?.message} | ||
onRetry={async () => mutate(undefined, true)} | ||
/> | ||
); | ||
} | ||
|
||
export default OrgRoles; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
@use '@/scss/underscore' as _; | ||
|
||
.container { | ||
> *:not(:first-child) { | ||
margin-top: _.unit(4); | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,56 @@ | ||
import { withAppInsights } from '@logto/app-insights/react/AppInsightsReact'; | ||
import classNames from 'classnames'; | ||
import { Outlet } from 'react-router-dom'; | ||
|
||
import Research from '@/assets/icons/research.svg'; | ||
import PageMeta from '@/components/PageMeta'; | ||
import { OrganizationTemplateTabs, organizationTemplateLink } from '@/consts'; | ||
import Button from '@/ds-components/Button'; | ||
import CardTitle from '@/ds-components/CardTitle'; | ||
import DynamicT from '@/ds-components/DynamicT'; | ||
import TabNav, { TabNavItem } from '@/ds-components/TabNav'; | ||
import useDocumentationUrl from '@/hooks/use-documentation-url'; | ||
import * as pageLayout from '@/scss/page-layout.module.scss'; | ||
|
||
import * as styles from './index.module.scss'; | ||
|
||
const basePathname = '/organization-template'; | ||
|
||
function OrganizationTemplate() { | ||
const { getDocumentationUrl } = useDocumentationUrl(); | ||
|
||
return ( | ||
<div className={classNames(pageLayout.container, styles.container)}> | ||
<PageMeta titleKey="organization_template.title" /> | ||
<div className={pageLayout.headline}> | ||
<CardTitle | ||
title="organization_template.title" | ||
subtitle="organization_template.subtitle" | ||
learnMoreLink={{ | ||
href: getDocumentationUrl(organizationTemplateLink), | ||
targetBlank: 'noopener', | ||
}} | ||
/> | ||
<Button | ||
icon={<Research />} | ||
title="application_details.check_guide" | ||
type="outline" | ||
onClick={() => { | ||
// Todo @xiaoyijun implement guide | ||
Check warning on line 39 in packages/console/src/pages/OrganizationTemplate/index.tsx
|
||
}} | ||
/> | ||
</div> | ||
<TabNav> | ||
<TabNavItem href={`${basePathname}/${OrganizationTemplateTabs.OrgRoles}`}> | ||
<DynamicT forKey="organization_template.org_roles.tab_name" /> | ||
</TabNavItem> | ||
<TabNavItem href={`${basePathname}/${OrganizationTemplateTabs.OrgPermissions}`}> | ||
<DynamicT forKey="organization_template.org_permissions.tab_name" /> | ||
</TabNavItem> | ||
</TabNav> | ||
<Outlet /> | ||
</div> | ||
); | ||
} | ||
|
||
export default withAppInsights(OrganizationTemplate); |