Skip to content

Commit

Permalink
Merge pull request #3253 from Thorium-Sim/print-queue
Browse files Browse the repository at this point in the history
feat: PrintQueue core makes it possible to queue items to be printed through keyboards and triggers. Also enables printing documents from macro buttons. Closes #3250
  • Loading branch information
alexanderson1993 authored Oct 5, 2022
2 parents 661203b + 5110fb8 commit a7f9cc6
Show file tree
Hide file tree
Showing 20 changed files with 294 additions and 45 deletions.
6 changes: 6 additions & 0 deletions server/app.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,12 @@ class Events extends EventEmitter {
dmxConfigs: ClassesImport.DMXConfig[] = [];
dmxSets: ClassesImport.DMXSet[] = [];
hackingPresets: ClassesImport.HackingPreset[] = [];
printQueue: {
id: string;
asset: string;
simulatorId: string;
timestamp: number;
}[] = [];
autoUpdate = true;
migrations: any = {assets: true, dmx: false};
thoriumId: string = randomWords(5).join("-");
Expand Down
5 changes: 4 additions & 1 deletion server/events/eventMacro.js
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,10 @@ App.on("triggerMacroButton", ({simulatorId, configId, buttonId}) => {
const macro = App.macroButtonConfigs.find(s => s.id === configId);
const button = macro.getButton(buttonId);
// Don't allow a macro to trigger itself
const macros = button.actions;
const excludedActions = ["printPdf"];
const macros = button.actions.filter(
({event}) => !excludedActions.includes(event),
);
if (macros.length > 0)
App.handleEvent({simulatorId, macros}, "triggerMacros");
});
Expand Down
39 changes: 39 additions & 0 deletions server/events/ship.js
Original file line number Diff line number Diff line change
Expand Up @@ -188,3 +188,42 @@ App.on(
});
},
);
App.on("printPdf", ({asset, simulatorId}) => {
App.printQueue.push({
id: uuid.v4(),
asset,
simulatorId,
timestamp: Date.now(),
});
pubsub.publish(
"printQueue",
App.printQueue.filter(queue => queue.simulatorId === simulatorId),
);
App.handleEvent(
{
simulatorId: simulatorId,
component: "PrintQueueCore",
title: `New Print Queue`,
body: asset,
color: "info",
},
"addCoreFeed",
);
pubsub.publish("notify", {
id: uuid.v4(),
simulatorId: simulatorId,
type: "Print Queue",
station: "Core",
title: `New Print Queue`,
body: asset,
color: "info",
});
});
App.on("clearPdf", ({id}) => {
const pdf = App.printQueue.find(item => item.id === id);
App.printQueue = App.printQueue.filter(item => item.id !== id);
pubsub.publish(
"printQueue",
App.printQueue.filter(queue => queue.simulatorId === pdf.simulatorId),
);
});
1 change: 1 addition & 0 deletions server/helpers/defaultSnapshot.js
Original file line number Diff line number Diff line change
Expand Up @@ -13637,6 +13637,7 @@ export default {
dmxConfigs: [],
dmxDevices: [],
hackingPresets: [],
printQueue: [],
autoUpdate: true,
thoriumId: randomWords(5).join("-"),
doTrack: false,
Expand Down
32 changes: 32 additions & 0 deletions server/typeDefs/ship.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import {gql, withFilter} from "apollo-server-express";
import App from "../app";
import {pubsub} from "../helpers/subscriptionManager";
import uuid from "uuid";

const mutationHelper = require("../helpers/mutationHelper").default;
// We define a schema that encompasses all of the types
// necessary for the functionality in this file.
Expand Down Expand Up @@ -100,11 +103,20 @@ const schema = gql`
Macro: Actions: Print PDF Asset
"""
printPdf(asset: String!): String
clearPdf(id: ID!): String
}
type PrintQueue {
id: ID!
simulatorId: String!
asset: String!
timestamp: Float!
}
extend type Subscription {
notify(simulatorId: ID!, station: String, trigger: String): Notification
widgetNotify(simulatorId: ID!, station: String): String
printQueue(simulatorId: ID!): [PrintQueue]
}
`;

Expand Down Expand Up @@ -148,6 +160,26 @@ const resolver = {
rootValue => !!rootValue,
),
},
printQueue: {
resolve(rootValue) {
return rootValue;
},
subscribe: withFilter(
(rootValue, {simulatorId}) => {
const id = uuid.v4();
process.nextTick(() => {
let returnVal = App.printQueue.filter(
queue => queue.simulatorId === simulatorId,
);
pubsub.publish(id, returnVal);
});
return pubsub.asyncIterator([id, "printQueue"]);
},
(rootValue, {simulatorId}) => {
return true;
},
),
},
},
};

Expand Down
4 changes: 3 additions & 1 deletion src/components/client/lighting.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,9 @@ export const ClientLighting: React.FC<{
const {data} = useDmxSetsSubscription();

React.useEffect(() => {
activate({variables: {clientId, dmxSetId}});
if (dmxSetId) {
activate({variables: {clientId, dmxSetId}});
}
}, [activate, clientId, dmxSetId]);

if (!data?.dmxSets || data?.dmxSets.length === 0) {
Expand Down
1 change: 1 addition & 0 deletions src/components/core/menubar/notificationConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ export const notifyComponents = [
"Medical Teams",
"Navigation",
"Phasers",
"Print Queue",
"Probes",
"Railgun",
"Reactivation Code",
Expand Down
6 changes: 4 additions & 2 deletions src/components/views/Macros/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import EventPicker from "containers/FlightDirector/MissionConfig/EventPicker";
import uuid from "uuid";
import MacroConfig from "./macroConfig";
import {FaBan} from "react-icons/fa";
import triggerLocalMacros from "helpers/triggerLocalMacros";
import triggerLocalMacros, {localMacrosList} from "helpers/triggerLocalMacros";
class MacrosCore extends Component {
state = {actions: []};
render() {
Expand Down Expand Up @@ -134,7 +134,9 @@ class MacrosCore extends Component {
`}
variables={{
simulatorId: simulator.id,
macros: actions.map(({id, ...rest}) => rest),
macros: actions
.filter(({event}) => localMacrosList.includes(event))
.map(({id, ...rest}) => rest),
}}
>
{triggerMacros => (
Expand Down
14 changes: 11 additions & 3 deletions src/components/views/Macros/macroButtons.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {useQuery, useMutation} from "@apollo/client";
import {Input, Button} from "helpers/reactstrap";
import useLocalStorage from "helpers/hooks/useLocalStorage";
import {capitalCase} from "change-case";
import triggerLocalMacros from "helpers/triggerLocalMacros";

const fragment = gql`
fragment MacrosButtonsData on MacroButtonConfig {
Expand All @@ -15,6 +16,12 @@ const fragment = gql`
name
color
category
actions {
id
event
args
delay
}
}
}
`;
Expand Down Expand Up @@ -108,15 +115,16 @@ const MacroButtons = ({simulator: {id: simulatorId}}) => {
key={b.id}
color={b.color}
size="sm"
onClick={() =>
onClick={() => {
triggerLocalMacros(b.actions);
trigger({
variables: {
configId: selectedConfig,
buttonId: b.id,
simulatorId,
},
})
}
});
}}
>
{b.name}
</Button>
Expand Down
3 changes: 3 additions & 0 deletions src/components/views/PrintQueue/clear.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
mutation ClearPdf($id: ID!) {
clearPdf(id: $id)
}
53 changes: 53 additions & 0 deletions src/components/views/PrintQueue/core.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import React from "react";
import {
Simulator,
usePrintQueueSubscription,
useClearPdfMutation,
} from "generated/graphql";
import "./style.scss";
import {TimeCounter} from "../Sensors";
import printJS from "print-js";

interface TemplateProps {
children: React.ReactNode;
simulator: Simulator;
}

const PrintQueue: React.FC<TemplateProps> = props => {
const {simulator} = props;
const {loading, data} = usePrintQueueSubscription({
variables: {simulatorId: simulator.id},
});

const [clearPdf] = useClearPdfMutation();

if (loading || !data) return null;
const {printQueue} = data;
if (!printQueue || printQueue?.length === 0)
return <div>No Items Queued</div>;
return (
<ul className="core-printqueue">
{printQueue.map(
queue =>
queue && (
<li key={queue.id}>
{queue.asset} (<TimeCounter time={new Date(queue.timestamp)} />){" "}
<button
type="button"
className="btn btn-success btn-sm"
onClick={() => {
if (queue.asset) {
printJS({printable: `/assets${queue.asset}`, type: "pdf"});
}
clearPdf({variables: {id: queue.id}});
}}
>
Print
</button>
</li>
),
)}
</ul>
);
};
export default PrintQueue;
7 changes: 7 additions & 0 deletions src/components/views/PrintQueue/query.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
subscription PrintQueue($simulatorId: ID!) {
printQueue(simulatorId: $simulatorId) {
id
asset
timestamp
}
}
7 changes: 7 additions & 0 deletions src/components/views/PrintQueue/style.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.core-printqueue {
li {
display: flex;
gap: 0.5rem;
margin-top: 0.25rem;
}
}
2 changes: 1 addition & 1 deletion src/components/views/Sensors/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ function calculateTime(milliseconds: number) {
);
}

const TimeCounter: React.FC<{time: Date}> = ({time}) => {
export const TimeCounter: React.FC<{time: Date}> = ({time}) => {
const milliseconds = Date.now() - Number(time);
return <>{calculateTime(milliseconds)}</>;
};
Expand Down
37 changes: 19 additions & 18 deletions src/components/views/Timeline/classicMission.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,26 +50,27 @@ const TimelineStep: React.FC<TimelineStepProps> = ({
const runMacro = (t: TimelineStepI) => {
if (!t) return;
const stepIndex = timeline.findIndex(i => i.id === t.id);
const macros = t.timelineItems
.filter(a =>
onlyExecuteViewscreen ? allowedMacros.indexOf(a.event) > -1 : true,
)
.map(tt => {
const args = !tt.args
? "{}"
: typeof tt.args === "string"
? JSON.stringify({...JSON.parse(tt.args)})
: JSON.stringify({...(tt.args as Object)});
return {
stepId: tt.id,
event: tt.event,
args,
delay: tt.delay || 0,
};
});
const macros = t.timelineItems.map(tt => {
const args = !tt.args
? "{}"
: typeof tt.args === "string"
? JSON.stringify({...JSON.parse(tt.args)})
: JSON.stringify({...(tt.args as Object)});
return {
stepId: tt.id,
event: tt.event,
args,
delay: tt.delay || 0,
};
});
const filteredMacros = macros.filter(
a =>
(onlyExecuteViewscreen ? allowedMacros.indexOf(a.event) > -1 : true) &&
!excludedTimelineActions.includes(a.event),
);
const variables = {
simulatorId,
macros,
macros: filteredMacros,
};
triggerLocalMacros(macros);
triggerMacros({variables});
Expand Down
Loading

0 comments on commit a7f9cc6

Please sign in to comment.