From 239147367fdb4a35a107168f59b5a1a48b4e7052 Mon Sep 17 00:00:00 2001 From: "Kyle J. Kemp" Date: Tue, 17 Sep 2024 11:29:52 -0500 Subject: [PATCH] support shared navigation urls/etc for easier debugging and sharing --- src/app/analysis/analysis.component.html | 13 +- src/app/analysis/analysis.component.ts | 88 +++----- src/app/home/home.component.html | 13 +- src/app/home/home.component.ts | 98 ++++++++- src/app/pinpoint/pinpoint.component.html | 13 +- src/app/pinpoint/pinpoint.component.ts | 41 +++- src/app/query/query.component.html | 2 +- src/app/query/query.component.ts | 4 +- .../input-analysis-report.component.ts | 203 +++++++++--------- .../input-itemclass.component.ts | 12 +- .../input-map/input-map.component.html | 6 +- .../input-map/input-map.component.ts | 17 +- .../input-spell/input-spell.component.html | 4 +- .../input-spell/input-spell.component.ts | 11 +- src/app/validation/validation.component.ts | 3 +- 15 files changed, 331 insertions(+), 197 deletions(-) diff --git a/src/app/analysis/analysis.component.html b/src/app/analysis/analysis.component.html index dd85648..867a496 100644 --- a/src/app/analysis/analysis.component.html +++ b/src/app/analysis/analysis.component.html @@ -1,7 +1,7 @@
- +
@@ -9,7 +9,8 @@
- +
@@ -18,11 +19,13 @@
@if(reportTypeName === 'progressionsingle' || reportTypeName === 'weaponpotency') { - + } @if(reportTypeName === 'spellpotency') { - + }
@@ -32,7 +35,7 @@ @if(reportTypeName === 'weaponpotency') { Weapon Tier + class="form-input" (change)="changeURLProp.emit(['tier', tierInput().toString()])" /> }
diff --git a/src/app/analysis/analysis.component.ts b/src/app/analysis/analysis.component.ts index 4666bb0..4cde73c 100644 --- a/src/app/analysis/analysis.component.ts +++ b/src/app/analysis/analysis.component.ts @@ -1,4 +1,12 @@ -import { Component, computed, inject, signal } from '@angular/core'; +import { + Component, + computed, + inject, + input, + OnInit, + output, + signal, +} from '@angular/core'; import { maxBy } from 'lodash'; import { AnalysisReportType, ItemClassType } from '../../interfaces'; import { AnalysisService } from '../services/analysis.service'; @@ -10,7 +18,14 @@ import { ReportModel } from '../shared/components/input-analysis-report/input-an templateUrl: './analysis.component.html', styleUrl: './analysis.component.scss', }) -export class AnalysisComponent { +export class AnalysisComponent implements OnInit { + public exit = output(); + public changeURLProp = output<[string, string | undefined]>(); + public defaultReport = input(); + public defaultItemclass = input(); + public defaultSpell = input(); + public defaultTier = input(); + public analysisService = inject(AnalysisService); public modService = inject(ModService); @@ -24,7 +39,7 @@ export class AnalysisComponent { return maxBy(this.modService.mod().items, 'tier')?.tier ?? 1; }); - public report = signal(undefined); + public report = signal(undefined); public reportData = computed(() => { const reportType = this.reportType(); const reportArgs = this.reportDataArgs(); @@ -89,70 +104,19 @@ export class AnalysisComponent { } }); + ngOnInit() { + const tier = this.defaultTier(); + if (tier) { + this.tierInput.set(+tier); + } + } + public updateReport($event: ReportModel | undefined) { if (!$event) return; this.reportType.set($event.type); this.reportDataArgs.set($event.data); - /* - let report: AnalysisReport | undefined = undefined; - - switch ($event.type) { - case AnalysisReportType.ArmorAverage: { - report = this.analysisService.generateArmorReport( - $event.data.itemClasses ?? [] - ); - break; - } - - case AnalysisReportType.GemStats: { - report = this.analysisService.generateGemReport(); - break; - } - - case AnalysisReportType.StatUtilization: { - report = this.analysisService.generateStatUtilizationReport(); - break; - } - - case AnalysisReportType.SpellPotency: { - report = this.analysisService.generateSpellPotencyReport( - $event.data.spellName ?? '' - ); - break; - } - - case AnalysisReportType.WeaponPotency: { - report = this.analysisService.generateWeaponPotencyReport( - $event.data.itemClass, - 5 - ); - break; - } - - case AnalysisReportType.TraitUsage: { - report = this.analysisService.generateTraitReport(); - break; - } - - TODO: this one should support an array of item classes (default) OR a singular item picker - case AnalysisReportType.Progression: { - report = this.analysisService.generateProgressionReport( - $event.data.itemClasses ?? [] - ); - break; - } - - case AnalysisReportType.WeaponAverage: { - report = this.analysisService.generateWeaponReport( - $event.data.itemClasses ?? [] - ); - break; - } - } - - this.reportData.set(report); - */ + this.changeURLProp.emit(['report', $event.value]); } } diff --git a/src/app/home/home.component.html b/src/app/home/home.component.html index 58e406e..467e3e0 100644 --- a/src/app/home/home.component.html +++ b/src/app/home/home.component.html @@ -74,7 +74,7 @@
- +
@@ -85,7 +85,10 @@
- +
@@ -96,7 +99,9 @@
- +
@@ -107,7 +112,7 @@
- +
diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts index 1399e10..dfad242 100644 --- a/src/app/home/home.component.ts +++ b/src/app/home/home.component.ts @@ -3,10 +3,13 @@ import { computed, ElementRef, inject, + OnInit, signal, viewChild, } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; import { SwalComponent } from '@sweetalert2/ngx-sweetalert2'; +import { isUndefined } from 'lodash'; import { LocalStorageService } from 'ngx-webstorage'; import { numErrorsForMod, validationMessagesForMod } from '../helpers'; import { formatMod } from '../helpers/exporter'; @@ -22,7 +25,10 @@ import { QueryService } from '../services/query.service'; templateUrl: './home.component.html', styleUrls: ['./home.component.scss'], }) -export class HomeComponent { +export class HomeComponent implements OnInit { + private router = inject(Router); + private route = inject(ActivatedRoute); + private localStorage = inject(LocalStorageService); public pinpointService = inject(PinpointService); public analysisService = inject(AnalysisService); @@ -98,15 +104,44 @@ export class HomeComponent { }, ]; - constructor() { + constructor() {} + + ngOnInit() { const lastTab = (this.localStorage.retrieve('lasttab') as number) ?? 0; - this.activeTab.set(lastTab); + const lastTabUrl = this.route.snapshot.queryParamMap.get('tab'); + + this.activeTab.set(lastTabUrl ? +lastTabUrl : lastTab); + + const lastSub = this.route.snapshot.queryParamMap.get('sub'); + switch (lastSub) { + case 'validate': { + return this.toggleModValidation(); + } + case 'pinpoint': { + return this.togglePinpointing(); + } + case 'analyze': { + return this.toggleAnalyzing(); + } + case 'query': { + return this.toggleQuerying(); + } + } } changeTab(newTab: number) { this.activeTab.set(newTab); this.localStorage.store('lasttab', newTab); + + void this.router.navigate([], { + relativeTo: this.route, + queryParamsHandling: 'merge', + queryParams: { + tab: newTab, + sub: '', + }, + }); } closeMenu() { @@ -151,6 +186,14 @@ export class HomeComponent { this.pinpointService.togglePinpointing(false); this.analysisService.toggleAnalyzing(false); this.queryService.toggleQuerying(false); + + void this.router.navigate([], { + relativeTo: this.route, + queryParamsHandling: 'merge', + queryParams: { + sub: 'validate', + }, + }); } togglePinpointing() { @@ -158,6 +201,14 @@ export class HomeComponent { this.isValidating.set(false); this.analysisService.toggleAnalyzing(false); this.queryService.toggleQuerying(false); + + void this.router.navigate([], { + relativeTo: this.route, + queryParamsHandling: 'merge', + queryParams: { + sub: 'pinpoint', + }, + }); } toggleAnalyzing() { @@ -165,6 +216,14 @@ export class HomeComponent { this.isValidating.set(false); this.pinpointService.togglePinpointing(false); this.queryService.toggleQuerying(false); + + void this.router.navigate([], { + relativeTo: this.route, + queryParamsHandling: 'merge', + queryParams: { + sub: 'analyze', + }, + }); } toggleQuerying() { @@ -172,6 +231,14 @@ export class HomeComponent { this.isValidating.set(false); this.pinpointService.togglePinpointing(false); this.analysisService.toggleAnalyzing(false); + + void this.router.navigate([], { + relativeTo: this.route, + queryParamsHandling: 'merge', + queryParams: { + sub: 'query', + }, + }); } toggleTester() { @@ -186,4 +253,29 @@ export class HomeComponent { void this.electronService.reloadExternalWebMod(); } + + getURLSubProp(prop: string): string | null { + return this.route.snapshot.queryParamMap.get(prop); + } + + updateSubURLProp(prop: string, value: string | number | undefined) { + if (isUndefined(value)) return; + + void this.router.navigate([], { + relativeTo: this.route, + queryParamsHandling: 'merge', + queryParams: { + [prop]: value, + }, + }); + } + + resetSub() { + void this.router.navigate([], { + relativeTo: this.route, + queryParams: { + tab: this.activeTab(), + }, + }); + } } diff --git a/src/app/pinpoint/pinpoint.component.html b/src/app/pinpoint/pinpoint.component.html index 93bd859..629b35b 100644 --- a/src/app/pinpoint/pinpoint.component.html +++ b/src/app/pinpoint/pinpoint.component.html @@ -2,13 +2,13 @@ @for(tab of tabOrder; track tab.name; let i = $index) { + (click)="pinpointService.activePinpointTab.set(i); changeURLProp.emit(['pptab', i.toString()])"> {{ tab.name }} }
- +
@@ -19,7 +19,8 @@
- +
@@ -63,7 +64,7 @@
-
@@ -146,7 +147,7 @@
-
@@ -223,7 +224,7 @@
-
diff --git a/src/app/pinpoint/pinpoint.component.ts b/src/app/pinpoint/pinpoint.component.ts index 82deab0..7cda8a8 100644 --- a/src/app/pinpoint/pinpoint.component.ts +++ b/src/app/pinpoint/pinpoint.component.ts @@ -1,4 +1,4 @@ -import { Component, inject } from '@angular/core'; +import { Component, inject, input, OnInit, output } from '@angular/core'; import { PinpointService } from '../services/pinpoint.service'; @Component({ @@ -6,7 +6,16 @@ import { PinpointService } from '../services/pinpoint.service'; templateUrl: './pinpoint.component.html', styleUrl: './pinpoint.component.scss', }) -export class PinpointComponent { +export class PinpointComponent implements OnInit { + public exit = output(); + public changeURLProp = output<[string, string]>(); + + public defaultTab = input(); + public defaultMap = input(); + public defaultItem = input(); + public defaultNPC = input(); + public defaultSTEM = input(); + public pinpointService = inject(PinpointService); public tabOrder = [ @@ -23,4 +32,32 @@ export class PinpointComponent { name: 'STEM', }, ]; + + ngOnInit() { + const defaultTab = this.defaultTab(); + const defaultMap = this.defaultMap(); + const defaultItem = this.defaultItem(); + const defaultNPC = this.defaultNPC(); + const defaultSTEM = this.defaultSTEM(); + + if (defaultTab) { + this.pinpointService.activePinpointTab.set(+defaultTab); + } + + if (defaultMap) { + this.pinpointService.searchMap(defaultMap); + } + + if (defaultItem) { + this.pinpointService.searchItem(defaultItem); + } + + if (defaultNPC) { + this.pinpointService.searchNPC(defaultNPC); + } + + if (defaultSTEM) { + this.pinpointService.searchSTEM(defaultSTEM); + } + } } diff --git a/src/app/query/query.component.html b/src/app/query/query.component.html index ac6cb4c..ded9f2b 100644 --- a/src/app/query/query.component.html +++ b/src/app/query/query.component.html @@ -15,7 +15,7 @@ } } - +
diff --git a/src/app/query/query.component.ts b/src/app/query/query.component.ts index b706be5..2cfa9e3 100644 --- a/src/app/query/query.component.ts +++ b/src/app/query/query.component.ts @@ -1,4 +1,4 @@ -import { Component, inject, signal } from '@angular/core'; +import { Component, inject, output, signal } from '@angular/core'; import { CodeModel } from '@ngstack/code-editor'; import * as alasql from 'alasql'; import * as _ from 'lodash'; @@ -12,6 +12,8 @@ import { QueryService } from '../services/query.service'; styleUrl: './query.component.scss', }) export class QueryComponent { + public exit = output(); + private localStorage = inject(LocalStorageService); public queryService = inject(QueryService); diff --git a/src/app/shared/components/input-analysis-report/input-analysis-report.component.ts b/src/app/shared/components/input-analysis-report/input-analysis-report.component.ts index 785d248..1318a63 100644 --- a/src/app/shared/components/input-analysis-report/input-analysis-report.component.ts +++ b/src/app/shared/components/input-analysis-report/input-analysis-report.component.ts @@ -1,12 +1,11 @@ import { Component, computed, - inject, input, model, + OnInit, output, } from '@angular/core'; -import { sortBy } from 'lodash'; import { AnalysisReportType, ArmorClasses, @@ -16,7 +15,6 @@ import { ShieldClasses, } from '../../../../interfaces'; import { armorClasses, weaponClasses } from '../../../helpers'; -import { ModService } from '../../../services/mod.service'; export type ReportModel = { category: string; @@ -27,6 +25,7 @@ export type ReportModel = { spellName?: string; }; value: string; + desc: string; }; @Component({ @@ -34,116 +33,116 @@ export type ReportModel = { templateUrl: './input-analysis-report.component.html', styleUrl: './input-analysis-report.component.scss', }) -export class InputAnalysisReportComponent { - private modService = inject(ModService); - - public report = model.required(); +export class InputAnalysisReportComponent implements OnInit { + public report = model.required(); public label = input('Report'); public change = output(); - - private allCalculableSpells = computed(() => { - return this.modService - .mod() - .stems.filter( - (s) => s._hasSpell && s.spell.skillMultiplierChanges?.length > 0 - ); - }); + public defaultValue = input(); public values = computed(() => { - return sortBy( - [ - { - category: 'Potency Estimator', - value: 'Spells', - type: AnalysisReportType.SpellPotency, - data: {}, - desc: `Level/skill varied damage calculator.`, - }, - { - category: 'Potency Estimator', - value: 'Weapons', - type: AnalysisReportType.WeaponPotency, - data: {}, - desc: `Level/skill varied damage calculator.`, - }, - { - category: 'Item Progression (Singular)', - value: 'Singular Weapon/Armor Class', - type: AnalysisReportType.ProgressionSingle, - data: {}, - desc: `Level-by-level progression report.`, - }, - { - category: 'Item Progression (Aggregate)', - value: 'Shield', - type: AnalysisReportType.ProgressionAggregate, - data: { - itemClasses: ShieldClasses, - }, - desc: `Level-by-level progression report (includes every Shield-adjacent item).`, + return [ + { + category: 'Potency Estimator', + value: 'Spells', + type: AnalysisReportType.SpellPotency, + data: {}, + desc: `Level/skill varied damage calculator.`, + }, + { + category: 'Potency Estimator', + value: 'Weapons', + type: AnalysisReportType.WeaponPotency, + data: {}, + desc: `Level/skill varied damage calculator.`, + }, + { + category: 'Item Progression (Singular)', + value: 'Singular Weapon/Armor Type', + type: AnalysisReportType.ProgressionSingle, + data: {}, + desc: `Level-by-level progression report.`, + }, + { + category: 'Item Progression (Aggregate)', + value: 'Armors', + type: AnalysisReportType.ProgressionAggregate, + data: { + itemClasses: ArmorClasses, }, - { - category: 'Item Progression (Aggregate)', - value: 'Armor', - type: AnalysisReportType.ProgressionAggregate, - data: { - itemClasses: ArmorClasses, - }, - desc: `Level-by-level progression report (includes every Armor-adjacent item).`, + desc: `Level-by-level progression report (includes every Armor-adjacent item).`, + }, + { + category: 'Item Progression (Aggregate)', + value: 'Robes', + type: AnalysisReportType.ProgressionAggregate, + data: { + itemClasses: RobeClasses, }, - { - category: 'Item Progression (Aggregate)', - value: 'Robe', - type: AnalysisReportType.ProgressionAggregate, - data: { - itemClasses: RobeClasses, - }, - desc: `Level-by-level progression report (includes every Robe-adjacent item).`, + desc: `Level-by-level progression report (includes every Robe-adjacent item).`, + }, + { + category: 'Item Progression (Aggregate)', + value: 'Shields', + type: AnalysisReportType.ProgressionAggregate, + data: { + itemClasses: ShieldClasses, }, - { - category: 'Stat Report', - value: 'Armor', - type: AnalysisReportType.ArmorAverage, - data: { - itemClasses: armorClasses, - }, - desc: 'A global and individual breakdown of each armor type, including average stats per bracket.', + desc: `Level-by-level progression report (includes every Shield-adjacent item).`, + }, + { + category: 'Stat Report', + value: 'Armor', + type: AnalysisReportType.ArmorAverage, + data: { + itemClasses: armorClasses, }, - { - category: 'Stat Report', - value: 'Weapon', - type: AnalysisReportType.WeaponAverage, - data: { - itemClasses: weaponClasses, - }, - desc: 'A global and individual breakdown of each weapon type, including average stats per bracket.', + desc: 'A global and individual breakdown of each armor type, including average stats per bracket.', + }, + { + category: 'Stat Report', + value: 'Gem', + type: AnalysisReportType.GemStats, + data: {}, + desc: 'A breakdown of each gem stat per item slot.', + }, + { + category: 'Stat Report', + value: 'Weapon', + type: AnalysisReportType.WeaponAverage, + data: { + itemClasses: weaponClasses, }, - { - category: 'Stat Report', - value: 'Gem', - type: AnalysisReportType.GemStats, - data: {}, - desc: 'A breakdown of each gem stat per item slot.', - }, - { - category: 'Stat Report', - value: 'Stat Utilization', - type: AnalysisReportType.StatUtilization, - data: {}, - desc: 'A breakdown of each stats utilization across weapons and armors', - }, - { - category: 'Miscellaneous', - value: 'Traits', - type: AnalysisReportType.TraitUsage, - data: {}, - desc: 'A breakdown of trait usage, including unused traits.', - }, - ], - ['category', 'value'] - ); + desc: 'A global and individual breakdown of each weapon type, including average stats per bracket.', + }, + { + category: 'Miscellaneous', + value: 'Stat Utilization', + type: AnalysisReportType.StatUtilization, + data: {}, + desc: 'A breakdown of each stats utilization across weapons and armors', + }, + { + category: 'Miscellaneous', + value: 'Traits', + type: AnalysisReportType.TraitUsage, + data: {}, + desc: 'A breakdown of trait usage, including unused traits.', + }, + ] as ReportModel[]; }); + ngOnInit() { + if (this.defaultValue()) { + const defaultObj = this.values().find( + (f) => f.value === this.defaultValue() + ); + if (!defaultObj) return; + + this.report.set(defaultObj.value); + this.change.emit(defaultObj); + } + } + public search(term: string, item: { value: string }) { return item.value.toLowerCase().includes(term.toLowerCase()); } diff --git a/src/app/shared/components/input-itemclass/input-itemclass.component.ts b/src/app/shared/components/input-itemclass/input-itemclass.component.ts index 3f91d39..39970bb 100644 --- a/src/app/shared/components/input-itemclass/input-itemclass.component.ts +++ b/src/app/shared/components/input-itemclass/input-itemclass.component.ts @@ -1,4 +1,4 @@ -import { Component, input, model, output } from '@angular/core'; +import { Component, input, model, OnInit, output } from '@angular/core'; import { ArmorClass, ItemClassType, @@ -11,10 +11,11 @@ import { templateUrl: './input-itemclass.component.html', styleUrl: './input-itemclass.component.scss', }) -export class InputItemclassComponent { +export class InputItemclassComponent implements OnInit { public itemClass = model(); public label = input('Type'); public change = output(); + public defaultValue = input(); public values = [ ...Object.values(WeaponClass).map((c) => ({ @@ -27,4 +28,11 @@ export class InputItemclassComponent { value: c, })), ]; + + ngOnInit() { + const val = this.defaultValue(); + if (val) { + this.itemClass.set(val as ItemClassType); + } + } } diff --git a/src/app/shared/components/input-map/input-map.component.html b/src/app/shared/components/input-map/input-map.component.html index a2e4bfb..e704c6d 100644 --- a/src/app/shared/components/input-map/input-map.component.html +++ b/src/app/shared/components/input-map/input-map.component.html @@ -1,6 +1,6 @@
- + Map -
+
\ No newline at end of file diff --git a/src/app/shared/components/input-map/input-map.component.ts b/src/app/shared/components/input-map/input-map.component.ts index dfe0a98..a72a479 100644 --- a/src/app/shared/components/input-map/input-map.component.ts +++ b/src/app/shared/components/input-map/input-map.component.ts @@ -1,4 +1,12 @@ -import { Component, computed, inject, model, output } from '@angular/core'; +import { + Component, + computed, + inject, + input, + model, + OnInit, + output, +} from '@angular/core'; import { uniq } from 'lodash'; import { ModService } from '../../../services/mod.service'; @@ -7,13 +15,18 @@ import { ModService } from '../../../services/mod.service'; templateUrl: './input-map.component.html', styleUrl: './input-map.component.scss', }) -export class InputMapComponent { +export class InputMapComponent implements OnInit { private modService = inject(ModService); public map = model.required(); + public defaultValue = input(); public change = output(); public values = computed(() => uniq(this.modService.mod().maps.map((m) => m.name)).sort() ); + + ngOnInit() { + this.map.set(this.values().find((f) => f === this.defaultValue())); + } } diff --git a/src/app/shared/components/input-spell/input-spell.component.html b/src/app/shared/components/input-spell/input-spell.component.html index 97fa938..83b671d 100644 --- a/src/app/shared/components/input-spell/input-spell.component.html +++ b/src/app/shared/components/input-spell/input-spell.component.html @@ -1,7 +1,7 @@
+ (change)="change.emit($event)"> {{ label() }} -
+ \ No newline at end of file diff --git a/src/app/shared/components/input-spell/input-spell.component.ts b/src/app/shared/components/input-spell/input-spell.component.ts index c518af3..1eec4eb 100644 --- a/src/app/shared/components/input-spell/input-spell.component.ts +++ b/src/app/shared/components/input-spell/input-spell.component.ts @@ -4,6 +4,7 @@ import { inject, input, model, + OnInit, output, } from '@angular/core'; import { ModService } from '../../../services/mod.service'; @@ -13,12 +14,13 @@ import { ModService } from '../../../services/mod.service'; templateUrl: './input-spell.component.html', styleUrl: './input-spell.component.scss', }) -export class InputSpellComponent { +export class InputSpellComponent implements OnInit { private modService = inject(ModService); public spell = model.required(); public label = input('Spell'); public change = output(); + public defaultValue = input(); public values = computed(() => { const baseSpells = this.modService @@ -32,4 +34,11 @@ export class InputSpellComponent { public search(term: string, item: { value: string }) { return item.value.toLowerCase().includes(term.toLowerCase()); } + + ngOnInit() { + const defaultValue = this.defaultValue(); + if (defaultValue) { + this.spell.set(defaultValue); + } + } } diff --git a/src/app/validation/validation.component.ts b/src/app/validation/validation.component.ts index 478312e..407926f 100644 --- a/src/app/validation/validation.component.ts +++ b/src/app/validation/validation.component.ts @@ -9,11 +9,12 @@ import { ModService } from '../services/mod.service'; styleUrl: './validation.component.scss', }) export class ValidationComponent { + public exit = output(); + private localStorage = inject(LocalStorageService); private modService = inject(ModService); public activeValidationTab = signal(0); - public exit = output(); public validationMessageContainers = computed(() => { const mod = this.modService.mod();