mirror of
https://github.com/langgenius/dify.git
synced 2026-01-08 07:14:14 +00:00
add app-info-panel
This commit is contained in:
@@ -0,0 +1,5 @@
|
||||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="file-check-02">
|
||||
<path id="Icon" d="M13.3337 8.33301V4.53301C13.3337 3.4129 13.3337 2.85285 13.1157 2.42503C12.9239 2.0487 12.618 1.74274 12.2416 1.55099C11.8138 1.33301 11.2538 1.33301 10.1337 1.33301H5.86699C4.74689 1.33301 4.18683 1.33301 3.75901 1.55099C3.38269 1.74274 3.07673 2.0487 2.88498 2.42503C2.66699 2.85285 2.66699 3.4129 2.66699 4.53301V11.4663C2.66699 12.5864 2.66699 13.1465 2.88498 13.5743C3.07673 13.9506 3.38269 14.2566 3.75901 14.4484C4.18683 14.6663 4.74689 14.6663 5.86699 14.6663H8.00033M9.33366 7.33301H5.33366M6.66699 9.99967H5.33366M10.667 4.66634H5.33366M9.66699 12.6663L11.0003 13.9997L14.0003 10.9997" stroke="#344054" stroke-width="1.25" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 832 B |
@@ -0,0 +1,39 @@
|
||||
{
|
||||
"icon": {
|
||||
"type": "element",
|
||||
"isRootNode": true,
|
||||
"name": "svg",
|
||||
"attributes": {
|
||||
"width": "16",
|
||||
"height": "16",
|
||||
"viewBox": "0 0 16 16",
|
||||
"fill": "none",
|
||||
"xmlns": "http://www.w3.org/2000/svg"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "g",
|
||||
"attributes": {
|
||||
"id": "file-check-02"
|
||||
},
|
||||
"children": [
|
||||
{
|
||||
"type": "element",
|
||||
"name": "path",
|
||||
"attributes": {
|
||||
"id": "Icon",
|
||||
"d": "M13.3337 8.33301V4.53301C13.3337 3.4129 13.3337 2.85285 13.1157 2.42503C12.9239 2.0487 12.618 1.74274 12.2416 1.55099C11.8138 1.33301 11.2538 1.33301 10.1337 1.33301H5.86699C4.74689 1.33301 4.18683 1.33301 3.75901 1.55099C3.38269 1.74274 3.07673 2.0487 2.88498 2.42503C2.66699 2.85285 2.66699 3.4129 2.66699 4.53301V11.4663C2.66699 12.5864 2.66699 13.1465 2.88498 13.5743C3.07673 13.9506 3.38269 14.2566 3.75901 14.4484C4.18683 14.6663 4.74689 14.6663 5.86699 14.6663H8.00033M9.33366 7.33301H5.33366M6.66699 9.99967H5.33366M10.667 4.66634H5.33366M9.66699 12.6663L11.0003 13.9997L14.0003 10.9997",
|
||||
"stroke": "currentColor",
|
||||
"stroke-width": "1.25",
|
||||
"stroke-linecap": "round",
|
||||
"stroke-linejoin": "round"
|
||||
},
|
||||
"children": []
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"name": "FileCheck02"
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
// GENERATE BY script
|
||||
// DON NOT EDIT IT MANUALLY
|
||||
|
||||
import * as React from 'react'
|
||||
import data from './FileCheck02.json'
|
||||
import IconBase from '@/app/components/base/icons/IconBase'
|
||||
import type { IconBaseProps, IconData } from '@/app/components/base/icons/IconBase'
|
||||
|
||||
const Icon = React.forwardRef<React.MutableRefObject<SVGElement>, Omit<IconBaseProps, 'data'>>((
|
||||
props,
|
||||
ref,
|
||||
) => <IconBase {...props} ref={ref} data={data as IconData} />)
|
||||
|
||||
Icon.displayName = 'FileCheck02'
|
||||
|
||||
export default Icon
|
||||
@@ -1,5 +1,6 @@
|
||||
export { default as ClipboardCheck } from './ClipboardCheck'
|
||||
export { default as Clipboard } from './Clipboard'
|
||||
export { default as File02 } from './File02'
|
||||
export { default as FileCheck02 } from './FileCheck02'
|
||||
export { default as FileDownload02 } from './FileDownload02'
|
||||
export { default as FilePlus02 } from './FilePlus02'
|
||||
|
||||
58
web/app/components/workflow/app-info-panel.tsx
Normal file
58
web/app/components/workflow/app-info-panel.tsx
Normal file
@@ -0,0 +1,58 @@
|
||||
import type { FC } from 'react'
|
||||
import { memo } from 'react'
|
||||
import BlockIcon from './block-icon'
|
||||
import { BlockEnum } from './types'
|
||||
import { useWorkflowContext } from './context'
|
||||
import { AlertTriangle } from '@/app/components/base/icons/src/vender/line/alertsAndFeedback'
|
||||
import { FileCheck02 } from '@/app/components/base/icons/src/vender/line/files'
|
||||
|
||||
const AppInfoPanel: FC = () => {
|
||||
const { selectedNode } = useWorkflowContext()
|
||||
|
||||
if (selectedNode)
|
||||
return null
|
||||
|
||||
return (
|
||||
<div className='absolute top-14 right-2 bottom-2 w-[420px] bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl z-10 overflow-y-auto'>
|
||||
<div className='sticky top-0 bg-white border-b-[0.5px] border-black/5'>
|
||||
<div className='flex pt-4 px-4 pb-1'>
|
||||
<div className='mr-3 w-10 h-10'></div>
|
||||
<div className='mt-2 text-base font-semibold text-gray-900'>
|
||||
Fitness and Nutrition Expert
|
||||
</div>
|
||||
</div>
|
||||
<div className='px-4 py-[13px] text-xs leading-[18px] text-gray-500'>
|
||||
A Fitness and Nutrition Expert specializes in guiding individuals towards healthier lifestyles through exercise and diet.
|
||||
</div>
|
||||
<div className='flex items-center px-4 h-[42px] text-[13px] font-semibold text-gray-700'>
|
||||
<FileCheck02 className='mr-1 w-4 h-4' />
|
||||
Checklist(2)
|
||||
</div>
|
||||
</div>
|
||||
<div className='py-2'>
|
||||
<div className='px-4 py-2 text-xs text-gray-400'>
|
||||
Make sure all issues are resolved before publishing
|
||||
</div>
|
||||
<div className='px-4 py-2'>
|
||||
<div className='border-[0.5px] border-gray-200 bg-white shadow-xs rounded-lg'>
|
||||
<div className='flex items-center p-2 h-9 text-xs font-medium text-gray-700'>
|
||||
<BlockIcon
|
||||
type={BlockEnum.Start}
|
||||
className='mr-1.5'
|
||||
/>
|
||||
Start
|
||||
</div>
|
||||
<div className='px-3 py-2 border-t-[0.5px] border-t-black/[0.02] bg-gray-25 rounded-b-lg'>
|
||||
<div className='flex text-xs leading-[18px] text-gray-500'>
|
||||
<AlertTriangle className='mt-[3px] mr-2 w-3 h-3 text-[#F79009]' />
|
||||
This step is not connected to anything
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(AppInfoPanel)
|
||||
@@ -37,6 +37,7 @@ const getIcon = (type: BlockEnum, className: string) => {
|
||||
[BlockEnum.QuestionClassifier]: <QuestionClassifier className={className} />,
|
||||
[BlockEnum.TemplateTransform]: <TemplatingTransform className={className} />,
|
||||
[BlockEnum.VariableAssigner]: <VariableX className={className} />,
|
||||
[BlockEnum.Tool]: <VariableX className={className} />,
|
||||
}[type]
|
||||
}
|
||||
const ICON_CONTAINER_BG_COLOR_MAP: Record<string, string> = {
|
||||
|
||||
@@ -17,6 +17,8 @@ import Header from './header'
|
||||
import CustomNode, {
|
||||
Panel,
|
||||
} from './nodes'
|
||||
import AppInfoPanel from './app-info-panel'
|
||||
import ZoomInOut from './zoom-in-out'
|
||||
import CustomEdge from './custom-edge'
|
||||
import type { Node } from './types'
|
||||
|
||||
@@ -36,7 +38,9 @@ const Workflow = () => {
|
||||
return (
|
||||
<div className='relative w-full h-full'>
|
||||
<Header />
|
||||
<AppInfoPanel />
|
||||
<Panel />
|
||||
<ZoomInOut />
|
||||
<ReactFlow
|
||||
nodeTypes={nodeTypes}
|
||||
edgeTypes={edgeTypes}
|
||||
|
||||
@@ -22,7 +22,7 @@ const BasePanel: FC<BasePanelProps> = ({
|
||||
} = useWorkflowContext()
|
||||
|
||||
return (
|
||||
<div className='absolute top-2 right-2 bottom-2 w-[420px] bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl z-20 overflow-y-auto'>
|
||||
<div className='absolute top-14 right-2 bottom-2 w-[420px] bg-white shadow-lg border-[0.5px] border-gray-200 rounded-2xl z-10 overflow-y-auto'>
|
||||
<div className='sticky top-0 bg-white border-b-[0.5px] border-black/5'>
|
||||
<div className='flex items-center px-4 pt-3'>
|
||||
<BlockIcon
|
||||
|
||||
@@ -34,11 +34,12 @@ const CustomNode = ({
|
||||
|
||||
export const Panel = () => {
|
||||
const { selectedNode } = useWorkflowContext()
|
||||
const PanelComponent = PanelMap[selectedNode?.data.type || '']
|
||||
|
||||
if (!PanelComponent)
|
||||
if (!selectedNode)
|
||||
return null
|
||||
|
||||
const PanelComponent = PanelMap[selectedNode.data.type]
|
||||
|
||||
return (
|
||||
<PanelComponent />
|
||||
)
|
||||
|
||||
96
web/app/components/workflow/zoom-in-out.tsx
Normal file
96
web/app/components/workflow/zoom-in-out.tsx
Normal file
@@ -0,0 +1,96 @@
|
||||
import type { FC } from 'react'
|
||||
import {
|
||||
Fragment,
|
||||
memo,
|
||||
useState,
|
||||
} from 'react'
|
||||
import {
|
||||
PortalToFollowElem,
|
||||
PortalToFollowElemContent,
|
||||
PortalToFollowElemTrigger,
|
||||
} from '@/app/components/base/portal-to-follow-elem'
|
||||
import { SearchLg } from '@/app/components/base/icons/src/vender/line/general'
|
||||
import { ChevronDown } from '@/app/components/base/icons/src/vender/line/arrows'
|
||||
|
||||
const ZOOM_IN_OUT_OPTIONS = [
|
||||
[
|
||||
{
|
||||
key: 'in',
|
||||
text: 'Zoom In',
|
||||
},
|
||||
{
|
||||
key: 'out',
|
||||
text: 'Zoom Out',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
key: 'to50',
|
||||
text: 'Zoom to 50%',
|
||||
},
|
||||
{
|
||||
key: 'to100',
|
||||
text: 'Zoom to 100%',
|
||||
},
|
||||
],
|
||||
[
|
||||
{
|
||||
key: 'fit',
|
||||
text: 'Zoom to Fit',
|
||||
},
|
||||
],
|
||||
]
|
||||
|
||||
const ZoomInOut: FC = () => {
|
||||
const [open, setOpen] = useState(false)
|
||||
|
||||
return (
|
||||
<PortalToFollowElem
|
||||
placement='top-start'
|
||||
open={open}
|
||||
onOpenChange={setOpen}
|
||||
offset={4}
|
||||
>
|
||||
<PortalToFollowElemTrigger asChild onClick={() => setOpen(v => !v)}>
|
||||
<div className={`
|
||||
absolute left-6 bottom-6
|
||||
flex items-center px-2.5 h-9 cursor-pointer rounded-lg border-[0.5px] border-gray-100 bg-white shadow-lg
|
||||
text-[13px] text-gray-500 z-10
|
||||
`}>
|
||||
<SearchLg className='mr-1 w-4 h-4' />
|
||||
100%
|
||||
<ChevronDown className='ml-1 w-4 h-4' />
|
||||
</div>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent>
|
||||
<div className='w-[168px] rounded-lg border-[0.5px] border-gray-200 bg-white shadow-lg'>
|
||||
{
|
||||
ZOOM_IN_OUT_OPTIONS.map((options, i) => (
|
||||
<Fragment key={i}>
|
||||
{
|
||||
i !== 0 && (
|
||||
<div className='h-[1px] bg-gray-100' />
|
||||
)
|
||||
}
|
||||
<div className='p-1'>
|
||||
{
|
||||
options.map(option => (
|
||||
<div
|
||||
key={option.key}
|
||||
className='flex items-center px-3 h-8 rounded-lg hover:bg-gray-50 cursor-pointer text-sm text-gray-700'
|
||||
>
|
||||
{option.text}
|
||||
</div>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</Fragment>
|
||||
))
|
||||
}
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)
|
||||
}
|
||||
|
||||
export default memo(ZoomInOut)
|
||||
Reference in New Issue
Block a user