diff --git a/Dockerfile b/Dockerfile index b95ca63a..fb4d3284 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,14 @@ ### STAGE 1: Build ### FROM node:9.11.1-alpine as builder -ARG branch=develop -ENV BRANCH=$branch +ENV BRANCH=master WORKDIR /src/app RUN mkdir -p /src/app/coriolis RUN mkdir -p /src/app/coriolis-data RUN apk add --update git -COPY . /src/app/coriolis - RUN npm i -g npm +ADD https://api.github.com/repos/edcd/coriolis-data/git/refs/heads/master /tmp/version.json # Set up coriolis-data WORKDIR /src/app/coriolis-data @@ -19,8 +17,11 @@ RUN git checkout ${BRANCH} RUN npm install --no-package-lock RUN npm start + +ADD https://api.github.com/repos/edcd/coriolis/git/refs/heads/master /tmp/version.json # Set up coriolis WORKDIR /src/app/coriolis +RUN git clone https://github.com/EDCD/coriolis.git . RUN git checkout ${BRANCH} RUN npm install --no-package-lock RUN npm run build diff --git a/Dockerfile.dev b/Dockerfile.dev new file mode 100644 index 00000000..9934de70 --- /dev/null +++ b/Dockerfile.dev @@ -0,0 +1,36 @@ +### STAGE 1: Build ### +FROM node:9.11.1-alpine as builder +ENV BRANCH=develop +WORKDIR /src/app +RUN mkdir -p /src/app/coriolis +RUN mkdir -p /src/app/coriolis-data + +RUN apk add --update git + +RUN npm i -g npm + +ADD https://api.github.com/repos/edcd/coriolis-data/git/refs/heads/develop /tmp/version.json +# Set up coriolis-data +WORKDIR /src/app/coriolis-data +RUN git clone https://github.com/EDCD/coriolis-data.git . +RUN git checkout ${BRANCH} +RUN npm install --no-package-lock +RUN npm start + + +ADD https://api.github.com/repos/edcd/coriolis/git/refs/heads/develop /tmp/version.json +# Set up coriolis +WORKDIR /src/app/coriolis +RUN git clone https://github.com/EDCD/coriolis.git . +RUN git checkout ${BRANCH} +RUN npm install --no-package-lock +RUN npm run build + + +### STAGE 2: Production Environment ### +FROM fholzer/nginx-brotli as web +COPY nginx.conf /etc/nginx/nginx.conf +COPY --from=builder /src/app/coriolis/build /usr/share/nginx/html +WORKDIR /usr/share/nginx/html +EXPOSE 80 +CMD ["nginx", "-c", "/etc/nginx/nginx.conf", "-g", "daemon off;"] diff --git a/__tests__/fixtures/expected-builds.json b/__tests__/fixtures/expected-builds.json index 2e5498a6..c9ed326a 100644 --- a/__tests__/fixtures/expected-builds.json +++ b/__tests__/fixtures/expected-builds.json @@ -1,50 +1,50 @@ { "type_6_transporter": { - "Cargo": "A0p0tdFal8d8s8f4-----04040303430101.Iw1/kA==.Aw1/kA==.", - "Miner": "A0p5tdFal8d8s8f42l2l---040403451q0101.Iw1/kA==.Aw1/kA==.", - "Hopper": "A0p0tdFal8d0s8f41717---030302024300-.Iw1/kA==.Aw1/kA==." + "Cargo": "A0p0tdFal8d8s8f4-----04040303430101-.Iw18UA==.Aw18UA==.", + "Miner": "A0p5tdFal8d8s8f42l2l---040403451q0101-.Iw18UA==.Aw18UA==.", + "Hopper": "A0p0tdFal8d0s8f41717---030302024300--.Iw18UA==.Aw18UA==." }, "type_7_transport": { - "Cargo": "A0p0tiFfliddsdf5--------0505040403480101.Iw18aQ==.Aw18aQ==.", - "Miner": "A0pdtiFflid8sdf5--2l2l----0505041v03450000.Iw18aQ==.Aw18aQ==." + "Cargo": "A0p0tiFfliddsdf5--------0505040403480101--.Iw18eQ==.Aw18eQ==.", + "Miner": "A0pdtiFflid8sdf5--2l2l----0505041v03450000--.Iw18eQ==.Aw18eQ==." }, "federal_dropship": { - "Cargo": "A0pdtiFflnddsif4-1717------05040448--020201.Iw18eQ==.Aw18eQ==." + "Cargo": "A0pdtiFflnddsif4-1717------05040448--020201-.Iw18RQ==.Aw18RQ==." }, "asp": { - "Miner": "A2pftfFflidfskf50s0s24242l2l---04054a1q02022o27.Iw18WQ==.Aw18WQ==." + "Miner": "A2pftfFflidfskf50s0s24242l2l---04054a1q02022o27-.Iw18eQ==.Aw18eQ==." }, "imperial_clipper": { - "Cargo": "A0p5tiFflndisnf4--0s0s----0605450302020101.Iw18aQ==.Aw18aQ==.", - "Dream": "A2pktkFflndpskf40v0v0s0s0404040n4k5n5d2b29292o-.AwRj4yWU1I==.CwBhCYy6YRigzLIA.", - "Current": "A0patkFflndfskf4----------------.AwRj4yWU1I==.CwBhCYy6YRigzLIA." + "Cargo": "A0p5tiFflndisnf4--0s0s----0605450302020101-.Iw18WQ==.Aw18WQ==.", + "Dream": "A2pktkFflndpskf40v0v0s0s0404040n4k5n5d2b29292o--.AwRj4yWU1Yg=.CwBhCYy6YRigzPIA.", + "Current": "A0patkFflndfskf4-----------------.AwRj4yWU1Yg=.CwBhCYy6YRigzPIA." }, "type_9_heavy": { - "Current": "A0patsFklndnsif6---------0706054a0303020224.AwRj4yoo.EwBhEYy6dsg=." + "Current": "A0patsFklndnsif6---------0706054a0303020224--.AwRj4yo5iA==.EwBhEYy6d6g=." }, "python": { - "Cargo": "A0patnFflidsssf5---------050505040448020201.Iw18eQ==.Aw18eQ==.", - "Miner": "A0pktkFflidpspf50v0v0v2m2m0404--050505Ce4a1v02022o.Iw18eQ==.IwBhBYy6dkCYg===.", - "Dream": "A2pptkFfliduspf50v0v0v27270404040m5n5n4f2d2d032t0201.Iw1+gDBxA===.EwBhEYy6e0WEA===.", - "Missile": "A0pttoFjljdystf52f2g2d2ePh----04044j03---002h.Iw18eQ==.Aw18eQ==." + "Cargo": "A0patnFflidsssf5---------050505040448020201-.Iw18eAMQ.Aw18RQ==.", + "Miner": "A0pktkFflidpspf50v0v0v2m2m0404--050505Ce4a1v02022o-.Iw18eAMQ.IwBhBYy6dkCYRA==.", + "Dream": "A2pptkFfliduspf50v0v0v27270404040m5n5n4f2d2d032t0201-.Iw1+gDByUA==.EwBhEYy6e0VEA===.", + "Missile": "A0pttoFjljdystf52f2g2d2ePh----04044j03---00--.Iw18eAMQ.Aw18RQ==." }, "anaconda": { - "Dream": "A4putpFklndzsuf52c0o0o0o1m1m0q0q0404040l0b0100004k5n5n112d2d04-0303326b.AwRj4yo5dyg=.MwBhCYy6duvARiA=.", - "Cargo": "A0patnFklndnsxf5----------------06050505040404-45030301.Iw18ZVA=.Aw18ZVA=.", - "Current": "A0patnFklndksxf5----------------06050505040404-03034524.Iw18ZVA=.Aw18ZVA=.", - "Explorer": "A0patnFklndksxf5--------0202------f7050505040s37-2f2i4524.AwRj4yVKJ9hA.AwhMIyumQRhEA===.", - "Test": "A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b.Iw18ZVA=.Aw18ZVA=." + "Dream": "A4putpFklndzsuf52c0o0o0o1m1m0q0q0404040l0b0100004k5n5n112d2d04-0303326b-.AwRj4yo5dzhA.MwBhCYy6duvARhEA.", + "Cargo": "A0patnFklndnsxf5----------------06050505040404-45030301-.Iw18ZUAxA===.Aw18ZXEA.", + "Current": "A0patnFklndksxf5----------------06050505040404-03034524-.Iw18ZUAxA===.Aw18ZXEA.", + "Explorer": "A0patnFklndksxf5--------0202------f7050505040s37--2i4524-.AwRj4yVKJ9jCA===.AwhMIyumQRgkA===.", + "Test": "A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b-.Iw18ZUAxA===.Aw18ZXEA." }, "diamondback_explorer": { - "Explorer": "A0p0tdFfldddsdf5---0202--320p432i2f-.AwRj4zTYg===.AwiMIyoo." + "Explorer": "A0p0tdFfldddsdf5---0202--320p432i----.AwRj4zTZaA==.AwiMIyqo." }, "vulture": { - "Bounty Hunter": "A3patcFalddksff31e1e0404-0l4a-5d27662j.AwRj4z2I.MwBhBYy6oJmAjLIA." + "Bounty Hunter": "A3patcFalddksff31e1e0404-0l4a-5d27662j--.AwRj4z2Gg===.MwBhBYy6oJmAjLMQ." }, "fer_de_lance": { - "Attack": "A2pfthFalidpsff31r0s0s0s0s000404-04-4a-5d27-.Iw18aQ==.CwBhrSu8EZyA." + "Attack": "A2pfthFalidpsff31r0s0s0s0s000404-04-4a-5d27--.Iw18aAMQ.CwBhrSu8EZxEA===." }, "eagle": { - "Figther": "A4p0t5F5l3d5s5f20p0p24-4053-2j-.Iw18kA==.Aw18kA==." + "Figther": "A4p0t5F5l3d5s5f20p0p24-4053-2j---.Iw18gDJQ.Aw19kA==." } } diff --git a/__tests__/fixtures/slef-multiple-builds.json b/__tests__/fixtures/slef-multiple-builds.json new file mode 100644 index 00000000..d6b95126 --- /dev/null +++ b/__tests__/fixtures/slef-multiple-builds.json @@ -0,0 +1,366 @@ +[ + { + "header": { + "appName": "Inara", + "appVersion": "1.0", + "appURL": "https:\/\/inara.cz\/cmdr-fleet\/123\/123\/", + "appCustomProperties": { + "inaraCommanderID": 123, + "inaraShipID": 123 + } + }, + "data": { + "Ship": "krait_mkii", + "ShipID": 7, + "ShipName": "pancake hammer", + "ShipIdent": "PH-01", + "HullValue": 44160710, + "ModulesValue": 111274094, + "Rebuy": 7771743, + "Modules": [ + { + "Slot": "largehardpoint1", + "Item": "hpt_mininglaser_fixed_small", + "On": true + }, + { + "Slot": "largehardpoint2", + "Item": "hpt_cannon_gimbal_large", + "On": true, + "Engineering": { + "BlueprintName": "weapon_overcharged", + "Level": 2, + "Quality": 1, + "ExperimentalEffect": "special_auto_loader" + } + }, + { + "Slot": "largehardpoint3", + "Item": "hpt_cannon_gimbal_large", + "On": true, + "Engineering": { + "BlueprintName": "weapon_overcharged", + "Level": 2, + "Quality": 1, + "ExperimentalEffect": "special_auto_loader" + } + }, + { + "Slot": "mediumhardpoint1", + "Item": "hpt_basicmissilerack_fixed_medium", + "On": true, + "Engineering": { + "BlueprintName": "weapon_highcapacity", + "Level": 5, + "Quality": 1 + } + }, + { + "Slot": "mediumhardpoint2", + "Item": "hpt_basicmissilerack_fixed_medium", + "On": true + }, + { + "Slot": "tinyhardpoint1", + "Item": "hpt_heatsinklauncher_turret_tiny", + "On": true + }, + { + "Slot": "tinyhardpoint2", + "Item": "hpt_cloudscanner_size0_class3", + "On": true + }, + { + "Slot": "tinyhardpoint3", + "Item": "hpt_shieldbooster_size0_class5", + "On": true + }, + { + "Slot": "tinyhardpoint4", + "Item": "hpt_shieldbooster_size0_class5", + "On": true, + "Priority": 1 + }, + { + "Slot": "slot01_size6", + "Item": "int_cargorack_size6_class1", + "On": true, + "Priority": 1 + }, + { + "Slot": "slot02_size6", + "Item": "int_cargorack_size6_class1", + "On": true, + "Priority": 1 + }, + { + "Slot": "slot03_size5", + "Item": "int_guardianfsdbooster_size5", + "On": true + }, + { + "Slot": "slot04_size5", + "Item": "int_fighterbay_size5_class1", + "On": true + }, + { + "Slot": "slot05_size4", + "Item": "int_shieldgenerator_size4_class5", + "On": true + }, + { + "Slot": "slot06_size3", + "Item": "int_dronecontrol_collection_size3_class4", + "On": true + }, + { + "Slot": "slot07_size3", + "Item": "int_dronecontrol_collection_size3_class4", + "On": true + }, + { + "Slot": "slot08_size2", + "Item": "int_refinery_size2_class2", + "On": true + }, + { + "Slot": "slot09_size1", + "Item": "int_dronecontrol_prospector_size1_class4", + "On": true + }, + { + "Slot": "powerplant", + "Item": "int_powerplant_size7_class5", + "On": true, + "Priority": 1 + }, + { + "Slot": "mainengines", + "Item": "int_engine_size6_class5", + "On": true + }, + { + "Slot": "frameshiftdrive", + "Item": "int_hyperdrive_size5_class5", + "On": true, + "Engineering": { + "BlueprintName": "fsd_longrange", + "Level": 2, + "Quality": 0.861 + } + }, + { + "Slot": "lifesupport", + "Item": "int_lifesupport_size4_class2", + "On": true, + "Priority": 3 + }, + { + "Slot": "powerdistributor", + "Item": "int_powerdistributor_size7_class5", + "On": true + }, + { + "Slot": "radar", + "Item": "int_sensors_size6_class2", + "On": true + }, + { + "Slot": "fueltank", + "Item": "int_fueltank_size5_class3", + "On": true, + "Priority": 1 + }, + { + "Slot": "armour", + "Item": "krait_mkii_armour_grade3", + "On": true, + "Priority": 1, + "Engineering": { + "BlueprintName": "armour_heavyduty", + "Level": 5, + "Quality": 1 + } + } + ] + } + }, + { + "header": { + "appName": "Inara", + "appVersion": "1.0", + "appURL": "https:\/\/inara.cz\/cmdr-fleet\/123\/123\/", + "appCustomProperties": { + "inaraCommanderID": 123, + "inaraShipID": 123 + } + }, + "data": { + "Ship": "diamondbackxl", + "ShipID": 11, + "ShipName": "star Hopper", + "ShipIdent": "PH-02", + "HullValue": 1615649, + "ModulesValue": 16981039, + "Rebuy": 929837, + "Modules": [ + { + "Slot": "tinyhardpoint1", + "Item": "hpt_heatsinklauncher_turret_tiny", + "On": true, + "Value": 3072 + }, + { + "Slot": "slot01_size4", + "Item": "int_fuelscoop_size4_class5", + "On": true, + "Priority": 3, + "Value": 2862364 + }, + { + "Slot": "slot02_size4", + "Item": "int_guardianfsdbooster_size4", + "On": true, + "Value": 2847499 + }, + { + "Slot": "slot03_size3", + "Item": "int_shieldgenerator_size3_class2", + "On": true, + "Value": 18812, + "Engineering": { + "BlueprintName": "shieldgenerator_thermic", + "Level": 3, + "Quality": 1, + "ExperimentalEffect": "special_shield_health" + } + }, + { + "Slot": "slot04_size3", + "Item": "int_repairer_size3_class5", + "On": true, + "Value": 2302911 + }, + { + "Slot": "slot05_size2", + "Item": "int_buggybay_size2_class2", + "On": true, + "Priority": 3, + "Value": 21600 + }, + { + "Slot": "slot06_size2", + "Item": "int_cargorack_size2_class1", + "On": true, + "Priority": 1, + "Value": 2852 + }, + { + "Slot": "slot07_size1", + "Item": "int_supercruiseassist", + "On": true, + "Priority": 3, + "Value": 9121 + }, + { + "Slot": "slot08_size1", + "Item": "int_detailedsurfacescanner_tiny", + "On": true, + "Value": 250000, + "Engineering": { + "BlueprintName": "sensor_expanded", + "Level": 5, + "Quality": 1 + } + }, + { + "Slot": "powerplant", + "Item": "int_powerplant_size4_class5", + "On": true, + "Priority": 1, + "Value": 1441233, + "Engineering": { + "BlueprintName": "powerplant_boosted", + "Level": 1, + "Quality": 1 + } + }, + { + "Slot": "mainengines", + "Item": "int_engine_size4_class5", + "On": true, + "Value": 1610080, + "Engineering": { + "BlueprintName": "engine_dirty", + "Level": 5, + "Quality": 1, + "ExperimentalEffect": "special_engine_lightweight" + } + }, + { + "Slot": "frameshiftdrive", + "Item": "int_hyperdrive_size5_class5", + "On": true, + "Value": 5103953, + "Engineering": { + "BlueprintName": "fsd_longrange", + "Level": 5, + "Quality": 1, + "ExperimentalEffect": "special_fsd_lightweight" + } + }, + { + "Slot": "lifesupport", + "Item": "int_lifesupport_size3_class2", + "On": true, + "Value": 10133, + "Engineering": { + "BlueprintName": "misc_lightweight", + "Level": 3, + "Quality": 1 + } + }, + { + "Slot": "powerdistributor", + "Item": "int_powerdistributor_size4_class5", + "On": true, + "Value": 389022, + "Engineering": { + "BlueprintName": "powerdistributor_highfrequency", + "Level": 4, + "Quality": 1 + } + }, + { + "Slot": "radar", + "Item": "int_sensors_size3_class2", + "On": true, + "Value": 10133, + "Engineering": { + "BlueprintName": "sensor_lightweight", + "Level": 5, + "Quality": 1 + } + }, + { + "Slot": "fueltank", + "Item": "int_fueltank_size5_class3", + "On": true, + "Priority": 1, + "Value": 97754 + }, + { + "Slot": "armour", + "Item": "diamondbackxl_armour_grade1", + "On": true, + "Priority": 1, + "Engineering": { + "BlueprintName": "armour_heavyduty", + "Level": 5, + "Quality": 1 + } + } + ] + } + } +] diff --git a/__tests__/fixtures/slef-multiple-expected-builds.json b/__tests__/fixtures/slef-multiple-expected-builds.json new file mode 100644 index 00000000..19c2bd7f --- /dev/null +++ b/__tests__/fixtures/slef-multiple-expected-builds.json @@ -0,0 +1,8 @@ +{ + "krait_mkii": { + "Imported pancake hammer": "A2pptkFflidussf52l1o1o2g2g020g040405051Ofr45C9C91oP3.Iw18eQ==.AwRgzKIkA===." + }, + "diamondback_explorer": { + "Imported star Hopper": "A0pataFflddfsdf5---02---321P430iv6013w2i.Iw18SQ==.AwRm44GYpKg=." + } +} diff --git a/__tests__/fixtures/slef-single-build.json b/__tests__/fixtures/slef-single-build.json new file mode 100644 index 00000000..1b578b83 --- /dev/null +++ b/__tests__/fixtures/slef-single-build.json @@ -0,0 +1,188 @@ +[ + { + "header": { + "appName": "Inara", + "appVersion": "1.0", + "appURL": "https:\/\/inara.cz\/cmdr-fleet\/123\/123\/", + "appCustomProperties": { + "inaraCommanderID": 123, + "inaraShipID": 123 + } + }, + "data": { + "Ship": "krait_mkii", + "ShipID": 7, + "ShipName": "pancake hammer", + "ShipIdent": "PH-01", + "HullValue": 44160710, + "ModulesValue": 111274094, + "Rebuy": 7771743, + "Modules": [ + { + "Slot": "largehardpoint1", + "Item": "hpt_mininglaser_fixed_small", + "On": true + }, + { + "Slot": "largehardpoint2", + "Item": "hpt_cannon_gimbal_large", + "On": true, + "Engineering": { + "BlueprintName": "weapon_overcharged", + "Level": 2, + "Quality": 1, + "ExperimentalEffect": "special_auto_loader" + } + }, + { + "Slot": "largehardpoint3", + "Item": "hpt_cannon_gimbal_large", + "On": true, + "Engineering": { + "BlueprintName": "weapon_overcharged", + "Level": 2, + "Quality": 1, + "ExperimentalEffect": "special_auto_loader" + } + }, + { + "Slot": "mediumhardpoint1", + "Item": "hpt_basicmissilerack_fixed_medium", + "On": true, + "Engineering": { + "BlueprintName": "weapon_highcapacity", + "Level": 5, + "Quality": 1 + } + }, + { + "Slot": "mediumhardpoint2", + "Item": "hpt_basicmissilerack_fixed_medium", + "On": true + }, + { + "Slot": "tinyhardpoint1", + "Item": "hpt_heatsinklauncher_turret_tiny", + "On": true + }, + { + "Slot": "tinyhardpoint2", + "Item": "hpt_cloudscanner_size0_class3", + "On": true + }, + { + "Slot": "tinyhardpoint3", + "Item": "hpt_shieldbooster_size0_class5", + "On": true + }, + { + "Slot": "tinyhardpoint4", + "Item": "hpt_shieldbooster_size0_class5", + "On": true, + "Priority": 1 + }, + { + "Slot": "slot01_size6", + "Item": "int_cargorack_size6_class1", + "On": true, + "Priority": 1 + }, + { + "Slot": "slot02_size6", + "Item": "int_cargorack_size6_class1", + "On": true, + "Priority": 1 + }, + { + "Slot": "slot03_size5", + "Item": "int_guardianfsdbooster_size5", + "On": true + }, + { + "Slot": "slot04_size5", + "Item": "int_fighterbay_size5_class1", + "On": true + }, + { + "Slot": "slot05_size4", + "Item": "int_shieldgenerator_size4_class5", + "On": true + }, + { + "Slot": "slot06_size3", + "Item": "int_dronecontrol_collection_size3_class4", + "On": true + }, + { + "Slot": "slot07_size3", + "Item": "int_dronecontrol_collection_size3_class4", + "On": true + }, + { + "Slot": "slot08_size2", + "Item": "int_refinery_size2_class2", + "On": true + }, + { + "Slot": "slot09_size1", + "Item": "int_dronecontrol_prospector_size1_class4", + "On": true + }, + { + "Slot": "powerplant", + "Item": "int_powerplant_size7_class5", + "On": true, + "Priority": 1 + }, + { + "Slot": "mainengines", + "Item": "int_engine_size6_class5", + "On": true + }, + { + "Slot": "frameshiftdrive", + "Item": "int_hyperdrive_size5_class5", + "On": true, + "Engineering": { + "BlueprintName": "fsd_longrange", + "Level": 2, + "Quality": 0.861 + } + }, + { + "Slot": "lifesupport", + "Item": "int_lifesupport_size4_class2", + "On": true, + "Priority": 3 + }, + { + "Slot": "powerdistributor", + "Item": "int_powerdistributor_size7_class5", + "On": true + }, + { + "Slot": "radar", + "Item": "int_sensors_size6_class2", + "On": true + }, + { + "Slot": "fueltank", + "Item": "int_fueltank_size5_class3", + "On": true, + "Priority": 1 + }, + { + "Slot": "armour", + "Item": "krait_mkii_armour_grade3", + "On": true, + "Priority": 1, + "Engineering": { + "BlueprintName": "armour_heavyduty", + "Level": 5, + "Quality": 1 + } + } + ] + } + } +] diff --git a/__tests__/test-import.js b/__tests__/test-import.js index 2bcd2c22..c7c484cc 100644 --- a/__tests__/test-import.js +++ b/__tests__/test-import.js @@ -18,13 +18,13 @@ describe('Import Modal', function() { const mockContext = { language: getLanguage('en'), sizeRatio: 1, - openMenu: jest.genMockFunction(), - closeMenu: jest.genMockFunction(), - showModal: jest.genMockFunction(), - hideModal: jest.genMockFunction(), - tooltip: jest.genMockFunction(), - termtip: jest.genMockFunction(), - onWindowResize: jest.genMockFunction() + openMenu: jest.fn(), + closeMenu: jest.fn(), + showModal: jest.fn(), + hideModal: jest.fn(), + tooltip: jest.fn(), + termtip: jest.fn(), + onWindowResize: jest.fn() }; let modal, render, ContextProvider = Utils.createContextProvider(mockContext); @@ -110,21 +110,25 @@ describe('Import Modal', function() { it('catches an invalid backup', function() { const importData = require('./fixtures/valid-backup'); let invalidImportData = Object.assign({}, importData); - //invalidImportData.builds.asp = null; // Remove Asp Miner build used in comparison + // Remove Asp Miner build used in comparison delete(invalidImportData.builds.asp); pasteText('"this is not valid"'); expect(modal.state.importValid).toBeFalsy(); expect(modal.state.errorMsg).toEqual('Must be an object or array!'); + pasteText('{ "builds": "Should not be a string" }'); expect(modal.state.importValid).toBeFalsy(); expect(modal.state.errorMsg).toEqual('builds must be an object!'); - pasteText(JSON.stringify(importData).replace('anaconda', 'invalid_ship')); + + pasteText(JSON.stringify(importData).replace(/anaconda/g, 'invalid_ship')); expect(modal.state.importValid).toBeFalsy(); - expect(modal.state.errorMsg).toEqual('"invalid_ship" is not a valid Ship Id!'); + expect(Object.keys(modal.state.builds)).not.toContain('anaconda'); + pasteText(JSON.stringify(importData).replace('Dream', '')); expect(modal.state.importValid).toBeFalsy(); - expect(modal.state.errorMsg).toEqual('Imperial Clipper build "" must be a string at least 1 character long!'); + expect(Object.keys(modal.state.builds.imperial_clipper).length).toEqual(3); + pasteText(JSON.stringify(invalidImportData)); expect(modal.state.importValid).toBeFalsy(); expect(modal.state.errorMsg).toEqual('asp build "Miner" data is missing!'); @@ -144,7 +148,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b.AwRj4zNLaA%3D%3D.CwBhCYzBGW9qCTSqq5xA.&bn=Test%20My%20Ship'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b-.AwRj4zNLeI%3D%3D.CwBhCYzBGW9qCTSqq5JA.&bn=Test%20My%20Ship'); }); it('catches an invalid build', function() { @@ -169,7 +173,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b.AwRj4zNLaA%3D%3D.CwBhCYzBGW9qCTSqq5xA.H4sIAAAAAAAAA2MUe8HMwPD%2FPwMAAGvB0AkAAAA%3D&bn=Test%20My%20Ship'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/anaconda?code=A4putkFklkdzsuf52c0o0o0o1m1m0q0q0404-0l0b0100034k5n052d04---0303326b-.AwRj4zNLeI%3D%3D.CwBhCYzBGW9qCTSqq5JA.H4sIAAAAAAAAE2MUe8HMwPD%2FPwMAAGvB0AkAAAA%3D&bn=Test%20My%20Ship'); }); }); @@ -186,7 +190,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/asp?code=A0pftiFflfddsnf5------020202033c044002v62f2i.AwRj4yvI.CwRgDBldHnJA.H4sIAAAAAAAAA2P858DAwPCXEUhwHPvx%2F78YG5AltB7I%2F8%2F0TwImJboDSPJ%2F%2B%2Ff%2Fv%2FKlX%2F%2F%2Fi3AwMTBIfARK%2FGf%2BJwVSxArStVAYqOjvz%2F%2F%2FJVo5GRhE2IBc4SKQSSz%2FDGEmCa398P8%2F%2F2%2BgTf%2F%2FA7kMAExxqlSAAAAA&bn=Multi-purpose%20Asp%20Explorer'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/asp?code=A0pftiFflfddsnf5------020202033c044002v6-2i-.AwRj4yvYg%3D%3D%3D.CwRgDBldHn5A.H4sIAAAAAAAAE2P858DAwPCXEUhwHPvx%2F78YG5AltB7I%2F8%2F0TwImJboDSPJ%2F%2B%2Ff%2Fv%2FKlX%2F%2F%2Fi3AwMTBIfARK%2FGf%2BJwVSxArStVAYqOjvz%2F%2F%2FJVo5GRhE2IBc4SKQSSz%2FDGEmCa398P8%2F%2F2%2BgTf%2F%2FA7kMAExxqlSAAAAA&bn=Multi-purpose%20Asp%20Explorer'); }); it('imports a valid v4 build with modifications', function() { @@ -198,11 +202,11 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/imperial_courier?code=A0patzF5l0das8f31a1a270202000e402t0101-2f.AwRj4zKA.CwRgDBldLiQ%3D.H4sIAAAAAAAAA12OPUvDYBSFT1OTfkRJjUkbbC3Yj8mlODgUISAtdOlety5ODv0Vgji7O7kJ%2FgzBQX%2BEY7Gg0NKhfY%2FnHQLFDBdynufe9%2BRMCmCb06g29oCgacjiRx6gY6oWKUT8UgLaszqQfHmSnpVFN1uSeXNsJVcj%2FA2EHlZkspIUpUc6UjTXGT85qwHuSEuVc%2F16r99kDQeSSjvSbSjpyUpNK10uJJ3aYqk6smwm1lQ9bOxw71TMm8VanEqq9JW1r3Qo%2BREOLnQHvbWmb7rZIu5VLIyGQGOukPv%2F0WQk5LeEAjPOUDwtAP6bShy2HKAz0HPO%2B5KsP25I79O2I7LvD%2Bz4Il1XAQAA&bn=Multi-purpose%20Imperial%20Courier'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/imperial_courier?code=A0patzF5l0das8f31a1a270202000e402t0101----.AwRj4zOYg%3D%3D%3D.CwRgDBldLuZA.H4sIAAAAAAAAE12OPUvDYBSFT1OTfkRJjUkbbC3Yj8mlODgUISAtdOlety5ODv0Vgji7O7kJ%2FgzBQX%2BEY7Gg0NKhfY%2FnHQLFDBdynufe9%2BRMCmCb06g29oCgacjiRx6gY6oWKUT8UgLaszqQfHmSnpVFN1uSeXNsJVcj%2FA2EHlZkspIUpUc6UjTXGT85qwHuSEuVc%2F16r99kDQeSSjvSbSjpyUpNK10uJJ3aYqk6smwm1lQ9bOxw71TMm8VanEqq9JW1r3Qo%2BREOLnQHvbWmb7rZIu5VLIyGQGOukPv%2F0WQk5LeEAjPOUDwtAP6bShy2HKAz0HPO%2B5KsP25I79O2I7LvD%2Bz4Il1XAQAA&bn=Multi-purpose%20Imperial%20Courier'); }); }); - describe('Import Detaild Builds Array', function() { + describe('Import Detailed Builds Array', function() { beforeEach(reset); @@ -240,7 +244,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=A2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifr--v66g2f.AwRj4zNaqA%3D%3D.CwRgDBldUExuBiIlUA%3D%3D.H4sIAAAAAAAAA12STy8DURTFb1szU53Ga8dg2qqqDmJDIoKFxJImumYjVrVqfAALC4lNbcUnkLCoDbEQu0bSlQVhI8JHsJBIQ73rXMkwMYuT9%2Bb87nl%2F7ovoRSL6ikD6TYNINZg5XsWUo7pfrBikr2USlRyXyDuLAhr6ZHanNLOzD5tjOiskysk5dOBvfTB7bjeRW0MNG3ohSBq1bKKxKwyLLUAjmwjpPu4wJx4xVbNI57heDfbUKUAy2xaRUQZpllHoHMHxKqjhhF4LgjtJiFHDmqbrEeVnUJOax7%2FSdRfRwBNotv9wo5kAuZMD2egKyDYcdYl1OBki6z%2BZQjaFnBPyFCM1LefF%2BcgrY0es9FKwbW8ZYj9gmBbxRVRdglMh6BNqnwsk4ouoO4HSIehNoBuBRHwR1QOmsBvHmk6IfMbd2fdCEka%2BjNSexPWGoEkcyX6CnxbxRZQtd%2BPpym%2B31xFtn0iSFPkf%2BBkttZlzB9KDFyBuFRfAGV0Ogoff8SSsCfjjD5hGWtLIwZB%2FgX5Zt%2BLHMI9My7sp6nzgZzekswTxVvCOkq%2FSXqb%2F3zfLxh6HrwIAAA%3D%3D&bn=Imported%20Federal%20Corvette'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/federal_corvette?code=A2putsFklndzsxf50x0x7l28281919040404040402020l06p05sf63c5ifr--v66g--.AwRj4zNapI%3D%3D.CwRgDBldUExuBiIlWIA%3D.&bn=Imported%20Federal%20Corvette'); }); it('imports a valid companion API build', function() { @@ -252,7 +256,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/beluga?code=A0pktsFplCdpsnf70t0t2727270004040404043c4fmimlmm04mc0iv62i2f.AwRj4yukg%3D%3D%3D.CwRgDBldHi8IUA%3D%3D.H4sIAAAAAAAAA2P8Z8%2FAwPCXEUiIKTMxMPCv%2F%2Ff%2FP8cFIPGf6Z8YTEr0GjMDg%2FJWICERBOTzn%2Fn7%2F7%2FIO5Ai5n9SIEWsQEIoSxAolfbt%2F3%2BJPk4GBhE7YQYGYVmgcuVnf4Aq%2FwOVAAAyiFctbgAAAA%3D%3D&bn=Imported%20Beluga%20Liner'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/beluga?code=A0pktsFplCdpsnf70t0t2727270004040404043c4fmimlmm04mc0iv62i--.AwRj4yusg%3D%3D%3D.CwRgDBldHi8IWIA%3D.&bn=Imported%20Beluga%20Liner'); }); it('imports a valid companion API build', function() { @@ -264,7 +268,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/type_7_transport?code=A0patfFflidasdf5----0404040005050504044d2402.AwRj4yrI.CwRgDBlVK7EiA%3D%3D%3D.&bn=Imported%20Type-7%20Transporter'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/type_7_transport?code=A0patfFflidasdf5----0404040005050504044d2402--.AwRj4yoo.CwRgDBlVK7HjEA%3D%3D.&bn=Imported%20Type-7%20Transporter'); }); it('imports a valid companion API build', function() { @@ -276,7 +280,7 @@ describe('Import Modal', function() { expect(modal.state.singleBuild).toBe(true); clickProceed(); expect(MockRouter.go.mock.calls.length).toBe(1); - expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/cobra_mk_iii?code=A0p0tdFaldd3sdf4------34---2f2i.AwRj4yKA.CwRgDMYExrezBUg%3D.&bn=Imported%20Cobra%20Mk%20III'); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/cobra_mk_iii?code=A0p0tdFaldd3sdf4------34----2i--.AwRj4yqA.CwRgDMYExrezBig%3D.&bn=Imported%20Cobra%20Mk%20III'); }); }); @@ -324,4 +328,41 @@ describe('Import Modal', function() { }); }); + describe('Imports SLEF data', () => { + beforeEach(reset); + + it('imports a single valid SLEF build', () => { + const importData = require('./fixtures/slef-single-build.json'); + pasteText(JSON.stringify(importData)); + + expect(modal.state.importValid).toBeTruthy(); + expect(modal.state.errorMsg).toEqual(null); + expect(modal.state.singleBuild).toBe(true); + clickProceed(); + expect(MockRouter.go.mock.calls.length).toBe(1); + expect(MockRouter.go.mock.calls[0][0]).toBe('/outfit/krait_mkii?code=A2pptkFflidussf52l1o1o2g2g020g040405051Ofr45C9C91oP3.Iw18eQ%3D%3D.AwRgzKIkA%3D%3D%3D.&bn=Imported%20pancake%20hammer'); + }); + + it('imports multiple SLEF builds', () => { + const importData = require('./fixtures/slef-multiple-builds.json'); + const expectedBuilds = require('./fixtures/slef-multiple-expected-builds.json'); + pasteText(JSON.stringify(importData)); + + expect(modal.state.importValid).toBeTruthy(); + expect(modal.state.errorMsg).toEqual(null); + expect(modal.state.singleBuild).toBe(false); + clickProceed(); + expect(modal.state.processed).toBeTruthy(); + clickImport(); + + const builds = Persist.getBuilds(); + + for (const shipModel in builds) { + for (const buildName in builds[shipModel]) { + expect(builds[shipModel][buildName]) + .toEqual(expectedBuilds[shipModel][buildName]); + } + } + }); + }); }); diff --git a/docker-compose.yml b/docker-compose.yml index 7496605d..4fbaee70 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,55 +1,43 @@ -version: '2.2' +version: '3.6' services: - coriolis_prod: + master: image: edcd/coriolis:master build: dockerfile: Dockerfile + context: . args: branch: master restart: always volumes: - - ./nginx.conf:/etc/nginx/nginx.conf + - ./nginx.conf:/etc/nginx/nginx.conf networks: - - web + - web labels: - - "traefik.docker.network=web" - - "traefik.enable=true" - - "traefik.basic.frontend.rule=Host:coriolis.io,coriolis.edcd.io" - - "traefik.basic.port=80" - - "traefik.basic.protocol=http" + - "traefik.docker.network=web" + - "traefik.enable=true" + - "traefik.basic.frontend.rule=Host:coriolis.io,coriolis.edcd.io" + - "traefik.basic.port=80" + - "traefik.basic.protocol=http" - coriolis_dev: + develop: image: edcd/coriolis:develop build: - dockerfile: Dockerfile + dockerfile: Dockerfile.dev + context: . args: branch: develop restart: always volumes: - ./nginx.conf:/etc/nginx/nginx.conf networks: - - web + - web labels: - - "traefik.docker.network=web" - - "traefik.enable=true" - - "traefik.basic.frontend.rule=Host:beta.coriolis.io,beta.coriolis.edcd.io" - - "traefik.basic.port=80" - - "traefik.basic.protocol=http" - - coriolis_dw2: - image: edcd/coriolis:dw2 - restart: always - volumes: - - ./nginx.conf:/etc/nginx/nginx.conf - networks: - - web - labels: - - "traefik.docker.network=web" - - "traefik.enable=true" - - "traefik.basic.frontend.rule=Host:dw2.coriolis.io" - - "traefik.basic.port=80" - - "traefik.basic.protocol=http" + - "traefik.docker.network=web" + - "traefik.enable=true" + - "traefik.basic.frontend.rule=Host:beta.coriolis.io,beta.coriolis.edcd.io" + - "traefik.basic.port=80" + - "traefik.basic.protocol=http" networks: web: diff --git a/src/app/Coriolis.jsx b/src/app/Coriolis.jsx index 8b544b1f..c90049ad 100644 --- a/src/app/Coriolis.jsx +++ b/src/app/Coriolis.jsx @@ -22,6 +22,7 @@ import ComparisonPage from './pages/ComparisonPage'; import ShipyardPage from './pages/ShipyardPage'; import ErrorDetails from './pages/ErrorDetails'; + const zlib = require('pako'); const request = require('superagent'); @@ -72,7 +73,7 @@ export default class Coriolis extends React.Component { route: {}, sizeRatio: Persist.getSizeRatio() }; - this._getAnnouncements(); + // this._getAnnouncements(); Router('', (r) => this._setPage(ShipyardPage, r)); Router('/import?', (r) => this._importBuild(r)); Router('/import/:data', (r) => this._importBuild(r)); @@ -97,15 +98,30 @@ export default class Coriolis extends React.Component { const json = JSON.parse(data); console.info('Ship import data: '); console.info(json); - let ship; - if (json && json.modules) { - ship = CompanionApiUtils.shipFromJson(json); - } else if (json && json.Modules) { - ship = JournalUtils.shipFromLoadoutJSON(json); + let ship, importString; + if (json) { + if (json.length && json[0].data) { // SLEF + if (json.length > 1) { // Multiple builds, open modal + importString = data; + } else { // Single build, import directly + ship = JournalUtils.shipFromLoadoutJSON(json[0].data); + } + } else { // not SLEF + if (json.modules) { + ship = CompanionApiUtils.shipFromJson(json); + } else if (json.Modules) { + ship = JournalUtils.shipFromLoadoutJSON(json); + } + } + } + if (ship) { + r.params.ship = ship.id; + r.params.code = ship.toString(); + this._setPage(OutfittingPage, r); + } else if (importString) { + this._setPage(ShipyardPage, r); + this._showModal(); } - r.params.ship = ship.id; - r.params.code = ship.toString(); - this._setPage(OutfittingPage, r) } catch (err) { this._onError('Failed to import ship', r.path, 0, 0, err); } @@ -113,8 +129,8 @@ export default class Coriolis extends React.Component { async _getAnnouncements() { try { - const announces = await request.get('https://orbis.zone/api/announcement') - .query({ showInCoriolis: true }); + const announces = await request.get('https://api.orbis.zone/announcements') + .query({ coriolis: true }); this.setState({ announcements: announces.body }); } catch (err) { console.error(err) @@ -394,18 +410,18 @@ export default class Coriolis extends React.Component { */ render() { let currentMenu = this.state.currentMenu; - return
{this.state.announcements.map(a => )}
+ text={a.text}/>)}
{this.state.error ? this.state.error : this.state.page ? React.createElement(this.state.page, { currentMenu }) : } {this.state.modal} {this.state.tooltip}