Update UI page manage value
This commit is contained in:
parent
d5454ac29d
commit
c73cf2d40e
|
|
@ -98,8 +98,11 @@ const ListLog = () => {
|
||||||
placeholder="Search file..."
|
placeholder="Search file..."
|
||||||
value={nameSearch}
|
value={nameSearch}
|
||||||
onChange={(e) => setNameSearch(e.target.value)}
|
onChange={(e) => setNameSearch(e.target.value)}
|
||||||
|
onKeyDown={(key) => {
|
||||||
|
if (key.keyCode === 13 || key.key === "Enter") getListFile(1)
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
<button className="btn success" onClick={() => getListFile(page)}>
|
<button className="btn success" onClick={() => getListFile(1)}>
|
||||||
Search
|
Search
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,147 @@
|
||||||
|
body {
|
||||||
|
background: #f4f6f9;
|
||||||
|
font-family: "Segoe UI", sans-serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.manageContainer {
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
padding: 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.card {
|
||||||
|
width: 90%;
|
||||||
|
max-width: 1200px;
|
||||||
|
background: white;
|
||||||
|
border-radius: 12px;
|
||||||
|
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
|
||||||
|
padding: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cardHeader {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tableWrapper {
|
||||||
|
height: 70vh;
|
||||||
|
overflow-y: auto;
|
||||||
|
border: 1px solid #d8d8d8;
|
||||||
|
border-radius: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modernTable {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modernTable thead th {
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
background: #f9fafb;
|
||||||
|
padding: 12px;
|
||||||
|
text-align: left;
|
||||||
|
border-bottom: 1px solid #d8d8d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modernTable tbody td {
|
||||||
|
padding: 10px 12px;
|
||||||
|
border-bottom: 1px solid #d8d8d8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.modernTable tbody tr:hover {
|
||||||
|
background: #f9fafb;
|
||||||
|
}
|
||||||
|
|
||||||
|
.keyCell {
|
||||||
|
font-weight: 600;
|
||||||
|
color: #1f2937;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input {
|
||||||
|
width: 100%;
|
||||||
|
padding: 6px 10px;
|
||||||
|
border-radius: 6px;
|
||||||
|
border: 1px solid #d1d5db;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.input:focus {
|
||||||
|
border-color: #2563eb;
|
||||||
|
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.actionGroup {
|
||||||
|
display: flex;
|
||||||
|
gap: 8px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn {
|
||||||
|
padding: 6px 12px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: 0.2s;
|
||||||
|
width: 70px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.primary {
|
||||||
|
background: #2563eb;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.success {
|
||||||
|
background: #16a34a;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.warning {
|
||||||
|
background: #f59e0b;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn.danger {
|
||||||
|
background: #dc2626;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn:hover {
|
||||||
|
opacity: 0.9;
|
||||||
|
}
|
||||||
|
|
||||||
|
.addSection {
|
||||||
|
margin-top: 20px;
|
||||||
|
display: flex;
|
||||||
|
gap: 10px;
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.isDisabled {
|
||||||
|
pointer-events: none;
|
||||||
|
opacity: 0.7;
|
||||||
|
-moz-user-focus: none;
|
||||||
|
-webkit-user-focus: none;
|
||||||
|
-ms-user-focus: none;
|
||||||
|
-moz-user-modify: read-only;
|
||||||
|
-webkit-user-modify: read-only;
|
||||||
|
-ms-user-modify: read-only;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btnLogs {
|
||||||
|
padding: 6px 12px;
|
||||||
|
border: none;
|
||||||
|
border-radius: 6px;
|
||||||
|
cursor: pointer;
|
||||||
|
font-weight: 500;
|
||||||
|
transition: 0.2s;
|
||||||
|
background: #2563eb;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
@ -1,214 +1,175 @@
|
||||||
import axios from "axios";
|
import axios from "axios";
|
||||||
import React, { useEffect, useState } from "react";
|
import React, { useEffect, useState } from "react";
|
||||||
import { addKeyValue, deleteValue, editValue, getKeyValues } from "../api/apiLog";
|
import {
|
||||||
|
addKeyValue,
|
||||||
|
deleteValue,
|
||||||
|
editValue,
|
||||||
|
getKeyValues,
|
||||||
|
} from "../api/apiLog";
|
||||||
import { Link } from "react-router-dom";
|
import { Link } from "react-router-dom";
|
||||||
|
import "./ManageValues.css";
|
||||||
|
|
||||||
const ManageValues = () => {
|
const ManageValues = () => {
|
||||||
const [keyValue, setKeyValue] = useState([]);
|
const [keyValue, setKeyValue] = useState([]);
|
||||||
const [key, setKey] = useState([]);
|
const [key, setKey] = useState([]);
|
||||||
const [addValue, setAddValue] = useState({ key: "CATCH_FAULTY", value: "" });
|
const [addValue, setAddValue] = useState({
|
||||||
const [inputSelect, setInpuSelect] = useState(0)
|
key: "CATCH_FAULTY",
|
||||||
const [inputValue, setInputValue] = useState("")
|
value: "",
|
||||||
|
});
|
||||||
|
const [editingId, setEditingId] = useState(null);
|
||||||
|
const [inputValue, setInputValue] = useState("");
|
||||||
|
const [isDisabled, setIsDisabled] = useState(false);
|
||||||
|
|
||||||
const getValues = async () => {
|
const getValues = async () => {
|
||||||
try {
|
const res = await axios.post(getKeyValues);
|
||||||
const res = await axios.post(getKeyValues);
|
setKeyValue(res.data.sort((a, b) => a.key.localeCompare(b.key)));
|
||||||
setKeyValue(res.data.sort((a, b) => a.key.localeCompare(b.key)));
|
setKey(res.data?.map((obj) => obj.key));
|
||||||
setKey(res.data?.map((obj) => obj.key));
|
|
||||||
} catch (error) {
|
|
||||||
console.log(error);
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getValues();
|
getValues();
|
||||||
}, []);
|
}, []);
|
||||||
console.log(inputValue)
|
|
||||||
return (
|
return (
|
||||||
<div
|
<div className="manageContainer">
|
||||||
style={{
|
<div className="card">
|
||||||
display: "flex",
|
<div className="tableWrapper">
|
||||||
alignItems: "center",
|
<table className="modernTable">
|
||||||
flexFlow: "column",
|
<thead>
|
||||||
}}
|
<tr>
|
||||||
>
|
<th>Key</th>
|
||||||
<div style={{ height: "80vh", overflow: "auto" }}>
|
<th>Value</th>
|
||||||
<table>
|
<th style={{ width: "200px" }}>Actions</th>
|
||||||
<thead style={{ width: "100%" }}>
|
|
||||||
<tr>
|
|
||||||
<th
|
|
||||||
style={{ position: "sticky", top: 0, backgroundColor: "white" }}
|
|
||||||
>
|
|
||||||
Key
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
style={{
|
|
||||||
position: "sticky",
|
|
||||||
top: 0,
|
|
||||||
backgroundColor: "white",
|
|
||||||
width: "400px",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Value
|
|
||||||
</th>
|
|
||||||
<th
|
|
||||||
style={{ position: "sticky", top: 0, backgroundColor: "white" }}
|
|
||||||
>
|
|
||||||
Option
|
|
||||||
</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{keyValue?.map((value) => (
|
|
||||||
<tr
|
|
||||||
style={{
|
|
||||||
backgroundColor:
|
|
||||||
value.key === "MODEL_SPECIAL"
|
|
||||||
? "rgb(219 219 255 / 47%)"
|
|
||||||
: value.key === "CATCH_FAULTY"
|
|
||||||
? "rgb(166 255 165 / 43%)"
|
|
||||||
: value.key === "MEMORY_DEFAULT"
|
|
||||||
? "rgb(253 244 52 / 41%)"
|
|
||||||
: "rgb(253 189 152 / 41%)",
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<td>{value.key}</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<input
|
|
||||||
value={inputSelect===value.id_key?inputValue:value.value}
|
|
||||||
disabled={inputSelect===value.id_key?false:true}
|
|
||||||
style={{ width: "100%" }}
|
|
||||||
onChange={(e)=>{
|
|
||||||
setInputValue(e.target.value)
|
|
||||||
|
|
||||||
}}
|
|
||||||
></input>
|
|
||||||
</td>
|
|
||||||
|
|
||||||
<td>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
cursor: "pointer",
|
|
||||||
backgroundColor: "red",
|
|
||||||
color: "white",
|
|
||||||
}}
|
|
||||||
onClick={async () => {
|
|
||||||
const res = await axios.post(deleteValue, {
|
|
||||||
id: value.id_key,
|
|
||||||
});
|
|
||||||
if (res.status !== 200) {
|
|
||||||
alert(res.data);
|
|
||||||
} else {
|
|
||||||
getValues();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Delete
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
cursor: "pointer",
|
|
||||||
backgroundColor: "yellow",
|
|
||||||
color: "black",
|
|
||||||
display:inputSelect===value.id_key?"none":"inline"
|
|
||||||
}}
|
|
||||||
onClick={async () => {
|
|
||||||
setInpuSelect(value.id_key)
|
|
||||||
setInputValue(value.value)
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Edit
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
style={{
|
|
||||||
cursor: "pointer",
|
|
||||||
backgroundColor: "green",
|
|
||||||
color: "white",
|
|
||||||
display:inputSelect===value.id_key?"inline":"none"
|
|
||||||
}}
|
|
||||||
onClick={async () => {
|
|
||||||
setInpuSelect(0)
|
|
||||||
const res = await axios.post(editValue, {
|
|
||||||
id: value.id_key,
|
|
||||||
value: inputValue
|
|
||||||
});
|
|
||||||
if (res.status !== 200) {
|
|
||||||
alert(res.data);
|
|
||||||
} else {
|
|
||||||
getValues();
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
Done
|
|
||||||
</button>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
))}
|
</thead>
|
||||||
</tbody>
|
<tbody>
|
||||||
</table>
|
{keyValue.map((item) => (
|
||||||
</div>
|
<tr style={{ backgroundColor: item.key === "MODEL_SPECIAL" ? "rgb(219 219 255 / 47%)" : item.key === "CATCH_FAULTY" ? "rgb(166 255 165 / 43%)" : item.key === "MEMORY_DEFAULT" ? "rgb(253 244 52 / 41%)" : "rgb(253 189 152 / 41%)", }} key={item.id_key}>
|
||||||
<div style={{ width: "50%", display: "flex", margin: 10 }}>
|
<td className="keyCell">{item.key}</td>
|
||||||
<select
|
|
||||||
style={{ width: "35%" }}
|
<td>
|
||||||
onChange={(e) => {
|
<input
|
||||||
setAddValue({ ...addValue, key: e.target.value });
|
className="input"
|
||||||
}}
|
value={
|
||||||
>
|
editingId === item.id_key
|
||||||
{key
|
? inputValue
|
||||||
.filter((value, index, self) => {
|
: item.value
|
||||||
return self.indexOf(value) === index;
|
}
|
||||||
})
|
disabled={editingId !== item.id_key}
|
||||||
?.map((u) => (
|
onChange={(e) =>
|
||||||
<option value={u}>{u}</option>
|
setInputValue(e.target.value)
|
||||||
))}
|
}
|
||||||
</select>
|
/>
|
||||||
<input
|
</td>
|
||||||
placeholder="value"
|
|
||||||
style={{ margin: "0 5px", width: "50%" }}
|
<td>
|
||||||
onChange={(e) => {
|
<div className="actionGroup">
|
||||||
setAddValue({ ...addValue, value: e.target.value });
|
{editingId !== item.id_key ? (
|
||||||
}}
|
<>
|
||||||
></input>
|
<button
|
||||||
<button
|
className={`btn warning ${isDisabled ? "isDisabled" : ""}`}
|
||||||
style={{
|
onClick={() => {
|
||||||
cursor: "pointer",
|
setEditingId(item.id_key);
|
||||||
backgroundColor: "green",
|
setInputValue(item.value);
|
||||||
color: "white",
|
}}
|
||||||
}}
|
>
|
||||||
onClick={async () => {
|
Edit
|
||||||
if (addValue.key !== "" && addValue.value !== "") {
|
</button>
|
||||||
const res = await axios.post(addKeyValue, {
|
|
||||||
key: addValue.key,
|
<button
|
||||||
value: addValue.value,
|
className={`btn danger ${isDisabled ? "isDisabled" : ""}`}
|
||||||
});
|
onClick={async () => {
|
||||||
if (res.status !== 200) {
|
setIsDisabled(true)
|
||||||
alert(res.data);
|
await axios.post(deleteValue, {
|
||||||
} else {
|
id: item.id_key,
|
||||||
getValues();
|
});
|
||||||
}
|
setIsDisabled(false)
|
||||||
} else {
|
getValues();
|
||||||
alert("Value is empty!");
|
}}
|
||||||
|
>
|
||||||
|
Delete
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
) : (
|
||||||
|
<>
|
||||||
|
<button
|
||||||
|
className={`btn success ${isDisabled ? "isDisabled" : ""}`}
|
||||||
|
onClick={async () => {
|
||||||
|
setEditingId(null);
|
||||||
|
setIsDisabled(true)
|
||||||
|
await axios.post(editValue, {
|
||||||
|
id: item.id_key,
|
||||||
|
value: inputValue,
|
||||||
|
});
|
||||||
|
setIsDisabled(false)
|
||||||
|
getValues();
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Save
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
className="btn"
|
||||||
|
onClick={() => {
|
||||||
|
setEditingId(null);
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Cancel
|
||||||
|
</button>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{/* Add new value */}
|
||||||
|
<div className="addSection">
|
||||||
|
<select
|
||||||
|
className="input"
|
||||||
|
onChange={(e) =>
|
||||||
|
setAddValue({ ...addValue, key: e.target.value })
|
||||||
}
|
}
|
||||||
}}
|
>
|
||||||
>
|
{[...new Set(key)].map((k) => (
|
||||||
Add
|
<option key={k}>{k}</option>
|
||||||
</button>
|
))}
|
||||||
</div>
|
</select>
|
||||||
<div>
|
|
||||||
<Link to={"/logs"}>
|
<input
|
||||||
{" "}
|
value={addValue.value || ""}
|
||||||
|
className="input"
|
||||||
|
placeholder="Enter value..."
|
||||||
|
onChange={(e) =>
|
||||||
|
setAddValue({ ...addValue, value: e.target.value })
|
||||||
|
}
|
||||||
|
/>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
style={{
|
className={`btn success ${isDisabled ? "isDisabled" : ""}`}
|
||||||
color: "white",
|
onClick={async () => {
|
||||||
backgroundColor: "blue",
|
if (!addValue.value) return alert("Value is empty");
|
||||||
cursor: "pointer",
|
setAddValue({ ...addValue, value: "" });
|
||||||
|
setIsDisabled(true)
|
||||||
|
await axios.post(addKeyValue, addValue);
|
||||||
|
setIsDisabled(false)
|
||||||
|
getValues();
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
List of detected files
|
Add
|
||||||
</button>
|
</button>
|
||||||
</Link>
|
</div>
|
||||||
|
|
||||||
|
<div className="addSection">
|
||||||
|
<Link to="/logs">
|
||||||
|
<button className="btnLogs">List of detected files</button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
export default ManageValues;
|
export default ManageValues;
|
||||||
Loading…
Reference in New Issue