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.
This commit is contained in:
+9
-4
@@ -55,10 +55,15 @@ bash ./scripts/dev-server-init.sh
|
|||||||
|
|
||||||
This completes the bootstrap wizard (default domain `example.org`, no TLS
|
This completes the bootstrap wizard (default domain `example.org`, no TLS
|
||||||
certificate request — safe for local/offline use), creates a real
|
certificate request — safe for local/offline use), creates a real
|
||||||
`devadmin@example.org` admin account, and sets the server's default OAuth
|
`devadmin@example.org` admin account, sets the server's default OAuth
|
||||||
access token lifetime to 3 hours. It's idempotent — safe to re-run, it
|
access token lifetime to 3 hours, and points the `x:Application` record
|
||||||
no-ops once the server is already bootstrapped. You only need to re-run it
|
serving `/admin`/`/account` at this fork's description and release URL
|
||||||
after `docker compose down -v` (which wipes the volumes).
|
(cosmetic — otherwise Settings > Web Applications' "Active WebUI" card
|
||||||
|
shows Stalwart's default "Stalwart Web Interface" / upstream release URL,
|
||||||
|
even though what's actually running is this fork served by Vite). It's
|
||||||
|
idempotent — safe to re-run, it no-ops once the server is already
|
||||||
|
bootstrapped. You only need to re-run it after `docker compose down -v`
|
||||||
|
(which wipes the volumes).
|
||||||
|
|
||||||
## 3. Get an access token
|
## 3. Get an access token
|
||||||
|
|
||||||
|
|||||||
@@ -119,4 +119,29 @@ try {
|
|||||||
} | Out-Null
|
} | Out-Null
|
||||||
} catch {}
|
} catch {}
|
||||||
|
|
||||||
|
# Cosmetic only: Stalwart seeds a default "Stalwart Web Interface" /
|
||||||
|
# stalwartlabs/webui entry for the x:Application record serving /admin and
|
||||||
|
# /account (see Settings > Web Applications' "Active WebUI" card). Point it
|
||||||
|
# at this fork so that card isn't misleading in local dev too.
|
||||||
|
Write-Host "Pointing the active WebUI's description at this fork..."
|
||||||
|
try {
|
||||||
|
$appResult = Invoke-Jmap @{
|
||||||
|
using = @("urn:ietf:params:jmap:core", "urn:stalwart:jmap")
|
||||||
|
methodCalls = @(, @("x:Application/query", @{ accountId = $accountId }, "0"))
|
||||||
|
}
|
||||||
|
$appId = $appResult.methodResponses[0][1].ids[0]
|
||||||
|
if ($appId) {
|
||||||
|
Invoke-Jmap @{
|
||||||
|
using = @("urn:ietf:params:jmap:core", "urn:stalwart:jmap")
|
||||||
|
methodCalls = @(, @("x:Application/set", @{
|
||||||
|
accountId = $accountId
|
||||||
|
update = @{ $appId = @{
|
||||||
|
description = "Stalwart WebUI Fork"
|
||||||
|
resourceUrl = "https://github.com/LinkPhoenix/stalwart-webui-fork/releases/latest/download/webui.zip"
|
||||||
|
} }
|
||||||
|
}, "0"))
|
||||||
|
} | Out-Null
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
|
||||||
Write-Host "Done. $DevAdminName@$DevDomain / $DevAdminSecret is ready - run scripts/dev-token.ps1 to get a token."
|
Write-Host "Done. $DevAdminName@$DevDomain / $DevAdminSecret is ready - run scripts/dev-token.ps1 to get a token."
|
||||||
|
|||||||
@@ -61,5 +61,16 @@ else
|
|||||||
jmap "{\"using\":[\"urn:ietf:params:jmap:core\",\"urn:stalwart:jmap\"],\"methodCalls\":[[\"x:OidcProvider/set\",{\"accountId\":\"$ACCOUNT_ID\",\"update\":{\"singleton\":{\"accessTokenExpiry\":$DEFAULT_TOKEN_EXPIRY_MS}}},\"0\"]]}" > /dev/null
|
jmap "{\"using\":[\"urn:ietf:params:jmap:core\",\"urn:stalwart:jmap\"],\"methodCalls\":[[\"x:OidcProvider/set\",{\"accountId\":\"$ACCOUNT_ID\",\"update\":{\"singleton\":{\"accessTokenExpiry\":$DEFAULT_TOKEN_EXPIRY_MS}}},\"0\"]]}" > /dev/null
|
||||||
jmap "{\"using\":[\"urn:ietf:params:jmap:core\",\"urn:stalwart:jmap\"],\"methodCalls\":[[\"x:Action/set\",{\"accountId\":\"$ACCOUNT_ID\",\"create\":{\"a1\":{\"@type\":\"ReloadSettings\"}}},\"0\"]]}" > /dev/null 2>&1 || true
|
jmap "{\"using\":[\"urn:ietf:params:jmap:core\",\"urn:stalwart:jmap\"],\"methodCalls\":[[\"x:Action/set\",{\"accountId\":\"$ACCOUNT_ID\",\"create\":{\"a1\":{\"@type\":\"ReloadSettings\"}}},\"0\"]]}" > /dev/null 2>&1 || true
|
||||||
|
|
||||||
|
# Cosmetic only: Stalwart seeds a default "Stalwart Web Interface" /
|
||||||
|
# stalwartlabs/webui entry for the x:Application record serving /admin
|
||||||
|
# and /account (see Settings > Web Applications' "Active WebUI" card).
|
||||||
|
# Point it at this fork so that card isn't misleading in local dev too.
|
||||||
|
echo "Pointing the active WebUI's description at this fork..."
|
||||||
|
APP_RESULT=$(jmap "{\"using\":[\"urn:ietf:params:jmap:core\",\"urn:stalwart:jmap\"],\"methodCalls\":[[\"x:Application/query\",{\"accountId\":\"$ACCOUNT_ID\"},\"0\"]]}") || true
|
||||||
|
APP_ID=$(printf '%s' "$APP_RESULT" | grep -o '"ids":\["[^"]*"' | cut -d'"' -f4)
|
||||||
|
if [ -n "$APP_ID" ]; then
|
||||||
|
jmap "{\"using\":[\"urn:ietf:params:jmap:core\",\"urn:stalwart:jmap\"],\"methodCalls\":[[\"x:Application/set\",{\"accountId\":\"$ACCOUNT_ID\",\"update\":{\"$APP_ID\":{\"description\":\"Stalwart WebUI Fork\",\"resourceUrl\":\"https://github.com/LinkPhoenix/stalwart-webui-fork/releases/latest/download/webui.zip\"}}},\"0\"]]}" > /dev/null 2>&1 || true
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Done. devadmin@$DEV_DOMAIN / $DEVADMIN_SECRET is ready — run scripts/dev-token.sh to get a token."
|
echo "Done. devadmin@$DEV_DOMAIN / $DEVADMIN_SECRET is ready — run scripts/dev-token.sh to get a token."
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -590,7 +590,7 @@ export function DynamicList({ viewName }: DynamicListProps) {
|
|||||||
objectName ?? 'x:Application',
|
objectName ?? 'x:Application',
|
||||||
accountId,
|
accountId,
|
||||||
{},
|
{},
|
||||||
['id', 'description', 'enabled', 'urlPrefix'],
|
['id', 'description', 'enabled', 'urlPrefix', 'resourceUrl'],
|
||||||
);
|
);
|
||||||
if (cancelled) return;
|
if (cancelled) return;
|
||||||
const active = result.list.find((item) => isActiveWebApplication(item));
|
const active = result.list.find((item) => isActiveWebApplication(item));
|
||||||
@@ -1573,6 +1573,19 @@ export function DynamicList({ viewName }: DynamicListProps) {
|
|||||||
<span className="text-muted-foreground">{t('webApplications.version', 'Version')}:</span>
|
<span className="text-muted-foreground">{t('webApplications.version', 'Version')}:</span>
|
||||||
<Badge variant="secondary">{__APP_VERSION__}</Badge>
|
<Badge variant="secondary">{__APP_VERSION__}</Badge>
|
||||||
</div>
|
</div>
|
||||||
|
{typeof activeWebApp.resourceUrl === 'string' && activeWebApp.resourceUrl && (
|
||||||
|
<div className="flex items-start gap-2 text-sm">
|
||||||
|
<span className="shrink-0 text-muted-foreground">{t('webApplications.resourceUrl', 'Source')}:</span>
|
||||||
|
<a
|
||||||
|
href={activeWebApp.resourceUrl}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
className="break-all text-primary hover:underline"
|
||||||
|
>
|
||||||
|
{activeWebApp.resourceUrl}
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</CardContent>
|
</CardContent>
|
||||||
</Card>
|
</Card>
|
||||||
)}
|
)}
|
||||||
|
|||||||
Reference in New Issue
Block a user