-
-
Notifications
You must be signed in to change notification settings - Fork 440
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(console): add org role details general settings page (#5610)
- Loading branch information
Showing
36 changed files
with
721 additions
and
15 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
packages/console/src/pages/OrganizationRoleDetails/Permissions/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
type Props = { | ||
organizationRoleId: string; | ||
}; | ||
|
||
function Permissions({ organizationRoleId }: Props) { | ||
return <div>TBD</div>; | ||
} | ||
|
||
export default Permissions; |
78 changes: 78 additions & 0 deletions
78
packages/console/src/pages/OrganizationRoleDetails/Settings/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
import { type OrganizationRole } from '@logto/schemas'; | ||
import { useForm } from 'react-hook-form'; | ||
import { toast } from 'react-hot-toast'; | ||
import { useTranslation } from 'react-i18next'; | ||
|
||
import DetailsForm from '@/components/DetailsForm'; | ||
import FormCard from '@/components/FormCard'; | ||
import UnsavedChangesAlertModal from '@/components/UnsavedChangesAlertModal'; | ||
import { organizationRoleLink } from '@/consts'; | ||
import FormField from '@/ds-components/FormField'; | ||
import TextInput from '@/ds-components/TextInput'; | ||
import useApi from '@/hooks/use-api'; | ||
import useDocumentationUrl from '@/hooks/use-documentation-url'; | ||
import { trySubmitSafe } from '@/utils/form'; | ||
|
||
type Props = { | ||
data: OrganizationRole; | ||
onUpdate: (updatedData: OrganizationRole) => void; | ||
}; | ||
|
||
function Settings({ data, onUpdate }: Props) { | ||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); | ||
const { getDocumentationUrl } = useDocumentationUrl(); | ||
const { | ||
register, | ||
handleSubmit, | ||
reset, | ||
formState: { errors, isDirty, isSubmitting }, | ||
} = useForm<OrganizationRole>({ defaultValues: data }); | ||
|
||
const api = useApi(); | ||
|
||
const onSubmit = handleSubmit( | ||
trySubmitSafe(async (formData) => { | ||
const updatedData = await api | ||
.patch(`api/organization-roles/${data.id}`, { json: formData }) | ||
.json<OrganizationRole>(); | ||
reset(updatedData); | ||
onUpdate(updatedData); | ||
toast.success(t('general.saved')); | ||
}) | ||
); | ||
|
||
return ( | ||
<DetailsForm | ||
isDirty={isDirty} | ||
isSubmitting={isSubmitting} | ||
onSubmit={onSubmit} | ||
onDiscard={reset} | ||
> | ||
<FormCard | ||
title="organization_role_details.general.settings" | ||
description="organization_role_details.general.description" | ||
learnMoreLink={{ | ||
href: getDocumentationUrl(organizationRoleLink), | ||
targetBlank: 'noopener', | ||
}} | ||
> | ||
<FormField isRequired title="organization_role_details.general.name_field"> | ||
<TextInput | ||
placeholder="viewer" | ||
error={Boolean(errors.name)} | ||
{...register('name', { required: true })} | ||
/> | ||
</FormField> | ||
<FormField title="organization_role_details.general.description_field"> | ||
<TextInput | ||
placeholder={t('organization_role_details.general.description_field_placeholder')} | ||
{...register('description')} | ||
/> | ||
</FormField> | ||
</FormCard> | ||
<UnsavedChangesAlertModal hasUnsavedChanges={isDirty} /> | ||
</DetailsForm> | ||
); | ||
} | ||
|
||
export default Settings; |
126 changes: 126 additions & 0 deletions
126
packages/console/src/pages/OrganizationRoleDetails/index.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
import { withAppInsights } from '@logto/app-insights/react/AppInsightsReact'; | ||
import { type OrganizationRole } from '@logto/schemas'; | ||
import { useState } from 'react'; | ||
import { toast } from 'react-hot-toast'; | ||
import { useTranslation } from 'react-i18next'; | ||
import { Navigate, Route, Routes, useParams } from 'react-router-dom'; | ||
import useSWR, { useSWRConfig } from 'swr'; | ||
|
||
import Delete from '@/assets/icons/delete.svg'; | ||
import OrgRoleIcon from '@/assets/icons/role-feature.svg'; | ||
import DetailsPage from '@/components/DetailsPage'; | ||
import DetailsPageHeader from '@/components/DetailsPage/DetailsPageHeader'; | ||
import PageMeta from '@/components/PageMeta'; | ||
import ThemedIcon from '@/components/ThemedIcon'; | ||
import { OrganizationRoleDetailsTabs, OrganizationTemplateTabs } from '@/consts'; | ||
import ConfirmModal from '@/ds-components/ConfirmModal'; | ||
import DynamicT from '@/ds-components/DynamicT'; | ||
import TabNav, { TabNavItem } from '@/ds-components/TabNav'; | ||
import useApi, { type RequestError } from '@/hooks/use-api'; | ||
import useTenantPathname from '@/hooks/use-tenant-pathname'; | ||
|
||
import Permissions from './Permissions'; | ||
import Settings from './Settings'; | ||
|
||
const orgRolesPath = `/organization-template/${OrganizationTemplateTabs.OrganizationRoles}`; | ||
|
||
function OrganizationRoleDetails() { | ||
const { t } = useTranslation(undefined, { keyPrefix: 'admin_console' }); | ||
|
||
const { id } = useParams(); | ||
const { navigate } = useTenantPathname(); | ||
|
||
const { data, error, mutate, isLoading } = useSWR<OrganizationRole, RequestError>( | ||
id && `api/organization-roles/${id}` | ||
); | ||
const api = useApi(); | ||
const { mutate: mutateGlobal } = useSWRConfig(); | ||
const [isDeletionAlertOpen, setIsDeletionAlertOpen] = useState(false); | ||
const [isDeleting, setIsDeleting] = useState(false); | ||
|
||
const handleDelete = async () => { | ||
if (!data) { | ||
return; | ||
} | ||
|
||
setIsDeleting(true); | ||
|
||
try { | ||
await api.delete(`api/organization-roles/${data.id}`); | ||
toast.success(t('organization_role_details.deleted', { name: data.name })); | ||
await mutateGlobal('api/roles'); | ||
navigate(orgRolesPath, { replace: true }); | ||
} finally { | ||
setIsDeleting(false); | ||
} | ||
}; | ||
|
||
return ( | ||
<DetailsPage | ||
backLink={orgRolesPath} | ||
backLinkTitle="organization_role_details.back_to_org_roles" | ||
isLoading={isLoading} | ||
error={error} | ||
onRetry={mutate} | ||
> | ||
<PageMeta titleKey="organization_role_details.page_title" /> | ||
{data && ( | ||
<> | ||
<DetailsPageHeader | ||
icon={<ThemedIcon for={OrgRoleIcon} size={60} />} | ||
title={data.name} | ||
primaryTag={t('organization_role_details.org_role')} | ||
identifier={{ name: 'ID', value: data.id }} | ||
actionMenuItems={[ | ||
{ | ||
title: 'general.delete', | ||
icon: <Delete />, | ||
type: 'danger', | ||
onClick: () => { | ||
setIsDeletionAlertOpen(true); | ||
}, | ||
}, | ||
]} | ||
/> | ||
<ConfirmModal | ||
isOpen={isDeletionAlertOpen} | ||
isLoading={isDeleting} | ||
confirmButtonText="general.delete" | ||
onCancel={() => { | ||
setIsDeletionAlertOpen(false); | ||
}} | ||
onConfirm={handleDelete} | ||
> | ||
<DynamicT forKey="organization_role_details.delete_confirm" /> | ||
</ConfirmModal> | ||
<TabNav> | ||
<TabNavItem | ||
href={`${orgRolesPath}/${data.id}/${OrganizationRoleDetailsTabs.Permissions}`} | ||
> | ||
<DynamicT forKey="organization_role_details.permissions.tab" /> | ||
</TabNavItem> | ||
<TabNavItem href={`${orgRolesPath}/${data.id}/${OrganizationRoleDetailsTabs.General}`}> | ||
<DynamicT forKey="organization_role_details.general.tab" /> | ||
</TabNavItem> | ||
</TabNav> | ||
<Routes> | ||
<Route | ||
index | ||
element={<Navigate replace to={OrganizationRoleDetailsTabs.Permissions} />} | ||
/> | ||
<Route | ||
path={OrganizationRoleDetailsTabs.Permissions} | ||
element={<Permissions organizationRoleId={data.id} />} | ||
/> | ||
<Route | ||
path={OrganizationRoleDetailsTabs.General} | ||
element={<Settings data={data} onUpdate={mutate} />} | ||
/> | ||
</Routes> | ||
</> | ||
)} | ||
</DetailsPage> | ||
); | ||
} | ||
|
||
export default withAppInsights(OrganizationRoleDetails); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
packages/phrases/src/locales/de/translation/admin-console/organization-role-details.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
const organization_role_details = { | ||
page_title: 'Organisationsrollendetails', | ||
back_to_org_roles: 'Zurück zu den Org-Rollen', | ||
org_role: 'Org-Rolle', | ||
delete_confirm: | ||
'Dadurch werden die mit dieser Rolle verbundenen Berechtigungen von den betroffenen Benutzern entfernt und die Beziehungen zwischen Organisationsrollen, Mitgliedern in der Organisation und Organisationsberechtigungen gelöscht.', | ||
deleted: 'Organisationsrolle {{name}} wurde erfolgreich gelöscht.', | ||
permissions: { | ||
tab: 'Berechtigungen', | ||
name_column: 'Berechtigung', | ||
description_column: 'Beschreibung', | ||
type_column: 'Berechtigungstyp', | ||
type: { | ||
api: 'API-Berechtigung', | ||
org: 'Org-Berechtigung', | ||
}, | ||
assign_permissions: 'Berechtigungen zuweisen', | ||
}, | ||
general: { | ||
tab: 'Allgemein', | ||
settings: 'Einstellungen', | ||
description: | ||
'Die Organisationsrolle ist eine Gruppierung von Berechtigungen, die Benutzern zugewiesen werden können. Die Berechtigungen müssen aus den vordefinierten Organisationsberechtigungen stammen.', | ||
name_field: 'Name', | ||
description_field: 'Beschreibung', | ||
description_field_placeholder: 'Benutzer mit nur Leseberechtigungen', | ||
}, | ||
}; | ||
|
||
export default Object.freeze(organization_role_details); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.