Skip to content

Commit

Permalink
[Vector Visualization Page] Graph (#85)
Browse files Browse the repository at this point in the history
* initial setup graph

* single color visualise

* random color

* parsed data fuction

* bug error management

* id bug

* multivector support and view point modal

* intro for visualization query editor

* visualize tab on the collection page, outlined dismiss button, removed unnecessary SnakbarProvider, updated visual design in ViewPointModal + small refactoring

* a collection name title and a back to collection button on Visualize page

* fix chart header

* Resize Visulaize chart resolved

---------

Co-authored-by: Kartik Gupta <[email protected]>
Co-authored-by: generall <[email protected]>
Co-authored-by: trean <[email protected]>
  • Loading branch information
4 people authored Jul 29, 2023
1 parent 3b572a3 commit f83e560
Show file tree
Hide file tree
Showing 15 changed files with 599 additions and 201 deletions.
30 changes: 30 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"@vitejs/plugin-react": "^4.0.0",
"autocomplete-openapi": "^0.1.1",
"axios": "^1.3.4",
"chart.js": "^4.3.0",
"jsonc-parser": "^3.2.0",
"lodash": "^4.17.21",
"mui-chips-input": "^2.0.1",
Expand Down
13 changes: 10 additions & 3 deletions src/components/FilterEditorWindow/config/RequesFromCode.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,18 @@ export function RequestFromCode(text, collectionName) {
})
.then((response) => {
response.data.color_by = data.reqBody.color_by;
response.data.vector_name = data.reqBody.vector_name;
return response.data;
response.data.vector_name = data.reqBody.vector_name;
return {
data: response.data,
error: null,
};
})
.catch((err) => {
return err.response?.data?.status ? err.response?.data?.status : err;

return {
data: null,
error: err.response?.data?.status ? err.response?.data?.status : err
};
});
}
}
Expand Down
4 changes: 2 additions & 2 deletions src/components/FilterEditorWindow/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ const CodeEditorWindow = ({ onChange, code, onChangeResult }) => {
async (_ctx, ...args) => {
let data = args[0];
const result = await RequestFromCode(data,collectionName);
onChangeResult(JSON.stringify(result));
onChangeResult(result);
},
""
);
Expand Down Expand Up @@ -90,7 +90,7 @@ const CodeEditorWindow = ({ onChange, code, onChangeResult }) => {
async () => {
let data = selectedCodeBlock.blockText;
const result = await RequestFromCode(data, collectionName);
onChangeResult("code", JSON.stringify(result));
onChangeResult( result);
}
);
}
Expand Down
57 changes: 5 additions & 52 deletions src/components/Points/PointCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,23 +3,22 @@ import PropTypes from "prop-types";
import {
Card,
CardContent,
Divider,
Typography,
Grid,
CardHeader,
Snackbar,
Alert, LinearProgress, Box,
} from "@mui/material";

import PointImage from "./PointImage";
import { alpha } from "@mui/material";
import { useTheme } from "@mui/material/styles";
import CopyAll from "@mui/icons-material/CopyAll";
import Edit from "@mui/icons-material/Edit";
import IconButton from "@mui/material/IconButton";
import Tooltip from "@mui/material/Tooltip";
import { JsonViewer } from "@textea/json-viewer";
import PointImage from "./PointImage";
import Vectors from "./PointVectors";
import { PayloadEditor } from "./PayloadEditor";
import { PointPayloadList } from "./PointPayloadList";

const PointCard = (props) => {
const theme = useTheme();
Expand All @@ -29,52 +28,6 @@ const PointCard = (props) => {
const [openSnackbar, setOpenSnackbar] = React.useState(false);
const [loading, setLoading] = React.useState(false);

function resDataView(data) {
const Payload = Object.keys(data.payload).map((key) => {
return (
<div key={key}>
<Grid container spacing={2}>
<Grid item xs={2} my={1}>
<Typography
variant="subtitle1"
display={"inline"}
fontWeight={600}
>
{key}
</Typography>
</Grid>

<Grid item xs={10} my={1}>
{typeof data.payload[key] === "object" ? (
<Typography variant="subtitle1">
{" "}
<JsonViewer
theme={theme.palette.mode}
value={data.payload[key]}
displayDataTypes={false}
defaultInspectDepth={0}
rootName={false}
/>{" "}
</Typography>
) : (
<Typography
variant="subtitle1"
color="text.secondary"
display={"inline"}
>
{"\t"} {data.payload[key].toString()}
</Typography>
)}
</Grid>
</Grid>
<Divider/>
</div>
);
});

return <>{Payload}</>;
}

const onPayloadEdit = (payload) => {
setPoint({ ...point, payload: structuredClone(payload) });
};
Expand Down Expand Up @@ -157,11 +110,11 @@ const PointCard = (props) => {
<CardContent>
<Grid container display={"flex"}>
<Grid item xs my={1}>
{resDataView(point)}
<PointPayloadList data={point} />
</Grid>
{point.payload.images &&
<Grid item xs={3} display="grid" justifyContent={"center"}>
<PointImage data={point.payload} sx={{ ml: 2 }}/>
<PointImage data={point.payload} sx={{ ml: 2 }} />
</Grid>
}
</Grid>
Expand Down
56 changes: 56 additions & 0 deletions src/components/Points/PointPayloadList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import React from "react";
import PropTypes from "prop-types";
import { JsonViewer } from "@textea/json-viewer";
import { useTheme } from "@mui/material/styles";
import { Divider, Grid, Typography } from "@mui/material";

export const PointPayloadList = function({data}) {
const theme = useTheme();

return Object.keys(data.payload).map((key) => {
return (
<div key={key}>
<Grid container spacing={2}>
<Grid item xs={3} my={1}>
<Typography
variant="subtitle1"
display={"inline"}
fontWeight={600}
sx={{wordBreak: "break-word"}}
>
{key}
</Typography>
</Grid>

<Grid item xs={9} my={1}>
{typeof data.payload[key] === "object" ? (
<Typography variant="subtitle1">
{" "}
<JsonViewer
theme={theme.palette.mode}
value={data.payload[key]}
displayDataTypes={false}
defaultInspectDepth={0}
rootName={false}
/>{" "}
</Typography>
) : (
<Typography
variant="subtitle1"
color="text.secondary"
display={"inline"}
>
{"\t"} {data.payload[key].toString()}
</Typography>
)}
</Grid>
</Grid>
<Divider/>
</div>
);
});
}

PointPayloadList.propTypes = {
data: PropTypes.object.isRequired,
}
2 changes: 1 addition & 1 deletion src/components/Snapshots/SnapshotUploadForm.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export const SnapshotUploadForm = ({ onSubmit, onComplete, sx }) => {
autoHideDuration: null,
action: (key) => (
<Button
variant="text"
variant="outlined"
color="inherit"
onClick={() => {
closeSnackbar(key);
Expand Down
2 changes: 1 addition & 1 deletion src/components/Snapshots/SnapshotsTab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const SnapshotsTab = ({ collectionName }) => {
autoHideDuration: null,
action: (key) => (
<Button
variant="text"
variant="outlined"
color="inherit"
onClick={() => {
closeSnackbar(key);
Expand Down
101 changes: 101 additions & 0 deletions src/components/VisualizeChart/ViewPointModal.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import React from "react";
import PropTypes from "prop-types";
import {
Alert,
Box,
Button,
Dialog,
DialogContent,
DialogActions,
DialogTitle,
IconButton,
Paper,
Tooltip,
Typography,
Snackbar,
} from "@mui/material";
import { alpha } from "@mui/material";
import { useTheme } from "@mui/material/styles";
import { CopyAll } from "@mui/icons-material";
import { PointPayloadList } from "../Points/PointPayloadList";

const ViewPointModal = (props) => {
const theme = useTheme();
const [openTooltip, setOpenTooltip] = React.useState(false);
const { openViewPoints, setOpenViewPoints, viewPoints } = props;

return (
<>
<Dialog open={openViewPoints} onClose={() => setOpenViewPoints(false)}
scroll={"paper"} maxWidth={"lg"} fullWidth={true}>
<DialogTitle id="scroll-dialog-title">Selected Points</DialogTitle>
<DialogContent>
{viewPoints.length > 0 ? (
<>
{viewPoints.map((point, index) => (
<Paper key={`${index}-${point.id}`}>
<Box
sx={{
display: "flex",
justifyContent: "space-between",
background: alpha(theme.palette.primary.main,
0.05),
px: 3,
py: 2,
}}>
<Typography variant="h6" component="h2"
>
Point {point.id}
</Typography>

<Tooltip title="Copy JSON" placement="left">
<IconButton
aria-label="copy point"
onClick={() => {
navigator.clipboard.writeText(
JSON.stringify(point),
);
setOpenTooltip(true);
}}
>
<CopyAll/>
</IconButton>
</Tooltip>
</Box>
<Box px={3} pt={1} pb={5}>
<PointPayloadList data={point} sx={{ px: 3, py: 4 }}/>
</Box>
</Paper>
))}
</>
) : (
<Typography variant="h6" component="h2">
no points selected
</Typography>
)}
</DialogContent>
<DialogActions>
<Button onClick={() => setOpenViewPoints(false)}>Close</Button>
</DialogActions>
</Dialog>
<Snackbar
open={openTooltip}
severity="success"
autoHideDuration={3000}
onClose={() => setOpenTooltip(false)}
>
<Alert severity="success" sx={{ width: "100%" }}>
Point JSON copied to clipboard.
</Alert>
</Snackbar>
</>
);
};

ViewPointModal.propTypes = {
openViewPoints: PropTypes.bool.isRequired,
setOpenViewPoints: PropTypes.func.isRequired,
viewPoints: PropTypes.array.isRequired,
};

export default ViewPointModal;
Loading

0 comments on commit f83e560

Please sign in to comment.