Better Event Creation

This commit is contained in:
Luke Berndt
2024-10-20 22:28:45 -04:00
parent 6c91a6d1d1
commit 61efcc44b4
9 changed files with 169 additions and 51 deletions

View File

@@ -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:

View File

@@ -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>
);
}

View File

@@ -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 = [
{

View File

@@ -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>
);
}

View File

@@ -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 &&

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View 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");
}