mirror of
https://github.com/openmhz/trunk-server.git
synced 2026-11-11 16:27:42 -05:00
Change CSV handling - fixed group delete
This commit is contained in:
42
.devcontainer/devcontainer.json
Normal file
42
.devcontainer/devcontainer.json
Normal 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"
|
||||
}
|
||||
26
.devcontainer/docker-compose.yml
Normal file
26
.devcontainer/docker-compose.yml
Normal 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"
|
||||
|
||||
@@ -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 );
|
||||
|
||||
@@ -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>
|
||||
)
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
})
|
||||
)
|
||||
|
||||
@@ -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({
|
||||
|
||||
Reference in New Issue
Block a user