1069 lines
33 KiB
TypeScript
1069 lines
33 KiB
TypeScript
import { ActionLink, ColumnDef, DataTable, Loading } from '@/components/shared'
|
||
import AdaptableCard from '@/components/shared/AdaptableCard'
|
||
import Container from '@/components/shared/Container'
|
||
import {
|
||
Button,
|
||
Card,
|
||
Dialog,
|
||
FormContainer,
|
||
FormItem,
|
||
Input,
|
||
Notification,
|
||
Select,
|
||
Table,
|
||
Tabs,
|
||
toast,
|
||
} from '@/components/ui'
|
||
import TBody from '@/components/ui/Table/TBody'
|
||
import Td from '@/components/ui/Table/Td'
|
||
import Th from '@/components/ui/Table/Th'
|
||
import THead from '@/components/ui/Table/THead'
|
||
import Tr from '@/components/ui/Table/Tr'
|
||
import TabContent from '@/components/ui/Tabs/TabContent'
|
||
import TabList from '@/components/ui/Tabs/TabList'
|
||
import TabNav from '@/components/ui/Tabs/TabNav'
|
||
import { getRoles, getUsers } from '@/services/identity.service'
|
||
import { IdentityRoleDto, IdentityUserDto } from '@/proxy/admin/models'
|
||
import {
|
||
CreateUpdateOrganizationUnitDto,
|
||
OrganizationUnitDto,
|
||
} from '@/proxy/admin/organization-unit/models'
|
||
import {
|
||
ouDelete,
|
||
ouDeleteMembers,
|
||
ouDeleteRoles,
|
||
ouGetAll,
|
||
ouGetMembers,
|
||
ouGetRoles,
|
||
ouMoveAllUsers,
|
||
ouPost,
|
||
ouPut,
|
||
ouPutMembers,
|
||
ouPutMove,
|
||
ouPutRoles,
|
||
} from '@/services/organization-unit.service'
|
||
import { SelectBoxOption } from '@/shared/types'
|
||
import { useLocalization } from '@/utils/hooks/useLocalization'
|
||
import TableNoRecords from '@/views/shared/TableNoRecords'
|
||
import classNames from 'classnames'
|
||
import { Field, FieldProps, Form, Formik, FormikHelpers } from 'formik'
|
||
import isEmpty from 'lodash/isEmpty'
|
||
import { memo, Suspense, useEffect, useMemo, useState } from 'react'
|
||
import { NodeApi, NodeRendererProps } from 'react-arborist'
|
||
import { Tree } from 'react-arborist/dist/module/components/tree'
|
||
import { Helmet } from 'react-helmet'
|
||
import { FaFolder, FaMinusCircle, FaPlusCircle, FaTrash } from 'react-icons/fa'
|
||
import { HiBadgeCheck, HiUser } from 'react-icons/hi'
|
||
import {
|
||
MdAccountTree,
|
||
MdAddModerator,
|
||
MdAdUnits,
|
||
MdDelete,
|
||
MdEdit,
|
||
MdGroup,
|
||
MdPersonAdd,
|
||
MdSupervisedUserCircle,
|
||
} from 'react-icons/md'
|
||
import { object, string } from 'yup'
|
||
|
||
const schema = object().shape({
|
||
id: string(),
|
||
parentId: string(),
|
||
displayName: string().required(),
|
||
})
|
||
|
||
const schemaMoveAllUsers = object().shape({
|
||
id: string().required(),
|
||
newId: string().required(),
|
||
})
|
||
|
||
interface TreeViewData {
|
||
id: string
|
||
name: string
|
||
children?: TreeViewData[]
|
||
}
|
||
|
||
const convertToTreeViewData = (
|
||
items: (OrganizationUnitDto & { isAdded?: boolean })[],
|
||
parentId?: string,
|
||
) => {
|
||
const levelItems = items.filter((a) => a.parentId == parentId)
|
||
if (!levelItems?.length) {
|
||
return
|
||
}
|
||
|
||
const data: TreeViewData[] = []
|
||
|
||
for (let item of levelItems) {
|
||
if (!item.id || item.isAdded) {
|
||
continue
|
||
}
|
||
|
||
item.isAdded = true
|
||
data.push({
|
||
id: item.id,
|
||
name: item.displayName,
|
||
children: convertToTreeViewData(items, item.id),
|
||
})
|
||
}
|
||
|
||
return data
|
||
}
|
||
|
||
interface DeleteTypeData {
|
||
id: string
|
||
name: 'Organization Unit' | 'User' | 'Role'
|
||
}
|
||
|
||
const OrganizationUnits = () => {
|
||
const [loading, setLoading] = useState(true)
|
||
const [ous, setOus] = useState<SelectBoxOption[]>([])
|
||
const [list, setList] = useState<TreeViewData[]>([])
|
||
const [activeOu, setActiveOu] = useState<string>()
|
||
const [dialogItem, setDialogItem] = useState<CreateUpdateOrganizationUnitDto | undefined>()
|
||
const [ouMembers, setOuMembers] = useState<IdentityUserDto[]>([])
|
||
const [userSelectionList, setUserSelectionList] = useState<IdentityUserDto[]>([])
|
||
const [userSelectedRows, setUserSelectedRows] = useState<string[]>([])
|
||
const [roleSelectionList, setRoleSelectionList] = useState<IdentityRoleDto[]>([])
|
||
const [ouRoles, setOuRoles] = useState<IdentityRoleDto[]>([])
|
||
const [roleSelectedRows, setRoleSelectedRows] = useState<string[]>([])
|
||
const [deleteRow, setDeleteRow] = useState<DeleteTypeData | null>()
|
||
const [isMoveAllUsersOpen, setIsMoveAllUsersOpen] = useState(false)
|
||
const [treeSearch, setTreeSearch] = useState('')
|
||
|
||
const { translate } = useLocalization()
|
||
|
||
const userSelectionColumns: ColumnDef<IdentityUserDto>[] = useMemo(
|
||
() => [
|
||
{
|
||
header: 'Name',
|
||
accessorKey: 'fullName',
|
||
cell: ({ row }) => (
|
||
<>
|
||
{row.original.name} {row.original.surname}
|
||
</>
|
||
),
|
||
},
|
||
{
|
||
header: 'Email',
|
||
accessorKey: 'email',
|
||
},
|
||
],
|
||
[],
|
||
)
|
||
|
||
const roleSelectionColumns: ColumnDef<IdentityRoleDto>[] = useMemo(
|
||
() => [
|
||
{
|
||
header: 'Name',
|
||
accessorKey: 'Name',
|
||
cell: ({ row }) => <>{row.original.name}</>,
|
||
},
|
||
],
|
||
[],
|
||
)
|
||
|
||
const handleUserRowSelect = (checked: boolean, row: IdentityUserDto) => {
|
||
if (checked) {
|
||
const newState = [...userSelectedRows, row.id!]
|
||
setUserSelectedRows(newState)
|
||
} else {
|
||
const newState = [...userSelectedRows.filter((id) => id !== row.id)]
|
||
setUserSelectedRows(newState)
|
||
}
|
||
}
|
||
|
||
const handleRoleRowSelect = (checked: boolean, row: IdentityRoleDto) => {
|
||
if (checked) {
|
||
const newState = [...roleSelectedRows, row.id!]
|
||
setRoleSelectedRows(newState)
|
||
} else {
|
||
const newState = [...roleSelectedRows.filter((id) => id !== row.id)]
|
||
setRoleSelectedRows(newState)
|
||
}
|
||
}
|
||
|
||
const fetchData = async () => {
|
||
setLoading(true)
|
||
const response = await ouGetAll()
|
||
if (response.data?.items) {
|
||
setOus(
|
||
response.data.items.map((a) => ({
|
||
value: a.id,
|
||
label: a.displayName,
|
||
})),
|
||
)
|
||
var list = convertToTreeViewData(response.data.items) ?? []
|
||
setList(list)
|
||
}
|
||
setLoading(false)
|
||
}
|
||
|
||
useEffect(() => {
|
||
if (isEmpty(list)) {
|
||
fetchData()
|
||
}
|
||
}, [])
|
||
|
||
const handleDialogSubmit = async (
|
||
values: CreateUpdateOrganizationUnitDto,
|
||
{ setSubmitting }: FormikHelpers<CreateUpdateOrganizationUnitDto>,
|
||
) => {
|
||
setLoading(true)
|
||
setSubmitting(true)
|
||
|
||
try {
|
||
if (values.id) {
|
||
await ouPut(values)
|
||
} else {
|
||
await ouPost(values)
|
||
}
|
||
toast.push(
|
||
<Notification type="success" duration={2000}>
|
||
{translate('::Kaydet')}
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
|
||
fetchData()
|
||
onDialogClose()
|
||
} catch (error) {
|
||
toast.push(
|
||
<Notification type="danger" duration={2000}>
|
||
Hata
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
} finally {
|
||
setLoading(false)
|
||
setSubmitting(false)
|
||
}
|
||
}
|
||
|
||
const onDialogClose = () => {
|
||
setDialogItem(undefined)
|
||
}
|
||
|
||
const onDropdownItemClick = (node: NodeApi<TreeViewData>, eventKey: string) => {
|
||
if (eventKey == 'edit') {
|
||
setDialogItem({
|
||
id: node.data.id,
|
||
displayName: node.data.name,
|
||
parentId: node.parent?.isRoot ? undefined : node.parent?.data.id,
|
||
})
|
||
} else if (eventKey == 'add-sub-unit') {
|
||
setDialogItem({
|
||
displayName: '',
|
||
parentId: node.data.id,
|
||
})
|
||
} else if (eventKey == 'delete') {
|
||
setDeleteRow({ id: node.data.id, name: 'Organization Unit' })
|
||
}
|
||
}
|
||
|
||
const onSelect = async (nodes: NodeApi<TreeViewData>[]) => {
|
||
if (nodes.length === 0) {
|
||
setActiveOu(undefined)
|
||
} else {
|
||
const node = nodes[0]
|
||
setActiveOu(node.data.id)
|
||
}
|
||
}
|
||
|
||
const fetchUsersAndRoles = async (id: string) => {
|
||
try {
|
||
setLoading(true)
|
||
const memberList = await ouGetMembers(id)
|
||
const members = memberList.data?.items ?? []
|
||
setOuMembers(members)
|
||
setUserSelectedRows(members.map((a) => a.id!))
|
||
|
||
const roleList = await ouGetRoles(id)
|
||
const roles = roleList.data?.items ?? []
|
||
setOuRoles(roles)
|
||
setRoleSelectedRows(roles.map((a) => a.id!))
|
||
} catch (error) {
|
||
toast.push(
|
||
<Notification type="danger" duration={2000}>
|
||
Hata
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
useEffect(() => {
|
||
const fn = async () => {
|
||
setOuMembers([])
|
||
setUserSelectedRows([])
|
||
setOuRoles([])
|
||
setRoleSelectedRows([])
|
||
|
||
if (activeOu) {
|
||
await fetchUsersAndRoles(activeOu)
|
||
}
|
||
}
|
||
fn()
|
||
}, [activeOu])
|
||
|
||
const handleEdit = async (id: string, name: string) => {
|
||
setLoading(true)
|
||
|
||
try {
|
||
if (!id) {
|
||
return
|
||
}
|
||
|
||
await ouPut({ id, displayName: name })
|
||
toast.push(
|
||
<Notification type="success" duration={2000}>
|
||
{translate('::Kaydet')}
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
|
||
fetchData()
|
||
} catch (error) {
|
||
toast.push(
|
||
<Notification type="danger" duration={2000}>
|
||
Hata
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
const handleMove = async (id: string, newParentId?: string) => {
|
||
setLoading(true)
|
||
|
||
try {
|
||
if (!id) {
|
||
return
|
||
}
|
||
|
||
await ouPutMove(id, newParentId)
|
||
toast.push(
|
||
<Notification type="success" duration={2000}>
|
||
{translate('::Kaydet')}
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
|
||
fetchData()
|
||
} catch (error) {
|
||
toast.push(
|
||
<Notification type="danger" duration={2000}>
|
||
Hata
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}
|
||
|
||
const Node = memo(({ node, style, dragHandle }: NodeRendererProps<any>) => {
|
||
return (
|
||
<div
|
||
className={classNames(
|
||
'h-6 text-md flex gap-2 items-center',
|
||
node.isSelected ? 'bg-indigo-200' : '',
|
||
)}
|
||
style={style}
|
||
ref={dragHandle}
|
||
>
|
||
<div
|
||
className="flex items-center h-full w-full"
|
||
onClick={() => node.isInternal && node.toggle()}
|
||
>
|
||
<div className="w-3">
|
||
{node.isInternal && (node.isOpen ? <FaMinusCircle /> : <FaPlusCircle />)}
|
||
</div>
|
||
|
||
<FaFolder className="ml-2 w-3" color="#337ab7" />
|
||
|
||
<span className="node-text m-1">
|
||
{node.isEditing ? (
|
||
<Input
|
||
className="h-4"
|
||
type="text"
|
||
defaultValue={node.data.name}
|
||
onBlur={() => node.reset()}
|
||
onKeyDown={(e) => {
|
||
if (e.key === 'Escape') {
|
||
node.reset()
|
||
}
|
||
if (e.key === 'Enter') {
|
||
node.submit(e.currentTarget.value)
|
||
}
|
||
}}
|
||
autoFocus
|
||
/>
|
||
) : (
|
||
<span>{node.data.name}</span>
|
||
)}
|
||
</span>
|
||
</div>
|
||
|
||
<div className="file-actions">
|
||
<div className="flex gap-1 folderFileActions">
|
||
<button
|
||
onClick={() => setIsMoveAllUsersOpen(true)}
|
||
title={translate('::Abp.Identity.OrganizationUnit.MoveAllUsers')}
|
||
>
|
||
<MdSupervisedUserCircle size="20" color="#2d6da3" />
|
||
</button>
|
||
<button
|
||
onClick={() => node.edit()}
|
||
title={translate('::Abp.Identity.OrganizationUnit.Rename')}
|
||
>
|
||
<MdEdit size="20" className="text-teal-900" />
|
||
</button>
|
||
<button
|
||
onClick={() => setDeleteRow({ id: node.data.id, name: 'Organization Unit' })}
|
||
title={translate('::Delete')}
|
||
>
|
||
<MdDelete size="20" className="text-red-500" />
|
||
</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
)
|
||
})
|
||
|
||
return (
|
||
<>
|
||
<Helmet
|
||
titleTemplate="%s | Kurs Platform"
|
||
title={translate('::Abp.Identity.OrganizationUnits')}
|
||
defaultTitle="Kurs Platform"
|
||
></Helmet>
|
||
<Loading type="cover" loading={loading}>
|
||
<Container>
|
||
<div className="flex flex-col lg:flex-row gap-4">
|
||
<Card
|
||
className="md:w-3/12 min-w-fit"
|
||
header={translate('::Abp.Identity.OrganizationUnits')}
|
||
headerExtra={
|
||
<div className="flex gap-1">
|
||
<Button
|
||
variant="solid"
|
||
size="xs"
|
||
title={translate('::Abp.Identity.OrganizationUnit.AddUnit')}
|
||
onClick={(e) => {
|
||
e.preventDefault()
|
||
setDialogItem({
|
||
parentId: activeOu,
|
||
displayName: '',
|
||
})
|
||
}}
|
||
>
|
||
{activeOu ? <MdAccountTree /> : <MdAdUnits />}
|
||
</Button>
|
||
|
||
<Button
|
||
variant="solid"
|
||
size="xs"
|
||
title={translate('::Abp.Identity.OrganizationUnit.MoveAllUsers')}
|
||
onClick={(e) => {
|
||
e.preventDefault()
|
||
setIsMoveAllUsersOpen(true)
|
||
}}
|
||
>
|
||
<MdGroup />
|
||
</Button>
|
||
</div>
|
||
}
|
||
>
|
||
<Input
|
||
className="h-8"
|
||
type="text"
|
||
placeholder={translate('::App.Search')}
|
||
value={treeSearch}
|
||
onChange={(e) => {
|
||
setTreeSearch(e.target.value)
|
||
}}
|
||
/>
|
||
<Tree
|
||
openByDefault={false}
|
||
data={list}
|
||
onSelect={onSelect}
|
||
onMove={({ dragIds, parentId }) => {
|
||
if (dragIds.length > 0) {
|
||
handleMove(dragIds[0], parentId ?? '')
|
||
}
|
||
}}
|
||
onRename={({ id, name }) => {
|
||
handleEdit(id, name)
|
||
}}
|
||
className="mt-2 cursor-pointer"
|
||
searchTerm={treeSearch}
|
||
indent={10}
|
||
searchMatch={(node, term) =>
|
||
node.data.name.toLowerCase().includes(term.toLowerCase())
|
||
}
|
||
width={'100%'}
|
||
>
|
||
{Node}
|
||
</Tree>
|
||
</Card>
|
||
<Card className="md:w-9/12 w-full">
|
||
<Tabs defaultValue="users">
|
||
<TabList>
|
||
<TabNav value="users" icon={<HiUser />}>
|
||
{translate('::AbpIdentity.Users')}
|
||
</TabNav>
|
||
<TabNav value="roles" icon={<HiBadgeCheck />}>
|
||
{translate('::AbpIdentity.Roles')}
|
||
</TabNav>
|
||
</TabList>
|
||
<TabContent value="users">
|
||
{activeOu ? (
|
||
<AdaptableCard
|
||
headerClass="text-right"
|
||
header={
|
||
<Button
|
||
variant="solid"
|
||
size="sm"
|
||
onClick={async (e) => {
|
||
e.preventDefault()
|
||
const response = await getUsers(0, 1000)
|
||
setUserSelectionList(response.data?.items ?? [])
|
||
}}
|
||
>
|
||
<MdPersonAdd />
|
||
</Button>
|
||
}
|
||
>
|
||
<Table compact>
|
||
{!!ouMembers.length && (
|
||
<THead>
|
||
<Tr>
|
||
<Th></Th>
|
||
<Th>Adı Soyadı</Th>
|
||
<Th>E-Posta</Th>
|
||
<Th>Durum</Th>
|
||
</Tr>
|
||
</THead>
|
||
)}
|
||
<TBody>
|
||
{ouMembers.map((user) => (
|
||
<Tr key={user.id}>
|
||
<Td>
|
||
<Button
|
||
className="mr-auto"
|
||
type="button"
|
||
size="xs"
|
||
onClick={() => {
|
||
setDeleteRow({
|
||
id: user.id ?? '',
|
||
name: 'User',
|
||
})
|
||
}}
|
||
>
|
||
<FaTrash />
|
||
</Button>
|
||
</Td>
|
||
<Td>
|
||
<ActionLink
|
||
href={`/admin/identity/users/${user.id}/details`}
|
||
className="font-bold"
|
||
target="_blank"
|
||
>
|
||
{user.name} {user.surname}
|
||
</ActionLink>
|
||
</Td>
|
||
<Td>{user.email}</Td>
|
||
<Td>{user.isActive ? 'Aktif' : 'Pasif'}</Td>
|
||
</Tr>
|
||
))}
|
||
<TableNoRecords show={!ouMembers.length} />
|
||
</TBody>
|
||
</Table>
|
||
</AdaptableCard>
|
||
) : (
|
||
<div className="p-3">
|
||
{translate('::Abp.Identity.OrganizationUnit.Users.Description')}
|
||
</div>
|
||
)}
|
||
</TabContent>
|
||
<TabContent value="roles">
|
||
{activeOu ? (
|
||
<AdaptableCard
|
||
headerClass="text-right"
|
||
header={
|
||
<Button
|
||
variant="solid"
|
||
size="sm"
|
||
onClick={async (e) => {
|
||
e.preventDefault()
|
||
const response = await getRoles(0, 1000)
|
||
setRoleSelectionList(response.data?.items ?? [])
|
||
}}
|
||
>
|
||
<MdPersonAdd />
|
||
</Button>
|
||
}
|
||
>
|
||
<Table compact>
|
||
{!!ouRoles.length && (
|
||
<THead>
|
||
<Tr>
|
||
<Th></Th>
|
||
<Th>Rol</Th>
|
||
</Tr>
|
||
</THead>
|
||
)}
|
||
<TBody>
|
||
{ouRoles.map((role) => (
|
||
<Tr key={role.id}>
|
||
<Td>
|
||
<Button
|
||
className="mr-auto"
|
||
type="button"
|
||
size="xs"
|
||
onClick={() => {
|
||
setDeleteRow({
|
||
id: role.id ?? '',
|
||
name: 'Role',
|
||
})
|
||
}}
|
||
>
|
||
<FaTrash />
|
||
</Button>
|
||
</Td>
|
||
<Td>{role.name}</Td>
|
||
</Tr>
|
||
))}
|
||
<TableNoRecords show={!ouRoles.length} />
|
||
</TBody>
|
||
</Table>
|
||
</AdaptableCard>
|
||
) : (
|
||
<div className="p-3">
|
||
{translate('::Abp.Identity.OrganizationUnit.Roles.Description')}
|
||
</div>
|
||
)}
|
||
</TabContent>
|
||
</Tabs>
|
||
</Card>
|
||
</div>
|
||
</Container>
|
||
</Loading>
|
||
|
||
<Dialog isOpen={!!dialogItem} onClose={onDialogClose} onRequestClose={onDialogClose}>
|
||
<h5 className="mb-4">{translate('::Abp.Identity.OrganizationUnit.NewUnit')}</h5>
|
||
<hr className="my-2"></hr>
|
||
<Suspense fallback={<></>}>
|
||
<Formik
|
||
initialValues={dialogItem ?? ({ displayName: '' } as CreateUpdateOrganizationUnitDto)}
|
||
validationSchema={schema}
|
||
onSubmit={handleDialogSubmit}
|
||
>
|
||
{({ touched, errors, isSubmitting }) => {
|
||
return (
|
||
<Form>
|
||
<FormContainer size="sm">
|
||
<FormItem
|
||
label={translate('::Abp.Identity.OrganizationUnit.Parent')}
|
||
invalid={errors.parentId && touched.parentId}
|
||
errorMessage={errors.parentId}
|
||
>
|
||
{/* Parent Name göster */}
|
||
<Field
|
||
type="text"
|
||
disabled
|
||
autoComplete="off"
|
||
name="parentId"
|
||
component={Input}
|
||
/>
|
||
</FormItem>
|
||
|
||
<FormItem
|
||
label={translate('::Abp.Identity.OrganizationUnit.DisplayName')}
|
||
invalid={errors.displayName && touched.displayName}
|
||
errorMessage={errors.displayName}
|
||
>
|
||
<Field
|
||
type="text"
|
||
autoComplete="off"
|
||
name="displayName"
|
||
component={Input}
|
||
autoFocus
|
||
/>
|
||
</FormItem>
|
||
|
||
<div className="mt-6 flex flex-row justify-end gap-3">
|
||
<Button variant="solid" loading={isSubmitting} type="submit">
|
||
{isSubmitting ? translate('::...') : translate('::Save')}
|
||
</Button>
|
||
<Button type="button" variant="plain" onClick={onDialogClose}>
|
||
{translate('::Cancel')}
|
||
</Button>
|
||
</div>
|
||
</FormContainer>
|
||
</Form>
|
||
)
|
||
}}
|
||
</Formik>
|
||
</Suspense>
|
||
</Dialog>
|
||
|
||
<Dialog
|
||
id="userSelection"
|
||
isOpen={userSelectionList.length > 0}
|
||
onClose={() => setUserSelectionList([])}
|
||
onRequestClose={() => setUserSelectionList([])}
|
||
>
|
||
<h5 className="mb-4">{translate('::Abp.Identity.OrganizationUnit.SelectMembers')}</h5>
|
||
|
||
<DataTable<IdentityUserDto>
|
||
selectable
|
||
selectedRows={[...userSelectedRows]}
|
||
columns={userSelectionColumns}
|
||
data={userSelectionList}
|
||
loading={loading}
|
||
// pagingData={tableData}
|
||
// onPaginationChange={handlePaginationChange}
|
||
// onSelectChange={handleSelectChange} // Items per page
|
||
// onSort={handleSort}
|
||
onCheckBoxChange={handleUserRowSelect}
|
||
// onIndeterminateCheckBoxChange={handleAllRowSelect}
|
||
/>
|
||
|
||
<div className="text-right mt-6">
|
||
<Button
|
||
className="ltr:mr-2 rtl:ml-2"
|
||
variant="plain"
|
||
onClick={() => {
|
||
setUserSelectionList([])
|
||
}}
|
||
>
|
||
{translate('::Cancel')}
|
||
</Button>
|
||
<Button
|
||
variant="solid"
|
||
onClick={async () => {
|
||
if (!activeOu) {
|
||
return
|
||
}
|
||
|
||
try {
|
||
setLoading(true)
|
||
await ouPutMembers(activeOu, userSelectedRows)
|
||
toast.push(
|
||
<Notification type="success" duration={2000}>
|
||
Updated
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
await fetchUsersAndRoles(activeOu)
|
||
setUserSelectionList([])
|
||
} catch (error) {
|
||
toast.push(
|
||
<Notification type="danger" duration={2000}>
|
||
Hata
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}}
|
||
>
|
||
{translate('::Abp.Identity.OrganizationUnit.AddMembers')}
|
||
</Button>
|
||
</div>
|
||
</Dialog>
|
||
|
||
<Dialog
|
||
id="roleSelection"
|
||
isOpen={roleSelectionList.length > 0}
|
||
onClose={() => setRoleSelectionList([])}
|
||
onRequestClose={() => setRoleSelectionList([])}
|
||
>
|
||
<h5 className="mb-4">{translate('::Abp.Identity.OrganizationUnit.SelectRoles')}</h5>
|
||
|
||
<DataTable<IdentityRoleDto>
|
||
selectable
|
||
selectedRows={[...roleSelectedRows]}
|
||
columns={roleSelectionColumns}
|
||
data={roleSelectionList}
|
||
loading={loading}
|
||
// pagingData={tableData}
|
||
// onPaginationChange={handlePaginationChange}
|
||
// onSelectChange={handleSelectChange} // Items per page
|
||
// onSort={handleSort}
|
||
onCheckBoxChange={handleRoleRowSelect}
|
||
// onIndeterminateCheckBoxChange={handleAllRowSelect}
|
||
/>
|
||
|
||
<div className="text-right mt-6">
|
||
<Button
|
||
className="ltr:mr-2 rtl:ml-2"
|
||
variant="plain"
|
||
onClick={() => {
|
||
setRoleSelectionList([])
|
||
}}
|
||
>
|
||
{translate('::Cancel')}
|
||
</Button>
|
||
<Button
|
||
variant="solid"
|
||
onClick={async () => {
|
||
if (!activeOu) {
|
||
return
|
||
}
|
||
|
||
try {
|
||
setLoading(true)
|
||
await ouPutRoles(activeOu, roleSelectedRows)
|
||
toast.push(
|
||
<Notification type="success" duration={2000}>
|
||
{translate('::ListForms.FormBilgileriKaydedildi')}
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
await fetchUsersAndRoles(activeOu)
|
||
setRoleSelectionList([])
|
||
} catch (error) {
|
||
toast.push(
|
||
<Notification type="danger" duration={2000}>
|
||
Hata
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}}
|
||
>
|
||
{translate('::Abp.Identity.OrganizationUnit.AddRoles')}
|
||
</Button>
|
||
</div>
|
||
</Dialog>
|
||
|
||
<Dialog
|
||
id="confirmDelete"
|
||
isOpen={!!deleteRow}
|
||
onClose={() => setDeleteRow(null)}
|
||
onRequestClose={() => setDeleteRow(null)}
|
||
>
|
||
<h5 className="mb-4">{translate('::Delete')}</h5>
|
||
|
||
<p>{translate('::DeleteConfirmation')}</p>
|
||
|
||
<div className="text-right mt-6">
|
||
<Button
|
||
className="ltr:mr-2 rtl:ml-2"
|
||
variant="plain"
|
||
onClick={() => {
|
||
setDeleteRow(null)
|
||
}}
|
||
>
|
||
{translate('::Cancel')}
|
||
</Button>
|
||
<Button
|
||
variant="solid"
|
||
onClick={async () => {
|
||
if (!deleteRow) {
|
||
return
|
||
}
|
||
|
||
try {
|
||
setLoading(true)
|
||
switch (deleteRow.name) {
|
||
case 'Organization Unit':
|
||
await ouDelete(deleteRow.id)
|
||
await fetchData()
|
||
break
|
||
case 'Role':
|
||
if (activeOu) {
|
||
await ouDeleteRoles(activeOu, deleteRow.id)
|
||
await fetchUsersAndRoles(activeOu)
|
||
}
|
||
break
|
||
case 'User':
|
||
if (activeOu) {
|
||
await ouDeleteMembers(activeOu, deleteRow.id)
|
||
await fetchUsersAndRoles(activeOu)
|
||
}
|
||
break
|
||
default:
|
||
break
|
||
}
|
||
setDeleteRow(null)
|
||
|
||
toast.push(
|
||
<Notification type="success" duration={2000}>
|
||
{translate('::KayitSilindi')}
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
} catch (error) {
|
||
toast.push(
|
||
<Notification type="danger" duration={2000}>
|
||
Hata
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
} finally {
|
||
setLoading(false)
|
||
}
|
||
}}
|
||
>
|
||
{translate('::Delete')}
|
||
</Button>
|
||
</div>
|
||
</Dialog>
|
||
|
||
<Dialog
|
||
id="moveAllUsers"
|
||
isOpen={isMoveAllUsersOpen}
|
||
onClose={() => setIsMoveAllUsersOpen(false)}
|
||
onRequestClose={() => setIsMoveAllUsersOpen(false)}
|
||
>
|
||
<h5 className="mb-4">{translate('::Abp.Identity.OrganizationUnit.MoveAllUsers')}</h5>
|
||
|
||
<Formik
|
||
initialValues={{ id: activeOu, newId: '' }}
|
||
validationSchema={schemaMoveAllUsers}
|
||
onSubmit={async (values, { setSubmitting }) => {
|
||
if (!values.id || values.id === values.newId) {
|
||
return
|
||
}
|
||
|
||
setSubmitting(true)
|
||
try {
|
||
setLoading(true)
|
||
await ouMoveAllUsers(values.id, values.newId)
|
||
toast.push(
|
||
<Notification type="success" duration={2000}>
|
||
{translate('::Abp.Identity.OrganizationUnit.MoveAllUsersMessage')}
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
await fetchUsersAndRoles(values.id)
|
||
setIsMoveAllUsersOpen(false)
|
||
} catch (error) {
|
||
toast.push(
|
||
<Notification type="danger" duration={2000}>
|
||
Hata
|
||
</Notification>,
|
||
{
|
||
placement: 'top-center',
|
||
},
|
||
)
|
||
} finally {
|
||
setSubmitting(false)
|
||
}
|
||
}}
|
||
>
|
||
{({ touched, errors, values, isSubmitting }) => {
|
||
return (
|
||
<Form>
|
||
<FormContainer size="sm">
|
||
<FormItem
|
||
label={translate('::Abp.Identity.OrganizationUnit.CurrentOrganizationUnit')}
|
||
invalid={errors.id && touched.id}
|
||
errorMessage={errors.id}
|
||
>
|
||
<Field
|
||
type="text"
|
||
autoComplete="off"
|
||
name="id"
|
||
placeholder={translate(
|
||
'::Abp.Identity.OrganizationUnit.CurrentOrganizationUnit',
|
||
)}
|
||
>
|
||
{({ field, form }: FieldProps<OrganizationUnitDto>) => (
|
||
<Select
|
||
field={field}
|
||
form={form}
|
||
isClearable={true}
|
||
options={ous}
|
||
value={ous?.filter((option) => option.value === values.id)}
|
||
onChange={(option) => form.setFieldValue(field.name, option?.value)}
|
||
/>
|
||
)}
|
||
</Field>
|
||
</FormItem>
|
||
<FormItem
|
||
label={translate('::Abp.Identity.OrganizationUnit.NewOrganizationUnit')}
|
||
invalid={errors.newId && touched.newId}
|
||
errorMessage={errors.newId}
|
||
>
|
||
<Field
|
||
type="text"
|
||
autoComplete="off"
|
||
name="newId"
|
||
placeholder={translate('::Abp.Identity.OrganizationUnit.NewOrganizationUnit')}
|
||
>
|
||
{({ field, form }: FieldProps<OrganizationUnitDto>) => (
|
||
<Select
|
||
field={field}
|
||
form={form}
|
||
isClearable={true}
|
||
options={ous}
|
||
value={ous?.filter((option) => option.value === values.newId)}
|
||
onChange={(option) => form.setFieldValue(field.name, option?.value)}
|
||
/>
|
||
)}
|
||
</Field>
|
||
</FormItem>
|
||
|
||
<div className="mt-6 flex flex-row justify-end gap-3">
|
||
<Button variant="solid" loading={isSubmitting} type="submit">
|
||
{isSubmitting ? translate('::...') : translate('::Save')}
|
||
</Button>
|
||
<Button
|
||
type="button"
|
||
variant="plain"
|
||
onClick={() => setIsMoveAllUsersOpen(false)}
|
||
>
|
||
{translate('::Cancel')}
|
||
</Button>
|
||
</div>
|
||
</FormContainer>
|
||
</Form>
|
||
)
|
||
}}
|
||
</Formik>
|
||
</Dialog>
|
||
</>
|
||
)
|
||
}
|
||
|
||
export default OrganizationUnits
|