mirror of
https://github.com/langgenius/dify.git
synced 2026-05-05 01:48:04 +08:00
feat: add plugin readme
This commit is contained in:
@ -128,13 +128,13 @@ const DetailHeader = ({
|
||||
return false
|
||||
if (!autoUpgradeInfo || !isFromMarketplace)
|
||||
return false
|
||||
if(autoUpgradeInfo.strategy_setting === 'disabled')
|
||||
if (autoUpgradeInfo.strategy_setting === 'disabled')
|
||||
return false
|
||||
if(autoUpgradeInfo.upgrade_mode === AUTO_UPDATE_MODE.update_all)
|
||||
if (autoUpgradeInfo.upgrade_mode === AUTO_UPDATE_MODE.update_all)
|
||||
return true
|
||||
if(autoUpgradeInfo.upgrade_mode === AUTO_UPDATE_MODE.partial && autoUpgradeInfo.include_plugins.includes(plugin_id))
|
||||
if (autoUpgradeInfo.upgrade_mode === AUTO_UPDATE_MODE.partial && autoUpgradeInfo.include_plugins.includes(plugin_id))
|
||||
return true
|
||||
if(autoUpgradeInfo.upgrade_mode === AUTO_UPDATE_MODE.exclude && !autoUpgradeInfo.exclude_plugins.includes(plugin_id))
|
||||
if (autoUpgradeInfo.upgrade_mode === AUTO_UPDATE_MODE.exclude && !autoUpgradeInfo.exclude_plugins.includes(plugin_id))
|
||||
return true
|
||||
return false
|
||||
}, [autoUpgradeInfo, plugin_id, isFromMarketplace])
|
||||
@ -331,6 +331,7 @@ const DetailHeader = ({
|
||||
pluginPayload={{
|
||||
provider: provider?.name || '',
|
||||
category: AuthCategory.tool,
|
||||
detail,
|
||||
}}
|
||||
/>
|
||||
)
|
||||
|
||||
@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import { useBoolean } from 'ahooks'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import { RiClipboardLine, RiDeleteBinLine, RiEditLine, RiLoginCircleLine } from '@remixicon/react'
|
||||
import type { EndpointListItem } from '../types'
|
||||
import type { EndpointListItem, PluginDetail } from '../types'
|
||||
import EndpointModal from './endpoint-modal'
|
||||
import { NAME_FIELD } from './utils'
|
||||
import { addDefaultValue, toolCredentialToFormSchemas } from '@/app/components/tools/utils/to-form-schema'
|
||||
@ -22,11 +22,13 @@ import {
|
||||
} from '@/service/use-endpoints'
|
||||
|
||||
type Props = {
|
||||
pluginDetail: PluginDetail
|
||||
data: EndpointListItem
|
||||
handleChange: () => void
|
||||
}
|
||||
|
||||
const EndpointCard = ({
|
||||
pluginDetail,
|
||||
data,
|
||||
handleChange,
|
||||
}: Props) => {
|
||||
@ -206,10 +208,11 @@ const EndpointCard = ({
|
||||
)}
|
||||
{isShowEndpointModal && (
|
||||
<EndpointModal
|
||||
formSchemas={formSchemas}
|
||||
formSchemas={formSchemas as any}
|
||||
defaultValues={formValue}
|
||||
onCancel={hideEndpointModalConfirm}
|
||||
onSaved={handleUpdate}
|
||||
pluginDetail={pluginDetail}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -102,14 +102,16 @@ const EndpointList = ({ detail }: Props) => {
|
||||
key={index}
|
||||
data={item}
|
||||
handleChange={() => invalidateEndpointList(detail.plugin_id)}
|
||||
pluginDetail={detail}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
{isShowEndpointModal && (
|
||||
<EndpointModal
|
||||
formSchemas={formSchemas}
|
||||
formSchemas={formSchemas as any}
|
||||
onCancel={hideEndpointModal}
|
||||
onSaved={handleCreate}
|
||||
pluginDetail={detail}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@ -10,12 +10,16 @@ import Form from '@/app/components/header/account-setting/model-provider-page/mo
|
||||
import Toast from '@/app/components/base/toast'
|
||||
import { useRenderI18nObject } from '@/hooks/use-i18n'
|
||||
import cn from '@/utils/classnames'
|
||||
import { ReadmeEntrance } from '../readme-panel/entrance'
|
||||
import type { PluginDetail } from '../types'
|
||||
import type { FormSchema } from '../../base/form/types'
|
||||
|
||||
type Props = {
|
||||
formSchemas: any
|
||||
formSchemas: FormSchema[]
|
||||
defaultValues?: any
|
||||
onCancel: () => void
|
||||
onSaved: (value: Record<string, any>) => void
|
||||
pluginDetail: PluginDetail
|
||||
}
|
||||
|
||||
const extractDefaultValues = (schemas: any[]) => {
|
||||
@ -32,6 +36,7 @@ const EndpointModal: FC<Props> = ({
|
||||
defaultValues = {},
|
||||
onCancel,
|
||||
onSaved,
|
||||
pluginDetail,
|
||||
}) => {
|
||||
const getValueFromI18nObject = useRenderI18nObject()
|
||||
const { t } = useTranslation()
|
||||
@ -43,7 +48,7 @@ const EndpointModal: FC<Props> = ({
|
||||
const handleSave = () => {
|
||||
for (const field of formSchemas) {
|
||||
if (field.required && !tempCredential[field.name]) {
|
||||
Toast.notify({ type: 'error', message: t('common.errorMsg.fieldRequired', { field: getValueFromI18nObject(field.label) }) })
|
||||
Toast.notify({ type: 'error', message: t('common.errorMsg.fieldRequired', { field: typeof field.label === 'string' ? field.label : getValueFromI18nObject(field.label as Record<string, string>) }) })
|
||||
return
|
||||
}
|
||||
}
|
||||
@ -84,6 +89,7 @@ const EndpointModal: FC<Props> = ({
|
||||
</ActionButton>
|
||||
</div>
|
||||
<div className='system-xs-regular mt-0.5 text-text-tertiary'>{t('plugin.detailPanel.endpointModalDesc')}</div>
|
||||
<ReadmeEntrance pluginDetail={pluginDetail} className='px-0 pt-3' />
|
||||
</div>
|
||||
<div className='grow overflow-y-auto'>
|
||||
<div className='px-4 py-2'>
|
||||
@ -92,7 +98,7 @@ const EndpointModal: FC<Props> = ({
|
||||
onChange={(v) => {
|
||||
setTempCredential(v)
|
||||
}}
|
||||
formSchemas={formSchemas}
|
||||
formSchemas={formSchemas as any}
|
||||
isEditMode={true}
|
||||
showOnVariableMap={{}}
|
||||
validating={false}
|
||||
|
||||
@ -3,7 +3,7 @@ import Drawer from '@/app/components/base/drawer'
|
||||
import { PluginCategoryEnum, type PluginDetail } from '@/app/components/plugins/types'
|
||||
import cn from '@/utils/classnames'
|
||||
import type { FC } from 'react'
|
||||
import { useEffect } from 'react'
|
||||
import { useCallback, useEffect } from 'react'
|
||||
import ActionList from './action-list'
|
||||
import AgentStrategyList from './agent-strategy-list'
|
||||
import DatasourceActionList from './datasource-action-list'
|
||||
@ -11,8 +11,9 @@ import DetailHeader from './detail-header'
|
||||
import EndpointList from './endpoint-list'
|
||||
import ModelList from './model-list'
|
||||
import { SubscriptionList } from './subscription-list'
|
||||
import { usePluginStore } from './subscription-list/store'
|
||||
import { usePluginStore } from './store'
|
||||
import { TriggerEventsList } from './trigger/event-list'
|
||||
import { ReadmeEntrance } from '../readme-panel/entrance'
|
||||
|
||||
type Props = {
|
||||
detail?: PluginDetail
|
||||
@ -25,19 +26,22 @@ const PluginDetailPanel: FC<Props> = ({
|
||||
onUpdate,
|
||||
onHide,
|
||||
}) => {
|
||||
const handleUpdate = (isDelete = false) => {
|
||||
const handleUpdate = useCallback((isDelete = false) => {
|
||||
if (isDelete)
|
||||
onHide()
|
||||
onUpdate()
|
||||
}
|
||||
}, [onHide, onUpdate])
|
||||
|
||||
const { setDetail } = usePluginStore()
|
||||
|
||||
useEffect(() => {
|
||||
setDetail(!detail ? undefined : {
|
||||
plugin_id: detail.plugin_id,
|
||||
provider: `${detail.plugin_id}/${detail.declaration.name}`,
|
||||
plugin_unique_identifier: detail.plugin_unique_identifier || '',
|
||||
declaration: detail.declaration,
|
||||
name: detail.name,
|
||||
id: detail.id,
|
||||
})
|
||||
}, [detail])
|
||||
|
||||
@ -56,23 +60,24 @@ const PluginDetailPanel: FC<Props> = ({
|
||||
>
|
||||
{detail && (
|
||||
<>
|
||||
<DetailHeader
|
||||
detail={detail}
|
||||
onHide={onHide}
|
||||
onUpdate={handleUpdate}
|
||||
/>
|
||||
<DetailHeader detail={detail} onUpdate={handleUpdate} onHide={onHide} />
|
||||
<div className='grow overflow-y-auto'>
|
||||
{detail.declaration.category === PluginCategoryEnum.trigger && (
|
||||
<>
|
||||
<SubscriptionList />
|
||||
<TriggerEventsList />
|
||||
</>
|
||||
)}
|
||||
{!!detail.declaration.tool && <ActionList detail={detail} />}
|
||||
{!!detail.declaration.agent_strategy && <AgentStrategyList detail={detail} />}
|
||||
{!!detail.declaration.endpoint && <EndpointList detail={detail} />}
|
||||
{!!detail.declaration.model && <ModelList detail={detail} />}
|
||||
{!!detail.declaration.datasource && <DatasourceActionList detail={detail} />}
|
||||
<div className='flex min-h-full flex-col'>
|
||||
<div className='flex-1'>
|
||||
{detail.declaration.category === PluginCategoryEnum.trigger && (
|
||||
<>
|
||||
<SubscriptionList />
|
||||
<TriggerEventsList />
|
||||
</>
|
||||
)}
|
||||
{!!detail.declaration.tool && <ActionList detail={detail} />}
|
||||
{!!detail.declaration.agent_strategy && <AgentStrategyList detail={detail} />}
|
||||
{!!detail.declaration.endpoint && <EndpointList detail={detail} />}
|
||||
{!!detail.declaration.model && <ModelList detail={detail} />}
|
||||
{!!detail.declaration.datasource && <DatasourceActionList detail={detail} />}
|
||||
</div>
|
||||
<ReadmeEntrance pluginDetail={detail} className='mt-auto' />
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
|
||||
14
web/app/components/plugins/plugin-detail-panel/store.ts
Normal file
14
web/app/components/plugins/plugin-detail-panel/store.ts
Normal file
@ -0,0 +1,14 @@
|
||||
import { create } from 'zustand'
|
||||
import type { PluginDetail } from '../types'
|
||||
|
||||
export type SimpleDetail = Pick<PluginDetail, 'plugin_id' | 'declaration' | 'name' | 'plugin_unique_identifier' | 'id'> & { provider: string }
|
||||
|
||||
type Shape = {
|
||||
detail: SimpleDetail | undefined
|
||||
setDetail: (detail?: SimpleDetail) => void
|
||||
}
|
||||
|
||||
export const usePluginStore = create<Shape>(set => ({
|
||||
detail: undefined,
|
||||
setDetail: (detail?: SimpleDetail) => set({ detail }),
|
||||
}))
|
||||
@ -23,7 +23,8 @@ import { debounce } from 'lodash-es'
|
||||
import React, { useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import LogViewer from '../log-viewer'
|
||||
import { usePluginStore, usePluginSubscriptionStore } from '../store'
|
||||
import { usePluginSubscriptionStore } from '../store'
|
||||
import { usePluginStore } from '../../store'
|
||||
|
||||
type Props = {
|
||||
onClose: () => void
|
||||
|
||||
@ -14,7 +14,7 @@ import { useBoolean } from 'ahooks'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { SupportedCreationMethods } from '../../../types'
|
||||
import { usePluginStore } from '../store'
|
||||
import { usePluginStore } from '../../store'
|
||||
import { useSubscriptionList } from '../use-subscription-list'
|
||||
import { CommonCreateModal } from './common-modal'
|
||||
import { OAuthClientSettingsModal } from './oauth-client'
|
||||
|
||||
@ -20,7 +20,7 @@ import {
|
||||
} from '@remixicon/react'
|
||||
import React, { useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { usePluginStore } from '../store'
|
||||
import { usePluginStore } from '../../store'
|
||||
|
||||
type Props = {
|
||||
oauthConfig?: TriggerOAuthConfig
|
||||
|
||||
@ -1,17 +1,4 @@
|
||||
import { create } from 'zustand'
|
||||
import type { PluginDetail } from '../../types'
|
||||
|
||||
export type SimpleDetail = Pick<PluginDetail, 'plugin_id' | 'declaration' | 'name'> & { provider: string }
|
||||
|
||||
type Shape = {
|
||||
detail: SimpleDetail | undefined
|
||||
setDetail: (detail?: SimpleDetail) => void
|
||||
}
|
||||
|
||||
export const usePluginStore = create<Shape>(set => ({
|
||||
detail: undefined,
|
||||
setDetail: (detail?: SimpleDetail) => set({ detail }),
|
||||
}))
|
||||
|
||||
type ShapeSubscription = {
|
||||
refresh?: () => void
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import { useEffect } from 'react'
|
||||
import { useTriggerSubscriptions } from '@/service/use-triggers'
|
||||
import { usePluginStore, usePluginSubscriptionStore } from './store'
|
||||
import { usePluginStore } from '../store'
|
||||
import { usePluginSubscriptionStore } from './store'
|
||||
|
||||
export const useSubscriptionList = () => {
|
||||
const detail = usePluginStore(state => state.detail)
|
||||
|
||||
@ -40,6 +40,7 @@ import {
|
||||
AuthCategory,
|
||||
PluginAuthInAgent,
|
||||
} from '@/app/components/plugins/plugin-auth'
|
||||
import { ReadmeEntrance } from '../../readme-panel/entrance'
|
||||
|
||||
type Props = {
|
||||
disabled?: boolean
|
||||
@ -272,7 +273,10 @@ const ToolSelector: FC<Props> = ({
|
||||
{/* base form */}
|
||||
<div className='flex flex-col gap-3 px-4 py-2'>
|
||||
<div className='flex flex-col gap-1'>
|
||||
<div className='system-sm-semibold flex h-6 items-center text-text-secondary'>{t('plugin.detailPanel.toolSelector.toolLabel')}</div>
|
||||
<div className='system-sm-semibold flex h-6 items-center justify-between text-text-secondary'>
|
||||
{t('plugin.detailPanel.toolSelector.toolLabel')}
|
||||
<ReadmeEntrance pluginDetail={currentProvider as any} showShortTip className='pb-0' />
|
||||
</div>
|
||||
<ToolPicker
|
||||
placement='bottom'
|
||||
offset={offset}
|
||||
@ -314,6 +318,7 @@ const ToolSelector: FC<Props> = ({
|
||||
pluginPayload={{
|
||||
provider: currentProvider.name,
|
||||
category: AuthCategory.tool,
|
||||
detail: currentProvider as any,
|
||||
}}
|
||||
credentialId={value?.credential_id}
|
||||
onAuthorizationItemClick={handleAuthorizationItemClick}
|
||||
|
||||
@ -5,7 +5,7 @@ import { useTriggerProviderInfo } from '@/service/use-triggers'
|
||||
import cn from '@/utils/classnames'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { usePluginStore } from '../subscription-list/store'
|
||||
import { usePluginStore } from '../store'
|
||||
import { EventDetailDrawer } from './event-detail-drawer'
|
||||
|
||||
type TriggerEventCardProps = {
|
||||
|
||||
Reference in New Issue
Block a user