mirror of
https://git.mirrors.martin98.com/https://github.com/langgenius/dify.git
synced 2025-08-16 08:45:55 +08:00
fix: add api
This commit is contained in:
parent
d1de872d86
commit
ab262b8506
@ -437,7 +437,7 @@ const AppCard = ({ app, onRefresh }: AppCardProps) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{showAccessControl && (
|
{showAccessControl && (
|
||||||
<AccessControl onClose={() => setShowAccessControl(false)} />
|
<AccessControl app={app} onClose={() => setShowAccessControl(false)} />
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -480,7 +480,7 @@ const AppInfo = ({ expand }: IAppInfoProps) => {
|
|||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{
|
{
|
||||||
showAccessControl && <AccessControl />
|
showAccessControl && <AccessControl app={appDetail} onClose={() => { setShowAccessControl(false) }} />
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</PortalToFollowElem>
|
</PortalToFollowElem>
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import type { FC, PropsWithChildren } from 'react'
|
import type { FC, PropsWithChildren } from 'react'
|
||||||
import type { AccessControlType } from './access-control-store'
|
|
||||||
import useAccessControlStore from './access-control-store'
|
import useAccessControlStore from './access-control-store'
|
||||||
|
import type { AccessMode } from '@/models/access-control'
|
||||||
|
|
||||||
type AccessControlItemProps = PropsWithChildren<{
|
type AccessControlItemProps = PropsWithChildren<{
|
||||||
type: AccessControlType
|
type: AccessMode
|
||||||
}>
|
}>
|
||||||
|
|
||||||
const AccessControlItem: FC<AccessControlItemProps> = ({ type, children }) => {
|
const AccessControlItem: FC<AccessControlItemProps> = ({ type, children }) => {
|
||||||
|
@ -1,26 +1,28 @@
|
|||||||
import { create } from 'zustand'
|
import { create } from 'zustand'
|
||||||
export enum AccessControlType {
|
import type { AccessControlAccount, AccessControlGroup } from '@/models/access-control'
|
||||||
PUBLIC = 'PUBLIC',
|
import { AccessMode } from '@/models/access-control'
|
||||||
SPECIFIC_GROUPS_MEMBERS = 'SPECIFIC_GROUPS_MEMBERS',
|
import type { App } from '@/types/app'
|
||||||
ORGANIZATION = 'ORGANIZATION',
|
|
||||||
}
|
|
||||||
|
|
||||||
type AccessControlStore = {
|
type AccessControlStore = {
|
||||||
specificGroups: []
|
appId: App['id']
|
||||||
setSpecificGroups: (specificGroups: []) => void
|
setAppId: (appId: App['id']) => void
|
||||||
specificMembers: []
|
specificGroups: AccessControlGroup[]
|
||||||
setSpecificMembers: (specificMembers: []) => void
|
setSpecificGroups: (specificGroups: AccessControlGroup[]) => void
|
||||||
currentMenu: AccessControlType
|
specificMembers: AccessControlAccount[]
|
||||||
setCurrentMenu: (currentMenu: AccessControlType) => void
|
setSpecificMembers: (specificMembers: AccessControlAccount[]) => void
|
||||||
|
currentMenu: AccessMode
|
||||||
|
setCurrentMenu: (currentMenu: AccessMode) => void
|
||||||
}
|
}
|
||||||
|
|
||||||
const useAccessControlStore = create<AccessControlStore>((set) => {
|
const useAccessControlStore = create<AccessControlStore>((set) => {
|
||||||
return {
|
return {
|
||||||
|
appId: '',
|
||||||
|
setAppId: appId => set({ appId }),
|
||||||
specificGroups: [],
|
specificGroups: [],
|
||||||
setSpecificGroups: specificGroups => set({ specificGroups }),
|
setSpecificGroups: specificGroups => set({ specificGroups }),
|
||||||
specificMembers: [],
|
specificMembers: [],
|
||||||
setSpecificMembers: specificMembers => set({ specificMembers }),
|
setSpecificMembers: specificMembers => set({ specificMembers }),
|
||||||
currentMenu: AccessControlType.SPECIFIC_GROUPS_MEMBERS,
|
currentMenu: AccessMode.SPECIFIC_GROUPS_MEMBERS,
|
||||||
setCurrentMenu: currentMenu => set({ currentMenu }),
|
setCurrentMenu: currentMenu => set({ currentMenu }),
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -13,6 +13,7 @@ import classNames from '@/utils/classnames'
|
|||||||
import { useSearchForWhiteListCandidates } from '@/service/access-control'
|
import { useSearchForWhiteListCandidates } from '@/service/access-control'
|
||||||
import type { AccessControlAccount, AccessControlGroup, Subject, SubjectAccount, SubjectGroup } from '@/models/access-control'
|
import type { AccessControlAccount, AccessControlGroup, Subject, SubjectAccount, SubjectGroup } from '@/models/access-control'
|
||||||
import { SubjectType } from '@/models/access-control'
|
import { SubjectType } from '@/models/access-control'
|
||||||
|
import { useSelector } from '@/context/app-context'
|
||||||
|
|
||||||
export default function AddMemberOrGroupDialog() {
|
export default function AddMemberOrGroupDialog() {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
@ -116,6 +117,8 @@ type MemberItemProps = {
|
|||||||
member: AccessControlAccount
|
member: AccessControlAccount
|
||||||
}
|
}
|
||||||
function MemberItem({ member }: MemberItemProps) {
|
function MemberItem({ member }: MemberItemProps) {
|
||||||
|
const currentUser = useSelector(s => s.userProfile)
|
||||||
|
const { t } = useTranslation()
|
||||||
return <BaseItem className='pr-3'>
|
return <BaseItem className='pr-3'>
|
||||||
<Checkbox className='w-4 h-4 shrink-0' />
|
<Checkbox className='w-4 h-4 shrink-0' />
|
||||||
<div className='flex items-center grow'>
|
<div className='flex items-center grow'>
|
||||||
@ -125,7 +128,7 @@ function MemberItem({ member }: MemberItemProps) {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p className='system-sm-medium text-text-secondary mr-1'>{member.name}</p>
|
<p className='system-sm-medium text-text-secondary mr-1'>{member.name}</p>
|
||||||
<p className='system-xs-regular text-text-tertiary'>You</p>
|
{currentUser.email === member.email && <p className='system-xs-regular text-text-tertiary'>({t('common.you')})</p>}
|
||||||
</div>
|
</div>
|
||||||
<p className='system-xs-regular text-text-quaternary'>{member.email}</p>
|
<p className='system-xs-regular text-text-quaternary'>{member.email}</p>
|
||||||
</BaseItem>
|
</BaseItem>
|
||||||
|
@ -2,22 +2,48 @@
|
|||||||
import { Dialog } from '@headlessui/react'
|
import { Dialog } from '@headlessui/react'
|
||||||
import { RiBuildingLine, RiGlobalLine } from '@remixicon/react'
|
import { RiBuildingLine, RiGlobalLine } from '@remixicon/react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useCallback, useEffect } from 'react'
|
||||||
import Button from '../../base/button'
|
import Button from '../../base/button'
|
||||||
|
import Toast from '../../base/toast'
|
||||||
import AccessControlDialog from './access-control-dialog'
|
import AccessControlDialog from './access-control-dialog'
|
||||||
import AccessControlItem from './access-control-item'
|
import AccessControlItem from './access-control-item'
|
||||||
import SpecificGroupsOrMembers, { WebAppSSONotEnabledTip } from './specific-groups-or-members'
|
import SpecificGroupsOrMembers, { WebAppSSONotEnabledTip } from './specific-groups-or-members'
|
||||||
import { AccessControlType } from './access-control-store'
|
import useAccessControlStore from './access-control-store'
|
||||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
import type { App } from '@/types/app'
|
||||||
|
import { AccessMode } from '@/models/access-control'
|
||||||
|
import { useUpdateAccessMode } from '@/service/access-control'
|
||||||
|
|
||||||
type AccessControlProps = {
|
type AccessControlProps = {
|
||||||
|
app: App
|
||||||
onClose: () => void
|
onClose: () => void
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function AccessControl(props: AccessControlProps) {
|
export default function AccessControl(props: AccessControlProps) {
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
||||||
|
const setAppId = useAccessControlStore(s => s.setAppId)
|
||||||
|
const specificGroups = useAccessControlStore(s => s.specificGroups)
|
||||||
|
const specificMembers = useAccessControlStore(s => s.specificMembers)
|
||||||
const hideTip = systemFeatures.enable_web_sso_switch_component && systemFeatures.sso_enforced_for_web
|
const hideTip = systemFeatures.enable_web_sso_switch_component && systemFeatures.sso_enforced_for_web
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
setAppId(props.app.id)
|
||||||
|
}, [props.app, setAppId])
|
||||||
|
|
||||||
|
const { isPending, mutateAsync: updateAccessMode } = useUpdateAccessMode()
|
||||||
|
const handleConfirm = useCallback(async () => {
|
||||||
|
const subjectIds: string[] = []
|
||||||
|
specificGroups.forEach((group) => {
|
||||||
|
subjectIds.push(group.id)
|
||||||
|
})
|
||||||
|
specificMembers.forEach((member) => {
|
||||||
|
subjectIds.push(member.id)
|
||||||
|
},
|
||||||
|
)
|
||||||
|
await updateAccessMode({ appId: props.app.id, subjects: subjectIds })
|
||||||
|
Toast.notify({ type: 'success', message: t('app.accessControlDialog.updateSuccess') })
|
||||||
|
}, [updateAccessMode, props.app, specificGroups, specificMembers, t])
|
||||||
return <AccessControlDialog show onClose={props.onClose}>
|
return <AccessControlDialog show onClose={props.onClose}>
|
||||||
<div className='flex flex-col gap-y-3'>
|
<div className='flex flex-col gap-y-3'>
|
||||||
<div className='pt-6 pr-14 pb-3 pl-6'>
|
<div className='pt-6 pr-14 pb-3 pl-6'>
|
||||||
@ -28,7 +54,7 @@ export default function AccessControl(props: AccessControlProps) {
|
|||||||
<div className='leading-6'>
|
<div className='leading-6'>
|
||||||
<p className='system-sm-medium'>{t('app.accessControlDialog.accessLabel')}</p>
|
<p className='system-sm-medium'>{t('app.accessControlDialog.accessLabel')}</p>
|
||||||
</div>
|
</div>
|
||||||
<AccessControlItem type={AccessControlType.ORGANIZATION}>
|
<AccessControlItem type={AccessMode.ORGANIZATION}>
|
||||||
<div className='flex items-center p-3'>
|
<div className='flex items-center p-3'>
|
||||||
<div className='grow flex items-center gap-x-2'>
|
<div className='grow flex items-center gap-x-2'>
|
||||||
<RiBuildingLine className='w-4 h-4 text-text-primary' />
|
<RiBuildingLine className='w-4 h-4 text-text-primary' />
|
||||||
@ -37,10 +63,10 @@ export default function AccessControl(props: AccessControlProps) {
|
|||||||
{!hideTip && <WebAppSSONotEnabledTip />}
|
{!hideTip && <WebAppSSONotEnabledTip />}
|
||||||
</div>
|
</div>
|
||||||
</AccessControlItem>
|
</AccessControlItem>
|
||||||
<AccessControlItem type={AccessControlType.SPECIFIC_GROUPS_MEMBERS}>
|
<AccessControlItem type={AccessMode.SPECIFIC_GROUPS_MEMBERS}>
|
||||||
<SpecificGroupsOrMembers />
|
<SpecificGroupsOrMembers />
|
||||||
</AccessControlItem>
|
</AccessControlItem>
|
||||||
<AccessControlItem type={AccessControlType.PUBLIC}>
|
<AccessControlItem type={AccessMode.PUBLIC}>
|
||||||
<div className='flex items-center p-3 gap-x-2'>
|
<div className='flex items-center p-3 gap-x-2'>
|
||||||
<RiGlobalLine className='w-4 h-4 text-text-primary' />
|
<RiGlobalLine className='w-4 h-4 text-text-primary' />
|
||||||
<p className='system-sm-medium text-text-primary'>{t('app.accessControlDialog.accessItems.anyone')}</p>
|
<p className='system-sm-medium text-text-primary'>{t('app.accessControlDialog.accessItems.anyone')}</p>
|
||||||
@ -49,7 +75,7 @@ export default function AccessControl(props: AccessControlProps) {
|
|||||||
</div>
|
</div>
|
||||||
<div className='flex items-center justify-end p-6 pt-5 gap-x-2'>
|
<div className='flex items-center justify-end p-6 pt-5 gap-x-2'>
|
||||||
<Button onClick={props.onClose}>{t('common.operation.cancel')}</Button>
|
<Button onClick={props.onClose}>{t('common.operation.cancel')}</Button>
|
||||||
<Button variant='primary'>{t('common.operation.confirm')}</Button>
|
<Button disabled={isPending} loading={isPending} variant='primary' onClick={handleConfirm}>{t('common.operation.confirm')}</Button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</AccessControlDialog>
|
</AccessControlDialog>
|
||||||
|
@ -1,20 +1,34 @@
|
|||||||
'use client'
|
'use client'
|
||||||
import { RiAlertFill, RiCloseCircleFill, RiLockLine, RiOrganizationChart } from '@remixicon/react'
|
import { RiAlertFill, RiCloseCircleFill, RiLockLine, RiOrganizationChart } from '@remixicon/react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
import { useEffect } from 'react'
|
||||||
import Avatar from '../../base/avatar'
|
import Avatar from '../../base/avatar'
|
||||||
import Divider from '../../base/divider'
|
import Divider from '../../base/divider'
|
||||||
import Tooltip from '../../base/tooltip'
|
import Tooltip from '../../base/tooltip'
|
||||||
|
import Loading from '../../base/loading'
|
||||||
import AddMemberOrGroupDialog from './add-member-or-group-pop'
|
import AddMemberOrGroupDialog from './add-member-or-group-pop'
|
||||||
import useAccessControlStore, { AccessControlType } from './access-control-store'
|
import useAccessControlStore from './access-control-store'
|
||||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
import { useGlobalPublicStore } from '@/context/global-public-context'
|
||||||
|
import type { AccessControlAccount, AccessControlGroup } from '@/models/access-control'
|
||||||
|
import { AccessMode } from '@/models/access-control'
|
||||||
|
import { useAppWhiteListSubjects } from '@/service/access-control'
|
||||||
|
|
||||||
export default function SpecificGroupsOrMembers() {
|
export default function SpecificGroupsOrMembers() {
|
||||||
const currentMenu = useAccessControlStore(s => s.currentMenu)
|
const currentMenu = useAccessControlStore(s => s.currentMenu)
|
||||||
|
const appId = useAccessControlStore(s => s.appId)
|
||||||
|
const setSpecificGroups = useAccessControlStore(s => s.setSpecificGroups)
|
||||||
|
const setSpecificMembers = useAccessControlStore(s => s.setSpecificMembers)
|
||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
||||||
const hideTip = systemFeatures.enable_web_sso_switch_component && systemFeatures.sso_enforced_for_web
|
const hideTip = systemFeatures.enable_web_sso_switch_component && systemFeatures.sso_enforced_for_web
|
||||||
|
|
||||||
if (currentMenu !== AccessControlType.SPECIFIC_GROUPS_MEMBERS) {
|
const { isPending, data } = useAppWhiteListSubjects(appId, Boolean(appId) && currentMenu === AccessMode.SPECIFIC_GROUPS_MEMBERS)
|
||||||
|
useEffect(() => {
|
||||||
|
setSpecificGroups(data?.groups ?? [])
|
||||||
|
setSpecificMembers(data?.members ?? [])
|
||||||
|
}, [data, setSpecificGroups, setSpecificMembers])
|
||||||
|
|
||||||
|
if (currentMenu !== AccessMode.SPECIFIC_GROUPS_MEMBERS) {
|
||||||
return <div className='flex items-center p-3'>
|
return <div className='flex items-center p-3'>
|
||||||
<div className='grow flex items-center gap-x-2'>
|
<div className='grow flex items-center gap-x-2'>
|
||||||
<RiLockLine className='w-4 h-4 text-text-primary' />
|
<RiLockLine className='w-4 h-4 text-text-primary' />
|
||||||
@ -40,7 +54,7 @@ export default function SpecificGroupsOrMembers() {
|
|||||||
</div>
|
</div>
|
||||||
<div className='px-1 pb-1'>
|
<div className='px-1 pb-1'>
|
||||||
<div className='bg-background-section rounded-lg p-2 flex flex-col gap-y-2'>
|
<div className='bg-background-section rounded-lg p-2 flex flex-col gap-y-2'>
|
||||||
<RenderGroupsAndMembers />
|
{isPending ? <Loading /> : <RenderGroupsAndMembers />}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div >
|
</div >
|
||||||
@ -65,21 +79,21 @@ function RenderGroupsAndMembers() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type GroupItemProps = {
|
type GroupItemProps = {
|
||||||
group: string
|
group: AccessControlGroup
|
||||||
}
|
}
|
||||||
function GroupItem({ group }: GroupItemProps) {
|
function GroupItem({ group }: GroupItemProps) {
|
||||||
return <BaseItem icon={<RiOrganizationChart className='w-[14px] h-[14px] text-components-avatar-shape-fill-stop-0' />}>
|
return <BaseItem icon={<RiOrganizationChart className='w-[14px] h-[14px] text-components-avatar-shape-fill-stop-0' />}>
|
||||||
<p className='system-xs-regular text-text-primary'>Group Name</p>
|
<p className='system-xs-regular text-text-primary'>{group.name}</p>
|
||||||
<p className='system-xs-regular text-text-tertiary'>7</p>
|
<p className='system-xs-regular text-text-tertiary'>{group.groupSize}</p>
|
||||||
</BaseItem>
|
</BaseItem>
|
||||||
}
|
}
|
||||||
|
|
||||||
type MemberItemProps = {
|
type MemberItemProps = {
|
||||||
member: string
|
member: AccessControlAccount
|
||||||
}
|
}
|
||||||
function MemberItem({ member }: MemberItemProps) {
|
function MemberItem({ member }: MemberItemProps) {
|
||||||
return <BaseItem icon={<Avatar className='w-[14px] h-[14px]' textClassName='text-[12px]' avatar={null} name='M' />}>
|
return <BaseItem icon={<Avatar className='w-[14px] h-[14px]' textClassName='text-[12px]' avatar={null} name={member.name} />}>
|
||||||
<p className='system-xs-regular text-text-primary'>Member Name</p>
|
<p className='system-xs-regular text-text-primary'>{member.name}</p>
|
||||||
</BaseItem>
|
</BaseItem>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,14 +21,12 @@ import type { AppIconType, AppSSO, Language } from '@/types/app'
|
|||||||
import { useToastContext } from '@/app/components/base/toast'
|
import { useToastContext } from '@/app/components/base/toast'
|
||||||
import { LanguagesSupported, languages } from '@/i18n/language'
|
import { LanguagesSupported, languages } from '@/i18n/language'
|
||||||
import Tooltip from '@/app/components/base/tooltip'
|
import Tooltip from '@/app/components/base/tooltip'
|
||||||
import { useAppContext } from '@/context/app-context'
|
|
||||||
import { useProviderContext } from '@/context/provider-context'
|
import { useProviderContext } from '@/context/provider-context'
|
||||||
import { useModalContext } from '@/context/modal-context'
|
import { useModalContext } from '@/context/modal-context'
|
||||||
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
||||||
import AppIconPicker from '@/app/components/base/app-icon-picker'
|
import AppIconPicker from '@/app/components/base/app-icon-picker'
|
||||||
import I18n from '@/context/i18n'
|
import I18n from '@/context/i18n'
|
||||||
import cn from '@/utils/classnames'
|
import cn from '@/utils/classnames'
|
||||||
import { useGlobalPublicStore } from '@/context/global-public-context'
|
|
||||||
|
|
||||||
export type ISettingsModalProps = {
|
export type ISettingsModalProps = {
|
||||||
isChat: boolean
|
isChat: boolean
|
||||||
@ -66,8 +64,6 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
|||||||
onClose,
|
onClose,
|
||||||
onSave,
|
onSave,
|
||||||
}) => {
|
}) => {
|
||||||
const { systemFeatures } = useGlobalPublicStore()
|
|
||||||
const { isCurrentWorkspaceEditor } = useAppContext()
|
|
||||||
const { notify } = useToastContext()
|
const { notify } = useToastContext()
|
||||||
const [isShowMore, setIsShowMore] = useState(false)
|
const [isShowMore, setIsShowMore] = useState(false)
|
||||||
const {
|
const {
|
||||||
@ -139,7 +135,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
|||||||
setAppIcon(icon_type === 'image'
|
setAppIcon(icon_type === 'image'
|
||||||
? { type: 'image', url: icon_url!, fileId: icon }
|
? { type: 'image', url: icon_url!, fileId: icon }
|
||||||
: { type: 'emoji', icon, background: icon_background! })
|
: { type: 'emoji', icon, background: icon_background! })
|
||||||
}, [appInfo])
|
}, [appInfo, chat_color_theme, chat_color_theme_inverted, copyright, custom_disclaimer, default_language, description, icon, icon_background, icon_type, icon_url, privacy_policy, show_workflow_steps, title, use_icon_as_answer_icon])
|
||||||
|
|
||||||
const onHide = () => {
|
const onHide = () => {
|
||||||
onClose()
|
onClose()
|
||||||
@ -325,28 +321,6 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
|||||||
</div>
|
</div>
|
||||||
<p className='pb-0.5 text-text-tertiary body-xs-regular'>{t(`${prefixSettings}.workflow.showDesc`)}</p>
|
<p className='pb-0.5 text-text-tertiary body-xs-regular'>{t(`${prefixSettings}.workflow.showDesc`)}</p>
|
||||||
</div>
|
</div>
|
||||||
{/* SSO */}
|
|
||||||
{systemFeatures.enable_web_sso_switch_component && (
|
|
||||||
<>
|
|
||||||
<Divider className="h-px my-0" />
|
|
||||||
<div className='w-full'>
|
|
||||||
<p className='mb-1 system-xs-medium-uppercase text-text-tertiary'>{t(`${prefixSettings}.sso.label`)}</p>
|
|
||||||
<div className='flex justify-between items-center'>
|
|
||||||
<div className={cn('py-1 text-text-secondary system-sm-semibold')}>{t(`${prefixSettings}.sso.title`)}</div>
|
|
||||||
<Tooltip
|
|
||||||
disabled={systemFeatures.sso_enforced_for_web}
|
|
||||||
popupContent={
|
|
||||||
<div className='w-[180px]'>{t(`${prefixSettings}.sso.tooltip`)}</div>
|
|
||||||
}
|
|
||||||
asChild={false}
|
|
||||||
>
|
|
||||||
<Switch disabled={!systemFeatures.sso_enforced_for_web || !isCurrentWorkspaceEditor} defaultValue={systemFeatures.sso_enforced_for_web && inputInfo.enable_sso} onChange={v => setInputInfo({ ...inputInfo, enable_sso: v })}></Switch>
|
|
||||||
</Tooltip>
|
|
||||||
</div>
|
|
||||||
<p className='pb-0.5 body-xs-regular text-text-tertiary'>{t(`${prefixSettings}.sso.description`)}</p>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
)}
|
|
||||||
{/* more settings switch */}
|
{/* more settings switch */}
|
||||||
<Divider className="h-px my-0" />
|
<Divider className="h-px my-0" />
|
||||||
{!isShowMore && (
|
{!isShowMore && (
|
||||||
|
@ -196,6 +196,7 @@ const translation = {
|
|||||||
expand: 'Expand',
|
expand: 'Expand',
|
||||||
noResult: 'No result',
|
noResult: 'No result',
|
||||||
},
|
},
|
||||||
|
updateSuccess: 'Update successfully',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,6 +621,7 @@ const translation = {
|
|||||||
pagination: {
|
pagination: {
|
||||||
perPage: 'Items per page',
|
perPage: 'Items per page',
|
||||||
},
|
},
|
||||||
|
your: 'You',
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translation
|
export default translation
|
||||||
|
@ -197,6 +197,7 @@ const translation = {
|
|||||||
expand: '展开',
|
expand: '展开',
|
||||||
noResult: '没有结果',
|
noResult: '没有结果',
|
||||||
},
|
},
|
||||||
|
updateSuccess: '更新成功',
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -621,6 +621,7 @@ const translation = {
|
|||||||
pagination: {
|
pagination: {
|
||||||
perPage: '每页显示',
|
perPage: '每页显示',
|
||||||
},
|
},
|
||||||
|
you: '你',
|
||||||
}
|
}
|
||||||
|
|
||||||
export default translation
|
export default translation
|
||||||
|
@ -3,9 +3,9 @@ export enum SubjectType {
|
|||||||
Account = 'account',
|
Account = 'account',
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum AccessModel {
|
export enum AccessMode {
|
||||||
PUBLIC = 'PUBLIC',
|
PUBLIC = 'PUBLIC',
|
||||||
PRIVATE = 'PRIVATE',
|
SPECIFIC_GROUPS_MEMBERS = 'SPECIFIC_GROUPS_MEMBERS',
|
||||||
ORGANIZATION = 'ORGANIZATION',
|
ORGANIZATION = 'ORGANIZATION',
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import { useQuery } from '@tanstack/react-query'
|
import { useMutation, useQuery } from '@tanstack/react-query'
|
||||||
import { get } from './base'
|
import { get, post } from './base'
|
||||||
import type { AccessControlAccount, AccessControlGroup, Subject } from '@/models/access-control'
|
import type { AccessControlAccount, AccessControlGroup, Subject } from '@/models/access-control'
|
||||||
|
import type { App } from '@/types/app'
|
||||||
|
|
||||||
const NAME_SPACE = 'access-control'
|
const NAME_SPACE = 'access-control'
|
||||||
|
|
||||||
export const useAppWhiteListSubjects = (appId: string) => {
|
export const useAppWhiteListSubjects = (appId: string, enabled: boolean) => {
|
||||||
return useQuery({
|
return useQuery({
|
||||||
queryKey: [NAME_SPACE, 'app-whitelist-subjects', appId],
|
queryKey: [NAME_SPACE, 'app-whitelist-subjects', appId],
|
||||||
queryFn: () => get<{ groups: AccessControlGroup[]; members: AccessControlAccount[] }>(`/enterprise/webapp/app/subjects?appId=${appId}`),
|
queryFn: () => get<{ groups: AccessControlGroup[]; members: AccessControlAccount[] }>(`/enterprise/webapp/app/subjects?appId=${appId}`),
|
||||||
|
enabled,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -33,3 +35,17 @@ export const useSearchForWhiteListCandidates = (query: { appId?: string; keyword
|
|||||||
enabled,
|
enabled,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type UpdateAccessModeParams = {
|
||||||
|
appId: App['id']
|
||||||
|
subjects: Subject['subjectId'][]
|
||||||
|
}
|
||||||
|
|
||||||
|
export const useUpdateAccessMode = () => {
|
||||||
|
return useMutation({
|
||||||
|
mutationKey: [NAME_SPACE, 'update-access-mode'],
|
||||||
|
mutationFn: (params: UpdateAccessModeParams) => {
|
||||||
|
return post('/enterprise/webapp/app/access-mode', { body: params })
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user