mirror of
https://github.com/langgenius/dify.git
synced 2026-05-01 01:00:51 -04:00
fix merge error
This commit is contained in:
@@ -26,14 +26,14 @@ vi.mock('@/utils/download', () => ({
|
||||
downloadBlob: (args: { data: Blob, fileName: string }) => mockDownloadBlob(args),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
vi.mock('@langgenius/dify-ui/toast', () => ({
|
||||
toast: {
|
||||
success: (...args: unknown[]) => mockToastSuccess(...args),
|
||||
error: (...args: unknown[]) => mockToastError(...args),
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/ui/dropdown-menu', () => ({
|
||||
vi.mock('@langgenius/dify-ui/dropdown-menu', () => ({
|
||||
DropdownMenu: ({
|
||||
open,
|
||||
onOpenChange,
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
|
||||
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
||||
import type { SnippetDetail } from '@/models/snippet'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import * as React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogActions,
|
||||
@@ -13,15 +10,18 @@ import {
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogTitle,
|
||||
} from '@/app/components/base/ui/alert-dialog'
|
||||
} from '@langgenius/dify-ui/alert-dialog'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuSeparator,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/app/components/base/ui/dropdown-menu'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
} from '@langgenius/dify-ui/dropdown-menu'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import * as React from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import CreateSnippetDialog from '@/app/components/workflow/create-snippet-dialog'
|
||||
import { useRouter } from '@/next/navigation'
|
||||
import { useDeleteSnippetMutation, useExportSnippetMutation, useUpdateSnippetMutation } from '@/service/use-snippets'
|
||||
|
||||
@@ -18,6 +18,7 @@ const mockToastError = vi.fn()
|
||||
const mockConvertWorkflowType = vi.fn()
|
||||
const mockRefetchEvaluationWorkflowAssociatedTargets = vi.fn()
|
||||
const mockInvalidateAppWorkflow = vi.fn()
|
||||
let mockCanAccessSnippetsAndEvaluation = true
|
||||
|
||||
const sectionProps = vi.hoisted(() => ({
|
||||
summary: null as null | Record<string, any>,
|
||||
@@ -72,6 +73,13 @@ vi.mock('@/hooks/use-async-window-open', () => ({
|
||||
useAsyncWindowOpen: () => mockOpenAsyncWindow,
|
||||
}))
|
||||
|
||||
vi.mock('@/hooks/use-snippet-and-evaluation-plan-access', () => ({
|
||||
useSnippetAndEvaluationPlanAccess: () => ({
|
||||
canAccess: mockCanAccessSnippetsAndEvaluation,
|
||||
isReady: true,
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/service/access-control', () => ({
|
||||
useGetUserCanAccessApp: () => ({
|
||||
data: { result: true },
|
||||
@@ -194,6 +202,7 @@ describe('AppPublisher', () => {
|
||||
sectionProps.summary = null
|
||||
sectionProps.access = null
|
||||
sectionProps.actions = null
|
||||
mockCanAccessSnippetsAndEvaluation = true
|
||||
mockAppDetail = {
|
||||
id: 'app-1',
|
||||
name: 'Demo App',
|
||||
@@ -657,4 +666,25 @@ describe('AppPublisher', () => {
|
||||
expect(sectionProps.summary?.workflowTypeSwitchDisabled).toBe(true)
|
||||
expect(sectionProps.summary?.workflowTypeSwitchDisabledReason).toBe('common.switchToEvaluationWorkflowDisabledTip')
|
||||
})
|
||||
|
||||
it('should keep the evaluation workflow switch visible but disabled when the current plan cannot access it', () => {
|
||||
mockCanAccessSnippetsAndEvaluation = false
|
||||
|
||||
render(
|
||||
<AppPublisher
|
||||
publishedAt={Date.now()}
|
||||
/>,
|
||||
)
|
||||
|
||||
fireEvent.click(screen.getByText('common.publish'))
|
||||
|
||||
expect(sectionProps.summary?.workflowTypeSwitchConfig).toEqual({
|
||||
targetType: AppTypeEnum.EVALUATION,
|
||||
publishLabelKey: 'common.publishAsEvaluationWorkflow',
|
||||
switchLabelKey: 'common.switchToEvaluationWorkflow',
|
||||
tipKey: 'common.switchToEvaluationWorkflowTip',
|
||||
})
|
||||
expect(sectionProps.summary?.workflowTypeSwitchDisabled).toBe(true)
|
||||
expect(sectionProps.summary?.workflowTypeSwitchDisabledReason).toBe('compliance.sandboxUpgradeTooltip')
|
||||
})
|
||||
})
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
import type { EvaluationWorkflowAssociatedTarget, EvaluationWorkflowAssociatedTargetType } from '@/types/evaluation'
|
||||
import type { I18nKeysWithPrefix } from '@/types/i18n'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
AlertDialog,
|
||||
AlertDialogActions,
|
||||
@@ -12,7 +10,9 @@ import {
|
||||
AlertDialogContent,
|
||||
AlertDialogDescription,
|
||||
AlertDialogTitle,
|
||||
} from '@/app/components/base/ui/alert-dialog'
|
||||
} from '@langgenius/dify-ui/alert-dialog'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Link from '@/next/link'
|
||||
|
||||
type EvaluationWorkflowSwitchConfirmDialogProps = {
|
||||
@@ -80,7 +80,7 @@ const DependentTargetItem = ({
|
||||
<span className={cn(meta.icon, 'size-5')} />
|
||||
</span>
|
||||
<span className="flex min-w-0 flex-1 flex-col gap-1 py-px">
|
||||
<span className="system-md-semibold truncate text-text-secondary">
|
||||
<span className="truncate system-md-semibold text-text-secondary">
|
||||
{targetName}
|
||||
</span>
|
||||
<span className="system-2xs-medium-uppercase text-text-tertiary">
|
||||
@@ -108,10 +108,10 @@ const EvaluationWorkflowSwitchConfirmDialog = ({
|
||||
<AlertDialog open={open} onOpenChange={onOpenChange}>
|
||||
<AlertDialogContent className="w-[480px]">
|
||||
<div className="flex flex-col gap-2 px-6 pt-6 pb-4">
|
||||
<AlertDialogTitle className="title-2xl-semi-bold w-full text-text-primary">
|
||||
<AlertDialogTitle className="w-full title-2xl-semi-bold text-text-primary">
|
||||
{t('common.switchToStandardWorkflowConfirm.title', { ns: 'workflow' })}
|
||||
</AlertDialogTitle>
|
||||
<AlertDialogDescription className="system-md-regular w-full text-text-secondary">
|
||||
<AlertDialogDescription className="w-full system-md-regular text-text-secondary">
|
||||
<span className="block">
|
||||
{t('common.switchToStandardWorkflowConfirm.activeIn', { ns: 'workflow', count: targets.length })}
|
||||
</span>
|
||||
@@ -123,7 +123,7 @@ const EvaluationWorkflowSwitchConfirmDialog = ({
|
||||
|
||||
<div className="flex flex-col gap-2 px-6 py-3">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="system-xs-medium-uppercase shrink-0 text-text-quaternary">
|
||||
<span className="shrink-0 system-xs-medium-uppercase text-text-quaternary">
|
||||
{t('common.switchToStandardWorkflowConfirm.dependentWorkflows', { ns: 'workflow' })}
|
||||
</span>
|
||||
<span className="h-px min-w-0 flex-1 bg-divider-subtle" />
|
||||
|
||||
@@ -149,11 +149,8 @@ const AppPublisher = ({
|
||||
if (!isWorkflowTypeConversionTarget(appDetail?.type))
|
||||
return undefined
|
||||
|
||||
if (appDetail.type !== AppTypeEnum.EVALUATION && !canAccessSnippetsAndEvaluation)
|
||||
return undefined
|
||||
|
||||
return WORKFLOW_TYPE_SWITCH_CONFIG[appDetail.type]
|
||||
}, [appDetail?.type, canAccessSnippetsAndEvaluation])
|
||||
}, [appDetail?.type])
|
||||
const isEvaluationWorkflowType = appDetail?.type === AppTypeEnum.EVALUATION
|
||||
const {
|
||||
refetch: refetchEvaluationWorkflowAssociatedTargets,
|
||||
@@ -163,11 +160,14 @@ const AppPublisher = ({
|
||||
if (workflowTypeSwitchConfig?.targetType !== AppTypeEnum.EVALUATION)
|
||||
return undefined
|
||||
|
||||
if (!canAccessSnippetsAndEvaluation)
|
||||
return t('compliance.sandboxUpgradeTooltip', { ns: 'common' })
|
||||
|
||||
if (!hasHumanInputNode && !hasTriggerNode)
|
||||
return undefined
|
||||
|
||||
return t('common.switchToEvaluationWorkflowDisabledTip', { ns: 'workflow' })
|
||||
}, [hasHumanInputNode, hasTriggerNode, t, workflowTypeSwitchConfig?.targetType])
|
||||
}, [canAccessSnippetsAndEvaluation, hasHumanInputNode, hasTriggerNode, t, workflowTypeSwitchConfig?.targetType])
|
||||
|
||||
const { data: userCanAccessApp, isLoading: isGettingUserCanAccessApp, refetch } = useGetUserCanAccessApp({ appId: appDetail?.id, enabled: false })
|
||||
const { data: appAccessSubjects, isLoading: isGettingAppWhiteListSubjects } = useAppWhiteListSubjects(appDetail?.id, open && systemFeatures.webapp_auth.enabled && appDetail?.access_mode === AccessMode.SPECIFIC_GROUPS_MEMBERS)
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
|
||||
import type { EvaluationLogItem } from '@/models/log'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/app/components/base/ui/popover'
|
||||
} from '@langgenius/dify-ui/popover'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { getNodeVisual, getToneClasses } from '@/app/components/evaluation/components/metric-selector/utils'
|
||||
|
||||
type EvaluationCellProps = {
|
||||
@@ -30,7 +30,7 @@ const EvaluationCell = ({
|
||||
|
||||
if (!evaluation.length) {
|
||||
return (
|
||||
<div className="system-sm-regular flex items-center justify-center px-2 py-3 text-text-quaternary">
|
||||
<div className="flex items-center justify-center px-2 py-3 system-sm-regular text-text-quaternary">
|
||||
-
|
||||
</div>
|
||||
)
|
||||
@@ -73,19 +73,19 @@ const EvaluationCell = ({
|
||||
)}
|
||||
>
|
||||
<div className="min-w-0">
|
||||
<div className="system-sm-medium truncate text-text-secondary">{item.name}</div>
|
||||
<div className="truncate system-sm-medium text-text-secondary">{item.name}</div>
|
||||
{item.nodeInfo && nodeVisual && nodeToneClasses && (
|
||||
<div className="mt-1 flex min-w-0 items-center gap-1.5">
|
||||
<div className={cn('flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-md border-[0.45px] border-divider-subtle shadow-xs shadow-shadow-shadow-3', nodeToneClasses.solid)}>
|
||||
<span aria-hidden="true" className={cn(nodeVisual.icon, 'h-3.5 w-3.5')} />
|
||||
</div>
|
||||
<span className="system-xs-regular truncate text-text-tertiary">
|
||||
<span className="truncate system-xs-regular text-text-tertiary">
|
||||
{item.nodeInfo.title}
|
||||
</span>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
<div className="system-sm-regular max-w-[120px] text-right wrap-break-word text-text-secondary">
|
||||
<div className="max-w-[120px] text-right system-sm-regular wrap-break-word text-text-secondary">
|
||||
{formatEvaluationValue(item.value)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
'use client'
|
||||
|
||||
import { Avatar } from '@langgenius/dify-ui/avatar'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Checkbox from '@/app/components/base/checkbox'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { Avatar } from '@/app/components/base/ui/avatar'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/app/components/base/ui/dropdown-menu'
|
||||
} from '@langgenius/dify-ui/dropdown-menu'
|
||||
import { useCallback, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Checkbox from '@/app/components/base/checkbox'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { useAppContext } from '@/context/app-context'
|
||||
import { useMembers } from '@/service/use-common'
|
||||
|
||||
|
||||
@@ -1,16 +1,16 @@
|
||||
import type { EvaluationResourceProps } from '../../types'
|
||||
import type { EvaluationLog, EvaluationLogFile } from '@/types/evaluation'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { keepPreviousData, useMutation, useQuery } from '@tanstack/react-query'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Pagination from '@/app/components/base/pagination'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/app/components/base/ui/dropdown-menu'
|
||||
} from '@langgenius/dify-ui/dropdown-menu'
|
||||
import { keepPreviousData, useMutation, useQuery } from '@tanstack/react-query'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Pagination from '@/app/components/base/pagination'
|
||||
import { consoleClient, consoleQuery } from '@/service/client'
|
||||
import { downloadUrl } from '@/utils/download'
|
||||
import { useEvaluationResource, useEvaluationStore } from '../../store'
|
||||
@@ -92,15 +92,15 @@ const HistoryTab = ({
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr className="border-b border-divider-regular">
|
||||
<th className="system-xs-medium-uppercase h-7 px-3 text-left text-text-tertiary">
|
||||
<th className="h-7 px-3 text-left system-xs-medium-uppercase text-text-tertiary">
|
||||
<span className="inline-flex items-center gap-0.5">
|
||||
{t('history.columns.time')}
|
||||
<span aria-hidden="true" className="i-ri-arrow-down-line h-3.5 w-3.5" />
|
||||
</span>
|
||||
</th>
|
||||
<th className="system-xs-medium-uppercase h-7 px-3 text-left text-text-tertiary">{t('history.columns.creator')}</th>
|
||||
<th className="system-xs-medium-uppercase h-7 px-3 text-left text-text-tertiary">{t('history.columns.version')}</th>
|
||||
<th className="system-xs-medium-uppercase h-7 px-3 text-left text-text-tertiary">{t('history.columns.status')}</th>
|
||||
<th className="h-7 px-3 text-left system-xs-medium-uppercase text-text-tertiary">{t('history.columns.creator')}</th>
|
||||
<th className="h-7 px-3 text-left system-xs-medium-uppercase text-text-tertiary">{t('history.columns.version')}</th>
|
||||
<th className="h-7 px-3 text-left system-xs-medium-uppercase text-text-tertiary">{t('history.columns.status')}</th>
|
||||
<th className="h-7 text-center text-text-tertiary">
|
||||
<span aria-hidden="true" className="i-ri-download-2-line inline-block h-3.5 w-3.5" />
|
||||
</th>
|
||||
@@ -128,9 +128,9 @@ const HistoryTab = ({
|
||||
setSelectedRunId(resourceType, resourceId, runId)
|
||||
}}
|
||||
>
|
||||
<td className="system-sm-regular h-10 truncate px-3 text-text-secondary">{formatCreatedAt(record.created_at)}</td>
|
||||
<td className="system-sm-regular h-10 truncate px-3 text-text-secondary">{record.created_by}</td>
|
||||
<td className="system-sm-regular h-10 truncate px-3 text-text-secondary">{record.version || '-'}</td>
|
||||
<td className="h-10 truncate px-3 system-sm-regular text-text-secondary">{formatCreatedAt(record.created_at)}</td>
|
||||
<td className="h-10 truncate px-3 system-sm-regular text-text-secondary">{record.created_by}</td>
|
||||
<td className="h-10 truncate px-3 system-sm-regular text-text-secondary">{record.version || '-'}</td>
|
||||
<td className="h-10 px-3 text-center">
|
||||
{record.result_file
|
||||
? <span aria-label={t('history.status.completed')} className="i-ri-checkbox-circle-fill inline-block h-4 w-4 text-util-colors-green-green-600" />
|
||||
@@ -181,7 +181,7 @@ const HistoryTab = ({
|
||||
</tbody>
|
||||
</table>
|
||||
{!isInitialLoading && records.length === 0 && (
|
||||
<div className="system-sm-regular rounded-2xl border border-dashed border-divider-subtle px-4 py-10 text-center text-text-tertiary">
|
||||
<div className="rounded-2xl border border-dashed border-divider-subtle px-4 py-10 text-center system-sm-regular text-text-tertiary">
|
||||
{t('history.empty')}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use client'
|
||||
|
||||
import type { BatchTestTab, EvaluationResourceProps } from '../../types'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { useSaveEvaluationConfigMutation } from '@/service/use-evaluation'
|
||||
import { isEvaluationRunnable, useEvaluationResource, useEvaluationStore } from '../../store'
|
||||
import { buildEvaluationConfigPayload } from '../../store-utils'
|
||||
@@ -65,7 +65,7 @@ const BatchTestPanel = ({
|
||||
<div className="flex items-start justify-between gap-3">
|
||||
<div className="min-w-0">
|
||||
<div className="system-xl-semibold text-text-primary">{t('batch.title')}</div>
|
||||
<div className="system-sm-regular mt-1 text-text-tertiary">{t('batch.description')}</div>
|
||||
<div className="mt-1 system-sm-regular text-text-tertiary">{t('batch.description')}</div>
|
||||
</div>
|
||||
<Button
|
||||
className="shrink-0"
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { EvaluationResourceProps } from '../../types'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import { getEvaluationMockConfig } from '../../mock'
|
||||
import InputFieldsRequirements from './input-fields/input-fields-requirements'
|
||||
import UploadRunPopover from './input-fields/upload-run-popover'
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
import type { ChangeEvent, DragEvent } from 'react'
|
||||
import type { InputField } from './input-fields-utils'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/app/components/base/ui/popover'
|
||||
} from '@langgenius/dify-ui/popover'
|
||||
import { useRef } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { getExampleValue } from './input-fields-utils'
|
||||
|
||||
type UploadRunPopoverProps = {
|
||||
@@ -92,10 +92,10 @@ const UploadRunPopover = ({
|
||||
<span aria-hidden="true" className="i-ri-file-excel-fill h-6 w-6 text-util-colors-green-green-600" />
|
||||
</div>
|
||||
<div className="min-w-0 flex-1 py-1 pr-2">
|
||||
<div className="system-xs-medium truncate text-text-secondary">
|
||||
<div className="truncate system-xs-medium text-text-secondary">
|
||||
{currentFileName}
|
||||
</div>
|
||||
<div className="system-2xs-medium mt-0.5 flex h-3 items-center gap-1 text-text-tertiary">
|
||||
<div className="mt-0.5 flex h-3 items-center gap-1 system-2xs-medium text-text-tertiary">
|
||||
{!!currentFileExtension && <span className="uppercase">{currentFileExtension}</span>}
|
||||
{!!currentFileExtension && !!currentFileSize && <span className="text-text-quaternary">·</span>}
|
||||
{!!currentFileSize && <span>{currentFileSize}</span>}
|
||||
@@ -138,7 +138,7 @@ const UploadRunPopover = ({
|
||||
{' '}
|
||||
{t('batch.uploadDropzoneSuffix')}
|
||||
</div>
|
||||
<div className="system-xs-regular mt-0.5 text-text-tertiary">
|
||||
<div className="mt-0.5 system-xs-regular text-text-tertiary">
|
||||
{t('batch.uploadDropzoneDownloadPrefix')}
|
||||
{' '}
|
||||
<button
|
||||
@@ -159,10 +159,10 @@ const UploadRunPopover = ({
|
||||
<div className="flex overflow-hidden rounded-lg border border-divider-regular">
|
||||
{previewFields.map((field, index) => (
|
||||
<div key={field.name} className={cn('min-w-0 flex-1', index < previewFields.length - 1 && 'border-r border-divider-subtle')}>
|
||||
<div className="system-xs-medium-uppercase min-h-8 border-b border-divider-regular px-3 py-2 text-text-tertiary">
|
||||
<div className="min-h-8 border-b border-divider-regular px-3 py-2 system-xs-medium-uppercase text-text-tertiary">
|
||||
{field.name}
|
||||
</div>
|
||||
<div className="system-sm-regular min-h-8 px-3 py-2 text-text-secondary">
|
||||
<div className="min-h-8 px-3 py-2 system-sm-regular text-text-secondary">
|
||||
{getExampleValue(field, booleanExampleValue)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { EvaluationResourceProps } from '../../../types'
|
||||
import type { InputField } from './input-fields-utils'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { useMutation } from '@tanstack/react-query'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { upload } from '@/service/base'
|
||||
import { useStartEvaluationRunMutation } from '@/service/use-evaluation'
|
||||
import { formatFileSize } from '@/utils/format'
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
|
||||
import type { ConditionMetricOptionGroup, EvaluationResourceProps } from '../../types'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -11,7 +9,9 @@ import {
|
||||
SelectGroupLabel,
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
} from '@/app/components/base/ui/select'
|
||||
} from '@langgenius/dify-ui/select'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useEvaluationStore } from '../../store'
|
||||
import { getConditionMetricValueTypeTranslationKey } from '../../utils'
|
||||
|
||||
@@ -46,7 +46,7 @@ const AddConditionSelect = ({
|
||||
<SelectContent placement="bottom-start" popupClassName="w-[320px]">
|
||||
{metricOptionGroups.map(group => (
|
||||
<SelectGroup key={group.label}>
|
||||
<SelectGroupLabel className="system-xs-medium-uppercase px-3 pt-2 pb-1 text-text-tertiary">{group.label}</SelectGroupLabel>
|
||||
<SelectGroupLabel className="px-3 pt-2 pb-1 system-xs-medium-uppercase text-text-tertiary">{group.label}</SelectGroupLabel>
|
||||
{group.options.map(option => (
|
||||
<SelectItem
|
||||
key={option.id}
|
||||
@@ -58,8 +58,8 @@ const AddConditionSelect = ({
|
||||
}}
|
||||
>
|
||||
<div className="flex min-w-0 flex-1 items-center gap-3">
|
||||
<span className="system-sm-medium truncate text-text-secondary">{option.itemLabel}</span>
|
||||
<span className="system-xs-medium ml-auto shrink-0 text-text-tertiary">
|
||||
<span className="truncate system-sm-medium text-text-secondary">{option.itemLabel}</span>
|
||||
<span className="ml-auto shrink-0 system-xs-medium text-text-tertiary">
|
||||
{t(getConditionMetricValueTypeTranslationKey(option.valueType))}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
@@ -6,11 +6,8 @@ import type {
|
||||
EvaluationResourceProps,
|
||||
JudgmentConditionItem,
|
||||
} from '../../types'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import {
|
||||
Select,
|
||||
SelectContent,
|
||||
@@ -19,7 +16,10 @@ import {
|
||||
SelectItem,
|
||||
SelectTrigger,
|
||||
SelectValue,
|
||||
} from '@/app/components/base/ui/select'
|
||||
} from '@langgenius/dify-ui/select'
|
||||
import { useMemo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { getAllowedOperators, requiresConditionValue, useEvaluationResource, useEvaluationStore } from '../../store'
|
||||
import {
|
||||
buildConditionMetricOptions,
|
||||
@@ -71,15 +71,15 @@ const ConditionMetricLabel = ({
|
||||
placeholder,
|
||||
}: ConditionMetricLabelProps) => {
|
||||
if (!metric)
|
||||
return <span className="system-sm-regular px-1 text-components-input-text-placeholder">{placeholder}</span>
|
||||
return <span className="px-1 system-sm-regular text-components-input-text-placeholder">{placeholder}</span>
|
||||
|
||||
return (
|
||||
<div className="flex min-w-0 items-center gap-2 px-1">
|
||||
<div className="inline-flex h-6 min-w-0 items-center gap-1 rounded-md border-[0.5px] border-components-panel-border-subtle bg-components-badge-white-to-dark pr-1.5 pl-[5px] shadow-xs">
|
||||
<span className={cn(getMetricValueTypeIconClassName(metric.valueType), 'h-3 w-3 shrink-0 text-text-secondary')} />
|
||||
<span className="system-xs-medium truncate text-text-secondary">{metric.itemLabel}</span>
|
||||
<span className="truncate system-xs-medium text-text-secondary">{metric.itemLabel}</span>
|
||||
</div>
|
||||
<span className="system-xs-regular shrink-0 text-text-tertiary">{metric.groupLabel}</span>
|
||||
<span className="shrink-0 system-xs-regular text-text-tertiary">{metric.groupLabel}</span>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
@@ -110,13 +110,13 @@ const ConditionMetricSelect = ({
|
||||
<SelectContent popupClassName="w-[360px]">
|
||||
{groupedMetricOptions.map(group => (
|
||||
<SelectGroup key={group.label}>
|
||||
<SelectGroupLabel className="system-xs-medium-uppercase px-3 pt-2 pb-1 text-text-tertiary">{group.label}</SelectGroupLabel>
|
||||
<SelectGroupLabel className="px-3 pt-2 pb-1 system-xs-medium-uppercase text-text-tertiary">{group.label}</SelectGroupLabel>
|
||||
{group.options.map(option => (
|
||||
<SelectItem key={option.id} value={serializeVariableSelector(option.variableSelector)}>
|
||||
<div className="flex min-w-0 flex-1 items-center gap-2">
|
||||
<span className={cn(getMetricValueTypeIconClassName(option.valueType), 'h-3.5 w-3.5 shrink-0 text-text-tertiary')} />
|
||||
<span className="truncate">{option.itemLabel}</span>
|
||||
<span className="system-xs-medium ml-auto shrink-0 text-text-quaternary">
|
||||
<span className="ml-auto shrink-0 system-xs-medium text-text-quaternary">
|
||||
{t(getConditionMetricValueTypeTranslationKey(option.valueType))}
|
||||
</span>
|
||||
</div>
|
||||
@@ -139,7 +139,7 @@ const ConditionOperatorSelect = ({
|
||||
return (
|
||||
<Select value={operator} onValueChange={value => value && onChange(value as ComparisonOperator)}>
|
||||
<SelectTrigger className="h-8 w-auto min-w-[88px] gap-1 rounded-md bg-transparent px-1.5 py-0 hover:bg-state-base-hover-alt focus-visible:bg-state-base-hover-alt">
|
||||
<span className="system-xs-medium truncate text-text-secondary">{getComparisonOperatorLabel(operator, t)}</span>
|
||||
<span className="truncate system-xs-medium text-text-secondary">{getComparisonOperatorLabel(operator, t)}</span>
|
||||
</SelectTrigger>
|
||||
<SelectContent className="z-[1002]" popupClassName="w-[240px] bg-components-panel-bg-blur backdrop-blur-[10px]">
|
||||
{operators.map(nextOperator => (
|
||||
@@ -232,7 +232,7 @@ const ConditionGroup = ({
|
||||
key={operator}
|
||||
type="button"
|
||||
className={cn(
|
||||
'system-xs-medium-uppercase rounded-md px-3 py-1.5',
|
||||
'rounded-md px-3 py-1.5 system-xs-medium-uppercase',
|
||||
resource.judgmentConfig.logicalOperator === operator
|
||||
? 'bg-components-card-bg text-text-primary shadow-xs'
|
||||
: 'text-text-tertiary',
|
||||
|
||||
@@ -2,24 +2,24 @@
|
||||
|
||||
import type { AvailableEvaluationWorkflow } from '@/types/evaluation'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useInfiniteScroll } from 'ahooks'
|
||||
import * as React from 'react'
|
||||
import { useDeferredValue, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/app/components/base/ui/popover'
|
||||
} from '@langgenius/dify-ui/popover'
|
||||
import {
|
||||
ScrollAreaContent,
|
||||
ScrollAreaRoot,
|
||||
ScrollAreaScrollbar,
|
||||
ScrollAreaThumb,
|
||||
ScrollAreaViewport,
|
||||
} from '@/app/components/base/ui/scroll-area'
|
||||
} from '@langgenius/dify-ui/scroll-area'
|
||||
import { useInfiniteScroll } from 'ahooks'
|
||||
import * as React from 'react'
|
||||
import { useDeferredValue, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { useAvailableEvaluationWorkflows } from '@/service/use-evaluation'
|
||||
|
||||
type WorkflowSelectorProps = {
|
||||
@@ -119,7 +119,7 @@ const WorkflowSelector = ({
|
||||
</div>
|
||||
<div className="min-w-0 flex-1 px-1 py-1 text-left">
|
||||
<div className={cn(
|
||||
'system-sm-regular truncate',
|
||||
'truncate system-sm-regular',
|
||||
currentWorkflowName ? 'text-text-secondary' : 'text-components-input-text-placeholder',
|
||||
)}
|
||||
>
|
||||
@@ -158,7 +158,7 @@ const WorkflowSelector = ({
|
||||
)
|
||||
: !workflows.length
|
||||
? (
|
||||
<div className="system-sm-regular flex h-[120px] items-center justify-center text-text-tertiary">
|
||||
<div className="flex h-[120px] items-center justify-center system-sm-regular text-text-tertiary">
|
||||
{t('noData', { ns: 'common' })}
|
||||
</div>
|
||||
)
|
||||
@@ -184,7 +184,7 @@ const WorkflowSelector = ({
|
||||
<span aria-hidden="true" className="i-ri-equalizer-2-line h-3.5 w-3.5 text-text-tertiary" />
|
||||
</div>
|
||||
</div>
|
||||
<div className="system-sm-medium min-w-0 flex-1 truncate px-1 py-1 text-text-secondary">
|
||||
<div className="min-w-0 flex-1 truncate px-1 py-1 system-sm-medium text-text-secondary">
|
||||
{getWorkflowName(workflow)}
|
||||
</div>
|
||||
{workflow.id === value && (
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
import type { EvaluationMetric, EvaluationResourceProps } from '../../types'
|
||||
import type { NodeInfo } from '@/types/evaluation'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuItem,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/app/components/base/ui/dropdown-menu'
|
||||
} from '@langgenius/dify-ui/dropdown-menu'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useEvaluationStore } from '../../store'
|
||||
import { dedupeNodeInfoList, getMetricVisual, getNodeVisual, getToneClasses } from '../metric-selector/utils'
|
||||
|
||||
@@ -53,7 +53,7 @@ const BuiltinMetricCard = ({
|
||||
<span aria-hidden="true" className={cn(metricVisual.icon, 'h-3.5 w-3.5')} />
|
||||
</div>
|
||||
<div className="flex min-w-0 items-center gap-0.5">
|
||||
<div className="system-md-medium truncate text-text-secondary">{metric.label}</div>
|
||||
<div className="truncate system-md-medium text-text-secondary">{metric.label}</div>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
className={cn('i-ri-arrow-down-s-line h-4 w-4 shrink-0 text-text-quaternary transition-transform', !isExpanded && '-rotate-90')}
|
||||
@@ -87,7 +87,7 @@ const BuiltinMetricCard = ({
|
||||
<div className={cn('flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-md border-[0.45px] border-divider-subtle shadow-xs shadow-shadow-shadow-3', nodeToneClasses.solid)}>
|
||||
<span aria-hidden="true" className={cn(nodeVisual.icon, 'h-3.5 w-3.5')} />
|
||||
</div>
|
||||
<span className="system-xs-regular px-1 text-text-primary">{nodeInfo.title}</span>
|
||||
<span className="px-1 system-xs-regular text-text-primary">{nodeInfo.title}</span>
|
||||
<button
|
||||
type="button"
|
||||
className="flex h-4 w-4 items-center justify-center rounded-sm text-text-quaternary transition-colors hover:text-text-secondary"
|
||||
@@ -105,7 +105,7 @@ const BuiltinMetricCard = ({
|
||||
)
|
||||
})
|
||||
: (
|
||||
<span className="system-xs-regular px-1 text-text-tertiary">{t('metrics.nodesAll')}</span>
|
||||
<span className="px-1 system-xs-regular text-text-tertiary">{t('metrics.nodesAll')}</span>
|
||||
)}
|
||||
|
||||
{shouldShowAddNode && (
|
||||
@@ -144,7 +144,7 @@ const BuiltinMetricCard = ({
|
||||
<div className={cn('flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-md border-[0.45px] border-divider-subtle shadow-xs shadow-shadow-shadow-3', nodeToneClasses.solid)}>
|
||||
<span aria-hidden="true" className={cn(nodeVisual.icon, 'h-3.5 w-3.5')} />
|
||||
</div>
|
||||
<span className="system-sm-medium truncate text-text-secondary">{nodeInfo.title}</span>
|
||||
<span className="truncate system-sm-medium text-text-secondary">{nodeInfo.title}</span>
|
||||
</div>
|
||||
</DropdownMenuItem>
|
||||
)
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
'use client'
|
||||
|
||||
import type { EvaluationMetric, EvaluationResourceProps } from '../../types'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Badge from '@/app/components/base/badge'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import { isCustomMetricConfigured, useEvaluationStore } from '../../store'
|
||||
import CustomMetricEditorCard from '../custom-metric-editor'
|
||||
import { getToneClasses } from '../metric-selector/utils'
|
||||
@@ -30,7 +30,7 @@ const CustomMetricCard = ({
|
||||
<div className={cn('flex h-[18px] w-[18px] shrink-0 items-center justify-center rounded-[5px]', metricToneClasses.soft)}>
|
||||
<span aria-hidden="true" className="i-ri-equalizer-2-line h-3.5 w-3.5" />
|
||||
</div>
|
||||
<div className="system-md-medium truncate text-text-secondary">{metric.label}</div>
|
||||
<div className="truncate system-md-medium text-text-secondary">{metric.label}</div>
|
||||
</div>
|
||||
|
||||
<div className="flex shrink-0 items-center gap-1">
|
||||
|
||||
@@ -2,16 +2,16 @@
|
||||
|
||||
import type { ChangeEvent } from 'react'
|
||||
import type { MetricSelectorProps } from './types'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import {
|
||||
Popover,
|
||||
PopoverContent,
|
||||
PopoverTrigger,
|
||||
} from '@/app/components/base/ui/popover'
|
||||
} from '@langgenius/dify-ui/popover'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { useEvaluationResource, useEvaluationStore } from '../../store'
|
||||
import SelectorEmptyState from './selector-empty-state'
|
||||
import SelectorFooter from './selector-footer'
|
||||
@@ -68,7 +68,7 @@ const MetricSelector = ({
|
||||
render={(
|
||||
triggerStyle === 'text'
|
||||
? (
|
||||
<button type="button" className={cn('system-sm-medium inline-flex items-center text-text-accent', triggerClassName)}>
|
||||
<button type="button" className={cn('inline-flex items-center system-sm-medium text-text-accent', triggerClassName)}>
|
||||
<span aria-hidden="true" className="mr-1 i-ri-add-line h-4 w-4" />
|
||||
{t('metrics.add')}
|
||||
</button>
|
||||
|
||||
@@ -2,8 +2,8 @@
|
||||
|
||||
import type { EvaluationResourceProps } from '../../types'
|
||||
import type { InputField } from '../batch-test-panel/input-fields/input-fields-utils'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import { getEvaluationMockConfig } from '../../mock'
|
||||
import { isEvaluationRunnable, useEvaluationResource } from '../../store'
|
||||
import UploadRunPopover from '../batch-test-panel/input-fields/upload-run-popover'
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
|
||||
import type { MetricOption } from '../../types'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Checkbox from '@/app/components/base/checkbox'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/app/components/base/ui/tooltip'
|
||||
import { getTranslatedMetricDescription } from '../../default-metric-descriptions'
|
||||
import { DEFAULT_PIPELINE_METRIC_THRESHOLD } from '../../store-utils'
|
||||
|
||||
@@ -37,7 +37,7 @@ const PipelineMetricItem = ({
|
||||
onClick={onToggle}
|
||||
>
|
||||
<Checkbox checked={selected} />
|
||||
<span className="system-sm-medium truncate text-text-secondary">{metric.label}</span>
|
||||
<span className="truncate system-sm-medium text-text-secondary">{metric.label}</span>
|
||||
<Tooltip>
|
||||
<TooltipTrigger
|
||||
render={(
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
import type { ReactNode } from 'react'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@/app/components/base/ui/tooltip'
|
||||
import { Tooltip, TooltipContent, TooltipTrigger } from '@langgenius/dify-ui/tooltip'
|
||||
|
||||
type SectionHeaderProps = {
|
||||
title: string
|
||||
@@ -32,7 +32,7 @@ const SectionHeader = ({
|
||||
<div className={cn('flex flex-wrap items-start justify-between gap-3', className)}>
|
||||
<div>
|
||||
<div className={cn('system-xl-semibold text-text-primary', titleClassName)}>{title}</div>
|
||||
{description && <div className={cn('system-sm-regular mt-1 text-text-tertiary', descriptionClassName)}>{description}</div>}
|
||||
{description && <div className={cn('mt-1 system-sm-regular text-text-tertiary', descriptionClassName)}>{description}</div>}
|
||||
</div>
|
||||
{action}
|
||||
</div>
|
||||
|
||||
@@ -14,7 +14,7 @@ vi.mock('@/next/navigation', () => ({
|
||||
}),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
vi.mock('@langgenius/dify-ui/toast', () => ({
|
||||
toast: {
|
||||
success: mockToastSuccess,
|
||||
error: mockToastError,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { SnippetInputField } from '@/models/snippet'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { act, renderHook } from '@testing-library/react'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { PipelineInputVarType } from '@/models/pipeline'
|
||||
import { useSnippetInputFieldActions } from '../use-snippet-input-field-actions'
|
||||
|
||||
@@ -23,7 +23,7 @@ let snippetDetailStoreState: {
|
||||
toggleInputPanel: typeof mockToggleInputPanel
|
||||
}
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
vi.mock('@langgenius/dify-ui/toast', () => ({
|
||||
toast: {
|
||||
error: vi.fn(),
|
||||
},
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { act, renderHook, waitFor } from '@testing-library/react'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { useSnippetPublish } from '../use-snippet-publish'
|
||||
|
||||
const mockMutateAsync = vi.fn()
|
||||
@@ -15,7 +15,7 @@ vi.mock('ahooks', () => ({
|
||||
useKeyPress: (...args: Parameters<typeof mockUseKeyPress>) => mockUseKeyPress(...args),
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
vi.mock('@langgenius/dify-ui/toast', () => ({
|
||||
toast: {
|
||||
error: vi.fn(),
|
||||
success: vi.fn(),
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { SnippetInputField } from '@/models/snippet'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { useNodesSyncDraft } from '../../hooks/use-nodes-sync-draft'
|
||||
import { useSnippetDetailStore } from '../../store'
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { useKeyPress } from 'ahooks'
|
||||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useShallow } from 'zustand/react/shallow'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { useWorkflowStore } from '@/app/components/workflow/store'
|
||||
import { getKeyboardKeyCodeBySystem } from '@/app/components/workflow/utils'
|
||||
import { usePublishSnippetWorkflowMutation } from '@/service/use-snippet-workflows'
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import type { FormData, InputFieldFormProps } from '@/app/components/rag-pipeline/components/panel/input-field/editor/form/types'
|
||||
import type { MoreInfo } from '@/app/components/workflow/types'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Divider from '@/app/components/base/divider'
|
||||
import { useFileSizeLimit } from '@/app/components/base/file-uploader/hooks'
|
||||
import { useAppForm } from '@/app/components/base/form'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import HiddenFields from '@/app/components/rag-pipeline/components/panel/input-field/editor/form/hidden-fields'
|
||||
import ShowAllSettings from '@/app/components/rag-pipeline/components/panel/input-field/editor/form/show-all-settings'
|
||||
import { ChangeType } from '@/app/components/workflow/types'
|
||||
|
||||
@@ -2,9 +2,9 @@
|
||||
|
||||
import type { SortableItem } from '@/app/components/rag-pipeline/components/panel/input-field/field-list/types'
|
||||
import type { SnippetInputField } from '@/models/snippet'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { memo, useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import FieldListContainer from '@/app/components/rag-pipeline/components/panel/input-field/field-list/field-list-container'
|
||||
|
||||
type SnippetInputFieldPanelProps = {
|
||||
@@ -45,12 +45,12 @@ const SnippetInputFieldPanel = ({
|
||||
|
||||
return (
|
||||
<div className="mr-1 flex h-full w-[min(400px,calc(100vw-24px))] flex-col rounded-2xl border border-components-panel-border bg-components-panel-bg shadow-xl shadow-shadow-shadow-5">
|
||||
<div className="flex items-start justify-between gap-3 px-4 pb-2 pt-4">
|
||||
<div className="flex items-start justify-between gap-3 px-4 pt-4 pb-2">
|
||||
<div className="min-w-0">
|
||||
<div className="text-text-primary system-xl-semibold">
|
||||
<div className="system-xl-semibold text-text-primary">
|
||||
{t('panelTitle')}
|
||||
</div>
|
||||
<div className="pt-1 text-text-tertiary system-sm-regular">
|
||||
<div className="pt-1 system-sm-regular text-text-tertiary">
|
||||
{t('panelDescription')}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
'use client'
|
||||
|
||||
import type { SnippetDetailUIModel } from '@/models/snippet'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import ShortcutsName from '@/app/components/workflow/shortcuts-name'
|
||||
import { useFormatTimeFromNow } from '@/hooks/use-format-time-from-now'
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
'use client'
|
||||
|
||||
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import CreateSnippetDialog from '@/app/components/workflow/create-snippet-dialog'
|
||||
import { useRouter } from '@/next/navigation'
|
||||
import {
|
||||
@@ -62,22 +62,22 @@ const SnippetCreateCard = () => {
|
||||
<>
|
||||
<div className="relative col-span-1 inline-flex h-[160px] flex-col justify-between rounded-xl border-[0.5px] border-components-card-border bg-components-card-bg transition-opacity">
|
||||
<div className="grow rounded-t-xl p-2">
|
||||
<div className="px-6 pb-1 pt-2 text-xs font-medium leading-[18px] text-text-tertiary">{t('create')}</div>
|
||||
<div className="px-6 pt-2 pb-1 text-xs leading-[18px] font-medium text-text-tertiary">{t('create')}</div>
|
||||
<button
|
||||
type="button"
|
||||
className="mb-1 flex w-full cursor-pointer items-center rounded-lg px-6 py-[7px] text-[13px] font-medium leading-[18px] text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary disabled:cursor-not-allowed disabled:opacity-50"
|
||||
className="mb-1 flex w-full cursor-pointer items-center rounded-lg px-6 py-[7px] text-[13px] leading-[18px] font-medium text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary disabled:cursor-not-allowed disabled:opacity-50"
|
||||
disabled={createSnippetMutation.isPending}
|
||||
onClick={handleCreateFromBlank}
|
||||
>
|
||||
<span aria-hidden className="i-ri-sticky-note-add-line mr-2 h-4 w-4 shrink-0" />
|
||||
<span aria-hidden className="mr-2 i-ri-sticky-note-add-line h-4 w-4 shrink-0" />
|
||||
{t('createFromBlank')}
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
className="flex w-full cursor-pointer items-center rounded-lg px-6 py-[7px] text-[13px] font-medium leading-[18px] text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary"
|
||||
className="flex w-full cursor-pointer items-center rounded-lg px-6 py-[7px] text-[13px] leading-[18px] font-medium text-text-tertiary hover:bg-state-base-hover hover:text-text-secondary"
|
||||
onClick={handleImportDSL}
|
||||
>
|
||||
<span aria-hidden className="i-ri-file-upload-line mr-2 h-4 w-4 shrink-0" />
|
||||
<span aria-hidden className="mr-2 i-ri-file-upload-line h-4 w-4 shrink-0" />
|
||||
{t('importDSL', { ns: 'app' })}
|
||||
</button>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
'use client'
|
||||
|
||||
import type { SnippetDetailUIModel } from '@/models/snippet'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import {
|
||||
DropdownMenu,
|
||||
DropdownMenuContent,
|
||||
DropdownMenuTrigger,
|
||||
} from '@/app/components/base/ui/dropdown-menu'
|
||||
} from '@langgenius/dify-ui/dropdown-menu'
|
||||
import { memo } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import PublishMenu from '../publish-menu'
|
||||
|
||||
type PublisherProps = {
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
'use client'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@langgenius/dify-ui/dialog'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { useDebounceFn, useKeyPress } from 'ahooks'
|
||||
import { useMemo, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Uploader from '@/app/components/app/create-from-dsl-modal/uploader'
|
||||
import Input from '@/app/components/base/input'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import { Dialog, DialogCloseButton, DialogContent, DialogTitle } from '@/app/components/base/ui/dialog'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import {
|
||||
DSLImportMode,
|
||||
DSLImportStatus,
|
||||
@@ -169,7 +169,7 @@ const SnippetImportDSLDialog = ({
|
||||
<DialogCloseButton className="top-6 right-5 h-8 w-8" />
|
||||
</div>
|
||||
|
||||
<div className="system-md-semibold flex h-9 items-center space-x-6 border-b border-divider-subtle px-6 text-text-tertiary">
|
||||
<div className="flex h-9 items-center space-x-6 border-b border-divider-subtle px-6 system-md-semibold text-text-tertiary">
|
||||
{[
|
||||
{ key: SnippetImportDSLTab.FromFile, label: t('importFromDSLFile', { ns: 'app' }) },
|
||||
{ key: SnippetImportDSLTab.FromURL, label: t('importFromDSLUrl', { ns: 'app' }) },
|
||||
@@ -201,7 +201,7 @@ const SnippetImportDSLDialog = ({
|
||||
)}
|
||||
{currentTab === SnippetImportDSLTab.FromURL && (
|
||||
<div>
|
||||
<div className="system-md-semibold mb-1 text-text-secondary">DSL URL</div>
|
||||
<div className="mb-1 system-md-semibold text-text-secondary">DSL URL</div>
|
||||
<Input
|
||||
placeholder={t('importFromDSLUrlPlaceholder', { ns: 'app' }) || ''}
|
||||
value={dslUrlValue}
|
||||
@@ -234,7 +234,7 @@ const SnippetImportDSLDialog = ({
|
||||
<DialogTitle className="title-2xl-semi-bold text-text-primary">
|
||||
{t('newApp.appCreateDSLErrorTitle', { ns: 'app' })}
|
||||
</DialogTitle>
|
||||
<div className="system-md-regular flex grow flex-col text-text-secondary">
|
||||
<div className="flex grow flex-col system-md-regular text-text-secondary">
|
||||
<div>{t('newApp.appCreateDSLErrorPart1', { ns: 'app' })}</div>
|
||||
<div>{t('newApp.appCreateDSLErrorPart2', { ns: 'app' })}</div>
|
||||
<br />
|
||||
|
||||
@@ -3,6 +3,8 @@
|
||||
import type { InputForm } from '@/app/components/base/chat/chat/type'
|
||||
import type { InputVar as WorkflowInputVar } from '@/app/components/workflow/types'
|
||||
import type { SnippetInputField } from '@/models/snippet'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import {
|
||||
memo,
|
||||
@@ -12,11 +14,9 @@ import {
|
||||
useState,
|
||||
} from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import { useCheckInputsForms } from '@/app/components/base/chat/chat/check-input-forms-hooks'
|
||||
import { getProcessedInputs } from '@/app/components/base/chat/chat/utils'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import {
|
||||
useWorkflowInteractions,
|
||||
useWorkflowRun,
|
||||
@@ -157,7 +157,7 @@ const SnippetRunPanel = ({
|
||||
style={{ width: `${panelWidth}px` }}
|
||||
>
|
||||
<div
|
||||
className="absolute bottom-0 left-[3px] top-1/2 z-50 h-6 w-[3px] cursor-col-resize rounded bg-gray-300"
|
||||
className="absolute top-1/2 bottom-0 left-[3px] z-50 h-6 w-[3px] cursor-col-resize rounded bg-gray-300"
|
||||
onMouseDown={startResizing}
|
||||
/>
|
||||
<div className="flex items-center justify-between p-4 pb-1 text-base font-semibold text-text-primary">
|
||||
@@ -170,26 +170,26 @@ const SnippetRunPanel = ({
|
||||
<div className="flex shrink-0 items-center border-b-[0.5px] border-divider-subtle px-4">
|
||||
{hasInputTab && (
|
||||
<div
|
||||
className={`mr-6 cursor-pointer border-b-2 py-3 text-[13px] font-semibold leading-[18px] ${currentTab === 'INPUT' ? '!border-[rgb(21,94,239)] text-text-secondary' : 'border-transparent text-text-tertiary'}`}
|
||||
className={`mr-6 cursor-pointer border-b-2 py-3 text-[13px] leading-[18px] font-semibold ${currentTab === 'INPUT' ? '!border-[rgb(21,94,239)] text-text-secondary' : 'border-transparent text-text-tertiary'}`}
|
||||
onClick={() => setSelectedTab('INPUT')}
|
||||
>
|
||||
{t('input', { ns: 'runLog' })}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={`mr-6 cursor-pointer border-b-2 py-3 text-[13px] font-semibold leading-[18px] ${currentTab === 'RESULT' ? '!border-[rgb(21,94,239)] text-text-secondary' : 'border-transparent text-text-tertiary'} ${!workflowRunningData ? '!cursor-not-allowed opacity-30' : ''}`}
|
||||
className={`mr-6 cursor-pointer border-b-2 py-3 text-[13px] leading-[18px] font-semibold ${currentTab === 'RESULT' ? '!border-[rgb(21,94,239)] text-text-secondary' : 'border-transparent text-text-tertiary'} ${!workflowRunningData ? '!cursor-not-allowed opacity-30' : ''}`}
|
||||
onClick={() => workflowRunningData && setSelectedTab('RESULT')}
|
||||
>
|
||||
{t('result', { ns: 'runLog' })}
|
||||
</div>
|
||||
<div
|
||||
className={`mr-6 cursor-pointer border-b-2 py-3 text-[13px] font-semibold leading-[18px] ${currentTab === 'DETAIL' ? '!border-[rgb(21,94,239)] text-text-secondary' : 'border-transparent text-text-tertiary'} ${!workflowRunningData ? '!cursor-not-allowed opacity-30' : ''}`}
|
||||
className={`mr-6 cursor-pointer border-b-2 py-3 text-[13px] leading-[18px] font-semibold ${currentTab === 'DETAIL' ? '!border-[rgb(21,94,239)] text-text-secondary' : 'border-transparent text-text-tertiary'} ${!workflowRunningData ? '!cursor-not-allowed opacity-30' : ''}`}
|
||||
onClick={() => workflowRunningData && setSelectedTab('DETAIL')}
|
||||
>
|
||||
{t('detail', { ns: 'runLog' })}
|
||||
</div>
|
||||
<div
|
||||
className={`mr-6 cursor-pointer border-b-2 py-3 text-[13px] font-semibold leading-[18px] ${currentTab === 'TRACING' ? '!border-[rgb(21,94,239)] text-text-secondary' : 'border-transparent text-text-tertiary'} ${!workflowRunningData ? '!cursor-not-allowed opacity-30' : ''}`}
|
||||
className={`mr-6 cursor-pointer border-b-2 py-3 text-[13px] leading-[18px] font-semibold ${currentTab === 'TRACING' ? '!border-[rgb(21,94,239)] text-text-secondary' : 'border-transparent text-text-tertiary'} ${!workflowRunningData ? '!cursor-not-allowed opacity-30' : ''}`}
|
||||
onClick={() => workflowRunningData && setSelectedTab('TRACING')}
|
||||
>
|
||||
{t('tracing', { ns: 'runLog' })}
|
||||
@@ -198,7 +198,7 @@ const SnippetRunPanel = ({
|
||||
<div className={`h-0 grow overflow-y-auto rounded-b-2xl ${(currentTab === 'RESULT' || currentTab === 'TRACING') ? '!bg-background-section-burn' : 'bg-components-panel-bg'}`}>
|
||||
{currentTab === 'INPUT' && hasInputTab && (
|
||||
<>
|
||||
<div className="px-4 pb-2 pt-3">
|
||||
<div className="px-4 pt-3 pb-2">
|
||||
{previewFields.map((field, index) => (
|
||||
<div
|
||||
key={field.variable}
|
||||
|
||||
@@ -26,7 +26,7 @@ vi.mock('@/service/client', () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
vi.mock('@langgenius/dify-ui/toast', () => ({
|
||||
toast: {
|
||||
success: (...args: unknown[]) => mockToastSuccess(...args),
|
||||
error: (...args: unknown[]) => mockToastError(...args),
|
||||
|
||||
@@ -38,7 +38,7 @@ vi.mock('../../../hooks', () => ({
|
||||
},
|
||||
}))
|
||||
|
||||
vi.mock('@/app/components/base/ui/toast', () => ({
|
||||
vi.mock('@langgenius/dify-ui/toast', () => ({
|
||||
toast: {
|
||||
error: (...args: unknown[]) => mockToastError(...args),
|
||||
},
|
||||
|
||||
@@ -1,4 +1,16 @@
|
||||
import { cn } from '@langgenius/dify-ui/cn'
|
||||
import {
|
||||
ScrollAreaContent,
|
||||
ScrollAreaRoot,
|
||||
ScrollAreaScrollbar,
|
||||
ScrollAreaThumb,
|
||||
ScrollAreaViewport,
|
||||
} from '@langgenius/dify-ui/scroll-area'
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from '@langgenius/dify-ui/tooltip'
|
||||
import { useInfiniteScroll } from 'ahooks'
|
||||
import {
|
||||
memo,
|
||||
@@ -8,18 +20,6 @@ import {
|
||||
useState,
|
||||
} from 'react'
|
||||
import Loading from '@/app/components/base/loading'
|
||||
import {
|
||||
ScrollAreaContent,
|
||||
ScrollAreaRoot,
|
||||
ScrollAreaScrollbar,
|
||||
ScrollAreaThumb,
|
||||
ScrollAreaViewport,
|
||||
} from '@/app/components/base/ui/scroll-area'
|
||||
import {
|
||||
Tooltip,
|
||||
TooltipContent,
|
||||
TooltipTrigger,
|
||||
} from '@/app/components/base/ui/tooltip'
|
||||
import { useInfiniteSnippetList } from '@/service/use-snippets'
|
||||
import CreateSnippetDialog from '../../create-snippet-dialog'
|
||||
import SnippetDetailCard from './snippet-detail-card'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { FC } from 'react'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
|
||||
type SnippetEmptyStateProps = {
|
||||
onCreate: () => void
|
||||
@@ -14,7 +14,7 @@ const SnippetEmptyState: FC<SnippetEmptyStateProps> = ({
|
||||
return (
|
||||
<div className="flex min-h-[480px] flex-col items-center justify-center gap-2 px-4">
|
||||
<span className="i-custom-vender-line-others-search-menu h-8 w-8 text-text-tertiary" />
|
||||
<div className="text-text-secondary system-sm-regular">
|
||||
<div className="system-sm-regular text-text-secondary">
|
||||
{t('tabs.noSnippetsFound', { ns: 'workflow' })}
|
||||
</div>
|
||||
<Button
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import type { CreateSnippetDialogPayload } from '../../create-snippet-dialog'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { useRouter } from '@/next/navigation'
|
||||
import { consoleClient } from '@/service/client'
|
||||
import { useCreateSnippetMutation } from '@/service/use-snippets'
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { Edge, Node } from '../../types'
|
||||
import { toast } from '@langgenius/dify-ui/toast'
|
||||
import { useQueryClient } from '@tanstack/react-query'
|
||||
import { useCallback } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import { useStoreApi } from 'reactflow'
|
||||
import { toast } from '@/app/components/base/ui/toast'
|
||||
import { consoleQuery } from '@/service/client'
|
||||
import { useNodesSyncDraft, useWorkflowHistory, WorkflowHistoryEvent } from '../../hooks'
|
||||
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
import type { FC } from 'react'
|
||||
import type { AppIconSelection } from '@/app/components/base/app-icon-picker'
|
||||
import type { SnippetCanvasData } from '@/models/snippet'
|
||||
import { Button } from '@langgenius/dify-ui/button'
|
||||
import { Dialog, DialogCloseButton, DialogContent, DialogPortal, DialogTitle } from '@langgenius/dify-ui/dialog'
|
||||
import { useKeyPress } from 'ahooks'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import AppIcon from '@/app/components/base/app-icon'
|
||||
import AppIconPicker from '@/app/components/base/app-icon-picker'
|
||||
import { Button } from '@/app/components/base/ui/button'
|
||||
import Input from '@/app/components/base/input'
|
||||
import Textarea from '@/app/components/base/textarea'
|
||||
import { Dialog, DialogCloseButton, DialogContent, DialogPortal, DialogTitle } from '@/app/components/base/ui/dialog'
|
||||
import ShortcutsName from './shortcuts-name'
|
||||
|
||||
export type CreateSnippetDialogPayload = {
|
||||
|
||||
Reference in New Issue
Block a user