feat: add emoji support to knowledge bases and pipelines (#1935)

* feat: add emoji support to knowledge bases and pipelines

* feat: add optional emoji property to ExternalKBCardVO for enhanced knowledge base representation
This commit is contained in:
Junyan Qin (Chin)
2026-01-26 17:37:35 +08:00
committed by GitHub
parent d6e1e79f07
commit b73847f1a6
24 changed files with 3701 additions and 1173 deletions
@@ -8,12 +8,15 @@ export default function PipelineCard({ cardVO }: { cardVO: PipelineCardVO }) {
return (
<div className={`${styles.cardContainer}`}>
<div className={`${styles.basicInfoContainer}`}>
<div className={`${styles.basicInfoNameContainer}`}>
<div className={`${styles.basicInfoNameText} ${styles.bigText}`}>
{cardVO.name}
</div>
<div className={`${styles.basicInfoDescriptionText}`}>
{cardVO.description}
<div className={`${styles.iconBasicInfoContainer}`}>
<div className={`${styles.iconEmoji}`}>{cardVO.emoji || '⚙️'}</div>
<div className={`${styles.basicInfoNameContainer}`}>
<div className={`${styles.basicInfoNameText} ${styles.bigText}`}>
{cardVO.name}
</div>
<div className={`${styles.basicInfoDescriptionText}`}>
{cardVO.description}
</div>
</div>
</div>
@@ -33,8 +36,8 @@ export default function PipelineCard({ cardVO }: { cardVO: PipelineCardVO }) {
</div>
</div>
<div className={styles.operationContainer}>
{cardVO.isDefault && (
{cardVO.isDefault && (
<div className={styles.operationContainer}>
<div className={styles.operationDefaultBadge}>
<svg
className={styles.operationDefaultBadgeIcon}
@@ -48,8 +51,8 @@ export default function PipelineCard({ cardVO }: { cardVO: PipelineCardVO }) {
{t('pipelines.defaultBadge')}
</div>
</div>
)}
</div>
</div>
)}
</div>
);
}
@@ -4,6 +4,7 @@ export interface IPipelineCardVO {
description: string;
lastUpdatedTimeAgo: string;
isDefault: boolean;
emoji?: string;
}
export class PipelineCardVO implements IPipelineCardVO {
@@ -12,6 +13,7 @@ export class PipelineCardVO implements IPipelineCardVO {
name: string;
lastUpdatedTimeAgo: string;
isDefault: boolean;
emoji?: string;
constructor(props: IPipelineCardVO) {
this.id = props.id;
@@ -19,5 +21,6 @@ export class PipelineCardVO implements IPipelineCardVO {
this.description = props.description;
this.lastUpdatedTimeAgo = props.lastUpdatedTimeAgo;
this.isDefault = props.isDefault;
this.emoji = props.emoji;
}
}
@@ -4,7 +4,7 @@
background-color: #fff;
border-radius: 10px;
box-shadow: 0px 2px 2px 0 rgba(0, 0, 0, 0.2);
padding: 1.2rem;
padding: 1rem;
cursor: pointer;
display: flex;
flex-direction: row;
@@ -32,14 +32,41 @@
display: flex;
flex-direction: column;
justify-content: space-between;
gap: 0.4rem;
gap: 0.5rem;
min-width: 0;
}
.iconEmoji {
width: 3rem;
height: 3rem;
border-radius: 0.5rem;
background-color: #f5f5f5;
display: flex;
align-items: center;
justify-content: center;
font-size: 1.75rem;
flex-shrink: 0;
}
:global(.dark) .iconEmoji {
background-color: #2a2a2d;
}
.iconBasicInfoContainer {
display: flex;
flex-direction: row;
gap: 0.75rem;
align-items: flex-start;
min-width: 0;
flex: 1;
}
.basicInfoNameContainer {
display: flex;
flex-direction: column;
gap: 0.2rem;
min-width: 0;
flex: 1;
}
.basicInfoNameText {
@@ -13,6 +13,7 @@ import { useForm } from 'react-hook-form';
import { zodResolver } from '@hookform/resolvers/zod';
import { z } from 'zod';
import { Input } from '@/components/ui/input';
import EmojiPicker from '@/components/ui/emoji-picker';
import {
Form,
FormControl,
@@ -62,6 +63,7 @@ export default function PipelineFormComponent({
description: z
.string()
.min(1, { message: t('pipelines.descriptionRequired') }),
emoji: z.string().optional(),
}),
ai: z.record(z.string(), z.any()),
trigger: z.record(z.string(), z.any()),
@@ -74,6 +76,7 @@ export default function PipelineFormComponent({
description: z
.string()
.min(1, { message: t('pipelines.descriptionRequired') }),
emoji: z.string().optional(),
}),
ai: z.record(z.string(), z.any()).optional(),
trigger: z.record(z.string(), z.any()).optional(),
@@ -105,7 +108,9 @@ export default function PipelineFormComponent({
const form = useForm<FormValues>({
resolver: zodResolver(formSchema),
defaultValues: {
basic: {},
basic: {
emoji: '⚙️',
},
ai: {},
trigger: {},
safety: {},
@@ -138,6 +143,7 @@ export default function PipelineFormComponent({
basic: {
name: resp.pipeline.name,
description: resp.pipeline.description,
emoji: resp.pipeline.emoji || '⚙️',
},
ai: resp.pipeline.config.ai,
trigger: resp.pipeline.config.trigger,
@@ -154,6 +160,7 @@ export default function PipelineFormComponent({
basic: {
name: '',
description: '',
emoji: '⚙️',
},
});
}
@@ -172,6 +179,7 @@ export default function PipelineFormComponent({
config: {},
description: values.basic.description,
name: values.basic.name,
emoji: values.basic.emoji,
};
httpClient
.createPipeline(pipeline)
@@ -199,6 +207,7 @@ export default function PipelineFormComponent({
description: values.basic.description,
// for_version: '',
name: values.basic.name,
emoji: values.basic.emoji,
// stages: [],
// updated_at: '',
// uuid: pipelineId || '',
@@ -399,22 +408,41 @@ export default function PipelineFormComponent({
>
{formLabel.name === 'basic' && (
<div className="space-y-6">
<FormField
control={form.control}
name="basic.name"
render={({ field }) => (
<FormItem>
<FormLabel>
{t('common.name')}
<span className="text-red-500">*</span>
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
{/* Name and Emoji in same row */}
<div className="flex gap-4 items-start">
<FormField
control={form.control}
name="basic.name"
render={({ field }) => (
<FormItem className="flex-1">
<FormLabel>
{t('common.name')}
<span className="text-red-500">*</span>
</FormLabel>
<FormControl>
<Input {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={form.control}
name="basic.emoji"
render={({ field }) => (
<FormItem>
<FormLabel>{t('common.icon')}</FormLabel>
<FormControl>
<EmojiPicker
value={field.value}
onChange={field.onChange}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
<FormField
control={form.control}