From 7ff13abbb6b604e00a2aef3901b11503ac566ea3 Mon Sep 17 00:00:00 2001 From: Botanist1866 Date: Mon, 23 Mar 2026 22:39:39 +0100 Subject: [PATCH 1/9] Add 'seen' sorting and filtering to character list --- README.md | 4 ++-- .../character-filter/TooltipCharacterFilter.svelte | 5 +++++ .../settings/sections/views/Sorting.svelte | 1 + .../utils/characters/use-character-filter.ts | 13 +++++++++++++ apps/frontend/utils/get-character-sort-func.ts | 2 ++ 5 files changed, 23 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1c1b1b110..329d658aa 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ any help with getting started, I'm available most days. 1. Install Docker and Docker Compose - [Windows install instructions](https://docs.docker.com/docker-for-windows/install/) -1. Install the dotnet SDK, currently 8.x +1. Install the dotnet SDK, currently 9.x 1. Log in or sign up for a [Battle.Net Developer](https://develop.battle.net) account @@ -119,7 +119,7 @@ any help with getting started, I'm available most days. 1. Start the initial data import/build, this will take a while: ```bash - cd app/tool/ + cd apps/tool/ dotnet run all ``` diff --git a/apps/frontend/components/tooltips/character-filter/TooltipCharacterFilter.svelte b/apps/frontend/components/tooltips/character-filter/TooltipCharacterFilter.svelte index 30c37b930..f173eeb87 100644 --- a/apps/frontend/components/tooltips/character-filter/TooltipCharacterFilter.svelte +++ b/apps/frontend/components/tooltips/character-filter/TooltipCharacterFilter.svelte @@ -48,6 +48,11 @@ level=60 | <=,<,=,>,>= +
Last seen (days)
+
+ seen<=7 | <=,<,=,>,>= +
+
Item Level
ilevel>=400 | <=,<,=,>,>= diff --git a/apps/frontend/user-home/components/settings/sections/views/Sorting.svelte b/apps/frontend/user-home/components/settings/sections/views/Sorting.svelte index 221d20921..1143caed4 100644 --- a/apps/frontend/user-home/components/settings/sections/views/Sorting.svelte +++ b/apps/frontend/user-home/components/settings/sections/views/Sorting.svelte @@ -23,6 +23,7 @@ { id: 'gold', name: 'Gold' }, { id: 'itemlevel', name: 'Item level' }, { id: 'level', name: 'Level' }, + { id: 'seen', name: 'Last seen' }, ]; let sortByChoices: SettingsChoice[] = $derived([ diff --git a/apps/frontend/utils/characters/use-character-filter.ts b/apps/frontend/utils/characters/use-character-filter.ts index 45172aff8..f9566ddd4 100644 --- a/apps/frontend/utils/characters/use-character-filter.ts +++ b/apps/frontend/utils/characters/use-character-filter.ts @@ -61,6 +61,19 @@ export function useCharacterFilter( ); } + // Last seen (in days) + match = part.match(/^seen(<|<=|=|>=|>)(\d+)$/); + if (match) { + const now = Math.floor(Date.now() / 1000); + const days = parseInt(match[2]); + const diff = (now - char.lastSeenAddonUnix) / 86400; + return compareValues( + match[1].toString(), + diff, + days + ); + } + // Item level match = part.match(/^(itemlevel|ilevel|ilvl)(<|<=|=|>=|>)(\d+)$/); if (match) { diff --git a/apps/frontend/utils/get-character-sort-func.ts b/apps/frontend/utils/get-character-sort-func.ts index 8346887e8..a61823aac 100644 --- a/apps/frontend/utils/get-character-sort-func.ts +++ b/apps/frontend/utils/get-character-sort-func.ts @@ -86,6 +86,8 @@ export const getCharacterSortFunc = (prefixFunc?: SortValueFunction, viewSortBy? '0' ) ); + } else if (thing === 'seen') { + out.push(leftPad(2000000000 - char.lastSeenAddonUnix, 10, '0')); } else if (thing === 'level') { // in descending order const levelData = getCharacterLevel(char); From a970ca1ad2f1d48bffd0e9068fad938d8acc1ba6 Mon Sep 17 00:00:00 2001 From: Freddie Date: Sat, 28 Mar 2026 14:45:56 -0700 Subject: [PATCH 2/9] Set visible characters as context in CharacterTable --- .../components/character-table/CharacterTable.svelte | 4 ++++ apps/frontend/components/character-table/context.ts | 9 +++++++++ 2 files changed, 13 insertions(+) create mode 100644 apps/frontend/components/character-table/context.ts diff --git a/apps/frontend/components/character-table/CharacterTable.svelte b/apps/frontend/components/character-table/CharacterTable.svelte index 1371fd753..dc8dd5847 100644 --- a/apps/frontend/components/character-table/CharacterTable.svelte +++ b/apps/frontend/components/character-table/CharacterTable.svelte @@ -3,6 +3,8 @@ import sortBy from 'lodash/sortBy'; import { router } from 'svelte-spa-router'; + import { setCharacterTableContext } from './context'; + import { ContextKey } from '@/enums/context-key'; import { browserState } from '@/shared/state/browser.svelte'; import { settingsState } from '@/shared/state/settings.svelte'; import { newNavState } from '@/stores/local-storage'; @@ -115,6 +117,8 @@ return [characters, groups]; }); + setCharacterTableContext(() => ({ characters })); + const paddingMap: Record = { small: 1, medium: 2, diff --git a/apps/frontend/components/character-table/context.ts b/apps/frontend/components/character-table/context.ts new file mode 100644 index 000000000..ea0696d4d --- /dev/null +++ b/apps/frontend/components/character-table/context.ts @@ -0,0 +1,9 @@ +import { createContext } from 'svelte'; +import type { Character } from '@/types/character/character.svelte'; + +interface CharacterTableContext { + characters: Character[]; +} + +export const [getCharacterTableContext, setCharacterTableContext] = + createContext<() => CharacterTableContext>(); From 5aee3510fdaf92d83e3330f500d348a3361140c6 Mon Sep 17 00:00:00 2001 From: Freddie Date: Sat, 28 Mar 2026 14:46:05 -0700 Subject: [PATCH 3/9] Add derived profession data to character --- .../types/character/character.svelte.ts | 40 ++++++++++++++++++- 1 file changed, 38 insertions(+), 2 deletions(-) diff --git a/apps/frontend/types/character/character.svelte.ts b/apps/frontend/types/character/character.svelte.ts index 526cadc06..6e746d663 100644 --- a/apps/frontend/types/character/character.svelte.ts +++ b/apps/frontend/types/character/character.svelte.ts @@ -28,7 +28,7 @@ import { getNumberKeyedEntries } from '@/utils/get-number-keyed-entries'; import { initializeContainsItems } from '@/utils/items/initialize-contains-items'; import { getDungeonScores } from '@/utils/mythic-plus'; import type { Region } from '@/enums/region'; -import type { StaticDataRealm } from '@/shared/stores/static/types'; +import type { StaticDataProfession, StaticDataRealm } from '@/shared/stores/static/types'; import type { Guild } from '@/types/guild'; import type { CharacterConfiguration } from './configuration'; @@ -46,7 +46,11 @@ import { type CharacterMythicPlusAddonMapArray, type CharacterMythicPlusAddonRunArray, } from './mythic-plus'; -import { CharacterProfession, type CharacterProfessionRaw } from './profession.svelte'; +import { + CharacterProfession, + CharacterSubProfession, + type CharacterProfessionRaw, +} from './profession.svelte'; import type { CharacterRaiderIoSeason } from './raider-io-season'; import type { CharacterReputation, @@ -72,6 +76,8 @@ import type { CharacterAura } from './aura'; import type { CharacterPatronOrder } from './patron-order'; import type { CharacterMovementSpeed } from './movement-speed'; import type { CharacterQuests } from '@/user-home/state/user/types'; +import { ProfessionType } from '@/enums/profession-type'; +import { getProfessionSortKey } from '@/utils/professions/get-profession-sort-key'; export class Character implements ContainsItems, HasNameAndRealm { // Static @@ -622,6 +628,36 @@ export class Character implements ContainsItems, HasNameAndRealm { return this.specializations[this.activeSpecId]?.find((loadout) => loadout.active); }); + public professionData = $derived.by(() => { + const ret: [StaticDataProfession, CharacterSubProfession, boolean][] = []; + + for (const staticProfession of wowthingData.static.professionById.values()) { + if (staticProfession?.type !== ProfessionType.Primary) { + continue; + } + + let best: [CharacterSubProfession, number]; + for (const expansion of settingsState.expansions) { + const subProfession = staticProfession.expansionSubProfession[expansion.id]; + if (subProfession) { + const characterSubProfession = + this.professions[staticProfession.id]?.subProfessions?.[subProfession.id]; + if (characterSubProfession && expansion.id >= (best?.[1] || 0)) { + best = [characterSubProfession, expansion.id]; + } + } + } + + if (best) { + ret.push([staticProfession, best[0], best[1] === Constants.expansion]); + } + } + + ret.sort((a, b) => getProfessionSortKey(a[0]).localeCompare(getProfessionSortKey(b[0]))); + + return ret; + }); + public allProfessionAbilities = $derived.by(() => { const allKnown = new Set(); for (const profession of Object.values(this.professions)) { From 278b504bb5eee36a8175f0d87f21c1b187faff94 Mon Sep 17 00:00:00 2001 From: Freddie Date: Sat, 28 Mar 2026 14:46:33 -0700 Subject: [PATCH 4/9] Only show concentration/moxie if any visible character has a relevant profession --- .../row/HomeTableRowProfessionsV2.svelte | 62 ++++++++----------- 1 file changed, 26 insertions(+), 36 deletions(-) diff --git a/apps/frontend/components/home/table/row/HomeTableRowProfessionsV2.svelte b/apps/frontend/components/home/table/row/HomeTableRowProfessionsV2.svelte index fd056ef30..d0667d9e3 100644 --- a/apps/frontend/components/home/table/row/HomeTableRowProfessionsV2.svelte +++ b/apps/frontend/components/home/table/row/HomeTableRowProfessionsV2.svelte @@ -1,18 +1,17 @@