26 Commits
Author SHA1 Message Date
Steven RYDELL eda20cbe2f chore: release v1.1.3
Fix column sort headers so a third click clears the sort and restores
the list's default order.
2026-08-01 23:31:27 +02:00
Steven RYDELL 503cae465f feat(roles): add Enabled/Disabled Permissions count columns
New SCHEMA-DEVIATION: role-permission-count-columns — the Roles list
only shows Description, so seeing how broad or restrictive a role is
required opening it and counting permissions by hand.

Generalized DynamicList's existing alias-count handling (previously
hardcoded to the single `aliasCount` -> `aliases` mapping) into
COUNT_COLUMN_SOURCES, a table of synthetic "*Count" column names to the
real set/objectList property they count. account-alias-count-column
now runs through the same generic path with no behavior change;
role-permission-count-columns (enabledPermissionCount/
disabledPermissionCount -> enabledPermissions/disabledPermissions) is
the second consumer, added with zero new DynamicList.tsx branching.

Verified against the live dev server: correct counts for both seeded
custom roles (Support Agent: 3/0, Read-only Auditor: 1/0) and the
built-in roles (System Administrator: 452/0, User: 244/0, etc.).
Confirmed no regression on Accounts' existing Aliases column/sort.
2026-08-01 22:23:48 +02:00
Steven RYDELL 93b10c3ed1 refactor(sort): make client-side column sorting generic, not view-hardcoded
Previous commit hardcoded which lists (viewName === 'x:Account/User' /
'x:Account/Group') and columns (a fixed accessor map) got client-side
sort. Moved the "which columns" decision into the schema itself instead:

- New ClientSortableColumn type in schemaDeviationTypes.ts (intersection
  with the official Column type, same pattern as ClientOnlyFilterEnum —
  src/types/schema.ts stays untouched).
- withAccountListColumns tags Email Address, Full Name, quotaUsage, and
  aliasCount with clientSortable: true when it builds the Accounts/
  Groups column lists — the deviation-specific knowledge lives where the
  columns themselves are defined.
- DynamicList reads that flag generically (clientSortableColumns, a
  useMemo over resolved.list.columns) with no viewName check at all.
  getClientSortValue() replaces the old per-list accessor map: real
  columns compare their own property directly, only the two synthetic
  columns need a value override.

Net effect for Accounts/Groups is unchanged (verified: sort indicators
still only on Email/Full Name/Usage/Aliases, ascending/descending still
works). Any other list can now opt into the same client-sort mechanism
by tagging a column clientSortable, without touching DynamicList.tsx.
2026-08-01 20:32:04 +02:00
Steven RYDELL 518ec4059a feat(accounts): add client-side column sorting to Accounts and Groups
Verified against a live server: x:Account/query rejects sort on every
property tried, including real ones like emailAddress, with
unsupportedSort — the schema's empty list.sort is accurate, this is a
systemic server gap, not something specific to this fork's synthetic
columns.

Added client-side sorting (SCHEMA-DEVIATION: account-client-sort) for
Email Address, Full Name, Usage/Quota, and Aliases on both lists,
reusing the fetch-all-then-sort-locally mechanism already established
for mailbox-client-hierarchy-sort: clicking a sortable header switches
that one query to an unpaginated fetch, sorts the results in memory by
the appropriate accessor (numeric for Usage/Aliases, string compare
otherwise), then paginates client-side. Role isn't included (not a
sortable scalar). Normal server-paginated lists are unaffected — this
only activates when a client-sortable column is actually clicked.

Verified end-to-end: sort indicators appear only on the intended
columns, clicking Email Address/Aliases correctly reorders rows and
toggles ascending/descending, Groups behaves the same as Accounts.
2026-08-01 20:23:42 +02:00
Steven RYDELL 3241dea5e4 feat(accounts): add Aliases count column to Accounts and Groups
Same pattern as the existing quotaUsage deviation: neither list's
schema exposes an alias count as a column, only the full `aliases`
objectList on the detail view. Added a synthetic `aliasCount` column
(SCHEMA-DEVIATION: account-alias-count-column, documented in
SCHEMA_DEVIATIONS.md) that DynamicList resolves by fetching the real
`aliases` property and counting its entries.

Verified against a live test server: adding a real alias to an
account correctly bumps its Aliases count from 0 to 1 in the list.
2026-08-01 20:18:01 +02:00
Steven RYDELL 0aa92c394c feat(accounts): add Usage/Quota column to Groups, show unlimited as ∞
Groups have real usedDiskQuota/quotas fields, same as Users, but the
Groups list schema doesn't expose usage as a column any more than the
Accounts list did — extend the existing account-quota-usage-column
deviation to x:Account/Group too (SCHEMA_DEVIATIONS.md updated).

The isAccountsList gate that resolved/rendered quotaUsage was hardcoded
to viewName === 'x:Account/User', so it silently no-oped for Groups.
Replaced with hasQuotaUsageColumn, derived from whether the resolved
list's own columns include the synthetic quotaUsage column — works for
any list withAccountListColumns patches, not just a hardcoded pair of
view names.

Also: "Unlimited" (no quota configured) now renders as "∞" instead of
the word, matching the size formatting style used elsewhere in the
column.
2026-08-01 20:02:10 +02:00
Steven RYDELL 40164a6652 feat(webapps): show and correctly set the active WebUI's resource URL
The "Active WebUI" card (Settings > Web Applications) only showed
description and __APP_VERSION__, never the resourceUrl it's actually
built from — add it as a linked "Source" row.

That card also turned out to be misleading in local dev: it reads the
x:Application record whose urlPrefix matches /admin or /account, and a
freshly bootstrapped server keeps Stalwart's seeded default there
("Stalwart Web Interface", pointing at stalwartlabs/webui's release),
regardless of what's actually being served — in dev that's this fork,
served directly by Vite, which never touches that record at all.

dev-server-init.sh/.ps1 now point that record's description and
resourceUrl at this fork's own release, so the card (now including the
visible Source URL) reflects what's actually running instead of
Stalwart's factory default.

Verified end-to-end against a fresh container with both scripts.
2026-08-01 19:17:44 +02:00
Steven RYDELL 101b24b361 fix(schema): track client-side schema deviations, restore schema.ts fidelity
src/types/schema.ts had drifted from the official schema contract: a
`clientOnly` field had been added to `FilterEnum` to support client-side
log filtering. Restored it to match upstream exactly and moved the
deviation-only type into a new intersection type in
src/lib/schemaDeviationTypes.ts instead.

Audited the codebase for every place the UI does something the official
schema doesn't support and tagged each with `// SCHEMA-DEVIATION: <id>`,
documented in the new SCHEMA_DEVIATIONS.md registry (what, why, and the
ideal server-side fix):

- log-client-filters: Level/Event filters on Log Entries, applied
  client-side because x:Log/query rejects them as JMAP filters.
- account-quota-usage-column: synthetic quotaUsage column on the
  Accounts list.
- mailbox-client-hierarchy-sort: full-fetch + client-side sort to
  reconstruct mailbox parent/child hierarchy.
- webapp-enabled-column-fallback: synthetic "Enabled" column label for
  x:Application when the schema list doesn't define one.

Other viewName/objectName special cases (x:OtpAuth, x:Expression,
x:Rate, x:Action, x:Trace, CustomComponent/*) were checked against
upstream and are pre-existing architecture, not fork deviations.
2026-08-01 17:54:08 +02:00
Steven RYDELL 0dec14c3f8 feat(accounts): highlight negative disk usage with recalculate hint 2026-07-30 19:54:46 +02:00
Steven RYDELL 1ab574a42a fix(ui): make admin lists usable on mobile viewports 2026-07-30 19:54:34 +02:00
Steven RYDELLandClaude Sonnet 5 7a96fa6786 feat: show mailbox hierarchy in the Mailboxes list
Fixes stalwartlabs/webui#16. Mailboxes had no visual indication of
parent/child relationships. Since a mailbox's parent can land on a
different server page than the mailbox itself, the Mailbox list now
always fetches the full set (like the existing client-filter path)
and orders it depth-first by parentId, then indents each row's name
with a corner connector proportional to its depth.

Verified against a live instance with a 3-level nested hierarchy
(Projects > Alpha > Docs) alongside the default flat mailboxes.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 17:27:48 +02:00
Steven RYDELLandClaude Sonnet 5 2ac3526da9 fix: refresh account-scoped lists when switching accounts
Switching accounts via the profile dropdown (TopBar) only updates
authStore.activeAccountId with no navigation, but DynamicList's fetch
effect depended on [viewName, sort, resolved?.list, appliedFilters] —
missing activeAccountId, and account resolution only happened through
a non-reactive getState() snapshot inside getAccountId(). So views
like Mailboxes, Calendars, or Sieve Scripts kept showing the previous
account's data until an unrelated viewName change (switching tabs)
incidentally re-ran the effect.

Reproduced and verified against a live Stalwart instance: a mailbox
list stayed on accountId "b" after switching to a group account "d"
in the dropdown, and only picked up "d" after navigating away and
back. Subscribing to activeAccountId reactively and adding it to the
effect's dependencies fixes the switch to apply immediately.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 17:05:12 +02:00
Steven RYDELLandClaude Sonnet 5 3dda6d1527 feat: show Role and Usage/Quota columns on the Accounts list
Created At is replaced with two columns that previously required
opening each account individually: Role (badge, resolved against
x:UserRoles specifically since the list's merged User/Group field
definitions otherwise resolve `roles` against the wrong object) and
Usage / Quota (usedDiskQuota vs quotas.maxDiskQuota, "Unlimited" when
no limit is set).

Also makes renderCellValue's generic 'object' case resolve variant
labels via schema.schemas, instead of only ever printing the raw
@type string.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 16:47:26 +02:00
Steven RYDELLandClaude Sonnet 5 3113e6309d feat: add rate-limited manual refresh button to Log Entries
Adds a Refresh button next to Filters, right-aligned, specific to the
Logs list. Guarded to one click per 5 seconds (button disabled and
re-enabled via a timer) to avoid hammering the server if left clicked
repeatedly.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 16:36:25 +02:00
Steven RYDELLandClaude Sonnet 5 21b183327c feat: add client-side Level/Event filters to Log Entries
The backend rejects `level`/`event` as x:Log/query filter conditions
(unsupportedFilter), even though both are already returned per row.
Since a real fix requires backend changes outside this repo, the two
filters are injected into the schema client-side (clientOnly flag) and
applied entirely in the browser: excluded from the JMAP filter sent to
the server, and used to narrow an eagerly-fetched, locally-paginated
result set instead.

Also makes large enum filters (Event has 634 values) render as a
searchable Combobox instead of a plain Select, generically for any
list with more than 15 enum options.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
2026-07-30 16:31:36 +02:00
Steven RYDELL bfdf8f4ba2 fix(web-applications): show Enabled column and active WebUI info card 2026-07-30 13:43:23 +02:00
Steven RYDELL 87cabf3886 Align x:Application list layout with Domains: Description first, Enabled second 2026-07-30 13:06:33 +02:00
Steven RYDELL aa48b90323 Show active WebUI column in x:Application list and active app info card 2026-07-30 13:03:05 +02:00
Steven RYDELL 40c04555b4 Remove the Web Applications version column and update action 2026-07-30 12:00:01 +02:00
Steven RYDELL 956212031a Clip table header background inside the rounded border 2026-07-29 07:24:58 +02:00
Steven RYDELL bd16e64e51 Show WebUI version and update action in the Web Applications list 2026-07-29 06:48:41 +02:00
Maurus Decimus 5eea77346a v1.0.6 2026-07-28 10:57:30 +02:00
Maurus Decimus e080a6e061 Properly serialize date filters when applying them to the list filter 2026-06-23 17:26:22 +02:00
Maurus Decimus dee0f7fbe3 Fix broken "Delivery History" link on OSS/Community editions 2026-05-01 09:03:02 +02:00
Maurus Decimus 35e0ef74b9 Fix array label properties display 2026-04-21 15:44:00 +02:00
Maurus Decimus 4470616775 Initial commit 2026-04-20 15:02:57 +02:00