Implement crude version of all CRUD endpoints
This commit is contained in:
parent
e0e5b81166
commit
66f97f4d84
8
package-lock.json
generated
8
package-lock.json
generated
@ -12649,6 +12649,14 @@
|
||||
"whatwg-fetch": "^3.4.1"
|
||||
}
|
||||
},
|
||||
"react-bootstrap-icons": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/react-bootstrap-icons/-/react-bootstrap-icons-1.5.0.tgz",
|
||||
"integrity": "sha512-QC5q4meHQG0cO9RJzeDLSqZ1gbVa9jxFCpONCE3GYl2FkbAKSyJAEsONlzTApbZ8/oG87gPWq0xAyn5SZ/Jafw==",
|
||||
"requires": {
|
||||
"prop-types": "^15.7.2"
|
||||
}
|
||||
},
|
||||
"react-dev-utils": {
|
||||
"version": "11.0.4",
|
||||
"resolved": "https://registry.npmjs.org/react-dev-utils/-/react-dev-utils-11.0.4.tgz",
|
||||
|
@ -11,6 +11,7 @@
|
||||
"axios": "^0.21.1",
|
||||
"gh-pages": "^3.2.3",
|
||||
"react": "^17.0.2",
|
||||
"react-bootstrap-icons": "^1.5.0",
|
||||
"react-dom": "^16.14.0",
|
||||
"react-router": "^5.2.0",
|
||||
"react-router-dom": "^5.2.0",
|
||||
|
@ -348,3 +348,8 @@ button{
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-shadow: -1px 1px 0 #000,1px 1px 0 #000,1px -1px 0 #000,-1px -1px 0 #000;
|
||||
}
|
||||
|
||||
.w-25{
|
||||
min-width:25%;
|
||||
width:25%;
|
||||
}
|
65
src/App.js
65
src/App.js
@ -1,10 +1,12 @@
|
||||
//import './App.css'; Old CSS
|
||||
import './reset.css'; // Generic reset
|
||||
import './style.css'; // The new new
|
||||
import React, {useState,useEffect,useRef} from 'react';
|
||||
import React, {useState,useEffect,useRef,useReducer} from 'react';
|
||||
import ReactWindow from 'reactjs-windows'
|
||||
import 'reactjs-windows/dist/index.css'
|
||||
|
||||
import {XSquareFill} from 'react-bootstrap-icons'
|
||||
|
||||
import {
|
||||
BrowserRouter as Router,
|
||||
Switch,
|
||||
@ -390,18 +392,26 @@ function EditableBackendBox(p) {
|
||||
const [update,setUpdate] = useState(false)
|
||||
const [edit,setEdit] = useState(false)
|
||||
const [value,setValue] = useState(p.children)
|
||||
const [originalValue,setOriginalValue] = useState(p.children)
|
||||
|
||||
useEffect(()=>{
|
||||
if (p.callback&&update) {
|
||||
p.callback(value)
|
||||
.then(()=>{
|
||||
setUpdate(false)
|
||||
setOriginalValue(value)
|
||||
})
|
||||
.catch(()=>{
|
||||
setUpdate(false)
|
||||
setValue(originalValue)
|
||||
})
|
||||
}
|
||||
},[update])
|
||||
|
||||
return <>
|
||||
<div className="hover" onClick={(f)=>{setEdit(true)}}>
|
||||
<div className="hover table-padding" onClick={(f)=>{setEdit(true)}}>
|
||||
{edit?
|
||||
<EditBackendBox maxlength={p.maxlength} setUpdate={setUpdate} setEdit={setEdit} originalName={value} setName={setValue} value={value}/>
|
||||
<EditBackendBox maxlength={p.maxlength} setUpdate={setUpdate} setEdit={setEdit} originalName={originalValue} setName={setValue} value={value}/>
|
||||
:<>{value}</>}
|
||||
</div>
|
||||
</>
|
||||
@ -409,10 +419,22 @@ function EditableBackendBox(p) {
|
||||
|
||||
function TableEditor(p) {
|
||||
|
||||
const initialVals={}
|
||||
|
||||
function updateVals(state,update) {
|
||||
if (update==='Clear') {
|
||||
return initialVals
|
||||
}
|
||||
state[update.field]=update.value
|
||||
return state
|
||||
}
|
||||
|
||||
const [fields,setFields] = useState([])
|
||||
const [data,setData] = useState([])
|
||||
const [update,setUpdate] = useState(false)
|
||||
const [submitVals,setSubmitVal] = useReducer(updateVals,initialVals)
|
||||
|
||||
useEffect(()=>{
|
||||
function updateData() {
|
||||
axios.get(BACKEND_URL+p.path)
|
||||
.then((data)=>{
|
||||
var cols = data.data.fields
|
||||
@ -421,19 +443,48 @@ function TableEditor(p) {
|
||||
setFields(cols.filter((col)=>col.name!=="id").map((col)=>col.name))
|
||||
setData(rows)
|
||||
})
|
||||
}
|
||||
|
||||
function SubmitBoxes() {
|
||||
axios.post(BACKEND_URL+p.path,submitVals)
|
||||
.then(()=>{
|
||||
setUpdate(true)
|
||||
})
|
||||
.catch((err)=>{
|
||||
alert(JSON.stringify(err.response.data))
|
||||
})
|
||||
}
|
||||
|
||||
useEffect(()=>{
|
||||
updateData()
|
||||
},[p.path])
|
||||
|
||||
useEffect(()=>{
|
||||
if (update) {
|
||||
updateData()
|
||||
setUpdate(false)
|
||||
}
|
||||
},[update])
|
||||
|
||||
return <>
|
||||
<div className="table-responsive">
|
||||
<table className="table text-light">
|
||||
<table cellPadding="10" className="table text-light table-padding">
|
||||
<caption>List of users</caption>
|
||||
<thead>
|
||||
<tr>
|
||||
{fields.map((field,i)=><React.Fragment key={i}><th scope="col">{field}</th></React.Fragment>)}
|
||||
<th className="table-padding"></th>
|
||||
{fields.map((field,i)=><React.Fragment key={i}><th scope="col" className="table-padding">{field}</th></React.Fragment>)}
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{data.map((dat,i)=><tr key={i}>{fields.map((col,i)=><td key={i}><EditableBackendBox callback={(value)=>{console.log(value)}}>{String(dat[col])}</EditableBackendBox></td>)}</tr>)}
|
||||
{data.map((dat)=><tr key={dat.id}>
|
||||
<td><XSquareFill className="webicon" onClick={()=>{axios.delete(BACKEND_URL+p.path,{data:{id:dat.id}}).then(()=>{setUpdate(true)}).catch((err)=>{alert(err.response.data)})}}/></td>{fields.map((col,i)=><td key={dat.id+"_"+i} className="table-padding table"><EditableBackendBox callback={(value)=>{
|
||||
return axios.patch(BACKEND_URL+p.path,{
|
||||
[col]:value,
|
||||
id:dat.id
|
||||
})
|
||||
}}>{String(dat[col])}</EditableBackendBox></td>)}</tr>)}
|
||||
{<tr><td></td>{fields.map((col,i)=><td key={i}>{<input id={"submitField"+i} onBlur={(i==fields.length-1)?(f)=>{setSubmitVal({field:col,value:f.currentTarget.value});SubmitBoxes();document.getElementById("submitField0").focus()}:(f)=>{setSubmitVal({field:col,value:f.currentTarget.value})}}/>}</td>)}</tr>}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -857,3 +857,31 @@ button{
|
||||
-webkit-font-smoothing: antialiased;
|
||||
text-shadow: -1px 1px 0 #000,1px 1px 0 #000,1px -1px 0 #000,-1px -1px 0 #000;
|
||||
}
|
||||
.w-25{
|
||||
min-width:240px;
|
||||
max-width:24%;
|
||||
}
|
||||
.w-75{
|
||||
min-width:75%;
|
||||
max-width:75%;
|
||||
}
|
||||
.table-responsive{;
|
||||
color:rgba(220,220,220);
|
||||
overflow-y:hidden;
|
||||
overflow-x:scroll;
|
||||
}
|
||||
.table{
|
||||
border: 1px solid black;
|
||||
border-spacing:1px;
|
||||
}
|
||||
.table-padding{
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
.webicon{
|
||||
color:maroon;
|
||||
}
|
||||
.webicon:hover{
|
||||
color:rgba(200,0,0,1);
|
||||
cursor:pointer;
|
||||
}
|
3
src/web-icons/x.svg
Normal file
3
src/web-icons/x.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x" viewBox="0 0 16 16">
|
||||
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 332 B |
3
src/x.svg
Normal file
3
src/x.svg
Normal file
@ -0,0 +1,3 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-x" viewBox="0 0 16 16">
|
||||
<path d="M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 332 B |
Loading…
x
Reference in New Issue
Block a user