Skip to content

feat(computers): rack overview filter/sort/group logic (web parity, step 1 of #60) - #4540

Open
stamp-build[bot] wants to merge 1 commit into
mainfrom
agent/lagoon/computers-rack-logic
Open

stamp-build[bot] wants to merge 1 commit into
mainfrom
agent/lagoon/computers-rack-logic

Conversation

@stamp-build

@stamp-build stamp-build Bot commented Nov 10, 2026

Copy link
Copy Markdown
Contributor

Lagoon from raft opened this pull request through Stamp
View in Stamp →


Step 1 of #proj-mobile:#60 (Computers rack overview, web parity, 1.24): the web's toolbar logic is ported into compose/shared as pure, tested code. The UI does not change. The toolbar, list body and strings are steps 2 and 3. There is no changeset because nothing user-visible ships in this PR; the UI PR will add it.

Web source of truth: botiverse/slock origin/staging @ fabcd51b4. This is newer than the spec's 194e5d3; see the spec gaps below. Paths are relative to packages/web/src/.

What's added

  • RaftComputersRackFilters.kt (next to RaftSettingsComputersModel.kt): the pure functions, the toolbar state and RaftComputersRackToolbarStore.
  • data/ComputersRackPreferences.kt: the ComputersRackGroupBy and ComputersRackSort* types, plus KeyValueComputersRackPreferenceRepository over SharedPreferenceStore. It stores Group (computers:rackGroup) and Sort (computers:rackSort, the web's JSON shape). View is delegated to the existing KeyValueComputersRackViewPreferenceRepository (computers:rackView).
  • hostProvider (nullable) is carried through ComputerDto → ComputerSummary → SettingsComputerSnapshot and the durable cache. The field name was checked against packages/server/src/services/machineReadModel.ts:163 (hostProvider: isHostProvider(machine.hostProvider) ? machine.hostProvider : null), packages/server/src/db/schema.ts:6481 (host_provider) and packages/shared/src/index.ts:2038-2056 (HOST_PROVIDER_LABELS, isHostProvider).

Rules → web reference

Rule Web Kotlin
Search: trimmed, case-insensitive, over name, hostname, owner display name or name (only while ownerUserId is set), and owner.name features/computer/computersRackFilter.ts:55-73 raftFilterRackComputers
Status: All / Online / Offline (anything not online) / Needs attention (upgrade waiting; a Computer that is not online; online with low disk) computersRackFilter.ts:43-47,74-76, utils/computerUpgradeIndicator.ts getComputerAttentionStatus raftRackNeedsAttention
Runtime: any chosen runtime; Other = a runtime with no usage provider; options = providers present (catalog order), then Other; a choice whose computers have gone filters nothing; picking prunes it and keeps the options' order computersRackFilter.ts:22-40,49-53,77-80, features/computer/ComputersRackToolbar.tsx:118-156 raftRackRuntimeFilterOptions, raftRackEffectiveRuntimeFilter, toggleRuntime
Group options: none, prefix, provider store/computersRackFilterPreference.ts:22 ComputersRackGroupBy
Name prefix: longest shared word prefix (split on - _ .), case-insensitive, lone groups fold up or go to Other, title = most common spelling computersRackFilter.ts:85-169 raftRackNamePrefixGroups
Provider: HOST_PROVIDER_LABELS; unknown or none goes to Personal computers computersRackFilter.ts:187-197 RAFT_HOST_PROVIDER_LABELS
Group order: fallback last; under a numeric sort, by best member; otherwise A to Z computersRackFilter.ts:206-239, features/computer/ComputersRackList.tsx:124-137 raftGroupRackComputers, raftRackGroupRank
Sort keys: Name, remaining:<provider> for each provider present, Disk, Memory; default Name A to Z; a new key starts at its first direction (name asc, numbers desc); no value goes last both ways; ties keep the list order; a stored runtime sort whose runtime is gone falls back to the default features/computer/computersRackSort.ts:19-121, features/computer/computersRackToolbarModel.ts:68-85, ComputersRackToolbar.tsx:58-61,196-248 raftSortRackComputers, raftRackEffectiveSort, raftRackSortMenuSections, raftRackSortDirectionCopy
Remaining: the tightest window of the tightest account; rate_limited = 0; reauth / unsupported / error = no value; limit_reached with no ratio = fully used computersRackSort.ts:49-75 raftRackRemaining
Offline section at the end; none under Status: Offline; open by default when nothing else is online ComputersRackList.tsx:102-123 raftComputersRackLayout
Clear all resets search, Status and Runtime, never Group, Sort or View; it shows while any of those three is active store/computersRackFilterPreference.ts:55-57,66-68,81-83 clearedFilters, RaftComputersRackFilters.active
Search, Status and Runtime are session-only and reset on another server; Group, Sort and View are stored; an unreadable stored value reads as the default store/computersRackFilterPreference.ts:35-51,71-78, store/computersRackSortPreference.ts:30-47, store/computersRackViewPreference.ts RaftComputersRackToolbarStore.onServer, KeyValueComputersRackPreferenceRepository

Tests (35 new, all commonTest)

  • RaftComputersRackFiltersTest (30) mirrors features/computer/tests/computersRackFilter.behavior.test.ts (all 14 tests: same fleets, same name-prefix table, same 20-seed order-independence shuffle, same remaining cases), plus the row-order expectations of computersRackSort.behavior.test.tsx and computersRackToolbar.behavior.test.tsx: search, Status, Runtime, Group, every sort key in both directions, provider groups under a remaining sort, a stale runtime choice, Clear all, server change, persistence, and the sort sheet's key/direction steps. The cases are tables, not copied tests.
  • ComputersRackPreferencesTest (4): the Group and Sort round trips (every key × direction), unreadable stored values, and View sharing the existing key.
  • ComputersApiTest.hostProviderMapsFromTheMachineReadModelAndIsNullWhenAbsent (1).
  • Existing suites rerun and green: ComputersApiTest, LocalPreferencesTest, RaftComputersRackModelTest, SharedComputersCacheFirstTest.

Spec vs web differences (followed the web)

  1. Name-prefix grouping changed after the spec's commit. The spec (B4) says "strips -N/_N, a group needs 2+ members". Staging (#14042, 77ba471b5) groups by the longest shared word prefix instead: it splits on - _ ., compares case-insensitively, and folds lone groups up (for example, artin-hostinger-root pulls artin-fluence-* into artin). The spec's line range computersRackFilter.ts:85-166 is now :85-239.
  2. Search also matches owner.name when the Computer has no owner. Web filterRackMachines adds machine.owner?.name even when ownerUserId is null. Only the display name requires an owner.
  3. "Needs attention" for offline machines applies only to Computers (isComputer). An offline bare daemon is not counted. A machine whose status is unknown counts as offline.
  4. Picking the current sort key again changes nothing in the Sort select. The desktop ⋯ menu instead resets the direction. The phone sheet follows the select.
  5. Collation. The web uses Intl.Collator(locale, {numeric, sensitivity: "base"}). Common Kotlin has no collator, so raftRackCompareText approximates it: numeric runs, case and common Latin accents ignored, punctuation < digits < letters. There is no locale tailoring, so zh pinyin order for Han names falls back to code point order.
  6. Naming and test files. The spec's B8 store name is SharedComputersRackToolbarStore; the code uses RaftComputersRackToolbarStore. The spec points to the toolbar and sort behaviour tests, but most of the logic tests are in computersRackFilter.behavior.test.ts, which this PR mirrors in full.
  7. Web store lifetime is the page/tab; the mobile store is meant to be one per app session. Its owner is wired in step 2.

🤖 Generated with Claude Code

…tep 1 of #60)

Port the web Computers rack toolbar logic into shared as pure code:
search, Status and Runtime filters, Group (none / name prefix / provider)
with its group order, Sort (name, runtime remaining, disk, memory) with
its tie-breakers, Clear all, and the Offline section split. Group, Sort
and View persist through a shared repository over SharedPreferenceStore;
search, Status and Runtime are session-only and reset on another server.
Decode the machine row's nullable hostProvider. No UI changes.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0 participants