Radish alpha
r
rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5
Radicle web interface
Radicle
Git
perf improvements with redundant project info and lazily loading tree stats
Merged did:key:z6MkkfM3...sVz5 opened 1 year ago
  • Move tree stats request out of router into Source Header
  • Use previously loaded Route for issue and patch view

check check-visual check-unit-test check-httpd-api-unit-test check-e2e check-build

👉 Preview 👉 Workflow runs 👉 Branch on GitHub

4 files changed +89 -67 56578114 3fd5d513
modified src/views/projects/History.svelte
@@ -5,7 +5,6 @@
    Project,
    Remote,
    Tree,
-
    TreeStats,
  } from "@httpd-client";
  import type { Route } from "@app/lib/router";

@@ -24,6 +23,7 @@
  import ProjectNameHeader from "./Source/ProjectNameHeader.svelte";

  export let baseUrl: BaseUrl;
+
  export let commit: string;
  export let branches: string[];
  export let commitHeaders: CommitHeader[];
  export let peer: string | undefined;
@@ -31,7 +31,6 @@
  export let project: Project;
  export let revision: string | undefined;
  export let tree: Tree;
-
  export let stats: TreeStats;
  export let seeding: boolean;

  const api = new HttpdClient(baseUrl);
@@ -112,12 +111,12 @@
  <div style:margin="1rem 0 1rem 1rem" slot="subheader">
    <Header
      node={baseUrl}
+
      {commit}
      {project}
      peers={peersWithRoute}
      branches={branchesWithRoute}
      {revision}
      {tree}
-
      {stats}
      filesLinkActive={false}
      historyLinkActive={true} />
  </div>
@@ -136,24 +135,41 @@
    {/each}
  </div>

-
  {#if loading || allCommitHeaders.length < stats.commits}
+
  {#await api.project.getTreeStatsBySha(project.id, commit)}
    <div class="more">
-
      {#if loading}
-
        <Loading small={page !== 0} center />
-
      {:else if allCommitHeaders.length < stats.commits}
-
        <Button size="large" variant="outline" on:click={loadMore}>More</Button>
-
      {/if}
+
      <Loading small center />
    </div>
-
  {/if}
+
  {:then stats}
+
    {#if loading || allCommitHeaders.length < stats.commits}
+
      <div class="more">
+
        {#if loading}
+
          <Loading small={page !== 0} center />
+
        {:else if allCommitHeaders.length < stats.commits}
+
          <Button size="large" variant="outline" on:click={loadMore}>
+
            More
+
          </Button>
+
        {/if}
+
      </div>
+
    {/if}

-
  {#if error}
+
    {#if error}
+
      <div class="message">
+
        <ErrorMessage
+
          title="Couldn't load commits"
+
          description="Make sure you are able to connect to the seed <code>${baseUrlToString(
+
            api.baseUrl,
+
          )}</code>"
+
          {error} />
+
      </div>
+
    {/if}
+
  {:catch error}
    <div class="message">
      <ErrorMessage
-
        title="Couldn't load commits"
+
        title="Couldn't load repo stats"
        description="Make sure you are able to connect to the seed <code>${baseUrlToString(
          api.baseUrl,
        )}</code>"
        {error} />
    </div>
-
  {/if}
+
  {/await}
</Layout>
modified src/views/projects/Source.svelte
@@ -1,11 +1,5 @@
<script lang="ts">
-
  import type {
-
    BaseUrl,
-
    Project,
-
    Remote,
-
    Tree,
-
    TreeStats,
-
  } from "@httpd-client";
+
  import type { BaseUrl, Project, Remote, Tree } from "@httpd-client";
  import type { BlobResult } from "./router";
  import type { Route } from "@app/lib/router";

@@ -21,6 +15,7 @@
  import ProjectNameHeader from "./Source/ProjectNameHeader.svelte";

  export let baseUrl: BaseUrl;
+
  export let commit: string;
  export let rawPath: (commit?: string) => string;
  export let blobResult: BlobResult;
  export let branches: string[];
@@ -30,7 +25,6 @@
  export let project: Project;
  export let revision: string | undefined;
  export let tree: Tree;
-
  export let stats: TreeStats;
  export let seeding: boolean;

  let mobileFileTree = false;
@@ -137,12 +131,12 @@
  <div style:margin="1rem 0 1rem 1rem" slot="subheader">
    <Header
      node={baseUrl}
+
      {commit}
      {project}
      peers={peersWithRoute}
      branches={branchesWithRoute}
      {revision}
      {tree}
-
      {stats}
      filesLinkActive={true}
      historyLinkActive={false} />
  </div>
modified src/views/projects/Source/Header.svelte
@@ -1,12 +1,8 @@
<script lang="ts">
-
  import type {
-
    BaseUrl,
-
    Project,
-
    Remote,
-
    Tree,
-
    TreeStats,
-
  } from "@httpd-client";
-
  import { type Route } from "@app/lib/router";
+
  import type { BaseUrl, Project, Remote, Tree } from "@httpd-client";
+
  import type { Route } from "@app/lib/router";
+

+
  import { HttpdClient } from "@httpd-client";

  import BranchSelector from "./BranchSelector.svelte";
  import PeerSelector from "./PeerSelector.svelte";
@@ -14,28 +10,30 @@
  import Button from "@app/components/Button.svelte";
  import IconSmall from "@app/components/IconSmall.svelte";
  import Link from "@app/components/Link.svelte";
+
  import Loading from "@app/components/Loading.svelte";

  export let node: BaseUrl;
+
  export let commit: string;
  export let branches: Array<{ name: string; route: Route }>;
  export let peers: Array<{ remote: Remote; selected: boolean; route: Route }>;
  export let filesLinkActive: boolean;
  export let historyLinkActive: boolean;
  export let revision: string | undefined;
  export let tree: Tree;
-
  export let stats: TreeStats;
  export let project: Project;

+
  const api = new HttpdClient(node);
  let selectedBranch: string | undefined;

  // Revision may be a commit ID, a branch name or `undefined` which means the
  // default branch. We assign `selectedBranch` accordingly.
-
  $: if (revision === commit.id) {
+
  $: if (revision === lastCommit.id) {
    selectedBranch = undefined;
  } else {
    selectedBranch = revision || project.defaultBranch;
  }

-
  $: commit = tree.lastCommit;
+
  $: lastCommit = tree.lastCommit;
  $: peer = peers.find(p => p.selected)?.remote.id;
</script>

@@ -77,6 +75,7 @@

  .title-counter {
    display: flex;
+
    align-items: center;
    gap: 0.5rem;
  }

@@ -96,7 +95,7 @@
    {project}
    {node}
    onCanonical={Boolean(!peer && selectedBranch === project.defaultBranch)}
-
    selectedCommit={commit}
+
    selectedCommit={lastCommit}
    {selectedBranch} />
</div>

@@ -127,9 +126,13 @@
        <IconSmall name="commit" />
        <div class="title-counter">
          Commits
-
          <div class="counter" class:selected={historyLinkActive}>
-
            {stats.commits}
-
          </div>
+
          {#await api.project.getTreeStatsBySha(project.id, commit)}
+
            <Loading small center noDelay grayscale />
+
          {:then stats}
+
            <div class="counter" class:selected={historyLinkActive}>
+
              {stats.commits}
+
            </div>
+
          {/await}
        </div>
      </Button>
    </Link>
modified src/views/projects/router.ts
@@ -18,7 +18,6 @@ import type {
  Project,
  Remote,
  Tree,
-
  TreeStats,
} from "@httpd-client";

import * as Syntax from "@app/lib/syntax";
@@ -45,13 +44,8 @@ export type ProjectRoute =
      commit: string;
    }
  | ProjectIssuesRoute
+
  | ProjectIssueRoute
  | { resource: "project.newIssue"; node: BaseUrl; project: string }
-
  | {
-
      resource: "project.issue";
-
      node: BaseUrl;
-
      project: string;
-
      issue: string;
-
    }
  | ProjectPatchesRoute
  | ProjectPatchRoute;

@@ -62,6 +56,13 @@ interface ProjectIssuesRoute {
  state?: "open" | "closed";
}

+
interface ProjectIssueRoute {
+
  resource: "project.issue";
+
  node: BaseUrl;
+
  project: string;
+
  issue: string;
+
}
+

interface ProjectTreeRoute {
  resource: "project.source";
  node: BaseUrl;
@@ -112,13 +113,13 @@ export type ProjectLoadedRoute =
      resource: "project.source";
      params: {
        baseUrl: BaseUrl;
+
        commit: string;
        project: Project;
        peers: Remote[];
        peer: string | undefined;
        branches: string[];
        revision: string | undefined;
        tree: Tree;
-
        stats: TreeStats;
        path: string;
        rawPath: (commit?: string) => string;
        blobResult: BlobResult;
@@ -129,13 +130,13 @@ export type ProjectLoadedRoute =
      resource: "project.history";
      params: {
        baseUrl: BaseUrl;
+
        commit: string;
        project: Project;
        peers: Remote[];
        peer: string | undefined;
        branches: string[];
        revision: string | undefined;
        tree: Tree;
-
        stats: TreeStats;
        commitHeaders: CommitHeader[];
        seeding: boolean;
      };
@@ -294,19 +295,7 @@ export async function loadProjectRoute(
        },
      };
    } else if (route.resource === "project.issue") {
-
      const [project, issue] = await Promise.all([
-
        api.project.getById(route.project),
-
        api.project.getIssueById(route.project, route.issue),
-
      ]);
-
      return {
-
        resource: "project.issue",
-
        params: {
-
          baseUrl: route.node,
-
          project,
-
          rawPath,
-
          issue,
-
        },
-
      };
+
      return await loadIssueView(route);
    } else if (route.resource === "project.patch") {
      return await loadPatchView(route);
    } else if (route.resource === "project.issues") {
@@ -444,11 +433,7 @@ async function loadTreeView(
    project.defaultBranch,
    branchMap,
  );
-

-
  const stats = await api.project.getTreeStatsBySha(route.project, commit);
-

  const path = route.path || "/";
-

  const [tree, blobResult] = await Promise.all([
    api.project.getTree(route.project, commit),
    loadBlob(api, project.id, commit, path),
@@ -457,6 +442,7 @@ async function loadTreeView(
    resource: "project.source",
    params: {
      baseUrl: route.node,
+
      commit,
      project,
      peers: peers.filter(remote => Object.keys(remote.heads).length > 0),
      peer: route.peer,
@@ -464,7 +450,6 @@ async function loadTreeView(
      rawPath,
      revision: route.revision,
      tree,
-
      stats,
      path,
      blobResult,
      seeding,
@@ -538,9 +523,8 @@ async function loadHistoryView(
    );
  }

-
  const [tree, stats, commitHeaders, seeding] = await Promise.all([
+
  const [tree, commitHeaders, seeding] = await Promise.all([
    api.project.getTree(route.project, commitId),
-
    api.project.getTreeStatsBySha(route.project, commitId),
    await api.project.getAllCommits(project.id, {
      parent: commitId,
      page: 0,
@@ -553,19 +537,43 @@ async function loadHistoryView(
    resource: "project.history",
    params: {
      baseUrl: route.node,
+
      commit: commitId,
      project,
      peers: peers.filter(remote => Object.keys(remote.heads).length > 0),
      peer: route.peer,
      branches: Object.keys(branchMap || {}),
      revision: route.revision,
      tree,
-
      stats,
      commitHeaders,
      seeding,
    },
  };
}

+
async function loadIssueView(
+
  route: ProjectIssueRoute,
+
): Promise<ProjectLoadedRoute> {
+
  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 [project, issue] = await Promise.all([
+
    api.project.getById(route.project),
+
    api.project.getIssueById(route.project, route.issue),
+
  ]);
+
  return {
+
    resource: "project.issue",
+
    params: {
+
      baseUrl: route.node,
+
      project,
+
      rawPath,
+
      issue,
+
    },
+
  };
+
}
+

async function loadPatchView(
  route: ProjectPatchRoute,
): Promise<ProjectLoadedRoute> {
@@ -574,6 +582,7 @@ async function loadPatchView(
    `${route.node.scheme}://${route.node.hostname}:${route.node.port}/raw/${
      route.project
    }${commit ? `/${commit}` : ""}`;
+

  const [project, patch] = await Promise.all([
    api.project.getById(route.project),
    api.project.getPatchById(route.project, route.patch),