Update UI page manage value
This commit is contained in:
parent
d5454ac29d
commit
c73cf2d40e
|
|
@ -98,8 +98,11 @@ const ListLog = () => {
|
|||
placeholder="Search file..."
|
||||
value={nameSearch}
|
||||
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
|
||||
</button>
|
||||
</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 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 "./ManageValues.css";
|
||||
|
||||
const ManageValues = () => {
|
||||
const [keyValue, setKeyValue] = useState([]);
|
||||
const [key, setKey] = useState([]);
|
||||
const [addValue, setAddValue] = useState({ key: "CATCH_FAULTY", value: "" });
|
||||
const [inputSelect, setInpuSelect] = useState(0)
|
||||
const [inputValue, setInputValue] = useState("")
|
||||
const [addValue, setAddValue] = useState({
|
||||
key: "CATCH_FAULTY",
|
||||
value: "",
|
||||
});
|
||||
const [editingId, setEditingId] = useState(null);
|
||||
const [inputValue, setInputValue] = useState("");
|
||||
const [isDisabled, setIsDisabled] = useState(false);
|
||||
|
||||
const getValues = async () => {
|
||||
try {
|
||||
const res = await axios.post(getKeyValues);
|
||||
setKeyValue(res.data.sort((a, b) => a.key.localeCompare(b.key)));
|
||||
setKey(res.data?.map((obj) => obj.key));
|
||||
} catch (error) {
|
||||
console.log(error);
|
||||
}
|
||||
const res = await axios.post(getKeyValues);
|
||||
setKeyValue(res.data.sort((a, b) => a.key.localeCompare(b.key)));
|
||||
setKey(res.data?.map((obj) => obj.key));
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
getValues();
|
||||
}, []);
|
||||
console.log(inputValue)
|
||||
|
||||
return (
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
alignItems: "center",
|
||||
flexFlow: "column",
|
||||
}}
|
||||
>
|
||||
<div style={{ height: "80vh", overflow: "auto" }}>
|
||||
<table>
|
||||
<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>
|
||||
<div className="manageContainer">
|
||||
<div className="card">
|
||||
<div className="tableWrapper">
|
||||
<table className="modernTable">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Key</th>
|
||||
<th>Value</th>
|
||||
<th style={{ width: "200px" }}>Actions</th>
|
||||
</tr>
|
||||
))}
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div style={{ width: "50%", display: "flex", margin: 10 }}>
|
||||
<select
|
||||
style={{ width: "35%" }}
|
||||
onChange={(e) => {
|
||||
setAddValue({ ...addValue, key: e.target.value });
|
||||
}}
|
||||
>
|
||||
{key
|
||||
.filter((value, index, self) => {
|
||||
return self.indexOf(value) === index;
|
||||
})
|
||||
?.map((u) => (
|
||||
<option value={u}>{u}</option>
|
||||
))}
|
||||
</select>
|
||||
<input
|
||||
placeholder="value"
|
||||
style={{ margin: "0 5px", width: "50%" }}
|
||||
onChange={(e) => {
|
||||
setAddValue({ ...addValue, value: e.target.value });
|
||||
}}
|
||||
></input>
|
||||
<button
|
||||
style={{
|
||||
cursor: "pointer",
|
||||
backgroundColor: "green",
|
||||
color: "white",
|
||||
}}
|
||||
onClick={async () => {
|
||||
if (addValue.key !== "" && addValue.value !== "") {
|
||||
const res = await axios.post(addKeyValue, {
|
||||
key: addValue.key,
|
||||
value: addValue.value,
|
||||
});
|
||||
if (res.status !== 200) {
|
||||
alert(res.data);
|
||||
} else {
|
||||
getValues();
|
||||
}
|
||||
} else {
|
||||
alert("Value is empty!");
|
||||
</thead>
|
||||
<tbody>
|
||||
{keyValue.map((item) => (
|
||||
<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}>
|
||||
<td className="keyCell">{item.key}</td>
|
||||
|
||||
<td>
|
||||
<input
|
||||
className="input"
|
||||
value={
|
||||
editingId === item.id_key
|
||||
? inputValue
|
||||
: item.value
|
||||
}
|
||||
disabled={editingId !== item.id_key}
|
||||
onChange={(e) =>
|
||||
setInputValue(e.target.value)
|
||||
}
|
||||
/>
|
||||
</td>
|
||||
|
||||
<td>
|
||||
<div className="actionGroup">
|
||||
{editingId !== item.id_key ? (
|
||||
<>
|
||||
<button
|
||||
className={`btn warning ${isDisabled ? "isDisabled" : ""}`}
|
||||
onClick={() => {
|
||||
setEditingId(item.id_key);
|
||||
setInputValue(item.value);
|
||||
}}
|
||||
>
|
||||
Edit
|
||||
</button>
|
||||
|
||||
<button
|
||||
className={`btn danger ${isDisabled ? "isDisabled" : ""}`}
|
||||
onClick={async () => {
|
||||
setIsDisabled(true)
|
||||
await axios.post(deleteValue, {
|
||||
id: item.id_key,
|
||||
});
|
||||
setIsDisabled(false)
|
||||
getValues();
|
||||
}}
|
||||
>
|
||||
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 })
|
||||
}
|
||||
}}
|
||||
>
|
||||
Add
|
||||
</button>
|
||||
</div>
|
||||
<div>
|
||||
<Link to={"/logs"}>
|
||||
{" "}
|
||||
>
|
||||
{[...new Set(key)].map((k) => (
|
||||
<option key={k}>{k}</option>
|
||||
))}
|
||||
</select>
|
||||
|
||||
<input
|
||||
value={addValue.value || ""}
|
||||
className="input"
|
||||
placeholder="Enter value..."
|
||||
onChange={(e) =>
|
||||
setAddValue({ ...addValue, value: e.target.value })
|
||||
}
|
||||
/>
|
||||
|
||||
<button
|
||||
style={{
|
||||
color: "white",
|
||||
backgroundColor: "blue",
|
||||
cursor: "pointer",
|
||||
className={`btn success ${isDisabled ? "isDisabled" : ""}`}
|
||||
onClick={async () => {
|
||||
if (!addValue.value) return alert("Value is empty");
|
||||
setAddValue({ ...addValue, value: "" });
|
||||
setIsDisabled(true)
|
||||
await axios.post(addKeyValue, addValue);
|
||||
setIsDisabled(false)
|
||||
getValues();
|
||||
}}
|
||||
>
|
||||
List of detected files
|
||||
Add
|
||||
</button>
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
<div className="addSection">
|
||||
<Link to="/logs">
|
||||
<button className="btnLogs">List of detected files</button>
|
||||
</Link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default ManageValues;
|
||||
export default ManageValues;
|
||||
Loading…
Reference in New Issue