Skip to content

Commit bcf4d8b

Browse files
authored
feat(ui): show message form submission (#1298)
1 parent 5bd7eb5 commit bcf4d8b

20 files changed

+343
-48
lines changed

apps/beeai-ui/src/api/a2a/utils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,4 +176,10 @@ export function getFilePlatformUrl(id: string) {
176176
return `${PLATFORM_FILE_CONTENT_URL_BASE}${id}`;
177177
}
178178

179+
export function getFileIdFromFilePlatformUrl(url: string) {
180+
const fileId = url.replace(PLATFORM_FILE_CONTENT_URL_BASE, '');
181+
182+
return fileId;
183+
}
184+
179185
const MAX_CONTENT_CHARS_LENGTH = 16000;

apps/beeai-ui/src/components/TextAreaAutoHeight/TextAreaAutoHeight.module.scss

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,11 @@ $padding-inline: $spacing-05;
4949
opacity: 0.5;
5050
}
5151
}
52+
&:disabled {
53+
cursor: not-allowed;
54+
color: $text-disabled;
55+
background-color: $field;
56+
}
5257
}
5358

5459
&::after,

apps/beeai-ui/src/modules/form/components/FormField.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,34 @@
44
*/
55

66
import type { CSSProperties } from 'react';
7-
import { match } from 'ts-pattern';
7+
import { match, P } from 'ts-pattern';
88

9-
import type { FormField } from '#api/a2a/extensions/ui/form.ts';
9+
import type { FormField, FormResponseValue } from '#api/a2a/extensions/ui/form.ts';
1010

1111
import { CheckboxField } from './fields/CheckboxField';
1212
import { DateField } from './fields/DateField';
1313
import { FileField } from './fields/FileField';
14+
import { FileFieldValue } from './fields/FileFieldValue';
1415
import { MultiSelectField } from './fields/MultiSelectField';
1516
import { TextField } from './fields/TextField';
1617
import classes from './FormField.module.scss';
1718

1819
interface Props {
1920
field: FormField;
21+
value?: FormResponseValue;
2022
}
2123

22-
export function FormField({ field }: Props) {
24+
export function FormField({ field, value }: Props) {
2325
const { col_span } = field;
2426

2527
const component = match(field)
2628
.with({ type: 'text' }, (field) => <TextField field={field} />)
2729
.with({ type: 'date' }, (field) => <DateField field={field} />)
28-
.with({ type: 'file' }, (field) => <FileField field={field} />)
30+
.with({ type: 'file' }, (field) =>
31+
match(value)
32+
.with({ type: 'file', value: P.nonNullable }, ({ value }) => <FileFieldValue field={field} value={value} />)
33+
.otherwise(() => <FileField field={field} />),
34+
)
2935
.with({ type: 'multiselect' }, (field) => <MultiSelectField field={field} />)
3036
.with({ type: 'checkbox' }, (field) => <CheckboxField field={field} />)
3137
.exhaustive();
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* Copyright 2025 © BeeAI a Series of LF Projects, LLC
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
.root {
7+
--field-gap: #{$spacing-04};
8+
--file-field-max-width: calc(50% - (var(--field-gap) / 2));
9+
display: grid;
10+
column-gap: var(--field-gap);
11+
row-gap: $spacing-06;
12+
grid-template-columns: repeat(var(--grid-columns, 1), minmax(0, 1fr));
13+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
/**
2+
* Copyright 2025 © BeeAI a Series of LF Projects, LLC
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import type { CSSProperties } from 'react';
7+
8+
import type { FormRender, FormResponse } from '#api/a2a/extensions/ui/form.ts';
9+
10+
import { FormField } from './FormField';
11+
import classes from './FormFields.module.scss';
12+
13+
interface Props {
14+
fields: FormRender['fields'];
15+
columns: FormRender['columns'];
16+
values?: FormResponse['values'];
17+
}
18+
19+
export function FormFields({ fields, columns, values }: Props) {
20+
return (
21+
<div className={classes.root} style={{ '--grid-columns': columns } as CSSProperties}>
22+
{fields.map((field) => {
23+
return <FormField key={field.id} field={field} value={values?.[field.id]} />;
24+
})}
25+
</div>
26+
);
27+
}

apps/beeai-ui/src/modules/form/components/FormRenderer.tsx

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55

66
import { Button } from '@carbon/react';
7-
import type { CSSProperties } from 'react';
87
import { FormProvider, useForm } from 'react-hook-form';
98

109
import type { FormRender } from '#api/a2a/extensions/ui/form.ts';
@@ -14,7 +13,7 @@ import { AgentWelcomeMessage } from '#modules/agents/components/AgentWelcomeMess
1413

1514
import type { RunFormValues } from '../types';
1615
import { getDefaultValues } from '../utils';
17-
import { FormField } from './FormField';
16+
import { FormFields } from './FormFields';
1817
import classes from './FormRenderer.module.scss';
1918

2019
interface Props {
@@ -48,11 +47,7 @@ export function FormRenderer({ definition, defaultHeading, showHeading = true, i
4847
</AgentHeader>
4948
)}
5049

51-
<div className={classes.fields} style={{ '--grid-columns': columns } as CSSProperties}>
52-
{fields.map((field) => (
53-
<FormField key={field.id} field={field} />
54-
))}
55-
</div>
50+
<FormFields fields={fields} columns={columns} />
5651

5752
{!isDisabled && (
5853
<>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/**
2+
* Copyright 2025 © BeeAI a Series of LF Projects, LLC
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
.files {
7+
column-gap: var(--field-gap);
8+
> li {
9+
max-inline-size: var(--file-field-max-width);
10+
}
11+
}
12+
13+
.empty {
14+
color: $text-secondary;
15+
}

apps/beeai-ui/src/modules/form/components/fields/FileField.module.scss

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,24 @@
44
*/
55

66
.button {
7-
&:global(.cds--btn:hover) {
8-
background-color: $layer-hover-02;
7+
&:global(.cds--btn) {
8+
&:hover {
9+
background-color: $layer-hover-02;
10+
}
11+
&:disabled {
12+
&,
13+
&:hover {
14+
color: $text-disabled;
15+
background-color: $field;
16+
border-color: $border-subtle-00;
17+
}
18+
}
919
}
1020
}
1121

1222
.files {
23+
column-gap: var(--field-gap);
1324
> li {
14-
max-inline-size: calc(50% - #{math.div($spacing-04, 2)});
25+
max-inline-size: var(--file-field-max-width);
1526
}
1627
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/**
2+
* Copyright 2025 © BeeAI a Series of LF Projects, LLC
3+
* SPDX-License-Identifier: Apache-2.0
4+
*/
5+
6+
import { FormGroup } from '@carbon/react';
7+
8+
import type { FileField, FormResponseValue } from '#api/a2a/extensions/ui/form.ts';
9+
import { getFileIdFromFilePlatformUrl } from '#api/a2a/utils.ts';
10+
import { FileCard } from '#modules/files/components/FileCard.tsx';
11+
import { FileCardsList } from '#modules/files/components/FileCardsList.tsx';
12+
import { getFileContentUrl } from '#modules/files/utils.ts';
13+
14+
import classes from './FielFieldValue.module.scss';
15+
16+
interface Props {
17+
field: FileField;
18+
value: NonNullable<Extract<FormResponseValue, { type: 'file' }>['value']>;
19+
}
20+
21+
export function FileFieldValue({ field, value }: Props) {
22+
const { label } = field;
23+
const hasFiles = value.length > 0;
24+
25+
return (
26+
<FormGroup legendText={label}>
27+
{hasFiles ? (
28+
<FileCardsList className={classes.files}>
29+
{value.map(({ uri, name }) => {
30+
const href = getFileContentUrl(getFileIdFromFilePlatformUrl(uri));
31+
const filename = name ?? uri;
32+
33+
return (
34+
<li key={uri}>
35+
<FileCard href={href} size="sm" filename={filename} />
36+
</li>
37+
);
38+
})}
39+
</FileCardsList>
40+
) : (
41+
<p className={classes.empty}>No files selected</p>
42+
)}
43+
</FormGroup>
44+
);
45+
}

apps/beeai-ui/src/modules/form/components/fields/MultiSelect.module.scss

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,17 +11,27 @@
1111

1212
.option {
1313
&:global(.cds--tag) {
14+
color: $text-primary;
1415
border-color: $layer-02;
1516
background-color: $layer-02;
16-
color: $text-primary;
1717
&:hover {
1818
border-color: $layer-hover-02;
1919
background-color: $layer-hover-02;
2020
}
21-
&.isSelected {
21+
&:disabled {
22+
cursor: not-allowed;
23+
color: $text-disabled;
24+
border-color: $field;
25+
background-color: $field;
26+
}
27+
&:global(.cds--tag--selected) {
28+
color: $text-inverse;
2229
border-color: $text-primary;
2330
background-color: $text-primary;
24-
color: $text-inverse;
31+
&:disabled {
32+
border-color: $layer-selected-disabled;
33+
background-color: $layer-selected-disabled;
34+
}
2535
}
2636
}
2737
}

0 commit comments

Comments
 (0)