Revert "feat: knowledge admin role" (#6018)

This commit is contained in:
takatost
2024-07-05 21:31:34 +08:00
committed by GitHub
parent 71c50b7e20
commit 79df8825c8
46 changed files with 350 additions and 1028 deletions

View File

@@ -35,7 +35,6 @@ import CustomPage from '@/app/components/custom/custom-page'
import Modal from '@/app/components/base/modal'
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
import { useProviderContext } from '@/context/provider-context'
import { useAppContext } from '@/context/app-context'
const iconClassName = `
w-4 h-4 ml-3 mr-2
@@ -65,11 +64,8 @@ export default function AccountSetting({
const [activeMenu, setActiveMenu] = useState(activeTab)
const { t } = useTranslation()
const { enableBilling, enableReplaceWebAppLogo } = useProviderContext()
const { isCurrentWorkspaceDatasetOperator } = useAppContext()
const workplaceGroupItems = (() => {
if (isCurrentWorkspaceDatasetOperator)
return []
return [
{
key: 'provider',
@@ -176,9 +172,7 @@ export default function AccountSetting({
{
menuItems.map(menuItem => (
<div key={menuItem.key} className='mb-4'>
{!isCurrentWorkspaceDatasetOperator && (
<div className='px-2 mb-[6px] text-[10px] sm:text-xs font-medium text-gray-500'>{menuItem.name}</div>
)}
<div className='px-2 mb-[6px] text-[10px] sm:text-xs font-medium text-gray-500'>{menuItem.name}</div>
<div>
{
menuItem.items.map(item => (

View File

@@ -29,7 +29,6 @@ const MembersPage = () => {
owner: t('common.members.owner'),
admin: t('common.members.admin'),
editor: t('common.members.editor'),
dataset_operator: t('common.members.datasetOperator'),
normal: t('common.members.normal'),
}
const { locale } = useContext(I18n)

View File

@@ -1,12 +1,13 @@
'use client'
import { useCallback, useState } from 'react'
import { Fragment, useCallback, useMemo, useState } from 'react'
import { useContext } from 'use-context-selector'
import { XMarkIcon } from '@heroicons/react/24/outline'
import { useTranslation } from 'react-i18next'
import { ReactMultiEmail } from 'react-multi-email'
import { Listbox, Transition } from '@headlessui/react'
import { CheckIcon } from '@heroicons/react/20/solid'
import cn from 'classnames'
import s from './index.module.css'
import RoleSelector from './role-selector'
import Modal from '@/app/components/base/modal'
import Button from '@/app/components/base/button'
import { inviteMember } from '@/service/common'
@@ -30,14 +31,29 @@ const InviteModal = ({
const { notify } = useContext(ToastContext)
const { locale } = useContext(I18n)
const [role, setRole] = useState<string>('normal')
const InvitingRoles = useMemo(() => [
{
name: 'normal',
description: t('common.members.normalTip'),
},
{
name: 'editor',
description: t('common.members.editorTip'),
},
{
name: 'admin',
description: t('common.members.adminTip'),
},
], [t])
const [role, setRole] = useState(InvitingRoles[0])
const handleSend = useCallback(async () => {
if (emails.map((email: string) => emailRegex.test(email)).every(Boolean)) {
try {
const { result, invitation_results } = await inviteMember({
url: '/workspaces/current/members/invite-email',
body: { emails, role, language: locale },
body: { emails, role: role.name, language: locale },
})
if (result === 'success') {
@@ -83,9 +99,53 @@ const InviteModal = ({
placeholder={t('common.members.emailPlaceholder') || ''}
/>
</div>
<div className='mb-6'>
<RoleSelector value={role} onChange={setRole} />
</div>
<Listbox value={role} onChange={setRole}>
<div className="relative pb-6">
<Listbox.Button className="relative w-full py-2 pl-3 pr-10 text-left bg-gray-100 outline-none border-none appearance-none text-sm text-gray-900 rounded-lg">
<span className="block truncate capitalize">{t('common.members.invitedAsRole', { role: t(`common.members.${role.name}`) })}</span>
</Listbox.Button>
<Transition
as={Fragment}
leave="transition ease-in duration-200"
leaveFrom="opacity-200"
leaveTo="opacity-0"
>
<Listbox.Options className="absolute w-full py-1 my-2 overflow-auto text-base bg-white rounded-md shadow-lg max-h-60 ring-1 ring-black ring-opacity-5 focus:outline-none sm:text-sm">
{InvitingRoles.map(role =>
<Listbox.Option
key={role.name}
className={({ active }) =>
`${active ? ' bg-gray-50 rounded-xl' : ' bg-transparent'}
cursor-default select-none relative py-2 px-4 mx-2 flex flex-col`
}
value={role}
>
{({ selected }) => (
<div className='flex flex-row'>
<span
className={cn(
'text-indigo-600 mr-2',
'flex items-center',
)}
>
{selected && (<CheckIcon className="h-5 w-5" aria-hidden="true" />)}
</span>
<div className=' flex flex-col flex-grow'>
<span className={`${selected ? 'font-medium' : 'font-normal'} capitalize block truncate`}>
{t(`common.members.${role.name}`)}
</span>
<span className={`${selected ? 'font-medium' : 'font-normal'} capitalize block text-gray-500`}>
{role.description}
</span>
</div>
</div>
)}
</Listbox.Option>,
)}
</Listbox.Options>
</Transition>
</div>
</Listbox>
<Button
tabIndex={0}
className='w-full'

View File

@@ -1,95 +0,0 @@
import { useTranslation } from 'react-i18next'
import cn from 'classnames'
import React, { useState } from 'react'
import { RiArrowDownSLine } from '@remixicon/react'
import { useProviderContext } from '@/context/provider-context'
import {
PortalToFollowElem,
PortalToFollowElemContent,
PortalToFollowElemTrigger,
} from '@/app/components/base/portal-to-follow-elem'
import { Check } from '@/app/components/base/icons/src/vender/line/general'
export type RoleSelectorProps = {
value: string
onChange: (role: string) => void
}
const RoleSelector = ({ value, onChange }: RoleSelectorProps) => {
const { t } = useTranslation()
const [open, setOpen] = useState(false)
const { datasetOperatorEnabled } = useProviderContext()
const toHump = (name: string) => name.replace(/_(\w)/g, (all, letter) => letter.toUpperCase())
return (
<PortalToFollowElem
open={open}
onOpenChange={setOpen}
placement='bottom-start'
offset={4}
>
<div className='relative'>
<PortalToFollowElemTrigger
onClick={() => setOpen(v => !v)}
className='block'
>
<div className={cn('flex items-center px-3 py-2 rounded-lg bg-gray-100 cursor-pointer hover:bg-gray-200', open && 'bg-gray-200')}>
<div className='grow mr-2 text-gray-900 text-sm leading-5'>{t('common.members.invitedAsRole', { role: t(`common.members.${toHump(value)}`) })}</div>
<RiArrowDownSLine className='shrink-0 w-4 h-4 text-gray-700' />
</div>
</PortalToFollowElemTrigger>
<PortalToFollowElemContent className='z-[1002]'>
<div className='relative w-[336px] bg-white rounded-lg border-[0.5px] bg-gray-200 shadow-lg'>
<div className='p-1'>
<div className='p-2 rounded-lg hover:bg-gray-50 cursor-pointer' onClick={() => {
onChange('normal')
setOpen(false)
}}>
<div className='relative pl-5'>
<div className='text-gray-700 text-sm leading-5'>{t('common.members.normal')}</div>
<div className='text-gray-500 text-xs leading-[18px]'>{t('common.members.normalTip')}</div>
{value === 'normal' && <Check className='absolute top-0.5 left-0 w-4 h-4 text-primary-600'/>}
</div>
</div>
<div className='p-2 rounded-lg hover:bg-gray-50 cursor-pointer' onClick={() => {
onChange('editor')
setOpen(false)
}}>
<div className='relative pl-5'>
<div className='text-gray-700 text-sm leading-5'>{t('common.members.editor')}</div>
<div className='text-gray-500 text-xs leading-[18px]'>{t('common.members.editorTip')}</div>
{value === 'editor' && <Check className='absolute top-0.5 left-0 w-4 h-4 text-primary-600'/>}
</div>
</div>
<div className='p-2 rounded-lg hover:bg-gray-50 cursor-pointer' onClick={() => {
onChange('admin')
setOpen(false)
}}>
<div className='relative pl-5'>
<div className='text-gray-700 text-sm leading-5'>{t('common.members.admin')}</div>
<div className='text-gray-500 text-xs leading-[18px]'>{t('common.members.adminTip')}</div>
{value === 'admin' && <Check className='absolute top-0.5 left-0 w-4 h-4 text-primary-600'/>}
</div>
</div>
{datasetOperatorEnabled && (
<div className='p-2 rounded-lg hover:bg-gray-50 cursor-pointer' onClick={() => {
onChange('dataset_operator')
setOpen(false)
}}>
<div className='relative pl-5'>
<div className='text-gray-700 text-sm leading-5'>{t('common.members.datasetOperator')}</div>
<div className='text-gray-500 text-xs leading-[18px]'>{t('common.members.datasetOperatorTip')}</div>
{value === 'dataset_operator' && <Check className='absolute top-0.5 left-0 w-4 h-4 text-primary-600'/>}
</div>
</div>
)}
</div>
</div>
</PortalToFollowElemContent>
</div>
</PortalToFollowElem>
)
}
export default RoleSelector

View File

@@ -1,12 +1,11 @@
'use client'
import { useTranslation } from 'react-i18next'
import { Fragment, useMemo } from 'react'
import { Fragment } from 'react'
import { useContext } from 'use-context-selector'
import { Menu, Transition } from '@headlessui/react'
import cn from 'classnames'
import { CheckIcon, ChevronDownIcon } from '@heroicons/react/24/outline'
import s from './index.module.css'
import { useProviderContext } from '@/context/provider-context'
import type { Member } from '@/models/common'
import { deleteMemberOrCancelInvitation, updateMemberRole } from '@/service/common'
import { ToastContext } from '@/app/components/base/toast'
@@ -34,22 +33,13 @@ const Operation = ({
onOperate,
}: IOperationProps) => {
const { t } = useTranslation()
const { datasetOperatorEnabled } = useProviderContext()
const RoleMap = {
owner: t('common.members.owner'),
admin: t('common.members.admin'),
editor: t('common.members.editor'),
normal: t('common.members.normal'),
dataset_operator: t('common.members.datasetOperator'),
}
const roleList = useMemo(() => {
return [
...['admin', 'editor', 'normal'],
...(datasetOperatorEnabled ? ['dataset_operator'] : []),
]
}, [datasetOperatorEnabled])
const { notify } = useContext(ToastContext)
const toHump = (name: string) => name.replace(/_(\w)/g, (all, letter) => letter.toUpperCase())
const handleDeleteMemberOrCancelInvitation = async () => {
try {
await deleteMemberOrCancelInvitation({ url: `/workspaces/current/members/${member.id}` })
@@ -109,7 +99,7 @@ const Operation = ({
>
<div className="px-1 py-1">
{
roleList.map(role => (
['admin', 'editor', 'normal'].map(role => (
<Menu.Item key={role}>
<div className={itemClassName} onClick={() => handleUpdateMemberRole(role)}>
{
@@ -118,8 +108,8 @@ const Operation = ({
: <div className={itemIconClassName} />
}
<div>
<div className={itemTitleClassName}>{t(`common.members.${toHump(role)}`)}</div>
<div className={itemDescClassName}>{t(`common.members.${toHump(role)}Tip`)}</div>
<div className={itemTitleClassName}>{t(`common.members.${role}`)}</div>
<div className={itemDescClassName}>{t(`common.members.${role}Tip`)}</div>
</div>
</div>
</Menu.Item>