Change CSV handling - fixed group delete

This commit is contained in:
Luke Berndt
2023-11-10 07:28:27 -05:00
parent b21f214e74
commit 2647c75733
7 changed files with 109 additions and 100 deletions

View File

@@ -0,0 +1,42 @@
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/docker-existing-docker-compose
{
"name": "Existing Docker Compose (Extend)",
// Update the 'dockerComposeFile' list if you have more compose files or use different names.
// The .devcontainer/docker-compose.yml file contains any overrides you need/want to make.
"dockerComposeFile": [
"../docker-compose.yml",
"../test-compose.yml",
"docker-compose.yml"
],
// The 'service' property is the name of the service for the container that VS Code should
// use. Update this value and .devcontainer/docker-compose.yml to the real service name.
"service": "admin",
// The optional 'workspaceFolder' property is the path VS Code should open by default when
// connected. This is typically a file mount in .devcontainer/docker-compose.yml
"workspaceFolder": "/workspaces/${localWorkspaceFolderBasename}"
// Features to add to the dev container. More info: https://containers.dev/features.
// "features": {},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
// "forwardPorts": [],
// Uncomment the next line if you want start specific services in your Docker Compose config.
// "runServices": [],
// Uncomment the next line if you want to keep your containers running after VS Code shuts down.
// "shutdownAction": "none",
// Uncomment the next line to run commands after the container is created.
// "postCreateCommand": "cat /etc/os-release",
// Configure tool-specific properties.
// "customizations": {},
// Uncomment to connect as an existing user other than the container default. More info: https://aka.ms/dev-containers-non-root.
// "remoteUser": "devcontainer"
}

View File

@@ -0,0 +1,26 @@
version: '3'
services:
# Update this to the name of the service you want to work with in your docker-compose.yml file
admin:
# Uncomment if you want to override the service's Dockerfile to one in the .devcontainer
# folder. Note that the path of the Dockerfile and context is relative to the *primary*
# docker-compose.yml file (the first in the devcontainer.json "dockerComposeFile"
# array). The sample below assumes your primary file is in the root of your project.
#
# build:
# context: .
# dockerfile: .devcontainer/Dockerfile
volumes:
# Update this to wherever you want VS Code to mount the folder of your project
- ..:/workspaces:cached
# Uncomment the next four lines if you will use a ptrace-based debugger like C++, Go, and Rust.
# cap_add:
# - SYS_PTRACE
# security_opt:
# - seccomp:unconfined
# Overrides default command so things don't shut down after the process ends.
command: /bin/sh -c "while sleep 1000; do :; done"

View File

@@ -40,6 +40,7 @@ exports.exportTalkgroups = function (req, res, next) {
}
res.statusCode = 200;
res.setHeader("Content-Type", "text/csv");
res.write("Decimal, Alpha Tag, Description, Priority\r\n");
talkgroups.forEach(function (item) {
/* res.write('"' + item.num + '", "'
+ item.mode + '", "'
@@ -51,12 +52,7 @@ exports.exportTalkgroups = function (req, res, next) {
if (item) {
var sending = "";
sending = item.num + ", ";
if (item.mode) {
sending = sending + item.mode.toString().replace(/\,/g, "") + ", ";
} else {
sending = sending + " ,";
}
if (item.alpa) {
if (item.alpha) {
sending = sending + item.alpha.toString().replace(/\,/g, "") + ", ";
} else {
sending = sending + " ,";
@@ -66,16 +62,6 @@ exports.exportTalkgroups = function (req, res, next) {
} else {
sending = sending + " ,";
}
if (item.tag) {
sending = sending + item.tag.toString().replace(/\,/g, "") + ", ";
} else {
sending = sending + " ,";
}
if (item.group) {
sending = sending + item.group.toString().replace(/\,/g, "") + ", ";
} else {
sending = sending + " ,";
}
if (item.priority) {
sending = sending + item.priority.toString().replace(/\,/g, "") + "\r\n";
} else {
@@ -97,15 +83,7 @@ async function csv_import(shortName, filename, callback) {
var parser = parse(
{
columns: [
"num",
"mode",
"alpha",
"description",
"tag",
"group",
"priority"
]
columns: true, ltrim: true, rtrim: true
},
async function (err, data) {
if (err) {
@@ -113,27 +91,31 @@ async function csv_import(shortName, filename, callback) {
callback(err, null);
} else {
var response = [];
for (var i = 0; i < data.length; i++) {
var row = data[i];
row.num = parseInt(row.num);
row.tag = row.tag.toLowerCase();
row.group = row.group.toLowerCase();
console.log(row)
if (!( "Decimal" in row) || !("Description" in row) || !("Alpha Tag" in row)) {
console.error("Error: csv import column header error");
callback("Column Headers are required - Required Columns: 'Decimal' 'Decscription' 'Alpha Tag' Optional Column: 'Priority' ", null);
return
}
var newTg = new Talkgroup();
newTg.num = row.num;
newTg.alpha = row.alpha;
newTg.mode = row.mode;
newTg.description = row.description;
newTg.tag = row.tag;
newTg.group = row.group;
newTg.priority = row.priority;
newTg.num = parseInt(row["Decimal"]);
newTg.alpha = row["Alpha Tag"].toLowerCase();
newTg.description = row["Description"];
newTg.priority = row["Priority"];
newTg.shortName = shortName;
await newTg.save().catch(err => {
console.log("Error: CSV import: " + err);
callback(err, null);
return
});
response.push(row);
response.push({num: newTg.num, alpha: newTg.alpha, description: newTg.description});
}
callback(null, response);
}
@@ -147,34 +129,23 @@ async function csv_import(shortName, filename, callback) {
exports.importTalkgroups = function (req, res, next) {
process.nextTick(async function () {
const system = await System.findOne({ shortName: req.params.shortName.toLowerCase() }).catch(err => {
res.status(500);
console.error("Error - importTalkgroups: " + err);
res.json({ success: false, message: err });
res.status(500).send("Error - importTalkgroups: " + err);
return;
});
if (!system) {
console.error("Error - importTalkgroups: System not found - " + req.params.shortName.toLowerCase());
res.status(404);
res.json({
success: false,
message: "That Short Name does not exist."
});
res.status(404).send("That Short Name does not exist.");
return;
}
if (!system.userId.equals(req.user._id)) {
console.error("Error - importTalkgroups: you are not the user for hte system: " + req.user._id);
res.status(401);
res.json({
success: false,
message: "You are not the user associated with this system."
});
console.error("Error - importTalkgroups: you are not the user for the system: " + req.user._id);
res.status(401).send("You are not the user associated with this system.");
return;
}
if (!req.file || req.file.size === 0) {
console.error("Error - File is bad. Size");
res.status(500);
res.json({ success: false, message: "Please select a file." });
res.status(500).send( "Please select a file." );
return;
}
@@ -183,9 +154,7 @@ exports.importTalkgroups = function (req, res, next) {
csv_import(system.shortName, req.file.path, function (err, data) {
if (err) {
console.error("Erorr - CSV import, callback: " + err);
res.status(500);
res.json({ success: false, message: err });
res.end();
res.status(500).send(err);
return;
} else {
res.json( data );

View File

@@ -13,9 +13,9 @@ import {
Icon,
Form,
TextArea,
Message,
Header,
Container,
Message,
List,
Segment,
Tab,
@@ -31,7 +31,7 @@ const System = () => {
//const { data: systemErrorData, isSuccess: isErrorsSuccess } = useGetErrorsQuery(shortName);
const [deleteGroupAPI] = useDeleteGroupMutation();
const [reorderGroupsAPI] = useSaveGroupOrderMutation();
const [importTalkgroupsAPI] = useImportTalkgroupsMutation();
const [importTalkgroupsAPI, { error: importError }] = useImportTalkgroupsMutation();
const [deleteSystemAPI ] = useDeleteSystemMutation();
const [openSystemDeleteConfirm, setOpenSystemDeleteConfirm] = useState(false);
const [openMessage, setOpenMessage] = useState(false);
@@ -401,22 +401,13 @@ const System = () => {
<List ordered celled>
<List.Item>
<List.Content>
<List.Header>Number</List.Header>
<List.Description>The talkgroup number</List.Description>
<List.Header>Decimal</List.Header>
<List.Description>The talkgroup number in decimal</List.Description>
</List.Content>
</List.Item>
<List.Item>
<List.Content>
<List.Header>Mode</List.Header>
<List.Description>
The mode for the talkgroup, it can be: 'A' = analog, 'D' =
P25 Digital, 'E' = Encrypted
</List.Description>
</List.Content>
</List.Item>
<List.Item>
<List.Content>
<List.Header>Alpha</List.Header>
<List.Header>Alpha Tag</List.Header>
<List.Description>
Up to 12 charecter description of the talkgroup
</List.Description>
@@ -430,31 +421,6 @@ const System = () => {
</List.Description>
</List.Content>
</List.Item>
<List.Item>
<List.Content>
<List.Header>Tag</List.Header>
<List.Description>
The type of talkgroup, eg: Dispatch, Fireground
</List.Description>
</List.Content>
</List.Item>
<List.Item>
<List.Content>
<List.Header>Group</List.Header>
<List.Description>
The department that uses this talkgroup
</List.Description>
</List.Content>
</List.Item>
<List.Item>
<List.Content>
<List.Header>Priority</List.Header>
<List.Description>
The priority for recording this talkgroup, 100 or over
will be skipped
</List.Description>
</List.Content>
</List.Item>
</List>
</Container>
<Divider />
@@ -483,6 +449,12 @@ const System = () => {
Export Talkgroups
</Button>
</a>
{importError ? (
<div>
<Message color='red'>{importError.data}</Message>
</div>
) : (<div></div>)}
<ListTalkgroups talkgroups={talkgroupsData} />
</div>
)

View File

@@ -20,16 +20,15 @@ class ListTalkgroups extends Component {
<Table celled>
<Table.Header>
<Table.Row>
<Table.HeaderCell>Mode</Table.HeaderCell>
<Table.HeaderCell>Number</Table.HeaderCell>
<Table.HeaderCell>Alpha</Table.HeaderCell>
<Table.HeaderCell>Decimal</Table.HeaderCell>
<Table.HeaderCell>Alpha Tag</Table.HeaderCell>
<Table.HeaderCell>Description</Table.HeaderCell>
</Table.Row>
</Table.Header>
<Table.Body>
{talkgroups.map((talkgroup, i) => (
<Table.Row key={talkgroup.num + "-" + i}>
<Table.Cell>{talkgroup.mode}</Table.Cell>
<Table.Cell>{talkgroup.num}</Table.Cell>
<Table.Cell>{talkgroup.alpha}</Table.Cell>
<Table.Cell>{talkgroup.description}</Table.Cell>

View File

@@ -94,7 +94,7 @@ export const apiSlice = createApi({
await queryFulfilled
dispatch(
apiSlice.util.updateQueryData('getGroups', group.shortName, (groups) => {
const groupIndex = groups.findIndex((obj => obj.groupId === group.groupId));
const groupIndex = groups.findIndex((obj => obj._id === group._id));
groups.splice(groupIndex,1);
})
)

View File

@@ -10,7 +10,8 @@ exports.get_talkgroups = async function (req, res) {
var talkgroups = {};
for (var tg in tg_results) {
talkgroups[tg_results[tg].num] = tg_results[tg];
var talkgroup = {num: tg_results[tg].num, alpha: tg_results[tg].alpha, description: tg_results[tg].description}
talkgroups[tg_results[tg].num] = talkgroup;
}
res.contentType('json');
res.send(JSON.stringify({