diff --git a/web/app/components/base/modal/modal.tsx b/web/app/components/base/modal/modal.tsx new file mode 100644 index 0000000000..3137e7adcc --- /dev/null +++ b/web/app/components/base/modal/modal.tsx @@ -0,0 +1,118 @@ +import { memo } from 'react' +import { useTranslation } from 'react-i18next' +import { RiCloseLine } from '@remixicon/react' +import { + PortalToFollowElem, + PortalToFollowElemContent, +} from '@/app/components/base/portal-to-follow-elem' +import Button from '@/app/components/base/button' +import type { ButtonProps } from '@/app/components/base/button' +import cn from '@/utils/classnames' + +type ModalProps = { + onClose?: () => void + size?: 'sm' | 'md' + title: string + subTitle?: string + children?: React.ReactNode + confirmButtonText?: string + onConfirm?: () => void + cancelButtonText?: string + onCancel?: () => void + showExtraButton?: boolean + extraButtonText?: string + extraButtonVariant?: ButtonProps['variant'] + onExtraButtonClick?: () => void + footerSlot?: React.ReactNode + bottomSlot?: React.ReactNode +} +const Modal = ({ + onClose, + size = 'sm', + title, + subTitle, + children, + confirmButtonText, + onConfirm, + cancelButtonText, + onCancel, + showExtraButton, + extraButtonVariant = 'warning', + extraButtonText, + onExtraButtonClick, + footerSlot, + bottomSlot, +}: ModalProps) => { + const { t } = useTranslation() + + return ( + + +
e.stopPropagation()} + > +
+ {title} + { + subTitle && ( +
+ {subTitle} +
+ ) + } +
+ +
+
+ { + children && ( +
{children}
+ ) + } +
+ {footerSlot} + { + showExtraButton && ( + <> + +
+ + ) + } + + +
+ {bottomSlot} +
+
+
+ ) +} + +export default memo(Modal) diff --git a/web/app/components/tools/tool-auth/add-api-key-button.tsx b/web/app/components/tools/tool-auth/add-api-key-button.tsx new file mode 100644 index 0000000000..21eeed5600 --- /dev/null +++ b/web/app/components/tools/tool-auth/add-api-key-button.tsx @@ -0,0 +1,40 @@ +import { + memo, + useState, +} from 'react' +import Button from '@/app/components/base/button' +import type { ButtonProps } from '@/app/components/base/button' +import ApiKeyModal from './api-key-modal' + +type AddApiKeyButtonProps = { + buttonVariant?: ButtonProps['variant'] + buttonText?: string +} +const AddApiKeyButton = ({ + buttonVariant = 'secondary-accent', + buttonText = 'use api key', +}: AddApiKeyButtonProps) => { + const [isApiKeyModalOpen, setIsApiKeyModalOpen] = useState(false) + + return ( + <> + + { + isApiKeyModalOpen && ( + setIsApiKeyModalOpen(false)} + /> + ) + } + + + ) +} + +export default memo(AddApiKeyButton) diff --git a/web/app/components/tools/tool-auth/add-oauth-button.tsx b/web/app/components/tools/tool-auth/add-oauth-button.tsx new file mode 100644 index 0000000000..7e6bc91774 --- /dev/null +++ b/web/app/components/tools/tool-auth/add-oauth-button.tsx @@ -0,0 +1,69 @@ +import { + memo, + useState, +} from 'react' +import { RiEqualizer2Line } from '@remixicon/react' +import Button from '@/app/components/base/button' +import type { ButtonProps } from '@/app/components/base/button' +import OAuthClientSettings from './oauth-client-settings' +import cn from '@/utils/classnames' + +type AddOAuthButtonProps = { + buttonVariant?: ButtonProps['variant'] + buttonText?: string + className?: string + buttonLeftClassName?: string + buttonRightClassName?: string + dividerClassName?: string +} +const AddOAuthButton = ({ + buttonVariant = 'primary', + buttonText = 'use oauth', + className, + buttonLeftClassName, + buttonRightClassName, + dividerClassName, +}: AddOAuthButtonProps) => { + const [isOAuthSettingsOpen, setIsOAuthSettingsOpen] = useState(false) + + return ( + <> + + { + isOAuthSettingsOpen && ( + setIsOAuthSettingsOpen(false)} + /> + ) + } + + ) +} + +export default memo(AddOAuthButton) diff --git a/web/app/components/tools/tool-auth/api-key-modal.tsx b/web/app/components/tools/tool-auth/api-key-modal.tsx new file mode 100644 index 0000000000..f4a2332861 --- /dev/null +++ b/web/app/components/tools/tool-auth/api-key-modal.tsx @@ -0,0 +1,52 @@ +import { memo } from 'react' +import { useTranslation } from 'react-i18next' +import { RiExternalLinkLine } from '@remixicon/react' +import { Lock01 } from '@/app/components/base/icons/src/vender/solid/security' +import Modal from '@/app/components/base/modal/modal' + +export type ApiKeyModalProps = { + onClose?: () => void +} +const ApiKeyModal = ({ + onClose, +}: ApiKeyModalProps) => { + const { t } = useTranslation() + + return ( + + Get your API Key from OpenAI + + + } + bottomSlot={ +
+ + {t('common.modelProvider.encrypted.front')} + + PKCS1_OAEP + + {t('common.modelProvider.encrypted.back')} +
+ } + > +
oauth
+
+ ) +} + +export default memo(ApiKeyModal) diff --git a/web/app/components/tools/tool-auth/authorization.tsx b/web/app/components/tools/tool-auth/authorization.tsx new file mode 100644 index 0000000000..5d3322d629 --- /dev/null +++ b/web/app/components/tools/tool-auth/authorization.tsx @@ -0,0 +1,124 @@ +import { + memo, + useState, +} from 'react' +import { + RiArrowDownSLine, + RiDeleteBinLine, + RiEditLine, +} from '@remixicon/react' +import { + PortalToFollowElem, + PortalToFollowElemContent, + PortalToFollowElemTrigger, +} from '@/app/components/base/portal-to-follow-elem' +import Button from '@/app/components/base/button' +import Indicator from '@/app/components/header/indicator' +import Badge from '@/app/components/base/badge' +import ActionButton from '@/app/components/base/action-button' +import cn from '@/utils/classnames' +import AddOauthButton from './add-oauth-button' +import AddApiKeyButton from './add-api-key-button' + +const Authorization = () => { + const [isOpen, setIsOpen] = useState(false) + + return ( + + setIsOpen(!isOpen)} + asChild + > + + + +
+
+
+
+ OAuth +
+
+
+ +
+ Auth 1 +
+ + Default + +
+
+ + + + + + +
+
+
+
+
+ API Keys +
+
+
+ +
+ Production +
+
+
+ + 0.2 + + + ENTERPRISE + +
+
+
+
+
+
+ + +
+
+
+
+ ) +} + +export default memo(Authorization) diff --git a/web/app/components/tools/tool-auth/index.tsx b/web/app/components/tools/tool-auth/index.tsx new file mode 100644 index 0000000000..a632029ca2 --- /dev/null +++ b/web/app/components/tools/tool-auth/index.tsx @@ -0,0 +1,23 @@ +import { + memo, +} from 'react' +import AddOAuthButton from './add-oauth-button' +import AddApiKeyButton from './add-api-key-button' + +const ToolAuth = () => { + return ( + <> +
+ +
+
+ or +
+
+ +
+ + ) +} + +export default memo(ToolAuth) diff --git a/web/app/components/tools/tool-auth/oauth-client-settings.tsx b/web/app/components/tools/tool-auth/oauth-client-settings.tsx new file mode 100644 index 0000000000..724351bd57 --- /dev/null +++ b/web/app/components/tools/tool-auth/oauth-client-settings.tsx @@ -0,0 +1,26 @@ +import { memo } from 'react' +import Modal from '@/app/components/base/modal/modal' + +type OAuthClientSettingsProps = { + onClose?: () => void +} +const OAuthClientSettings = ({ + onClose, +}: OAuthClientSettingsProps) => { + return ( + +
oauth
+
+ ) +} + +export default memo(OAuthClientSettings) diff --git a/web/app/components/workflow/nodes/tool/panel.tsx b/web/app/components/workflow/nodes/tool/panel.tsx index 038159870e..561a6e8eea 100644 --- a/web/app/components/workflow/nodes/tool/panel.tsx +++ b/web/app/components/workflow/nodes/tool/panel.tsx @@ -14,6 +14,8 @@ import Loading from '@/app/components/base/loading' import OutputVars, { VarItem } from '@/app/components/workflow/nodes/_base/components/output-vars' import StructureOutputItem from '@/app/components/workflow/nodes/_base/components/variable/object-child-tree-panel/show' import { Type } from '../llm/types' +import ToolAuth from '@/app/components/tools/tool-auth' +import Authorization from '@/app/components/tools/tool-auth/authorization' const i18nPrefix = 'workflow.nodes.tool' @@ -53,6 +55,10 @@ const Panel: FC> = ({ return (
+
+ + +
{!readOnly && isShowAuthBtn && ( <>