Skip to content

Commit

Permalink
workspaces
Browse files Browse the repository at this point in the history
  • Loading branch information
joon-at-sri committed Jul 22, 2024
1 parent 83b660b commit a5452f2
Show file tree
Hide file tree
Showing 8 changed files with 152 additions and 116 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.idea
node_modules
/build
coverage
coverage
workspaces.json
18 changes: 5 additions & 13 deletions proxy-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,8 @@ app.use(cors({
// parse application/json
app.use(bodyParser.json());


//----------------------------------------------------------------------------------------------------------------------------
const workspacesFilePath = path.join(__dirname, 'workspaces.json');

// Helper function to read workspaces from file
const readWorkspaces = () => {
if (!fs.existsSync(workspacesFilePath)) {
fs.writeFileSync(workspacesFilePath, JSON.stringify({ workspaces: [] }));
Expand All @@ -27,12 +24,10 @@ const readWorkspaces = () => {
return JSON.parse(workspacesData).workspaces;
};

// Helper function to write workspaces to file
const writeWorkspaces = (workspaces) => {
fs.writeFileSync(workspacesFilePath, JSON.stringify({ workspaces }, null, 2));
};

// CRUD Endpoints
app.post('/workspaces', (req, res) => {
const workspaces = readWorkspaces();
const newWorkspace = req.body;
Expand All @@ -41,16 +36,15 @@ app.post('/workspaces', (req, res) => {
res.status(201).send(newWorkspace);
});

app.get('/workspaces', (req, res) => {
app.get('/workspaces', (_req, res) => {
const workspaces = readWorkspaces();
console.log(workspaces);
res.send(workspaces);
});

app.put('/workspaces/:id', (req, res) => {
app.put('/workspaces/:name', (req, res) => {
const workspaces = readWorkspaces();
const updatedWorkspace = req.body;
const workspaceIndex = workspaces.findIndex(w => w.id === req.params.id);
const workspaceIndex = workspaces.findIndex(w => w.name === req.params.name);
if (workspaceIndex !== -1) {
workspaces[workspaceIndex] = updatedWorkspace;
writeWorkspaces(workspaces);
Expand All @@ -60,15 +54,13 @@ app.put('/workspaces/:id', (req, res) => {
}
});

app.delete('/workspaces/:id', (req, res) => {
app.delete('/workspaces/:name', (req, res) => {
let workspaces = readWorkspaces();
workspaces = workspaces.filter(w => w.id !== req.params.id);
workspaces = workspaces.filter(w => w.name !== req.params.name);
writeWorkspaces(workspaces);
res.status(204).send();
});


//---------------------------------------------------------------------------------------------------------------------------
function mapToObj(inputMap) {
let obj = {};
inputMap.forEach((value, key) => {
Expand Down
156 changes: 137 additions & 19 deletions src/components/Details/SettingsComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ import {
} from "../../reducers/optionReducer";
import DeleteIcon from "@mui/icons-material/Delete";
import { selectGremlin, setHost, setPort } from "../../reducers/gremlinReducer";
import { addWorkspace, refreshNodeLabels, selectGraph, Workspace } from "../../reducers/graphReducer";
import { refreshNodeLabels, selectGraph } from "../../reducers/graphReducer";
import { applyLayout, getNodePositions, layoutOptions, setNodePositions } from "../../logics/graph";
import { GRAPH_IMPL, WORKSPACE_ENDPOINT } from "../../constants";
import { type } from "os";
Expand All @@ -47,6 +47,13 @@ import { DIALOG_TYPES } from "../../components/ModalDialog/ModalDialogComponent"
import axios from 'axios';


export type Workspace = {
name: string,
impl: string,
layout: Record<string, { x: number, y: number }>
zoom: number,
view: { x: number, y: number }
}

type NodeLabelListProps = {
nodeLabels: Array<any>;
Expand Down Expand Up @@ -141,9 +148,12 @@ export const Settings = () => {
const [workspaces, setWorkspaces] = useState<Workspace[]>([]);
const [loadWorkspace, setLoadWorkspace] = useState(false);
const [saveWorkspace, setSaveWorkspace] = useState(false);
const [deleteWorkspace, setDeleteWorkspace] = useState(false);
const [workspaceToDelete, setWorkspaceToDelete] = useState<string>('');
const [workspaceToLoad, setWorkspaceToLoad] = useState<string>('');
const [workspaceSaveName, setWorkspaceSaveName] = useState<string>('');
const [workspaceSaveNameConflict, setWorkspaceSaveNameConflict] = useState(false);
const [workspaceDeleteConfirm, setWorkspaceDeleteConfirm] = useState(false);

const fetchWorkspaces = async () => {
try {
Expand Down Expand Up @@ -204,7 +214,6 @@ export const Settings = () => {

async function onConfirmLoadWorkspace(event: { preventDefault: () => void; }) {
event.preventDefault();
console.log(workspaces);
let workspace = workspaces.find(workspace => workspace.name === workspaceToLoad)
setNodePositions(workspace)
onCancelLoadWorkspace()
Expand All @@ -216,8 +225,6 @@ export const Settings = () => {
}

function loadWorkspaceOptions() {
// const workspaces = await axios.get(WORKSPACE_ENDPOINT) as Workspace[];
console.log(workspaces);
const workspaceOptions = workspaces.filter(workspace => workspace.impl === GRAPH_IMPL);
if (workspaceOptions.length > 0) return workspaceOptions.map(workspace => {
return <MenuItem key={workspace.name} value={workspace.name}>{workspace.name}</MenuItem>;
Expand All @@ -237,28 +244,44 @@ export const Settings = () => {
setWorkspaceSaveNameConflict(true)
return;
}
finishSaveWorkspace(null)
finishSaveWorkspace(false, null)
}

function finishSaveWorkspace(event: { preventDefault: () => void; } | null) {
function finishSaveWorkspace(overwrite: boolean, event: { preventDefault: () => void; } | null) {
event?.preventDefault()
let savedWorkspace = {
name: workspaceSaveName,
impl: GRAPH_IMPL,
...getNodePositions()
}
// dispatch(addWorkspace(savedWorkspace))
axios
.post(
WORKSPACE_ENDPOINT,
savedWorkspace
)
.then((_response) => {
fetchWorkspaces();
})
.catch((error) => {
const errorMessage = error.response?.data?.message || error.message
});
if (!overwrite) {
axios
.post(
WORKSPACE_ENDPOINT,
savedWorkspace
)
.then((_response) => {
fetchWorkspaces();
})
.catch((error) => {
const errorMessage = error.response?.data?.message || error.message
console.error(errorMessage);
});
}
else {
axios
.put(
`${WORKSPACE_ENDPOINT}/${workspaceSaveName}`,
savedWorkspace
)
.then((_response) => {
fetchWorkspaces();
})
.catch((error) => {
const errorMessage = error.response?.data?.message || error.message
console.error(errorMessage);
});
}
onCancelSaveWorkspace()
}

Expand All @@ -267,6 +290,36 @@ export const Settings = () => {
setWorkspaceSaveNameConflict(false)
}


function onCancelDeleteWorkspace() {
setDeleteWorkspace(false);
setWorkspaceToDelete('');
setWorkspaceDeleteConfirm(false);
}
function onConfirmDeleteWorkspace(event: { preventDefault: () => void; }) {
event.preventDefault();
setWorkspaceDeleteConfirm(true);
}


function onDeleteWorkspace(event: { target: { value: React.SetStateAction<string>; }; }) {
setWorkspaceToDelete(event.target.value);
}
function finishDeleteWorkspace(event: { preventDefault: () => void; } | null) {
event?.preventDefault()
axios
.delete(
`${WORKSPACE_ENDPOINT}/${workspaceToDelete}`
)
.then((_response) => {
fetchWorkspaces();
})
.catch((error) => {
const errorMessage = error.response?.data?.message || error.message;
console.error(errorMessage);
});
onCancelDeleteWorkspace()
}
return (
<Grid container spacing={2}>
<Grid item xs={12} sm={12} md={12}>
Expand Down Expand Up @@ -354,6 +407,14 @@ export const Settings = () => {
Load Workspace
</Button>
</Grid>
<Grid item xs={12} sm={12} md={12}>
<Button
variant='contained'
onClick={() => setDeleteWorkspace(true)}
style={{ width: 'calc(50% - 10px)', margin: '5px' }}>
Delete Workspace
</Button>
</Grid>
<Grid item xs={12} sm={12} md={12}>
<Divider />
</Grid>
Expand Down Expand Up @@ -452,7 +513,7 @@ export const Settings = () => {
onClose={() => setWorkspaceSaveNameConflict(false)}
PaperProps={{
component: 'form',
onSubmit: finishSaveWorkspace,
onSubmit: (event: any) => finishSaveWorkspace(true, event),
}}
>
<DialogTitle>Workspace Name Conflict</DialogTitle>
Expand All @@ -465,6 +526,63 @@ export const Settings = () => {
<Button type='submit' variant='contained'>Yes</Button>
</DialogActions>
</Dialog>



<Dialog
id='deleteWorkspaceDialog'
open={deleteWorkspace}
onClose={onCancelDeleteWorkspace}
PaperProps={{
component: 'form',
onSubmit: onConfirmDeleteWorkspace,
}}
>
<DialogTitle>Delete Workspace</DialogTitle>
<DialogContent>
<Grid container>
<Grid item>
<TextField
select
required
id="workspaceSelect"
label="Workspace"
margin="dense"
variant="standard"
value={workspaceToDelete}
style={{ width: '300px' }}
onChange={onDeleteWorkspace}
>
{loadWorkspaceOptions()}
</TextField>
</Grid>
</Grid>
</DialogContent>
<DialogActions>
<Button variant='outlined' onClick={onCancelDeleteWorkspace}>Cancel</Button>
<Button type='submit' variant='contained'>Delete</Button>
</DialogActions>
</Dialog>


<Dialog
id='confirmDeleteWorkspace'
open={workspaceDeleteConfirm}
onClose={() => setWorkspaceDeleteConfirm(false)}
PaperProps={{
component: 'form',
onSubmit: finishDeleteWorkspace,
}}
>
<DialogTitle>Workspace Name Conflict</DialogTitle>
<DialogContent>
<Typography>Are you sure you want to delete "{workspaceToDelete}"?</Typography>
</DialogContent>
<DialogActions>
<Button variant='outlined' onClick={onCancelDeleteWorkspace}>No</Button>
<Button type='submit' variant='contained'>Yes</Button>
</DialogActions>
</Dialog>
</Grid>
)
}
3 changes: 2 additions & 1 deletion src/logics/graphImpl/cytoImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import edgehandles from 'cytoscape-edgehandles';
import { EdgeData, getColor, GraphData, GraphOptions, GraphTypes, NodeData } from "../utils";
import cola, { ColaLayoutOptions } from "cytoscape-cola";
import store from "../../app/store";
import { setSelectedEdge, setSelectedNode, updateColorMap, Workspace } from "../../reducers/graphReducer";
import { setSelectedEdge, setSelectedNode, updateColorMap } from "../../reducers/graphReducer";
import {Workspace} from "../../components/Details/SettingsComponent";
import { setIsPhysicsEnabled } from "../../reducers/optionReducer";
import getIcon from "../../assets/icons";
import { openEdgeDialog, openNodeDialog } from "../../reducers/dialogReducer";
Expand Down
3 changes: 2 additions & 1 deletion src/logics/graphImpl/sigmaImpl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import FA2Layout from "graphology-layout-forceatlas2/worker";
import Graph from "graphology";
import Sigma from "sigma";
import store from "../../app/store";
import { setSelectedEdge, setSelectedNode, updateColorMap, Workspace } from "../../reducers/graphReducer";
import { setSelectedEdge, setSelectedNode, updateColorMap } from "../../reducers/graphReducer";
import {Workspace} from "../../components/Details/SettingsComponent";
import { getColor, GraphData, GraphOptions, GraphTypes } from "../utils";
import { setIsPhysicsEnabled } from "../../reducers/optionReducer";
import { createNodeImageProgram } from "@sigma/node-image";
Expand Down
3 changes: 2 additions & 1 deletion src/logics/graphImpl/visImpl.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { DataInterfaceEdges, DataInterfaceNodes, Edge, IdType, Network, Node, Options } from "vis-network";
import store from "../../app/store"
import { setSelectedEdge, setSelectedNode, Workspace } from "../../reducers/graphReducer";
import { setSelectedEdge, setSelectedNode } from "../../reducers/graphReducer";
import {Workspace} from "../../components/Details/SettingsComponent";
import { openEdgeDialog, openNodeDialog } from "../../reducers/dialogReducer";
import { EdgeData, GraphData, GraphOptions, GraphTypes, NodeData } from "../utils";
import { setIsPhysicsEnabled } from "../../reducers/optionReducer";
Expand Down
16 changes: 0 additions & 16 deletions src/reducers/graphReducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,21 +4,12 @@ import { RootState } from '../app/store';
import _ from 'lodash';
import { defaultNodeLabel, EdgeData, NodeData } from "../logics/utils";

export type Workspace = {
name: string,
impl: string,
layout: Record<string, { x: number, y: number }>
zoom: number,
view: { x: number, y: number }
}

type GraphState = {
nodes: NodeData[];
edges: EdgeData[];
selectedNode?: NodeData;
selectedEdge?: EdgeData;
nodeColorMap: { [index: string]: string };
workspaces: Workspace[]
};

const initialState: GraphState = {
Expand All @@ -27,7 +18,6 @@ const initialState: GraphState = {
selectedNode: undefined,
selectedEdge: undefined,
nodeColorMap: {},
workspaces: []
};

const slice = createSlice({
Expand Down Expand Up @@ -108,11 +98,6 @@ const slice = createSlice({
},
updateColorMap: (state, action) => {
Object.assign(state.nodeColorMap, action.payload);
},
addWorkspace: (state, action) => {
let workspaceToOverwriteIndex = state.workspaces.findIndex(workspace => workspace.name === action.payload.name)
if (workspaceToOverwriteIndex !== -1) state.workspaces[workspaceToOverwriteIndex] = action.payload
else state.workspaces.push(action.payload)
}
},
});
Expand All @@ -127,7 +112,6 @@ export const {
setSelectedNode,
refreshNodeLabels,
updateColorMap,
addWorkspace
} = slice.actions;

export const selectGraph = (state: RootState) => state.graph;
Expand Down
Loading

0 comments on commit a5452f2

Please sign in to comment.