mirror of
https://github.com/langgenius/dify.git
synced 2026-05-04 01:18:05 +08:00
Merge remote-tracking branch 'origin/main' into feat/queue-based-graph-engine
This commit is contained in:
@ -72,6 +72,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
const [showSwitchModal, setShowSwitchModal] = useState<boolean>(false)
|
||||
const [showImportDSLModal, setShowImportDSLModal] = useState<boolean>(false)
|
||||
const [secretEnvList, setSecretEnvList] = useState<EnvironmentVariable[]>([])
|
||||
const [showExportWarning, setShowExportWarning] = useState(false)
|
||||
|
||||
const onEdit: CreateAppModalProps['onConfirm'] = useCallback(async ({
|
||||
name,
|
||||
@ -159,6 +160,14 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
onExport()
|
||||
return
|
||||
}
|
||||
|
||||
setShowExportWarning(true)
|
||||
}
|
||||
|
||||
const handleConfirmExport = async () => {
|
||||
if (!appDetail)
|
||||
return
|
||||
setShowExportWarning(false)
|
||||
try {
|
||||
const workflowDraft = await fetchWorkflowDraft(`/apps/${appDetail.id}/workflows/draft`)
|
||||
const list = (workflowDraft.environment_variables || []).filter(env => env.value_type === 'secret')
|
||||
@ -407,6 +416,16 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
onClose={() => setSecretEnvList([])}
|
||||
/>
|
||||
)}
|
||||
{showExportWarning && (
|
||||
<Confirm
|
||||
type="info"
|
||||
isShow={showExportWarning}
|
||||
title={t('workflow.sidebar.exportWarning')}
|
||||
content={t('workflow.sidebar.exportWarningDesc')}
|
||||
onConfirm={handleConfirmExport}
|
||||
onCancel={() => setShowExportWarning(false)}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
@ -32,6 +32,7 @@ export type ActionButtonProps = {
|
||||
size?: 'xs' | 's' | 'm' | 'l' | 'xl'
|
||||
state?: ActionButtonState
|
||||
styleCss?: CSSProperties
|
||||
ref?: React.Ref<HTMLButtonElement>
|
||||
} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof actionButtonVariants>
|
||||
|
||||
function getActionButtonState(state: ActionButtonState) {
|
||||
@ -49,24 +50,22 @@ function getActionButtonState(state: ActionButtonState) {
|
||||
}
|
||||
}
|
||||
|
||||
const ActionButton = React.forwardRef<HTMLButtonElement, ActionButtonProps>(
|
||||
({ className, size, state = ActionButtonState.Default, styleCss, children, ...props }, ref) => {
|
||||
return (
|
||||
<button
|
||||
type='button'
|
||||
className={classNames(
|
||||
actionButtonVariants({ className, size }),
|
||||
getActionButtonState(state),
|
||||
)}
|
||||
ref={ref}
|
||||
style={styleCss}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
},
|
||||
)
|
||||
const ActionButton = ({ className, size, state = ActionButtonState.Default, styleCss, children, ref, ...props }: ActionButtonProps) => {
|
||||
return (
|
||||
<button
|
||||
type='button'
|
||||
className={classNames(
|
||||
actionButtonVariants({ className, size }),
|
||||
getActionButtonState(state),
|
||||
)}
|
||||
ref={ref}
|
||||
style={styleCss}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
ActionButton.displayName = 'ActionButton'
|
||||
|
||||
export default ActionButton
|
||||
|
||||
@ -35,27 +35,26 @@ export type ButtonProps = {
|
||||
loading?: boolean
|
||||
styleCss?: CSSProperties
|
||||
spinnerClassName?: string
|
||||
ref?: React.Ref<HTMLButtonElement>
|
||||
} & React.ButtonHTMLAttributes<HTMLButtonElement> & VariantProps<typeof buttonVariants>
|
||||
|
||||
const Button = React.forwardRef<HTMLButtonElement, ButtonProps>(
|
||||
({ className, variant, size, destructive, loading, styleCss, children, spinnerClassName, ...props }, ref) => {
|
||||
return (
|
||||
<button
|
||||
type='button'
|
||||
className={classNames(
|
||||
buttonVariants({ variant, size, className }),
|
||||
destructive && 'btn-destructive',
|
||||
)}
|
||||
ref={ref}
|
||||
style={styleCss}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
{loading && <Spinner loading={loading} className={classNames('!ml-1 !h-3 !w-3 !border-2 !text-white', spinnerClassName)} />}
|
||||
</button>
|
||||
)
|
||||
},
|
||||
)
|
||||
const Button = ({ className, variant, size, destructive, loading, styleCss, children, spinnerClassName, ref, ...props }: ButtonProps) => {
|
||||
return (
|
||||
<button
|
||||
type='button'
|
||||
className={classNames(
|
||||
buttonVariants({ variant, size, className }),
|
||||
destructive && 'btn-destructive',
|
||||
)}
|
||||
ref={ref}
|
||||
style={styleCss}
|
||||
{...props}
|
||||
>
|
||||
{children}
|
||||
{loading && <Spinner loading={loading} className={classNames('!ml-1 !h-3 !w-3 !border-2 !text-white', spinnerClassName)} />}
|
||||
</button>
|
||||
)
|
||||
}
|
||||
Button.displayName = 'Button'
|
||||
|
||||
export default Button
|
||||
|
||||
@ -30,9 +30,10 @@ export type InputProps = {
|
||||
wrapperClassName?: string
|
||||
styleCss?: CSSProperties
|
||||
unit?: string
|
||||
ref?: React.Ref<HTMLInputElement>
|
||||
} & Omit<React.InputHTMLAttributes<HTMLInputElement>, 'size'> & VariantProps<typeof inputVariants>
|
||||
|
||||
const Input = React.forwardRef<HTMLInputElement, InputProps>(({
|
||||
const Input = ({
|
||||
size,
|
||||
disabled,
|
||||
destructive,
|
||||
@ -46,8 +47,9 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({
|
||||
placeholder,
|
||||
onChange = noop,
|
||||
unit,
|
||||
ref,
|
||||
...props
|
||||
}, ref) => {
|
||||
}: InputProps) => {
|
||||
const { t } = useTranslation()
|
||||
return (
|
||||
<div className={cn('relative w-full', wrapperClassName)}>
|
||||
@ -93,7 +95,7 @@ const Input = React.forwardRef<HTMLInputElement, InputProps>(({
|
||||
}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
Input.displayName = 'Input'
|
||||
|
||||
|
||||
@ -107,10 +107,13 @@ const initMermaid = () => {
|
||||
return isMermaidInitialized
|
||||
}
|
||||
|
||||
const Flowchart = React.forwardRef((props: {
|
||||
type FlowchartProps = {
|
||||
PrimitiveCode: string
|
||||
theme?: 'light' | 'dark'
|
||||
}, ref) => {
|
||||
ref?: React.Ref<HTMLDivElement>
|
||||
}
|
||||
|
||||
const Flowchart = (props: FlowchartProps) => {
|
||||
const { t } = useTranslation()
|
||||
const [svgString, setSvgString] = useState<string | null>(null)
|
||||
const [look, setLook] = useState<'classic' | 'handDrawn'>('classic')
|
||||
@ -490,7 +493,7 @@ const Flowchart = React.forwardRef((props: {
|
||||
}
|
||||
|
||||
return (
|
||||
<div ref={ref as React.RefObject<HTMLDivElement>} className={themeClasses.container}>
|
||||
<div ref={props.ref as React.RefObject<HTMLDivElement>} className={themeClasses.container}>
|
||||
<div className={themeClasses.segmented}>
|
||||
<div className="msh-segmented-group">
|
||||
<label className="msh-segmented-item m-2 flex w-[200px] items-center space-x-1">
|
||||
@ -572,7 +575,7 @@ const Flowchart = React.forwardRef((props: {
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
Flowchart.displayName = 'Flowchart'
|
||||
|
||||
|
||||
@ -24,30 +24,29 @@ export type TextareaProps = {
|
||||
disabled?: boolean
|
||||
destructive?: boolean
|
||||
styleCss?: CSSProperties
|
||||
ref?: React.Ref<HTMLTextAreaElement>
|
||||
} & React.TextareaHTMLAttributes<HTMLTextAreaElement> & VariantProps<typeof textareaVariants>
|
||||
|
||||
const Textarea = React.forwardRef<HTMLTextAreaElement, TextareaProps>(
|
||||
({ className, value, onChange, disabled, size, destructive, styleCss, ...props }, ref) => {
|
||||
return (
|
||||
<textarea
|
||||
ref={ref}
|
||||
style={styleCss}
|
||||
className={cn(
|
||||
'min-h-20 w-full appearance-none border border-transparent bg-components-input-bg-normal p-2 text-components-input-text-filled caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs',
|
||||
textareaVariants({ size }),
|
||||
disabled && 'cursor-not-allowed border-transparent bg-components-input-bg-disabled text-components-input-text-filled-disabled hover:border-transparent hover:bg-components-input-bg-disabled',
|
||||
destructive && 'border-components-input-border-destructive bg-components-input-bg-destructive text-components-input-text-filled hover:border-components-input-border-destructive hover:bg-components-input-bg-destructive focus:border-components-input-border-destructive focus:bg-components-input-bg-destructive',
|
||||
className,
|
||||
)}
|
||||
value={value ?? ''}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
{...props}
|
||||
>
|
||||
</textarea>
|
||||
)
|
||||
},
|
||||
)
|
||||
const Textarea = ({ className, value, onChange, disabled, size, destructive, styleCss, ref, ...props }: TextareaProps) => {
|
||||
return (
|
||||
<textarea
|
||||
ref={ref}
|
||||
style={styleCss}
|
||||
className={cn(
|
||||
'min-h-20 w-full appearance-none border border-transparent bg-components-input-bg-normal p-2 text-components-input-text-filled caret-primary-600 outline-none placeholder:text-components-input-text-placeholder hover:border-components-input-border-hover hover:bg-components-input-bg-hover focus:border-components-input-border-active focus:bg-components-input-bg-active focus:shadow-xs',
|
||||
textareaVariants({ size }),
|
||||
disabled && 'cursor-not-allowed border-transparent bg-components-input-bg-disabled text-components-input-text-filled-disabled hover:border-transparent hover:bg-components-input-bg-disabled',
|
||||
destructive && 'border-components-input-border-destructive bg-components-input-bg-destructive text-components-input-text-filled hover:border-components-input-border-destructive hover:bg-components-input-bg-destructive focus:border-components-input-border-destructive focus:bg-components-input-bg-destructive',
|
||||
className,
|
||||
)}
|
||||
value={value ?? ''}
|
||||
onChange={onChange}
|
||||
disabled={disabled}
|
||||
{...props}
|
||||
>
|
||||
</textarea>
|
||||
)
|
||||
}
|
||||
Textarea.displayName = 'Textarea'
|
||||
|
||||
export default Textarea
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
import type { ComponentProps, FC, ReactNode } from 'react'
|
||||
import { forwardRef } from 'react'
|
||||
import classNames from '@/utils/classnames'
|
||||
|
||||
export type PreviewContainerProps = ComponentProps<'div'> & {
|
||||
header: ReactNode
|
||||
mainClassName?: string
|
||||
ref?: React.Ref<HTMLDivElement>
|
||||
}
|
||||
|
||||
export const PreviewContainer: FC<PreviewContainerProps> = forwardRef((props, ref) => {
|
||||
const { children, className, header, mainClassName, ...rest } = props
|
||||
export const PreviewContainer: FC<PreviewContainerProps> = (props) => {
|
||||
const { children, className, header, mainClassName, ref, ...rest } = props
|
||||
return <div className={className}>
|
||||
<div
|
||||
{...rest}
|
||||
@ -25,5 +25,5 @@ export const PreviewContainer: FC<PreviewContainerProps> = forwardRef((props, re
|
||||
</main>
|
||||
</div>
|
||||
</div>
|
||||
})
|
||||
}
|
||||
PreviewContainer.displayName = 'PreviewContainer'
|
||||
|
||||
@ -740,84 +740,6 @@ Workflow applications offers non-session support and is ideal for translation, a
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/files/:file_id/preview'
|
||||
method='GET'
|
||||
title='File Preview'
|
||||
name='#file-preview'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
Preview or download uploaded files. This endpoint allows you to access files that have been previously uploaded via the File Upload API.
|
||||
|
||||
<i>Files can only be accessed if they belong to messages within the requesting application.</i>
|
||||
|
||||
### Path Parameters
|
||||
- `file_id` (string) Required
|
||||
The unique identifier of the file to preview, obtained from the File Upload API response.
|
||||
|
||||
### Query Parameters
|
||||
- `as_attachment` (boolean) Optional
|
||||
Whether to force download the file as an attachment. Default is `false` (preview in browser).
|
||||
|
||||
### Response
|
||||
Returns the file content with appropriate headers for browser display or download.
|
||||
- `Content-Type` Set based on file mime type
|
||||
- `Content-Length` File size in bytes (if available)
|
||||
- `Content-Disposition` Set to "attachment" if `as_attachment=true`
|
||||
- `Cache-Control` Caching headers for performance
|
||||
- `Accept-Ranges` Set to "bytes" for audio/video files
|
||||
|
||||
### Errors
|
||||
- 400, `invalid_param`, abnormal parameter input
|
||||
- 403, `file_access_denied`, file access denied or file does not belong to current application
|
||||
- 404, `file_not_found`, file not found or has been deleted
|
||||
- 500, internal server error
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
### Request Example
|
||||
<CodeGroup
|
||||
title="Request"
|
||||
tag="GET"
|
||||
label="/files/:file_id/preview"
|
||||
targetCode={`curl -X GET '${props.appDetail.api_base_url}/files/72fa9618-8f89-4a37-9b33-7e1178a24a67/preview' \\
|
||||
--header 'Authorization: Bearer {api_key}'`}
|
||||
/>
|
||||
|
||||
### Download as Attachment
|
||||
<CodeGroup
|
||||
title="Download Request"
|
||||
tag="GET"
|
||||
label="/files/:file_id/preview?as_attachment=true"
|
||||
targetCode={`curl -X GET '${props.appDetail.api_base_url}/files/72fa9618-8f89-4a37-9b33-7e1178a24a67/preview?as_attachment=true' \\
|
||||
--header 'Authorization: Bearer {api_key}' \\
|
||||
--output downloaded_file.png`}
|
||||
/>
|
||||
|
||||
### Response Headers Example
|
||||
<CodeGroup title="Response Headers">
|
||||
```http {{ title: 'Headers - Image Preview' }}
|
||||
Content-Type: image/png
|
||||
Content-Length: 1024
|
||||
Cache-Control: public, max-age=3600
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### Download Response Headers
|
||||
<CodeGroup title="Download Response Headers">
|
||||
```http {{ title: 'Headers - File Download' }}
|
||||
Content-Type: image/png
|
||||
Content-Length: 1024
|
||||
Content-Disposition: attachment; filename*=UTF-8''example.png
|
||||
Cache-Control: public, max-age=3600
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/workflows/logs'
|
||||
method='GET'
|
||||
|
||||
@ -736,84 +736,6 @@ import { Row, Col, Properties, Property, Heading, SubProperty, Paragraph } from
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/files/:file_id/preview'
|
||||
method='GET'
|
||||
title='ファイルプレビュー'
|
||||
name='#file-preview'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
アップロードされたファイルをプレビューまたはダウンロードします。このエンドポイントを使用すると、以前にファイルアップロード API でアップロードされたファイルにアクセスできます。
|
||||
|
||||
<i>ファイルは、リクエストしているアプリケーションのメッセージ範囲内にある場合のみアクセス可能です。</i>
|
||||
|
||||
### パスパラメータ
|
||||
- `file_id` (string) 必須
|
||||
プレビューするファイルの一意識別子。ファイルアップロード API レスポンスから取得します。
|
||||
|
||||
### クエリパラメータ
|
||||
- `as_attachment` (boolean) オプション
|
||||
ファイルを添付ファイルとして強制ダウンロードするかどうか。デフォルトは `false`(ブラウザでプレビュー)。
|
||||
|
||||
### レスポンス
|
||||
ブラウザ表示またはダウンロード用の適切なヘッダー付きでファイル内容を返します。
|
||||
- `Content-Type` ファイル MIME タイプに基づいて設定
|
||||
- `Content-Length` ファイルサイズ(バイト、利用可能な場合)
|
||||
- `Content-Disposition` `as_attachment=true` の場合は "attachment" に設定
|
||||
- `Cache-Control` パフォーマンス向上のためのキャッシュヘッダー
|
||||
- `Accept-Ranges` 音声/動画ファイルの場合は "bytes" に設定
|
||||
|
||||
### エラー
|
||||
- 400, `invalid_param`, パラメータ入力異常
|
||||
- 403, `file_access_denied`, ファイルアクセス拒否またはファイルが現在のアプリケーションに属していません
|
||||
- 404, `file_not_found`, ファイルが見つからないか削除されています
|
||||
- 500, サーバー内部エラー
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
### リクエスト例
|
||||
<CodeGroup
|
||||
title="Request"
|
||||
tag="GET"
|
||||
label="/files/:file_id/preview"
|
||||
targetCode={`curl -X GET '${props.appDetail.api_base_url}/files/72fa9618-8f89-4a37-9b33-7e1178a24a67/preview' \\
|
||||
--header 'Authorization: Bearer {api_key}'`}
|
||||
/>
|
||||
|
||||
### 添付ファイルとしてダウンロード
|
||||
<CodeGroup
|
||||
title="Download Request"
|
||||
tag="GET"
|
||||
label="/files/:file_id/preview?as_attachment=true"
|
||||
targetCode={`curl -X GET '${props.appDetail.api_base_url}/files/72fa9618-8f89-4a37-9b33-7e1178a24a67/preview?as_attachment=true' \\
|
||||
--header 'Authorization: Bearer {api_key}' \\
|
||||
--output downloaded_file.png`}
|
||||
/>
|
||||
|
||||
### レスポンスヘッダー例
|
||||
<CodeGroup title="Response Headers">
|
||||
```http {{ title: 'ヘッダー - 画像プレビュー' }}
|
||||
Content-Type: image/png
|
||||
Content-Length: 1024
|
||||
Cache-Control: public, max-age=3600
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### ダウンロードレスポンスヘッダー
|
||||
<CodeGroup title="Download Response Headers">
|
||||
```http {{ title: 'ヘッダー - ファイルダウンロード' }}
|
||||
Content-Type: image/png
|
||||
Content-Length: 1024
|
||||
Content-Disposition: attachment; filename*=UTF-8''example.png
|
||||
Cache-Control: public, max-age=3600
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/workflows/logs'
|
||||
method='GET'
|
||||
|
||||
@ -727,83 +727,6 @@ Workflow 应用无会话支持,适合用于翻译/文章写作/总结 AI 等
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/files/:file_id/preview'
|
||||
method='GET'
|
||||
title='文件预览'
|
||||
name='#file-preview'
|
||||
/>
|
||||
<Row>
|
||||
<Col>
|
||||
预览或下载已上传的文件。此端点允许您访问先前通过文件上传 API 上传的文件。
|
||||
|
||||
<i>文件只能在属于请求应用程序的消息范围内访问。</i>
|
||||
|
||||
### 路径参数
|
||||
- `file_id` (string) 必需
|
||||
要预览的文件的唯一标识符,从文件上传 API 响应中获得。
|
||||
|
||||
### 查询参数
|
||||
- `as_attachment` (boolean) 可选
|
||||
是否强制将文件作为附件下载。默认为 `false`(在浏览器中预览)。
|
||||
|
||||
### 响应
|
||||
返回带有适当浏览器显示或下载标头的文件内容。
|
||||
- `Content-Type` 根据文件 MIME 类型设置
|
||||
- `Content-Length` 文件大小(以字节为单位,如果可用)
|
||||
- `Content-Disposition` 如果 `as_attachment=true` 则设置为 "attachment"
|
||||
- `Cache-Control` 用于性能的缓存标头
|
||||
- `Accept-Ranges` 对于音频/视频文件设置为 "bytes"
|
||||
|
||||
### 错误
|
||||
- 400, `invalid_param`, 参数输入异常
|
||||
- 403, `file_access_denied`, 文件访问被拒绝或文件不属于当前应用程序
|
||||
- 404, `file_not_found`, 文件未找到或已被删除
|
||||
- 500, 服务内部错误
|
||||
|
||||
</Col>
|
||||
<Col sticky>
|
||||
### 请求示例
|
||||
<CodeGroup
|
||||
title="Request"
|
||||
tag="GET"
|
||||
label="/files/:file_id/preview"
|
||||
targetCode={`curl -X GET '${props.appDetail.api_base_url}/files/72fa9618-8f89-4a37-9b33-7e1178a24a67/preview' \\
|
||||
--header 'Authorization: Bearer {api_key}'`}
|
||||
/>
|
||||
|
||||
### 作为附件下载
|
||||
<CodeGroup
|
||||
title="Request"
|
||||
tag="GET"
|
||||
label="/files/:file_id/preview?as_attachment=true"
|
||||
targetCode={`curl -X GET '${props.appDetail.api_base_url}/files/72fa9618-8f89-4a37-9b33-7e1178a24a67/preview?as_attachment=true' \\
|
||||
--header 'Authorization: Bearer {api_key}' \\
|
||||
--output downloaded_file.png`}
|
||||
/>
|
||||
|
||||
### 响应标头示例
|
||||
<CodeGroup title="Response Headers">
|
||||
```http {{ title: 'Headers - 图片预览' }}
|
||||
Content-Type: image/png
|
||||
Content-Length: 1024
|
||||
Cache-Control: public, max-age=3600
|
||||
```
|
||||
</CodeGroup>
|
||||
|
||||
### 文件下载响应标头
|
||||
<CodeGroup title="Download Response Headers">
|
||||
```http {{ title: 'Headers - 文件下载' }}
|
||||
Content-Type: image/png
|
||||
Content-Length: 1024
|
||||
Content-Disposition: attachment; filename*=UTF-8''example.png
|
||||
Cache-Control: public, max-age=3600
|
||||
```
|
||||
</CodeGroup>
|
||||
</Col>
|
||||
</Row>
|
||||
---
|
||||
|
||||
<Heading
|
||||
url='/workflows/logs'
|
||||
method='GET'
|
||||
|
||||
@ -1,5 +1,4 @@
|
||||
'use client'
|
||||
import type { ForwardRefRenderFunction } from 'react'
|
||||
import { useImperativeHandle } from 'react'
|
||||
import React, { useCallback, useEffect, useMemo, useState } from 'react'
|
||||
import type { Dependency, GitHubItemAndMarketPlaceDependency, PackageDependency, Plugin, VersionInfo } from '../../../types'
|
||||
@ -21,6 +20,7 @@ type Props = {
|
||||
onDeSelectAll: () => void
|
||||
onLoadedAllPlugin: (installedInfo: Record<string, VersionInfo>) => void
|
||||
isFromMarketPlace?: boolean
|
||||
ref?: React.Ref<ExposeRefs>
|
||||
}
|
||||
|
||||
export type ExposeRefs = {
|
||||
@ -28,7 +28,7 @@ export type ExposeRefs = {
|
||||
deSelectAllPlugins: () => void
|
||||
}
|
||||
|
||||
const InstallByDSLList: ForwardRefRenderFunction<ExposeRefs, Props> = ({
|
||||
const InstallByDSLList = ({
|
||||
allPlugins,
|
||||
selectedPlugins,
|
||||
onSelect,
|
||||
@ -36,7 +36,8 @@ const InstallByDSLList: ForwardRefRenderFunction<ExposeRefs, Props> = ({
|
||||
onDeSelectAll,
|
||||
onLoadedAllPlugin,
|
||||
isFromMarketPlace,
|
||||
}, ref) => {
|
||||
ref,
|
||||
}: Props) => {
|
||||
const systemFeatures = useGlobalPublicStore(s => s.systemFeatures)
|
||||
// DSL has id, to get plugin info to show more info
|
||||
const { isLoading: isFetchingMarketplaceDataById, data: infoGetById, error: infoByIdError } = useFetchPluginsInMarketPlaceByInfo(allPlugins.filter(d => d.type === 'marketplace').map((d) => {
|
||||
@ -268,4 +269,4 @@ const InstallByDSLList: ForwardRefRenderFunction<ExposeRefs, Props> = ({
|
||||
</>
|
||||
)
|
||||
}
|
||||
export default React.forwardRef(InstallByDSLList)
|
||||
export default InstallByDSLList
|
||||
|
||||
@ -82,9 +82,7 @@ const PluginTypeSwitch = ({
|
||||
}, [showSearchParams, handleActivePluginTypeChange])
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('popstate', () => {
|
||||
handlePopState()
|
||||
})
|
||||
window.addEventListener('popstate', handlePopState)
|
||||
return () => {
|
||||
window.removeEventListener('popstate', handlePopState)
|
||||
}
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
'use client'
|
||||
import React, { forwardRef, useEffect, useImperativeHandle, useMemo, useRef } from 'react'
|
||||
import React, { useEffect, useImperativeHandle, useMemo, useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import useStickyScroll, { ScrollPosition } from '../use-sticky-scroll'
|
||||
import Item from './item'
|
||||
@ -17,18 +17,20 @@ export type ListProps = {
|
||||
tags: string[]
|
||||
toolContentClassName?: string
|
||||
disableMaxWidth?: boolean
|
||||
ref?: React.Ref<ListRef>
|
||||
}
|
||||
|
||||
export type ListRef = { handleScroll: () => void }
|
||||
|
||||
const List = forwardRef<ListRef, ListProps>(({
|
||||
const List = ({
|
||||
wrapElemRef,
|
||||
searchText,
|
||||
tags,
|
||||
list,
|
||||
toolContentClassName,
|
||||
disableMaxWidth = false,
|
||||
}, ref) => {
|
||||
ref,
|
||||
}: ListProps) => {
|
||||
const { t } = useTranslation()
|
||||
const hasFilter = !searchText
|
||||
const hasRes = list.length > 0
|
||||
@ -125,7 +127,7 @@ const List = forwardRef<ListRef, ListProps>(({
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
List.displayName = 'List'
|
||||
|
||||
|
||||
Reference in New Issue
Block a user