feat: add searchable json viewer component

This commit is contained in:
Rıdvan Akca
2023-03-10 16:27:32 +03:00
parent 1e62e09825
commit 3e0149c058
2 changed files with 82 additions and 4 deletions

View File

@@ -10,7 +10,7 @@ import Box from '@mui/material/Box';
import type { IApp, IExecutionStep, IStep } from '@automatisch/types';
import TabPanel from 'components/TabPanel';
import JSONViewer from 'components/JSONViewer';
import SearchableJSONViewer from 'components/SearchableJSONViewer';
import AppIcon from 'components/AppIcon';
import { GET_APPS } from 'graphql/queries/get-apps';
import useFormatMessage from 'hooks/useFormatMessage';
@@ -92,16 +92,16 @@ export default function ExecutionStep(
</Box>
<TabPanel value={activeTabIndex} index={0}>
<JSONViewer data={executionStep.dataIn} />
<SearchableJSONViewer data={executionStep.dataIn} />
</TabPanel>
<TabPanel value={activeTabIndex} index={1}>
<JSONViewer data={executionStep.dataOut} />
<SearchableJSONViewer data={executionStep.dataOut} />
</TabPanel>
{hasError && (
<TabPanel value={activeTabIndex} index={2}>
<JSONViewer data={executionStep.errorDetails} />
<SearchableJSONViewer data={executionStep.errorDetails} />
</TabPanel>
)}
</Content>

View File

@@ -0,0 +1,78 @@
import * as React from 'react';
import get from 'lodash/get';
import set from 'lodash/set';
import throttle from 'lodash/throttle';
import { Box } from '@mui/material';
import { IJSONObject, IJSONValue } from '@automatisch/types';
import JSONViewer from 'components/JSONViewer';
import SearchInput from 'components/SearchInput';
type JSONViewerProps = {
data: IJSONObject;
};
type Entry = [string, IJSONValue];
const SearchableJSONViewer = ({ data }: JSONViewerProps) => {
const [filteredData, setFilteredData] = React.useState(data);
const allEntries = React.useMemo(() => {
const entries: Entry[] = [];
const collectEntries = (obj: IJSONObject, prefix?: string) => {
for (const key in obj) {
if (typeof obj[key] === 'object' && obj[key] !== null) {
entries.push([[prefix, key].filter(Boolean).join('.'), obj[key]]);
collectEntries(
obj[key] as IJSONObject,
[prefix, key].filter(Boolean).join('.')
);
} else {
entries.push([[prefix, key].filter(Boolean).join('.'), obj[key]]);
}
}
};
collectEntries(data);
return entries;
}, [data]);
const onSearchChange = React.useMemo(
() =>
throttle((event: React.ChangeEvent) => {
const search = (event.target as HTMLInputElement).value.toLowerCase();
const newFilteredData: IJSONObject = {};
if (!search) {
setFilteredData(data);
return;
}
allEntries.forEach(([key, value]) => {
if (
key.toLowerCase().includes(search) ||
(typeof value !== 'object' &&
value.toString().toLowerCase().includes(search))
) {
const value = get(filteredData, key);
set(newFilteredData, key, value);
}
});
setFilteredData(newFilteredData);
}, 400),
[allEntries]
);
return (
<>
<Box mb={1} mt={2}>
<SearchInput onChange={onSearchChange} />
</Box>
<JSONViewer data={filteredData} />
</>
);
};
export default SearchableJSONViewer;