[DEPRECATED 2] Evaluate: Modernize UX with Zero-Refactor SPA-Like Navigation #3005
Zak Siddiqui opened 1 week ago

Summary

Improve perceived page load performance by adding a client-side navigation progress indicator (e.g., a thin top loading bar) that appears on every full-page navigation, regardless of backend response time.

sequenceDiagram participant U as User participant B as Browser (UI) participant S as OneDev Server rect rgba(200, 200, 200, 0.1) Note over U,S: Current Architecture (Full Hard Reload) U->>B: Clicks Navigation Link (e.g. Issues -> Builds) B->>S: HTTP GET /builds Note over B,S: ❌ Entire DOM destroyed. Screen flashes blank. S-->>B: Returns Full HTML B->>B: Re-parses & repaints Header, Sidebar, and Main Content end rect rgba(100, 255, 100, 0.1) Note over U,S: Proposed Architecture (SPA Interceptor) U->>B: Clicks Navigation Link (e.g. Issues -> Builds) B->>S: Fetch API GET /builds (Background) Note over B: ✅ Header & Sidebar remain visible and stable. No flash. S-->>B: Returns Full HTML B->>B: Extracts <div id="main"> from response B->>B: Seamlessly swaps current #main with new #main B->>B: Re-executes scripts & Updates URL History end

Motivation

Currently, when navigating between pages in OneDev, there is no visual feedback until the server finishes rendering the full Wicket page. On slower connections or when the backend is processing (e.g., loading a large repository tree or CI pipeline history), the user sees a blank page or a frozen screen with no indication that navigation is in progress. This creates a poor UX, especially in the following scenarios:

  • Switching between Projects, Pull Requests, Issues, or CI Jobs
  • Navigating into a repository with large commit history
  • Loading pipeline/build logs

Proposed Solution

Add a lightweight, non-intrusive page-level loading progress bar (similar to YouTube's red loading bar or GitHub's top progress bar) that activates automatically on every full-page navigation event and completes when the page finishes loading (DOMContentLoaded or window.onload).

Technical Approach (Wicket-Compatible)

Since OneDev uses Apache Wicket, we cannot switch to SPA-style navigation without a major refactor. However, a pure client-side progress bar is trivial to implement and fully compatible with Wicket's full-page lifecycle:

  1. Inject a thin (3px) <div id="nav-progress-bar"> at the top of the page layout (e.g., in BasePage.html or the main Wicket markup).
  2. Use a small inline JavaScript snippet (or a Wicket HeaderContributor) that:
    • Listens for window.onbeforeunload (or any anchor click) to start the progress bar animation.
    • Listens for window.onload to complete the progress bar.
    • Uses CSS transitions for smooth animation (no external dependencies).
  3. The bar is styled with a CSS gradient or solid color matching the OneDev theme accent.

CSS/JS Sketch

#nav-progress-bar {
  position: fixed;
  top: 0;
  left: 0;
  height: 3px;
  width: 0%;
  background: #2b7de9;
  z-index: 9999;
  transition: width 0.2s ease;
}
window.addEventListener('beforeunload', function() {
  var bar = document.getElementById('nav-progress-bar');
  if (bar) {
    bar.style.width = '60%';
    bar.style.transition = 'width 0.5s ease';
  }
});

window.addEventListener('load', function() {
  var bar = document.getElementById('nav-progress-bar');
  if (bar) {
    bar.style.width = '100%';
    setTimeout(function() {
      bar.style.width = '0%';
      bar.style.transition = 'none';
    }, 400);
  }
});

Advantages

  • Zero refactoring of the existing Wicket page structure
  • No external libraries (pure CSS + vanilla JS)
  • Works on every page automatically via the shared layout template
  • Low implementation effort (~1-2 hours)
  • High user-facing impact — eliminates the "blank page" anxiety

Alternatives Considered

  • TurboLinks / Turbolinks-style navigation: Not compatible with Wicket's server-side component tree and would require extensive re-architecture.
  • Full SPA rewrite: Not feasible for a Wicket-based application at this time.
  • AJAX-based partial page updates: Already used in some areas (e.g., dynamic issue fields), but full-page navigation is inherent to Wicket's page model and cannot be fully replaced without a framework migration.

Acceptance Criteria

  •  A thin progress bar appears at the top of the browser window when navigating between pages.
  •  The bar animates smoothly from 0% to ~60% immediately on page unload, then completes to 100% on page load.
  •  The bar resets to 0% after each navigation completes.
  •  The feature does not interfere with any existing Wicket AJAX behaviors or page components.
  •  The bar is styled consistently with the current OneDev theme.
  • Service Desk commented 1 week ago

    Thanks for the detailed write-up. Here is an evaluation of the two ideas in this issue (SPA-style content swap vs. a top progress bar) against the current OneDev/Wicket UI.

    SPA interceptor (swap #main / keep chrome stable)

    This is not feasible without a major rewrite, which the issue already notes.

    • There is no div#main. Layout chrome lives in LayoutPage (sidebar + topbar + a .main class container). Sidebar and topbar are Wicket components with their own Ajax behaviors, not a static shell.
    • Full-page GETs return a new Wicket page instance. Component markup IDs, Ajax callbacks, wicket-ajax-baseurl, and the WebSocket channel are bound to that instance. Extracting HTML and swapping it would leave the client talking to a dead page map.
    • OneDev already uses the History API (onedev.server.history) and Ajax for in-page updates. That is the supported partial-update path; intercepting ordinary links is not.

    Turbolinks / htmx / a hand-rolled fetch-and-swap layer would have the same problem.

    Progress bar via beforeunload / load

    The CSS/JS sketch would not produce a GitHub/YouTube-style bar on full-page navigation.

    1. beforeunload does not paint. Browsers tear down the current document as soon as navigation starts. Width transitions started there are typically never shown. OneDev already uses beforeunload for unsaved-form confirmation (onedev.server.form.setupDirtyCheck) and WebSocket disconnect handling; another handler that mutates the DOM would be unreliable and risks interacting with those.
    2. load runs on a new document. After navigation the bar is a fresh element at width: 0%. Completing it to 100% then hiding it would flash a bar after the page is already visible, which is the opposite of the intended feedback.
    3. GitHub/YouTube bars work because those apps intercept clicks (or are SPAs). They do not rely on beforeunload.

    What already exists

    BasePage already has a global Ajax loading indicator (#ajax-loading-indicator, “Please wait…”). onedev.server.setupAjaxLoadingIndicator shows it after 2s of Wicket Ajax, and there are per-component indicators (AttachAjaxIndicatorListener, infinite-scroll spinners, etc.). That covers in-page work (issue fields, lists, logs streamed over Ajax/WebSocket).

    Primary sidebar/topbar navigation uses ViewStateAwarePageLink / BookmarkablePageLink, so Issues → Builds etc. are genuine full page loads. That is inherent to Wicket’s page model.

    Recommendation

    Do not implement SPA-like HTML swapping, and do not implement the beforeunload/load progress bar as specified — it would not meet the acceptance criteria and would not keep header/sidebar stable.

    If slow full-page navigations are the real pain (large repo tree, long pipeline history), the effective fixes are faster server rendering of those pages and more Ajax where it already fits. A click-intercepted top bar (start on same-origin link click, persist via sessionStorage, complete on the next page) could be a small polish item, but it is a different design from this sketch, still would not prevent a blank document during load, and would need careful exclusions (downloads, target=_blank, modifier-clicks, Wicket Ajax, dirty-form confirm).

    Please say if this answers the evaluation, or if you want a follow-up improvement issue scoped only to a click-time indicator (not SPA navigation).

  • Zak Siddiqui commented 1 week ago

    SORRY - imcomplete!!!

  • Zak Siddiqui changed state to 'Closed' 1 week ago
    Previous Value Current Value
    Open
    Closed
  • Zak Siddiqui changed title 1 week ago
    Previous Value Current Value
    Evaluate: Modernize UX with Zero-Refactor SPA-Like Navigation
    [DEPRECATED 2] Evaluate: Modernize UX with Zero-Refactor SPA-Like Navigation
1/1
Type
Question
Priority
Normal
Assignee
Labels
No labels
Issue Votes (0)
Watchers (3)
Reference
OD-3005
Please wait...
Connection lost or session expired, reload to recover
Page is in error, reload to recover