Radish alpha
r
rad:z4D5UCArafTzTQpDZNQRuqswh3ury
Radicle desktop app
Radicle
Git
Persist issue/patch filter state between list and single views
Open rudolfs opened 1 year ago
11 files changed +107 -63 3109e1d2 0e427c7a
modified src/components/IssueSecondColumn.svelte
@@ -1,6 +1,7 @@
<script lang="ts">
  import type { Issue } from "@bindings/cob/issue/Issue";
  import type { RepoInfo } from "@bindings/repo/RepoInfo";
+
  import type { IssueStatus } from "@app/views/repo/router";

  import * as router from "@app/lib/router";

@@ -14,10 +15,11 @@
    repo: RepoInfo;
    selectedIssueId?: string;
    issues: Issue[];
+
    status: IssueStatus;
  }

  /* eslint-disable prefer-const */
-
  let { repo, selectedIssueId, issues }: Props = $props();
+
  let { repo, selectedIssueId, issues, status }: Props = $props();
  /* eslint-enable prefer-const */
</script>

@@ -43,6 +45,7 @@
      void router.push({
        resource: "repo.createIssue",
        rid: repo.rid,
+
        status,
      });
    }}>
    <Icon name="plus" />New
@@ -53,6 +56,7 @@
    <IssueTeaser
      compact
      {issue}
+
      {status}
      rid={repo.rid}
      selected={issue.id === selectedIssueId} />
  {/each}
modified src/components/IssueTeaser.svelte
@@ -1,5 +1,6 @@
<script lang="ts">
  import type { Issue } from "@bindings/cob/issue/Issue";
+
  import type { IssueStatus } from "@app/views/repo/router";

  import {
    authorForNodeId,
@@ -18,11 +19,18 @@
  interface Props {
    issue: Issue;
    rid: string;
+
    status: IssueStatus;
    selected?: boolean;
    compact?: boolean;
  }

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

<style>
@@ -66,7 +74,7 @@
  class="issue-teaser"
  class:selected
  onclick={() => {
-
    void push({ resource: "repo.issue", rid, issue: issue.id });
+
    void push({ resource: "repo.issue", rid, issue: issue.id, status });
  }}>
  <div class="global-flex">
    <div
modified src/components/PatchTeaser.svelte
@@ -1,6 +1,7 @@
<script lang="ts">
  import type { Patch } from "@bindings/cob/patch/Patch";
  import type { Stats } from "@bindings/cob/Stats";
+
  import type { PatchStatus } from "@app/views/repo/router";

  import {
    authorForNodeId,
@@ -23,6 +24,7 @@
    selected?: boolean;
    compact?: boolean;
    loadPatch?: (rid: string, patchId: string) => void;
+
    status: PatchStatus | undefined;
  }

  const {
@@ -31,6 +33,7 @@
    selected = false,
    compact = false,
    loadPatch,
+
    status,
  }: Props = $props();
</script>

@@ -78,7 +81,7 @@
    if (loadPatch) {
      loadPatch(rid, patch.id);
    } else {
-
      void push({ resource: "repo.patch", rid, patch: patch.id });
+
      void push({ resource: "repo.patch", rid, patch: patch.id, status });
    }
  }}>
  <div class="global-flex">
modified src/components/PatchesSecondColumn.svelte
@@ -11,7 +11,7 @@

  interface Props {
    project: ProjectPayload;
-
    status?: PatchStatus;
+
    status: PatchStatus | undefined;
    repo: RepoInfo;
  }
  const { project, status, repo }: Props = $props();
@@ -91,7 +91,7 @@
      <Link
        styleWidth="100%"
        underline={false}
-
        route={{ resource: "repo.patches", rid: repo.rid }}>
+
        route={{ resource: "repo.patches", rid: repo.rid, status }}>
        <div class="tab active">
          <div class="global-flex"><Icon name="patch" />Patches</div>
          <div class="global-counter">
modified src/components/Sidebar.svelte
@@ -1,17 +1,22 @@
<script lang="ts">
+
  import type { IssueStatus, PatchStatus } from "@app/views/repo/router";
+

  import * as router from "@app/lib/router";
+
  import { patchStatusColor } from "@app/lib/utils";
+
  import { issueStatusColor } from "@app/lib/utils";

  import Icon from "@app/components/Icon.svelte";
  import Settings from "@app/components/Settings.svelte";
  import Border from "./Border.svelte";

  interface Props {
-
    activeTab: "issues" | "patches";
+
    activeTab:
+
      | { type: "issues"; status: IssueStatus }
+
      | { type: "patches"; status?: PatchStatus };
    rid: string;
-
    activeIconColor?: string;
  }

-
  const { activeTab, rid, activeIconColor }: Props = $props();
+
  const { activeTab, rid }: Props = $props();
</script>

<style>
@@ -39,7 +44,7 @@
  <div class="global-flex" style:margin-bottom="5px" style:height="40px">
    <Icon name="repo" />
  </div>
-
  {#if activeTab === "issues"}
+
  {#if activeTab.type === "issues"}
    <Border
      styleCursor="pointer"
      onclick={() => {
@@ -53,7 +58,12 @@
      styleWidth="40px"
      styleHeight="40px"
      styleJustifyContent="center">
-
      <div style:color={activeIconColor}><Icon name="issue" /></div>
+
      <div
+
        style:color={activeTab.status === "all"
+
          ? undefined
+
          : issueStatusColor[activeTab.status]}>
+
        <Icon name="issue" />
+
      </div>
    </Border>
  {:else}
    <button
@@ -69,7 +79,7 @@
    </button>
  {/if}

-
  {#if activeTab === "patches"}
+
  {#if activeTab.type === "patches"}
    <Border
      styleCursor="pointer"
      onclick={() => {
@@ -83,7 +93,12 @@
      styleWidth="40px"
      styleHeight="40px"
      styleJustifyContent="center">
-
      <div style:color={activeIconColor}><Icon name="patch" /></div>
+
      <div
+
        style:color={activeTab.status
+
          ? patchStatusColor[activeTab.status]
+
          : undefined}>
+
        <Icon name="patch" />
+
      </div>
    </Border>
  {:else}
    <button
modified src/views/repo/CreateIssue.svelte
@@ -3,6 +3,7 @@
  import type { Config } from "@bindings/config/Config";
  import type { Issue } from "@bindings/cob/issue/Issue";
  import type { RepoInfo } from "@bindings/repo/RepoInfo";
+
  import type { IssueStatus } from "./router";

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

@@ -32,9 +33,10 @@
    repo: RepoInfo;
    issues: Issue[];
    config: Config;
+
    status: IssueStatus;
  }

-
  const { repo, issues, config }: Props = $props();
+
  const { repo, issues, config, status }: Props = $props();

  let description: string = $state("");
  let preview: boolean = $state(false);
@@ -61,6 +63,7 @@
      resource: "repo.issue",
      rid: repo.rid,
      issue: response.id,
+
      status,
    });
  }

@@ -127,11 +130,11 @@
  {/snippet}

  {#snippet sidebar()}
-
    <Sidebar activeTab="issues" rid={repo.rid} />
+
    <Sidebar activeTab={{ type: "issues", status }} rid={repo.rid} />
  {/snippet}

  {#snippet secondColumn()}
-
    <IssueSecondColumn {repo} {issues} />
+
    <IssueSecondColumn {repo} {issues} {status} />
  {/snippet}

  <div class="content">
modified src/views/repo/Issue.svelte
@@ -6,6 +6,7 @@
  import type { Operation } from "@bindings/cob/issue/Operation";
  import type { RepoInfo } from "@bindings/repo/RepoInfo";
  import type { Thread } from "@bindings/cob/thread/Thread";
+
  import type { IssueStatus } from "./router";

  import partial from "lodash/partial";
  import { tick } from "svelte";
@@ -44,6 +45,7 @@
    activity: Operation[];
    config: Config;
    threads: Thread[];
+
    status: IssueStatus;
  }

  /* eslint-disable prefer-const */
@@ -54,6 +56,7 @@
    activity,
    config,
    threads,
+
    status,
  }: Props = $props();
  /* eslint-enable prefer-const */

@@ -398,11 +401,11 @@
  {/snippet}

  {#snippet sidebar()}
-
    <Sidebar activeTab="issues" rid={repo.rid} />
+
    <Sidebar activeTab={{ type: "issues", status }} rid={repo.rid} />
  {/snippet}

  {#snippet secondColumn()}
-
    <IssueSecondColumn {repo} selectedIssueId={issue.id} {issues} />
+
    <IssueSecondColumn {repo} selectedIssueId={issue.id} {issues} {status} />
  {/snippet}

  <div class="content">
modified src/views/repo/Issues.svelte
@@ -5,7 +5,6 @@
  import type { RepoInfo } from "@bindings/repo/RepoInfo";

  import * as router from "@app/lib/router";
-
  import { issueStatusColor } from "@app/lib/utils";

  import Layout from "./Layout.svelte";

@@ -71,12 +70,7 @@
  {/snippet}

  {#snippet sidebar()}
-
    <Sidebar
-
      activeTab="issues"
-
      rid={repo.rid}
-
      activeIconColor={status !== "all"
-
        ? issueStatusColor[status]
-
        : undefined} />
+
    <Sidebar activeTab={{ type: "issues", status }} rid={repo.rid} />
  {/snippet}

  {#snippet secondColumn()}
@@ -93,6 +87,7 @@
        onclick={() => {
          void router.push({
            resource: "repo.createIssue",
+
            status,
            rid: repo.rid,
          });
        }}>
@@ -103,7 +98,7 @@

  <div class="list">
    {#each issues as issue}
-
      <IssueTeaser {issue} rid={repo.rid} />
+
      <IssueTeaser {issue} rid={repo.rid} {status} />
    {/each}

    {#if issues.length === 0}
modified src/views/repo/Patch.svelte
@@ -5,6 +5,7 @@
  import type { Patch } from "@bindings/cob/patch/Patch";
  import type { RepoInfo } from "@bindings/repo/RepoInfo";
  import type { Revision } from "@bindings/cob/patch/Revision";
+
  import type { PatchStatus } from "./router";

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

@@ -26,10 +27,11 @@
    patches: PaginatedQuery<Patch[]>;
    revisions: Revision[];
    config: Config;
+
    status: PatchStatus | undefined;
  }

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

  let items = $state(patches.content);
@@ -148,7 +150,7 @@
  {/snippet}

  {#snippet sidebar()}
-
    <Sidebar activeTab="patches" rid={repo.rid} />
+
    <Sidebar activeTab={{ type: "patches", status }} rid={repo.rid} />
  {/snippet}

  {#snippet secondColumn()}
@@ -165,6 +167,7 @@
          {loadPatch}
          patch={p}
          rid={repo.rid}
+
          {status}
          selected={patch && p.id === patch.id} />
      {/each}
    </div>
modified src/views/repo/Patches.svelte
@@ -6,7 +6,6 @@
  import type { RepoInfo } from "@bindings/repo/RepoInfo";

  import { invoke } from "@app/lib/invoke";
-
  import { patchStatusColor } from "@app/lib/utils";

  import CopyableId from "@app/components/CopyableId.svelte";
  import Icon from "@app/components/Icon.svelte";
@@ -21,7 +20,7 @@
    repo: RepoInfo;
    patches: PaginatedQuery<Patch[]>;
    config: Config;
-
    status?: PatchStatus;
+
    status: PatchStatus | undefined;
  }

  const { repo, patches, config, status }: Props = $props();
@@ -95,12 +94,7 @@
  {/snippet}

  {#snippet sidebar()}
-
    <Sidebar
-
      activeTab="patches"
-
      rid={repo.rid}
-
      activeIconColor={status !== undefined
-
        ? patchStatusColor[status]
-
        : undefined} />
+
    <Sidebar activeTab={{ type: "patches", status }} rid={repo.rid} />
  {/snippet}

  {#snippet secondColumn()}
@@ -113,7 +107,7 @@

  <div class="list">
    {#each items as patch}
-
      <PatchTeaser rid={repo.rid} {patch} />
+
      <PatchTeaser rid={repo.rid} {patch} {status} />
    {/each}

    {#if patches.content.length === 0}
modified src/views/repo/router.ts
@@ -16,11 +16,13 @@ export interface RepoIssueRoute {
  resource: "repo.issue";
  rid: string;
  issue: string;
+
  status: IssueStatus;
}

export interface RepoCreateIssueRoute {
  resource: "repo.createIssue";
  rid: string;
+
  status: IssueStatus;
}

export interface LoadedRepoIssueRoute {
@@ -30,6 +32,7 @@ export interface LoadedRepoIssueRoute {
    config: Config;
    issue: Issue;
    issues: Issue[];
+
    status: IssueStatus;
    activity: Operation[];
    threads: Thread[];
  };
@@ -41,6 +44,7 @@ export interface LoadedRepoCreateIssueRoute {
    repo: RepoInfo;
    config: Config;
    issues: Issue[];
+
    status: IssueStatus;
  };
}

@@ -66,6 +70,7 @@ export interface RepoPatchRoute {
  resource: "repo.patch";
  rid: string;
  patch: string;
+
  status: PatchStatus | undefined;
}

export interface LoadedRepoPatchRoute {
@@ -75,6 +80,7 @@ export interface LoadedRepoPatchRoute {
    config: Config;
    patch: Patch;
    patches: PaginatedQuery<Patch[]>;
+
    status: PatchStatus | undefined;
    revisions: Revision[];
  };
}
@@ -82,7 +88,7 @@ export interface LoadedRepoPatchRoute {
export interface RepoPatchesRoute {
  resource: "repo.patches";
  rid: string;
-
  status?: PatchStatus;
+
  status: PatchStatus | undefined;
}

export interface LoadedRepoPatchesRoute {
@@ -91,7 +97,7 @@ export interface LoadedRepoPatchesRoute {
    repo: RepoInfo;
    config: Config;
    patches: PaginatedQuery<Patch[]>;
-
    status?: PatchStatus;
+
    status: PatchStatus | undefined;
  };
}

@@ -118,6 +124,7 @@ export async function loadPatch(
    }),
    invoke<PaginatedQuery<Patch[]>>("list_patches", {
      rid: route.rid,
+
      status: route.status,
    }),
    invoke<Patch>("patch_by_id", {
      rid: route.rid,
@@ -131,7 +138,7 @@ export async function loadPatch(

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

@@ -165,13 +172,13 @@ export async function loadCreateIssue(
    }),
    invoke<Issue[]>("list_issues", {
      rid: route.rid,
-
      status: "all",
+
      status: route.status,
    }),
  ]);

  return {
    resource: "repo.createIssue",
-
    params: { repo, config, issues },
+
    params: { repo, config, issues, status: route.status },
  };
}

@@ -194,7 +201,7 @@ export async function loadIssue(
    }),
    invoke<Issue[]>("list_issues", {
      rid: route.rid,
-
      status: "all",
+
      status: route.status,
    }),
    invoke<Thread[]>("comment_threads_by_issue_id", {
      rid: route.rid,
@@ -204,7 +211,15 @@ export async function loadIssue(

  return {
    resource: "repo.issue",
-
    params: { repo, config, issue, activity, issues, threads },
+
    params: {
+
      repo,
+
      config,
+
      issue,
+
      activity,
+
      issues,
+
      threads,
+
      status: route.status,
+
    },
  };
}

@@ -230,27 +245,32 @@ export async function loadIssues(

export function repoRouteToPath(route: RepoRoute): string {
  const pathSegments = ["/repos", route.rid];
+
  const searchParams = new URLSearchParams();

  if (route.resource === "repo.issue") {
-
    const url = [...pathSegments, "issues", route.issue].join("/");
+
    let url = [...pathSegments, "issues", route.issue].join("/");
+
    searchParams.set("status", route.status);
+
    url += `?${searchParams}`;
    return url;
  } else if (route.resource === "repo.createIssue") {
-
    const url = [...pathSegments, "issues", "create"].join("/");
+
    let url = [...pathSegments, "issues", "create"].join("/");
+
    searchParams.set("status", route.status);
+
    url += `?${searchParams}`;
    return url;
  } else if (route.resource === "repo.issues") {
    let url = [...pathSegments, "issues"].join("/");
-
    const searchParams = new URLSearchParams();
+
    searchParams.set("status", route.status);
+
    url += `?${searchParams}`;
+
    return url;
+
  } else if (route.resource === "repo.patch") {
+
    let url = [...pathSegments, "patches", route.patch].join("/");
    if (route.status) {
      searchParams.set("status", route.status);
      url += `?${searchParams}`;
    }
    return url;
-
  } else if (route.resource === "repo.patch") {
-
    const url = [...pathSegments, "patches", route.patch].join("/");
-
    return url;
  } else if (route.resource === "repo.patches") {
    let url = [...pathSegments, "patches"].join("/");
-
    const searchParams = new URLSearchParams();
    if (route.status) {
      searchParams.set("status", route.status);
      url += `?${searchParams}`;
@@ -272,13 +292,15 @@ export function repoUrlToRoute(
    if (resource === "issues") {
      const idOrAction = segments.shift();
      if (idOrAction) {
+
        const status = (searchParams.get("status") ?? "all") as IssueStatus;
        if (idOrAction === "create") {
-
          return { resource: "repo.createIssue", rid };
+
          return { resource: "repo.createIssue", rid, status };
        } else {
          return {
            resource: "repo.issue",
            rid,
            issue: idOrAction,
+
            status,
          };
        }
      } else {
@@ -291,24 +313,18 @@ export function repoUrlToRoute(
      }
    } else if (resource === "patches") {
      const id = segments.shift();
+
      const status = (searchParams.get("status") ?? undefined) as
+
        | PatchStatus
+
        | undefined;
      if (id) {
        return {
          resource: "repo.patch",
          rid,
          patch: id,
+
          status,
        };
      } else {
-
        const status = searchParams.get("status");
-
        if (
-
          status === "draft" ||
-
          status === "open" ||
-
          status === "archived" ||
-
          status === "merged"
-
        ) {
-
          return { resource: "repo.patches", rid, status };
-
        } else {
-
          return { resource: "repo.patches", rid };
-
        }
+
        return { resource: "repo.patches", rid, status };
      }
    } else {
      return null;