apps/Standalone/src/dataMapperV1/components/DevSerializationTester.tsx (218 lines of code) (raw):
import type { RootState } from '../state/Store';
import { Stack } from '@fluentui/react';
import {
Accordion,
AccordionHeader,
AccordionItem,
AccordionPanel,
Button,
makeStyles,
shorthands,
Tab,
TabList,
Text,
tokens,
} from '@fluentui/react-components';
import type { MonacoProps } from '@microsoft/designer-ui';
import { MonacoEditor } from '@microsoft/designer-ui';
import {
convertSchemaToSchemaExtended,
convertToMapDefinition,
flattenSchemaIntoSortArray,
loadMapDefinition,
MapDefinitionDeserializer,
} from '@microsoft/logic-apps-data-mapper';
import { EditorLanguage } from '@microsoft/logic-apps-shared';
import { useMemo, useState } from 'react';
import { useSelector } from 'react-redux';
const SerializationTab = {
Deserialization: 'Deserialization',
Serialization: 'Serialization',
} as const;
type SerializationTab = (typeof SerializationTab)[keyof typeof SerializationTab];
const commonCodeEditorProps: Partial<MonacoProps> = {
lineNumbers: 'on',
scrollbar: { horizontal: 'auto', vertical: 'auto' },
wordWrap: 'on',
wrappingIndent: 'same',
width: '600px',
};
const useStyles = makeStyles({
editorStyle: {
...shorthands.border('1px', 'solid', tokens.colorNeutralStroke1),
...shorthands.borderRadius(tokens.borderRadiusMedium),
...shorthands.padding('2px'),
},
});
export const DevSerializationTester = () => {
const styles = useStyles();
const [selectedTab, setSelectedTab] = useState<SerializationTab>(SerializationTab.Deserialization);
const [inputMapDefinition, setInputMapDefinition] = useState<string>('');
const [outputConnections, setOutputConnections] = useState<string>('');
const [inputConnections, setInputConnections] = useState<string>('');
const [outputMapDefinition, setOutputMapDefinition] = useState<string>('');
const { fetchedFunctions } = useSelector((state: RootState) => state.dataMapDataLoader);
const { sourceSchema, targetSchema } = useSelector((state: RootState) => state.schemaDataLoader);
const sourceSchemaExtended = useMemo(() => {
if (sourceSchema) {
return convertSchemaToSchemaExtended(sourceSchema);
}
return undefined;
}, [sourceSchema]);
const targetSchemaExtended = useMemo(() => {
if (targetSchema) {
return convertSchemaToSchemaExtended(targetSchema);
}
return undefined;
}, [targetSchema]);
const targetSchemaSortArray = useMemo(() => {
return targetSchemaExtended ? flattenSchemaIntoSortArray(targetSchemaExtended.schemaTreeRoot) : [];
}, [targetSchemaExtended]);
const deserializeMapDefinitionIntoConnections = () => {
if (!sourceSchemaExtended || !targetSchemaExtended) {
window.alert('You must select your source and target schemas in the dropdowns above!');
return;
}
if (!fetchedFunctions) {
window.alert('No function data was found.');
return;
}
const mapDefinitionDeserializer = new MapDefinitionDeserializer(
loadMapDefinition(inputMapDefinition ?? ''),
sourceSchemaExtended,
targetSchemaExtended,
fetchedFunctions
);
const deserializedConnections = mapDefinitionDeserializer.convertFromMapDefinition();
setOutputConnections(JSON.stringify(deserializedConnections, null, 2));
};
const serializeConnectionsIntoMapDefinition = () => {
if (!sourceSchema || !targetSchema) {
window.alert('You must select your source and target schemas in the dropdowns above!');
return;
}
const serializedMapDefinition = convertToMapDefinition(
JSON.parse(inputConnections),
sourceSchemaExtended,
targetSchemaExtended,
targetSchemaSortArray
);
setOutputMapDefinition(serializedMapDefinition);
};
return (
<div style={{ backgroundColor: tokens.colorNeutralBackground2 }}>
<Accordion collapsible>
<AccordionItem value="1">
<AccordionHeader>Serialization Tester</AccordionHeader>
<AccordionPanel>
<Text>
<Text weight="bold">NOTE:</Text> This uses the source and target schemas you've selected above!
</Text>
<TabList
selectedValue={selectedTab}
onTabSelect={(_e, data) => setSelectedTab(data.value as SerializationTab)}
style={{ marginBottom: 16 }}
>
<Tab id="Deserialization" value={SerializationTab.Deserialization}>
Deserialization
</Tab>
<Tab id="Serialization" value={SerializationTab.Serialization}>
Serialization
</Tab>
</TabList>
<Stack horizontal horizontalAlign="space-around" tokens={{ childrenGap: '8px' }} wrap>
{selectedTab === SerializationTab.Deserialization && (
<>
<Stack tokens={{ childrenGap: '8px' }}>
<Text
style={{
fontWeight: 'bold',
fontSize: '22px',
display: 'block',
marginBottom: '12px',
}}
>
Map definition
</Text>
<MonacoEditor
{...commonCodeEditorProps}
language={EditorLanguage.yaml}
value={inputMapDefinition}
onContentChanged={(e) => setInputMapDefinition(e.value ?? '')}
className={styles.editorStyle}
height="400px"
/>
<Button onClick={deserializeMapDefinitionIntoConnections}>Deserialize map definition</Button>
</Stack>
<Stack tokens={{ childrenGap: '8px' }}>
<Text
style={{
fontWeight: 'bold',
fontSize: '22px',
display: 'block',
marginBottom: '12px',
}}
>
Connections
</Text>
<MonacoEditor
{...commonCodeEditorProps}
language={EditorLanguage.json}
value={outputConnections}
className={styles.editorStyle}
height="400px"
readOnly
/>
</Stack>
</>
)}
{selectedTab === SerializationTab.Serialization && (
<>
<Stack tokens={{ childrenGap: '8px' }}>
<Text
style={{
fontWeight: 'bold',
fontSize: '22px',
display: 'block',
marginBottom: '12px',
}}
>
Connections
</Text>
<MonacoEditor
{...commonCodeEditorProps}
language={EditorLanguage.json}
value={inputConnections}
onContentChanged={(e) => setInputConnections(e.value ?? '')}
className={styles.editorStyle}
height="400px"
/>
<Button onClick={serializeConnectionsIntoMapDefinition}>Serialize connections</Button>
</Stack>
<Stack tokens={{ childrenGap: '8px' }}>
<Text
style={{
fontWeight: 'bold',
fontSize: '22px',
display: 'block',
marginBottom: '12px',
}}
>
Map definition
</Text>
<MonacoEditor
{...commonCodeEditorProps}
language={EditorLanguage.json}
value={outputMapDefinition}
className={styles.editorStyle}
height="400px"
readOnly
/>
</Stack>
</>
)}
</Stack>
</AccordionPanel>
</AccordionItem>
</Accordion>
</div>
);
};