Radish alpha
r
rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5
Radicle web interface
Radicle
Git
Re-use project-level data when browsing source code
Merged did:key:z6Mki9XN...FvWF opened 2 years ago

We make source code browsing faster by re-using project-level data when navigating between files. This comes at a cost: Project info (like the issue counter), remotes and branches are only updated when the page is hard-refreshed or the user navigates away from the source code view.

3 files changed +51 -13 dcced2e0 69429cb0
modified src/lib/router.ts
@@ -1,7 +1,7 @@
import type { BaseUrl } from "@httpd-client";
import type { LoadedRoute, Route } from "@app/lib/router/definitions";

-
import { writable } from "svelte/store";
+
import { get, writable } from "svelte/store";

import * as mutexExecutor from "@app/lib/mutexExecutor";
import * as utils from "@app/lib/utils";
@@ -101,9 +101,10 @@ async function navigate(
    window.history.replaceState(newRoute, "");
  }
  currentUrl = new URL(window.location.href);
+
  const currentLoadedRoute = get(activeRouteStore);

  const loadedRoute = await loadExecutor.run(async () => {
-
    return loadRoute(newRoute);
+
    return loadRoute(newRoute, currentLoadedRoute);
  });

  // Only let the last request through.
modified src/lib/router/definitions.ts
@@ -62,7 +62,10 @@ export type LoadedRoute =
  | NodesLoadedRoute
  | SessionRoute;

-
export async function loadRoute(route: Route): Promise<LoadedRoute> {
+
export async function loadRoute(
+
  route: Route,
+
  previousLoaded: LoadedRoute,
+
): Promise<LoadedRoute> {
  if (route.resource === "nodes") {
    return await loadNodeRoute(route.params);
  } else if (route.resource === "home") {
@@ -77,7 +80,7 @@ export async function loadRoute(route: Route): Promise<LoadedRoute> {
    route.resource === "project.patches" ||
    route.resource === "project.patch"
  ) {
-
    return await loadProjectRoute(route);
+
    return await loadProjectRoute(route, previousLoaded);
  } else {
    return route;
  }
modified src/views/projects/router.ts
@@ -1,4 +1,8 @@
-
import type { ErrorRoute, NotFoundRoute } from "@app/lib/router/definitions";
+
import type {
+
  ErrorRoute,
+
  LoadedRoute,
+
  NotFoundRoute,
+
} from "@app/lib/router/definitions";
import type {
  BaseUrl,
  Blob,
@@ -269,6 +273,7 @@ async function isLocalNodeSeeding(route: ProjectRoute): Promise<boolean> {

export async function loadProjectRoute(
  route: ProjectRoute,
+
  previousLoaded: LoadedRoute,
): Promise<ProjectLoadedRoute | ErrorRoute | NotFoundRoute> {
  const api = new HttpdClient(route.node);
  const rawPath = (commit?: string) =>
@@ -278,7 +283,7 @@ export async function loadProjectRoute(

  try {
    if (route.resource === "project.source") {
-
      return await loadTreeView(route);
+
      return await loadTreeView(route, previousLoaded);
    } else if (route.resource === "project.history") {
      return await loadHistoryView(route);
    } else if (route.resource === "project.commit") {
@@ -407,21 +412,50 @@ async function loadIssuesView(

async function loadTreeView(
  route: ProjectTreeRoute,
-
): Promise<ProjectLoadedRoute> {
+
  previousLoaded: LoadedRoute,
+
): Promise<ProjectLoadedRoute | NotFoundRoute> {
  const api = new HttpdClient(route.node);
  const rawPath = (commit?: string) =>
    `${route.node.scheme}://${route.node.hostname}:${route.node.port}/raw/${
      route.project
    }${commit ? `/${commit}` : ""}`;

-
  const [profile, project, peers, branchMap, seeding] = await Promise.all([
+
  let projectPromise: Promise<Project>;
+
  let peersPromise: Promise<Remote[]>;
+
  if (
+
    previousLoaded.resource === "project.source" &&
+
    previousLoaded.params.project.id === route.project &&
+
    previousLoaded.params.peer === route.peer
+
  ) {
+
    projectPromise = Promise.resolve(previousLoaded.params.project);
+
    peersPromise = Promise.resolve(previousLoaded.params.peers);
+
  } else {
+
    projectPromise = api.project.getById(route.project);
+
    peersPromise = api.project.getAllRemotes(route.project);
+
  }
+

+
  const [profile, project, peers, seeding] = await Promise.all([
    api.profile.getProfile().catch(() => undefined),
-
    api.project.getById(route.project),
-
    api.project.getAllRemotes(route.project),
-
    getPeerBranches(api, route.project, route.peer),
+
    projectPromise,
+
    peersPromise,
    isLocalNodeSeeding(route),
  ]);

+
  let branchMap: Record<string, string>;
+
  if (route.peer) {
+
    const peer = peers.find(peer => peer.id === route.peer);
+
    if (!peer) {
+
      return {
+
        resource: "notFound",
+
        params: { title: `Peer ${route.peer} could not be found` },
+
      };
+
    } else {
+
      branchMap = peer.heads;
+
    }
+
  } else {
+
    branchMap = { [project.defaultBranch]: project.head };
+
  }
+

  if (route.route) {
    const { revision, path } = detectRevision(
      route.route,
@@ -434,7 +468,7 @@ async function loadTreeView(
  const commit = parseRevisionToOid(
    route.revision,
    project.defaultBranch,
-
    branchMap || { [project.defaultBranch]: project.head },
+
    branchMap,
  );

  const path = route.path || "/";
@@ -450,7 +484,7 @@ async function loadTreeView(
      project,
      peers,
      peer: route.peer,
-
      branches: Object.keys(branchMap || {}),
+
      branches: Object.keys(branchMap),
      rawPath,
      revision: route.revision,
      tree,