Radish alpha
r
Radicle desktop app
Radicle
Git (anonymous pull)
Log in to clone via SSH
Implement loading on scroll for patch second column
✓ CI success Rūdolfs Ošiņš committed 1 year ago
commit 9ff061793db600d71e0a02b74caa7426fe2d98cf
parent ff8fca8dd79524680efd9f59de272a74205e027b
1 passed (1 total) View logs
6 files changed +103 -38
modified src/components/PatchTeaser.svelte
@@ -9,33 +9,29 @@
    patchStatusColor,
  } from "@app/lib/utils";
  import { invoke } from "@app/lib/invoke";
-
  import { onMount } from "svelte";
  import { push } from "@app/lib/router";

  import DiffStatBadge from "./DiffStatBadge.svelte";
  import Icon from "./Icon.svelte";
+
  import Id from "./Id.svelte";
  import InlineTitle from "./InlineTitle.svelte";
  import NodeId from "./NodeId.svelte";
-
  import Id from "./Id.svelte";
-

-
  let stats: Stats | undefined = $state(undefined);
-

-
  onMount(async () => {
-
    stats = await invoke<Stats>("diff_stats", {
-
      rid,
-
      base: patch.base,
-
      head: patch.head,
-
    });
-
  });

  interface Props {
    patch: Patch;
    rid: string;
    selected?: boolean;
    compact?: boolean;
+
    loadPatch?: (rid: string, patchId: string) => void;
  }

-
  const { patch, rid, selected = false, compact = false }: Props = $props();
+
  const {
+
    patch,
+
    rid,
+
    selected = false,
+
    compact = false,
+
    loadPatch,
+
  }: Props = $props();
</script>

<style>
@@ -79,7 +75,11 @@
  class:selected
  class="patch-teaser"
  onclick={() => {
-
    void push({ resource: "repo.patch", rid, patch: patch.id });
+
    if (loadPatch) {
+
      loadPatch(rid, patch.id);
+
    } else {
+
      void push({ resource: "repo.patch", rid, patch: patch.id });
+
    }
  }}>
  <div class="global-flex">
    <div
@@ -104,9 +104,10 @@

  {#if !compact}
    <div class="global-flex">
-
      {#if stats}
+
      {#await invoke<Stats>( "diff_stats", { rid, base: patch.base, head: patch.head }, ) then stats}
        <DiffStatBadge {stats} />
-
      {/if}
+
      {/await}
+

      {#each patch.labels as label}
        <div class="global-counter txt-small">{label}</div>
      {/each}
modified src/components/Sidebar.svelte
@@ -71,6 +71,7 @@

  {#if activeTab === "patches"}
    <Border
+
      styleCursor="pointer"
      onclick={() => {
        void router.push({
          resource: "repo.patches",
modified src/views/repo/Layout.svelte
@@ -13,7 +13,8 @@
    headerCenter?: Snippet;
    secondColumn: Snippet;
    sidebar: Snippet;
-
    loadMore?: () => Promise<void>;
+
    loadMoreContent?: () => Promise<void>;
+
    loadMoreSecondColumn?: () => Promise<void>;
    hideSidebar?: boolean;
    styleSecondColumnOverflow?: string;
  }
@@ -24,7 +25,8 @@
    headerCenter = undefined,
    secondColumn,
    sidebar,
-
    loadMore = undefined,
+
    loadMoreContent = undefined,
+
    loadMoreSecondColumn = undefined,
    hideSidebar = false,
    styleSecondColumnOverflow = "scroll",
  }: Props = $props();
@@ -34,8 +36,10 @@
  let oneColumnLayout = $state(
    localStorage ? localStorage.getItem(LAYOUT_KEY) === "one-column" : false,
  );
-
  let listElement: HTMLElement | undefined = $state();
-
  let loading = false;
+
  let contentContainer: HTMLElement | undefined = $state();
+
  let secondColumnContainer: HTMLElement | undefined = $state();
+
  let loadingContent = false;
+
  let loadingSecondColumn = false;

  function storeLayout(newValue: LayoutState): void {
    oneColumnLayout = newValue === "one-column";
@@ -49,16 +53,33 @@
  }

  onMount(() => {
-
    if (listElement && loadMore) {
-
      listElement.addEventListener("scroll", async () => {
+
    if (contentContainer && loadMoreContent) {
+
      contentContainer.addEventListener("scroll", async () => {
        if (
-
          listElement &&
-
          listElement.scrollTop + listElement.clientHeight >=
-
            listElement.scrollHeight - 600 &&
-
          loading === false
+
          contentContainer &&
+
          contentContainer.scrollTop + contentContainer.clientHeight >=
+
            contentContainer.scrollHeight - 600 &&
+
          loadingContent === false
        ) {
-
          loading = true;
-
          void loadMore().finally(() => (loading = false));
+
          loadingContent = true;
+
          void loadMoreContent().finally(() => (loadingContent = false));
+
        }
+
      });
+
    }
+

+
    if (secondColumnContainer && loadMoreSecondColumn) {
+
      secondColumnContainer.addEventListener("scroll", async () => {
+
        if (
+
          secondColumnContainer &&
+
          secondColumnContainer.scrollTop +
+
            secondColumnContainer.clientHeight >=
+
            secondColumnContainer.scrollHeight - 600 &&
+
          loadingSecondColumn === false
+
        ) {
+
          loadingSecondColumn = true;
+
          void loadMoreSecondColumn().finally(
+
            () => (loadingSecondColumn = false),
+
          );
        }
      });
    }
@@ -93,7 +114,7 @@
  .secondColumn {
    grid-column: 2 / 3;
    margin: 1rem 0 0 0;
-
    max-width: 30rem;
+
    max-width: 28rem;
    min-width: 14rem;
    margin-right: 1rem;
  }
@@ -162,6 +183,7 @@

  <div
    class="secondColumn"
+
    bind:this={secondColumnContainer}
    style:display={oneColumnLayout ? "none" : undefined}
    style:overflow={styleSecondColumnOverflow}>
    {@render secondColumn()}
@@ -169,7 +191,7 @@

  <div
    class="content global-reset-scroll-after-navigate"
-
    bind:this={listElement}>
+
    bind:this={contentContainer}>
    {@render children()}
  </div>
</div>
modified src/views/repo/Patch.svelte
@@ -1,9 +1,12 @@
<script lang="ts">
  import type { Config } from "@bindings/config/Config";
+
  import type { PaginatedQuery } from "@bindings/cob/PaginatedQuery";
  import type { Patch } from "@bindings/cob/patch/Patch";
  import type { RepoInfo } from "@bindings/repo/RepoInfo";
  import type { Revision } from "@bindings/cob/patch/Revision";

+
  import { invoke } from "@app/lib/invoke";
+

  import CommentComponent from "@app/components/Comment.svelte";
  import CopyableId from "@app/components/CopyableId.svelte";
  import Icon from "@app/components/Icon.svelte";
@@ -18,12 +21,49 @@
  interface Props {
    repo: RepoInfo;
    patch: Patch;
-
    patches: Patch[];
+
    patches: PaginatedQuery<Patch[]>;
    revisions: Revision[];
    config: Config;
  }

-
  const { repo, patch, patches, revisions, config }: Props = $props();
+
  /* eslint-disable prefer-const */
+
  let { repo, patch, patches, revisions, config }: Props = $props();
+
  /* eslint-enable prefer-const */
+

+
  let items = $state(patches.content);
+
  let cursor = patches.cursor;
+
  let more = patches.more;
+

+
  $effect(() => {
+
    items = patches.content;
+
    cursor = patches.cursor;
+
    more = patches.more;
+
  });
+

+
  async function loadPatch(rid: string, patchId: string) {
+
    patch = await invoke<Patch>("patch_by_id", {
+
      rid: rid,
+
      id: patchId,
+
    });
+
    revisions = await invoke<Revision[]>("revisions_by_patch", {
+
      rid: rid,
+
      id: patchId,
+
    });
+
  }
+

+
  async function loadMoreSecondColumn() {
+
    if (more) {
+
      const p = await invoke<PaginatedQuery<Patch[]>>("list_patches", {
+
        rid: repo.rid,
+
        skip: cursor + 20,
+
        take: 20,
+
      });
+

+
      cursor = p.cursor;
+
      more = p.more;
+
      items = [...items, ...p.content];
+
    }
+
  }

  const project = $derived(repo.payloads["xyz.radicle.project"]!);
</script>
@@ -66,7 +106,7 @@
  }
</style>

-
<Layout>
+
<Layout {loadMoreSecondColumn}>
  {#snippet breadcrumbs()}
    <Link route={{ resource: "home" }}>
      <NodeId
@@ -105,9 +145,10 @@
      Patches
    </div>
    <div class="patch-list">
-
      {#each patches as p}
+
      {#each items as p}
        <PatchTeaser
          compact
+
          {loadPatch}
          patch={p}
          rid={repo.rid}
          selected={patch && p.id === patch.id} />
modified src/views/repo/Patches.svelte
@@ -36,7 +36,7 @@
    more = patches.more;
  });

-
  async function loadMore() {
+
  async function loadMoreContent() {
    if (more) {
      const p = await invoke<PaginatedQuery<Patch[]>>("list_patches", {
        rid: repo.rid,
@@ -71,7 +71,7 @@
  }
</style>

-
<Layout {loadMore} hideSidebar styleSecondColumnOverflow="visible">
+
<Layout {loadMoreContent} hideSidebar styleSecondColumnOverflow="visible">
  {#snippet breadcrumbs()}
    <Link route={{ resource: "home" }}>
      <NodeId
modified src/views/repo/router.ts
@@ -74,7 +74,7 @@ export interface LoadedRepoPatchRoute {
    repo: RepoInfo;
    config: Config;
    patch: Patch;
-
    patches: Patch[];
+
    patches: PaginatedQuery<Patch[]>;
    revisions: Revision[];
  };
}
@@ -131,7 +131,7 @@ export async function loadPatch(

  return {
    resource: "repo.patch",
-
    params: { repo, config, patch, patches: patches.content, revisions },
+
    params: { repo, config, patch, patches, revisions },
  };
}