Skip to content

Commit

Permalink
feat: Add CRUD features for entries and root nodes (#41)
Browse files Browse the repository at this point in the history
* Initial commit: Front page + list of entries

* Removed duplicate file

* Change import

* Changed buttons and image types

* View parents and children in frontend

* Added navbar + parents/children + Main language synonyms

* Added all translations and properties

* Fix stopwords/synonyms page + add preceding_lines

* Change favicons and manifest

* Add requested changes

* Add requested changes (part 2)

* Added submit button + update functionality

* Add requested changes (part 3)

* Change variable obj to value

* Remove console.log

* Changed div to Mui Box

* Changes regarding variable nodeObject

* Restructure AccumulateAllComponents.jsx and index.jsx

* Change text css

* Add/Delete Properties WIP

* Properties CRUD WIP2

* Properties Table Edit WIP

* Remove WIP Properties table implementation

* Add comment

* Add helper comments

* Added CRUD for properties of an entry

* Add useEffect

* Implement CRUD for translations + Refactor previous code

* Added CRUD for synonyms, stopwords

* Previous PR changes WIP

* Add a translation button

* Added functionality to add translation language

* Added deletion of a translation language

* Add paths for updating children and add in frontend

* Update children query changed

* Added update in backend

* Add node functionality completed

* Completed delete root node functionality

* Rename files and add previous PR changes

* Change variable names + Remove backend changes

* Add requested changes + fixes

* Remove state from originalNodeObject

* Change then/catch position

* Change dialog to snackbar

* Add requested changes

* Remove whitespaces

* Add newline

* Add requested changes WIP

* Change variable type

* Add keyCode

* Change to e.KeyCode

* Change typo

* Remove original nodeObject

* Add early return and comments
  • Loading branch information
aadarsh-ram authored Oct 5, 2022
1 parent 59670be commit 038a1a6
Show file tree
Hide file tree
Showing 12 changed files with 1,078 additions and 288 deletions.
2 changes: 0 additions & 2 deletions backend/editor/entries.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,8 @@ def delete_node(label, entry):
// Find node to be deleted using node ID
MATCH (deleted_node:{label})-[:is_before]->(next_node) WHERE deleted_node.id = $id
MATCH (previous_node)-[:is_before]->(deleted_node)
// Remove node
DETACH DELETE (deleted_node)
// Rebuild relationships after deletion
CREATE (previous_node)-[:is_before]->(next_node)
"""
Expand Down
6 changes: 5 additions & 1 deletion taxonomy-editor-frontend/src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ import Home from './pages/home';
const theme = createTheme({
typography: {
fontFamily : 'Plus Jakarta Sans',
button: {
fontFamily : 'Roboto, Helvetica, Arial, sans-serif',
color: '#808080'
},
},
});

Expand All @@ -29,4 +33,4 @@ function App() {
);
}

export default App;
export default App;
2 changes: 1 addition & 1 deletion taxonomy-editor-frontend/src/constants.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// FIXME we should find a way that works for production build
export const API_URL = process.env.REACT_APP_API_URL || "http://localhost:80/"
export const API_URL = process.env.REACT_APP_API_URL || "http://localhost:80/"
246 changes: 187 additions & 59 deletions taxonomy-editor-frontend/src/pages/allentries/index.jsx
Original file line number Diff line number Diff line change
@@ -1,83 +1,211 @@
import { Typography, Button, Box } from "@mui/material";
import useFetch from "../../components/useFetch";
import { useNavigate } from "react-router-dom";
import { useState } from "react";
import { API_URL } from "../../constants";
import { Typography, Box, TextField, Stack, Button, IconButton, Paper, FormControl, InputLabel } from "@mui/material";
import Table from '@mui/material/Table';
import TableBody from '@mui/material/TableBody';
import TableCell from '@mui/material/TableCell';
import TableContainer from '@mui/material/TableContainer';
import TableHead from '@mui/material/TableHead';
import TableRow from '@mui/material/TableRow';
import Paper from '@mui/material/Paper';
import EditIcon from '@mui/icons-material/Edit';
import { Link } from "react-router-dom";
import useFetch from "../../components/useFetch";
import { API_URL } from "../../constants";
import AddBoxIcon from '@mui/icons-material/AddBox';
import Dialog from '@mui/material/Dialog';
import DialogActions from '@mui/material/DialogActions';
import DialogContent from '@mui/material/DialogContent';
import DialogContentText from '@mui/material/DialogContentText';
import DialogTitle from '@mui/material/DialogTitle';
import Select from '@mui/material/Select';
import ISO6391 from 'iso-639-1';

const Entry = () => {
const { data: nodes, isPending, isError, isSuccess, errorMessage } = useFetch(API_URL+'nodes');
const url = API_URL+'nodes';
const title = "Test";
if (isError) {
const {data: nodes, isPending, errorMessage} = useFetch(url);
const [nodeType, setNodeType] = useState('entry'); // Used for storing node type
const [newLanguageCode, setNewLanguageCode] = useState(null); // Used for storing new Language Code
const [newNode, setnewNode] = useState(null); // Used for storing canonical tag
const [isValidLC, setisValidLC] = useState(false); // Used for validating a new LC
const [openAddDialog, setOpenAddDialog] = useState(false);
const [openSuccessDialog, setOpenSuccessDialog] = useState(false);
const [btnDisabled, setBtnDisabled] = useState(true);
const navigate = useNavigate();

// Handler function for button clicks
const handleClick = (event, id) => {
event.preventDefault();
navigate('/entry/'+id);
}
// Helper functions for Dialog component
function handleCloseAddDialog() { setOpenAddDialog(false); }
function handleOpenAddDialog() { setOpenAddDialog(true); }
function handleCloseSuccessDialog() { setOpenSuccessDialog(false); }
function handleOpenSuccessDialog() { setOpenSuccessDialog(true); }

function handleAddNode() {
const newNodeID = newLanguageCode + ':' + newNode // Reconstructing node ID
const data = {"id": newNodeID, "main_language": newLanguageCode};
fetch(url, {
method : 'POST',
headers: {"Content-Type" : "application/json"},
body: JSON.stringify(data)
}).then(() => {
handleCloseAddDialog();
nodes.push([{"id" : newNodeID, ...data}]) // Not required after "all nodes" table removal
handleOpenSuccessDialog();
}).catch((errorMessage) => {
console.log(errorMessage);
})
}

if (errorMessage) {
return (
<div className="all-entries">
{isError && <div>{errorMessage}</div>}
</div>
<Box>
<Typography variant='h5'>{errorMessage}</Typography>
</Box>
)
}
if (isPending) {
return (
<div className="all-entries">
{isPending && <div>Loading...</div>}
</div>
<Box>
<Typography variant='h5'>Loading..</Typography>
</Box>
)
}
return (
<div className="all-entries">
<Box className="entry">
<Typography sx={{mb: 1, mt:2, ml: 2}} variant="h4">
List of nodes in {title} Taxonomy:
</Typography>
<Typography variant="h6" sx={{mt: 2, ml: 2, mb: 1}}>
Number of nodes in taxonomy: {nodes.length}
</Typography>
{/* Table for listing all nodes in taxonomy */}
<Box className="entry-preview">
<TableContainer sx={{ml: 2}} component={Paper}>
<Table sx={{ width: 400 }}>
<TableHead>
<TableRow>
<TableCell align="left">
<Typography variant="h6">
Nodes
</Typography>
<Box>
<Typography sx={{mb: 1, mt:2, ml: 2}} variant="h4">
List of nodes in {title} Taxonomy:
</Typography>
<Typography variant="h6" sx={{mt: 2, ml: 2, mb: 1}}>
Number of nodes in taxonomy: {nodes.length}
</Typography>
{/* Table for listing all nodes in taxonomy */}
<TableContainer sx={{ml: 2}} component={Paper}>
<Table sx={{ width: 400 }}>
<TableHead>
<TableRow>
<Stack direction="row" alignItems="center">
<TableCell align="left">
<Typography variant="h6">
Nodes
</Typography>
</TableCell>
<IconButton sx={{ml: 1, color: "#808080"}} onClick={handleOpenAddDialog}>
<AddBoxIcon />
</IconButton>
</Stack>
<TableCell align="left">
<Typography variant="h6">
Action
</Typography>
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{nodes.map((node) => (
<TableRow
key={node[0].id}
>
<TableCell align="left" component="td" scope="row">
<Typography variant="subtitle1">
{node[0].id}
</Typography>
</TableCell>
<TableCell align="left">
<Typography variant="h6">
Action
</Typography>
<TableCell align="left" component="td" scope="row">
<IconButton onClick={event => handleClick(event, node[0].id) } aria-label="edit">
<EditIcon color="primary"/>
</IconButton>
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{nodes.map((node) => (
<TableRow
key={node[0].id}
>
<TableCell align="left" component="td" scope="row">
<Typography variant="subtitle1">
{node[0].id}
</Typography>
</TableCell>
<TableCell align="left" component="td" scope="row">
<Button component={Link} to={`/entry/${node[0].id}`}>
<EditIcon color="primary"/>
</Button>
</TableCell>
</TableRow>
))}
</TableBody>
</Table>
</TableContainer>
</Box>
</Box>
</div>
))}
</TableBody>
</Table>
</TableContainer>
{/* Dialog box for adding nodes */}
<Dialog open={openAddDialog} onClose={handleCloseAddDialog}>
<DialogTitle>Add a node</DialogTitle>
<DialogContent>
<Stack direction="row" alignItems="center" sx={{mt: 1, ml: 2, mr: 2, mb: 2}}>
<Typography>Type of node</Typography>
<FormControl sx={{ml: 6.5}}>
<InputLabel>Type</InputLabel>
<Select
native
label="Type"
value={nodeType}
onChange={(e) => {
setNodeType(e.target.value);
}}
>
{/* TODO: Add support for synonyms and stopwords */}
<option value={'entry'}>Entry</option>
</Select>
</FormControl>
</Stack>
<Stack direction="row" alignItems="center" sx={{m: 2}}>
<Typography>Main Language</Typography>
<TextField
onChange={(e) => {
setNewLanguageCode(e.target.value);
const validateBool = ISO6391.validate(e.target.value);
validateBool ? setisValidLC(true) : setisValidLC(false);
validateBool ? setBtnDisabled(false) : setBtnDisabled(true);
}}
label="Language Code"
error={!isValidLC}
sx={{width : 150, ml: 4.5}}
size="small"
variant="outlined"
/>
</Stack>
{
nodeType === 'entry' &&
<Stack direction="row" alignItems="center" sx={{mt: 2, ml: 2, mr: 2}}>
<Typography>Node ID</Typography>
<TextField
onChange={(e) => {
setnewNode(e.target.value);
}}
label="Node ID"
sx={{width : 150, ml: 11}}
size="small"
variant="outlined"
/>
</Stack>
}
</DialogContent>
<DialogActions>
<Button onClick={handleCloseAddDialog}>Cancel</Button>
<Button
disabled={btnDisabled}
onClick={(e) => {handleAddNode(e)}}>
Add
</Button>
</DialogActions>
</Dialog>
{/* Dialog box for acknowledgement of addition of node */}
<Dialog
open={openSuccessDialog}
aria-labelledby="alert-dialog-title"
aria-describedby="alert-dialog-description"
>
<DialogTitle id="alert-dialog-title">
{"Your edits have been saved!"}
</DialogTitle>
<DialogContent>
<DialogContentText id="alert-dialog-description">
The node {newNode} has been successfully added.
</DialogContentText>
</DialogContent>
<DialogActions>
<Button onClick={handleCloseSuccessDialog} autoFocus>
Continue
</Button>
</DialogActions>
</Dialog>
</Box>
);
}

Expand Down
Loading

0 comments on commit 038a1a6

Please sign in to comment.