Skip to content

Commit a7c1cc5

Browse files
committed
fix(launch): render object map values as JSON instead of crashing on relaunch
A map whose values are objects (e.g. Map[str, Struct]) parsed each value into the string-typed value field, so the launch form bound an object straight into a text input -- coerced to "[object Object]" and producing render errors on relaunch. JSON-stringify object values at parse time so the field always receives a string. Signed-off-by: 1fanwang <1fannnw@gmail.com>
1 parent b80a88a commit a7c1cc5

2 files changed

Lines changed: 56 additions & 2 deletions

File tree

packages/oss-console/src/components/Launch/LaunchForm/MapInput.tsx

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ const MapSingleInputItem = (props: MapInputItemProps) => {
109109
);
110110
};
111111

112-
const getNewMapItem = (id, key = '', value = ''): MapInputItem => {
112+
const getNewMapItem = (id: number | null, key = '', value = ''): MapInputItem => {
113113
return { id, key, value };
114114
};
115115

@@ -121,7 +121,11 @@ function parseMappedTypeValue(value?: InputValue): MapInputItem[] {
121121
try {
122122
const mapObj = JSON.parse(value.toString());
123123
if (typeof mapObj === 'object') {
124-
return Object.keys(mapObj).map((key, index) => getNewMapItem(index, key, mapObj[key]));
124+
return Object.keys(mapObj).map((key, index) => {
125+
// Object values (e.g. Map[str, struct] on relaunch) must be JSON-stringified for the text field.
126+
const itemValue = mapObj[key];
127+
return getNewMapItem(index, key, typeof itemValue === 'object' ? JSON.stringify(itemValue) : itemValue);
128+
});
125129
}
126130
} catch (e) {
127131
// do nothing
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
import * as React from 'react';
2+
import { ThemeProvider } from '@mui/material/styles';
3+
import { render } from '@testing-library/react';
4+
import { muiTheme } from '@clients/theme/Theme/muiTheme';
5+
import { MapInput } from '../MapInput';
6+
import { InputProps, InputType } from '../types';
7+
8+
const makeMapProps = (value: string): InputProps => ({
9+
description: '',
10+
name: 'mapInput',
11+
label: 'Map Input',
12+
required: false,
13+
typeDefinition: {
14+
literalType: {},
15+
type: InputType.Map,
16+
subtype: { literalType: {}, type: InputType.Struct },
17+
},
18+
value,
19+
onChange: jest.fn(),
20+
});
21+
22+
const renderMap = (value: string) =>
23+
render(
24+
<ThemeProvider theme={muiTheme}>
25+
<MapInput {...makeMapProps(value)} />
26+
</ThemeProvider>,
27+
);
28+
29+
describe('MapInput', () => {
30+
it('renders an object map value as JSON (not "[object Object]") when relaunching', () => {
31+
// A map whose values are themselves objects -- the shape a prior execution produces when
32+
// relaunching (e.g. Map[str, struct]). Before the fix this binds an object straight into the
33+
// value text field, which coerces to "[object Object]" (and produced render errors).
34+
const { container } = renderMap('{"foo":{"nested":"bar"}}');
35+
36+
const keyField = container.querySelector('.keyControl input') as HTMLInputElement;
37+
const valueField = container.querySelector('.valueControl textarea') as HTMLTextAreaElement;
38+
39+
expect(keyField?.value).toBe('foo');
40+
expect(valueField).not.toBeNull();
41+
expect(valueField.value).toBe('{"nested":"bar"}');
42+
expect(valueField.value).not.toBe('[object Object]');
43+
});
44+
45+
it('leaves plain string map values unchanged', () => {
46+
const { container } = renderMap('{"foo":"bar"}');
47+
const valueField = container.querySelector('.valueControl textarea') as HTMLTextAreaElement;
48+
expect(valueField?.value).toBe('bar');
49+
});
50+
});

0 commit comments

Comments
 (0)