0.1.109 — Inbox unsubscribe works offline + no 3s delay; Casdoor signin_url moved to org-themed page
Two follow-ups to user reports:
"The user should be able to unsubscribe the default course even in offline mode, if user unsubscribe, there should not be 3s delay for remove category."
"Fix the bug for casdoor sso, the final endpoint should be on https://auth.trance-0.com/login/notechondria. If env is wrong, fix that and tell me which var need updates."
1. Inbox row is now removable from the sidebar (offline + no delay)
Before: the Inbox category was hard-blocked in
_promptEditCategory — long-press / right-click on the Inbox
row showed an "Inbox is the default category. It cannot be
renamed or deleted." dialog with only an OK button. There was
no path to remove the Inbox at all, so users with a stale or
unwanted Inbox row had to wipe local data to get rid of it.
After (in editor_app/lib/core/category_actions.dart): the
Inbox dialog now offers a "Remove from sidebar" action
alongside Cancel. Tapping it routes through
_unsubscribeCategory immediately — no 3-second confirmation
delay (the action is fully recoverable: _ensureStarterWorkspace
reseeds the Inbox on the next editor launch).
_unsubscribeCategory itself was rewritten to work in any auth
state:
- Cloud + signed in — best-effort
widget.client.unsubscribeCourse(token, courseId). A failed call (401 stale session, 403 owned-row, network blip) is logged at warning and does not block the local removal. - Cloud + offline / no token — skip the server call entirely,
drop the row from
_courseslocally +_persistLocalCache(). - Local-only row — drop from
_localCourseslocally +persistLocalCourses(). No server call.
User intent ("get this off my sidebar") wins. The next online sync may re-surface a cloud row whose subscription wasn't actually dropped server-side; that's acceptable for now and clearer than failing the action when the cloud call fails.
The non-Inbox unsubscribe path (_promptEditCategory →
action == 'unsubscribe') also dropped the
_confirmWithDelay(...) second confirm — the user already
confirmed by tapping "Unsubscribe" in the edit dialog, and
unsubscribe is non-destructive (the category itself stays on
the server, only the sidebar row is dropped).
The 3-second delay stays in place for delete since that permanently destroys the row server-side and moves notes to the default category.
2. Casdoor signin_url now points at the org-themed login page
Before: CasdoorConfigApiView returned
{ "signin_url": "https://auth.trance-0.com/login/oauth/authorize" }
The frontend's launchOAuth('casdoor', intent: 'login') then
appended OAuth query params and redirected the user to the raw
OAuth authorization endpoint — a generic Casdoor consent screen.
After (in backend/creators/api.py,
CasdoorConfigApiView.get): signin_url is now derived from
the org name —
"signin_url": f"{endpoint}/login/{settings.CASDOOR_ORG_NAME}",
so for CASDOOR_ENDPOINT=https://auth.trance-0.com/ and
CASDOOR_ORG_NAME=notechondria, the redirect lands at
https://auth.trance-0.com/login/notechondria?client_id=...&...
— the branded Casdoor login page for the Notechondria
organization. Casdoor accepts the same OAuth params on this
URL as on /login/oauth/authorize, so the post-login callback
flow is unchanged.
Operator follow-up — Casdoor backend env vars
The user-supplied log shows the production backend at
notechondria.trance-0.com is still 404'ing on
/api/v1/auth/casdoor/config/. That route was added in
0.1.96; the 404 means the deployed image predates that release.
A backend redeploy is required to pick up both the route and
this round's signin_url change.
backend/notechondria/settings.py:477-485 reads six env vars.
All six must be set in the Northflank service env (or linked
Secret Group) for /auth/casdoor/config/ to return
{configured: true, ...}:
| Env var | Value (per sample.northflank.env) |
|---|---|
CASDOOR_ENDPOINT | https://auth.trance-0.com/ |
CASDOOR_CLIENT_ID | (Casdoor app's Client ID — d24d31a88e52e81733aa per the sample) |
CASDOOR_CLIENT_SECRET | (Casdoor app's Client Secret) |
CASDOOR_ORG_NAME | notechondria |
CASDOOR_APP_NAME | notechondria |
CASDOOR_CERTIFICATE | (Public-key PEM from the Casdoor app's Cert tab; single-line, literal \n in place of newlines) |
After the redeploy:
curl -sS https://notechondria.trance-0.com/api/v1/auth/casdoor/config/should return JSON withconfigured: trueand asignin_urlending in/login/notechondria.- The frontend's boot-time probe will succeed, and clicking
"Continue with Casdoor" will redirect to
https://auth.trance-0.com/login/notechondriawith the appended OAuth params.
If the redeploy is blocked, the Casdoor button still renders (0.1.108 made it always-visible) and clicking it produces a debug-log warning instead of a redirect — non-fatal, just inert until the backend catches up.
Files changed
frontend/editor_app/lib/core/category_actions.dart_promptEditCategory: Inbox path now confirms + removes instead of blocking._unsubscribeCategory: works in any auth state; cloud failure is logged but doesn't block local removal.action == 'unsubscribe'handler: dropped the 3-second_confirmWithDelaycall.
backend/creators/api.pyCasdoorConfigApiView.get:signin_urlnow uses/login/<org>instead of/login/oauth/authorize.
Verification
flutter analyzeclean foreditor_app(only pre-existing info-level lints remain).- Backend file edited only inside
CasdoorConfigApiView.get; no migration impact, no URL routing changes.