From f45483437ca2fac423d37211a202627aedd65bd6 Mon Sep 17 00:00:00 2001 From: Alex Anderson Date: Sat, 9 May 2020 08:24:51 -0600 Subject: [PATCH 1/4] Starting on multi-Tractor Beam --- .../{tractorBeam.js => tractorBeam.ts} | 38 ++++++++++++++----- .../views/PowerDistribution/index.js | 2 +- 2 files changed, 30 insertions(+), 10 deletions(-) rename server/classes/{tractorBeam.js => tractorBeam.ts} (64%) diff --git a/server/classes/tractorBeam.js b/server/classes/tractorBeam.ts similarity index 64% rename from server/classes/tractorBeam.js rename to server/classes/tractorBeam.ts index 67cf4b5b3..c16928421 100644 --- a/server/classes/tractorBeam.js +++ b/server/classes/tractorBeam.ts @@ -1,22 +1,42 @@ import {System} from "./generic"; +class Beam { + state: boolean; + target: boolean; + targetLabel: string; + strength: number; + stress: number; + constructor(params: Partial = {}) { + this.state = params.state || false; + this.target = params.target || false; + this.targetLabel = params.targetLabel || ""; + this.strength = params.strength || 0.0; + this.stress = params.stress || 0.15; + } +} export default class TractorBeam extends System { - constructor(params) { + class: "TractorBeam" = "TractorBeam"; + type: "TractorBeam" = "TractorBeam"; + beams: Beam[]; + + constructor(params: Partial = {}) { super(params); this.class = "TractorBeam"; this.type = "TractorBeam"; this.wing = params.wing || "right"; this.name = params.name || "Tractor Beam"; - this.state = params.state || false; - this.target = params.target || false; - this.targetLabel = params.targetLabel || ""; - this.strength = params.strength || 0.0; - this.stress = params.stress || 0.15; - this.scanning = params.scanning || false; + this.beams = params.beams + ? params.beams.map(b => new Beam(b)) + : [new Beam(params)]; } get stealthFactor() { - return this.state ? this.stress / 5 + 0.8 : 0; + const beamsRunning = this.beams.find(b => b.state); + const strength = this.beams.reduce( + (prev, next) => Math.max(prev, next.strength), + 0, + ); + return beamsRunning ? strength / 5 + 0.8 : 0; } trainingMode() { this.setTarget(true); @@ -24,7 +44,7 @@ export default class TractorBeam extends System { } break(report, destroyed, which) { - this.state = false; + this.beams.forEach(b => (b.state = false)); super.break(report, destroyed, which); } setPower(powerLevel) { diff --git a/src/components/views/PowerDistribution/index.js b/src/components/views/PowerDistribution/index.js index d9871b810..169858025 100644 --- a/src/components/views/PowerDistribution/index.js +++ b/src/components/views/PowerDistribution/index.js @@ -2,7 +2,7 @@ import React from "react"; import {css, jsx} from "@emotion/core"; import gql from "graphql-tag.macro"; -import {Row, Col, Container, Card} from "helpers/reactstrap"; +import {Container, Card} from "helpers/reactstrap"; import {withApollo} from "react-apollo"; import Tour from "helpers/tourHelper"; import "./style.scss"; From eb3776b719504ff58ede92c283efb2bc77cc0c93 Mon Sep 17 00:00:00 2001 From: Alex Anderson Date: Sat, 9 May 2020 13:09:24 -0600 Subject: [PATCH 2/4] feat(Tractor Beam): Adds support for up to four tractor beams on one simulator. Configure it on the Tractor Beam systems config. Closes #2929 --- server/classes/tractorBeam.ts | 69 +++- server/events/index.js | 1 - server/events/tractorBeam.js | 110 ----- server/generated/resolvers.ts | 117 ++++-- server/typeDefs/tractorBeam.ts | 172 +++++++- .../views/TractorBeam/MutliBeam.tsx | 279 +++++++++++++ src/components/views/TractorBeam/OneBeam.tsx | 130 ++++++ .../views/TractorBeam/{arrow.js => arrow.tsx} | 17 +- src/components/views/TractorBeam/bars.js | 128 ------ src/components/views/TractorBeam/bars.tsx | 113 ++++++ src/components/views/TractorBeam/beam.js | 37 -- src/components/views/TractorBeam/beam.tsx | 45 +++ src/components/views/TractorBeam/core.js | 175 -------- src/components/views/TractorBeam/core.tsx | 110 +++++ src/components/views/TractorBeam/index.js | 205 ---------- src/components/views/TractorBeam/index.tsx | 92 +++++ .../queries/tractorBeamLabel.graphql | 3 + .../queries/tractorBeamState.graphql | 3 + .../queries/tractorBeamStrength.graphql | 3 + .../queries/tractorBeamStress.graphql | 3 + .../queries/tractorBeamSub.graphql | 24 ++ .../queries/tractorBeamTarget.graphql | 3 + src/components/views/TractorBeam/style.scss | 59 +-- .../TractorBeam/{target.js => target.tsx} | 12 +- .../SimulatorConfig/config/Systems.js | 101 ++--- .../config/systemsConfig/TractorBeam.tsx | 59 +++ .../config/systemsConfig/index.js | 1 + .../queries/setTractorBeamCount.graphql | 3 + src/generated/graphql.tsx | 378 +++++++++++++++++- src/helpers/hooks/useMeasure.ts | 6 +- src/schema.graphql | 44 +- 31 files changed, 1620 insertions(+), 882 deletions(-) delete mode 100644 server/events/tractorBeam.js create mode 100644 src/components/views/TractorBeam/MutliBeam.tsx create mode 100644 src/components/views/TractorBeam/OneBeam.tsx rename src/components/views/TractorBeam/{arrow.js => arrow.tsx} (78%) delete mode 100644 src/components/views/TractorBeam/bars.js create mode 100644 src/components/views/TractorBeam/bars.tsx delete mode 100644 src/components/views/TractorBeam/beam.js create mode 100644 src/components/views/TractorBeam/beam.tsx delete mode 100644 src/components/views/TractorBeam/core.js create mode 100644 src/components/views/TractorBeam/core.tsx delete mode 100644 src/components/views/TractorBeam/index.js create mode 100644 src/components/views/TractorBeam/index.tsx create mode 100644 src/components/views/TractorBeam/queries/tractorBeamLabel.graphql create mode 100644 src/components/views/TractorBeam/queries/tractorBeamState.graphql create mode 100644 src/components/views/TractorBeam/queries/tractorBeamStrength.graphql create mode 100644 src/components/views/TractorBeam/queries/tractorBeamStress.graphql create mode 100644 src/components/views/TractorBeam/queries/tractorBeamSub.graphql create mode 100644 src/components/views/TractorBeam/queries/tractorBeamTarget.graphql rename src/components/views/TractorBeam/{target.js => target.tsx} (82%) create mode 100644 src/containers/FlightDirector/SimulatorConfig/config/systemsConfig/TractorBeam.tsx create mode 100644 src/containers/FlightDirector/SimulatorConfig/config/systemsConfig/queries/setTractorBeamCount.graphql diff --git a/server/classes/tractorBeam.ts b/server/classes/tractorBeam.ts index c16928421..bba2b514b 100644 --- a/server/classes/tractorBeam.ts +++ b/server/classes/tractorBeam.ts @@ -1,17 +1,40 @@ import {System} from "./generic"; +import uuid from "uuid"; class Beam { + id: string; state: boolean; target: boolean; targetLabel: string; strength: number; stress: number; + scanning: boolean; constructor(params: Partial = {}) { + this.id = params.id || uuid.v4(); this.state = params.state || false; this.target = params.target || false; this.targetLabel = params.targetLabel || ""; this.strength = params.strength || 0.0; this.stress = params.stress || 0.15; + this.scanning = params.scanning || false; + } + setState(tf: boolean) { + this.state = tf; + } + setTarget(tf: boolean) { + this.target = tf; + } + setTargetLabel(label: string) { + this.targetLabel = label; + } + setStrength(percent: number) { + this.strength = Math.min(1, Math.max(0, percent)); + } + setStress(percent: number) { + this.stress = Math.min(1, Math.max(0, percent)); + } + setScanning(scanning: boolean) { + this.scanning = scanning; } } export default class TractorBeam extends System { @@ -28,7 +51,7 @@ export default class TractorBeam extends System { this.name = params.name || "Tractor Beam"; this.beams = params.beams ? params.beams.map(b => new Beam(b)) - : [new Beam(params)]; + : [new Beam({...params, id: null})]; } get stealthFactor() { const beamsRunning = this.beams.find(b => b.state); @@ -39,12 +62,12 @@ export default class TractorBeam extends System { return beamsRunning ? strength / 5 + 0.8 : 0; } trainingMode() { - this.setTarget(true); - this.setTargetLabel("Training Target"); + this.beams?.[0].setTarget(true); + this.beams?.[0].setTargetLabel("Training Target"); } break(report, destroyed, which) { - this.beams.forEach(b => (b.state = false)); + this.beams.forEach(b => b.setState(false)); super.break(report, destroyed, which); } setPower(powerLevel) { @@ -52,26 +75,38 @@ export default class TractorBeam extends System { this.power.powerLevels.length && powerLevel < this.power.powerLevels[0] ) { - this.state = false; + this.beams.forEach(b => b.setState(false)); } super.setPower(powerLevel); } - setState(tf) { - this.state = tf; + setBeamCount(count: number) { + if (count > 4 || count <= 0 || count === 3) return; + if (this.beams.length < count) { + const needed = count - this.beams.length; + for (let i = 0; i < needed; i++) { + this.beams.push(new Beam({})); + } + } else if (this.beams.length > count) { + this.beams = this.beams.slice(0, count); + } } - setTarget(tf) { - this.target = tf; + setState(beam: string, tf: boolean) { + this.beams.find(b => b.id === beam).setState(tf); } - setTargetLabel(label) { - this.targetLabel = label; + setTarget(beam: string, tf: boolean) { + console.log(beam, this.beams); + this.beams.find(b => b.id === beam).setTarget(tf); } - setStrength(perc) { - this.strength = Math.min(1, Math.max(0, perc)); + setTargetLabel(beam: string, label: string) { + this.beams.find(b => b.id === beam).setTargetLabel(label); } - setStress(perc) { - this.stress = Math.min(1, Math.max(0, perc)); + setStrength(beam: string, percent: number) { + this.beams.find(b => b.id === beam).setStrength(percent); } - setScanning(scanning) { - this.scanning = scanning; + setStress(beam: string, percent: number) { + this.beams.find(b => b.id === beam).setStress(percent); + } + setScanning(beam: string, scanning: boolean) { + this.beams.find(b => b.id === beam).setScanning(scanning); } } diff --git a/server/events/index.js b/server/events/index.js index 73ea6e7a1..a9f0c1600 100644 --- a/server/events/index.js +++ b/server/events/index.js @@ -24,7 +24,6 @@ import "./probes"; import "./stealthField"; import "./thrusters"; import "./coolant"; -import "./tractorBeam"; import "./crew"; import "./teams"; import "./viewscreen"; diff --git a/server/events/tractorBeam.js b/server/events/tractorBeam.js deleted file mode 100644 index 9cadf8993..000000000 --- a/server/events/tractorBeam.js +++ /dev/null @@ -1,110 +0,0 @@ -import App from "../app"; -import {pubsub} from "../helpers/subscriptionManager"; -import uuid from "uuid"; - -App.on("setTractorBeamState", ({id, state}) => { - const system = App.systems.find(s => s.id === id); - system.setState(state); - system.setScanning(false); - pubsub.publish("notify", { - id: uuid.v4(), - simulatorId: system.simulatorId, - type: "Tractor Beam", - station: "Core", - title: `Tractor Beam ${state ? "Activated" : "Deactivated"}`, - body: "", - color: "info", - }); - App.handleEvent( - { - simulatorId: system.simulatorId, - component: "TractorBeamCore", - title: `Tractor Beam ${state ? "Activated" : "Deactivated"}`, - body: null, - color: "info", - }, - "addCoreFeed", - ); - pubsub.publish( - "tractorBeamUpdate", - App.systems.filter(s => s.type === "TractorBeam"), - ); -}); -App.on("setTractorBeamTarget", ({id, target}) => { - const sys = App.systems.find(s => s.id === id); - sys.setTarget(target); - sys.setScanning(false); - pubsub.publish( - "tractorBeamUpdate", - App.systems.filter(s => s.type === "TractorBeam"), - ); -}); -App.on("setTractorBeamStrength", ({id, strength}) => { - App.systems.find(s => s.id === id).setStrength(strength); - pubsub.publish( - "tractorBeamUpdate", - App.systems.filter(s => s.type === "TractorBeam"), - ); -}); -App.on("setTractorBeamStress", ({id, stress}) => { - App.systems.find(s => s.id === id).setStress(stress); - pubsub.publish( - "tractorBeamUpdate", - App.systems.filter(s => s.type === "TractorBeam"), - ); -}); -App.on("setTractorBeamScanning", ({id, scanning}) => { - const sys = App.systems.find(s => s.id === id); - sys.setScanning(scanning); - pubsub.publish( - "tractorBeamUpdate", - App.systems.filter(s => s.type === "TractorBeam"), - ); - App.handleEvent( - {simulatorId: sys.simulatorId, component: "TractorBeamCore"}, - "addCoreFeed", - ); -}); -App.on("setTractorBeamTargetLabel", ({id, label}) => { - const sys = App.systems.find(s => s.id === id); - sys.setTargetLabel(label); - pubsub.publish( - "tractorBeamUpdate", - App.systems.filter(s => s.type === "TractorBeam"), - ); -}); -App.on("addTractorTarget", ({id, simulatorId, label}) => { - let sys; - if (id) { - sys = App.systems.find(s => s.id === id); - } else { - sys = App.systems.find( - s => s.simulatorId === simulatorId && s.class === "TractorBeam", - ); - } - if (!sys) return; - sys.setTargetLabel(label); - sys.setTarget(true); - sys.setScanning(false); - pubsub.publish( - "tractorBeamUpdate", - App.systems.filter(s => s.type === "TractorBeam"), - ); -}); -App.on("removeTractorTarget", ({id, simulatorId, label}) => { - let sys; - if (id) { - sys = App.systems.find(s => s.id === id); - } else { - sys = App.systems.find( - s => s.simulatorId === simulatorId && s.class === "TractorBeam", - ); - } - if (!sys) return; - sys.setTargetLabel(label); - sys.setTarget(false); - pubsub.publish( - "tractorBeamUpdate", - App.systems.filter(s => s.type === "TractorBeam"), - ); -}); diff --git a/server/generated/resolvers.ts b/server/generated/resolvers.ts index 0218fcbc0..5fe00137c 100644 --- a/server/generated/resolvers.ts +++ b/server/generated/resolvers.ts @@ -2371,6 +2371,7 @@ export type Mutation = { setTractorBeamStress?: Maybe; setTractorBeamScanning?: Maybe; setTractorBeamTargetLabel?: Maybe; + setTractorBeamCount?: Maybe; addTractorTarget?: Maybe; removeTractorTarget?: Maybe; setTransportDestination?: Maybe; @@ -5849,41 +5850,54 @@ export type MutationTorpedoFireArgs = { export type MutationSetTractorBeamStateArgs = { id: Scalars["ID"]; + beam: Scalars["ID"]; state: Scalars["Boolean"]; }; export type MutationSetTractorBeamTargetArgs = { id: Scalars["ID"]; + beam: Scalars["ID"]; target: Scalars["Boolean"]; }; export type MutationSetTractorBeamStrengthArgs = { id: Scalars["ID"]; + beam: Scalars["ID"]; strength: Scalars["Float"]; }; export type MutationSetTractorBeamStressArgs = { id: Scalars["ID"]; + beam: Scalars["ID"]; stress: Scalars["Float"]; }; export type MutationSetTractorBeamScanningArgs = { id: Scalars["ID"]; + beam: Scalars["ID"]; scanning: Scalars["Boolean"]; }; export type MutationSetTractorBeamTargetLabelArgs = { id: Scalars["ID"]; + beam: Scalars["ID"]; label: Scalars["String"]; }; +export type MutationSetTractorBeamCountArgs = { + id: Scalars["ID"]; + beams: Scalars["Int"]; +}; + export type MutationAddTractorTargetArgs = { id: Scalars["ID"]; + beamId: Scalars["ID"]; label?: Maybe; }; export type MutationRemoveTractorTargetArgs = { id: Scalars["ID"]; + beamId: Scalars["ID"]; }; export type MutationSetTransportDestinationArgs = { @@ -9027,23 +9041,29 @@ export type Torpedo = SystemInterface & { export type TractorBeam = SystemInterface & { __typename?: "TractorBeam"; - id?: Maybe; + id: Scalars["ID"]; simulatorId?: Maybe; type?: Maybe; - power?: Maybe; - damage?: Maybe; - name?: Maybe; - displayName?: Maybe; + power: Power; + damage: Damage; + name: Scalars["String"]; + displayName: Scalars["String"]; upgradeName?: Maybe; upgraded?: Maybe; stealthFactor?: Maybe; locations?: Maybe>>; - state?: Maybe; - target?: Maybe; - targetLabel?: Maybe; - strength?: Maybe; - stress?: Maybe; - scanning?: Maybe; + beams: Array; +}; + +export type TractorBeamBeam = { + __typename?: "TractorBeamBeam"; + id: Scalars["ID"]; + state: Scalars["Boolean"]; + target: Scalars["Boolean"]; + targetLabel: Scalars["String"]; + strength: Scalars["Float"]; + stress: Scalars["Float"]; + scanning: Scalars["Boolean"]; }; export type Transporter = SystemInterface & { @@ -9689,6 +9709,7 @@ export type ResolversTypes = ResolversObject<{ Torpedo: ResolverTypeWrapper; Warhead: ResolverTypeWrapper; TractorBeam: ResolverTypeWrapper; + TractorBeamBeam: ResolverTypeWrapper; Transporter: ResolverTypeWrapper; TransporterTarget: ResolverTypeWrapper; Transwarp: ResolverTypeWrapper; @@ -10058,6 +10079,7 @@ export type ResolversParentTypes = ResolversObject<{ Torpedo: Torpedo; Warhead: Warhead; TractorBeam: TractorBeam; + TractorBeamBeam: TractorBeamBeam; Transporter: Transporter; TransporterTarget: TransporterTarget; Transwarp: Transwarp; @@ -17076,49 +17098,64 @@ export type MutationResolvers< Maybe, ParentType, ContextType, - RequireFields + RequireFields >; setTractorBeamTarget?: Resolver< Maybe, ParentType, ContextType, - RequireFields + RequireFields >; setTractorBeamStrength?: Resolver< Maybe, ParentType, ContextType, - RequireFields + RequireFields< + MutationSetTractorBeamStrengthArgs, + "id" | "beam" | "strength" + > >; setTractorBeamStress?: Resolver< Maybe, ParentType, ContextType, - RequireFields + RequireFields >; setTractorBeamScanning?: Resolver< Maybe, ParentType, ContextType, - RequireFields + RequireFields< + MutationSetTractorBeamScanningArgs, + "id" | "beam" | "scanning" + > >; setTractorBeamTargetLabel?: Resolver< Maybe, ParentType, ContextType, - RequireFields + RequireFields< + MutationSetTractorBeamTargetLabelArgs, + "id" | "beam" | "label" + > + >; + setTractorBeamCount?: Resolver< + Maybe, + ParentType, + ContextType, + RequireFields >; addTractorTarget?: Resolver< Maybe, ParentType, ContextType, - RequireFields + RequireFields >; removeTractorTarget?: Resolver< Maybe, ParentType, ContextType, - RequireFields + RequireFields >; setTransportDestination?: Resolver< Maybe, @@ -22077,17 +22114,13 @@ export type TractorBeamResolvers< ContextType = any, ParentType extends ResolversParentTypes["TractorBeam"] = ResolversParentTypes["TractorBeam"] > = ResolversObject<{ - id?: Resolver, ParentType, ContextType>; + id?: Resolver; simulatorId?: Resolver, ParentType, ContextType>; type?: Resolver, ParentType, ContextType>; - power?: Resolver, ParentType, ContextType>; - damage?: Resolver, ParentType, ContextType>; - name?: Resolver, ParentType, ContextType>; - displayName?: Resolver< - Maybe, - ParentType, - ContextType - >; + power?: Resolver; + damage?: Resolver; + name?: Resolver; + displayName?: Resolver; upgradeName?: Resolver< Maybe, ParentType, @@ -22108,23 +22141,28 @@ export type TractorBeamResolvers< ParentType, ContextType >; - state?: Resolver, ParentType, ContextType>; - target?: Resolver, ParentType, ContextType>; - targetLabel?: Resolver< - Maybe, - ParentType, - ContextType - >; - strength?: Resolver, ParentType, ContextType>; - stress?: Resolver, ParentType, ContextType>; - scanning?: Resolver< - Maybe, + beams?: Resolver< + Array, ParentType, ContextType >; __isTypeOf?: isTypeOfResolverFn; }>; +export type TractorBeamBeamResolvers< + ContextType = any, + ParentType extends ResolversParentTypes["TractorBeamBeam"] = ResolversParentTypes["TractorBeamBeam"] +> = ResolversObject<{ + id?: Resolver; + state?: Resolver; + target?: Resolver; + targetLabel?: Resolver; + strength?: Resolver; + stress?: Resolver; + scanning?: Resolver; + __isTypeOf?: isTypeOfResolverFn; +}>; + export type TransporterResolvers< ContextType = any, ParentType extends ResolversParentTypes["Transporter"] = ResolversParentTypes["Transporter"] @@ -22574,6 +22612,7 @@ export type Resolvers = ResolversObject<{ Timer?: TimerResolvers; Torpedo?: TorpedoResolvers; TractorBeam?: TractorBeamResolvers; + TractorBeamBeam?: TractorBeamBeamResolvers; Transporter?: TransporterResolvers; TransporterTarget?: TransporterTargetResolvers; Transwarp?: TranswarpResolvers; diff --git a/server/typeDefs/tractorBeam.ts b/server/typeDefs/tractorBeam.ts index 794e4255e..534d0637c 100644 --- a/server/typeDefs/tractorBeam.ts +++ b/server/typeDefs/tractorBeam.ts @@ -1,39 +1,45 @@ import App from "../app"; import {gql, withFilter} from "apollo-server-express"; import {pubsub} from "../helpers/subscriptionManager"; -const mutationHelper = require("../helpers/mutationHelper").default; +import uuid from "uuid"; +import {TractorBeam} from "../classes"; // We define a schema that encompasses all of the types // necessary for the functionality in this file. const schema = gql` + type TractorBeamBeam { + id: ID! + state: Boolean! + target: Boolean! + targetLabel: String! + strength: Float! + stress: Float! + scanning: Boolean! + } type TractorBeam implements SystemInterface { - id: ID + id: ID! simulatorId: ID type: String - power: Power - damage: Damage - name: String - displayName: String + power: Power! + damage: Damage! + name: String! + displayName: String! upgradeName: String upgraded: Boolean stealthFactor: Float locations: [Room] - state: Boolean - target: Boolean - targetLabel: String - strength: Float - stress: Float - scanning: Boolean + beams: [TractorBeamBeam!]! } extend type Query { tractorBeam(simulatorId: ID): [TractorBeam] } extend type Mutation { - setTractorBeamState(id: ID!, state: Boolean!): String - setTractorBeamTarget(id: ID!, target: Boolean!): String - setTractorBeamStrength(id: ID!, strength: Float!): String - setTractorBeamStress(id: ID!, stress: Float!): String - setTractorBeamScanning(id: ID!, scanning: Boolean!): String - setTractorBeamTargetLabel(id: ID!, label: String!): String + setTractorBeamState(id: ID!, beam: ID!, state: Boolean!): String + setTractorBeamTarget(id: ID!, beam: ID!, target: Boolean!): String + setTractorBeamStrength(id: ID!, beam: ID!, strength: Float!): String + setTractorBeamStress(id: ID!, beam: ID!, stress: Float!): String + setTractorBeamScanning(id: ID!, beam: ID!, scanning: Boolean!): String + setTractorBeamTargetLabel(id: ID!, beam: ID!, label: String!): String + setTractorBeamCount(id: ID!, beams: Int!): String """ Macro: Tractor Beam: Add Target @@ -41,20 +47,33 @@ const schema = gql` - Cards:TractorBeam - Systems:TractorBeam """ - addTractorTarget(id: ID!, label: String): String + addTractorTarget(id: ID!, beamId: ID!, label: String): String """ Macro: Tractor Beam: Remove Target Requires: - Cards:TractorBeam - Systems:TractorBeam """ - removeTractorTarget(id: ID!): String + removeTractorTarget(id: ID!, beamId: ID!): String } extend type Subscription { tractorBeamUpdate(simulatorId: ID): [TractorBeam] } `; +function doAction( + id: string, + beam: string, + action: (sys: TractorBeam) => void, +) { + const system: TractorBeam = App.systems.find(s => s.id === id); + action(system); + pubsub.publish( + "tractorBeamUpdate", + App.systems.filter(s => s.type === "TractorBeam"), + ); +} + const resolver = { Query: { tractorBeam(root, {simulatorId}) { @@ -65,7 +84,106 @@ const resolver = { return returnVal; }, }, - Mutation: mutationHelper(schema), + Mutation: { + setTractorBeamCount(rootValue, {id, beams}) { + doAction(id, null, system => { + system.setBeamCount(beams); + }); + }, + setTractorBeamState: (rootValue, {id, beam, state}) => { + doAction(id, beam, system => { + system.setState(beam, state); + system.setScanning(beam, false); + pubsub.publish("notify", { + id: uuid.v4(), + simulatorId: system.simulatorId, + type: "Tractor Beam", + station: "Core", + title: `Tractor Beam ${state ? "Activated" : "Deactivated"}`, + body: "", + color: "info", + }); + App.handleEvent( + { + simulatorId: system.simulatorId, + component: "TractorBeamCore", + title: `Tractor Beam ${state ? "Activated" : "Deactivated"}`, + body: null, + color: "info", + }, + "addCoreFeed", + ); + }); + }, + setTractorBeamTarget: (rootValue, {id, beam, target}) => { + doAction(id, beam, sys => { + sys.setTarget(beam, target); + sys.setScanning(beam, false); + }); + }, + setTractorBeamStrength: (rootValue, {id, beam, strength}) => { + doAction(id, beam, system => { + system.setStrength(beam, strength); + }); + }, + setTractorBeamStress: (rootValue, {id, beam, stress}) => { + doAction(id, beam, system => { + system.setStress(beam, stress); + }); + }, + setTractorBeamScanning: (rootValue, {id, beam, scanning}) => { + doAction(id, beam, system => { + system.setScanning(beam, scanning); + App.handleEvent( + {simulatorId: system.simulatorId, component: "TractorBeamCore"}, + "addCoreFeed", + ); + }); + }, + setTractorBeamTargetLabel: (rootValue, {id, beam, label}) => { + doAction(id, beam, system => { + system.setTargetLabel(beam, label); + }); + }, + addTractorTarget: (rootValue, {id, simulatorId, beam, label}) => { + let sys: TractorBeam; + if (id) { + sys = App.systems.find(s => s.id === id); + } else { + sys = App.systems.find( + s => s.simulatorId === simulatorId && s.class === "TractorBeam", + ); + } + if (!sys) return; + const beamId = beam || sys.beams[0].id; + sys.setTargetLabel(beamId, label); + sys.setTarget(beamId, true); + sys.setScanning(beamId, false); + pubsub.publish( + "tractorBeamUpdate", + App.systems.filter(s => s.type === "TractorBeam"), + ); + }, + removeTractorTarget: (rootValue, {id, simulatorId, beam, label}) => { + let sys: TractorBeam; + if (id) { + sys = App.systems.find(s => s.id === id); + } else { + sys = App.systems.find( + s => s.simulatorId === simulatorId && s.class === "TractorBeam", + ); + } + if (!sys) return; + const beamId = beam || sys.beams[0].id; + + sys.setTargetLabel(beamId, label); + sys.setTarget(beamId, false); + pubsub.publish( + "tractorBeamUpdate", + App.systems.filter(s => s.type === "TractorBeam"), + ); + }, + }, Subscription: { tractorBeamUpdate: { resolve(rootValue, {simulatorId}) { @@ -75,7 +193,17 @@ const resolver = { return returnRes; }, subscribe: withFilter( - () => pubsub.asyncIterator("tractorBeamUpdate"), + (rootValue, {simulatorId}) => { + const id = uuid.v4(); + process.nextTick(() => { + let returnVal = App.systems.filter(s => s.class === "TractorBeam"); + if (simulatorId) + returnVal = returnVal.filter(s => s.simulatorId === simulatorId); + + pubsub.publish(id, returnVal); + }); + return pubsub.asyncIterator([id, "tractorBeamUpdate"]); + }, rootValue => !!(rootValue && rootValue.length), ), }, diff --git a/src/components/views/TractorBeam/MutliBeam.tsx b/src/components/views/TractorBeam/MutliBeam.tsx new file mode 100644 index 000000000..05ab5e4c0 --- /dev/null +++ b/src/components/views/TractorBeam/MutliBeam.tsx @@ -0,0 +1,279 @@ +/** @jsx jsx */ +import React from "react"; +import {Button} from "helpers/reactstrap"; +import {css, jsx} from "@emotion/core"; +import Beam from "./beam"; +import Target from "./target"; +import "./style.scss"; +import { + Simulator, + TractorBeam as TractorBeamI, + useTractorBeamStrengthMutation, + TractorBeamBeam, +} from "generated/graphql"; +import {useGesture} from "react-use-gesture"; +import useMeasure from "helpers/hooks/useMeasure"; + +const StrengthBar: React.FC<{ + index: number; + state: boolean; + strength: number; + maxPower: number; + beam: string; + id: string; +}> = ({state, index, strength, id, beam, maxPower}) => { + const [str, setStr] = React.useState(strength); + const [ref, dimensions] = useMeasure(); + React.useEffect(() => { + setStr(strength); + }, [strength]); + const [setStrength] = useTractorBeamStrengthMutation(); + const bind = useGesture({ + onDrag: ({xy: [x]}) => { + setStr( + Math.min( + maxPower, + Math.max(0, (x - dimensions.left) / dimensions.width), + ), + ); + }, + onDragEnd: () => { + setStrength({variables: {id, beam, strength: str}}); + }, + }); + + return ( +
+ + Strength: + +
+
+
+
+
+
+
+ ); +}; +const BeamInst: React.FC<{ + index: number; + beam: TractorBeamBeam; + tractorBeam: TractorBeamI; + + maxPower: number; + toggleBeam: (beam: string) => void; +}> = ({index, beam, tractorBeam, maxPower, toggleBeam}) => { + return ( + + 2 ? "3/5" : "8/11"}; + transform: scaleX(${index % 2 === 0 ? -1 : 1}); + width: 100%; + height: 100%; + mask-size: 100% 100%; + mask-image: linear-gradient( + 45deg, + rgba(0, 0, 0, 0) 10%, + rgba(0, 0, 0, 1) 20%, + rgba(0, 0, 0, 1) 100% + ); + `} + shown={beam.state} + /> + +
+ + Stress: + +
+
+
+
+ + +
+ ); +}; +const MultiBeams: React.FC<{ + tractorBeam: TractorBeamI; + simulator: Simulator; + maxPower: number; + toggleBeam: (beam: string) => void; +}> = ({tractorBeam, simulator, maxPower, toggleBeam}) => { + const {assets} = simulator; + + return ( +
+
+
+
+ {tractorBeam.beams.map((b, i) => ( + + ))} +
+ ); +}; + +export default MultiBeams; diff --git a/src/components/views/TractorBeam/OneBeam.tsx b/src/components/views/TractorBeam/OneBeam.tsx new file mode 100644 index 000000000..0e68c0baf --- /dev/null +++ b/src/components/views/TractorBeam/OneBeam.tsx @@ -0,0 +1,130 @@ +/** @jsx jsx */ +import React from "react"; +import {Button} from "helpers/reactstrap"; +import {css, jsx} from "@emotion/core"; +import Beam from "./beam"; +import Target from "./target"; +import Bars from "./bars"; +import "./style.scss"; +import { + Simulator, + TractorBeam as TractorBeamI, + useTractorBeamStrengthMutation, +} from "generated/graphql"; + +const OneBeam: React.FC<{ + tractorBeam: TractorBeamI; + simulator: Simulator; + maxPower: number; + toggleBeam: (beam: string) => void; +}> = ({tractorBeam, simulator, maxPower, toggleBeam}) => { + const beam = tractorBeam.beams[0]; + const {assets} = simulator; + const [setStrength] = useTractorBeamStrengthMutation(); + return ( +
+ + +
+ + + + setStrength({ + variables: { + id: tractorBeam.id, + beam: beam.id, + strength: Math.min(1, Math.max(0, level)), + }, + }) + } + /> + +
+ ); +}; + +export default OneBeam; diff --git a/src/components/views/TractorBeam/arrow.js b/src/components/views/TractorBeam/arrow.tsx similarity index 78% rename from src/components/views/TractorBeam/arrow.js rename to src/components/views/TractorBeam/arrow.tsx index 26601da1e..776848aac 100644 --- a/src/components/views/TractorBeam/arrow.js +++ b/src/components/views/TractorBeam/arrow.tsx @@ -1,23 +1,20 @@ import React from "react"; -const Arrow = ({ - alertLevel, - level = 1, - mouseDown = () => {}, - dimensions, - flop, - connected, -}) => { +const Arrow: React.FC<{ + alertLevel: string; + level?: number; + flop?: boolean; + connected?: boolean; +}> = ({alertLevel, level = 1, flop, connected, ...props}) => { return (
{}; -const Bars = ({ - color, - simulator, - arrow, - flop, - className, - label, - active = true, - noLevel, - level: propsLevel, - max = 0, - mouseMove: mouseMoveProp = noOp, - mouseUp: mouseUpProp = noOp, -}) => { - const [height, setHeight] = React.useState(0); - const [top, setTop] = React.useState(0); - const [level, setLevel] = React.useState(propsLevel); - const [dragging, setDragging] = React.useState(false); - - React.useEffect(() => { - setLevel(propsLevel); - }, [propsLevel]); - - const mouseDown = (dimensions, evt) => { - setHeight(dimensions.height); - setTop(dimensions.top); - setDragging(true); - }; - - React.useEffect(() => { - const mouseMove = e => { - const pageY = - e.clientY || (e.touches && e.touches[0] && e.touches[0].clientY) || 0; - setLevel(Math.max(Math.min((pageY - top) / height, 1), max)); - mouseMoveProp(Math.max(Math.min((pageY - top) / height, 1), max)); - }; - if (dragging) { - document.addEventListener("mousemove", mouseMove); - document.addEventListener("touchmove", mouseMove); - } else { - document.removeEventListener("mousemove", mouseMove); - document.removeEventListener("touchmove", mouseMove); - } - return () => { - document.removeEventListener("mousemove", mouseMove); - document.removeEventListener("touchmove", mouseMove); - }; - }, [dragging, height, max, mouseMoveProp, top]); - - React.useEffect(() => { - const mouseUp = e => { - setDragging(false); - mouseUpProp(level); - }; - if (dragging) { - document.addEventListener("mouseup", mouseUp); - document.addEventListener("touchend", mouseUp); - } else { - document.removeEventListener("mouseup", mouseUp); - document.removeEventListener("touchend", mouseUp); - } - return () => { - document.removeEventListener("mouseup", mouseUp); - document.removeEventListener("touchend", mouseUp); - }; - }, [dragging, level, mouseUpProp]); - - const [measureRef, dimensions] = useMeasure(); - return ( -
- {arrow && ( -
- {dimensions && ( - - )} -
- )} - - {!noLevel && ( -

- {label && label + ": "} - {Math.round(Math.abs(level - 1) * 100) + "%"} -

- )} - -
- {Array(40) - .fill(0) - .map((_, index, array) => { - return ( -
= level ? 1 : 0.3, - backgroundColor: color || null, - width: - (array.length / (index + 2)) * (100 / array.length) + "%", - marginLeft: flop - ? Math.abs( - (array.length / (index + 2)) * (100 / array.length) - - 100, - ) + "%" - : 0, - }} - /> - ); - })} -
-
- ); -}; - -export default Bars; diff --git a/src/components/views/TractorBeam/bars.tsx b/src/components/views/TractorBeam/bars.tsx new file mode 100644 index 000000000..b2784296e --- /dev/null +++ b/src/components/views/TractorBeam/bars.tsx @@ -0,0 +1,113 @@ +import React from "react"; +import Arrow from "./arrow"; +import useMeasure from "helpers/hooks/useMeasure"; +import "./style.scss"; +import {Simulator} from "generated/graphql"; +import {useGesture} from "react-use-gesture"; + +const noOp = () => {}; + +const Bars: React.FC<{ + simulator: Simulator; + color?: string; + arrow?: boolean; + flop?: boolean; + className: string; + label: string; + active?: boolean; + noLevel?: boolean; + level: number; + max?: number; + mouseMove?: (level: number) => void; + mouseUp?: (level: number) => void; +}> = ({ + color, + simulator, + arrow, + flop, + className, + label, + active = true, + noLevel, + level: propsLevel, + max = 1, + mouseMove: mouseMoveProp = noOp, + mouseUp: mouseUpProp = noOp, +}) => { + const [level, setLevel] = React.useState(propsLevel); + + const bind = useGesture({ + onDrag: ({xy: [, y]}) => { + const val = Math.abs( + 1 - + Math.min(max, Math.max(0, (y - dimensions.top) / dimensions.height)), + ); + + setLevel(val); + mouseMoveProp(val); + }, + onDragEnd: () => { + mouseUpProp(level); + }, + }); + + React.useEffect(() => { + setLevel(propsLevel); + }, [propsLevel]); + + const [measureRef, dimensions] = useMeasure(); + return ( +
+ {!noLevel && ( +

+ {label && label + ": "} + {Math.round(level * 100) + "%"} +

+ )} +
+ {arrow && ( +
+ {dimensions && ( + + )} +
+ )} +
+ {Array(40) + .fill(0) + .map((_, index, array) => { + return ( +
= Math.abs(level - 1) ? 1 : 0.3, + backgroundColor: color || undefined, + width: + (array.length / (index + 2)) * (100 / array.length) + "%", + marginLeft: flop + ? Math.abs( + (array.length / (index + 2)) * (100 / array.length) - + 100, + ) + "%" + : 0, + }} + /> + ); + })} +
+
+
+ ); +}; + +export default Bars; diff --git a/src/components/views/TractorBeam/beam.js b/src/components/views/TractorBeam/beam.js deleted file mode 100644 index 72cd1bc64..000000000 --- a/src/components/views/TractorBeam/beam.js +++ /dev/null @@ -1,37 +0,0 @@ -import React, {Component} from "react"; -import {findDOMNode} from "react-dom"; - -export default class Beam extends Component { - draw = () => { - if (!this.animating) return; - this.animation = requestAnimationFrame(this.draw); - const canvas = findDOMNode(this); - const context = canvas.getContext("2d"); - context.clearRect(0, 0, 400, 200); - for (let i = 0; i < 200; i++) { - context.beginPath(); - context.moveTo(400, 0); - context.lineTo(0, 140 + Math.random() * 100); - context.strokeStyle = "rgba(50,180,255," + (Math.random() - 0.25) + ")"; - context.stroke(); - } - }; - componentDidMount() { - this.animating = true; - this.draw(); - } - componentWillUnmount() { - this.animating = false; - cancelAnimationFrame(this.animation); - } - render() { - return ( - - ); - } -} diff --git a/src/components/views/TractorBeam/beam.tsx b/src/components/views/TractorBeam/beam.tsx new file mode 100644 index 000000000..5631a7c75 --- /dev/null +++ b/src/components/views/TractorBeam/beam.tsx @@ -0,0 +1,45 @@ +import React from "react"; +import useMeasure from "helpers/hooks/useMeasure"; + +const Beam: React.FC<{shown: boolean; className?: string}> = ({ + shown, + className = "", +}) => { + const [dimRef, dimensions, canvas] = useMeasure(); + React.useEffect(() => { + let animation: number; + const context = canvas?.getContext("2d"); + const draw = () => { + animation = requestAnimationFrame(draw); + + if (!canvas || !context) return; + canvas.width = dimensions.width; + canvas.height = dimensions.height; + context.clearRect(0, 0, dimensions.width, dimensions.height); + for (let i = 0; i < 200; i++) { + context.beginPath(); + context.moveTo(dimensions.width, 0); + context.lineTo( + 0, + 0.7 * dimensions.height + (Math.random() * dimensions.height) / 2, + ); + context.strokeStyle = "rgba(50,180,255," + (Math.random() - 0.25) + ")"; + context.stroke(); + } + }; + draw(); + return () => { + cancelAnimationFrame(animation); + }; + }, [canvas, dimensions]); + + return ( + + ); +}; + +export default Beam; diff --git a/src/components/views/TractorBeam/core.js b/src/components/views/TractorBeam/core.js deleted file mode 100644 index 5b80f49e0..000000000 --- a/src/components/views/TractorBeam/core.js +++ /dev/null @@ -1,175 +0,0 @@ -import React, {Component} from "react"; -import gql from "graphql-tag.macro"; -import {graphql, withApollo} from "react-apollo"; -import {InputField, OutputField} from "../../generic/core"; -import SubscriptionHelper from "helpers/subscriptionHelper"; -import "./style.scss"; - -export const TRACTORBEAM_CORE_SUB = gql` - subscription TractorBeamUpdate($simulatorId: ID!) { - tractorBeamUpdate(simulatorId: $simulatorId) { - id - state - target - targetLabel - strength - stress - scanning - } - } -`; - -class TractorBeamCore extends Component { - state = { - stress: 0, - }; - targetLabel = label => { - const tractorBeam = this.props.data.tractorBeam[0]; - const mutation = gql` - mutation TractorBeamTargetLabel($id: ID!, $label: String!) { - setTractorBeamTargetLabel(id: $id, label: $label) - } - `; - const variables = { - id: tractorBeam.id, - label, - }; - this.props.client.mutate({ - mutation, - variables, - }); - }; - toggleTractor = (which, state) => { - const tractorBeam = this.props.data.tractorBeam[0]; - let mutation; - const variables = { - id: tractorBeam.id, - state, - }; - if (which === "target") { - mutation = gql` - mutation TractorBeamTarget($id: ID!, $state: Boolean!) { - setTractorBeamTarget(id: $id, target: $state) - } - `; - } - if (which === "state") { - mutation = gql` - mutation TractorBeamState($id: ID!, $state: Boolean!) { - setTractorBeamState(id: $id, state: $state) - } - `; - } - this.props.client.mutate({ - mutation, - variables, - }); - }; - setStress = evt => { - this.setState({ - stress: evt.target.value, - }); - }; - updateStress = () => { - const tractorBeam = this.props.data.tractorBeam[0]; - const mutation = gql` - mutation TractorBeamStress($id: ID!, $stress: Float!) { - setTractorBeamStress(id: $id, stress: $stress) - } - `; - const variables = { - id: tractorBeam.id, - stress: parseFloat(this.state.stress), - }; - this.props.client.mutate({ - mutation, - variables, - }); - }; - render() { - if (this.props.data.loading || !this.props.data.tractorBeam) return null; - const tractorBeam = this.props.data.tractorBeam[0]; - if (!tractorBeam) return

No Tractor Beam

; - return ( -
- - this.props.data.subscribeToMore({ - document: TRACTORBEAM_CORE_SUB, - variables: { - simulatorId: this.props.simulator.id, - }, - updateQuery: (previousResult, {subscriptionData}) => { - return Object.assign({}, previousResult, { - tractorBeam: subscriptionData.data.tractorBeamUpdate, - }); - }, - }) - } - /> - this.toggleTractor("state", !tractorBeam.state)} - > - {tractorBeam.state ? "Active" : "Deactivated"} - - - -
- Target Label: - - {tractorBeam.targetLabel} - -
-
- - -
-
- ); - } -} - -export const TRACTORBEAM_CORE_QUERY = gql` - query TractorBeamInfo($simulatorId: ID!) { - tractorBeam(simulatorId: $simulatorId) { - id - state - target - targetLabel - strength - stress - scanning - } - } -`; -export default graphql(TRACTORBEAM_CORE_QUERY, { - options: ownProps => ({ - fetchPolicy: "cache-and-network", - variables: { - simulatorId: ownProps.simulator.id, - }, - }), -})(withApollo(TractorBeamCore)); diff --git a/src/components/views/TractorBeam/core.tsx b/src/components/views/TractorBeam/core.tsx new file mode 100644 index 000000000..94e136a00 --- /dev/null +++ b/src/components/views/TractorBeam/core.tsx @@ -0,0 +1,110 @@ +/** @jsx jsx */ +import React from "react"; +import {jsx, css} from "@emotion/core"; +import {InputField, OutputField} from "../../generic/core"; +import "./style.scss"; +import { + Simulator, + useTractorBeamUpdateSubscription, + useTractorBeamTargetMutation, + useTractorBeamTargetLabelMutation, + useTractorBeamStressMutation, + useTractorBeamStateMutation, + TractorBeamBeam, +} from "generated/graphql"; + +const Beam: React.FC<{id: string; beam: TractorBeamBeam; index: number}> = ({ + id, + beam, + index, +}) => { + const [stress, setStress] = React.useState(0); + const [setState] = useTractorBeamStateMutation(); + const [setStressMutation] = useTractorBeamStressMutation(); + const [setTarget] = useTractorBeamTargetMutation(); + const [setLabel] = useTractorBeamTargetLabelMutation(); + + return ( +
+

Tractor Beam {index}

+ + setState({variables: {id, beam: beam.id, state: !beam.state}}) + } + > + {beam.state ? "Active" : "Deactivated"} + + + +
+ Target Label: + + setLabel({variables: {id, beam: beam.id, label: String(label)}}) + } + > + {beam.targetLabel} + +
+
+ + +
+
+ ); +}; + +const TractorBeamCore: React.FC<{simulator: Simulator}> = ({simulator}) => { + const {data} = useTractorBeamUpdateSubscription({ + variables: {simulatorId: simulator.id}, + }); + const tractorBeam = data?.tractorBeamUpdate?.[0]; + if (!tractorBeam) return

No Tractor Beam

; + + return ( +
+ {tractorBeam.beams.map((b, i) => ( + + ))} +
+ ); +}; + +export default TractorBeamCore; diff --git a/src/components/views/TractorBeam/index.js b/src/components/views/TractorBeam/index.js deleted file mode 100644 index 7d42360dd..000000000 --- a/src/components/views/TractorBeam/index.js +++ /dev/null @@ -1,205 +0,0 @@ -import React, {Component} from "react"; -import {Container, Button} from "helpers/reactstrap"; -import gql from "graphql-tag.macro"; -import {graphql, withApollo} from "react-apollo"; -import SubscriptionHelper from "helpers/subscriptionHelper"; - -import Beam from "./beam"; -import Target from "./target"; -import Bars from "./bars"; -import DamageOverlay from "../helpers/DamageOverlay"; -import Tour from "helpers/tourHelper"; - -import "./style.scss"; - -export const TRACTORBEAM_SUB = gql` - subscription TractorBeamUpdate($simulatorId: ID!) { - tractorBeamUpdate(simulatorId: $simulatorId) { - id - name - displayName - state - target - targetLabel - strength - stress - damage { - damaged - report - } - power { - power - powerLevels - } - } - } -`; - -class TractorBeam extends Component { - toggleBeam = () => { - const tractorBeam = this.props.data.tractorBeam[0]; - const mutation = gql` - mutation TractorBeamState($id: ID!, $state: Boolean!) { - setTractorBeamState(id: $id, state: $state) - } - `; - const variables = { - id: tractorBeam.id, - state: !tractorBeam.state, - }; - this.props.client.mutate({ - mutation, - variables, - }); - }; - trainingSteps = tractorBeam => [ - { - selector: ".activate", - content: `The ${tractorBeam.displayName || - tractorBeam.name} pulls objects to you with zero-point energy. Once a target it in sight, it will appear below the ship. Press this button to activate the ${tractorBeam.displayName || - tractorBeam.name}.`, - }, - { - selector: ".strengthBar", - content: `The size and speed of the object will impact the stress on the ${tractorBeam.displayName || - tractorBeam.name}. If the object is large, fast, or dense, it will put more stress on our ship, and we will need to strengthen the ${tractorBeam.displayName || - tractorBeam.name} in order to pull in the object. If we pull it in too fast, the object may collide with our ship and cause damage. Use this tool to match the strength of the ${tractorBeam.displayName || - tractorBeam.name} to the stress being put on it.`, - }, - ]; - render() { - if (this.props.data.loading || !this.props.data.tractorBeam) return null; - const tractorBeam = - this.props.data.tractorBeam && this.props.data.tractorBeam[0]; - if (!tractorBeam) return

No Tractor Beam

; - const maxPower = Math.min( - 1, - tractorBeam.power.powerLevels.length - ? (tractorBeam.power.power + 1 - tractorBeam.power.powerLevels[0]) / - (tractorBeam.power.powerLevels[ - tractorBeam.power.powerLevels.length - 1 - ] - - tractorBeam.power.powerLevels[0] + - 1) - : 1, - ); - const {assets} = this.props.simulator; - return ( - - - this.props.data.subscribeToMore({ - document: TRACTORBEAM_SUB, - variables: { - simulatorId: this.props.simulator.id, - }, - updateQuery: (previousResult, {subscriptionData}) => { - return Object.assign({}, previousResult, { - tractorBeam: subscriptionData.data.tractorBeamUpdate, - }); - }, - }) - } - /> - - - -
- - - - this.props.client.mutate({ - mutation: gql` - mutation TractorBeamStrength($id: ID!, $strength: Float!) { - setTractorBeamStrength(id: $id, strength: $strength) - } - `, - variables: { - id: tractorBeam.id, - strength: Math.min(1, Math.max(0, Math.abs(level - 1))), - }, - }) - } - /> - - - - ); - } -} - -export const TRACTORBEAM_QUERY = gql` - query TractorBeamInfo($simulatorId: ID!) { - tractorBeam(simulatorId: $simulatorId) { - id - name - displayName - state - target - targetLabel - strength - stress - damage { - damaged - report - } - power { - power - powerLevels - } - } - } -`; -export default graphql(TRACTORBEAM_QUERY, { - options: ownProps => ({ - fetchPolicy: "cache-and-network", - variables: { - simulatorId: ownProps.simulator.id, - }, - }), -})(withApollo(TractorBeam)); diff --git a/src/components/views/TractorBeam/index.tsx b/src/components/views/TractorBeam/index.tsx new file mode 100644 index 000000000..2c6e9e2c7 --- /dev/null +++ b/src/components/views/TractorBeam/index.tsx @@ -0,0 +1,92 @@ +import React from "react"; +import {Container} from "helpers/reactstrap"; +import DamageOverlay from "../helpers/DamageOverlay"; +import Tour from "helpers/tourHelper"; + +import "./style.scss"; +import { + Simulator, + TractorBeam as TractorBeamI, + useTractorBeamUpdateSubscription, + useTractorBeamStateMutation, +} from "generated/graphql"; +import OneBeam from "./OneBeam"; +import MultiBeams from "./MutliBeam"; + +const trainingSteps = ( + tractorBeam: Pick, +) => [ + { + selector: ".activate", + content: `The ${tractorBeam.displayName || + tractorBeam.name} pulls objects to you with zero-point energy. Once a target it in sight, it will appear below the ship. Press this button to activate the ${tractorBeam.displayName || + tractorBeam.name}.`, + }, + { + selector: ".strengthBar", + content: `The size and speed of the object will impact the stress on the ${tractorBeam.displayName || + tractorBeam.name}. If the object is large, fast, or dense, it will put more stress on our ship, and we will need to strengthen the ${tractorBeam.displayName || + tractorBeam.name} in order to pull in the object. If we pull it in too fast, the object may collide with our ship and cause damage. Use this tool to match the strength of the ${tractorBeam.displayName || + tractorBeam.name} to the stress being put on it.`, + }, +]; + +function isNumber(l: unknown): l is number { + return typeof l === "number"; +} + +const TractorBeam: React.FC<{simulator: Simulator}> = ({simulator}) => { + const {data} = useTractorBeamUpdateSubscription({ + variables: {simulatorId: simulator.id}, + }); + const [setState] = useTractorBeamStateMutation(); + const tractorBeam = data?.tractorBeamUpdate?.[0]; + if (!tractorBeam) return

No Tractor Beam

; + const toggleBeam = (beam: string) => { + setState({ + variables: { + id: tractorBeam.id, + beam, + state: !tractorBeam.beams.find(b => b.id === beam)?.state, + }, + }); + }; + + const powerLength = tractorBeam.power.powerLevels?.length || 0; + const power = tractorBeam.power.power || 0; + const levels = tractorBeam.power.powerLevels?.filter(isNumber) || [0]; + const maxPower = Math.min( + 1, + powerLength + ? (power + 1 - levels[0]) / (levels[powerLength - 1] - levels[0] + 1) + : 1, + ); + + // const beamCount = tractorBeam.beams.length; + return ( + + + {tractorBeam.beams.length === 1 ? ( + + ) : ( + + )} + + + ); +}; + +export default TractorBeam; diff --git a/src/components/views/TractorBeam/queries/tractorBeamLabel.graphql b/src/components/views/TractorBeam/queries/tractorBeamLabel.graphql new file mode 100644 index 000000000..202221343 --- /dev/null +++ b/src/components/views/TractorBeam/queries/tractorBeamLabel.graphql @@ -0,0 +1,3 @@ +mutation TractorBeamTargetLabel($id: ID!, $beam: ID!, $label: String!) { + setTractorBeamTargetLabel(id: $id, beam: $beam, label: $label) +} diff --git a/src/components/views/TractorBeam/queries/tractorBeamState.graphql b/src/components/views/TractorBeam/queries/tractorBeamState.graphql new file mode 100644 index 000000000..cdc2d4ac4 --- /dev/null +++ b/src/components/views/TractorBeam/queries/tractorBeamState.graphql @@ -0,0 +1,3 @@ +mutation TractorBeamState($id: ID!, $beam: ID!, $state: Boolean!) { + setTractorBeamState(id: $id, beam: $beam, state: $state) +} diff --git a/src/components/views/TractorBeam/queries/tractorBeamStrength.graphql b/src/components/views/TractorBeam/queries/tractorBeamStrength.graphql new file mode 100644 index 000000000..ac3accf50 --- /dev/null +++ b/src/components/views/TractorBeam/queries/tractorBeamStrength.graphql @@ -0,0 +1,3 @@ +mutation TractorBeamStrength($id: ID!, $beam: ID!, $strength: Float!) { + setTractorBeamStrength(id: $id, beam: $beam, strength: $strength) +} diff --git a/src/components/views/TractorBeam/queries/tractorBeamStress.graphql b/src/components/views/TractorBeam/queries/tractorBeamStress.graphql new file mode 100644 index 000000000..26be1208d --- /dev/null +++ b/src/components/views/TractorBeam/queries/tractorBeamStress.graphql @@ -0,0 +1,3 @@ +mutation TractorBeamStress($id: ID!, $beam: ID!, $stress: Float!) { + setTractorBeamStress(id: $id, beam: $beam, stress: $stress) +} diff --git a/src/components/views/TractorBeam/queries/tractorBeamSub.graphql b/src/components/views/TractorBeam/queries/tractorBeamSub.graphql new file mode 100644 index 000000000..49904e47c --- /dev/null +++ b/src/components/views/TractorBeam/queries/tractorBeamSub.graphql @@ -0,0 +1,24 @@ +subscription TractorBeamUpdate($simulatorId: ID!) { + tractorBeamUpdate(simulatorId: $simulatorId) { + id + name + displayName + beams { + id + state + target + targetLabel + strength + stress + scanning + } + damage { + damaged + report + } + power { + power + powerLevels + } + } +} diff --git a/src/components/views/TractorBeam/queries/tractorBeamTarget.graphql b/src/components/views/TractorBeam/queries/tractorBeamTarget.graphql new file mode 100644 index 000000000..00f5552fd --- /dev/null +++ b/src/components/views/TractorBeam/queries/tractorBeamTarget.graphql @@ -0,0 +1,3 @@ +mutation TractorBeamTarget($id: ID!, $beam: ID!, $state: Boolean!) { + setTractorBeamTarget(id: $id, beam: $beam, target: $state) +} diff --git a/src/components/views/TractorBeam/style.scss b/src/components/views/TractorBeam/style.scss index f51076e98..a8a250080 100644 --- a/src/components/views/TractorBeam/style.scss +++ b/src/components/views/TractorBeam/style.scss @@ -1,36 +1,16 @@ .tractor-beam { height: 100%; - .ship-side { - position: absolute; - right: 10%; - bottom: 54%; - width: 60%; - } + #tractorEffect { - position: absolute; - top: 43%; - right: 56%; - -webkit-transition: opacity 1s ease-in-out; - -webkit-mask-size: 400px 400px; - -webkit-mask-image: -webkit-gradient( - linear, - left bottom, - right top, - color-stop(0.4, rgba(0, 0, 0, 0)), - color-stop(0.6, rgba(0, 0, 0, 1)), - color-stop(1, rgba(0, 0, 0, 1)) - ); + transition: opacity 1s ease-in-out; + pointer-events: none; opacity: 0; &.shown { opacity: 1; } } .target { - position: absolute; - width: 8%; - top: 52%; - right: 71%; - -webkit-transition: opacity 1s ease-in-out; + transition: opacity 1s ease-in-out; opacity: 0; &.shown { opacity: 1; @@ -42,35 +22,11 @@ width: 100%; } } - .activate { - position: absolute; - width: 30%; - top: 80%; - } - .stressBar { - position: absolute; - bottom: 5%; - right: 33%; - } - .strengthBar { - position: absolute; - bottom: 5%; - right: 0%; - } + .barLabel { font-size: 24px; - position: absolute; + text-align: center; - top: 50%; - bottom: 50%; - left: 50%; - right: 50%; - } - @media (width: 1024px) { - .target { - top: 52%; - right: 75%; - } } } .tractor-beam-core { @@ -83,7 +39,7 @@ .bar-container { position: relative; opacity: 0; - -webkit-transition: opacity 1s ease-in-out; + transition: opacity 1s ease-in-out; &.shown { opacity: 1; } @@ -96,6 +52,7 @@ position: absolute; height: 100%; left: -50px; + bottom: 0; } .arrow-container.flop { right: -50px; diff --git a/src/components/views/TractorBeam/target.js b/src/components/views/TractorBeam/target.tsx similarity index 82% rename from src/components/views/TractorBeam/target.js rename to src/components/views/TractorBeam/target.tsx index 7c933e315..230647b5f 100644 --- a/src/components/views/TractorBeam/target.js +++ b/src/components/views/TractorBeam/target.tsx @@ -1,14 +1,18 @@ import React from "react"; -export default ({shown, label}) => { +const Target: React.FC<{ + shown: boolean; + className?: string; + label?: string; +}> = ({shown, className, label = ""}) => { return ( -
+
{
); }; + +export default Target; diff --git a/src/containers/FlightDirector/SimulatorConfig/config/Systems.js b/src/containers/FlightDirector/SimulatorConfig/config/Systems.js index 4484bc47d..e78a29194 100644 --- a/src/containers/FlightDirector/SimulatorConfig/config/Systems.js +++ b/src/containers/FlightDirector/SimulatorConfig/config/Systems.js @@ -1,4 +1,6 @@ +/** @jsx jsx */ import React, {Component} from "react"; +import {jsx, css} from "@emotion/core"; import { Container, Row, @@ -7,6 +9,7 @@ import { CardBody, Button, ButtonGroup, + Input, } from "helpers/reactstrap"; import {capitalCase, camelCase} from "change-case"; import {Query, Mutation} from "react-apollo"; @@ -118,9 +121,8 @@ const reconfigureShields = (num, id) => { }; class SystemsConfig extends Component { state = {}; - addSystem = action => () => { + addSystem = (action, addSystem) => { const {id} = this.props.selectedSimulator; - const {addSystem} = this.state; this.setState({addSystem: null}); if (addSystem.indexOf("Shield") > -1) { // Create based on the shield count @@ -189,15 +191,15 @@ class SystemsConfig extends Component { ? Configs[selectedType] || Configs.Generic : () => null; return ( - + {({data, loading}) => { if (loading) return null; return ( - +
Available Systems
- - - - {systems.map(s => ( - this.setState({addSystem: s})} - /> - ))} - - - - {action => ( - + + {systems.map(s => ( + + ))} + )} ( )} - +
Installed Systems
diff --git a/src/containers/FlightDirector/SimulatorConfig/config/systemsConfig/TractorBeam.tsx b/src/containers/FlightDirector/SimulatorConfig/config/systemsConfig/TractorBeam.tsx new file mode 100644 index 000000000..feba06235 --- /dev/null +++ b/src/containers/FlightDirector/SimulatorConfig/config/systemsConfig/TractorBeam.tsx @@ -0,0 +1,59 @@ +import React from "react"; +import {FormGroup, Label} from "helpers/reactstrap"; +import GenericSystemConfig from "./Generic"; +import { + useTractorBeamUpdateSubscription, + useTractorBeamSetCountMutation, +} from "generated/graphql"; +import {Button} from "reactstrap"; + +const TractorBeam = (props: any) => { + const {simulatorId} = props; + const {data} = useTractorBeamUpdateSubscription({variables: {simulatorId}}); + const [setCount] = useTractorBeamSetCountMutation(); + + const tractorBeam = data?.tractorBeamUpdate?.[0]; + return ( + + {tractorBeam && ( + +
+ +
+
+ )} +
+ ); +}; +export default TractorBeam; diff --git a/src/containers/FlightDirector/SimulatorConfig/config/systemsConfig/index.js b/src/containers/FlightDirector/SimulatorConfig/config/systemsConfig/index.js index d1180f9e3..88a60fe29 100644 --- a/src/containers/FlightDirector/SimulatorConfig/config/systemsConfig/index.js +++ b/src/containers/FlightDirector/SimulatorConfig/config/systemsConfig/index.js @@ -14,3 +14,4 @@ export {default as Targeting} from "./Targeting"; export {default as ComputerCore} from "./ComputerCore"; export {default as Crm} from "./CRM"; export {default as SignalJammer} from "./SignalJammer"; +export {default as TractorBeam} from "./TractorBeam"; diff --git a/src/containers/FlightDirector/SimulatorConfig/config/systemsConfig/queries/setTractorBeamCount.graphql b/src/containers/FlightDirector/SimulatorConfig/config/systemsConfig/queries/setTractorBeamCount.graphql new file mode 100644 index 000000000..0900e0fcf --- /dev/null +++ b/src/containers/FlightDirector/SimulatorConfig/config/systemsConfig/queries/setTractorBeamCount.graphql @@ -0,0 +1,3 @@ +mutation TractorBeamSetCount($id: ID!, $beams: Int!) { + setTractorBeamCount(id: $id, beams: $beams) +} diff --git a/src/generated/graphql.tsx b/src/generated/graphql.tsx index acd359e52..3796bdcc9 100644 --- a/src/generated/graphql.tsx +++ b/src/generated/graphql.tsx @@ -2368,6 +2368,7 @@ export type Mutation = { setTractorBeamStress?: Maybe, setTractorBeamScanning?: Maybe, setTractorBeamTargetLabel?: Maybe, + setTractorBeamCount?: Maybe, addTractorTarget?: Maybe, removeTractorTarget?: Maybe, setTransportDestination?: Maybe, @@ -6496,48 +6497,62 @@ export type MutationTorpedoFireArgs = { export type MutationSetTractorBeamStateArgs = { id: Scalars['ID'], + beam: Scalars['ID'], state: Scalars['Boolean'] }; export type MutationSetTractorBeamTargetArgs = { id: Scalars['ID'], + beam: Scalars['ID'], target: Scalars['Boolean'] }; export type MutationSetTractorBeamStrengthArgs = { id: Scalars['ID'], + beam: Scalars['ID'], strength: Scalars['Float'] }; export type MutationSetTractorBeamStressArgs = { id: Scalars['ID'], + beam: Scalars['ID'], stress: Scalars['Float'] }; export type MutationSetTractorBeamScanningArgs = { id: Scalars['ID'], + beam: Scalars['ID'], scanning: Scalars['Boolean'] }; export type MutationSetTractorBeamTargetLabelArgs = { id: Scalars['ID'], + beam: Scalars['ID'], label: Scalars['String'] }; +export type MutationSetTractorBeamCountArgs = { + id: Scalars['ID'], + beams: Scalars['Int'] +}; + + export type MutationAddTractorTargetArgs = { id: Scalars['ID'], + beamId: Scalars['ID'], label?: Maybe }; export type MutationRemoveTractorTargetArgs = { - id: Scalars['ID'] + id: Scalars['ID'], + beamId: Scalars['ID'] }; @@ -9943,23 +9958,29 @@ export type Torpedo = SystemInterface & { export type TractorBeam = SystemInterface & { __typename?: 'TractorBeam', - id?: Maybe, + id: Scalars['ID'], simulatorId?: Maybe, type?: Maybe, - power?: Maybe, - damage?: Maybe, - name?: Maybe, - displayName?: Maybe, + power: Power, + damage: Damage, + name: Scalars['String'], + displayName: Scalars['String'], upgradeName?: Maybe, upgraded?: Maybe, stealthFactor?: Maybe, locations?: Maybe>>, - state?: Maybe, - target?: Maybe, - targetLabel?: Maybe, - strength?: Maybe, - stress?: Maybe, - scanning?: Maybe, + beams: Array, +}; + +export type TractorBeamBeam = { + __typename?: 'TractorBeamBeam', + id: Scalars['ID'], + state: Scalars['Boolean'], + target: Scalars['Boolean'], + targetLabel: Scalars['String'], + strength: Scalars['Float'], + stress: Scalars['Float'], + scanning: Scalars['Boolean'], }; export type Transporter = SystemInterface & { @@ -11597,6 +11618,89 @@ export type TimelineMissionSubscription = ( )> } ); +export type TractorBeamTargetLabelMutationVariables = { + id: Scalars['ID']; + beam: Scalars['ID']; + label: Scalars['String']; +}; + + +export type TractorBeamTargetLabelMutation = ( + { __typename?: 'Mutation' } + & Pick +); + +export type TractorBeamStateMutationVariables = { + id: Scalars['ID']; + beam: Scalars['ID']; + state: Scalars['Boolean']; +}; + + +export type TractorBeamStateMutation = ( + { __typename?: 'Mutation' } + & Pick +); + +export type TractorBeamStrengthMutationVariables = { + id: Scalars['ID']; + beam: Scalars['ID']; + strength: Scalars['Float']; +}; + + +export type TractorBeamStrengthMutation = ( + { __typename?: 'Mutation' } + & Pick +); + +export type TractorBeamStressMutationVariables = { + id: Scalars['ID']; + beam: Scalars['ID']; + stress: Scalars['Float']; +}; + + +export type TractorBeamStressMutation = ( + { __typename?: 'Mutation' } + & Pick +); + +export type TractorBeamUpdateSubscriptionVariables = { + simulatorId: Scalars['ID']; +}; + + +export type TractorBeamUpdateSubscription = ( + { __typename?: 'Subscription' } + & { tractorBeamUpdate?: Maybe + & { beams: Array<( + { __typename?: 'TractorBeamBeam' } + & Pick + )>, damage: ( + { __typename?: 'Damage' } + & Pick + ), power: ( + { __typename?: 'Power' } + & Pick + ) } + )>>> } +); + +export type TractorBeamTargetMutationVariables = { + id: Scalars['ID']; + beam: Scalars['ID']; + state: Scalars['Boolean']; +}; + + +export type TractorBeamTargetMutation = ( + { __typename?: 'Mutation' } + & Pick +); + export type ClientChangedSubscriptionVariables = {}; @@ -12814,6 +12918,17 @@ export type ReactorSetWingsMutation = ( & Pick ); +export type TractorBeamSetCountMutationVariables = { + id: Scalars['ID']; + beams: Scalars['Int']; +}; + + +export type TractorBeamSetCountMutation = ( + { __typename?: 'Mutation' } + & Pick +); + export type RemoveSimulatorMutationVariables = { id: Scalars['ID']; }; @@ -16751,6 +16866,214 @@ export function useTimelineMissionSubscription(baseOptions?: ApolloReactHooks.Su } export type TimelineMissionSubscriptionHookResult = ReturnType; export type TimelineMissionSubscriptionResult = ApolloReactCommon.SubscriptionResult; +export const TractorBeamTargetLabelDocument = gql` + mutation TractorBeamTargetLabel($id: ID!, $beam: ID!, $label: String!) { + setTractorBeamTargetLabel(id: $id, beam: $beam, label: $label) +} + `; +export type TractorBeamTargetLabelMutationFn = ApolloReactCommon.MutationFunction; + +/** + * __useTractorBeamTargetLabelMutation__ + * + * To run a mutation, you first call `useTractorBeamTargetLabelMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useTractorBeamTargetLabelMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [tractorBeamTargetLabelMutation, { data, loading, error }] = useTractorBeamTargetLabelMutation({ + * variables: { + * id: // value for 'id' + * beam: // value for 'beam' + * label: // value for 'label' + * }, + * }); + */ +export function useTractorBeamTargetLabelMutation(baseOptions?: ApolloReactHooks.MutationHookOptions) { + return ApolloReactHooks.useMutation(TractorBeamTargetLabelDocument, baseOptions); + } +export type TractorBeamTargetLabelMutationHookResult = ReturnType; +export type TractorBeamTargetLabelMutationResult = ApolloReactCommon.MutationResult; +export type TractorBeamTargetLabelMutationOptions = ApolloReactCommon.BaseMutationOptions; +export const TractorBeamStateDocument = gql` + mutation TractorBeamState($id: ID!, $beam: ID!, $state: Boolean!) { + setTractorBeamState(id: $id, beam: $beam, state: $state) +} + `; +export type TractorBeamStateMutationFn = ApolloReactCommon.MutationFunction; + +/** + * __useTractorBeamStateMutation__ + * + * To run a mutation, you first call `useTractorBeamStateMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useTractorBeamStateMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [tractorBeamStateMutation, { data, loading, error }] = useTractorBeamStateMutation({ + * variables: { + * id: // value for 'id' + * beam: // value for 'beam' + * state: // value for 'state' + * }, + * }); + */ +export function useTractorBeamStateMutation(baseOptions?: ApolloReactHooks.MutationHookOptions) { + return ApolloReactHooks.useMutation(TractorBeamStateDocument, baseOptions); + } +export type TractorBeamStateMutationHookResult = ReturnType; +export type TractorBeamStateMutationResult = ApolloReactCommon.MutationResult; +export type TractorBeamStateMutationOptions = ApolloReactCommon.BaseMutationOptions; +export const TractorBeamStrengthDocument = gql` + mutation TractorBeamStrength($id: ID!, $beam: ID!, $strength: Float!) { + setTractorBeamStrength(id: $id, beam: $beam, strength: $strength) +} + `; +export type TractorBeamStrengthMutationFn = ApolloReactCommon.MutationFunction; + +/** + * __useTractorBeamStrengthMutation__ + * + * To run a mutation, you first call `useTractorBeamStrengthMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useTractorBeamStrengthMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [tractorBeamStrengthMutation, { data, loading, error }] = useTractorBeamStrengthMutation({ + * variables: { + * id: // value for 'id' + * beam: // value for 'beam' + * strength: // value for 'strength' + * }, + * }); + */ +export function useTractorBeamStrengthMutation(baseOptions?: ApolloReactHooks.MutationHookOptions) { + return ApolloReactHooks.useMutation(TractorBeamStrengthDocument, baseOptions); + } +export type TractorBeamStrengthMutationHookResult = ReturnType; +export type TractorBeamStrengthMutationResult = ApolloReactCommon.MutationResult; +export type TractorBeamStrengthMutationOptions = ApolloReactCommon.BaseMutationOptions; +export const TractorBeamStressDocument = gql` + mutation TractorBeamStress($id: ID!, $beam: ID!, $stress: Float!) { + setTractorBeamStress(id: $id, beam: $beam, stress: $stress) +} + `; +export type TractorBeamStressMutationFn = ApolloReactCommon.MutationFunction; + +/** + * __useTractorBeamStressMutation__ + * + * To run a mutation, you first call `useTractorBeamStressMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useTractorBeamStressMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [tractorBeamStressMutation, { data, loading, error }] = useTractorBeamStressMutation({ + * variables: { + * id: // value for 'id' + * beam: // value for 'beam' + * stress: // value for 'stress' + * }, + * }); + */ +export function useTractorBeamStressMutation(baseOptions?: ApolloReactHooks.MutationHookOptions) { + return ApolloReactHooks.useMutation(TractorBeamStressDocument, baseOptions); + } +export type TractorBeamStressMutationHookResult = ReturnType; +export type TractorBeamStressMutationResult = ApolloReactCommon.MutationResult; +export type TractorBeamStressMutationOptions = ApolloReactCommon.BaseMutationOptions; +export const TractorBeamUpdateDocument = gql` + subscription TractorBeamUpdate($simulatorId: ID!) { + tractorBeamUpdate(simulatorId: $simulatorId) { + id + name + displayName + beams { + id + state + target + targetLabel + strength + stress + scanning + } + damage { + damaged + report + } + power { + power + powerLevels + } + } +} + `; + +/** + * __useTractorBeamUpdateSubscription__ + * + * To run a query within a React component, call `useTractorBeamUpdateSubscription` and pass it any options that fit your needs. + * When your component renders, `useTractorBeamUpdateSubscription` returns an object from Apollo Client that contains loading, error, and data properties + * you can use to render your UI. + * + * @param baseOptions options that will be passed into the subscription, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options; + * + * @example + * const { data, loading, error } = useTractorBeamUpdateSubscription({ + * variables: { + * simulatorId: // value for 'simulatorId' + * }, + * }); + */ +export function useTractorBeamUpdateSubscription(baseOptions?: ApolloReactHooks.SubscriptionHookOptions) { + return ApolloReactHooks.useSubscription(TractorBeamUpdateDocument, baseOptions); + } +export type TractorBeamUpdateSubscriptionHookResult = ReturnType; +export type TractorBeamUpdateSubscriptionResult = ApolloReactCommon.SubscriptionResult; +export const TractorBeamTargetDocument = gql` + mutation TractorBeamTarget($id: ID!, $beam: ID!, $state: Boolean!) { + setTractorBeamTarget(id: $id, beam: $beam, target: $state) +} + `; +export type TractorBeamTargetMutationFn = ApolloReactCommon.MutationFunction; + +/** + * __useTractorBeamTargetMutation__ + * + * To run a mutation, you first call `useTractorBeamTargetMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useTractorBeamTargetMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [tractorBeamTargetMutation, { data, loading, error }] = useTractorBeamTargetMutation({ + * variables: { + * id: // value for 'id' + * beam: // value for 'beam' + * state: // value for 'state' + * }, + * }); + */ +export function useTractorBeamTargetMutation(baseOptions?: ApolloReactHooks.MutationHookOptions) { + return ApolloReactHooks.useMutation(TractorBeamTargetDocument, baseOptions); + } +export type TractorBeamTargetMutationHookResult = ReturnType; +export type TractorBeamTargetMutationResult = ApolloReactCommon.MutationResult; +export type TractorBeamTargetMutationOptions = ApolloReactCommon.BaseMutationOptions; export const ClientChangedDocument = gql` subscription ClientChanged { clientChanged { @@ -19881,6 +20204,37 @@ export function useReactorSetWingsMutation(baseOptions?: ApolloReactHooks.Mutati export type ReactorSetWingsMutationHookResult = ReturnType; export type ReactorSetWingsMutationResult = ApolloReactCommon.MutationResult; export type ReactorSetWingsMutationOptions = ApolloReactCommon.BaseMutationOptions; +export const TractorBeamSetCountDocument = gql` + mutation TractorBeamSetCount($id: ID!, $beams: Int!) { + setTractorBeamCount(id: $id, beams: $beams) +} + `; +export type TractorBeamSetCountMutationFn = ApolloReactCommon.MutationFunction; + +/** + * __useTractorBeamSetCountMutation__ + * + * To run a mutation, you first call `useTractorBeamSetCountMutation` within a React component and pass it any options that fit your needs. + * When your component renders, `useTractorBeamSetCountMutation` returns a tuple that includes: + * - A mutate function that you can call at any time to execute the mutation + * - An object with fields that represent the current status of the mutation's execution + * + * @param baseOptions options that will be passed into the mutation, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options-2; + * + * @example + * const [tractorBeamSetCountMutation, { data, loading, error }] = useTractorBeamSetCountMutation({ + * variables: { + * id: // value for 'id' + * beams: // value for 'beams' + * }, + * }); + */ +export function useTractorBeamSetCountMutation(baseOptions?: ApolloReactHooks.MutationHookOptions) { + return ApolloReactHooks.useMutation(TractorBeamSetCountDocument, baseOptions); + } +export type TractorBeamSetCountMutationHookResult = ReturnType; +export type TractorBeamSetCountMutationResult = ApolloReactCommon.MutationResult; +export type TractorBeamSetCountMutationOptions = ApolloReactCommon.BaseMutationOptions; export const RemoveSimulatorDocument = gql` mutation RemoveSimulator($id: ID!) { removeSimulator(simulatorId: $id) diff --git a/src/helpers/hooks/useMeasure.ts b/src/helpers/hooks/useMeasure.ts index 2c0da9ac2..1cef757d3 100644 --- a/src/helpers/hooks/useMeasure.ts +++ b/src/helpers/hooks/useMeasure.ts @@ -1,6 +1,6 @@ import {useState, useCallback, useLayoutEffect} from "react"; -interface Dimensions { +export interface Dimensions { width: number; height: number; top: number; @@ -29,7 +29,7 @@ function getDimensionObject(node: T): Dimensions { } } -function useDimensions(): [ +function useMeasure(): [ (node: Element) => void, Dimensions, Element | undefined, @@ -71,4 +71,4 @@ function useDimensions(): [ return [ref, dimensions, node]; } -export default useDimensions; +export default useMeasure; diff --git a/src/schema.graphql b/src/schema.graphql index 018d5efed..af4b31c8e 100644 --- a/src/schema.graphql +++ b/src/schema.graphql @@ -2616,12 +2616,13 @@ type Mutation { torpedoSetWarheadCount(id: ID!, warheadType: String!, count: Int!): String torpedoUnload(id: ID!): String torpedoFire(id: ID!): String - setTractorBeamState(id: ID!, state: Boolean!): String - setTractorBeamTarget(id: ID!, target: Boolean!): String - setTractorBeamStrength(id: ID!, strength: Float!): String - setTractorBeamStress(id: ID!, stress: Float!): String - setTractorBeamScanning(id: ID!, scanning: Boolean!): String - setTractorBeamTargetLabel(id: ID!, label: String!): String + setTractorBeamState(id: ID!, beam: ID!, state: Boolean!): String + setTractorBeamTarget(id: ID!, beam: ID!, target: Boolean!): String + setTractorBeamStrength(id: ID!, beam: ID!, strength: Float!): String + setTractorBeamStress(id: ID!, beam: ID!, stress: Float!): String + setTractorBeamScanning(id: ID!, beam: ID!, scanning: Boolean!): String + setTractorBeamTargetLabel(id: ID!, beam: ID!, label: String!): String + setTractorBeamCount(id: ID!, beams: Int!): String """ Macro: Tractor Beam: Add Target @@ -2629,7 +2630,7 @@ type Mutation { - Cards:TractorBeam - Systems:TractorBeam """ - addTractorTarget(id: ID!, label: String): String + addTractorTarget(id: ID!, beamId: ID!, label: String): String """ Macro: Tractor Beam: Remove Target @@ -2637,7 +2638,7 @@ type Mutation { - Cards:TractorBeam - Systems:TractorBeam """ - removeTractorTarget(id: ID!): String + removeTractorTarget(id: ID!, beamId: ID!): String setTransportDestination(transporter: ID!, destination: String!): String setTransportTarget(transporter: ID!, target: String!): String beginTransportScan(transporter: ID!): String @@ -4561,23 +4562,28 @@ type Torpedo implements SystemInterface { } type TractorBeam implements SystemInterface { - id: ID + id: ID! simulatorId: ID type: String - power: Power - damage: Damage - name: String - displayName: String + power: Power! + damage: Damage! + name: String! + displayName: String! upgradeName: String upgraded: Boolean stealthFactor: Float locations: [Room] - state: Boolean - target: Boolean - targetLabel: String - strength: Float - stress: Float - scanning: Boolean + beams: [TractorBeamBeam!]! +} + +type TractorBeamBeam { + id: ID! + state: Boolean! + target: Boolean! + targetLabel: String! + strength: Float! + stress: Float! + scanning: Boolean! } type Transporter implements SystemInterface { From bade25ab156fc9dbf7dd4fa9d9658bf6a29c578a Mon Sep 17 00:00:00 2001 From: Alex Anderson Date: Sat, 9 May 2020 13:52:55 -0600 Subject: [PATCH 3/4] Fixes --- src/components/views/TractorBeam/TractorBeam.test.js | 6 +++--- src/components/views/TractorBeam/TractorBeamCore.test.js | 5 +++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/components/views/TractorBeam/TractorBeam.test.js b/src/components/views/TractorBeam/TractorBeam.test.js index ed2625fbe..4213803da 100644 --- a/src/components/views/TractorBeam/TractorBeam.test.js +++ b/src/components/views/TractorBeam/TractorBeam.test.js @@ -2,11 +2,11 @@ import React from "react"; import {waitForElementToBeRemoved, wait} from "@testing-library/react"; import render from "../../../helpers/testHelper"; import baseProps from "../../../stories/helpers/baseProps"; -import Component, {TRACTORBEAM_QUERY, TRACTORBEAM_SUB} from "./index"; - +import Component from "./index"; +import {TractorBeamUpdateDocument} from "generated/graphql"; it("should render", async () => { const {container, getByText} = render(, { - queries: [TRACTORBEAM_QUERY, TRACTORBEAM_SUB], + queries: [TractorBeamUpdateDocument], }); await waitForElementToBeRemoved(() => getByText("Loading...")); await wait(); diff --git a/src/components/views/TractorBeam/TractorBeamCore.test.js b/src/components/views/TractorBeam/TractorBeamCore.test.js index 9479232a9..eed69a34a 100644 --- a/src/components/views/TractorBeam/TractorBeamCore.test.js +++ b/src/components/views/TractorBeam/TractorBeamCore.test.js @@ -2,11 +2,12 @@ import React from "react"; import {waitForElementToBeRemoved, wait} from "@testing-library/react"; import render from "../../../helpers/testHelper"; import baseProps from "../../../stories/helpers/baseProps"; -import Core, {TRACTORBEAM_CORE_QUERY, TRACTORBEAM_CORE_SUB} from "./core"; +import Core from "./core"; +import {TractorBeamUpdateDocument} from "generated/graphql"; it("should render", async () => { const {container, getByText} = render(, { - queries: [TRACTORBEAM_CORE_QUERY, TRACTORBEAM_CORE_SUB], + queries: [TractorBeamUpdateDocument], }); await waitForElementToBeRemoved(() => getByText("Loading...")); await wait(); From 97be7ad0074964c3bd9e5e4c791badc36db4deac Mon Sep 17 00:00:00 2001 From: Alex Anderson Date: Sat, 9 May 2020 14:07:42 -0600 Subject: [PATCH 4/4] Moar fixes --- src/components/views/PowerDistribution/index.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/components/views/PowerDistribution/index.js b/src/components/views/PowerDistribution/index.js index 169858025..357e00b5e 100644 --- a/src/components/views/PowerDistribution/index.js +++ b/src/components/views/PowerDistribution/index.js @@ -161,7 +161,7 @@ const PowerDistribution = ({client, simulator, clientObj, wing = null}) => {
)}
@@ -243,7 +243,8 @@ const Systems = React.memo( const Summary = ({battery, reactor, powerTotal, wing}) => { const wingPower = reactor?.hasWings && wing ? reactor?.[`${wing}WingPower`] : 0; - const reactorPower = Math.round(reactor.efficiency * reactor.powerOutput); + const reactorPower = + Math.round(reactor?.efficiency * reactor?.powerOutput) || 0; return (