From 478d4ecdd227145944b9bbfff071ae838e954a21 Mon Sep 17 00:00:00 2001 From: Matt <7128721+TobiTenno@users.noreply.github.com> Date: Sat, 24 Sep 2022 12:15:24 -0500 Subject: [PATCH] feat: archon hunt panel (#872) --- .../modalDialogs/Filters/ComponentsFilter.jsx | 25 ++-- .../modalDialogs/Filters/FissureFilters.jsx | 16 ++- .../Filters/NotificationFilters.jsx | 16 +-- components/panels/SortiePanel.jsx | 115 ++++++++++++++++++ components/panels/SortiePanel.vue | 93 -------------- cypress/.eslintrc.yaml | 16 ++- cypress/e2e/openworld/load.spec.js | 28 ++--- cypress/e2e/synthesis/load.spec.js | 6 +- cypress/e2e/timers/load.spec.js | 19 +-- package-lock.json | 11 +- package.json | 1 + pages/index.vue | 3 +- services/Notifier.js | 27 ++-- static/json/components.json | 10 ++ static/json/trackables.json | 5 + static/lang/en.json | 5 +- 16 files changed, 226 insertions(+), 170 deletions(-) create mode 100644 components/panels/SortiePanel.jsx delete mode 100644 components/panels/SortiePanel.vue diff --git a/components/modalDialogs/Filters/ComponentsFilter.jsx b/components/modalDialogs/Filters/ComponentsFilter.jsx index d7845192..6fb1bb1f 100644 --- a/components/modalDialogs/Filters/ComponentsFilter.jsx +++ b/components/modalDialogs/Filters/ComponentsFilter.jsx @@ -3,13 +3,10 @@ import baseComponents from '@/static/json/components.json'; export default { computed: { - ...mapGetters('worldstate', { - rawCS: 'componentState', - }), + ...mapGetters('worldstate', ['componentState']), activeComponents: { get() { - return Object.keys(this.rawCS) - .map((component) => this.rawCS[component]) + return Object.values(this.componentState) .filter( (component) => component.display && (!baseComponents[component.key] || baseComponents[component.key].displayable) @@ -17,23 +14,25 @@ export default { .map((component) => component.key); }, set(enabledComponents) { - Object.keys(this.rawCS).forEach((component) => { - this.$store.commit('worldstate/commitComponentDisplayMode', [ - component, - enabledComponents.includes(component), - ]); + Object.keys(this.componentState).forEach((component) => { + if (this.componentState[component].display !== enabledComponents.includes(component)) { + this.$store.commit('worldstate/commitComponentDisplayMode', [ + component, + enabledComponents.includes(component), + ]); + } }); }, }, componentStates() { - return Object.keys(this.rawCS) + return Object.keys(this.componentState) .map((component) => { if (!baseComponents[component] || !baseComponents[component].displayable) { return false; } return { - text: this.rawCS[component].displayName, - value: this.rawCS[component].key, + text: this.componentState[component].displayName, + value: this.componentState[component].key, }; }) .filter((c) => c); diff --git a/components/modalDialogs/Filters/FissureFilters.jsx b/components/modalDialogs/Filters/FissureFilters.jsx index 4fb55a27..2b3fe485 100644 --- a/components/modalDialogs/Filters/FissureFilters.jsx +++ b/components/modalDialogs/Filters/FissureFilters.jsx @@ -15,14 +15,13 @@ export default { return planets.filter((planet) => planet.state).map((planet) => planet.value); }, - set() {}, - }, - }, - methods: { - updateFissureStates(enabledFissures) { - Object.keys(this.fissureStates).forEach((planet) => { - this.$store.commit('worldstate/commitFissurePlanetState', [planet, enabledFissures.includes(planet)]); - }); + set(enabledFissures) { + Object.keys(this.fissureStates).forEach((planet) => { + if (this.fissureStates[planet] !== enabledFissures.includes(planet)) { + this.$store.commit('worldstate/commitFissurePlanetState', [planet, enabledFissures.includes(planet)]); + } + }); + }, }, }, render() { @@ -40,7 +39,6 @@ export default { switches stacked class="settings-group fissure-setting-group" - input={(vals) => this.updateFissureStates(vals)} > diff --git a/components/modalDialogs/Filters/NotificationFilters.jsx b/components/modalDialogs/Filters/NotificationFilters.jsx index 8c24f43c..7c6dd21a 100644 --- a/components/modalDialogs/Filters/NotificationFilters.jsx +++ b/components/modalDialogs/Filters/NotificationFilters.jsx @@ -97,8 +97,8 @@ export default { preserve-search={true} hide-selected={true} multiple={true} - select={this.toggleRewardState} - remove={this.toggleRewardState} + onSelect={this.toggleRewardState} + onRemove={this.toggleRewardState} />


diff --git a/components/panels/SortiePanel.jsx b/components/panels/SortiePanel.jsx new file mode 100644 index 00000000..73fd88b8 --- /dev/null +++ b/components/panels/SortiePanel.jsx @@ -0,0 +1,115 @@ +import dayjs from 'dayjs'; + +import HubImg from '@/components/HubImg.jsx'; +import TimeBadge from '@/components/TimeBadge.jsx'; +import HubPanelWrap from '@/components/HubPanelWrap.jsx'; +import { cdn } from '@/services/utilities'; + +const corpus = cdn('svg/factions/corpus.svg'); +const corrupted = cdn('svg/factions/corrupted.svg'); +const grineer = cdn('svg/factions/grineer.svg'); +const infested = cdn('svg/factions/infested.svg'); +const sentient = cdn('svg/factions/sentient.svg'); +const narmer = cdn('svg/factions/narmer2.svg'); + +const styles = { + inline: { + display: 'inline', + }, + missionType: { + filter: 'invert(100%)', + 'margin-top': '-3px', + 'margin-right': '5px', + width: '25px', + height: '25px', + }, +}; +const tooltips = { + 'v-b-tooltip.top': true, +}; + +export default { + name: 'SortiePanel', + components: { + TimeBadge, + HubImg, + HubPanelWrap, + }, + props: { + sortie: { + type: Object, + default: () => { + return {}; + }, + }, + }, + computed: { + headertext() { + return this.$props.sortie?.missions?.length ? this.$t('sortie.hunt.header') : this.$t('sortie.header'); + }, + factionImg() { + const fImg = { + corpus, + grineer, + infested, + infestation: infested, + corrupted, + orokin: corrupted, + sentient, + narmer, + }; + return fImg[this.$props.sortie?.faction?.toLowerCase()] || corrupted; + }, + missions() { + return (this.$props.sortie?.variants?.length ? this.$props.sortie.variants : this.$props.sortie.missions) || []; + }, + }, + render() { + const now = dayjs().toISOString(); + return ( + + + + +

+ + {this.sortie.boss} +

+
+ +
+ {this.missions.map((mission, index) => { + return ( + +
+ + + {mission.missionType || mission.type} - {mission.node} + + + + {mission.modifier} + +
+
+ ); + })} +
+
+ ); + }, +}; diff --git a/components/panels/SortiePanel.vue b/components/panels/SortiePanel.vue deleted file mode 100644 index f8e820f7..00000000 --- a/components/panels/SortiePanel.vue +++ /dev/null @@ -1,93 +0,0 @@ - - - diff --git a/cypress/.eslintrc.yaml b/cypress/.eslintrc.yaml index 0b03a94a..e2a61c04 100644 --- a/cypress/.eslintrc.yaml +++ b/cypress/.eslintrc.yaml @@ -1,6 +1,14 @@ globals: cy: readonly - it: readonly - describe: readonly - beforeEach: readonly - expect: readonly +env: + mocha: true + cypress/globals: true +plugins: + - cypress +rules: + cypress/no-assigning-return-values: error + cypress/no-unnecessary-waiting: 0 + cypress/assertion-before-screenshot: warn + cypress/no-force: warn + cypress/no-async-tests: error + cypress/no-pause: error diff --git a/cypress/e2e/openworld/load.spec.js b/cypress/e2e/openworld/load.spec.js index 164c651a..d73bafe4 100644 --- a/cypress/e2e/openworld/load.spec.js +++ b/cypress/e2e/openworld/load.spec.js @@ -6,8 +6,8 @@ describe('Maps', () => { }); describe(`${ow} map`, () => { it('should load', () => { - const map = cy.get('div.vue2leaflet-map'); - map.should('exist'); + cy.get('div.vue2leaflet-map').as('map'); + cy.get('@map').should('exist'); cy.get('div.leaflet-control-zoom').should('exist'); cy.get('div.leaflet-control-layers').should('exist'); cy.get('div.leaflet-pane.leaflet-map-pane').should('exist'); @@ -23,20 +23,20 @@ describe('Fish', () => { }); describe(`${ow} fish data`, () => { it('should load', () => { - const table = cy.get('div.fish-info'); - table.should('exist'); - const rowtypes = table.find('[role=rowgroup]'); - rowtypes.should('have.length', 2); - const head = rowtypes.get('thead'); - head.should('exist'); + cy.get('div.fish-info').as('fish'); + cy.get('@fish').should('exist'); + cy.get('@fish').find('[role=rowgroup]').as('rowtypes'); + cy.get('@rowtypes').should('have.length', 2); + cy.get('@rowtypes').get('thead').as('head'); + cy.get('@head').should('exist'); - const rows = rowtypes.get('tbody'); - rows.should('exist'); - rows.children().should('have.length.gt', 10); + cy.get('@rowtypes').get('tbody').as('rows'); + cy.get('@rows').should('exist'); + cy.get('@rows').children().should('have.length.gt', 10); - const first = rows.children().get('tr:nth-of-type(1)'); - first.should('exist'); - first.children().should('have.length.gt', 13); + cy.get('@rows').children().get('tr:nth-of-type(1)').as('first'); + cy.get('@first').should('exist'); + cy.get('@first').children().should('have.length.gt', 13); }); }); }); diff --git a/cypress/e2e/synthesis/load.spec.js b/cypress/e2e/synthesis/load.spec.js index 453f51ce..18ed73d0 100644 --- a/cypress/e2e/synthesis/load.spec.js +++ b/cypress/e2e/synthesis/load.spec.js @@ -4,8 +4,8 @@ describe('Synthesis', () => { cy.wait(1000); }); it('should load', () => { - const searchBox = cy.get('input#filterInput'); - searchBox.should('exist'); - searchBox.siblings('.input-group-append').find('.btn').should('have.text', 'Clear'); + cy.get('input#filterInput').as('search'); + cy.get('@search').should('exist'); + cy.get('@search').siblings('.input-group-append').find('.btn').should('have.text', 'Clear'); }); }); diff --git a/cypress/e2e/timers/load.spec.js b/cypress/e2e/timers/load.spec.js index 5e89f7e3..50f9f68c 100644 --- a/cypress/e2e/timers/load.spec.js +++ b/cypress/e2e/timers/load.spec.js @@ -1,7 +1,7 @@ describe('Timers', () => { - beforeEach(() => { + before(() => { cy.visit('http://localhost:3000/'); - cy.wait(1000); + cy.wait(5000); }); describe('Fissures', () => { let fissures; @@ -82,21 +82,22 @@ describe('Timers', () => { }); describe('Nightwave', () => { it('should load', () => { - const nightwave = cy.get('div.nightwave'); - nightwave.children().should('have.length', 2); + cy.get('div.nightwave').as('nightwave'); + cy.get('@nightwave').children().should('have.length', 2); }); }); describe('Sortie', () => { it('should load', () => { - const sortie = cy.get('div.sortie'); - sortie.children().should('have.length', 2); + cy.get('div.sortie').as('sortie'); + // 2 for archons, 2 for sortie + cy.get('@sortie').children().should('have.length', 4); }); }); describe('Bounties', () => { it('should load', () => { - const bounties = cy.get('div.bounties'); - bounties.should('have.length', 3); - bounties.each((bountyPanel) => { + cy.get('div.bounties').as('bounties'); + cy.get('@bounties').should('have.length', 3); + cy.get('@bounties').each((bountyPanel) => { expect(bountyPanel.children()).to.have.length(2); }); }); diff --git a/package-lock.json b/package-lock.json index 43885394..925465a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "@wfcd/hub", - "version": "2.1.2", + "version": "2.1.3", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -9507,6 +9507,15 @@ } } }, + "eslint-plugin-cypress": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-cypress/-/eslint-plugin-cypress-2.12.1.tgz", + "integrity": "sha512-c2W/uPADl5kospNDihgiLc7n87t5XhUbFDoTl6CfVkmG+kDAb5Ux10V9PoLPu9N+r7znpc+iQlcmAqT1A/89HA==", + "dev": true, + "requires": { + "globals": "^11.12.0" + } + }, "eslint-plugin-es": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-4.1.0.tgz", diff --git a/package.json b/package.json index 5b3448d2..30d9b53b 100644 --- a/package.json +++ b/package.json @@ -55,6 +55,7 @@ "cypress": "^10.8.0", "eslint": "^8.4.1", "eslint-config-prettier": "^8.3.0", + "eslint-plugin-cypress": "^2.12.1", "eslint-plugin-nuxt": "^4.0.0", "eslint-plugin-prettier": "^4.2.1", "eslint-plugin-vuejs-accessibility": "^1.2.0", diff --git a/pages/index.vue b/pages/index.vue index 4c7dc72e..90faa0ad 100644 --- a/pages/index.vue +++ b/pages/index.vue @@ -15,6 +15,7 @@ + @@ -31,7 +32,7 @@ import { mapState, mapGetters } from 'vuex'; import AlertPanel from '@/components/panels/AlertPanel.jsx'; import NewsPanel from '@/components/panels/NewsPanel.vue'; import AggregatedTimePanel from '@/components/panels/AggregatedTimePanel.jsx'; -import SortiePanel from '@/components/panels/SortiePanel.vue'; +import SortiePanel from '@/components/panels/SortiePanel.jsx'; import FissuresPanel from '@/components/panels/FissuresPanel.vue'; import BountyPanel from '@/components/panels/BountyPanel.vue'; import InvasionsPanel from '@/components/panels/InvasionsPanel.jsx'; diff --git a/services/Notifier.js b/services/Notifier.js index ee7403fc..6cd961f2 100644 --- a/services/Notifier.js +++ b/services/Notifier.js @@ -107,6 +107,14 @@ const makeNotification = (type, data) => { icon: wfcdLogoUrl, }, }; + case 'archonHunt': + return { + head: `Archon Hunt: ${data.boss}`, + body: { + body: `${data.missions.map((mission) => `${mission.type} • ${mission.node}`).join('\n')}\n${data.eta}`, + icon: wfcdLogoUrl, + }, + }; case 'fissure': return { head: 'New Fissure Detected', @@ -250,7 +258,6 @@ export default class Notifier { } } }); - safeCall(() => { for (const event of ws.events) { if (this.isNotifiable(event.id, 'operation')) { @@ -258,7 +265,6 @@ export default class Notifier { } } }); - safeCall(() => { if (ws.cetusCycle.shortString) { if (ws.cetusCycle.isDay) { @@ -270,20 +276,17 @@ export default class Notifier { } } }); - safeCall(() => { const cetus = ws.syndicateMissions.filter((synd) => synd.syndicate === 'Ostrons')[0]; if (cetus && this.isNotifiable(cetus.id, 'syndicate.ostrons')) { toNotify.push(makeNotification('syndicate.ostrons', cetus)); } }); - safeCall(() => { if (ws.voidTrader.active && this.isNotifiable(ws.voidTrader.id, 'baro')) { toNotify.push(makeNotification('baro', ws.voidTrader)); } }); - safeCall(() => { for (const currentItem of ws.dailyDeals) { if (this.isNotifiable(currentItem.id, 'darvo')) { @@ -291,7 +294,6 @@ export default class Notifier { } } }); - safeCall(() => { for (const acolyte of ws.persistentEnemies) { if (this.isNotifiable(acolyte.pid, 'enemies')) { @@ -299,13 +301,16 @@ export default class Notifier { } } }); - safeCall(() => { if (ws.sortie && this.isNotifiable(ws.sortie.id)) { toNotify.push(makeNotification('sortie', ws.sortie)); } }); - + safeCall(() => { + if (ws.archonHunt && this.isNotifiable(ws.archonHunt.id)) { + toNotify.push(makeNotification('archonHunt', ws.archonHunt)); + } + }); safeCall(() => { for (const fissure of ws.fissures) { const notifIdentifier = `fissures.t${fissure.tierNum}.${fissure.missionType.toLowerCase().replace(/\s/gi, '')}`; @@ -314,7 +319,6 @@ export default class Notifier { } } }); - safeCall(() => { for (const article of ws.news) { let type; @@ -335,7 +339,6 @@ export default class Notifier { } } }); - safeCall(() => { for (const invasion of ws.invasions) { if (this.isNotifiable(invasion.id, 'invasions', invasion.rewardTypes)) { @@ -343,7 +346,6 @@ export default class Notifier { } } }); - safeCall(() => { if (ws.vallisCycle.shortString) { if (ws.vallisCycle.isWarm) { @@ -355,7 +357,6 @@ export default class Notifier { } } }); - safeCall(() => { if (ws.nightwave && ws.nightwave.activeChallenges.length) { for (const challenge of ws.nightwave.activeChallenges) { @@ -365,7 +366,6 @@ export default class Notifier { } } }); - safeCall(() => { if (ws.sentientOutposts.id && ws.sentientOutposts.active) { if (this.isNotifiable(ws.sentientOutposts.id, 'outposts')) { @@ -373,7 +373,6 @@ export default class Notifier { } } }); - safeCall(() => { if (ws.arbitration) { const id = `arbitration:${new Date(ws.arbitration.expiry).getTime()}`; diff --git a/static/json/components.json b/static/json/components.json index 01025581..274725b0 100644 --- a/static/json/components.json +++ b/static/json/components.json @@ -153,6 +153,16 @@ "sortie": "@worldstate.sortie" } }, + "archonHunt": { + "display": true, + "displayable": true, + "displayName": "Archon Hunt", + "key": "archonHunt", + "component": "SortiePanel", + "props": { + "sortie": "@worldstate.archonHunt" + } + }, "arbitration": { "display": true, "displayable": true, diff --git a/static/json/trackables.json b/static/json/trackables.json index 58244ee2..338b956a 100644 --- a/static/json/trackables.json +++ b/static/json/trackables.json @@ -122,6 +122,11 @@ "value": "sorties", "text": "Sorties" }, + "archonHunt": { + "state": false, + "value": "archonHunt", + "text": "Archon Hunt" + }, "baro": { "state": false, "value": "baro", diff --git a/static/lang/en.json b/static/lang/en.json index 1ead7b7d..02c7023f 100644 --- a/static/lang/en.json +++ b/static/lang/en.json @@ -154,7 +154,10 @@ "prediction": "Prediction" }, "sortie": { - "header": "Sortie" + "header": "Sortie", + "hunt": { + "header": "Archon Hunt" + } }, "steelPath": { "header": "Steel Path"