Skip to content

feat(signup): Angular version of signup page using existing backend.#1827

Open
gtandersen wants to merge 39 commits into
runbox:masterfrom
gtandersen:geir/signup-screen
Open

feat(signup): Angular version of signup page using existing backend.#1827
gtandersen wants to merge 39 commits into
runbox:masterfrom
gtandersen:geir/signup-screen

Conversation

@gtandersen
Copy link
Copy Markdown
Contributor

@gtandersen gtandersen commented May 5, 2026

This is an AI assisted attempt at upgrading the Runbox 6 signup screen to Runbox 7 in Angular without modifying the backend except for Apache rewriting. Fixes #1354.

Summary
Runbox 7 signup has been implemented as a new Angular route and is now functionally working against the existing signup backend. The page is live in the test environment, visually modernized, responsive, and compatible with the current Apache/nginx routing setup.

Runbox 7 signup page

What Has Been Delivered

  • New Angular signup screen at /app/signup
  • Compatibility with existing legacy signup processing
  • Apache rewrite support for /signup -> /app/signup
  • Deep-link compatibility for Angular routing under /app
  • Responsive layout for desktop, tablet, and mobile
  • Updated UI aligned with Runbox 7 visual style
  • Inline form validation feedback
  • hCaptcha integration
  • Dynamic loading of:
    • signup form action
    • hCaptcha site key
    • Runbox domain list

How It Works
The Angular page does not yet use a dedicated signup metadata API. Instead, it fetches the existing legacy signup page and parses it to obtain:

  • form action
  • available Runbox domains
  • hCaptcha site key

Form submission is then handed off to the existing backend signup flow using the same field names and POST behavior expected by the legacy system.

Backend Impact
No new signup backend business logic was required.

However, this implementation does depend on the existing backend providing:

  • reachable legacy signup HTML
  • stable legacy form markup
  • working hCaptcha/backend services

So this is not purely frontend-only in operational terms, even though no new signup processing code was added.

Testing Status
Implemented:

  • unit test coverage for signup component behavior
  • Cypress smoke coverage for deployed page behavior/content
  • reusable Firefox-based signup unit test command

Unit test coverage now includes:

  • legacy metadata loading
  • query-param initialization
  • metadata fetch fallback behavior
  • field-level validation behavior
  • invalid custom domain handling
  • CAPTCHA-gated submission
  • successful native submit path

What has been validated:

  • targeted Firefox unit test passes in headless server setup
  • live manual testing confirms page rendering and successful signup flow

What is still environment-dependent:

  • Cypress against gw01test can only run from a machine that can actually reach that hostname
  • full project CI-equivalent verification still depends on running:
    • npm run lint
    • npm run policy
    • broader CI/test phases as needed

Current Risks / Technical Debt
Main technical debt:

  • frontend currently parses legacy HTML for signup metadata instead of consuming a dedicated JSON endpoint

Risks:

  • coupling to legacy markup structure
  • template changes can break metadata extraction
  • harder contract testing than a formal API

This is acceptable for staging, but not ideal as the long-term architecture.

Recommendation
Proceed with staging now.

Reason:

  • flow is working
  • frontend integration is in place
  • backend scope was minimized
  • remaining risk is architectural cleanliness, not immediate functionality

Recommended next phase after staging:

  1. validate staging behavior thoroughly
  2. add dedicated REST/JSON signup metadata endpoint
  3. switch Angular signup from HTML parsing to JSON
  4. keep legacy signup processing in place until full backend modernization is justified

Suggested Staging Validation

  • account creation success path
  • backend validation failure path
  • CAPTCHA expiration/error handling
  • all Runbox domain options
  • /signup, /app/signup, and deep-link routing behavior
  • mobile/tablet browser validation
  • smoke test execution from a reachable client host

piratefinn and others added 28 commits April 1, 2026 15:15
Add Cypress E2E tests covering floating time, UTC, TZID, all-day,
recurring, and citadel-path TZID event imports. Add mockserver
endpoint for ICS calendar import and event reset for test isolation.
ICS properties use semicolons before parameters (DTSTART;TZID=Europe/Oslo:...)
not colons. The previous DTSTART:TZID=... format caused the parser to treat
the entire TZID string as the property value, breaking TZID, VALUE=DATE,
and citadel-path tests.
…ezone flakiness

moment.toISOString() produces strings with milliseconds (e.g.
"2026-04-02T14:30:00.000Z"), which causes ICAL.js to miss the 'Z' UTC
designator at index 19 (it finds '.' instead). This makes ICAL.js treat
the time as floating/local rather than UTC, leading to different code
paths in convertIcalTimeToDate on UTC CI systems versus local machines.

Introduce toIcalISOString() helper that formats without milliseconds and
apply it to simpleEvents and recurringEvents test data.
…wser tz

Fix event times displaying incorrectly when account timezone differs from
browser timezone. The root cause was momentToIcalTime assigning account tz
to browser-local hours then converting, causing double-conversion when
browser tz != account tz. Now constructs ICAL.Time from UTC fields and
converts to target zone, avoiding the double-conversion.

- Rewrite momentToIcalTime to go through UTC instead of browser-local
- Fix month view template to use Angular date pipe instead of getHours()
- Add null safety for timezone lookups and ICAL.Recur access
- Extract getRecur() and getAccountTimezone() helpers to reduce duplication
- Add E2E tests for London TZID, floating time, and timezone change bugs
- Add unit tests for round-trip time, exception storage, and tz change
- Extract ICS test helpers into shared support module
- Add mockserver timezone fixture endpoints for E2E testing
Tests were hardcoding expected display times (12:00, 14:00) that only
matched BST (UTC+1) browsers. CI runs in UTC causing failures.
Added expectedDisplayTime() helper that computes what the Angular date
pipe would display for a given UTC time in the browser's actual timezone.
… write path

Three timezone-related bugs fixed in runbox-calendar-event.ts:

1. All-day events displayed one day earlier because toJSDate() shifted
   midnight UTC+offset to previous-day UTC. Fix: return noon UTC date
   in convertIcalTimeToDate() for isDate=true.

2. Citadel-path TZIDs (/citadel.org/.../Europe/Oslo) caused wrong display
   hour because moment-timezone couldn't resolve them. Fix: extract IANA
   name from path-style TZIDs in resolveTimezoneName() helper.

3. Multi-day all-day events stored wrong end date because momentToIcalTime()
   used UTC date parts for new events. Fix: use local date parts for all-day
   events and set zone to account timezone.

Also consolidates e2e timezone tests into calendar-timezone.ts, fixes
fragile getHours mock and day-cell selector ambiguity.
- Add navigateToEventMonth to prevent E2E flakiness at month boundaries
- Fix ensureTimezone helper indentation in spec file
- Add cross-reference comment on all-day end getter duplication
- Replace undefined with typed values in test calls
- Add negative-offset timezone unit test (America/New_York)
- Add dateStrDay helper for consistent date string parsing
- Override CSS visibility for add-event button in E2E dialog test
- Use input[matInput] selector for dialog title field
…matting

- Remove unused win parameter from navigateToEventMonth
- Reuse dateStrYear/Month/Day in expectedDisplayTime
- Fix ensureTimezone negative offset formatting (-0500 not +-500)
- Remove redundant narrating comments in E2E tests
The PUT handler assigned bare IDs like "mock-event-1" while the import
handler uses "calendarId/eventId". When RunboxCalendarEvent re-parses
a fetched event it extracts _calendar from id.split('/')[0], getting
"mock-event-1" instead of "mock cal". This caused filterEvents() to
drop the event because calendarVisibility["mock-event-1"] is undefined.
The dialog-based event creation test was racing with the initial
sync's reloadEvents() GET: if the (stale, pre-PUT) response arrived
after addEvent() pushed the local event, it replaced this.events with
an empty list, causing the event to disappear. Waiting for the initial
events load in beforeEach eliminates the race.
Use invoke('val')+trigger('input') instead of type() in the dialog
test to prevent XHR-triggered Angular change detection from
overwriting the input value mid-typing. Also preserve locally-pushed
events in updateEventList() so they aren't dropped if the view
refreshes before the next sync.
@gtandersen gtandersen force-pushed the geir/signup-screen branch from b951f95 to 6a6e049 Compare May 6, 2026 21:18
@gtandersen
Copy link
Copy Markdown
Contributor Author

Possible improvements:

  1. The tooltips should only show when hovering over the "i" icons, not the fields themselves.
  2. "Identity: These names are also used as the default sender name recipients will see when you send email." Is this something you can change later and if so, should we mention that here?
  3. "Email address: Pick a Runbox address or use your own domain." Should we specify that you can use any of the Runbox domains at any time, regardless of which one you pick here - it is not obvious to someone new to Runbox?

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.

#Feature-Add: Signup screen

2 participants