mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-10-29 00:10:47 +08:00
Add revision selector
This commit is contained in:
@@ -1,10 +1,8 @@
|
||||
<script lang="ts">
|
||||
import type { Action } from "@bindings/cob/patch/Action";
|
||||
import type { Author } from "@bindings/cob/Author";
|
||||
import type { Config } from "@bindings/config/Config";
|
||||
import type { Diff } from "@bindings/diff/Diff";
|
||||
import type { Embed } from "@bindings/cob/thread/Embed";
|
||||
import type { Operation } from "@bindings/cob/Operation";
|
||||
import type { Revision } from "@bindings/cob/patch/Revision";
|
||||
import type { Thread } from "@bindings/cob/thread/Thread";
|
||||
|
||||
@@ -21,7 +19,6 @@
|
||||
import CommentComponent from "@app/components/Comment.svelte";
|
||||
import CommentToggleInput from "@app/components/CommentToggleInput.svelte";
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import PatchTimeline from "@app/components/PatchTimeline.svelte";
|
||||
import ThreadComponent from "@app/components/Thread.svelte";
|
||||
|
||||
interface Props {
|
||||
@@ -30,26 +27,17 @@
|
||||
patchId: string;
|
||||
revision: Revision;
|
||||
config: Config;
|
||||
activity: Operation<Action>[];
|
||||
reload: () => Promise<void>;
|
||||
}
|
||||
|
||||
/* eslint-disable prefer-const */
|
||||
let {
|
||||
rid,
|
||||
repoDelegates,
|
||||
patchId,
|
||||
revision,
|
||||
config,
|
||||
activity,
|
||||
reload,
|
||||
}: Props = $props();
|
||||
let { rid, repoDelegates, patchId, revision, config, reload }: Props =
|
||||
$props();
|
||||
/* eslint-enable prefer-const */
|
||||
|
||||
let focusReply: boolean = $state(false);
|
||||
let hideChanges = $state(false);
|
||||
let hideDiscussion = $state(false);
|
||||
let hideTimeline = $state(false);
|
||||
let topLevelReplyOpen = $state(false);
|
||||
|
||||
const threads = $derived(
|
||||
@@ -78,7 +66,6 @@
|
||||
|
||||
hideDiscussion = false;
|
||||
hideChanges = false;
|
||||
hideTimeline = false;
|
||||
});
|
||||
|
||||
async function editRevision(
|
||||
@@ -350,19 +337,3 @@
|
||||
{/await}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<div
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class="txt-semibold global-flex"
|
||||
style:margin="1rem 0"
|
||||
style:cursor="pointer"
|
||||
onclick={() => (hideTimeline = !hideTimeline)}>
|
||||
<Icon name={hideTimeline ? "chevron-right" : "chevron-down"} />Timeline
|
||||
</div>
|
||||
<div class:hide={hideTimeline}>
|
||||
<PatchTimeline {activity} {patchId} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -37,6 +37,7 @@
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
padding: 5px 0;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.active {
|
||||
|
||||
+150
-11
@@ -9,9 +9,13 @@
|
||||
import type { RepoInfo } from "@bindings/repo/RepoInfo";
|
||||
import type { Revision } from "@bindings/cob/patch/Revision";
|
||||
|
||||
import uniqBy from "lodash/uniqBy";
|
||||
import orderBy from "lodash/orderBy";
|
||||
|
||||
import * as roles from "@app/lib/roles";
|
||||
import { announce } from "@app/components/AnnounceSwitch.svelte";
|
||||
import {
|
||||
authorForNodeId,
|
||||
formatOid,
|
||||
patchStatusBackgroundColor,
|
||||
patchStatusColor,
|
||||
@@ -33,6 +37,13 @@
|
||||
import Sidebar from "@app/components/Sidebar.svelte";
|
||||
import Tab from "@app/components/Tab.svelte";
|
||||
import TextInput from "@app/components/TextInput.svelte";
|
||||
import NakedButton from "@app/components/NakedButton.svelte";
|
||||
import Popover, { closeFocused } from "@app/components/Popover.svelte";
|
||||
import DropdownList from "@app/components/DropdownList.svelte";
|
||||
import DropdownListItem from "@app/components/DropdownListItem.svelte";
|
||||
import NodeId from "@app/components/NodeId.svelte";
|
||||
import Avatar from "@app/components/Avatar.svelte";
|
||||
import PatchTimeline from "@app/components/PatchTimeline.svelte";
|
||||
|
||||
interface Props {
|
||||
repo: RepoInfo;
|
||||
@@ -65,6 +76,24 @@
|
||||
let labelSaveInProgress: boolean = $state(false);
|
||||
let assigneesSaveInProgress: boolean = $state(false);
|
||||
let tab: "patch" | "revisions" = $state("patch");
|
||||
let hideTimeline = $state(false);
|
||||
let selectedRevision: Revision = $state(revisions.slice(-1)[0]);
|
||||
const revisionAuthors = $derived(
|
||||
orderBy(
|
||||
uniqBy(
|
||||
revisions.map(r => {
|
||||
return r.author;
|
||||
}),
|
||||
"did",
|
||||
),
|
||||
[
|
||||
o => {
|
||||
return o.did === patch.author.did;
|
||||
},
|
||||
],
|
||||
["desc"],
|
||||
),
|
||||
);
|
||||
|
||||
$effect(() => {
|
||||
items = patches.content;
|
||||
@@ -79,6 +108,8 @@
|
||||
tab = "patch";
|
||||
editingTitle = false;
|
||||
updatedTitle = patch.title;
|
||||
selectedRevision = revisions.slice(-1)[0];
|
||||
hideTimeline = false;
|
||||
});
|
||||
|
||||
const project = $derived(repo.payloads["xyz.radicle.project"]!);
|
||||
@@ -257,7 +288,7 @@
|
||||
padding-bottom: 1rem;
|
||||
}
|
||||
.content {
|
||||
padding: 1rem 1rem 1rem 0;
|
||||
padding: 1rem 1rem 0 0;
|
||||
}
|
||||
|
||||
.metadata-divider {
|
||||
@@ -279,6 +310,12 @@
|
||||
margin-bottom: 0.5rem;
|
||||
color: var(--color-foreground-dim);
|
||||
}
|
||||
.dropdown-group:not(:last-of-type) {
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
</style>
|
||||
|
||||
<Layout {loadMoreSecondColumn} publicKey={config.publicKey}>
|
||||
@@ -419,6 +456,9 @@
|
||||
style:z-index="10"
|
||||
style:gap="1rem"
|
||||
style:padding="0 1rem">
|
||||
<span class="txt-small" style:color="var(--color-foreground-dim)">
|
||||
Revisions
|
||||
</span>
|
||||
<Tab
|
||||
active={tab === "patch"}
|
||||
onclick={() => {
|
||||
@@ -438,14 +478,99 @@
|
||||
onclick={() => {
|
||||
tab = "revisions";
|
||||
}}>
|
||||
{formatOid(revisions.slice(-1)[0].id)}
|
||||
<span
|
||||
class="global-counter"
|
||||
style:height="22px"
|
||||
style:color="var(--color-foreground-contrast)">
|
||||
Latest
|
||||
</span>
|
||||
<Avatar
|
||||
publicKey={selectedRevision.author.did.replace(
|
||||
"did:key:",
|
||||
"",
|
||||
)} />
|
||||
{formatOid(selectedRevision.id)}
|
||||
{#if selectedRevision.id === revisions.slice(-1)[0].id}
|
||||
<span
|
||||
class="global-counter"
|
||||
style:height="22px"
|
||||
style:color="var(--color-foreground-contrast)">
|
||||
Latest
|
||||
</span>
|
||||
{/if}
|
||||
{#if selectedRevision.id === revisions[0].id}
|
||||
<span
|
||||
class="global-counter"
|
||||
style:height="22px"
|
||||
style:color="var(--color-foreground-contrast)">
|
||||
Initial
|
||||
</span>
|
||||
{/if}
|
||||
</Tab>
|
||||
|
||||
<Popover
|
||||
popoverPadding="0"
|
||||
popoverPositionTop="2.5rem"
|
||||
popoverPositionLeft="0">
|
||||
{#snippet toggle(onclick)}
|
||||
<NakedButton variant="ghost" {onclick}>
|
||||
<Icon name="chevron-down" />
|
||||
</NakedButton>
|
||||
{/snippet}
|
||||
|
||||
{#snippet popover()}
|
||||
<Border variant="ghost">
|
||||
<div style:max-width="20rem" style:padding-top="0.5rem">
|
||||
{#each revisionAuthors as author}
|
||||
<div class="dropdown-group">
|
||||
<div
|
||||
style:padding-left="0.5rem"
|
||||
style:padding-bottom="0.5rem">
|
||||
<NodeId {...authorForNodeId(author)} />
|
||||
</div>
|
||||
<DropdownList
|
||||
items={orderBy(
|
||||
revisions.filter(r => {
|
||||
return r.author.did === author.did;
|
||||
}),
|
||||
"timestamp",
|
||||
["desc"],
|
||||
)}>
|
||||
{#snippet item(revision)}
|
||||
<DropdownListItem
|
||||
selected={revision.id === selectedRevision.id}
|
||||
onclick={() => {
|
||||
closeFocused();
|
||||
selectedRevision = revision;
|
||||
tab = "revisions";
|
||||
}}>
|
||||
<div class="global-flex txt-overflow">
|
||||
<span class="global-oid">
|
||||
{formatOid(revision.id)}
|
||||
</span>
|
||||
{#if revision.id === revisions.slice(-1)[0].id}
|
||||
<span
|
||||
class="global-counter"
|
||||
style:height="22px"
|
||||
style:color="var(--color-foreground-contrast)">
|
||||
Latest
|
||||
</span>
|
||||
{/if}
|
||||
{#if revision.id === revisions[0].id}
|
||||
<span
|
||||
class="global-counter"
|
||||
style:height="22px"
|
||||
style:color="var(--color-foreground-contrast)">
|
||||
Initial
|
||||
</span>
|
||||
{/if}
|
||||
<span class="txt-overflow">
|
||||
{revision.description[0].body}
|
||||
</span>
|
||||
</div>
|
||||
</DropdownListItem>
|
||||
{/snippet}
|
||||
</DropdownList>
|
||||
</div>
|
||||
{/each}
|
||||
</div>
|
||||
</Border>
|
||||
{/snippet}
|
||||
</Popover>
|
||||
{/if}
|
||||
</div>
|
||||
</Border>
|
||||
@@ -465,7 +590,6 @@
|
||||
repoDelegates={repo.delegates}
|
||||
patchId={patch.id}
|
||||
{reload}
|
||||
{activity}
|
||||
revision={revisions[0]}
|
||||
{config} />
|
||||
</Border>
|
||||
@@ -483,10 +607,25 @@
|
||||
repoDelegates={repo.delegates}
|
||||
patchId={patch.id}
|
||||
{reload}
|
||||
{activity}
|
||||
revision={revisions.slice(-1)[0]}
|
||||
revision={selectedRevision}
|
||||
{config} />
|
||||
</Border>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<div style:margin-bottom="1rem">
|
||||
<!-- svelte-ignore a11y_click_events_have_key_events -->
|
||||
<div
|
||||
role="button"
|
||||
tabindex="0"
|
||||
class="txt-semibold global-flex"
|
||||
style:margin="1rem 0"
|
||||
style:cursor="pointer"
|
||||
onclick={() => (hideTimeline = !hideTimeline)}>
|
||||
<Icon name={hideTimeline ? "chevron-right" : "chevron-down"} />Timeline
|
||||
</div>
|
||||
<div class:hide={hideTimeline}>
|
||||
<PatchTimeline {activity} patchId={patch.id} />
|
||||
</div>
|
||||
</div>
|
||||
</Layout>
|
||||
|
||||
Reference in New Issue
Block a user