feat: introduce trigger functionality (#27644)
Signed-off-by: lyzno1 <yuanyouhuilyz@gmail.com> Co-authored-by: Stream <Stream_2@qq.com> Co-authored-by: lyzno1 <92089059+lyzno1@users.noreply.github.com> Co-authored-by: zhsama <torvalds@linux.do> Co-authored-by: Harry <xh001x@hotmail.com> Co-authored-by: lyzno1 <yuanyouhuilyz@gmail.com> Co-authored-by: yessenia <yessenia.contact@gmail.com> Co-authored-by: hjlarry <hjlarry@163.com> Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com> Co-authored-by: autofix-ci[bot] <114827586+autofix-ci[bot]@users.noreply.github.com> Co-authored-by: WTW0313 <twwu@dify.ai> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -26,11 +26,11 @@ import { fetchWorkflowDraft } from '@/service/workflow'
|
||||
import ContentDialog from '@/app/components/base/content-dialog'
|
||||
import Button from '@/app/components/base/button'
|
||||
import CardView from '@/app/(commonLayout)/app/(appDetailLayout)/[appId]/overview/card-view'
|
||||
import Divider from '../base/divider'
|
||||
import type { Operation } from './app-operations'
|
||||
import AppOperations from './app-operations'
|
||||
import dynamic from 'next/dynamic'
|
||||
import cn from '@/utils/classnames'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
|
||||
const SwitchAppModal = dynamic(() => import('@/app/components/app/switch-app-modal'), {
|
||||
ssr: false,
|
||||
@@ -158,7 +158,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
const exportCheck = async () => {
|
||||
if (!appDetail)
|
||||
return
|
||||
if (appDetail.mode !== 'workflow' && appDetail.mode !== 'advanced-chat') {
|
||||
if (appDetail.mode !== AppModeEnum.WORKFLOW && appDetail.mode !== AppModeEnum.ADVANCED_CHAT) {
|
||||
onExport()
|
||||
return
|
||||
}
|
||||
@@ -208,7 +208,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
if (!appDetail)
|
||||
return null
|
||||
|
||||
const operations = [
|
||||
const primaryOperations = [
|
||||
{
|
||||
id: 'edit',
|
||||
title: t('app.editApp'),
|
||||
@@ -235,7 +235,11 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
icon: <RiFileDownloadLine />,
|
||||
onClick: exportCheck,
|
||||
},
|
||||
(appDetail.mode !== 'agent-chat' && (appDetail.mode === 'advanced-chat' || appDetail.mode === 'workflow')) ? {
|
||||
]
|
||||
|
||||
const secondaryOperations: Operation[] = [
|
||||
// Import DSL (conditional)
|
||||
...(appDetail.mode !== AppModeEnum.AGENT_CHAT && (appDetail.mode === AppModeEnum.ADVANCED_CHAT || appDetail.mode === AppModeEnum.WORKFLOW)) ? [{
|
||||
id: 'import',
|
||||
title: t('workflow.common.importDSL'),
|
||||
icon: <RiFileUploadLine />,
|
||||
@@ -244,18 +248,39 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
onDetailExpand?.(false)
|
||||
setShowImportDSLModal(true)
|
||||
},
|
||||
} : undefined,
|
||||
(appDetail.mode !== 'agent-chat' && (appDetail.mode === 'completion' || appDetail.mode === 'chat')) ? {
|
||||
id: 'switch',
|
||||
title: t('app.switch'),
|
||||
icon: <RiExchange2Line />,
|
||||
}] : [],
|
||||
// Divider
|
||||
{
|
||||
id: 'divider-1',
|
||||
title: '',
|
||||
icon: <></>,
|
||||
onClick: () => { /* divider has no action */ },
|
||||
type: 'divider' as const,
|
||||
},
|
||||
// Delete operation
|
||||
{
|
||||
id: 'delete',
|
||||
title: t('common.operation.delete'),
|
||||
icon: <RiDeleteBinLine />,
|
||||
onClick: () => {
|
||||
setOpen(false)
|
||||
onDetailExpand?.(false)
|
||||
setShowSwitchModal(true)
|
||||
setShowConfirmDelete(true)
|
||||
},
|
||||
} : undefined,
|
||||
].filter((op): op is Operation => Boolean(op))
|
||||
},
|
||||
]
|
||||
|
||||
// Keep the switch operation separate as it's not part of the main operations
|
||||
const switchOperation = (appDetail.mode !== AppModeEnum.AGENT_CHAT && (appDetail.mode === AppModeEnum.COMPLETION || appDetail.mode === AppModeEnum.CHAT)) ? {
|
||||
id: 'switch',
|
||||
title: t('app.switch'),
|
||||
icon: <RiExchange2Line />,
|
||||
onClick: () => {
|
||||
setOpen(false)
|
||||
onDetailExpand?.(false)
|
||||
setShowSwitchModal(true)
|
||||
},
|
||||
} : null
|
||||
|
||||
return (
|
||||
<div>
|
||||
@@ -298,7 +323,12 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
<div className='flex w-full'>
|
||||
<div className='system-md-semibold truncate whitespace-nowrap text-text-secondary'>{appDetail.name}</div>
|
||||
</div>
|
||||
<div className='system-2xs-medium-uppercase whitespace-nowrap text-text-tertiary'>{appDetail.mode === 'advanced-chat' ? t('app.types.advanced') : appDetail.mode === 'agent-chat' ? t('app.types.agent') : appDetail.mode === 'chat' ? t('app.types.chatbot') : appDetail.mode === 'completion' ? t('app.types.completion') : t('app.types.workflow')}</div>
|
||||
<div className='system-2xs-medium-uppercase whitespace-nowrap text-text-tertiary'>
|
||||
{appDetail.mode === AppModeEnum.ADVANCED_CHAT ? t('app.types.advanced')
|
||||
: appDetail.mode === AppModeEnum.AGENT_CHAT ? t('app.types.agent')
|
||||
: appDetail.mode === AppModeEnum.CHAT ? t('app.types.chatbot')
|
||||
: appDetail.mode === AppModeEnum.COMPLETION ? t('app.types.completion')
|
||||
: t('app.types.workflow')}</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
@@ -323,7 +353,7 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
/>
|
||||
<div className='flex flex-1 flex-col items-start justify-center overflow-hidden'>
|
||||
<div className='system-md-semibold w-full truncate text-text-secondary'>{appDetail.name}</div>
|
||||
<div className='system-2xs-medium-uppercase text-text-tertiary'>{appDetail.mode === 'advanced-chat' ? t('app.types.advanced') : appDetail.mode === 'agent-chat' ? t('app.types.agent') : appDetail.mode === 'chat' ? t('app.types.chatbot') : appDetail.mode === 'completion' ? t('app.types.completion') : t('app.types.workflow')}</div>
|
||||
<div className='system-2xs-medium-uppercase text-text-tertiary'>{appDetail.mode === AppModeEnum.ADVANCED_CHAT ? t('app.types.advanced') : appDetail.mode === AppModeEnum.AGENT_CHAT ? t('app.types.agent') : appDetail.mode === AppModeEnum.CHAT ? t('app.types.chatbot') : appDetail.mode === AppModeEnum.COMPLETION ? t('app.types.completion') : t('app.types.workflow')}</div>
|
||||
</div>
|
||||
</div>
|
||||
{/* description */}
|
||||
@@ -333,7 +363,8 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
{/* operations */}
|
||||
<AppOperations
|
||||
gap={4}
|
||||
operations={operations}
|
||||
primaryOperations={primaryOperations}
|
||||
secondaryOperations={secondaryOperations}
|
||||
/>
|
||||
</div>
|
||||
<CardView
|
||||
@@ -341,22 +372,20 @@ const AppInfo = ({ expand, onlyShowDetail = false, openState = false, onDetailEx
|
||||
isInPanel={true}
|
||||
className='flex flex-1 flex-col gap-2 overflow-auto px-2 py-1'
|
||||
/>
|
||||
<Divider />
|
||||
<div className='flex min-h-fit shrink-0 flex-col items-start justify-center gap-3 self-stretch pb-2'>
|
||||
<Button
|
||||
size={'medium'}
|
||||
variant={'ghost'}
|
||||
className='gap-0.5'
|
||||
onClick={() => {
|
||||
setOpen(false)
|
||||
onDetailExpand?.(false)
|
||||
setShowConfirmDelete(true)
|
||||
}}
|
||||
>
|
||||
<RiDeleteBinLine className='h-4 w-4 text-text-tertiary' />
|
||||
<span className='system-sm-medium text-text-tertiary'>{t('common.operation.deleteApp')}</span>
|
||||
</Button>
|
||||
</div>
|
||||
{/* Switch operation (if available) */}
|
||||
{switchOperation && (
|
||||
<div className='flex min-h-fit shrink-0 flex-col items-start justify-center gap-3 self-stretch pb-2'>
|
||||
<Button
|
||||
size={'medium'}
|
||||
variant={'ghost'}
|
||||
className='gap-0.5'
|
||||
onClick={switchOperation.onClick}
|
||||
>
|
||||
{switchOperation.icon}
|
||||
<span className='system-sm-medium text-text-tertiary'>{switchOperation.title}</span>
|
||||
</Button>
|
||||
</div>
|
||||
)}
|
||||
</ContentDialog>
|
||||
{showSwitchModal && (
|
||||
<SwitchAppModal
|
||||
|
||||
@@ -1,19 +1,33 @@
|
||||
import type { JSX } from 'react'
|
||||
import { cloneElement, useCallback } from 'react'
|
||||
import { useEffect, useRef, useState } from 'react'
|
||||
import { cloneElement, useCallback, useEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
import Button from '@/app/components/base/button'
|
||||
import { PortalToFollowElem, PortalToFollowElemContent, PortalToFollowElemTrigger } from '../base/portal-to-follow-elem'
|
||||
import { RiMoreLine } from '@remixicon/react'
|
||||
|
||||
export type Operation = {
|
||||
id: string; title: string; icon: JSX.Element; onClick: () => void
|
||||
id: string
|
||||
title: string
|
||||
icon: JSX.Element
|
||||
onClick: () => void
|
||||
type?: 'divider'
|
||||
}
|
||||
|
||||
const AppOperations = ({ operations, gap }: {
|
||||
operations: Operation[]
|
||||
type AppOperationsProps = {
|
||||
gap: number
|
||||
}) => {
|
||||
operations?: Operation[]
|
||||
primaryOperations?: Operation[]
|
||||
secondaryOperations?: Operation[]
|
||||
}
|
||||
|
||||
const EMPTY_OPERATIONS: Operation[] = []
|
||||
|
||||
const AppOperations = ({
|
||||
operations,
|
||||
primaryOperations,
|
||||
secondaryOperations,
|
||||
gap,
|
||||
}: AppOperationsProps) => {
|
||||
const { t } = useTranslation()
|
||||
const [visibleOpreations, setVisibleOperations] = useState<Operation[]>([])
|
||||
const [moreOperations, setMoreOperations] = useState<Operation[]>([])
|
||||
@@ -23,22 +37,59 @@ const AppOperations = ({ operations, gap }: {
|
||||
setShowMore(true)
|
||||
}, [setShowMore])
|
||||
|
||||
const primaryOps = useMemo(() => {
|
||||
if (operations)
|
||||
return operations
|
||||
if (primaryOperations)
|
||||
return primaryOperations
|
||||
return EMPTY_OPERATIONS
|
||||
}, [operations, primaryOperations])
|
||||
|
||||
const secondaryOps = useMemo(() => {
|
||||
if (operations)
|
||||
return EMPTY_OPERATIONS
|
||||
if (secondaryOperations)
|
||||
return secondaryOperations
|
||||
return EMPTY_OPERATIONS
|
||||
}, [operations, secondaryOperations])
|
||||
const inlineOperations = primaryOps.filter(operation => operation.type !== 'divider')
|
||||
|
||||
useEffect(() => {
|
||||
const moreElement = document.getElementById('more')
|
||||
const navElement = document.getElementById('nav')
|
||||
const applyState = (visible: Operation[], overflow: Operation[]) => {
|
||||
const combinedMore = [...overflow, ...secondaryOps]
|
||||
if (!overflow.length && combinedMore[0]?.type === 'divider')
|
||||
combinedMore.shift()
|
||||
setVisibleOperations(visible)
|
||||
setMoreOperations(combinedMore)
|
||||
}
|
||||
|
||||
const inline = primaryOps.filter(operation => operation.type !== 'divider')
|
||||
|
||||
if (!inline.length) {
|
||||
applyState([], [])
|
||||
return
|
||||
}
|
||||
|
||||
const navElement = navRef.current
|
||||
const moreElement = document.getElementById('more-measure')
|
||||
|
||||
if (!navElement || !moreElement)
|
||||
return
|
||||
|
||||
let width = 0
|
||||
const containerWidth = navElement?.clientWidth ?? 0
|
||||
const moreWidth = moreElement?.clientWidth ?? 0
|
||||
const containerWidth = navElement.clientWidth
|
||||
const moreWidth = moreElement.clientWidth
|
||||
|
||||
if (containerWidth === 0 || moreWidth === 0) return
|
||||
if (containerWidth === 0 || moreWidth === 0)
|
||||
return
|
||||
|
||||
const updatedEntries: Record<string, boolean> = operations.reduce((pre, cur) => {
|
||||
const updatedEntries: Record<string, boolean> = inline.reduce((pre, cur) => {
|
||||
pre[cur.id] = false
|
||||
return pre
|
||||
}, {} as Record<string, boolean>)
|
||||
const childrens = Array.from(navRef.current!.children).slice(0, -1)
|
||||
const childrens = Array.from(navElement.children).slice(0, -1)
|
||||
for (let i = 0; i < childrens.length; i++) {
|
||||
const child: any = childrens[i]
|
||||
const child = childrens[i] as HTMLElement
|
||||
const id = child.dataset.targetid
|
||||
if (!id) break
|
||||
const childWidth = child.clientWidth
|
||||
@@ -55,88 +106,106 @@ const AppOperations = ({ operations, gap }: {
|
||||
break
|
||||
}
|
||||
}
|
||||
setVisibleOperations(operations.filter(item => updatedEntries[item.id]))
|
||||
setMoreOperations(operations.filter(item => !updatedEntries[item.id]))
|
||||
}, [operations, gap])
|
||||
|
||||
const visible = inline.filter(item => updatedEntries[item.id])
|
||||
const overflow = inline.filter(item => !updatedEntries[item.id])
|
||||
|
||||
applyState(visible, overflow)
|
||||
}, [gap, primaryOps, secondaryOps])
|
||||
|
||||
const shouldShowMoreButton = moreOperations.length > 0
|
||||
|
||||
return (
|
||||
<>
|
||||
{!visibleOpreations.length && <div
|
||||
id="nav"
|
||||
<div
|
||||
aria-hidden="true"
|
||||
ref={navRef}
|
||||
className="flex h-0 items-center self-stretch overflow-hidden"
|
||||
className="pointer-events-none flex h-0 items-center self-stretch overflow-hidden"
|
||||
style={{ gap }}
|
||||
>
|
||||
{operations.map((operation, index) =>
|
||||
<Button
|
||||
key={index}
|
||||
data-targetid={operation.id}
|
||||
size={'small'}
|
||||
variant={'secondary'}
|
||||
className="gap-[1px]">
|
||||
{cloneElement(operation.icon, { className: 'h-3.5 w-3.5 text-components-button-secondary-text' })}
|
||||
<span className="system-xs-medium text-components-button-secondary-text">
|
||||
{operation.title}
|
||||
</span>
|
||||
</Button>,
|
||||
)}
|
||||
<Button
|
||||
id="more"
|
||||
size={'small'}
|
||||
variant={'secondary'}
|
||||
className="gap-[1px]"
|
||||
>
|
||||
<RiMoreLine className="h-3.5 w-3.5 text-components-button-secondary-text" />
|
||||
<span className="system-xs-medium text-components-button-secondary-text">
|
||||
{t('common.operation.more')}
|
||||
</span>
|
||||
</Button>
|
||||
</div>}
|
||||
<div className="flex items-center self-stretch overflow-hidden" style={{ gap }}>
|
||||
{visibleOpreations.map(operation =>
|
||||
{inlineOperations.map(operation => (
|
||||
<Button
|
||||
key={operation.id}
|
||||
data-targetid={operation.id}
|
||||
size={'small'}
|
||||
variant={'secondary'}
|
||||
className="gap-[1px]"
|
||||
onClick={operation.onClick}>
|
||||
tabIndex={-1}
|
||||
>
|
||||
{cloneElement(operation.icon, { className: 'h-3.5 w-3.5 text-components-button-secondary-text' })}
|
||||
<span className="system-xs-medium text-components-button-secondary-text">
|
||||
{operation.title}
|
||||
</span>
|
||||
</Button>,
|
||||
)}
|
||||
{visibleOpreations.length < operations.length && <PortalToFollowElem
|
||||
open={showMore}
|
||||
onOpenChange={setShowMore}
|
||||
placement='bottom-end'
|
||||
offset={{
|
||||
mainAxis: 4,
|
||||
}}>
|
||||
<PortalToFollowElemTrigger onClick={handleTriggerMore}>
|
||||
<Button
|
||||
size={'small'}
|
||||
variant={'secondary'}
|
||||
className='gap-[1px]'
|
||||
>
|
||||
<RiMoreLine className='h-3.5 w-3.5 text-components-button-secondary-text' />
|
||||
<span className='system-xs-medium text-components-button-secondary-text'>{t('common.operation.more')}</span>
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className='z-[30]'>
|
||||
<div className='flex min-w-[264px] flex-col rounded-[12px] border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg backdrop-blur-[5px]'>
|
||||
{moreOperations.map(item => <div
|
||||
key={item.id}
|
||||
className='flex h-8 cursor-pointer items-center gap-x-1 rounded-lg p-1.5 hover:bg-state-base-hover'
|
||||
onClick={item.onClick}
|
||||
</Button>
|
||||
))}
|
||||
<Button
|
||||
id="more-measure"
|
||||
size={'small'}
|
||||
variant={'secondary'}
|
||||
className="gap-[1px]"
|
||||
tabIndex={-1}
|
||||
>
|
||||
<RiMoreLine className="h-3.5 w-3.5 text-components-button-secondary-text" />
|
||||
<span className="system-xs-medium text-components-button-secondary-text">
|
||||
{t('common.operation.more')}
|
||||
</span>
|
||||
</Button>
|
||||
</div>
|
||||
<div className="flex items-center self-stretch overflow-hidden" style={{ gap }}>
|
||||
{visibleOpreations.map(operation => (
|
||||
<Button
|
||||
key={operation.id}
|
||||
data-targetid={operation.id}
|
||||
size={'small'}
|
||||
variant={'secondary'}
|
||||
className="gap-[1px]"
|
||||
onClick={operation.onClick}
|
||||
>
|
||||
{cloneElement(operation.icon, { className: 'h-3.5 w-3.5 text-components-button-secondary-text' })}
|
||||
<span className="system-xs-medium text-components-button-secondary-text">
|
||||
{operation.title}
|
||||
</span>
|
||||
</Button>
|
||||
))}
|
||||
{shouldShowMoreButton && (
|
||||
<PortalToFollowElem
|
||||
open={showMore}
|
||||
onOpenChange={setShowMore}
|
||||
placement="bottom-end"
|
||||
offset={{ mainAxis: 4 }}
|
||||
>
|
||||
<PortalToFollowElemTrigger onClick={handleTriggerMore}>
|
||||
<Button
|
||||
size={'small'}
|
||||
variant={'secondary'}
|
||||
className="gap-[1px]"
|
||||
>
|
||||
{cloneElement(item.icon, { className: 'h-4 w-4 text-text-tertiary' })}
|
||||
<span className='system-md-regular text-text-secondary'>{item.title}</span>
|
||||
</div>)}
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>}
|
||||
<RiMoreLine className="h-3.5 w-3.5 text-components-button-secondary-text" />
|
||||
<span className="system-xs-medium text-components-button-secondary-text">
|
||||
{t('common.operation.more')}
|
||||
</span>
|
||||
</Button>
|
||||
</PortalToFollowElemTrigger>
|
||||
<PortalToFollowElemContent className="z-[30]">
|
||||
<div className="flex min-w-[264px] flex-col rounded-[12px] border-[0.5px] border-components-panel-border bg-components-panel-bg-blur p-1 shadow-lg backdrop-blur-[5px]">
|
||||
{moreOperations.map(item => item.type === 'divider'
|
||||
? (
|
||||
<div key={item.id} className="my-1 h-px bg-divider-subtle" />
|
||||
)
|
||||
: (
|
||||
<div
|
||||
key={item.id}
|
||||
className="flex h-8 cursor-pointer items-center gap-x-1 rounded-lg p-1.5 hover:bg-state-base-hover"
|
||||
onClick={item.onClick}
|
||||
>
|
||||
{cloneElement(item.icon, { className: 'h-4 w-4 text-text-tertiary' })}
|
||||
<span className="system-md-regular text-text-secondary">{item.title}</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</PortalToFollowElemContent>
|
||||
</PortalToFollowElem>
|
||||
)}
|
||||
</div>
|
||||
</>
|
||||
)
|
||||
|
||||
@@ -17,6 +17,7 @@ import NavLink from './navLink'
|
||||
import { useStore as useAppStore } from '@/app/components/app/store'
|
||||
import type { NavIcon } from './navLink'
|
||||
import cn from '@/utils/classnames'
|
||||
import { AppModeEnum } from '@/types/app'
|
||||
|
||||
type Props = {
|
||||
navigation: Array<{
|
||||
@@ -97,7 +98,7 @@ const AppSidebarDropdown = ({ navigation }: Props) => {
|
||||
<div className='flex w-full'>
|
||||
<div className='system-md-semibold truncate text-text-secondary'>{appDetail.name}</div>
|
||||
</div>
|
||||
<div className='system-2xs-medium-uppercase text-text-tertiary'>{appDetail.mode === 'advanced-chat' ? t('app.types.advanced') : appDetail.mode === 'agent-chat' ? t('app.types.agent') : appDetail.mode === 'chat' ? t('app.types.chatbot') : appDetail.mode === 'completion' ? t('app.types.completion') : t('app.types.workflow')}</div>
|
||||
<div className='system-2xs-medium-uppercase text-text-tertiary'>{appDetail.mode === AppModeEnum.ADVANCED_CHAT ? t('app.types.advanced') : appDetail.mode === AppModeEnum.AGENT_CHAT ? t('app.types.agent') : appDetail.mode === AppModeEnum.CHAT ? t('app.types.chatbot') : appDetail.mode === AppModeEnum.COMPLETION ? t('app.types.completion') : t('app.types.workflow')}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,7 +3,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import AppIcon from '../base/app-icon'
|
||||
import Tooltip from '@/app/components/base/tooltip'
|
||||
import {
|
||||
Code,
|
||||
ApiAggregate,
|
||||
WindowCursor,
|
||||
} from '@/app/components/base/icons/src/vender/workflow'
|
||||
|
||||
@@ -40,8 +40,8 @@ const NotionSvg = <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xm
|
||||
|
||||
const ICON_MAP = {
|
||||
app: <AppIcon className='border !border-[rgba(0,0,0,0.05)]' />,
|
||||
api: <div className='rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-violet-violet-500 p-1 shadow-md'>
|
||||
<Code className='h-4 w-4 text-text-primary-on-surface' />
|
||||
api: <div className='rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-brand-blue-brand-500 p-1 shadow-md'>
|
||||
<ApiAggregate className='h-4 w-4 text-text-primary-on-surface' />
|
||||
</div>,
|
||||
dataset: <AppIcon innerIcon={DatasetSvg} className='!border-[0.5px] !border-indigo-100 !bg-indigo-25' />,
|
||||
webapp: <div className='rounded-lg border-[0.5px] border-divider-subtle bg-util-colors-blue-brand-blue-brand-500 p-1 shadow-md'>
|
||||
@@ -56,12 +56,12 @@ export default function AppBasic({ icon, icon_background, name, isExternal, type
|
||||
return (
|
||||
<div className="flex grow items-center">
|
||||
{icon && icon_background && iconType === 'app' && (
|
||||
<div className='mr-3 shrink-0'>
|
||||
<div className='mr-2 shrink-0'>
|
||||
<AppIcon icon={icon} background={icon_background} />
|
||||
</div>
|
||||
)}
|
||||
{iconType !== 'app'
|
||||
&& <div className='mr-3 shrink-0'>
|
||||
&& <div className='mr-2 shrink-0'>
|
||||
{ICON_MAP[iconType]}
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user