diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml
index 14cf99ca5..92bf792c9 100644
--- a/.pre-commit-config.yaml
+++ b/.pre-commit-config.yaml
@@ -9,9 +9,12 @@ repos:
rev: v2.2.1
hooks:
- id: prettier
- types: [javascript]
+ files: \.[j]sx?$ # *.js and *.jsx
+ types: [file]
- repo: https://github.com/pre-commit/mirrors-eslint
rev: v7.19.0
hooks:
- - id: eslint
\ No newline at end of file
+ - id: eslint
+ files: \.[j]sx?$ # *.js and *.jsx
+ types: [file]
diff --git a/Jenkinsfile b/Jenkinsfile
index d0966a68c..323eec94c 100644
--- a/Jenkinsfile
+++ b/Jenkinsfile
@@ -17,6 +17,7 @@ pipeline {
branch "bugfix/*"
branch "hotfix/*"
branch "release/*"
+ branch "tickets/*"
}
}
steps {
@@ -27,7 +28,7 @@ pipeline {
if (slashPosition > 0) {
git_tag = git_branch.substring(slashPosition + 1, git_branch.length())
git_branch = git_branch.substring(0, slashPosition)
- if (git_branch == "release" || git_branch == "hotfix" || git_branch == "bugfix") {
+ if (git_branch == "release" || git_branch == "hotfix" || git_branch == "bugfix" || git_branch == "tickets") {
image_tag = git_tag
}
}
@@ -45,6 +46,7 @@ pipeline {
branch "bugfix/*"
branch "hotfix/*"
branch "release/*"
+ branch "tickets/*"
}
}
steps {
diff --git a/love/package.json b/love/package.json
index c1e76fcb7..1fd086b77 100644
--- a/love/package.json
+++ b/love/package.json
@@ -17,6 +17,7 @@
"html2canvas": "^1.0.0-rc.5",
"lodash": "^4.17.19",
"lodash.throttle": "^4.1.1",
+ "lodash.debounce": "^4.0.8",
"luxon": "^1.23.0",
"ml-matrix": "^6.5.0",
"moment-range": "^4.0.0",
@@ -45,6 +46,7 @@
"redux-logger": "^3.0.6",
"redux-thunk": "^2.3.0",
"redux-undo": "^1.0.0",
+ "remarkable": "^2.0.1",
"reselect": "^4.0.0",
"resize-observer-polyfill": "^1.5.1",
"rfdc": "^1.1.4",
diff --git a/love/src/Config.js b/love/src/Config.js
index a388978e9..1803f43a2 100644
--- a/love/src/Config.js
+++ b/love/src/Config.js
@@ -14,7 +14,7 @@ export const DATE_TIME_FORMAT = 'YYYY/MM/DD, HH:mm:ss';
// eslint-disable-next-line
export const CSCSummaryHierarchy = {
- 'Aux Telescope': {
+ 'Auxiliary Telescope': {
ATTCS: [
{ name: 'ATMCS', salindex: 0 },
{ name: 'ATPtg', salindex: 0 },
@@ -23,7 +23,6 @@ export const CSCSummaryHierarchy = {
{ name: 'ATAOS', salindex: 0 },
{ name: 'ATPneumatics', salindex: 0 },
{ name: 'ATHexapod', salindex: 0 },
- { name: 'GenericCamera', salindex: 1 },
],
ATCalSys: [
{ name: 'ATMonochromator', salindex: 0 },
@@ -42,18 +41,31 @@ export const CSCSummaryHierarchy = {
],
},
'Main Telescope': {
- 'CSC Group 1': [
- { name: 'Test', salindex: 1 },
- { name: 'Test', salindex: 2 },
+ MTCS: [
+ { name: 'MTMount', salindex: 0 },
+ { name: 'MTPtg', salindex: 0 },
+ { name: 'MTAOS', salindex: 0 },
+ { name: 'MTM1M3', salindex: 0 },
+ { name: 'MTM2', salindex: 0 },
+ { name: 'MTHexapod', salindex: 1 },
+ { name: 'MTHexapod', salindex: 2 },
+ { name: 'MTRotator', salindex: 0 },
+ { name: 'MTDome', salindex: 0 },
+ { name: 'MTDomeTrajectory', salindex: 0 },
+ ],
+ ComCam: [
+ { name: 'CCCamera', salindex: 0 },
+ { name: 'CCArchiver', salindex: 0 },
+ { name: 'CCHeaderService', salindex: 0 },
],
- 'CSC Group 2': [],
},
Observatory: {
- Queue: [
+ HigherLevel: [
{ name: 'ScriptQueue', salindex: 1 },
{ name: 'ScriptQueue', salindex: 2 },
+ { name: 'Watcher', salindex: 0 },
],
- WeatherStation: [
+ Environment: [
{ name: 'DIMM', salindex: 1 },
{ name: 'DIMM', salindex: 2 },
{ name: 'WeatherStation', salindex: 1 },
@@ -289,12 +301,10 @@ export const stateToStyleMotorBrake = {
export const HEARTBEAT_COMPONENTS = {
MANAGER: 'Manager',
- EVENTS: 'Events',
- TELEMETRIES: 'Telemetries',
- HEARTBEATS: 'CSCHeartbeats',
- LOVE: 'LOVE CSC',
- SCRIPTQUEUE: 'ScriptQueue-1',
COMMANDER: 'Commander',
+ /** Deprecated: used for old producer version */
+ /* EVENTS: 'Events',
+ TELEMETRIES: 'Telemetries', */
};
export const severityToStatus = {
@@ -313,161 +323,232 @@ export const severityEnum = {
critical: 4,
};
+/**
+ * Available commands in the TCS and their parameters. Each command is represented
+ * as a dictionary key and their parameters as the values of said dictionary.
+ * Within each dictionary value, each parameter is represented in a separate dictionary.
+ * Each key in this new dictionary contains the parameter name and each corresponding
+ * value contains a 2 item array with its first element being the param type, e.g.
+ * 'string', 'angle', 'number', 'boolean'. The second element contains the default
+ * value.
+ *
+ */
+
+const rotTypes = [
+ { label: 'Sky', value: 0 },
+ { label: 'SkyAuto', value: 1 },
+ { label: 'Parallactic', value: 2 },
+ { label: 'PhysicalSky', value: 3 },
+ { label: 'Physical', value: 4 },
+];
+
+export const TCSCommands = {
+ slew_object: {
+ name: ['string', undefined],
+ rot: ['angle', 0.0],
+ rot_type: [rotTypes, rotTypes[1]],
+ slew_timeout: ['number', 240.0],
+ },
+ slew_icrs: {
+ ra: ['angle', undefined],
+ dec: ['angle', undefined],
+ rot: ['angle', 0.0],
+ rot_type: [rotTypes, rotTypes[1]],
+ target_name: ['string', 'slew_icrs'],
+ slew_timeout: ['number', 240.0],
+ stop_before_slew: ['boolean', true],
+ wait_settle: ['boolean', true],
+ },
+ point_azel: {
+ az: ['angle', undefined],
+ el: ['angle', undefined],
+ rot_tel: ['angle', 0.0],
+ target_name: ['string', 'azel_target'],
+ wait_dome: ['boolean', false],
+ slew_timeout: ['number', 1200.0],
+ },
+ offset_xy: {
+ x: ['number', undefined],
+ y: ['number', undefined],
+ relative: ['boolean', false],
+ persistent: ['boolean', false],
+ },
+ offset_azel: {
+ az: ['number', undefined],
+ el: ['number', undefined],
+ relative: ['boolean', false],
+ persistent: ['boolean', false],
+ },
+ offset_radec: {
+ ra: ['angle', undefined],
+ dec: ['angle', undefined],
+ },
+ slew_dome_to: {
+ az: ['number', undefined],
+ },
+ // focus_offset: {},
+ home_dome: {},
+};
+
+export const ATCSCommands = {
+ ...TCSCommands,
+};
+
export const M1M3ActuatorPositions = [
- {id: 101, position: [-3.0582000e+01, 0.0000000e+00]},
- {id: 102, position: [-5.6794000e+01, 0.0000000e+00]},
- {id: 103, position: [-8.3007000e+01, 0.0000000e+00]},
- {id: 104, position: [-1.0922000e+02, 0.0000000e+00]},
- {id: 105, position: [-1.3543300e+02, 0.0000000e+00]},
- {id: 106, position: [-1.5622100e+02, 0.0000000e+00]},
- {id: 107, position: [-1.7475000e+01, -2.2701000e+01]},
- {id: 108, position: [-4.3688000e+01, -2.2701000e+01]},
- {id: 109, position: [-6.9901000e+01, -2.2701000e+01]},
- {id: 110, position: [-9.6114000e+01, -2.2701000e+01]},
- {id: 111, position: [-1.2232600e+02, -2.2701000e+01]},
- {id: 112, position: [-1.4853900e+02, -2.2701000e+01]},
- {id: 113, position: [ 0.0000000e+00, -4.5402000e+01]},
- {id: 114, position: [-3.0582000e+01, -4.5402000e+01]},
- {id: 115, position: [-5.6794000e+01, -4.5402000e+01]},
- {id: 116, position: [-8.3007000e+01, -4.5402000e+01]},
- {id: 117, position: [-1.0922000e+02, -4.5402000e+01]},
- {id: 118, position: [-1.3543300e+02, -4.5402000e+01]},
- {id: 119, position: [-1.5356300e+02, -3.9279000e+01]},
- {id: 120, position: [-1.7475000e+01, -6.8103000e+01]},
- {id: 121, position: [-4.3688000e+01, -6.8103000e+01]},
- {id: 122, position: [-6.9901000e+01, -6.8103000e+01]},
- {id: 123, position: [-9.6113000e+01, -6.8103000e+01]},
- {id: 124, position: [-1.2232600e+02, -6.8103000e+01]},
- {id: 125, position: [-1.4663200e+02, -5.9762000e+01]},
- {id: 126, position: [ 0.0000000e+00, -9.0804000e+01]},
- {id: 127, position: [-3.0582000e+01, -9.0804000e+01]},
- {id: 128, position: [-5.6794000e+01, -9.0804000e+01]},
- {id: 129, position: [-8.3007000e+01, -9.0804000e+01]},
- {id: 130, position: [-1.0922000e+02, -9.0804000e+01]},
- {id: 131, position: [-1.3338400e+02, -8.5331000e+01]},
- {id: 132, position: [-1.7475000e+01, -1.1350500e+02]},
- {id: 133, position: [-4.3688000e+01, -1.1350500e+02]},
- {id: 134, position: [-6.9901000e+01, -1.1350500e+02]},
- {id: 135, position: [-9.6113000e+01, -1.1350500e+02]},
- {id: 136, position: [-1.1572300e+02, -1.0807800e+02]},
- {id: 137, position: [-8.7380000e+00, -1.3620600e+02]},
- {id: 138, position: [-3.4950000e+01, -1.3620600e+02]},
- {id: 139, position: [-6.1163000e+01, -1.2863900e+02]},
- {id: 140, position: [-8.2273000e+01, -1.3529100e+02]},
- {id: 141, position: [-1.4399000e+01, -1.5768700e+02]},
- {id: 142, position: [-4.2720000e+01, -1.5247100e+02]},
- {id: 143, position: [-6.3150000e+01, -1.4538500e+02]},
- {id: 207, position: [ 1.7475000e+01, -2.2701000e+01]},
- {id: 208, position: [ 4.3688000e+01, -2.2701000e+01]},
- {id: 209, position: [ 6.9901000e+01, -2.2701000e+01]},
- {id: 210, position: [ 9.6114000e+01, -2.2701000e+01]},
- {id: 211, position: [ 1.2232600e+02, -2.2701000e+01]},
- {id: 212, position: [ 1.4853900e+02, -2.2701000e+01]},
- {id: 214, position: [ 3.0582000e+01, -4.5402000e+01]},
- {id: 215, position: [ 5.6794000e+01, -4.5402000e+01]},
- {id: 216, position: [ 8.3007000e+01, -4.5402000e+01]},
- {id: 217, position: [ 1.0922000e+02, -4.5402000e+01]},
- {id: 218, position: [ 1.3543300e+02, -4.5402000e+01]},
- {id: 219, position: [ 1.5356300e+02, -3.9279000e+01]},
- {id: 220, position: [ 1.7475000e+01, -6.8103000e+01]},
- {id: 221, position: [ 4.3688000e+01, -6.8103000e+01]},
- {id: 222, position: [ 6.9901000e+01, -6.8103000e+01]},
- {id: 223, position: [ 9.6113000e+01, -6.8103000e+01]},
- {id: 224, position: [ 1.2232600e+02, -6.8103000e+01]},
- {id: 225, position: [ 1.4663200e+02, -5.9762000e+01]},
- {id: 227, position: [ 3.0582000e+01, -9.0804000e+01]},
- {id: 228, position: [ 5.6794000e+01, -9.0804000e+01]},
- {id: 229, position: [ 8.3007000e+01, -9.0804000e+01]},
- {id: 230, position: [ 1.0922000e+02, -9.0804000e+01]},
- {id: 231, position: [ 1.3338400e+02, -8.5331000e+01]},
- {id: 232, position: [ 1.7475000e+01, -1.1350500e+02]},
- {id: 233, position: [ 4.3688000e+01, -1.1350500e+02]},
- {id: 234, position: [ 6.9901000e+01, -1.1350500e+02]},
- {id: 235, position: [ 9.6113000e+01, -1.1350500e+02]},
- {id: 236, position: [ 1.1572300e+02, -1.0807800e+02]},
- {id: 237, position: [ 8.7380000e+00, -1.3620600e+02]},
- {id: 238, position: [ 3.4950000e+01, -1.3620600e+02]},
- {id: 239, position: [ 6.1163000e+01, -1.2863900e+02]},
- {id: 240, position: [ 8.2273000e+01, -1.3529100e+02]},
- {id: 241, position: [ 1.4399000e+01, -1.5768700e+02]},
- {id: 242, position: [ 4.2720000e+01, -1.5247100e+02]},
- {id: 243, position: [ 6.3150000e+01, -1.4538500e+02]},
- {id: 301, position: [ 3.0582000e+01, 0.0000000e+00]},
- {id: 302, position: [ 5.6794000e+01, 0.0000000e+00]},
- {id: 303, position: [ 8.3007000e+01, 0.0000000e+00]},
- {id: 304, position: [ 1.0922000e+02, 0.0000000e+00]},
- {id: 305, position: [ 1.3543300e+02, 0.0000000e+00]},
- {id: 306, position: [ 1.5622100e+02, -9.7000000e-02]},
- {id: 307, position: [ 1.7475000e+01, 2.2701000e+01]},
- {id: 308, position: [ 4.3688000e+01, 2.2701000e+01]},
- {id: 309, position: [ 6.9901000e+01, 2.2701000e+01]},
- {id: 310, position: [ 9.6114000e+01, 2.2701000e+01]},
- {id: 311, position: [ 1.2232600e+02, 2.2701000e+01]},
- {id: 312, position: [ 1.4853900e+02, 2.2701000e+01]},
- {id: 313, position: [ 0.0000000e+00, 4.5402000e+01]},
- {id: 314, position: [ 3.0582000e+01, 4.5402000e+01]},
- {id: 315, position: [ 5.6794000e+01, 4.5402000e+01]},
- {id: 316, position: [ 8.3007000e+01, 4.5402000e+01]},
- {id: 317, position: [ 1.0922000e+02, 4.5402000e+01]},
- {id: 318, position: [ 1.3543300e+02, 4.5402000e+01]},
- {id: 319, position: [ 1.5356300e+02, 3.9279000e+01]},
- {id: 320, position: [ 1.7475000e+01, 6.8103000e+01]},
- {id: 321, position: [ 4.3688000e+01, 6.8103000e+01]},
- {id: 322, position: [ 6.9901000e+01, 6.8103000e+01]},
- {id: 323, position: [ 9.6113000e+01, 6.8103000e+01]},
- {id: 324, position: [ 1.2232600e+02, 6.8103000e+01]},
- {id: 325, position: [ 1.4663200e+02, 5.9762000e+01]},
- {id: 326, position: [ 0.0000000e+00, 9.0804000e+01]},
- {id: 327, position: [ 3.0582000e+01, 9.0804000e+01]},
- {id: 328, position: [ 5.6794000e+01, 9.0804000e+01]},
- {id: 329, position: [ 8.3007000e+01, 9.0804000e+01]},
- {id: 330, position: [ 1.0922000e+02, 9.0804000e+01]},
- {id: 331, position: [ 1.3338400e+02, 8.5331000e+01]},
- {id: 332, position: [ 1.7475000e+01, 1.1350500e+02]},
- {id: 333, position: [ 4.3688000e+01, 1.1350500e+02]},
- {id: 334, position: [ 6.9901000e+01, 1.1350500e+02]},
- {id: 335, position: [ 9.6113000e+01, 1.1350500e+02]},
- {id: 336, position: [ 1.1572300e+02, 1.0807800e+02]},
- {id: 337, position: [ 8.7380000e+00, 1.3620600e+02]},
- {id: 338, position: [ 3.4950000e+01, 1.3620600e+02]},
- {id: 339, position: [ 6.1163000e+01, 1.2863900e+02]},
- {id: 340, position: [ 8.2273000e+01, 1.3529100e+02]},
- {id: 341, position: [ 1.4399000e+01, 1.5768700e+02]},
- {id: 342, position: [ 4.2720000e+01, 1.5247100e+02]},
- {id: 343, position: [ 6.3150000e+01, 1.4538500e+02]},
- {id: 407, position: [-1.7475000e+01, 2.2701000e+01]},
- {id: 408, position: [-4.3688000e+01, 2.2701000e+01]},
- {id: 409, position: [-6.9901000e+01, 2.2701000e+01]},
- {id: 410, position: [-9.6114000e+01, 2.2701000e+01]},
- {id: 411, position: [-1.2232600e+02, 2.2701000e+01]},
- {id: 412, position: [-1.4853900e+02, 2.2701000e+01]},
- {id: 414, position: [-3.0582000e+01, 4.5402000e+01]},
- {id: 415, position: [-5.6794000e+01, 4.5402000e+01]},
- {id: 416, position: [-8.3007000e+01, 4.5402000e+01]},
- {id: 417, position: [-1.0922000e+02, 4.5402000e+01]},
- {id: 418, position: [-1.3543300e+02, 4.5402000e+01]},
- {id: 419, position: [-1.5356300e+02, 3.9279000e+01]},
- {id: 420, position: [-1.7475000e+01, 6.8103000e+01]},
- {id: 421, position: [-4.3688000e+01, 6.8103000e+01]},
- {id: 422, position: [-6.9901000e+01, 6.8103000e+01]},
- {id: 423, position: [-9.6113000e+01, 6.8103000e+01]},
- {id: 424, position: [-1.2232600e+02, 6.8103000e+01]},
- {id: 425, position: [-1.4663200e+02, 5.9762000e+01]},
- {id: 427, position: [-3.0582000e+01, 9.0804000e+01]},
- {id: 428, position: [-5.6794000e+01, 9.0804000e+01]},
- {id: 429, position: [-8.3007000e+01, 9.0804000e+01]},
- {id: 430, position: [-1.0922000e+02, 9.0804000e+01]},
- {id: 431, position: [-1.3338400e+02, 8.5331000e+01]},
- {id: 432, position: [-1.7475000e+01, 1.1350500e+02]},
- {id: 433, position: [-4.3688000e+01, 1.1350500e+02]},
- {id: 434, position: [-6.9901000e+01, 1.1350500e+02]},
- {id: 435, position: [-9.6113000e+01, 1.1350500e+02]},
- {id: 436, position: [-1.1572300e+02, 1.0807800e+02]},
- {id: 437, position: [-8.7380000e+00, 1.3620600e+02]},
- {id: 438, position: [-3.4950000e+01, 1.3620600e+02]},
- {id: 439, position: [-6.1163000e+01, 1.2863900e+02]},
- {id: 440, position: [-8.2273000e+01, 1.3529100e+02]},
- {id: 441, position: [-1.4399000e+01, 1.5768700e+02]},
- {id: 442, position: [-4.2720000e+01, 1.5247100e+02]},
- {id: 443, position: [-6.3150000e+01, 1.4538500e+02]}
- ]
\ No newline at end of file
+ { id: 101, position: [-3.0582e1, 0.0] },
+ { id: 102, position: [-5.6794e1, 0.0] },
+ { id: 103, position: [-8.3007e1, 0.0] },
+ { id: 104, position: [-1.0922e2, 0.0] },
+ { id: 105, position: [-1.35433e2, 0.0] },
+ { id: 106, position: [-1.56221e2, 0.0] },
+ { id: 107, position: [-1.7475e1, -2.2701e1] },
+ { id: 108, position: [-4.3688e1, -2.2701e1] },
+ { id: 109, position: [-6.9901e1, -2.2701e1] },
+ { id: 110, position: [-9.6114e1, -2.2701e1] },
+ { id: 111, position: [-1.22326e2, -2.2701e1] },
+ { id: 112, position: [-1.48539e2, -2.2701e1] },
+ { id: 113, position: [0.0, -4.5402e1] },
+ { id: 114, position: [-3.0582e1, -4.5402e1] },
+ { id: 115, position: [-5.6794e1, -4.5402e1] },
+ { id: 116, position: [-8.3007e1, -4.5402e1] },
+ { id: 117, position: [-1.0922e2, -4.5402e1] },
+ { id: 118, position: [-1.35433e2, -4.5402e1] },
+ { id: 119, position: [-1.53563e2, -3.9279e1] },
+ { id: 120, position: [-1.7475e1, -6.8103e1] },
+ { id: 121, position: [-4.3688e1, -6.8103e1] },
+ { id: 122, position: [-6.9901e1, -6.8103e1] },
+ { id: 123, position: [-9.6113e1, -6.8103e1] },
+ { id: 124, position: [-1.22326e2, -6.8103e1] },
+ { id: 125, position: [-1.46632e2, -5.9762e1] },
+ { id: 126, position: [0.0, -9.0804e1] },
+ { id: 127, position: [-3.0582e1, -9.0804e1] },
+ { id: 128, position: [-5.6794e1, -9.0804e1] },
+ { id: 129, position: [-8.3007e1, -9.0804e1] },
+ { id: 130, position: [-1.0922e2, -9.0804e1] },
+ { id: 131, position: [-1.33384e2, -8.5331e1] },
+ { id: 132, position: [-1.7475e1, -1.13505e2] },
+ { id: 133, position: [-4.3688e1, -1.13505e2] },
+ { id: 134, position: [-6.9901e1, -1.13505e2] },
+ { id: 135, position: [-9.6113e1, -1.13505e2] },
+ { id: 136, position: [-1.15723e2, -1.08078e2] },
+ { id: 137, position: [-8.738, -1.36206e2] },
+ { id: 138, position: [-3.495e1, -1.36206e2] },
+ { id: 139, position: [-6.1163e1, -1.28639e2] },
+ { id: 140, position: [-8.2273e1, -1.35291e2] },
+ { id: 141, position: [-1.4399e1, -1.57687e2] },
+ { id: 142, position: [-4.272e1, -1.52471e2] },
+ { id: 143, position: [-6.315e1, -1.45385e2] },
+ { id: 207, position: [1.7475e1, -2.2701e1] },
+ { id: 208, position: [4.3688e1, -2.2701e1] },
+ { id: 209, position: [6.9901e1, -2.2701e1] },
+ { id: 210, position: [9.6114e1, -2.2701e1] },
+ { id: 211, position: [1.22326e2, -2.2701e1] },
+ { id: 212, position: [1.48539e2, -2.2701e1] },
+ { id: 214, position: [3.0582e1, -4.5402e1] },
+ { id: 215, position: [5.6794e1, -4.5402e1] },
+ { id: 216, position: [8.3007e1, -4.5402e1] },
+ { id: 217, position: [1.0922e2, -4.5402e1] },
+ { id: 218, position: [1.35433e2, -4.5402e1] },
+ { id: 219, position: [1.53563e2, -3.9279e1] },
+ { id: 220, position: [1.7475e1, -6.8103e1] },
+ { id: 221, position: [4.3688e1, -6.8103e1] },
+ { id: 222, position: [6.9901e1, -6.8103e1] },
+ { id: 223, position: [9.6113e1, -6.8103e1] },
+ { id: 224, position: [1.22326e2, -6.8103e1] },
+ { id: 225, position: [1.46632e2, -5.9762e1] },
+ { id: 227, position: [3.0582e1, -9.0804e1] },
+ { id: 228, position: [5.6794e1, -9.0804e1] },
+ { id: 229, position: [8.3007e1, -9.0804e1] },
+ { id: 230, position: [1.0922e2, -9.0804e1] },
+ { id: 231, position: [1.33384e2, -8.5331e1] },
+ { id: 232, position: [1.7475e1, -1.13505e2] },
+ { id: 233, position: [4.3688e1, -1.13505e2] },
+ { id: 234, position: [6.9901e1, -1.13505e2] },
+ { id: 235, position: [9.6113e1, -1.13505e2] },
+ { id: 236, position: [1.15723e2, -1.08078e2] },
+ { id: 237, position: [8.738, -1.36206e2] },
+ { id: 238, position: [3.495e1, -1.36206e2] },
+ { id: 239, position: [6.1163e1, -1.28639e2] },
+ { id: 240, position: [8.2273e1, -1.35291e2] },
+ { id: 241, position: [1.4399e1, -1.57687e2] },
+ { id: 242, position: [4.272e1, -1.52471e2] },
+ { id: 243, position: [6.315e1, -1.45385e2] },
+ { id: 301, position: [3.0582e1, 0.0] },
+ { id: 302, position: [5.6794e1, 0.0] },
+ { id: 303, position: [8.3007e1, 0.0] },
+ { id: 304, position: [1.0922e2, 0.0] },
+ { id: 305, position: [1.35433e2, 0.0] },
+ { id: 306, position: [1.56221e2, -9.7e-2] },
+ { id: 307, position: [1.7475e1, 2.2701e1] },
+ { id: 308, position: [4.3688e1, 2.2701e1] },
+ { id: 309, position: [6.9901e1, 2.2701e1] },
+ { id: 310, position: [9.6114e1, 2.2701e1] },
+ { id: 311, position: [1.22326e2, 2.2701e1] },
+ { id: 312, position: [1.48539e2, 2.2701e1] },
+ { id: 313, position: [0.0, 4.5402e1] },
+ { id: 314, position: [3.0582e1, 4.5402e1] },
+ { id: 315, position: [5.6794e1, 4.5402e1] },
+ { id: 316, position: [8.3007e1, 4.5402e1] },
+ { id: 317, position: [1.0922e2, 4.5402e1] },
+ { id: 318, position: [1.35433e2, 4.5402e1] },
+ { id: 319, position: [1.53563e2, 3.9279e1] },
+ { id: 320, position: [1.7475e1, 6.8103e1] },
+ { id: 321, position: [4.3688e1, 6.8103e1] },
+ { id: 322, position: [6.9901e1, 6.8103e1] },
+ { id: 323, position: [9.6113e1, 6.8103e1] },
+ { id: 324, position: [1.22326e2, 6.8103e1] },
+ { id: 325, position: [1.46632e2, 5.9762e1] },
+ { id: 326, position: [0.0, 9.0804e1] },
+ { id: 327, position: [3.0582e1, 9.0804e1] },
+ { id: 328, position: [5.6794e1, 9.0804e1] },
+ { id: 329, position: [8.3007e1, 9.0804e1] },
+ { id: 330, position: [1.0922e2, 9.0804e1] },
+ { id: 331, position: [1.33384e2, 8.5331e1] },
+ { id: 332, position: [1.7475e1, 1.13505e2] },
+ { id: 333, position: [4.3688e1, 1.13505e2] },
+ { id: 334, position: [6.9901e1, 1.13505e2] },
+ { id: 335, position: [9.6113e1, 1.13505e2] },
+ { id: 336, position: [1.15723e2, 1.08078e2] },
+ { id: 337, position: [8.738, 1.36206e2] },
+ { id: 338, position: [3.495e1, 1.36206e2] },
+ { id: 339, position: [6.1163e1, 1.28639e2] },
+ { id: 340, position: [8.2273e1, 1.35291e2] },
+ { id: 341, position: [1.4399e1, 1.57687e2] },
+ { id: 342, position: [4.272e1, 1.52471e2] },
+ { id: 343, position: [6.315e1, 1.45385e2] },
+ { id: 407, position: [-1.7475e1, 2.2701e1] },
+ { id: 408, position: [-4.3688e1, 2.2701e1] },
+ { id: 409, position: [-6.9901e1, 2.2701e1] },
+ { id: 410, position: [-9.6114e1, 2.2701e1] },
+ { id: 411, position: [-1.22326e2, 2.2701e1] },
+ { id: 412, position: [-1.48539e2, 2.2701e1] },
+ { id: 414, position: [-3.0582e1, 4.5402e1] },
+ { id: 415, position: [-5.6794e1, 4.5402e1] },
+ { id: 416, position: [-8.3007e1, 4.5402e1] },
+ { id: 417, position: [-1.0922e2, 4.5402e1] },
+ { id: 418, position: [-1.35433e2, 4.5402e1] },
+ { id: 419, position: [-1.53563e2, 3.9279e1] },
+ { id: 420, position: [-1.7475e1, 6.8103e1] },
+ { id: 421, position: [-4.3688e1, 6.8103e1] },
+ { id: 422, position: [-6.9901e1, 6.8103e1] },
+ { id: 423, position: [-9.6113e1, 6.8103e1] },
+ { id: 424, position: [-1.22326e2, 6.8103e1] },
+ { id: 425, position: [-1.46632e2, 5.9762e1] },
+ { id: 427, position: [-3.0582e1, 9.0804e1] },
+ { id: 428, position: [-5.6794e1, 9.0804e1] },
+ { id: 429, position: [-8.3007e1, 9.0804e1] },
+ { id: 430, position: [-1.0922e2, 9.0804e1] },
+ { id: 431, position: [-1.33384e2, 8.5331e1] },
+ { id: 432, position: [-1.7475e1, 1.13505e2] },
+ { id: 433, position: [-4.3688e1, 1.13505e2] },
+ { id: 434, position: [-6.9901e1, 1.13505e2] },
+ { id: 435, position: [-9.6113e1, 1.13505e2] },
+ { id: 436, position: [-1.15723e2, 1.08078e2] },
+ { id: 437, position: [-8.738, 1.36206e2] },
+ { id: 438, position: [-3.495e1, 1.36206e2] },
+ { id: 439, position: [-6.1163e1, 1.28639e2] },
+ { id: 440, position: [-8.2273e1, 1.35291e2] },
+ { id: 441, position: [-1.4399e1, 1.57687e2] },
+ { id: 442, position: [-4.272e1, 1.52471e2] },
+ { id: 443, position: [-6.315e1, 1.45385e2] },
+];
diff --git a/love/src/Utils.js b/love/src/Utils.js
index e49a3369f..4caf8d93b 100644
--- a/love/src/Utils.js
+++ b/love/src/Utils.js
@@ -3,6 +3,7 @@
import React, { useState } from 'react';
import html2canvas from 'html2canvas';
import { DateTime } from 'luxon';
+import { toast } from 'react-toastify';
import { WEBSOCKET_SIMULATION } from 'Config.js';
import { SALCommandStatus } from 'redux/actions/ws';
@@ -325,6 +326,68 @@ export default class ManagerInterface {
});
});
}
+
+ static runATCSCommand(commandName, params = {}) {
+ const token = ManagerInterface.getToken();
+ if (token === null) {
+ // console.log('Token not found during validation');
+ return new Promise((resolve) => resolve(false));
+ }
+ const url = `${this.getApiBaseUrl()}tcs/aux`;
+ return fetch(url, {
+ method: 'POST',
+ headers: this.getHeaders(),
+ body: JSON.stringify({
+ command_name: commandName,
+ params,
+ }),
+ }).then((response) => {
+ if (response.status >= 500) {
+ toast.error('Error communicating with the server.');
+ return false;
+ }
+ if (response.status === 401 || response.status === 403) {
+ toast.error('Session expired. Logging out.');
+ ManagerInterface.removeToken();
+ return false;
+ }
+ if (response.status === 400) {
+ return response.json().then((resp) => {
+ toast.error(resp.ack);
+ });
+ }
+ return response.json().then((resp) => {
+ toast.info(resp.ack);
+ return resp;
+ });
+ });
+ }
+
+ static getATCSDocstrings() {
+ const token = ManagerInterface.getToken();
+ if (token === null) {
+ // console.log('Token not found during validation');
+ return new Promise((resolve) => resolve(false));
+ }
+ const url = `${this.getApiBaseUrl()}tcs/docstrings`;
+ return fetch(url, {
+ method: 'GET',
+ headers: this.getHeaders(),
+ }).then((response) => {
+ if (response.status >= 500) {
+ // console.error('Error communicating with the server.);
+ return false;
+ }
+ if (response.status === 401 || response.status === 403) {
+ // console.log('Session expired. Logging out');
+ ManagerInterface.removeToken();
+ return false;
+ }
+ return response.json().then((resp) => {
+ return resp;
+ });
+ });
+ }
}
/**
@@ -653,9 +716,9 @@ export const parseCommanderData = (data, tsLabel = 'x', valueLabel = 'y') => {
};
export function radians(degrees) {
- return degrees * Math.PI / 180;
-};
+ return (degrees * Math.PI) / 180;
+}
export function degrees(radians) {
- return radians * 180 / Math.PI;
-};
+ return (radians * 180) / Math.PI;
+}
diff --git a/love/src/components/AuxTel/Camera/Camera.jsx b/love/src/components/AuxTel/Camera/Camera.jsx
index 4983e4f49..da02d0dd7 100644
--- a/love/src/components/AuxTel/Camera/Camera.jsx
+++ b/love/src/components/AuxTel/Camera/Camera.jsx
@@ -15,6 +15,8 @@ export default class Camera extends Component {
calibrationDetailedState: PropTypes.string,
shutterDetailedState: PropTypes.string,
imageSequence: PropTypes.object,
+ subscribeToStreams: PropTypes.func,
+ unsubscribeToStreams: PropTypes.func,
};
constructor(props) {
diff --git a/love/src/components/CSCSummary/CSCDetail/CSCDetail.container.jsx b/love/src/components/CSCSummary/CSCDetail/CSCDetail.container.jsx
index 847f05def..07f339637 100644
--- a/love/src/components/CSCSummary/CSCDetail/CSCDetail.container.jsx
+++ b/love/src/components/CSCSummary/CSCDetail/CSCDetail.container.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import { connect } from 'react-redux';
import CSCDetail from './CSCDetail';
-import { addGroup } from '../../../redux/actions/ws';
+import { addGroup, removeGroup } from '../../../redux/actions/ws';
import { getStreamData, getCSCHeartbeat } from '../../../redux/selectors';
export const schema = {
@@ -67,6 +67,7 @@ const CSCDetailContainer = ({
summaryStateData,
onCSCClick,
subscribeToStreams,
+ unsubscribeToStreams,
heartbeatData,
embedded,
}) => {
@@ -79,6 +80,7 @@ const CSCDetailContainer = ({
summaryStateData={summaryStateData}
onCSCClick={onCSCClick}
subscribeToStreams={subscribeToStreams}
+ unsubscribeToStreams={unsubscribeToStreams}
heartbeatData={heartbeatData}
embedded={embedded}
/>
@@ -93,6 +95,12 @@ const mapDispatchToProps = (dispatch) => {
dispatch(addGroup(`event-${cscName}-${index}-logMessage`));
dispatch(addGroup(`event-${cscName}-${index}-errorCode`));
},
+ unsubscribeToStreams: (cscName, index) => {
+ dispatch(removeGroup('event-Heartbeat-0-stream'));
+ dispatch(removeGroup(`event-${cscName}-${index}-summaryState`));
+ dispatch(removeGroup(`event-${cscName}-${index}-logMessage`));
+ dispatch(removeGroup(`event-${cscName}-${index}-errorCode`));
+ },
};
};
diff --git a/love/src/components/CSCSummary/CSCDetail/CSCDetail.jsx b/love/src/components/CSCSummary/CSCDetail/CSCDetail.jsx
index a08d7140e..73a709c46 100644
--- a/love/src/components/CSCSummary/CSCDetail/CSCDetail.jsx
+++ b/love/src/components/CSCSummary/CSCDetail/CSCDetail.jsx
@@ -14,6 +14,7 @@ export default class CSCDetail extends Component {
heartbeatData: PropTypes.object,
summaryStateData: PropTypes.object,
subscribeToStreams: PropTypes.func,
+ unsubscribeToStreams: PropTypes.func,
embedded: PropTypes.bool,
/* Whether the component should subscribe to streams*/
shouldSubscribe: PropTypes.bool,
@@ -27,6 +28,7 @@ export default class CSCDetail extends Component {
heartbeatData: null,
summaryStateData: undefined,
subscribeToStreams: () => {},
+ unsubscribeToStreams: () => {},
embedded: false,
shouldSubscribe: true,
};
@@ -74,6 +76,10 @@ export default class CSCDetail extends Component {
if (!this.props.shouldSubscribe) this.props.subscribeToStreams(this.props.name, this.props.salindex);
};
+ componentWillUnmount = () => {
+ if (!this.props.shouldSubscribe) this.props.unsubscribeToStreams(this.props.name, this.props.salindex);
+ }
+
render() {
const { props } = this;
let heartbeatStatus = 'unknown';
diff --git a/love/src/components/CSCSummary/CSCExpanded/CSCExpanded.container.jsx b/love/src/components/CSCSummary/CSCExpanded/CSCExpanded.container.jsx
index f4041739b..1e3d2e815 100644
--- a/love/src/components/CSCSummary/CSCExpanded/CSCExpanded.container.jsx
+++ b/love/src/components/CSCSummary/CSCExpanded/CSCExpanded.container.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import { connect } from 'react-redux';
import CSCExpanded from './CSCExpanded';
-import { addGroup } from '../../../redux/actions/ws';
+import { addGroup, removeGroup } from '../../../redux/actions/ws';
import { removeCSCLogMessages, removeCSCErrorCodeData } from '../../../redux/actions/summaryData';
import { getStreamData, getCSCHeartbeat, getCSCLogMessages, getCSCErrorCodeData } from '../../../redux/selectors';
@@ -59,8 +59,10 @@ const CSCExpandedContainer = ({
logMessageData,
errorCodeData,
subscribeToStreams,
+ unsubscribeToStreams,
heartbeatData,
displaySummaryState = true,
+ hideTitle = false,
}) => {
return (
);
};
@@ -87,7 +91,12 @@ const mapDispatchToProps = (dispatch) => {
dispatch(addGroup(`event-${cscName}-${index}-summaryState`));
dispatch(addGroup(`event-${cscName}-${index}-logMessage`));
dispatch(addGroup(`event-${cscName}-${index}-errorCode`));
- dispatch(addGroup('event-Heartbeat-0-stream'));
+ },
+ unsubscribeToStreams: (cscName, index) => {
+ dispatch(removeGroup('event-Heartbeat-0-stream'));
+ dispatch(removeGroup(`event-${cscName}-${index}-summaryState`));
+ dispatch(removeGroup(`event-${cscName}-${index}-logMessage`));
+ dispatch(removeGroup(`event-${cscName}-${index}-errorCode`));
},
clearCSCLogMessages: (csc, salindex) => {
dispatch(removeCSCLogMessages(csc, salindex));
diff --git a/love/src/components/CSCSummary/CSCExpanded/CSCExpanded.jsx b/love/src/components/CSCSummary/CSCExpanded/CSCExpanded.jsx
index c22b83cc0..603d1d110 100644
--- a/love/src/components/CSCSummary/CSCExpanded/CSCExpanded.jsx
+++ b/love/src/components/CSCSummary/CSCExpanded/CSCExpanded.jsx
@@ -18,6 +18,8 @@ export default class CSCExpanded extends PureComponent {
summaryStateData: PropTypes.object,
logMessageData: PropTypes.array,
errorCodeData: PropTypes.array,
+ subscribeToStreams: PropTypes.func,
+ unsubscribeToStreams: PropTypes.func,
};
static defaultProps = {
@@ -36,17 +38,16 @@ export default class CSCExpanded extends PureComponent {
this.props.subscribeToStreams(this.props.name, this.props.salindex);
};
- constructor(props) {
- super(props);
- this.state = {
- messageFilters: {
- 10: { value: true, name: 'Debug' },
- 20: { value: true, name: 'Info' },
- 30: { value: true, name: 'Warning' },
- 40: { value: true, name: 'Error' },
- },
- };
- }
+ componentWillUnmount = () => {
+ this.props.unsubscribeToStreams(this.props.name, this.props.salindex);
+ };
+
+ componentDidUpdate = (prevProps, prevState) => {
+ if (prevProps.name !== this.props.name || prevProps.salindex !== this.props.salindex) {
+ this.props.unsubscribeToStreams(prevProps.name, prevProps.salindex);
+ this.props.subscribeToStreams(this.props.name, this.props.salindex);
+ }
+ };
static states = {
0: {
@@ -87,14 +88,6 @@ export default class CSCExpanded extends PureComponent {
},
};
- updateFilter = (key, value) => {
- const filters = this.state.messageFilters;
- filters[key].value = value;
- this.setState({
- messageFilters: { ...filters },
- });
- };
-
render() {
const summaryStateValue = this.props.summaryStateData ? this.props.summaryStateData.summaryState.value : 0;
const summaryState = CSCExpanded.states[summaryStateValue];
@@ -152,7 +145,7 @@ export default class CSCExpanded extends PureComponent {
>
>
)}
- {cscText(this.props.name, this.props.salindex)}
+ {!this.props.hideTitle && {cscText(this.props.name, this.props.salindex)}}
{this.props.displaySummaryState && (
diff --git a/love/src/components/CSCSummary/CSCGroup/CSCGroup.container.jsx b/love/src/components/CSCSummary/CSCGroup/CSCGroup.container.jsx
index 7cd115bb9..c9a54eafe 100644
--- a/love/src/components/CSCSummary/CSCGroup/CSCGroup.container.jsx
+++ b/love/src/components/CSCSummary/CSCGroup/CSCGroup.container.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import { connect } from 'react-redux';
import CSCGroup from './CSCGroup';
-import { addGroup } from '../../../redux/actions/ws';
+import { addGroup, removeGroup } from '../../../redux/actions/ws';
import { removeCSCLogMessages, removeCSCErrorCodeData } from '../../../redux/actions/summaryData';
import { getStreamData, getCSCHeartbeat, getCSCLogMessages, getCSCErrorCodeData } from '../../../redux/selectors';
@@ -90,20 +90,26 @@ export const schema = {
},
};
-const CSCGroupContainer = ({ subscribeToStreams, ...props }) => {
- return
;
+const CSCGroupContainer = ({ subscribeToStreams, unsubscribeToStreams, ...props }) => {
+ return
;
};
const mapDispatchToProps = (dispatch, ownProps) => {
return {
subscribeToStreams: (cscName, index) => {
+ console.log(`SUBSCRIBING TO ${cscName}-${index}...`);
dispatch(addGroup('event-Heartbeat-0-stream'));
dispatch(addGroup(`event-${cscName}-${index}-summaryState`));
dispatch(addGroup(`event-${cscName}-${index}-logMessage`));
dispatch(addGroup(`event-${cscName}-${index}-errorCode`));
- dispatch(addGroup('event-Heartbeat-0-stream'));
ownProps.subscribeToStreamCallback(cscName, index);
},
+ unsubscribeToStreams: (cscName, index) => {
+ dispatch(removeGroup('event-Heartbeat-0-stream'));
+ dispatch(removeGroup(`event-${cscName}-${index}-summaryState`));
+ dispatch(removeGroup(`event-${cscName}-${index}-logMessage`));
+ dispatch(removeGroup(`event-${cscName}-${index}-errorCode`));
+ },
clearCSCLogMessages: (csc, salindex) => {
dispatch(removeCSCLogMessages(csc, salindex));
},
diff --git a/love/src/components/CSCSummary/CSCGroup/CSCGroup.jsx b/love/src/components/CSCSummary/CSCGroup/CSCGroup.jsx
index 0be7ee833..8760d5b14 100644
--- a/love/src/components/CSCSummary/CSCGroup/CSCGroup.jsx
+++ b/love/src/components/CSCSummary/CSCGroup/CSCGroup.jsx
@@ -12,17 +12,21 @@ export default class CSCGroup extends Component {
selectedCSC: undefined,
};
}
+
static propTypes = {
name: PropTypes.string,
cscs: PropTypes.array,
onCSCClick: PropTypes.func,
embedded: PropTypes.bool,
+ subscribeToStreams: PropTypes.func,
+ unsubscribeToStreams: PropTypes.func,
};
static defaultProps = {
name: '',
cscs: [],
subscribeToStreams: () => 0,
+ unsubscribeToStreams: () => 0,
selectedCSC: undefined,
embedded: false,
};
@@ -35,6 +39,14 @@ export default class CSCGroup extends Component {
}
};
+ componentWillUnmount = () => {
+ if (this.props.csc !== undefined) {
+ this.props.cscs.forEach((csc) => {
+ this.props.unsubscribeToStreams(csc.name, csc.salindex);
+ });
+ }
+ }
+
renderExpandedView = (selectedCSC) => {
const groupView = selectedCSC.csc === 'all';
diff --git a/love/src/components/CSCSummary/CSCGroupLog/CSCGroupLog.container.jsx b/love/src/components/CSCSummary/CSCGroupLog/CSCGroupLog.container.jsx
index 22c1cdd51..6beb4a5a7 100644
--- a/love/src/components/CSCSummary/CSCGroupLog/CSCGroupLog.container.jsx
+++ b/love/src/components/CSCSummary/CSCGroupLog/CSCGroupLog.container.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import { connect } from 'react-redux';
import CSCGroupLog from './CSCGroupLog';
-import { addGroup } from '../../../redux/actions/ws';
+import { addGroup, removeGroup } from '../../../redux/actions/ws';
import { getGroupSortedErrorCodeData } from '../../../redux/selectors';
import { removeCSCErrorCodeData } from '../../../redux/actions/summaryData';
@@ -61,6 +61,7 @@ const CSCGroupLogContainer = ({
onCSCClick,
clearCSCErrorCodes,
subscribeToStream,
+ unsubscribeToStream,
errorCodeData,
cscList,
embedded,
@@ -72,6 +73,7 @@ const CSCGroupLogContainer = ({
onCSCClick={onCSCClick}
clearCSCErrorCodes={clearCSCErrorCodes}
subscribeToStream={subscribeToStream}
+ unsubscribeToStream={unsubscribeToStream}
errorCodeData={errorCodeData}
cscList={cscList}
embedded={embedded}
@@ -84,6 +86,9 @@ const mapDispatchtoProps = (dispatch) => {
subscribeToStream: (cscName, index) => {
dispatch(addGroup(`event-${cscName}-${index}-errorCode`));
},
+ unsubscribeToStream: (cscName, index) => {
+ dispatch(removeGroup(`event-${cscName}-${index}-errorCode`));
+ },
clearCSCErrorCodes: (csc, salindex) => {
dispatch(removeCSCErrorCodeData(csc, salindex));
},
diff --git a/love/src/components/CSCSummary/CSCGroupLog/CSCGroupLog.jsx b/love/src/components/CSCSummary/CSCGroupLog/CSCGroupLog.jsx
index 525859507..8c59bf7a1 100644
--- a/love/src/components/CSCSummary/CSCGroupLog/CSCGroupLog.jsx
+++ b/love/src/components/CSCSummary/CSCGroupLog/CSCGroupLog.jsx
@@ -15,8 +15,10 @@ export default class CSCGroupLog extends Component {
clearCSCErrorCodes: PropTypes.func,
clearCSCLogMessages: PropTypes.func,
subscribeToStream: PropTypes.func,
+ unsubscribeToStream: PropTypes.func,
errorCodeData: PropTypes.array,
embedded: PropTypes.bool,
+ cscList: PropTypes.array,
};
static defaultProps = {
@@ -36,6 +38,12 @@ export default class CSCGroupLog extends Component {
});
};
+ componentWillUnmount = () => {
+ this.props.cscList.forEach(({ name, salindex }) => {
+ this.props.unsubscribeToStream(name, salindex);
+ });
+ }
+
clearGroupErrorCodes = () => {
this.props.cscList.forEach(({ name, salindex }) => {
this.props.clearCSCErrorCodes(name, salindex);
diff --git a/love/src/components/CSCSummary/CSCSummary.container.jsx b/love/src/components/CSCSummary/CSCSummary.container.jsx
index 1b90b4ab8..000e66a3b 100644
--- a/love/src/components/CSCSummary/CSCSummary.container.jsx
+++ b/love/src/components/CSCSummary/CSCSummary.container.jsx
@@ -25,7 +25,6 @@ export const schema = {
const CSCSummaryContainer = ({
hierarchy = CSCSummaryHierarchy,
expandHeight,
- subscribeToStreamsWithCallback,
...props
}) => {
const [subscriptions, setSubscriptions] = useState([]);
diff --git a/love/src/components/CommandPanel/CommandPanel.container.jsx b/love/src/components/CommandPanel/CommandPanel.container.jsx
index bbbff2a74..62784c9b0 100644
--- a/love/src/components/CommandPanel/CommandPanel.container.jsx
+++ b/love/src/components/CommandPanel/CommandPanel.container.jsx
@@ -1,6 +1,7 @@
import React from 'react';
import { connect } from 'react-redux';
import { requestSALCommand } from '../../redux/actions/ws';
+import { getPermCmdExec, getScriptQueueState } from '../../redux/selectors';
import CommandPanel from './CommandPanel';
export const schema = {
@@ -29,9 +30,19 @@ const CommandPanelContainer = ({ ...props }) => {
const mapDispatchToProps = (dispatch, ownProps) => {
return {
requestSALCommand: (component, salindex, cmd) => {
- return dispatch(requestSALCommand({ ...cmd, component, salindex }));
+ return;
+ dispatch(requestSALCommand({ ...cmd, component, salindex }));
},
};
};
-export default connect(() => {}, mapDispatchToProps)(CommandPanelContainer);
+const mapStateToProps = (state) => {
+ const commandExecutePermission = getPermCmdExec(state);
+ const queueState = getScriptQueueState(state, 1);
+ return {
+ commandExecutePermission: commandExecutePermission,
+ queueState: queueState,
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(CommandPanelContainer);
diff --git a/love/src/components/CommandPanel/CommandPanel.jsx b/love/src/components/CommandPanel/CommandPanel.jsx
index a2bae37ae..1b0b89d40 100644
--- a/love/src/components/CommandPanel/CommandPanel.jsx
+++ b/love/src/components/CommandPanel/CommandPanel.jsx
@@ -1,12 +1,14 @@
import React, { Component } from 'react';
-import DomeCloseButton from './DomeCloseButton/DomeCloseButton';
+// import DomeCloseButton from './DomeCloseButton/DomeCloseButton';
+import StopAllTSCButton from './StopAllTSCButton/StopAllTSCButton';
import styles from './CommandPanel.module.css';
export default class CommandPanel extends Component {
render() {
return (
-
+ {/* */}
+
);
}
diff --git a/love/src/components/CommandPanel/CommandPanel.module.css b/love/src/components/CommandPanel/CommandPanel.module.css
index 674249d83..bd3612306 100644
--- a/love/src/components/CommandPanel/CommandPanel.module.css
+++ b/love/src/components/CommandPanel/CommandPanel.module.css
@@ -2,5 +2,8 @@
display: flex;
/* justify-content: center;
align-items: center; */
- height: 100%;
+}
+
+.container div {
+ margin-right: 32px;
}
diff --git a/love/src/components/CommandPanel/DomeCloseButton/DomeCloseButton.jsx b/love/src/components/CommandPanel/DomeCloseButton/DomeCloseButton.jsx
index edd0f89f2..b200bc5ad 100644
--- a/love/src/components/CommandPanel/DomeCloseButton/DomeCloseButton.jsx
+++ b/love/src/components/CommandPanel/DomeCloseButton/DomeCloseButton.jsx
@@ -6,17 +6,11 @@ export default class DomeCloseButton extends Component {
return (
diff --git a/love/src/components/CommandPanel/DomeCloseButton/DomeCloseButton.module.css b/love/src/components/CommandPanel/DomeCloseButton/DomeCloseButton.module.css
index 0f5ea2bda..b4108ecb4 100644
--- a/love/src/components/CommandPanel/DomeCloseButton/DomeCloseButton.module.css
+++ b/love/src/components/CommandPanel/DomeCloseButton/DomeCloseButton.module.css
@@ -1,15 +1,15 @@
.buttonWrapper {
+ height: 200px;
+ width: 200px;
+ text-align: center;
}
.button {
- display: grid;
- grid-template-columns: min-content;
- grid-template-rows: min-content min-content;
+ width: 100%;
+ height: 100%;
border-radius: 5px;
- overflow: hidden;
- width: fit-content;
- border: none;
- padding: 0;
+ border: 0;
+ padding: 16px;
cursor: pointer;
background: var(--status-alert-color);
}
@@ -18,32 +18,23 @@
background: var(--status-alert-dimmed-color-2);
}
-.domeSVG {
-}
-
-.domeSVG path {
- transform: translate(-140px, -120px);
- fill: #fde8df;
-}
-
-.domePath {
-}
-
-.domeXPath {
- stroke: var(--status-alert-color);
- stroke-width: 3;
- stroke-miterlimit: 10;
+.button[disabled] {
+ cursor: not-allowed;
+ background: var(--status-alert-dimmed-color-2);
}
-.button:hover .domeXPath {
- stroke: var(--status-alert-dimmed-color-2);
- stroke-width: 3;
- stroke-miterlimit: 10;
+.svg {
+ height: 100px;
+ width: 100px;
}
.buttonLabel {
+ display: block;
padding: 0.5em 1em;
- padding-top: 0;
color: white;
font-size: var(--font-size-large);
}
+
+.cls-1 {
+ fill: #fbe6dd;
+}
diff --git a/love/src/components/CommandPanel/StopAllTSCButton/StopAllTSCButton.jsx b/love/src/components/CommandPanel/StopAllTSCButton/StopAllTSCButton.jsx
new file mode 100644
index 000000000..db9d2dd33
--- /dev/null
+++ b/love/src/components/CommandPanel/StopAllTSCButton/StopAllTSCButton.jsx
@@ -0,0 +1,37 @@
+import React, { Component } from 'react';
+import styles from './StopAllTSCButton.module.css';
+import ManagerInterface from 'Utils';
+// import { TCSCommands } from 'Config.js';
+
+export default class StopAllTSCButton extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {};
+ }
+
+ callTSCStopAll() {
+ // TODO: Reference command from variable
+ ManagerInterface.runATCSCommand('stop_all');
+ }
+
+ render() {
+ return (
+
+
+
+ );
+ }
+}
diff --git a/love/src/components/CommandPanel/StopAllTSCButton/StopAllTSCButton.module.css b/love/src/components/CommandPanel/StopAllTSCButton/StopAllTSCButton.module.css
new file mode 100644
index 000000000..b4108ecb4
--- /dev/null
+++ b/love/src/components/CommandPanel/StopAllTSCButton/StopAllTSCButton.module.css
@@ -0,0 +1,40 @@
+.buttonWrapper {
+ height: 200px;
+ width: 200px;
+ text-align: center;
+}
+
+.button {
+ width: 100%;
+ height: 100%;
+ border-radius: 5px;
+ border: 0;
+ padding: 16px;
+ cursor: pointer;
+ background: var(--status-alert-color);
+}
+
+.button:hover {
+ background: var(--status-alert-dimmed-color-2);
+}
+
+.button[disabled] {
+ cursor: not-allowed;
+ background: var(--status-alert-dimmed-color-2);
+}
+
+.svg {
+ height: 100px;
+ width: 100px;
+}
+
+.buttonLabel {
+ display: block;
+ padding: 0.5em 1em;
+ color: white;
+ font-size: var(--font-size-large);
+}
+
+.cls-1 {
+ fill: #fbe6dd;
+}
diff --git a/love/src/components/EventLog/EventLog.container.jsx b/love/src/components/EventLog/EventLog.container.jsx
index c996812ce..2432c3e36 100644
--- a/love/src/components/EventLog/EventLog.container.jsx
+++ b/love/src/components/EventLog/EventLog.container.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import { connect } from 'react-redux';
import EventLog from './EventLog';
-import { addGroup } from '../../redux/actions/ws';
+import { addGroup, removeGroup } from '../../redux/actions/ws';
import { removeCSCLogMessages, removeCSCErrorCodeData } from '../../redux/actions/summaryData';
import { getGroupSortedErrorCodeData, getGroupSortedLogMessageData } from '../../redux/selectors';
import { CSCSummaryHierarchy } from '../../Config';
@@ -48,6 +48,7 @@ const EventLogContainer = ({
logMessageData,
errorCodeData,
subscribeToStreams,
+ unsubscribeToStreams,
heartbeatData,
...props
}) => {
@@ -61,6 +62,7 @@ const EventLogContainer = ({
errorCodeData={errorCodeData}
summaryStateData={summaryStateData}
subscribeToStreams={subscribeToStreams}
+ unsubscribeToStreams={unsubscribeToStreams}
logMessageData={logMessageData}
heartbeatData={heartbeatData}
clearCSCLogMessages={clearCSCLogMessages}
@@ -77,7 +79,13 @@ const mapDispatchToProps = (dispatch) => {
dispatch(addGroup(`event-${nameIndex}-logMessage`));
dispatch(addGroup(`event-${nameIndex}-errorCode`));
});
- // dispatch(addGroup('event-Heartbeat-0-stream'));
+ },
+ unsubscribeToStreams: (cscList) => {
+ cscList.forEach((cscNameIndex) => {
+ const nameIndex = Object.values(cscNameIndex).join('-');
+ dispatch(removeGroup(`event-${nameIndex}-logMessage`));
+ dispatch(removeGroup(`event-${nameIndex}-errorCode`));
+ });
},
clearCSCLogMessages: (cscList) => {
cscList.forEach((cscNameIndex) => {
diff --git a/love/src/components/EventLog/EventLog.jsx b/love/src/components/EventLog/EventLog.jsx
index 65d8e657e..c3f64674b 100644
--- a/love/src/components/EventLog/EventLog.jsx
+++ b/love/src/components/EventLog/EventLog.jsx
@@ -17,6 +17,7 @@ export default class EventLog extends PureComponent {
clearCSCErrorCodes: PropTypes.func,
clearCSCLogMessages: PropTypes.func,
subscribeToStream: PropTypes.func,
+ unsubscribeToStream: PropTypes.func,
errorCodeData: PropTypes.array,
embedded: PropTypes.bool,
};
@@ -58,6 +59,10 @@ export default class EventLog extends PureComponent {
this.props.subscribeToStreams(this.props.cscList);
};
+ componentWillUnmount = () => {
+ this.props.unsubscribeToStreams(this.props.cscList);
+ };
+
clearGroupErrorCodes = () => {
// this.props.cscList.forEach(({ name, salindex }) => {
// this.props.clearCSCErrorCodes(name, salindex);
diff --git a/love/src/components/GeneralPurpose/LogMessageDisplay/LogMessageDisplay.jsx b/love/src/components/GeneralPurpose/LogMessageDisplay/LogMessageDisplay.jsx
index 8f4b0a140..16fa86497 100644
--- a/love/src/components/GeneralPurpose/LogMessageDisplay/LogMessageDisplay.jsx
+++ b/love/src/components/GeneralPurpose/LogMessageDisplay/LogMessageDisplay.jsx
@@ -1,18 +1,19 @@
import React, { useState, memo } from 'react';
import PropTypes from 'prop-types';
-import InfoIcon from '../../icons/InfoIcon/InfoIcon';
-import WarningIcon from '../../icons/WarningIcon/WarningIcon';
-import ErrorIcon from '../../icons/ErrorIcon/ErrorIcon';
+import DebugIcon from '../../icons/CSCExpanded/DebugIcon/DebugIcon';
+import InfoIcon from '../../icons/CSCExpanded/InfoIcon/InfoIcon';
+import WarningIcon from '../../icons/CSCExpanded/WarningIcon/WarningIcon';
+import ErrorIcon from '../../icons/CSCExpanded/ErrorIcon/ErrorIcon';
import Button from '../../GeneralPurpose/Button/Button';
import styles from './LogMessageDisplay.module.css';
import { formatTimestamp } from '../../../Utils';
function LogMessageDisplay({ logMessageData, clearCSCLogMessages }) {
const [messageFilters, setMessageFilters] = useState({
- 10: { value: true, name: 'Debug' },
- 20: { value: true, name: 'Info' },
- 30: { value: true, name: 'Warning' },
- 40: { value: true, name: 'Error' },
+ 10: { value: true, name: 'Debug', icon:
},
+ 20: { value: true, name: 'Info', icon:
},
+ 30: { value: true, name: 'Warning', icon:
},
+ 40: { value: true, name: 'Error', icon:
},
});
const updateFilter = (key, value) => {
@@ -35,13 +36,14 @@ function LogMessageDisplay({ logMessageData, clearCSCLogMessages }) {
return (
);
diff --git a/love/src/components/GeneralPurpose/Plot/PolarPlot/PolarPlot.container.jsx b/love/src/components/GeneralPurpose/Plot/PolarPlot/PolarPlot.container.jsx
index a2da2aad1..b0eac2e6d 100644
--- a/love/src/components/GeneralPurpose/Plot/PolarPlot/PolarPlot.container.jsx
+++ b/love/src/components/GeneralPurpose/Plot/PolarPlot/PolarPlot.container.jsx
@@ -1,13 +1,9 @@
import React from 'react';
import { connect } from 'react-redux';
-import { addGroup, requestGroupRemoval } from 'redux/actions/ws';
+import { addGroup, removeGroup } from 'redux/actions/ws';
import { getStreamsData, getTaiToUtc } from 'redux/selectors/selectors';
import PolarPlot from './PolarPlot';
import ManagerInterface, { parseTimestamp, parsePlotInputs, parseCommanderData } from 'Utils';
-import Moment from 'moment';
-import { extendMoment } from 'moment-range';
-
-const moment = extendMoment(Moment);
export const defaultStyles = [
{
@@ -384,7 +380,7 @@ const mapDispatchToProps = (dispatch, ownProps) => {
const displayDome = ownProps.displayDome || schema.props.displayDome.default;
const groupNames = getGroupNames(inputs, displayDome);
groupNames.forEach((groupName) => {
- dispatch(requestGroupRemoval(groupName));
+ dispatch(removeGroup(groupName));
});
},
};
diff --git a/love/src/components/Layout/Layout.jsx b/love/src/components/Layout/Layout.jsx
index 08cda3a84..b40ce3cca 100644
--- a/love/src/components/Layout/Layout.jsx
+++ b/love/src/components/Layout/Layout.jsx
@@ -75,7 +75,7 @@ class Layout extends Component {
tokenSwapStatus: PropTypes.string,
/** Function to be called when requiring a user swap, similar to a logout */
requireUserSwap: PropTypes.func,
- /** Function to call in order to rese4t subscriptions (when the manager heartbeat is missed) */
+ /** Function to call in order to reset subscriptions (when the manager heartbeat is missed) */
resetSubscriptions: PropTypes.func,
};
@@ -116,9 +116,10 @@ class Layout extends Component {
componentDidMount = () => {
this.moveCustomTopbar();
this.props.subscribeToStreams();
+ this.checkHeartbeat();
this.heartbeatInterval = setInterval(() => {
this.checkHeartbeat();
- }, 3000);
+ }, 10000);
};
componentWillUnmount = () => {
@@ -305,20 +306,22 @@ class Layout extends Component {
};
renderHeartbeatsMenu = () => {
- const producerHeartbeats = [
- HEARTBEAT_COMPONENTS.EVENTS,
- HEARTBEAT_COMPONENTS.TELEMETRIES,
- HEARTBEAT_COMPONENTS.HEARTBEATS,
- HEARTBEAT_COMPONENTS.LOVE,
- HEARTBEAT_COMPONENTS.SCRIPTQUEUE,
- ].map((source) => this.state.heartbeatStatus[source]);
- let producerHeartbeatStatus;
- if (!producerHeartbeats.every((hb) => hb === undefined)) {
- producerHeartbeatStatus = producerHeartbeats.includes('alert') ? 'alert' : 'ok';
- }
+ // const producerHeartbeats = [
+ // HEARTBEAT_COMPONENTS['LOVE:0'],
+ // HEARTBEAT_COMPONENTS['ATDome:0'],
+ // HEARTBEAT_COMPONENTS['ATMCS:0'],
+ // HEARTBEAT_COMPONENTS['Watcher:0'],
+ // HEARTBEAT_COMPONENTS['GenericCamera:0'],
+ // HEARTBEAT_COMPONENTS['ScriptQueue:1'],
+ // HEARTBEAT_COMPONENTS['WeatherStation:1'],
+ // ].map((source) => this.state.heartbeatStatus[source]);
+ // let producerHeartbeatStatus;
+ // if (!producerHeartbeats.every((hb) => hb === undefined)) {
+ // producerHeartbeatStatus = producerHeartbeats.includes('alert') ? 'alert' : 'ok';
+ // }
const summaryHeartbeats = [
- producerHeartbeatStatus,
+ // producerHeartbeatStatus,
this.state.heartbeatStatus[HEARTBEAT_COMPONENTS.MANAGER],
this.state.heartbeatStatus[HEARTBEAT_COMPONENTS.COMMANDER],
];
@@ -326,6 +329,7 @@ class Layout extends Component {
if (!summaryHeartbeats.every((hb) => hb === undefined)) {
summaryHeartbeatStatus = summaryHeartbeats.includes('alert') ? 'alert' : 'ok';
}
+
return (
LOVE manager
-
+ {/** Deprecated: used for old producer version */
+ /*
LOVE producers:
@@ -406,7 +411,7 @@ class Layout extends Component {
>
{HEARTBEAT_COMPONENTS.SCRIPTQUEUE}
-
+
*/}
{
};
const mapDispatchToProps = (dispatch) => {
- const subscriptions = [
- ];
+ const subscriptions = [];
return {
subscriptions,
subscribeToStreams: () => {
diff --git a/love/src/components/MainTel/CableWraps/CableWraps.jsx b/love/src/components/MainTel/CableWraps/CableWraps.jsx
index b1826d3a6..57c60dd21 100755
--- a/love/src/components/MainTel/CableWraps/CableWraps.jsx
+++ b/love/src/components/MainTel/CableWraps/CableWraps.jsx
@@ -22,6 +22,7 @@ class CableWraps extends Component {
}
componentDidMount() {
+ this.props.subscribeToStreams();
// Replace the following code with data from redux selectors
setInterval(
() =>
@@ -39,6 +40,10 @@ class CableWraps extends Component {
);
}
+ componentWillUnmount() {
+ this.props.unsubscribeToStreams();
+ }
+
receiveMsg(msg) {
this.setState({
cable_wraps: msg,
diff --git a/love/src/components/MainTel/M1M3/M1M3.jsx b/love/src/components/MainTel/M1M3/M1M3.jsx
index 190497fa6..7a5cea296 100644
--- a/love/src/components/MainTel/M1M3/M1M3.jsx
+++ b/love/src/components/MainTel/M1M3/M1M3.jsx
@@ -19,6 +19,8 @@ export default class M1M3 extends Component {
}
componentDidMount() {
+ this.props.subscribeToStreams();
+
let yMax = -Infinity;
let xMax = -Infinity;
let yMin = Infinity;
@@ -42,6 +44,10 @@ export default class M1M3 extends Component {
});
}
+ componentWillUnmount() {
+ this.props.unsubscribeToStreams();
+ }
+
componentDidUpdate(prevProps, prevState) {
d3.select('#circle-overlay-' + this.props.id).call(d3.zoom().scaleExtent([1, Infinity]).on('zoom', this.zoomed));
}
diff --git a/love/src/components/ScriptQueue/ConfigPanel/ConfigPanel.jsx b/love/src/components/ScriptQueue/ConfigPanel/ConfigPanel.jsx
index 242f68fe0..49cc90d34 100644
--- a/love/src/components/ScriptQueue/ConfigPanel/ConfigPanel.jsx
+++ b/love/src/components/ScriptQueue/ConfigPanel/ConfigPanel.jsx
@@ -6,6 +6,8 @@ import YAML from 'yaml';
import 'brace/mode/yaml';
import 'brace/theme/solarized_dark';
+import { SCRIPT_DOCUMENTATION_BASE_URL } from 'Config';
+import Select from 'components/GeneralPurpose/Select/Select';
import styles from './ConfigPanel.module.css';
import Button from '../../GeneralPurpose/Button/Button';
import Input from '../../GeneralPurpose/Input/Input';
@@ -14,9 +16,7 @@ import RotateIcon from '../../icons/RotateIcon/RotateIcon';
import CloseIcon from '../../icons/CloseIcon/CloseIcon';
import Hoverable from '../../GeneralPurpose/Hoverable/Hoverable';
import InfoPanel from '../../GeneralPurpose/InfoPanel/InfoPanel';
-import Select from 'components/GeneralPurpose/Select/Select';
import ManagerInterface from '../../../Utils';
-import { SCRIPT_DOCUMENTATION_BASE_URL } from 'Config';
const NO_SCHEMA_MESSAGE = '# ( waiting for schema . . .)';
diff --git a/love/src/components/ScriptQueue/GlobalState/GlobalState.jsx b/love/src/components/ScriptQueue/GlobalState/GlobalState.jsx
index d41540eea..02b67a559 100644
--- a/love/src/components/ScriptQueue/GlobalState/GlobalState.jsx
+++ b/love/src/components/ScriptQueue/GlobalState/GlobalState.jsx
@@ -4,7 +4,7 @@ import styles from './GlobalState.module.css';
import StatusText from 'components/GeneralPurpose/StatusText/StatusText.jsx';
import ResumeIcon from 'components/icons/ScriptQueue/ResumeIcon/ResumeIcon';
import PauseIcon from 'components/icons/ScriptQueue/PauseIcon/PauseIcon';
-import GearIcon from 'components/icons/GearIcon/GearIcon.jsx';
+import GearIcon from 'components/icons/ScriptQueue/GearIcon/GearIcon.jsx';
import ContextMenu from '../Scripts/ContextMenu/ContextMenu';
import CSCDetail from 'components/CSCSummary/CSCDetail/CSCDetail.jsx';
@@ -30,11 +30,13 @@ const GlobalState = ({
}) => {
const [contextMenuIsOpen, setContextMenuIsOpen] = React.useState(false);
const [contextMenuData, setContextMenuData] = React.useState({});
+ const [contextMenuTarget, setContextMenuTarget] = React.useState(undefined);
const onClickContextMenu = React.useCallback((event) => {
event.stopPropagation();
setContextMenuIsOpen((state) => !state);
- setContextMenuData(event.target.getBoundingClientRect());
+ setContextMenuData(event.currentTarget.getBoundingClientRect());
+ setContextMenuTarget(event.currentTarget);
}, []);
React.useEffect(() => {
@@ -137,7 +139,12 @@ const GlobalState = ({
-
+
);
diff --git a/love/src/components/ScriptQueue/GlobalState/GlobalState.module.css b/love/src/components/ScriptQueue/GlobalState/GlobalState.module.css
index 7a2dce49e..609b994aa 100644
--- a/love/src/components/ScriptQueue/GlobalState/GlobalState.module.css
+++ b/love/src/components/ScriptQueue/GlobalState/GlobalState.module.css
@@ -7,6 +7,7 @@
align-items: flex-start;
padding-bottom: 1em;
padding-left: 0.5rem;
+ border-right: 1px solid var(--second-tertiary-background-color);
}
.globalStateContainer {
@@ -15,6 +16,7 @@
padding: 0.5em 0.5em;
height: 100%;
width: 100%;
+ box-sizing: border-box;
}
.title {
@@ -39,7 +41,7 @@
.stateCell {
display: grid;
grid-template-columns: 8em 1fr;
- align-items: baseline;
+ align-items: center;
grid-column-gap: 0.5rem;
}
.stateLabel {
@@ -74,13 +76,6 @@
}
.pauseIconWrapper {
- width: 1em;
- background: var(--commandable-background);
- border: 1px solid var(--commandable-background);
- padding: 0.25em 0.5em;
+ width: 2em;
border-radius: 100%;
}
-
-.gearIcon > path {
- fill: var(--commandable-font-color);
-}
diff --git a/love/src/components/ScriptQueue/ScriptQueue.jsx b/love/src/components/ScriptQueue/ScriptQueue.jsx
index 7aeb5596d..0a47e9032 100644
--- a/love/src/components/ScriptQueue/ScriptQueue.jsx
+++ b/love/src/components/ScriptQueue/ScriptQueue.jsx
@@ -17,8 +17,9 @@ import MoveToBottomIcon from '../icons/ScriptQueue/MoveToBottomIcon/MoveToBottom
import { SALCommandStatus } from '../../redux/actions/ws';
import Input from '../GeneralPurpose/Input/Input';
import GlobalState from './GlobalState/GlobalState';
-import Modal from '../GeneralPurpose/Modal/Modal';
import ScriptDetails from './Scripts/ScriptDetails';
+import CSCExpandedContainer from 'components/CSCSummary/CSCExpanded/CSCExpanded.container';
+import debounce from 'lodash.debounce';
/**
* Display lists of scripts from the ScriptQueue SAL object. It includes: Available scripts list, Waiting scripts list and Finished scripts list.
@@ -36,8 +37,6 @@ export default class ScriptQueue extends Component {
x: 100,
y: 100,
configSchema: '',
- // name: undefined,
- // script: {},
},
state: 'Unknown',
summaryStateValue: 0,
@@ -49,8 +48,15 @@ export default class ScriptQueue extends Component {
availableScriptsStandardExpanded: true,
availableScriptsExternalExpanded: true,
availableScriptsFilter: '',
- scriptModal: null,
+ currentScriptDetailState: {
+ height: 'initial',
+ initialHeight: 350,
+ },
+ resetButton: Hide details ▲,
};
+
+ this.observer = null;
+ this.currentScriptDetailsContainer = React.createRef();
}
static defaultProps = {
@@ -99,6 +105,28 @@ export default class ScriptQueue extends Component {
};
componentDidUpdate = (prevProps, _prevState) => {
+ if (this.props.current !== prevProps.current) {
+ if (this.props.current === 'None') {
+ this.setState((state) => ({
+ currentScriptDetailState: { ...state.currentScriptDetailState, height: 0 },
+ }));
+ } else {
+ this.setState((state) => ({
+ currentScriptDetailState: {
+ ...state.currentScriptDetailState,
+ height: state.currentScriptDetailState.initialHeight,
+ },
+ }));
+ }
+ }
+ if (this.state.currentScriptDetailState !== _prevState.currentScriptDetailState) {
+ if (this.state.currentScriptDetailState.height < this.state.currentScriptDetailState.initialHeight) {
+ this.setState({ resetButton: Show details ▼ });
+ } else {
+ this.setState({ resetButton: Hide details ▲ });
+ }
+ }
+
if (this.props.availableScriptList && this.props.availableScriptList !== prevProps.availableScriptList) {
this.props.availableScriptList.sort((a, b) => {
return a.path.localeCompare(b.path, 'en', { sensitivity: 'base' });
@@ -141,10 +169,60 @@ export default class ScriptQueue extends Component {
componentDidMount = () => {
this.props.subscribeToStreams();
+
+ const debouncedResizeCallback = debounce((entries) => {
+ const newHeight = entries[0].target.clientHeight;
+ // console.log("New height: ", newHeight);
+ if (newHeight >= this.state.currentScriptDetailState.initialHeight) {
+ this.setState((state) => ({
+ currentScriptDetailState: {
+ ...state.currentScriptDetailState,
+ height: state.currentScriptDetailState.initialHeight,
+ },
+ }));
+ } else {
+ this.setState((state) => ({
+ currentScriptDetailState: {
+ ...state.currentScriptDetailState,
+ height: newHeight,
+ },
+ }));
+ }
+ }, 100);
+ this.observer = new ResizeObserver(debouncedResizeCallback);
+ if (this.currentScriptDetailsContainer.current) {
+ const currentHeight = this.currentScriptDetailsContainer.current.clientHeight;
+ this.setState((state) => ({
+ currentScriptDetailState: {
+ ...state.currentScriptDetailState,
+ initialHeight: currentHeight,
+ height: this.props.current === 'None' ? 0 : currentHeight,
+ },
+ }));
+ this.observer.observe(this.currentScriptDetailsContainer.current);
+ }
};
componentWillUnmount = () => {
this.props.unsubscribeToStreams();
+
+ if (this.observer) {
+ this.observer.unobserve(this.currentScriptDetailsContainer.current);
+ }
+ };
+
+ handleResizeButton = () => {
+ const { height, initialHeight } = this.state.currentScriptDetailState;
+ this.setState((state) => ({
+ currentScriptDetailState: {
+ ...state.currentScriptDetailState,
+ height: height >= initialHeight ? 0 : initialHeight,
+ },
+ }));
+ };
+
+ onShowScriptDetails = (script) => {
+ // console.log(script);
};
displayAvailableScripts = () => {
@@ -165,18 +243,6 @@ export default class ScriptQueue extends Component {
return null;
};
- onScriptModalOpen = (script) => () => {
- this.setState({
- scriptModal: script,
- });
- };
-
- onScriptModalClose = (event) => {
- this.setState({
- scriptModal: null,
- });
- };
-
onDragStart = (e, draggingId) => {
if (!this.props.commandExecutePermission) return;
const draggingScriptInstance = this.getScriptFromId(draggingId);
@@ -270,13 +336,13 @@ export default class ScriptQueue extends Component {
};
launchScriptConfig = (e, script) => {
- let { x } = e.target.getBoundingClientRect();
+ const { x } = e.target.getBoundingClientRect();
this.setState({
configPanel: {
- script: script,
+ script,
name: script.name,
show: true,
- x: x,
+ x,
y: 100,
configSchema: script.configSchema,
},
@@ -399,6 +465,7 @@ export default class ScriptQueue extends Component {
});
};
onClickContextMenu = (event, index, currentMenuSelected = false) => {
+ console.log('Click context menu');
event.stopPropagation();
this.setState({ isContextMenuOpen: !this.state.isContextMenuOpen });
this.setState({
@@ -490,7 +557,6 @@ export default class ScriptQueue extends Component {
const finishedScriptListClass = this.state.isFinishedScriptListListVisible ? '' : styles.collapsedScriptList;
const availableScriptListClass = this.state.isAvailableScriptListVisible ? '' : styles.collapsedScriptList;
const current = this.props.current === 'None' ? {} : { ...this.props.current };
-
// const now = new Date();
// Fix time zones for next line
// const currentScriptElapsedTime =
@@ -551,6 +617,19 @@ export default class ScriptQueue extends Component {
contextMenuData={this.state.contextMenuData}
options={contextMenuOption}
/>
+
+
+
@@ -569,23 +648,40 @@ export default class ScriptQueue extends Component {
onClickContextMenu={this.onClickContextMenu}
commandExecutePermission={this.props.commandExecutePermission}
resumeScript={this.resumeScript}
- onClick={this.onScriptModalOpen(current)}
+ onClick={() => null}
+ />
+
+
+
+
+
+
+ {this.state.resetButton}
+
+
+
+
+
+
+ null}
+ displaySummaryState={false}
+ hideTitle={true}
/>
-
{/* LISTS BODY */}
@@ -703,21 +799,25 @@ export default class ScriptQueue extends Component {
draggingScriptInstance={this.state.draggingScriptInstance}
disabled={!this.props.commandExecutePermission}
>
-
+
+ this.onShowScriptDetails(script)}
+ />
+
);
})}
@@ -768,19 +868,21 @@ export default class ScriptQueue extends Component {
: script.timestampProcessEnd - script.timestampRunStart;
return (
-
+
+ this.onShowScriptDetails(script)}
+ />
+
);
})}
@@ -789,17 +891,6 @@ export default class ScriptQueue extends Component {
-
- document.querySelector('#container')}
- size={50}
- /* footerChildren={} */
- >
-
-
);
}
diff --git a/love/src/components/ScriptQueue/ScriptQueue.module.css b/love/src/components/ScriptQueue/ScriptQueue.module.css
index a8a7c4755..64082074c 100644
--- a/love/src/components/ScriptQueue/ScriptQueue.module.css
+++ b/love/src/components/ScriptQueue/ScriptQueue.module.css
@@ -1,9 +1,10 @@
.scriptQueueContainer {
display: grid;
grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr;
- grid-template-rows: min-content 1fr;
+ grid-template-rows: min-content min-content 1fr;
grid-template-areas:
- 'current current current current global global'
+ 'global global current current current current'
+ 'current-details current-details current-details current-details current-details current-details'
'body body body body body body';
color: var(--second-base-font-color);
min-width: 1050px;
@@ -58,13 +59,12 @@
display: flex;
flex-direction: column;
justify-content: center;
- border-right: 1px solid var(--second-tertiary-background-color);
}
.currentScriptContainer {
grid-area: current;
text-align: left;
- padding: 0.5em 0.5em;
+ padding: 0.5em 1em;
}
.currentScriptWrapper {
@@ -77,6 +77,36 @@
display: flex;
}
+.currentScriptDetailsWrapper {
+ grid-area: current-details;
+}
+
+.currentScriptResetSize {
+ text-align: right;
+ margin-right: 1em;
+ padding: 0.5em 0;
+}
+
+.currentScriptDetails {
+ display: grid;
+ grid-template-columns: 40% 60%;
+ margin-bottom: 1em;
+ border-bottom: 1px solid var(--second-tertiary-background-color);
+ /* resize: vertical; */
+ /* overflow-x: hidden; */
+ overflow-y: hidden;
+ transition: all 300ms ease-in-out;
+}
+
+.currentScriptDescription {
+ background: var(--second-secondary-background-color);
+ border-right: 1px solid var(--second-tertiary-background-color);
+}
+
+.currentScriptLogs {
+ overflow-y: scroll;
+}
+
.scriptList {
display: grid;
grid-template-rows: min-content 1fr;
diff --git a/love/src/components/ScriptQueue/Scripts/ContextMenu/ContextMenu.jsx b/love/src/components/ScriptQueue/Scripts/ContextMenu/ContextMenu.jsx
index 63bbb6a96..f6e6bf57c 100644
--- a/love/src/components/ScriptQueue/Scripts/ContextMenu/ContextMenu.jsx
+++ b/love/src/components/ScriptQueue/Scripts/ContextMenu/ContextMenu.jsx
@@ -1,9 +1,9 @@
-import React, { Component } from 'react';
+import React, { PureComponent } from 'react';
import PropTypes from 'prop-types';
import styles from './ContextMenu.module.css';
-export default class ContextMenu extends Component {
+export default class ContextMenu extends PureComponent {
static propTypes = {
/**Position data for the context menu.
* Usually from event.target.getBoundingClientRect()
@@ -26,26 +26,41 @@ export default class ContextMenu extends Component {
disabled: PropTypes.bool,
}),
),
+ /** Target element which triggered the contextmenu */
+ target: PropTypes.object,
};
static defaultProps = {
contextMenuData: {},
isOpen: false,
options: [],
+ target: undefined,
};
constructor(props) {
super(props);
- this.state = {};
+ this.state = {
+ offset: 0,
+ };
}
+ componentDidUpdate = (nextState, nextProps) => {
+ if (this.props.target !== nextProps.target) {
+ const parentCustomView = this.props.target ? this.props.target.closest('.react-grid-item') : undefined;
+ const offset = parentCustomView ? parentCustomView.getBoundingClientRect().x : 0;
+ this.setState({
+ offset,
+ });
+ }
+ };
+
render() {
return (
this.props.isOpen && (
e.stopPropagation()}
diff --git a/love/src/components/ScriptQueue/Scripts/ContextMenu/ContextMenu.module.css b/love/src/components/ScriptQueue/Scripts/ContextMenu/ContextMenu.module.css
index b751be791..4f1b905db 100644
--- a/love/src/components/ScriptQueue/Scripts/ContextMenu/ContextMenu.module.css
+++ b/love/src/components/ScriptQueue/Scripts/ContextMenu/ContextMenu.module.css
@@ -38,11 +38,9 @@ div.buttonText {
.iconWrapper {
background: none;
- border: 1px solid var(--commandable-font-color);
- padding: 0.15em;
border-radius: 100%;
margin-right: 0.4em;
- width: 0.8em;
+ width: 2em;
}
.enabled {
@@ -50,11 +48,6 @@ div.buttonText {
cursor: pointer;
}
-.enabled .iconWrapper {
- border: 1px solid var(--commandable-background);
- background: var(--commandable-background);
+.row:not(.enabled) .iconWrapper path{
+ fill: initial;
}
-
-/* .disabled:hover > svg {
- background: none;
-} */
diff --git a/love/src/components/ScriptQueue/Scripts/CurrentScript/CurrentScript.module.css b/love/src/components/ScriptQueue/Scripts/CurrentScript/CurrentScript.module.css
index 88d115cfc..f7355b9fc 100644
--- a/love/src/components/ScriptQueue/Scripts/CurrentScript/CurrentScript.module.css
+++ b/love/src/components/ScriptQueue/Scripts/CurrentScript/CurrentScript.module.css
@@ -1,6 +1,5 @@
.currentScriptContainer {
padding: 0.5em;
- cursor: pointer;
user-select: none;
}
diff --git a/love/src/components/ScriptQueue/Scripts/FinishedScript/FinishedScript.jsx b/love/src/components/ScriptQueue/Scripts/FinishedScript/FinishedScript.jsx
index f319143ad..d6723e7d6 100644
--- a/love/src/components/ScriptQueue/Scripts/FinishedScript/FinishedScript.jsx
+++ b/love/src/components/ScriptQueue/Scripts/FinishedScript/FinishedScript.jsx
@@ -42,9 +42,13 @@ export default class FinishedScript extends PureComponent {
constructor(props) {
super(props);
+ this.state = {
+ expanded: false,
+ };
}
onClick = () => {
+ this.setState((state) => ({ expanded: !state.expanded }));
this.props.onClick();
};
@@ -126,6 +130,11 @@ export default class FinishedScript extends PureComponent {
+
+
+
{this.props.commandExecutePermission && (
this.props.requeueScript(this.props.index)}>
diff --git a/love/src/components/ScriptQueue/Scripts/ScriptDetails.jsx b/love/src/components/ScriptQueue/Scripts/ScriptDetails.jsx
index 7f3452e49..2df9c7367 100644
--- a/love/src/components/ScriptQueue/Scripts/ScriptDetails.jsx
+++ b/love/src/components/ScriptQueue/Scripts/ScriptDetails.jsx
@@ -87,15 +87,6 @@ export default ({
);
})}
-
- console.log(a)}
- displaySummaryState={false}
- />
-
);
diff --git a/love/src/components/ScriptQueue/Scripts/Scripts.module.css b/love/src/components/ScriptQueue/Scripts/Scripts.module.css
index 60f6b980b..b6fc31c15 100644
--- a/love/src/components/ScriptQueue/Scripts/Scripts.module.css
+++ b/love/src/components/ScriptQueue/Scripts/Scripts.module.css
@@ -147,6 +147,7 @@
}
.expandedSectionWrapper {
+ border-top: 1px solid gray;
padding: 0.5em;
}
@@ -172,6 +173,7 @@
color: var(--highlighted-font-color);
font-size: var(--font-size-large);
grid-column-start: span 2;
+ text-align: left;
}
.subSectionLabel {
@@ -194,47 +196,27 @@
grid-column-gap: 0.2em;
}
-.buttonContainer {
- padding: 0;
- border: 1px solid transparent;
- white-space: pre;
- background: var(--commandable-background);
- border-radius: 100%;
- height: 1.5em;
- width: 1.5em;
- display: flex;
- justify-content: center;
-}
-
.noBackgroundButton {
background: none;
line-height: 1em;
}
.buttonContainer:hover {
- /* background: var(--script-ok-color); */
background: var(--commandable-background-hover);
- border: 1px solid var(--commandable-background);
}
.commandButton {
display: grid;
- /* grid-template-columns: 2em 1fr; */
padding: 0em;
text-align: left;
align-items: center;
user-select: none;
}
-.commandButton div {
- padding: 0 0.3em;
-}
-
div.commandButtonText {
padding-left: 0em;
}
.compact {
- /* grid-template-columns: 2em 0; */
width: 1.8em;
}
diff --git a/love/src/components/ScriptQueue/Scripts/WaitingScript/WaitingScript.jsx b/love/src/components/ScriptQueue/Scripts/WaitingScript/WaitingScript.jsx
index 3007186a8..887d94406 100644
--- a/love/src/components/ScriptQueue/Scripts/WaitingScript/WaitingScript.jsx
+++ b/love/src/components/ScriptQueue/Scripts/WaitingScript/WaitingScript.jsx
@@ -61,9 +61,13 @@ export default class WaitingScript extends PureComponent {
constructor(props) {
super(props);
+ this.state = {
+ expanded: false,
+ };
}
onClick = () => {
+ this.setState((state) => ({ expanded: !state.expanded }));
this.props.onClick();
};
@@ -222,6 +226,11 @@ export default class WaitingScript extends PureComponent {
+
+
+
);
diff --git a/love/src/components/TCSCommands/TCSCommands.container.jsx b/love/src/components/TCSCommands/TCSCommands.container.jsx
new file mode 100644
index 000000000..076841c15
--- /dev/null
+++ b/love/src/components/TCSCommands/TCSCommands.container.jsx
@@ -0,0 +1,69 @@
+import React from 'react';
+import { connect } from 'react-redux';
+import { addGroup, removeGroup, requestSALCommand } from '../../redux/actions/ws';
+import { getPermCmdExec, getScriptQueueState } from '../../redux/selectors';
+import TCSCommands from './TCSCommands';
+
+export const schema = {
+ description: 'Panel containing multiple buttons that execute different commands, such as closing the dome',
+ defaultSize: [57, 35],
+ props: {
+ title: {
+ type: 'string',
+ description: 'Name diplayed in the title bar (if visible)',
+ isPrivate: false,
+ default: 'TCS Commands',
+ },
+ hasRawMode: {
+ type: 'boolean',
+ description: 'Whether the component has a raw mode version',
+ isPrivate: true,
+ default: false,
+ },
+ },
+};
+
+const TCSCommandsContainer = ({
+ queueState,
+ commandExecutePermission,
+ subscribeToStreams,
+ unsubscribeToStreams,
+ ...props
+}) => {
+ return (
+
+ );
+};
+
+const mapDispatchToProps = (dispatch, ownProps) => {
+ const subscriptions = [`event-ScriptQueueState-1-stream`];
+ return {
+ subscriptions,
+ subscribeToStreams: () => {
+ subscriptions.forEach((stream) => dispatch(addGroup(stream)));
+ },
+ unsubscribeToStreams: () => {
+ subscriptions.forEach((stream) => dispatch(removeGroup(stream)));
+ },
+ requestSALCommand: (component, salindex, cmd) => {
+ return dispatch(requestSALCommand({ ...cmd, component, salindex }));
+ },
+ };
+};
+
+const mapStateToProps = (state) => {
+ const commandExecutePermission = getPermCmdExec(state);
+ const queueState = getScriptQueueState(state, 1);
+ return {
+ commandExecutePermission: commandExecutePermission,
+ queueState: queueState,
+ };
+};
+
+export default connect(mapStateToProps, mapDispatchToProps)(TCSCommandsContainer);
diff --git a/love/src/components/TCSCommands/TCSCommands.jsx b/love/src/components/TCSCommands/TCSCommands.jsx
new file mode 100644
index 000000000..a2f023616
--- /dev/null
+++ b/love/src/components/TCSCommands/TCSCommands.jsx
@@ -0,0 +1,189 @@
+import React, { Component } from 'react';
+import styles from './TCSCommands.module.css';
+import Select from 'components/GeneralPurpose/Select/Select';
+import Input from 'components/GeneralPurpose/Input/Input';
+import Button from 'components/GeneralPurpose/Button/Button';
+import Modal from 'components/GeneralPurpose/Modal/Modal';
+import ScriptQueue from 'components/ScriptQueue/ScriptQueue';
+import StatusText from 'components/GeneralPurpose/StatusText/StatusText.jsx';
+import HelpIcon from 'components/icons/HelpIcon/HelpIcon';
+import WarningIcon from 'components/icons/WarningIcon/WarningIcon';
+import { TCSCommands } from 'Config.js';
+import ManagerInterface from 'Utils';
+import { Remarkable } from 'remarkable';
+
+var md = new Remarkable();
+
+const angleRegExp = new RegExp(/(\d\d(:| )\d\d(:| )\d\d)+(\.\d{1,10})?$/);
+const floatRegExp = new RegExp(/^-?\d*(\.\d+)?$/);
+
+export default class CommandPanel extends Component {
+ constructor(props) {
+ super(props);
+ this.state = {
+ selectedCommand: null,
+ paramValues: {},
+ paramWarnings: {},
+ docstrings: {},
+ isModalOpen: false,
+ };
+ }
+
+ componentDidMount = () => {
+ this.props.subscribeToStreams();
+ ManagerInterface.getATCSDocstrings().then((data) => {
+ this.setState({
+ docstrings: data,
+ });
+ });
+ };
+
+ componentWillUnmount = () => {
+ this.props.unsubscribeToStreams();
+ };
+
+ updateParamValue = (name, value, paramType) => {
+ this.setState({
+ paramValues: {
+ ...this.state.paramValues,
+ [name]: value,
+ },
+ });
+ };
+
+ checkInvalidAngle = (name, value) => {
+ const testValue = value ?? '';
+ this.setState({
+ paramWarnings: {
+ ...this.state.paramWarnings,
+ [name]: isNaN(parseFloat(testValue.match(floatRegExp))) && !angleRegExp.test(testValue),
+ },
+ });
+ };
+
+ renderParam = (name, param) => {
+ const [paramType, defaultValue] = param;
+ const { paramValues } = this.state;
+ return (
+
+
{name}
+ {paramType == 'string' && (
+
this.updateParamValue(name, e.target.value, paramType)} />
+ )}
+ {paramType == 'number' && (
+
this.updateParamValue(name, e.target.value, paramType)} />
+ )}
+ {paramType == 'angle' && (
+ <>
+
this.updateParamValue(name, e.target.value, paramType)}
+ onBlur={() => this.checkInvalidAngle(name, paramValues[name])}
+ />
+ {this.state.paramWarnings[name] && (
+
+ Angle should be a float (deg) or a sexagesimal string (DD:MM:SS.S or DD MM SS.S)
+
+ )}
+ >
+ )}
+ {paramType == 'boolean' && (
+
this.updateParamValue(name, e.target.checked, paramType)}
+ />
+ )}
+ {Array.isArray(paramType) && (
+
+ );
+ };
+
+ selectCommand = (commandName) => {
+ const paramsDict = TCSCommands[commandName] ?? {};
+ const paramNames = Object.keys(paramsDict);
+ const paramValues = {};
+ paramNames.forEach((paramName) => (paramValues[paramName] = paramsDict[paramName][1]));
+ this.setState({ selectedCommand: commandName, paramValues });
+ };
+
+ render() {
+ const paramsDict = TCSCommands[this.state.selectedCommand] ?? {};
+ const queueState = {
+ statusText: ScriptQueue.stateStyleDict[this.props.state],
+ name: this.props.state,
+ };
+ const isAvailable = queueState.name !== 'Running';
+ return (
+
+
this.setState({ isModalOpen: false })}
+ contentLabel="Component selection modal"
+ size={50}
+ >
+ {this.state.docstrings[this.state.selectedCommand] ? (
+
+ ) : (
+ No documentation available
+ )}
+
+
+ AUX TEL QUEUE STATE
+ {queueState.name}
+
+
+
+
+ TCS commands are not allowed while queue is running
+
+
+
+
+
+
+ {Object.keys(paramsDict).map((key, index) => {
+ const param = paramsDict[key];
+ return
{this.renderParam(key, param)}
;
+ })}
+
+ {this.state.selectedCommand && (
+
+
+
+ )}
+
+ );
+ }
+}
diff --git a/love/src/components/TCSCommands/TCSCommands.module.css b/love/src/components/TCSCommands/TCSCommands.module.css
new file mode 100644
index 000000000..0d2410a2c
--- /dev/null
+++ b/love/src/components/TCSCommands/TCSCommands.module.css
@@ -0,0 +1,100 @@
+.container {
+ display: grid;
+ grid-template-rows: min-content 1fr min-content;
+ row-gap: 1em;
+ height: 100%;
+}
+
+.containerExtraRow {
+ grid-template-rows: min-content min-content 1fr min-content;
+}
+
+.selectContainer {
+ cursor: pointer;
+ display: grid;
+ grid-template-columns: 1fr min-content;
+ align-items: center;
+}
+
+.select {
+ cursor: pointer;
+}
+
+.commandParamsContainer {
+}
+
+.paramContainer {
+ display: grid;
+ grid-template-columns: 1fr;
+ padding: 0.5em;
+ text-align: left;
+}
+
+.paramLabel {
+ padding-left: 0.5em;
+}
+
+.checkboxParam {
+ grid-template-columns: 1fr min-content;
+}
+
+.sendButtonContainer {
+ padding: 1em;
+}
+
+.markdown {
+ text-align: left;
+}
+
+.markdown pre {
+ white-space: pre-wrap;
+}
+
+.buttonWrapper {
+ padding-left: 0.5em;
+ width: 1em;
+}
+
+.hidden {
+ visibility: hidden;
+}
+
+.queueStateContainer {
+ display: grid;
+ grid-template-columns: 1fr 12em;
+ border-bottom: solid var(--second-tertiary-background-color) 1px;
+ padding: 0.5em 0em;
+ align-items: center;
+}
+
+.queueStateLabel {
+ color: var(--base-font-color);
+ font-size: var(--font-size-medium);
+ font-weight: bold;
+ justify-self: left;
+}
+
+.warningText {
+ justify-self: left;
+ display: grid;
+ grid-template-columns: min-content 1fr;
+ grid-column: 1 / span 2;
+ align-items: center;
+}
+
+.warningIcon {
+ width: 1em;
+ min-width: 1em;
+ padding: 0.5em;
+ text-align: center;
+ user-select: none;
+ vertical-align: top;
+}
+
+.warningIcon svg {
+ vertical-align: middle;
+}
+
+.removed {
+ display: none;
+}
diff --git a/love/src/components/UIF/ComponentIndex.jsx b/love/src/components/UIF/ComponentIndex.jsx
index dc1a3dd11..050ced216 100644
--- a/love/src/components/UIF/ComponentIndex.jsx
+++ b/love/src/components/UIF/ComponentIndex.jsx
@@ -320,6 +320,16 @@ export const utilitiesIndex = {
},
},
},
+ TCSCommands: {
+ component: require('../TCSCommands/TCSCommands.container').default,
+ schema: {
+ ...require('../TCSCommands/TCSCommands.container').schema,
+ props: {
+ ...defaultSchemaProps,
+ ...require('../TCSCommands/TCSCommands.container').schema.props,
+ },
+ },
+ },
};
export const internalIndex = {
diff --git a/love/src/components/icons/CSCExpanded/DebugIcon/DebugIcon.jsx b/love/src/components/icons/CSCExpanded/DebugIcon/DebugIcon.jsx
new file mode 100644
index 000000000..90cb5e828
--- /dev/null
+++ b/love/src/components/icons/CSCExpanded/DebugIcon/DebugIcon.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import styles from './DebugIcon.module.css';
+
+export default function DebugIcon(props) {
+ const className = [styles.svg, props.className].join(' ');
+ return (
+
+
+
+
+
+ );
+}
diff --git a/love/src/components/icons/CSCExpanded/DebugIcon/DebugIcon.module.css b/love/src/components/icons/CSCExpanded/DebugIcon/DebugIcon.module.css
new file mode 100644
index 000000000..569c34455
--- /dev/null
+++ b/love/src/components/icons/CSCExpanded/DebugIcon/DebugIcon.module.css
@@ -0,0 +1,11 @@
+.svg {
+ vertical-align: middle;
+}
+
+.cls-1 {
+ fill: #70b5ba;
+}
+
+.cls-2 {
+ fill: #2a3f4b;
+}
diff --git a/love/src/components/icons/CSCExpanded/ErrorIcon/ErrorIcon.jsx b/love/src/components/icons/CSCExpanded/ErrorIcon/ErrorIcon.jsx
new file mode 100644
index 000000000..435199189
--- /dev/null
+++ b/love/src/components/icons/CSCExpanded/ErrorIcon/ErrorIcon.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import styles from './ErrorIcon.module.css';
+
+export default function ErrorIcon(props) {
+ const className = [styles.svg, props.className].join(' ');
+ return (
+
+
+
+
+ );
+}
diff --git a/love/src/components/icons/CSCExpanded/ErrorIcon/ErrorIcon.module.css b/love/src/components/icons/CSCExpanded/ErrorIcon/ErrorIcon.module.css
new file mode 100644
index 000000000..e3c4320ef
--- /dev/null
+++ b/love/src/components/icons/CSCExpanded/ErrorIcon/ErrorIcon.module.css
@@ -0,0 +1,14 @@
+.svg {
+ vertical-align: middle;
+}
+
+.cls-1 {
+ fill: #ff6900;
+}
+
+.cls-2 {
+ fill: #2a3f4b;
+ stroke: #2a3f4b;
+ stroke-miterlimit: 10;
+ stroke-width: 2px;
+}
diff --git a/love/src/components/icons/CSCExpanded/InfoIcon/InfoIcon.jsx b/love/src/components/icons/CSCExpanded/InfoIcon/InfoIcon.jsx
new file mode 100644
index 000000000..ec3782675
--- /dev/null
+++ b/love/src/components/icons/CSCExpanded/InfoIcon/InfoIcon.jsx
@@ -0,0 +1,21 @@
+import React from 'react';
+import styles from './InfoIcon.module.css';
+
+export default function InfoIcon(props) {
+ const className = [styles.svg, props.className].join(' ');
+ return (
+
+
+
+
+
+ );
+}
diff --git a/love/src/components/icons/CSCExpanded/InfoIcon/InfoIcon.module.css b/love/src/components/icons/CSCExpanded/InfoIcon/InfoIcon.module.css
new file mode 100644
index 000000000..cb3cdaa8d
--- /dev/null
+++ b/love/src/components/icons/CSCExpanded/InfoIcon/InfoIcon.module.css
@@ -0,0 +1,11 @@
+.svg {
+ vertical-align: middle;
+}
+
+.cls-1 {
+ fill: #39b2c0;
+}
+
+.cls-2 {
+ fill: #2a3f4b;
+}
diff --git a/love/src/components/icons/CSCExpanded/WarningIcon/WarningIcon.jsx b/love/src/components/icons/CSCExpanded/WarningIcon/WarningIcon.jsx
new file mode 100644
index 000000000..dc2a89bb4
--- /dev/null
+++ b/love/src/components/icons/CSCExpanded/WarningIcon/WarningIcon.jsx
@@ -0,0 +1,25 @@
+import React from 'react';
+import styles from './WarningIcon.module.css';
+
+export default function WarningIcon(props) {
+ const className = [styles.svg, props.className].join(' ');
+ return (
+
+
+
+
+
+ );
+}
diff --git a/love/src/components/icons/CSCExpanded/WarningIcon/WarningIcon.module.css b/love/src/components/icons/CSCExpanded/WarningIcon/WarningIcon.module.css
new file mode 100644
index 000000000..6b30c071c
--- /dev/null
+++ b/love/src/components/icons/CSCExpanded/WarningIcon/WarningIcon.module.css
@@ -0,0 +1,11 @@
+.svg {
+ vertical-align: middle;
+}
+
+.cls-1 {
+ fill: #eee200;
+}
+
+.cls-2 {
+ fill: #2a3f4b;
+}
diff --git a/love/src/components/icons/GearIcon/GearIcon.module.css b/love/src/components/icons/GearIcon/GearIcon.module.css
index 250b34895..ce73d25cb 100644
--- a/love/src/components/icons/GearIcon/GearIcon.module.css
+++ b/love/src/components/icons/GearIcon/GearIcon.module.css
@@ -1,13 +1,13 @@
.gearIcon {
display: inline-block;
- max-height: 100%;
- stroke-miterlimit: 10;
- stroke-width: 2px;
+ max-height:100%;
+ stroke-miterlimit:10;
+ stroke-width:2px;
vertical-align: middle;
}
.active {
- fill: var(--base-font-color);
+ fill:var(--base-font-color);
}
.inactive {
diff --git a/love/src/components/icons/HelpIcon/HelpIcon.jsx b/love/src/components/icons/HelpIcon/HelpIcon.jsx
new file mode 100644
index 000000000..cc98318bd
--- /dev/null
+++ b/love/src/components/icons/HelpIcon/HelpIcon.jsx
@@ -0,0 +1,18 @@
+import React from 'react';
+import styles from './HelpIcon.module.css';
+
+class HelpIcon extends React.Component {
+ render() {
+ return (
+
+
+
+ );
+ }
+}
+
+export default HelpIcon;
diff --git a/love/src/components/icons/HelpIcon/HelpIcon.module.css b/love/src/components/icons/HelpIcon/HelpIcon.module.css
new file mode 100644
index 000000000..fff2b02f4
--- /dev/null
+++ b/love/src/components/icons/HelpIcon/HelpIcon.module.css
@@ -0,0 +1,8 @@
+.helpIcon {
+ display: inline-block;
+ fill: var(--secondary-font-color);
+ fill-rule: evenodd;
+ width: 1em;
+ padding-right: 0.5em;
+ padding-left: 0.25em;
+}
diff --git a/love/src/components/icons/ScriptQueue/GearIcon/GearIcon.jsx b/love/src/components/icons/ScriptQueue/GearIcon/GearIcon.jsx
new file mode 100644
index 000000000..9eb2754ef
--- /dev/null
+++ b/love/src/components/icons/ScriptQueue/GearIcon/GearIcon.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import styles from './GearIcon.module.css';
+
+export default function GearIcon(props) {
+ const className = [styles.gearIcon, props.className].join(' ');
+ return (
+
+
+
+
+ );
+}
diff --git a/love/src/components/icons/ScriptQueue/GearIcon/GearIcon.module.css b/love/src/components/icons/ScriptQueue/GearIcon/GearIcon.module.css
new file mode 100644
index 000000000..df70827df
--- /dev/null
+++ b/love/src/components/icons/ScriptQueue/GearIcon/GearIcon.module.css
@@ -0,0 +1,14 @@
+.gearIcon {
+ vertical-align: middle;
+}
+
+.cls-1{
+ fill:none;
+ stroke:#1ecfe8;
+ stroke-miterlimit:10;
+ stroke-width:2px;
+}
+
+.cls-2{
+ fill:#1ecfe8;
+}
\ No newline at end of file
diff --git a/love/src/components/icons/ScriptQueue/LaunchScriptIcon/LaunchScriptIcon.jsx b/love/src/components/icons/ScriptQueue/LaunchScriptIcon/LaunchScriptIcon.jsx
index 962bdc567..377c74393 100644
--- a/love/src/components/icons/ScriptQueue/LaunchScriptIcon/LaunchScriptIcon.jsx
+++ b/love/src/components/icons/ScriptQueue/LaunchScriptIcon/LaunchScriptIcon.jsx
@@ -9,29 +9,31 @@ export default class LaunchScriptIcon extends Component {
render() {
return (
-
+
{this.props.title}
-
-
+
);
diff --git a/love/src/components/icons/ScriptQueue/LaunchScriptIcon/LaunchScriptIcon.module.css b/love/src/components/icons/ScriptQueue/LaunchScriptIcon/LaunchScriptIcon.module.css
index c4ab0b91d..7bdb584d9 100644
--- a/love/src/components/icons/ScriptQueue/LaunchScriptIcon/LaunchScriptIcon.module.css
+++ b/love/src/components/icons/ScriptQueue/LaunchScriptIcon/LaunchScriptIcon.module.css
@@ -1,11 +1,24 @@
-.classOne {
- fill: none;
- /* stroke: var(--second-base-font-color); */
- stroke: var(--commandable-font-color);
+.svg {
+ vertical-align: middle;
+}
+
+.cls-1 {
+ fill: #122632;
+ opacity: 0.99;
+}
+
+.cls-2 {
+ fill: #1ecfe8;
+}
+
+.cls-1, .cls-2 {
+ fill-rule: evenodd;
+}
+
+.cls-3 {
+ fill: #2b414d;
+ stroke: #1ecfe8;
stroke-linecap: round;
stroke-linejoin: round;
-}
-.classTwo {
- /* fill: var(--second-base-font-color); */
- fill: var(--commandable-font-color);
+ stroke-width: 2px;
}
diff --git a/love/src/components/icons/ScriptQueue/MoveDownIcon/MoveDownIcon.jsx b/love/src/components/icons/ScriptQueue/MoveDownIcon/MoveDownIcon.jsx
index 2c416ade7..5d0e7faad 100644
--- a/love/src/components/icons/ScriptQueue/MoveDownIcon/MoveDownIcon.jsx
+++ b/love/src/components/icons/ScriptQueue/MoveDownIcon/MoveDownIcon.jsx
@@ -4,13 +4,12 @@ import styles from './MoveDownIcon.module.css';
export default class MoveDownIcon extends Component {
render() {
return (
-
+
{'Move script down'}
);
diff --git a/love/src/components/icons/ScriptQueue/MoveDownIcon/MoveDownIcon.module.css b/love/src/components/icons/ScriptQueue/MoveDownIcon/MoveDownIcon.module.css
index c85578dd0..3dad44dfa 100644
--- a/love/src/components/icons/ScriptQueue/MoveDownIcon/MoveDownIcon.module.css
+++ b/love/src/components/icons/ScriptQueue/MoveDownIcon/MoveDownIcon.module.css
@@ -1,8 +1,7 @@
-.path {
- fill: var(--commandable-font-color);
- stroke: var(--commandable-font-color);
-}
-
.svg {
vertical-align: middle;
}
+
+.cls-1 {
+ fill: #1ecfe8;
+}
diff --git a/love/src/components/icons/ScriptQueue/MoveUpIcon/MoveUpIcon.jsx b/love/src/components/icons/ScriptQueue/MoveUpIcon/MoveUpIcon.jsx
index 303a34dba..a1444fb69 100644
--- a/love/src/components/icons/ScriptQueue/MoveUpIcon/MoveUpIcon.jsx
+++ b/love/src/components/icons/ScriptQueue/MoveUpIcon/MoveUpIcon.jsx
@@ -4,14 +4,12 @@ import styles from './MoveUpIcon.module.css';
export default class MoveUpIcon extends Component {
render() {
return (
-
- {'Move script up'}
+
+ Move script up
);
diff --git a/love/src/components/icons/ScriptQueue/MoveUpIcon/MoveUpIcon.module.css b/love/src/components/icons/ScriptQueue/MoveUpIcon/MoveUpIcon.module.css
index 5f4358aff..3dad44dfa 100644
--- a/love/src/components/icons/ScriptQueue/MoveUpIcon/MoveUpIcon.module.css
+++ b/love/src/components/icons/ScriptQueue/MoveUpIcon/MoveUpIcon.module.css
@@ -1,19 +1,7 @@
-.st0 {
- fill: none;
- stroke: var(--second-base-font-color);
- stroke-linecap: round;
- stroke-linejoin: round;
-}
-
-.st1 {
- fill: var(--second-base-font-color);
-}
-
.svg {
vertical-align: middle;
}
-.svg path {
- fill: var(--commandable-font-color);
- stroke: var(--commandable-font-color);
+.cls-1 {
+ fill: #1ecfe8;
}
diff --git a/love/src/components/icons/ScriptQueue/PauseIcon/PauseIcon.jsx b/love/src/components/icons/ScriptQueue/PauseIcon/PauseIcon.jsx
index ec1c9f579..1f26019cf 100644
--- a/love/src/components/icons/ScriptQueue/PauseIcon/PauseIcon.jsx
+++ b/love/src/components/icons/ScriptQueue/PauseIcon/PauseIcon.jsx
@@ -4,14 +4,11 @@ import styles from './PauseIcon.module.css';
export default class PauseIcon extends Component {
render() {
return (
-
+
-
);
diff --git a/love/src/components/icons/ScriptQueue/PauseIcon/PauseIcon.module.css b/love/src/components/icons/ScriptQueue/PauseIcon/PauseIcon.module.css
index a75696d28..77c076a80 100644
--- a/love/src/components/icons/ScriptQueue/PauseIcon/PauseIcon.module.css
+++ b/love/src/components/icons/ScriptQueue/PauseIcon/PauseIcon.module.css
@@ -1,14 +1,5 @@
-.st0 {
- fill: var(--second-primary-background-color);
- stroke: var(--second-primary-background-color);
- stroke-miterlimit: 10;
-}
-
-.svg {
+.pauseIcon {
vertical-align: middle;
}
-.svg path {
- fill: var(--commandable-font-color);
- stroke: var(--commandable-font-color);
-}
+.cls-1{fill:#1ecfe8;}
\ No newline at end of file
diff --git a/love/src/components/icons/ScriptQueue/RequeueIcon/RequeueIcon.jsx b/love/src/components/icons/ScriptQueue/RequeueIcon/RequeueIcon.jsx
index dfbbdf8a1..aa2d47bae 100644
--- a/love/src/components/icons/ScriptQueue/RequeueIcon/RequeueIcon.jsx
+++ b/love/src/components/icons/ScriptQueue/RequeueIcon/RequeueIcon.jsx
@@ -3,35 +3,41 @@ import styles from './RequeueIcon.module.css';
export default class RequeueIcon extends Component {
render() {
- const status = this.props.active !== undefined && this.props.active === false ? styles.inactive : styles.active;
- const title = this.props.title ? this.props.title : 'Requeue script';
return (
-
- {title}
+
+ {this.props.title}
+
);
diff --git a/love/src/components/icons/ScriptQueue/RequeueIcon/RequeueIcon.module.css b/love/src/components/icons/ScriptQueue/RequeueIcon/RequeueIcon.module.css
index b6029e4c3..b1ba2949c 100644
--- a/love/src/components/icons/ScriptQueue/RequeueIcon/RequeueIcon.module.css
+++ b/love/src/components/icons/ScriptQueue/RequeueIcon/RequeueIcon.module.css
@@ -1,26 +1,22 @@
-.st0 {
- fill: none;
- stroke: var(--second-primary-background-color);
- stroke-linecap: round;
- stroke-linejoin: round;
-}
-
-.st1 {
- fill: var(--second-primary-background-color);
-}
-
.svg {
vertical-align: middle;
}
-.active {
- stroke: var(--second-primary-background-color);
+.cls-1 {
+ fill: #122632;
+ opacity: 0.99;
+}
+
+.cls-3 {
+ stroke: #2b414d;
+ stroke-linecap: round;
+ stroke-linejoin: round;
}
-.inactive {
- stroke: var(--secondary-font-color);
+.cls-1, .cls-2 {
+ fill-rule: evenodd;
}
-.svg path {
- stroke: var(--commandable-font-color);
+.cls-2, .cls-3 {
+ fill: #1ecfe8;
}
diff --git a/love/src/components/icons/ScriptQueue/ResumeIcon/ResumeIcon.jsx b/love/src/components/icons/ScriptQueue/ResumeIcon/ResumeIcon.jsx
index a942b5b81..e4700db41 100644
--- a/love/src/components/icons/ScriptQueue/ResumeIcon/ResumeIcon.jsx
+++ b/love/src/components/icons/ScriptQueue/ResumeIcon/ResumeIcon.jsx
@@ -4,10 +4,11 @@ import styles from './ResumeIcon.module.css';
export default class ResumeIcon extends Component {
render() {
return (
-
+
);
diff --git a/love/src/components/icons/ScriptQueue/ResumeIcon/ResumeIcon.module.css b/love/src/components/icons/ScriptQueue/ResumeIcon/ResumeIcon.module.css
index 9e8a00a5a..c4131e41f 100644
--- a/love/src/components/icons/ScriptQueue/ResumeIcon/ResumeIcon.module.css
+++ b/love/src/components/icons/ScriptQueue/ResumeIcon/ResumeIcon.module.css
@@ -1,7 +1,5 @@
-.st0 {
- fill: var(--commandable-font-color);
- stroke: var(--commandable-font-color);
- stroke-miterlimit: 10;
+.cls-1{
+ fill:#1ecfe8;
}
.svg {
diff --git a/love/src/components/icons/ScriptQueue/StopIcon/StopIcon.jsx b/love/src/components/icons/ScriptQueue/StopIcon/StopIcon.jsx
index 1e9ef93bd..ecfffbd5d 100644
--- a/love/src/components/icons/ScriptQueue/StopIcon/StopIcon.jsx
+++ b/love/src/components/icons/ScriptQueue/StopIcon/StopIcon.jsx
@@ -4,13 +4,13 @@ import styles from './StopIcon.module.css';
export default class StopIcon extends Component {
render() {
return (
-
+
{'Stop script'}
-
);
}
diff --git a/love/src/components/icons/ScriptQueue/StopIcon/StopIcon.module.css b/love/src/components/icons/ScriptQueue/StopIcon/StopIcon.module.css
index 94a78c8d4..3dad44dfa 100644
--- a/love/src/components/icons/ScriptQueue/StopIcon/StopIcon.module.css
+++ b/love/src/components/icons/ScriptQueue/StopIcon/StopIcon.module.css
@@ -1,14 +1,7 @@
-.st0 {
- fill: #798d99;
- stroke: #798d99;
- stroke-miterlimit: 10;
-}
-
.svg {
vertical-align: middle;
}
-.svg path {
- fill: var(--commandable-font-color);
- stroke: var(--commandable-font-color);
+.cls-1 {
+ fill: #1ecfe8;
}
diff --git a/love/src/components/icons/ScriptQueue/TerminateIcon/TerminateIcon.jsx b/love/src/components/icons/ScriptQueue/TerminateIcon/TerminateIcon.jsx
index 6258f27a9..d4203001b 100644
--- a/love/src/components/icons/ScriptQueue/TerminateIcon/TerminateIcon.jsx
+++ b/love/src/components/icons/ScriptQueue/TerminateIcon/TerminateIcon.jsx
@@ -4,15 +4,12 @@ import styles from './TerminateIcon.module.css';
export default class TerminateIcon extends Component {
render() {
return (
-
+
{'Terminate script'}
-
);
diff --git a/love/src/components/icons/ScriptQueue/TerminateIcon/TerminateIcon.module.css b/love/src/components/icons/ScriptQueue/TerminateIcon/TerminateIcon.module.css
index 8ffbe104e..3dad44dfa 100644
--- a/love/src/components/icons/ScriptQueue/TerminateIcon/TerminateIcon.module.css
+++ b/love/src/components/icons/ScriptQueue/TerminateIcon/TerminateIcon.module.css
@@ -1,11 +1,7 @@
-.st0 {
- stroke-miterlimit: 10;
-}
-
.svg {
vertical-align: middle;
}
-.svg path {
- stroke: var(--commandable-font-color);
+.cls-1 {
+ fill: #1ecfe8;
}
diff --git a/love/src/redux/actions/ws.js b/love/src/redux/actions/ws.js
index 52a0e91a9..10932b893 100644
--- a/love/src/redux/actions/ws.js
+++ b/love/src/redux/actions/ws.js
@@ -131,13 +131,12 @@ export const resetSubscriptions = (subscriptions = null) => {
resetSubsTimer = setInterval(() => dispatch(resetSubscriptions()), RESET_SUBS_PERIOD);
dispatch({
type: RESET_SUBSCRIPTIONS,
- subscriptions: subs
- ? subs.map((sub) => ({
- ...sub,
- status: groupStates.PENDING,
- confirmationMessage: undefined,
- }))
- : [],
+ subscriptions:
+ subs?.map((sub) => ({
+ ...sub,
+ status: groupStates.PENDING,
+ confirmationMessage: undefined,
+ })) || [],
});
dispatch(_requestSubscriptions());
};
diff --git a/love/src/redux/selectors/selectors.js b/love/src/redux/selectors/selectors.js
index 8d7f2bec0..eca3f8beb 100644
--- a/love/src/redux/selectors/selectors.js
+++ b/love/src/redux/selectors/selectors.js
@@ -445,7 +445,7 @@ export const getCSCHeartbeat = (state, csc, salindex) => {
*/
export const getLastManagerHeartbeat = (state) => {
if (state.heartbeats === undefined) return undefined;
- return state.heartbeats?.lastHeartbeatInfo?.manager;
+ return state.heartbeats?.lastHeartbeatInfo?.Manager;
};
/**
diff --git a/love/src/redux/tests/heartbeats.test.js b/love/src/redux/tests/heartbeats.test.js
index 4ce9de926..67ca7f93a 100644
--- a/love/src/redux/tests/heartbeats.test.js
+++ b/love/src/redux/tests/heartbeats.test.js
@@ -20,17 +20,17 @@ let server;
const heartbeatsInfo = [
{
category: 'heartbeat',
- data: [{ csc: 'manager', salindex: 0, data: { timestamp: 1582141499.626869 } }],
+ data: [{ csc: 'Manager', salindex: 0, data: { timestamp: 1582141499.626869 } }],
subscription: 'heartbeat',
},
{
category: 'heartbeat',
- data: [{ csc: 'manager', salindex: 0, data: { timestamp: 1692141499.626869 } }],
+ data: [{ csc: 'Manager', salindex: 0, data: { timestamp: 1692141499.626869 } }],
subscription: 'heartbeat',
},
{
category: 'heartbeat',
- data: [{ csc: HEARTBEAT_COMPONENTS.EVENTS, salindex: 0, data: { timestamp: 1992141499.626869 } }],
+ data: [{ csc: 'Commander', salindex: 0, data: { timestamp: 1792141499.626869 } }],
subscription: 'heartbeat',
},
];
@@ -91,16 +91,6 @@ describe('GIVEN we are subscribed to the manager heartbeat', () => {
});
});
- describe('WHEN we receive a producer heartbeat', () => {
- it('THEN we store it the state ', async () => {
- // Arrange:
- await server.send(heartbeatsInfo[2]);
- const lastProducerHeartbeat = getLastComponentHeartbeat(store.getState(), HEARTBEAT_COMPONENTS.EVENTS);
- // Assert:
- expect(lastProducerHeartbeat).toEqual(heartbeatsInfo[2].data[0]);
- });
- });
-
describe('WHEN we receive 2 manager heartbeats', () => {
it('THEN we store the last one ', async () => {
// Arrange:
@@ -112,6 +102,16 @@ describe('GIVEN we are subscribed to the manager heartbeat', () => {
});
});
+ describe('WHEN we receive a commander heartbeat', () => {
+ it('THEN we store it the state ', async () => {
+ // Arrange:
+ await server.send(heartbeatsInfo[2]);
+ const lastProducerHeartbeat = getLastComponentHeartbeat(store.getState(), HEARTBEAT_COMPONENTS.COMMANDER);
+ // Assert:
+ expect(lastProducerHeartbeat).toEqual(heartbeatsInfo[2].data[0]);
+ });
+ });
+
describe('WHEN we lose server connection', () => {
it('THEN we dont receive new manager heartbeats ', async () => {
// Arrange:
diff --git a/love/yarn.lock b/love/yarn.lock
index cbb6f9135..496f2284a 100644
--- a/love/yarn.lock
+++ b/love/yarn.lock
@@ -2454,7 +2454,7 @@ arch@^2.1.2:
resolved "https://registry.yarnpkg.com/arch/-/arch-2.2.0.tgz#1bc47818f305764f23ab3306b0bfc086c5a29d11"
integrity sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==
-argparse@^1.0.7:
+argparse@^1.0.10, argparse@^1.0.7:
version "1.0.10"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911"
integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==
@@ -2673,6 +2673,13 @@ atob@^2.1.2:
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9"
integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==
+autolinker@^3.11.0:
+ version "3.14.2"
+ resolved "https://registry.yarnpkg.com/autolinker/-/autolinker-3.14.2.tgz#71856274eb768fb7149039e24d3a2be2f5c55a63"
+ integrity sha512-VO66nXUCZFxTq7fVHAaiAkZNXRQ1l3IFi6D5P7DLoyIEAn2E8g7TWbyEgLlz1uW74LfWmu1A17IPWuPQyGuNVg==
+ dependencies:
+ tslib "^1.9.3"
+
autoprefixer@^9.6.1:
version "9.8.6"
resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.8.6.tgz#3b73594ca1bf9266320c5acf1588d74dea74210f"
@@ -11694,6 +11701,14 @@ remark@^11.0.1:
remark-stringify "^7.0.0"
unified "^8.2.0"
+remarkable@^2.0.1:
+ version "2.0.1"
+ resolved "https://registry.yarnpkg.com/remarkable/-/remarkable-2.0.1.tgz#280ae6627384dfb13d98ee3995627ca550a12f31"
+ integrity sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA==
+ dependencies:
+ argparse "^1.0.10"
+ autolinker "^3.11.0"
+
remove-trailing-separator@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
@@ -12562,9 +12577,9 @@ sshpk@^1.7.0:
tweetnacl "~0.14.0"
ssri@^6.0.1:
- version "6.0.1"
- resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.1.tgz#2a3c41b28dd45b62b63676ecb74001265ae9edd8"
- integrity sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==
+ version "6.0.2"
+ resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5"
+ integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q==
dependencies:
figgy-pudding "^3.5.1"
@@ -13261,7 +13276,7 @@ tslib@2.0.0:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.0.tgz#18d13fc2dce04051e20f074cc8387fd8089ce4f3"
integrity sha512-lTqkx847PI7xEDYJntxZH89L2/aXInsyF2luSafe/+0fHOMjlBNXdH6th7f70qxLDhul7KZK0zC8V5ZIyHl0/g==
-tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0:
+tslib@^1.10.0, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
version "1.14.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
@@ -14814,9 +14829,9 @@ xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==
y18n@^4.0.0:
- version "4.0.0"
- resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b"
- integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.1.tgz#8db2b83c31c5d75099bb890b23f3094891e247d4"
+ integrity sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==
y18n@^5.0.1:
version "5.0.5"