Web app now supports SSO config (#7137)
This commit is contained in:
@@ -15,13 +15,14 @@ import {
|
||||
} from '@remixicon/react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import { useContextSelector } from 'use-context-selector'
|
||||
import s from './style.module.css'
|
||||
import cn from '@/utils/classnames'
|
||||
import { useStore } from '@/app/components/app/store'
|
||||
import AppSideBar from '@/app/components/app-sidebar'
|
||||
import type { NavIcon } from '@/app/components/app-sidebar/navLink'
|
||||
import { fetchAppDetail } from '@/service/apps'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { fetchAppDetail, fetchAppSSO } from '@/service/apps'
|
||||
import AppContext, { useAppContext } from '@/context/app-context'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import useBreakpoints, { MediaType } from '@/hooks/use-breakpoints'
|
||||
|
||||
@@ -52,6 +53,7 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||
icon: NavIcon
|
||||
selectedIcon: NavIcon
|
||||
}>>([])
|
||||
const systemFeatures = useContextSelector(AppContext, state => state.systemFeatures)
|
||||
|
||||
const getNavigations = useCallback((appId: string, isCurrentWorkspaceEditor: boolean, mode: string) => {
|
||||
const navs = [
|
||||
@@ -114,8 +116,13 @@ const AppDetailLayout: FC<IAppDetailLayoutProps> = (props) => {
|
||||
router.replace(`/app/${appId}/configuration`)
|
||||
}
|
||||
else {
|
||||
setAppDetail(res)
|
||||
setAppDetail({ ...res, enable_sso: false })
|
||||
setNavigation(getNavigations(appId, isCurrentWorkspaceEditor, res.mode))
|
||||
if (systemFeatures.enable_web_sso_switch_component) {
|
||||
fetchAppSSO({ appId }).then((ssoRes) => {
|
||||
setAppDetail({ ...res, enable_sso: ssoRes.enabled })
|
||||
})
|
||||
}
|
||||
}
|
||||
}).catch((e: any) => {
|
||||
if (e.status === 404)
|
||||
|
||||
@@ -2,22 +2,25 @@
|
||||
import type { FC } from 'react'
|
||||
import React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useContext } from 'use-context-selector'
|
||||
import { useContext, useContextSelector } from 'use-context-selector'
|
||||
import AppCard from '@/app/components/app/overview/appCard'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { ToastContext } from '@/app/components/base/toast'
|
||||
import {
|
||||
fetchAppDetail,
|
||||
fetchAppSSO,
|
||||
updateAppSSO,
|
||||
updateAppSiteAccessToken,
|
||||
updateAppSiteConfig,
|
||||
updateAppSiteStatus,
|
||||
} from '@/service/apps'
|
||||
import type { App } from '@/types/app'
|
||||
import type { App, AppSSO } from '@/types/app'
|
||||
import type { UpdateAppSiteCodeResponse } from '@/models/app'
|
||||
import { asyncRunSafe } from '@/utils'
|
||||
import { NEED_REFRESH_APP_LIST_KEY } from '@/config'
|
||||
import type { IAppCardProps } from '@/app/components/app/overview/appCard'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import AppContext from '@/context/app-context'
|
||||
|
||||
export type ICardViewProps = {
|
||||
appId: string
|
||||
@@ -28,11 +31,20 @@ const CardView: FC<ICardViewProps> = ({ appId }) => {
|
||||
const { notify } = useContext(ToastContext)
|
||||
const appDetail = useAppStore(state => state.appDetail)
|
||||
const setAppDetail = useAppStore(state => state.setAppDetail)
|
||||
const systemFeatures = useContextSelector(AppContext, state => state.systemFeatures)
|
||||
|
||||
const updateAppDetail = async () => {
|
||||
fetchAppDetail({ url: '/apps', id: appId }).then((res) => {
|
||||
setAppDetail(res)
|
||||
})
|
||||
try {
|
||||
const res = await fetchAppDetail({ url: '/apps', id: appId })
|
||||
if (systemFeatures.enable_web_sso_switch_component) {
|
||||
const ssoRes = await fetchAppSSO({ appId })
|
||||
setAppDetail({ ...res, enable_sso: ssoRes.enabled })
|
||||
}
|
||||
else {
|
||||
setAppDetail({ ...res })
|
||||
}
|
||||
}
|
||||
catch (error) { console.error(error) }
|
||||
}
|
||||
|
||||
const handleCallbackResult = (err: Error | null, message?: string) => {
|
||||
@@ -81,6 +93,16 @@ const CardView: FC<ICardViewProps> = ({ appId }) => {
|
||||
if (!err)
|
||||
localStorage.setItem(NEED_REFRESH_APP_LIST_KEY, '1')
|
||||
|
||||
if (systemFeatures.enable_web_sso_switch_component) {
|
||||
const [sso_err] = await asyncRunSafe<AppSSO>(
|
||||
updateAppSSO({ id: appId, enabled: params.enable_sso }) as Promise<AppSSO>,
|
||||
)
|
||||
if (sso_err) {
|
||||
handleCallbackResult(sso_err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
handleCallbackResult(err)
|
||||
}
|
||||
|
||||
|
||||
@@ -27,10 +27,11 @@ import ShareQRCode from '@/app/components/base/qrcode'
|
||||
import SecretKeyButton from '@/app/components/develop/secret-key/secret-key-button'
|
||||
import type { AppDetailResponse } from '@/models/app'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import type { AppSSO } from '@/types/app'
|
||||
|
||||
export type IAppCardProps = {
|
||||
className?: string
|
||||
appInfo: AppDetailResponse
|
||||
appInfo: AppDetailResponse & Partial<AppSSO>
|
||||
cardType?: 'api' | 'webapp'
|
||||
customBgColor?: string
|
||||
onChangeStatus: (val: boolean) => Promise<void>
|
||||
|
||||
@@ -4,21 +4,25 @@ import React, { useEffect, useState } from 'react'
|
||||
import { ChevronRightIcon } from '@heroicons/react/20/solid'
|
||||
import Link from 'next/link'
|
||||
import { Trans, useTranslation } from 'react-i18next'
|
||||
import { useContextSelector } from 'use-context-selector'
|
||||
import s from './style.module.css'
|
||||
import Modal from '@/app/components/base/modal'
|
||||
import Button from '@/app/components/base/button'
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
import Switch from '@/app/components/base/switch'
|
||||
import { SimpleSelect } from '@/app/components/base/select'
|
||||
import type { AppDetailResponse } from '@/models/app'
|
||||
import type { AppIconType, Language } from '@/types/app'
|
||||
import type { AppIconType, AppSSO, Language } from '@/types/app'
|
||||
import { useToastContext } from '@/app/components/base/toast'
|
||||
import { languages } from '@/i18n/language'
|
||||
import TooltipPlus from '@/app/components/base/tooltip-plus'
|
||||
import AppContext from '@/context/app-context'
|
||||
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
||||
import AppIconPicker from '@/app/components/base/app-icon-picker'
|
||||
|
||||
export type ISettingsModalProps = {
|
||||
isChat: boolean
|
||||
appInfo: AppDetailResponse
|
||||
appInfo: AppDetailResponse & Partial<AppSSO>
|
||||
isShow: boolean
|
||||
defaultValue?: string
|
||||
onClose: () => void
|
||||
@@ -39,6 +43,7 @@ export type ConfigParams = {
|
||||
icon: string
|
||||
icon_background?: string
|
||||
show_workflow_steps: boolean
|
||||
enable_sso?: boolean
|
||||
}
|
||||
|
||||
const prefixSettings = 'appOverview.overview.appInfo.settings'
|
||||
@@ -50,6 +55,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
||||
onClose,
|
||||
onSave,
|
||||
}) => {
|
||||
const systemFeatures = useContextSelector(AppContext, state => state.systemFeatures)
|
||||
const { notify } = useToastContext()
|
||||
const [isShowMore, setIsShowMore] = useState(false)
|
||||
const {
|
||||
@@ -76,6 +82,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
||||
privacyPolicy: privacy_policy,
|
||||
customDisclaimer: custom_disclaimer,
|
||||
show_workflow_steps,
|
||||
enable_sso: appInfo.enable_sso,
|
||||
})
|
||||
const [language, setLanguage] = useState(default_language)
|
||||
const [saveLoading, setSaveLoading] = useState(false)
|
||||
@@ -98,6 +105,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
||||
privacyPolicy: privacy_policy,
|
||||
customDisclaimer: custom_disclaimer,
|
||||
show_workflow_steps,
|
||||
enable_sso: appInfo.enable_sso,
|
||||
})
|
||||
setLanguage(default_language)
|
||||
setAppIcon(icon_type === 'image'
|
||||
@@ -149,6 +157,7 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
||||
icon: appIcon.type === 'emoji' ? appIcon.icon : appIcon.fileId,
|
||||
icon_background: appIcon.type === 'emoji' ? appIcon.background : undefined,
|
||||
show_workflow_steps: inputInfo.show_workflow_steps,
|
||||
enable_sso: inputInfo.enable_sso,
|
||||
}
|
||||
await onSave?.(params)
|
||||
setSaveLoading(false)
|
||||
@@ -219,9 +228,19 @@ const SettingsModal: FC<ISettingsModalProps> = ({
|
||||
<input className={`w-full mt-2 rounded-lg h-10 box-border px-3 ${s.projectName} bg-gray-100`}
|
||||
value={inputInfo.chatColorTheme ?? ''}
|
||||
onChange={onChange('chatColorTheme')}
|
||||
placeholder= 'E.g #A020F0'
|
||||
placeholder='E.g #A020F0'
|
||||
/>
|
||||
</>}
|
||||
{systemFeatures.enable_web_sso_switch_component && <div className='w-full mt-8'>
|
||||
<p className='system-xs-medium text-gray-500'>{t(`${prefixSettings}.sso.label`)}</p>
|
||||
<div className='flex justify-between items-center'>
|
||||
<div className='font-medium system-sm-semibold flex-grow text-gray-900'>{t(`${prefixSettings}.sso.title`)}</div>
|
||||
<TooltipPlus disabled={systemFeatures.sso_enforced_for_web} popupContent={<div className='w-[180px]'>{t(`${prefixSettings}.sso.tooltip`)}</div>}>
|
||||
<Switch disabled={!systemFeatures.sso_enforced_for_web} defaultValue={systemFeatures.sso_enforced_for_web && inputInfo.enable_sso} onChange={v => setInputInfo({ ...inputInfo, enable_sso: v })}></Switch>
|
||||
</TooltipPlus>
|
||||
</div>
|
||||
<p className='body-xs-regular text-gray-500'>{t(`${prefixSettings}.sso.description`)}</p>
|
||||
</div>}
|
||||
{!isShowMore && <div className='w-full cursor-pointer mt-8' onClick={() => setIsShowMore(true)}>
|
||||
<div className='flex justify-between'>
|
||||
<div className={`font-medium ${s.settingTitle} flex-grow text-gray-900`}>{t(`${prefixSettings}.more.entry`)}</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { create } from 'zustand'
|
||||
import type { App } from '@/types/app'
|
||||
import type { App, AppSSO } from '@/types/app'
|
||||
import type { IChatItem } from '@/app/components/base/chat/chat/type'
|
||||
|
||||
type State = {
|
||||
appDetail?: App
|
||||
appDetail?: App & Partial<AppSSO>
|
||||
appSidebarExpand: string
|
||||
currentLogItem?: IChatItem
|
||||
currentLogModalActiveTab: string
|
||||
@@ -13,7 +13,7 @@ type State = {
|
||||
}
|
||||
|
||||
type Action = {
|
||||
setAppDetail: (appDetail?: App) => void
|
||||
setAppDetail: (appDetail?: App & Partial<AppSSO>) => void
|
||||
setAppSiderbarExpand: (state: string) => void
|
||||
setCurrentLogItem: (item?: IChatItem) => void
|
||||
setCurrentLogModalActiveTab: (tab: string) => void
|
||||
|
||||
Reference in New Issue
Block a user