mirror of
https://github.com/openmhz/trunk-server.git
synced 2026-11-09 15:27:30 -05:00
Better Event Creation
This commit is contained in:
@@ -190,6 +190,9 @@ services:
|
||||
- REACT_APP_FRONTEND_SERVER
|
||||
- REACT_APP_SITE_NAME
|
||||
- REACT_APP_GOOGLE_ANALYTICS
|
||||
- GLIBC_TUNABLES=glibc.pthread.rseq=0
|
||||
ulimits:
|
||||
memlock: -1
|
||||
depends_on:
|
||||
- mongo
|
||||
networks:
|
||||
|
||||
@@ -194,12 +194,8 @@ function CallPlayer(props) {
|
||||
</Sticky>
|
||||
}
|
||||
<Sidebar.Pushable>
|
||||
<Sidebar.Pusher
|
||||
style={{ minHeight: '100vh' }}
|
||||
>
|
||||
|
||||
<Sidebar.Pusher style={{ minHeight: '100vh' }} >
|
||||
<div ref={loadNewerRef} />
|
||||
|
||||
<ListCalls callsData={callsData} activeCallId={currentCallId} talkgroups={talkgroupsData ? talkgroupsData.talkgroups : false} playCall={playCall} />
|
||||
<div ref={loadOlderRef} style={{ height: 50 }} />
|
||||
</Sidebar.Pusher>
|
||||
@@ -213,7 +209,7 @@ function CallPlayer(props) {
|
||||
|
||||
<Menu fixed="bottom" inverted vertical fluid>
|
||||
<div className="item-container">
|
||||
<div className={autoplayClassName} onClick={() => handleAutoPlay(autoPlay)}><Icon name="level up" /><span className="desktop-only">Autoplay</span></div>
|
||||
<div className={autoplayClassName} onClick={() => handleAutoPlay(autoPlay)}><Icon name="level up" /><span className="desktop-only">Autoplay</span></div>
|
||||
<div className="mediaplayer">
|
||||
<MediaPlayer call={currentCall} playSilence={silenceCount} onEnded={callEnded} onPlayPause={handlePlayPause} />
|
||||
</div>
|
||||
@@ -225,7 +221,6 @@ function CallPlayer(props) {
|
||||
</div>
|
||||
</div>
|
||||
</Menu>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import React, { useState } from "react";
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { useCallLink } from "./CallLinks";
|
||||
import { useGetGroupsQuery, useGetTalkgroupsQuery } from '../../features/api/apiSlice'
|
||||
import { Link, useLocation, useParams, useNavigate } from 'react-router-dom';
|
||||
@@ -14,10 +15,12 @@ import {
|
||||
} from "semantic-ui-react";
|
||||
import PlaylistBuilder from "./PlaylistBuilder"
|
||||
import CallInfoPane from "./CallInfoPane"
|
||||
import { setBuildingPlaylist } from '../../features/callPlayer/callPlayerSlice';
|
||||
// ----------------------------------------------------
|
||||
function CallInfo(props) {
|
||||
const { shortName } = useParams();
|
||||
const { data: talkgroupsData, isSuccess: isTalkgroupsSuccess } = useGetTalkgroupsQuery(shortName);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
let srcList = "";
|
||||
let callLength = "-";
|
||||
@@ -48,7 +51,14 @@ function CallInfo(props) {
|
||||
}
|
||||
const { callLink, callDownload, callTweet } = useCallLink(props.call)
|
||||
const [activeTab, setActiveTab] = useState(0);
|
||||
const handleTabChange = (e, data) => setActiveTab(data.activeIndex);
|
||||
const handleTabChange = (e, data) => {
|
||||
if (data.activeIndex == 1) {
|
||||
dispatch(setBuildingPlaylist(true));
|
||||
} else {
|
||||
dispatch(setBuildingPlaylist(false));
|
||||
}
|
||||
setActiveTab(data.activeIndex);
|
||||
}
|
||||
|
||||
const panes = [
|
||||
{
|
||||
|
||||
@@ -1,27 +1,40 @@
|
||||
import React, { useState } from "react";
|
||||
import React, { useState, useEffect } from "react";
|
||||
import {
|
||||
Table,
|
||||
Icon,
|
||||
Label
|
||||
Label,
|
||||
FormField,
|
||||
Checkbox
|
||||
} from "semantic-ui-react";
|
||||
|
||||
|
||||
import { addStar, removeStar } from "../../features/calls/callsSlice";
|
||||
|
||||
import { useDispatch } from 'react-redux'
|
||||
import { addToPlaylist, removeFromPlaylist } from '../../features/callPlayer/callPlayerSlice';
|
||||
import { useDispatch, useSelector } from 'react-redux'
|
||||
|
||||
const CallItem = (props) => {
|
||||
const call = props.call;
|
||||
const buildingPlaylist = useSelector((state) => state.callPlayer.buildingPlaylist);
|
||||
|
||||
const playlist = useSelector((state) => state.callPlayer.playlist);
|
||||
const shortName = props.shortName;
|
||||
const talkgroups = props.talkgroups;
|
||||
const activeCall = props.activeCall;
|
||||
const [starVisible, setStarVisible] = useState(false);
|
||||
const [starClicked, setStarClicked] = useState(false);
|
||||
const [inPlaylist, setInPlaylist] = useState(false);
|
||||
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const time = new Date(call.time);
|
||||
|
||||
useEffect(() => {
|
||||
if (playlist.find((item) => item._id == call._id)) {
|
||||
setInPlaylist(true);
|
||||
} else {
|
||||
setInPlaylist(false);
|
||||
}
|
||||
}, [playlist]);
|
||||
|
||||
const handleStarClicked = (e) => {
|
||||
e.preventDefault();
|
||||
@@ -56,6 +69,16 @@ const CallItem = (props) => {
|
||||
|
||||
}
|
||||
|
||||
const handlePlaylist = (e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
if (inPlaylist) {
|
||||
dispatch(removeFromPlaylist(call));
|
||||
} else {
|
||||
dispatch(addToPlaylist(call));
|
||||
}
|
||||
}
|
||||
|
||||
if (!starClicked) {
|
||||
starClickable = { link: true };
|
||||
}
|
||||
@@ -111,6 +134,9 @@ const CallItem = (props) => {
|
||||
<Table.Cell>{talkgroup}</Table.Cell>
|
||||
<Table.Cell>{`${time.toLocaleTimeString()} ${time.toLocaleDateString() !== new Date().toLocaleDateString() ? time.getMonth() + 1 + '/' + time.getDate() : ''}`}</Table.Cell>
|
||||
<Table.Cell onMouseEnter={() => setStarVisible(true)} onMouseLeave={() => setStarVisible(false)} onClick={handleStarClicked}>{starButton}</Table.Cell>
|
||||
{buildingPlaylist && <Table.Cell> <FormField>
|
||||
<Checkbox checked={inPlaylist} onChange={handlePlaylist} />
|
||||
</FormField></Table.Cell>}
|
||||
</Table.Row>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import "../CallPlayer.css";
|
||||
import { useGetTalkgroupsQuery } from '../../features/api/apiSlice'
|
||||
import { useSelector } from 'react-redux'
|
||||
|
||||
|
||||
// ----------------------------------------------------
|
||||
const ListCalls = (props) => {
|
||||
const activeCallRef = useRef();
|
||||
@@ -17,6 +18,7 @@ const ListCalls = (props) => {
|
||||
const { shortName } = useParams();
|
||||
const centerCall = useSelector((state) => state.callPlayer.centerCall);
|
||||
const { data: talkgroupsData, isSuccess: isTalkgroupsSuccess } = useGetTalkgroupsQuery(shortName);
|
||||
const buildingPlaylist = useSelector((state) => state.callPlayer.buildingPlaylist);
|
||||
//https://stackoverflow.com/questions/36559661/how-can-i-dispatch-from-child-components-in-react-redux
|
||||
//https://stackoverflow.com/questions/42597602/react-onclick-pass-event-with-parameter
|
||||
|
||||
@@ -41,6 +43,7 @@ const ListCalls = (props) => {
|
||||
<Table.HeaderCell>Talkgroup</Table.HeaderCell>
|
||||
<Table.HeaderCell>Time</Table.HeaderCell>
|
||||
<Table.HeaderCell><Icon name='star' /></Table.HeaderCell>
|
||||
{buildingPlaylist && <Table.HeaderCell><Icon name='list ul' /></Table.HeaderCell>}
|
||||
</Table.Row>
|
||||
</Table.Header>
|
||||
{callsData &&
|
||||
|
||||
@@ -79,8 +79,8 @@ function PlaylistBuilder(props) {
|
||||
let tgAlpha = call.talkgroupNum;
|
||||
if (talkgroupsData) {
|
||||
const talkgroup = talkgroupsData.talkgroups[call.talkgroupNum]
|
||||
if (talkgroup && talkgroup.alpha!=" ") {
|
||||
tgAlpha = talkgroup.alpha;
|
||||
if (talkgroup && talkgroup.alpha != " ") {
|
||||
tgAlpha = talkgroup.alpha;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -96,28 +96,28 @@ function PlaylistBuilder(props) {
|
||||
if ((title.length < 3) || (description.length < 3)) {
|
||||
setSubmitMessage("Please fill out the title and description with something useful");
|
||||
} else {
|
||||
setOpen(false);
|
||||
const callIds = playlist.map((call) => call._id)
|
||||
const event = {
|
||||
title,
|
||||
description,
|
||||
callIds
|
||||
setOpen(false);
|
||||
const callIds = playlist.map((call) => call._id)
|
||||
const event = {
|
||||
title,
|
||||
description,
|
||||
callIds
|
||||
}
|
||||
try {
|
||||
const returned = await addNewEvent(event).unwrap();
|
||||
console.log(returned);
|
||||
setEventUrl(new URL(returned.url, document.baseURI).href)
|
||||
setEventPath(returned.url);
|
||||
setSuccessModalOpen(true);
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
// you can handle errors here if you want to
|
||||
}
|
||||
|
||||
setTitle("");
|
||||
setDescription("");
|
||||
dispatch(setPlaylist([]));
|
||||
}
|
||||
try {
|
||||
const returned = await addNewEvent(event).unwrap();
|
||||
console.log(returned);
|
||||
setEventUrl(new URL(returned.url, document.baseURI).href)
|
||||
setEventPath(returned.url);
|
||||
setSuccessModalOpen(true);
|
||||
} catch (error) {
|
||||
console.error(error)
|
||||
// you can handle errors here if you want to
|
||||
}
|
||||
|
||||
setTitle("");
|
||||
setDescription("");
|
||||
dispatch(setPlaylist([]));
|
||||
}
|
||||
}
|
||||
|
||||
let content = (<Header as="h3" icon textAlign='center' style={{ paddingTop: "3em" }}><Icon name='target' />Drag Calls Here</Header>)
|
||||
@@ -134,25 +134,24 @@ function PlaylistBuilder(props) {
|
||||
<Modal open={successModalOpen}
|
||||
onClose={() => setSuccessModalOpen(false)}
|
||||
size='tiny'
|
||||
>
|
||||
<Modal.Header>Event Successfully Created</Modal.Header>
|
||||
<Modal.Content>Your Event is here: <p><Link to={eventPath}>{eventUrl}</Link></p></Modal.Content>
|
||||
<Modal.Actions>
|
||||
>
|
||||
<Modal.Header>Event Successfully Created</Modal.Header>
|
||||
<Modal.Content>Your Event is here: <p><Link to={eventPath}>{eventUrl}</Link></p></Modal.Content>
|
||||
<Modal.Actions>
|
||||
|
||||
<Button
|
||||
content="Done"
|
||||
labelPosition='right'
|
||||
icon='checkmark'
|
||||
onClick={() => setSuccessModalOpen(false)}
|
||||
positive
|
||||
/>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
<Button
|
||||
content="Done"
|
||||
labelPosition='right'
|
||||
icon='checkmark'
|
||||
onClick={() => setSuccessModalOpen(false)}
|
||||
positive
|
||||
/>
|
||||
</Modal.Actions>
|
||||
</Modal>
|
||||
<Modal
|
||||
onClose={() => setOpen(false)}
|
||||
onOpen={() => setOpen(true)}
|
||||
open={open}
|
||||
|
||||
>
|
||||
<Modal.Header>Submit an Event</Modal.Header>
|
||||
<Modal.Content>
|
||||
@@ -179,7 +178,7 @@ function PlaylistBuilder(props) {
|
||||
onChange={handleDescriptionChange}
|
||||
/>
|
||||
</Form>
|
||||
{submitMessage&& <Message error>{submitMessage}</Message>}
|
||||
{submitMessage && <Message error>{submitMessage}</Message>}
|
||||
</Modal.Description>
|
||||
</Modal.Content>
|
||||
<Modal.Actions>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { createSlice } from '@reduxjs/toolkit'
|
||||
import { set } from 'date-fns';
|
||||
const now = new Date().getTime();
|
||||
const initialState = {
|
||||
isWaiting: false,
|
||||
@@ -14,6 +15,7 @@ const initialState = {
|
||||
filterStarred: false,
|
||||
filterCallId: false,
|
||||
currentCallId: false,
|
||||
buildingPlaylist: false,
|
||||
playlist: [],
|
||||
live: false,
|
||||
centerCall: true,
|
||||
@@ -44,6 +46,9 @@ export const callPlayerSlice = createSlice({
|
||||
state.newestCallTime = action.payload;
|
||||
state.oldestCallTime = action.payload;
|
||||
},
|
||||
setBuildingPlaylist: (state, action) => {
|
||||
state.buildingPlaylist = action.payload;
|
||||
},
|
||||
setPlaylist: (state, action) => {
|
||||
if (Array.isArray(action.payload )) {
|
||||
state.playlist = action.payload;
|
||||
@@ -115,7 +120,7 @@ export const callPlayerSlice = createSlice({
|
||||
})
|
||||
|
||||
// Action creators are generated for each case reducer function
|
||||
export const { setCurrentCallId, setCallTime, setFilter, setLive, setCenterCall, setBackgroundAutoplay, setPlaylist, removeFromPlaylist, addToPlaylist, setShortName, setDateFilter, setStarredFilter, setAllFilter, setGroupFilter, setTalkgroupFilter } = callPlayerSlice.actions
|
||||
export const { setCurrentCallId, setCallTime, setFilter, setLive, setCenterCall, setBackgroundAutoplay, setBuildingPlaylist, setPlaylist, removeFromPlaylist, addToPlaylist, setShortName, setDateFilter, setStarredFilter, setAllFilter, setGroupFilter, setTalkgroupFilter } = callPlayerSlice.actions
|
||||
|
||||
export default callPlayerSlice.reducer
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ ADD upgrade_db_admin.js /app
|
||||
ADD permissions.js /app
|
||||
ADD errors.js /app
|
||||
ADD clean.js /app
|
||||
ADD remove_old_systems.js /app
|
||||
|
||||
ENV GLIBC_TUNABLES=glibc.pthread.rseq=0
|
||||
|
||||
|
||||
76
mongo/remove_old_systems.js
Normal file
76
mongo/remove_old_systems.js
Normal file
@@ -0,0 +1,76 @@
|
||||
// inactive-systems.js
|
||||
// This script finds inactive systems and removes them along with their related groups and talkgroups
|
||||
// Run with: mongosh scanner inactive-systems.js
|
||||
|
||||
// Switch to scanner database
|
||||
db = db.getSiblingDB('scanner');
|
||||
|
||||
// Calculate date 6 months ago
|
||||
const sixMonthsAgo = new Date();
|
||||
sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6);
|
||||
|
||||
// Print the date we're using as threshold
|
||||
print("Finding systems inactive since: " + sixMonthsAgo.toISOString());
|
||||
|
||||
// Run the aggregation to get inactive systems
|
||||
const result = db.systems.aggregate([
|
||||
{
|
||||
$match: {
|
||||
$or: [
|
||||
{ lastActive: { $lt: sixMonthsAgo } },
|
||||
{ lastActive: { $exists: false } }
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
_id: 0,
|
||||
shortName: 1
|
||||
}
|
||||
},
|
||||
{
|
||||
$group: {
|
||||
_id: null,
|
||||
inactiveShortNames: { $push: "$shortName" }
|
||||
}
|
||||
},
|
||||
{
|
||||
$project: {
|
||||
_id: 0,
|
||||
inactiveShortNames: 1
|
||||
}
|
||||
}
|
||||
]).toArray();
|
||||
|
||||
// If we found inactive systems, process them
|
||||
if (result.length > 0) {
|
||||
const inactiveShortNames = result[0].inactiveShortNames;
|
||||
print("\nInactive systems found: " + inactiveShortNames.length);
|
||||
print("\nShort names of inactive systems:");
|
||||
print(JSON.stringify(inactiveShortNames, null, 2));
|
||||
|
||||
// Remove groups associated with inactive systems
|
||||
const deleteGroupsResult = db.groups.deleteMany({
|
||||
shortName: { $in: inactiveShortNames }
|
||||
});
|
||||
|
||||
// Remove talkgroups associated with inactive systems
|
||||
const deleteTalkgroupsResult = db.talkgroups.deleteMany({
|
||||
shortName: { $in: inactiveShortNames }
|
||||
});
|
||||
|
||||
// Remove the inactive systems themselves
|
||||
const deleteSystemsResult = db.systems.deleteMany({
|
||||
$or: [
|
||||
{ lastActive: { $lt: sixMonthsAgo } },
|
||||
{ lastActive: { $exists: false } }
|
||||
]
|
||||
});
|
||||
|
||||
print("\nCleanup results:");
|
||||
print(`Deleted ${deleteGroupsResult.deletedCount} groups associated with inactive systems`);
|
||||
print(`Deleted ${deleteTalkgroupsResult.deletedCount} talkgroups associated with inactive systems`);
|
||||
print(`Deleted ${deleteSystemsResult.deletedCount} inactive systems`);
|
||||
} else {
|
||||
print("No inactive systems found");
|
||||
}
|
||||
Reference in New Issue
Block a user