Merge pull request #52 from Fisker-Inc/delete-button

CEC-256 Added delete button to deploy packages page
This commit is contained in:
John Cotten Watson
2021-06-09 16:38:42 -07:00
committed by GitHub
8 changed files with 2294 additions and 2602 deletions

View File

@@ -30,14 +30,14 @@ describe("App", () => {
beforeAll(() => { beforeAll(() => {
// Stablize Table Pagination control ids // Stablize Table Pagination control ids
expect.addSnapshotSerializer({ expect.addSnapshotSerializer({
test: function(val) { test: function (val) {
return val && typeof val === "string" && val.indexOf("mui-") >= 0; return val && typeof val === "string" && val.indexOf("mui-") >= 0;
}, },
print: function(val) { print: function (val) {
let str = val; let str = val;
str = str.replace(/mui-[0-9]*/g, "mui-00000"); str = str.replace(/mui-[0-9]*/g, "mui-00000");
return `"${str}"`; return `"${str}"`;
} }
}); });
}); });
@@ -67,10 +67,6 @@ describe("App", () => {
await check("/updates", "span.MuiButton-label", "Sign In"); await check("/updates", "span.MuiButton-label", "Sign In");
}); });
it("Route /update unauthenticated", async () => {
await check("/update/1", "span.MuiButton-label", "Sign In");
});
it("Route /carupdate-deploy unauthenticated", async () => { it("Route /carupdate-deploy unauthenticated", async () => {
await check("/carupdate-deploy/1", "span.MuiButton-label", "Sign In"); await check("/carupdate-deploy/1", "span.MuiButton-label", "Sign In");
}); });
@@ -120,17 +116,12 @@ describe("App", () => {
await check("/updates", "h6", "Deploy Packages"); await check("/updates", "h6", "Deploy Packages");
}); });
it("Route /update authenticated", async () => {
setToken(TEST_AUTH_OBJECT);
await check("/update/1", "h6", "Edit Update Package 1");
});
it("Route /carupdate-status authenticated", async () => { it("Route /carupdate-status authenticated", async () => {
setToken(TEST_AUTH_OBJECT); setToken(TEST_AUTH_OBJECT);
await check("/carupdate-status/1", "h6", ""); await check("/carupdate-status/1", "h6", "Package Package 1.0");
}); });
it("Route /vehicles authenticated", async () => { it("Route /vehicles authenticated", async () => {
setToken(TEST_AUTH_OBJECT); setToken(TEST_AUTH_OBJECT);
await check("/vehicles", "h6", "Vehicles"); await check("/vehicles", "h6", "Vehicles");
}); });
@@ -156,7 +147,7 @@ describe("App", () => {
it("Route /carupdate-deploy authenticated", async () => { it("Route /carupdate-deploy authenticated", async () => {
setToken(TEST_AUTH_OBJECT); setToken(TEST_AUTH_OBJECT);
await check("/carupdate-deploy/1", "h6", "Deploy "); await check("/carupdate-deploy/1", "h6", "Deploy Package 1.0");
}); });
it("Route /dashboard authenticated", async () => { it("Route /dashboard authenticated", async () => {

File diff suppressed because it is too large Load Diff

View File

@@ -5,7 +5,7 @@ import { StatusProvider } from "../Contexts/StatusContext";
import { CssBaseline } from "@material-ui/core"; import { CssBaseline } from "@material-ui/core";
import MenuDrawer from "../Layouts/MenuDrawer"; import MenuDrawer from "../Layouts/MenuDrawer";
import SiteRoutes from "../Routes/SiteRoutes"; import SiteRoutes from "../Routes/SiteRoutes";
import {} from "../../services/monitoring"; import { } from "../../services/monitoring";
function App() { function App() {
return ( return (

View File

@@ -120,6 +120,31 @@ const SendCommand = ({ vins }) => {
))} ))}
</Select> </Select>
</FormControl> </FormControl>
<FormControl className={classes.formControlInline} variant="outlined">
<InputLabel
htmlFor="send-parameter"
style={{ backgroundColor: "White" }}
>
Parameter
</InputLabel>
<Select
native
value={parameter}
variant="outlined"
inputProps={{
name: "send-parameter",
id: "send-parameter",
}}
onChange={changeParametersHandler}
disabled={parameters.length === 0}
>
{parameters.map((item) => (
<option key={item.value} value={item.value}>
{item.label}
</option>
))}
</Select>
</FormControl>
<IconButton <IconButton
color="primary" color="primary"
aria-label="send command" aria-label="send command"

View File

@@ -48,6 +48,26 @@ export const UpdatesProvider = ({ children }) => {
return result; return result;
}; };
const deletePackage = async (package_id, token) => {
let result;
const index = packages.findIndex((element) => {
return element.id === package_id;
});
packages.splice(index, 1);
try {
setBusy(true);
result = await api.deletePackage(package_id, token);
if (result.error)
throw new Error(`Delete package error. ${result.message}`);
} finally {
setBusy(false);
}
return result;
};
const createCarUpdates = async (data, token) => { const createCarUpdates = async (data, token) => {
let result; let result;
@@ -188,6 +208,7 @@ export const UpdatesProvider = ({ children }) => {
totalCarUpdates, totalCarUpdates,
getPackages, getPackages,
updatePackage, updatePackage,
deletePackage,
createCarUpdates, createCarUpdates,
getCarUpdates, getCarUpdates,
getVINUpdates, getVINUpdates,

View File

@@ -4,6 +4,15 @@ const UpdatesContext = React.createContext();
let busy = false; let busy = false;
let packages = []; let packages = [];
const examplePackage = {
id: 0,
package_name: "Package",
version: "1.0",
desc: "Description",
release_notes: "https://www.google.com/",
created: Date.now().toString(),
};
packages.push(examplePackage)
let totalPackages = 0; let totalPackages = 0;
let carUpdates = []; let carUpdates = [];
let totalCarUpdates = 0; let totalCarUpdates = 0;

View File

@@ -12,6 +12,7 @@ import {
} from "@material-ui/core"; } from "@material-ui/core";
import SendIcon from "@material-ui/icons/Send"; import SendIcon from "@material-ui/icons/Send";
import VisibilityIcon from "@material-ui/icons/Visibility"; import VisibilityIcon from "@material-ui/icons/Visibility";
import DeleteIcon from "@material-ui/icons/Delete";
import useStyles from "../../useStyles"; import useStyles from "../../useStyles";
import { import {
UpdatesProvider, UpdatesProvider,
@@ -54,14 +55,15 @@ const UpdatePackagesList = () => {
const [orderBy, setOrderBy] = useState("id"); const [orderBy, setOrderBy] = useState("id");
const [order, setOrder] = useState("desc"); const [order, setOrder] = useState("desc");
const [search, setSearch] = useState(""); const [search, setSearch] = useState("");
const { getPackages, packages, totalPackages } = useUpdatesContext(); const { getPackages, deletePackage, packages, totalPackages } =
useUpdatesContext();
const { const {
token: { token: {
idToken: { jwtToken: token }, idToken: { jwtToken: token },
}, },
groups, groups,
} = useUserContext(); } = useUserContext();
const { setTitle } = useStatusContext(); const { setMessage, setTitle } = useStatusContext();
useEffect(() => { useEffect(() => {
setTitle("Deploy Packages"); setTitle("Deploy Packages");
@@ -107,6 +109,14 @@ const UpdatePackagesList = () => {
setSearch(search); setSearch(search);
}; };
const onDelete = async (package_id) => {
try {
await deletePackage(parseInt(package_id), token);
} catch (e) {
setMessage(e.message);
}
};
const Actions = (row) => { const Actions = (row) => {
let actions = []; let actions = [];
if (hasRole([Roles.CREATE, Roles.READ], groups)) { if (hasRole([Roles.CREATE, Roles.READ], groups)) {
@@ -131,18 +141,39 @@ const UpdatePackagesList = () => {
/> />
), ),
}, },
{
tip: `Delete "${row.package_name} ${row.version}"`,
id: row.id,
icon: (
<DeleteIcon
aria-label={`Delete ${row.package_name} ${row.version}`}
/>
),
},
]); ]);
} }
if (actions.length === 0) return "No actions"; if (actions.length === 0) return "No actions";
return actions.map((action) => ( return actions.map((action) => {
<Tooltip key={action.link} title={action.tip}> if (action.link != null) {
<Link to={action.link} style={{ margin: 5 }}> return (
{action.icon} <Tooltip key={action.link} title={action.tip}>
</Link> <Link to={action.link} style={{ margin: 5 }}>
</Tooltip> {action.icon}
)); </Link>
</Tooltip>
);
} else {
return (
<Tooltip key={`delete-${action.id}`} title={action.tip}>
<Link to="#" onClick={() => onDelete(action.id)}>
{action.icon}
</Link>
</Tooltip>
);
}
});
}; };
return ( return (

View File

@@ -9,13 +9,19 @@ const updatesAPI = {
body: JSON.stringify(data), body: JSON.stringify(data),
}) })
.then(fetchRespHandler), .then(fetchRespHandler),
deletePackage: async (package_id, token) => fetch(`${API_ENDPOINT}/update?id=${package_id}`, {
method: "DELETE",
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
})
.then(fetchRespHandler),
getPackages: async (search, token) => { getPackages: async (search, token) => {
var u = addQueryParams(`${API_ENDPOINT}/updates`, search); var u = addQueryParams(`${API_ENDPOINT}/updates`, search);
return fetch(u, { return fetch(u, {
method: "GET", method: "GET",
headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)), headers: Object.assign({ "Content-Type": "application/json" }, getAuthHeaderOptions(token)),
}) })
.then(fetchRespHandler); .then(fetchRespHandler);
}, },
@@ -36,7 +42,7 @@ const updatesAPI = {
}) })
.then(fetchRespHandler); .then(fetchRespHandler);
}, },
getVINUpdates: async (vin, token) => { getVINUpdates: async (vin, token) => {
var u = addQueryParams(`${API_ENDPOINT}/carupdates`, { vin }); var u = addQueryParams(`${API_ENDPOINT}/carupdates`, { vin });
return fetch(u, { return fetch(u, {