Tweak copyable IDs

This commit is contained in:
Rūdolfs Ošiņš
2024-06-12 15:49:03 +02:00
parent adc6c6c290
commit 6d87823ce0
24 changed files with 225 additions and 269 deletions
+3 -7
View File
@@ -9,6 +9,7 @@
import ExtendedTextarea from "@app/components/ExtendedTextarea.svelte";
import IconButton from "@app/components/IconButton.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import Id from "@app/components/Id.svelte";
import Markdown from "@app/components/Markdown.svelte";
import NodeId from "@app/components/NodeId.svelte";
import ReactionSelector from "@app/components/ReactionSelector.svelte";
@@ -136,15 +137,10 @@
{/if}
<div class="card-header" class:card-header-no-icon={isReply}>
<slot class="icon" name="icon" />
<NodeId
stylePopoverPositionLeft="-13px"
nodeId={authorId}
alias={authorAlias} />
<NodeId nodeId={authorId} alias={authorAlias} />
<slot name="caption">{caption}</slot>
{#if id}
<span class="global-oid">
{utils.formatObjectId(id)}
</span>
<Id {id} />
{/if}
<span class="timestamp" title={utils.absoluteTimestamp(timestamp)}>
{utils.formatTimestamp(timestamp)}
-42
View File
@@ -1,42 +0,0 @@
<script lang="ts">
import type { SvelteComponent } from "svelte";
import Clipboard from "@app/components/Clipboard.svelte";
export let id: string;
export let style: "commit" | "oid";
let clipboard: SvelteComponent;
</script>
<style>
.id {
cursor: pointer;
color: var(--color-foreground-emphasized);
overflow-wrap: anywhere;
display: flex;
align-items: center;
gap: 0.125rem;
width: fit-content;
}
.id:hover {
color: var(--color-foreground-emphasized-hover);
}
</style>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
role="button"
tabindex="0"
on:click={() => {
clipboard.copy();
}}
class="id">
<span
class="txt-overflow"
class:global-commit={style === "commit"}
class:global-oid={style === "oid"}
style="color: inherit">
<slot>{id}</slot>
</span>
<Clipboard bind:this={clipboard} text={id} />
</div>
+6 -20
View File
@@ -1,32 +1,26 @@
<script lang="ts">
import debounce from "lodash/debounce";
// eslint-disable-next-line @typescript-eslint/no-empty-function
export let onShow: () => void = () => {};
export let stylePopoverPositionLeft: string | undefined = undefined;
export let stylePopoverPositionRight: string | undefined = undefined;
export let stylePopoverPositionTop: string | undefined = undefined;
export let stylePopoverPositionBottom: string | undefined = undefined;
export let stylePopoverPadding: string | undefined = "1rem";
export let stylePopoverPositionLeft: string | undefined = undefined;
let visible: boolean = false;
const setVisible = debounce((value: boolean) => {
visible = value;
if (visible) {
onShow();
}
}, 500);
}, 50);
</script>
<style>
.container {
position: relative;
display: inline-block;
}
.popover {
background: var(--color-background-float);
border-radius: var(--border-radius-regular);
border: 1px solid var(--color-border-hint);
padding: 1rem;
box-shadow: var(--elevation-low);
position: absolute;
z-index: 10;
@@ -42,19 +36,11 @@
<slot name="toggle" />
{#if visible}
<!-- If this component is used inside a button (see `NodeId`, for example)
we don’t want clicks in the popover to trigger button actions. So we
stop propagation of click events. -->
<!-- svelte-ignore a11y-click-events-have-key-events -->
<!-- svelte-ignore a11y-no-static-element-interactions -->
<div style:position="absolute" on:click|stopPropagation>
<div style:position="absolute">
<div
class="popover"
style:padding={stylePopoverPadding}
style:left={stylePopoverPositionLeft}
style:right={stylePopoverPositionRight}
style:bottom={stylePopoverPositionBottom}
style:top={stylePopoverPositionTop}>
style:bottom={stylePopoverPositionBottom}>
<slot name="popover" />
</div>
</div>
+116
View File
@@ -0,0 +1,116 @@
<script lang="ts">
import type { ComponentProps } from "svelte";
import { debounce } from "lodash";
import { formatObjectId } from "@app/lib/utils";
import { toClipboard } from "@app/lib/utils";
import IconSmall from "./IconSmall.svelte";
export let id: string;
export let clipboard: string = id;
export let shorten: boolean = true;
export let style: "oid" | "commit" | "none" = "oid";
export let subject: string | undefined = undefined;
export let ariaLabel: string | undefined = undefined;
let icon: ComponentProps<IconSmall>["name"] = "clipboard";
const text = subject ? `Click to copy ${subject}` : "Click to copy";
let tooltip = text;
const restoreIcon = debounce(() => {
icon = "clipboard";
tooltip = text;
visible = false;
}, 1000);
async function copy() {
await toClipboard(clipboard);
icon = "checkmark";
tooltip = "Copied to clipboard";
restoreIcon();
}
let visible: boolean = false;
export let debounceTimeout = 50;
const setVisible = debounce((value: boolean) => {
visible = value;
}, debounceTimeout);
</script>
<style>
.container {
position: relative;
display: inline-block;
}
.popover {
position: absolute;
bottom: 1.5rem;
left: 0;
display: flex;
align-items: center;
flex-direction: row;
gap: 0.5rem;
justify-content: center;
z-index: 10;
background: var(--color-background-float);
color: var(--color-foreground-default);
border: 1px solid var(--color-border-hint);
border-radius: var(--border-radius-small);
box-shadow: var(--elevation-low);
font-family: var(--font-family-sans-serif);
font-size: var(--font-size-small);
font-weight: var(--font-weight-regular);
white-space: nowrap;
padding: 0.25rem 0.5rem;
}
.target-commit:hover {
color: var(--color-foreground-contrast);
}
.target-oid:hover {
color: var(--color-foreground-emphasized-hover);
}
</style>
<div class="container">
<div
role="button"
tabindex="0"
on:mouseenter={() => {
setVisible(true);
}}
on:mouseleave={() => {
setVisible(false);
}}>
<!-- svelte-ignore a11y-click-events-have-key-events -->
<div
class="target-{style} global-{style}"
style:cursor="pointer"
aria-label={ariaLabel}
on:click={async () => {
await copy();
setVisible(true);
}}
role="button"
tabindex="0">
<slot>
{#if shorten}
{formatObjectId(id)}
{:else}
{id}
{/if}
</slot>
</div>
{#if visible}
<div style:position="absolute">
<div class="popover">
<IconSmall name={icon} />
{tooltip}
</div>
</div>
{/if}
</div>
</div>
+4 -44
View File
@@ -2,13 +2,10 @@
import { formatNodeId } from "@app/lib/utils";
import Avatar from "./Avatar.svelte";
import HoverPopover from "./HoverPopover.svelte";
import CopyableId from "./CopyableId.svelte";
import Id from "./Id.svelte";
export let nodeId: string;
export let alias: string | undefined = undefined;
export let large: boolean = false;
export let stylePopoverPositionLeft = "-4.5rem";
</script>
<style>
@@ -22,32 +19,10 @@
font-weight: var(--font-weight-semibold);
font-size: var(--font-size-small);
}
.large {
height: 1.25rem;
gap: 0.5rem;
}
.popover-avatar {
height: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
font-family: var(--font-family-monospace);
font-weight: var(--font-weight-semibold);
font-size: var(--font-size-small);
white-space: nowrap;
}
.popover-container {
display: flex;
align-items: center;
gap: 1rem;
}
</style>
<HoverPopover
{stylePopoverPositionLeft}
stylePopoverPadding="0.5rem 0.5rem 0.5rem 0.75rem"
stylePopoverPositionTop="-4.5rem">
<div slot="toggle" class="avatar-alias" class:large>
<Id id={nodeId} subject={formatNodeId(nodeId)} style="none">
<div class="avatar-alias">
<Avatar {nodeId} />
{#if alias}
{alias}
@@ -55,19 +30,4 @@
{formatNodeId(nodeId)}
{/if}
</div>
<div slot="popover">
<div class="popover-container">
<div class="popover-avatar">
<Avatar {nodeId} />
{#if alias}
{alias}
{/if}
</div>
<CopyableId id={nodeId} style="oid">
{formatNodeId(nodeId)}
</CopyableId>
</div>
</div>
</HoverPopover>
</Id>
+17 -15
View File
@@ -11,9 +11,9 @@
import { isDelegate } from "@app/lib/roles";
import AppLayout from "@app/App/AppLayout.svelte";
import CopyableId from "@app/components/CopyableId.svelte";
import IconButton from "@app/components/IconButton.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import Id from "@app/components/Id.svelte";
import Loading from "@app/components/Loading.svelte";
import Popover from "@app/components/Popover.svelte";
import ProjectCard from "@app/components/ProjectCard.svelte";
@@ -128,25 +128,27 @@
{#each externalAddresses as address}
<!-- If there are externalAddresses this is probably a remote node -->
<!-- in that case, we show all the defined externalAddresses as a listing -->
<CopyableId id={`${nid}@${address}`} style="oid">
{truncateId(nid)}@{address}
</CopyableId>
<Id
ariaLabel="node-id"
shorten={false}
id="{truncateId(nid)}@{address}"
clipboard={`${nid}@${address}`} />
{:else}
<!-- else this is probably a local node -->
<!-- So we show only the nid -->
<CopyableId id={nid} style="oid">
<div class="global-hide-on-small-desktop-up">
{truncateId(nid)}
</div>
<div class="global-hide-on-mobile-down">
{nid}
</div>
</CopyableId>
<div class="global-hide-on-small-desktop-up">
<Id ariaLabel="node-id" id={truncateId(nid)} shorten={false} />
</div>
<div class="global-hide-on-mobile-down">
<Id ariaLabel="node-id" id={nid} shorten={false} />
</div>
{/each}
</div>
<div class="version">
{version}
</div>
<Id ariaLabel="version" id={version} shorten={false} style="none">
<div class="version">
{version}
</div>
</Id>
</div>
</div>
@@ -3,11 +3,11 @@
import { twemoji } from "@app/lib/utils";
import CommitLink from "@app/views/projects/components/CommitLink.svelte";
import CompactCommitAuthorship from "@app/components/CompactCommitAuthorship.svelte";
import ExpandButton from "@app/components/ExpandButton.svelte";
import IconButton from "@app/components/IconButton.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import Id from "@app/components/Id.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import Link from "@app/components/Link.svelte";
@@ -88,7 +88,7 @@
{/if}
<div class="global-hide-on-small-desktop-up">
<CompactCommitAuthorship {commit}>
<CommitLink {baseUrl} {projectId} commitId={commit.id} />
<Id id={commit.id} style="commit" />
</CompactCommitAuthorship>
</div>
</div>
@@ -96,7 +96,7 @@
<div style="display: flex; gap: 0.5rem; height: 21px; align-items: center;">
<div class="global-hide-on-mobile-down">
<CompactCommitAuthorship {commit}>
<CommitLink {baseUrl} {projectId} commitId={commit.id} />
<Id id={commit.id} style="commit" />
</CompactCommitAuthorship>
</div>
<IconButton title="Browse repo at this commit">
-1
View File
@@ -11,7 +11,6 @@
flex-wrap: wrap;
gap: 0.5rem;
font-size: var(--font-size-small);
font-family: var(--font-family-monospace);
}
.summary {
display: flex;
+9 -22
View File
@@ -18,7 +18,6 @@
import CobCommitTeaser from "@app/views/projects/Cob/CobCommitTeaser.svelte";
import CommentComponent from "@app/components/Comment.svelte";
import CommitLink from "@app/views/projects/components/CommitLink.svelte";
import DiffStatBadge from "@app/components/DiffStatBadge.svelte";
import DropdownList from "@app/components/DropdownList.svelte";
import DropdownListItem from "@app/components/DropdownList/DropdownListItem.svelte";
@@ -35,6 +34,7 @@
import ReactionSelector from "@app/components/ReactionSelector.svelte";
import Reactions from "@app/components/Reactions.svelte";
import Thread from "@app/components/Thread.svelte";
import Id from "@app/components/Id.svelte";
export let baseUrl: BaseUrl;
export let initiallyExpanded: boolean = false;
@@ -300,7 +300,7 @@
<ExpandButton {expanded} on:toggle={() => (expanded = !expanded)} />
<span>
Revision
<span class="global-oid">{utils.formatObjectId(revisionId)}</span>
<Id id={revisionId} />
</span>
</div>
<div class="revision-data">
@@ -409,21 +409,16 @@
style:padding="0 0.375rem">
<IconSmall name="patch" />
</div>
<NodeId
stylePopoverPositionLeft="-13px"
nodeId={revisionAuthor.id}
alias={revisionAuthor.alias} />
<NodeId nodeId={revisionAuthor.id} alias={revisionAuthor.alias} />
{#if patchId === revisionId}
opened this patch on base
<CommitLink {baseUrl} {projectId} commitId={revisionBase} />
<Id id={revisionBase} style="commit" />
{:else}
updated to
<span class="global-oid">
{utils.formatObjectId(revisionId)}
</span>
<Id id={revisionId} />
{#if previousRevBase && previousRevBase !== revisionBase}
with base
<CommitLink {baseUrl} {projectId} commitId={revisionBase} />
<Id id={revisionBase} style="commit" />
{/if}
{/if}
<span
@@ -556,20 +551,14 @@
</div>
<NodeId
stylePopoverPositionLeft="-13px"
nodeId={element.inner.author.id}
alias={element.inner.author.alias}>
</NodeId>
merged revision
<span class="global-oid">
{utils.formatObjectId(element.inner.revision)}
</span>
<Id id={element.inner.revision} />
at commit
<CommitLink
{baseUrl}
{projectId}
commitId={element.inner.commit} />
<Id id={element.inner.commit} style="commit" />
<span
class="timestamp"
title={utils.absoluteTimestamp(revisionTimestamp)}>
@@ -593,9 +582,7 @@
body={review.summary ?? ""}>
<div slot="caption">
{formatVerdict(review.verdict)}
<span class="global-oid">
{utils.formatObjectId(revisionId)}
</span>
<Id id={revisionId} />
</div>
<div slot="icon" style:color={verdictIconColor(review.verdict)}>
{#if review.verdict === "accept"}
+2 -6
View File
@@ -1,17 +1,15 @@
<script lang="ts">
import type { BaseUrl, Commit, Node, Project } from "@http-client";
import { formatCommit } from "@app/lib/utils";
import Button from "@app/components/Button.svelte";
import Changeset from "@app/views/projects/Changeset.svelte";
import CommitAuthorship from "@app/views/projects/Commit/CommitAuthorship.svelte";
import CopyableId from "@app/components/CopyableId.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import Layout from "./Layout.svelte";
import Link from "@app/components/Link.svelte";
import Share from "./Share.svelte";
import Id from "@app/components/Id.svelte";
export let baseUrl: BaseUrl;
export let node: Node;
@@ -73,9 +71,7 @@
</div>
</span>
<CommitAuthorship {header}>
<CopyableId id={header.id} style="commit">
{formatCommit(header.id)}
</CopyableId>
<Id id={header.id} style="commit" ariaLabel="commit-id" />
</CommitAuthorship>
</div>
{#if header.description}
@@ -4,12 +4,12 @@
import { twemoji } from "@app/lib/utils";
import CommitAuthorship from "./CommitAuthorship.svelte";
import CommitLink from "@app/views/projects/components/CommitLink.svelte";
import ExpandButton from "@app/components/ExpandButton.svelte";
import IconButton from "@app/components/IconButton.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import Link from "@app/components/Link.svelte";
import Id from "@app/components/Id.svelte";
export let baseUrl: BaseUrl;
export let commit: CommitHeader;
@@ -104,7 +104,7 @@
</div>
{/if}
<CommitAuthorship header={commit}>
<CommitLink {baseUrl} {projectId} commitId={commit.id} />
<Id id={commit.id} style="commit" />
</CommitAuthorship>
</div>
<div class="right">
+3 -8
View File
@@ -32,11 +32,11 @@
import CobHeader from "@app/views/projects/Cob/CobHeader.svelte";
import CobStateButton from "@app/views/projects/Cob/CobStateButton.svelte";
import CommentToggleInput from "@app/components/CommentToggleInput.svelte";
import CopyableId from "@app/components/CopyableId.svelte";
import Embeds from "@app/views/projects/Cob/Embeds.svelte";
import ErrorModal from "@app/modals/ErrorModal.svelte";
import ExtendedTextarea from "@app/components/ExtendedTextarea.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import Id from "@app/components/Id.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import LabelInput from "./Cob/LabelInput.svelte";
import Layout from "./Layout.svelte";
@@ -547,14 +547,9 @@
{issue.state.reason}
</Badge>
{/if}
<NodeId
stylePopoverPositionLeft="-13px"
nodeId={issue.author.id}
alias={issue.author.alias} />
<NodeId nodeId={issue.author.id} alias={issue.author.alias} />
opened
<CopyableId id={issue.id} style="oid">
{utils.formatObjectId(issue.id)}
</CopyableId>
<Id id={issue.id} />
<span title={utils.absoluteTimestamp(issue.discussion[0].timestamp)}>
{utils.formatTimestamp(issue.discussion[0].timestamp)}
</span>
+4 -10
View File
@@ -1,11 +1,7 @@
<script lang="ts">
import type { BaseUrl, Issue } from "@http-client";
import {
absoluteTimestamp,
formatObjectId,
formatTimestamp,
} from "@app/lib/utils";
import { absoluteTimestamp, formatTimestamp } from "@app/lib/utils";
import IconSmall from "@app/components/IconSmall.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
@@ -14,6 +10,7 @@
import CommentCounter from "../CommentCounter.svelte";
import Labels from "../Cob/Labels.svelte";
import Id from "@app/components/Id.svelte";
export let baseUrl: BaseUrl;
export let issue: Issue;
@@ -123,12 +120,9 @@
{/if}
<div
style="display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;">
<NodeId
stylePopoverPositionLeft="-13px"
nodeId={issue.author.id}
alias={issue.author.alias} />
<NodeId nodeId={issue.author.id} alias={issue.author.alias} />
opened
<span class="global-oid">{formatObjectId(issue.id)}</span>
<Id id={issue.id} />
<span title={absoluteTimestamp(issue.discussion[0].timestamp)}>
{formatTimestamp(issue.discussion[0].timestamp)}
</span>
+5 -10
View File
@@ -52,12 +52,13 @@
import * as role from "@app/lib/roles";
import * as router from "@app/lib/router";
import * as utils from "@app/lib/utils";
import { experimental } from "@app/lib/appearance";
import capitalize from "lodash/capitalize";
import isEqual from "lodash/isEqual";
import partial from "lodash/partial";
import uniqBy from "lodash/uniqBy";
import { HttpdClient } from "@http-client";
import { closeFocused } from "@app/components/Popover.svelte";
import { experimental } from "@app/lib/appearance";
import { httpdStore } from "@app/lib/httpd";
import { parseEmbedIntoMap } from "@app/lib/file";
@@ -68,12 +69,12 @@
import CobStateButton from "@app/views/projects/Cob/CobStateButton.svelte";
import CommentToggleInput from "@app/components/CommentToggleInput.svelte";
import CompareButton from "@app/views/projects/Patch/CompareButton.svelte";
import CopyableId from "@app/components/CopyableId.svelte";
import DiffStatBadge from "@app/components/DiffStatBadge.svelte";
import Embeds from "@app/views/projects/Cob/Embeds.svelte";
import ErrorModal from "@app/modals/ErrorModal.svelte";
import ExtendedTextarea from "@app/components/ExtendedTextarea.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import Id from "@app/components/Id.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import LabelInput from "@app/views/projects/Cob/LabelInput.svelte";
import Layout from "@app/views/projects/Layout.svelte";
@@ -89,7 +90,6 @@
import RevisionSelector from "@app/views/projects/Patch/RevisionSelector.svelte";
import Share from "@app/views/projects/Share.svelte";
import TextInput from "@app/components/TextInput.svelte";
import { closeFocused } from "@app/components/Popover.svelte";
export let baseUrl: BaseUrl;
export let node: Node;
@@ -775,14 +775,9 @@
insertions={stats.insertions}
deletions={stats.deletions} />
</Link>
<NodeId
stylePopoverPositionLeft="-13px"
nodeId={patch.author.id}
alias={patch.author.alias} />
<NodeId nodeId={patch.author.id} alias={patch.author.alias} />
opened
<CopyableId id={patch.id} style="oid">
{utils.formatObjectId(patch.id)}
</CopyableId>
<Id id={patch.id} />
<span title={utils.absoluteTimestamp(patch.revisions[0].timestamp)}>
{utils.formatTimestamp(patch.revisions[0].timestamp)}
</span>
+7 -15
View File
@@ -2,20 +2,17 @@
import type { BaseUrl } from "@http-client";
import type { Patch } from "@http-client";
import {
absoluteTimestamp,
formatObjectId,
formatTimestamp,
} from "@app/lib/utils";
import { absoluteTimestamp, formatTimestamp } from "@app/lib/utils";
import IconSmall from "@app/components/IconSmall.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import Link from "@app/components/Link.svelte";
import NodeId from "@app/components/NodeId.svelte";
import Labels from "../Cob/Labels.svelte";
import DiffStatBadgeLoader from "../DiffStatBadgeLoader.svelte";
import CommentCounter from "../CommentCounter.svelte";
import DiffStatBadgeLoader from "../DiffStatBadgeLoader.svelte";
import Id from "@app/components/Id.svelte";
import Labels from "../Cob/Labels.svelte";
export let projectId: string;
export let baseUrl: BaseUrl;
@@ -137,17 +134,12 @@
{/if}
<div
style="display: flex; align-items: center; gap: 0.5rem; flex-wrap: wrap;">
<NodeId
stylePopoverPositionLeft="-13px"
nodeId={patch.author.id}
alias={patch.author.alias} />
<NodeId nodeId={patch.author.id} alias={patch.author.alias} />
{patch.revisions.length > 1 ? "updated" : "opened"}
<span class="global-oid">{formatObjectId(patch.id)}</span>
<Id id={patch.id} />
{#if patch.revisions.length > 1}
<span class="global-hide-on-mobile-down">
to <span class="global-oid">
{formatObjectId(patch.revisions[patch.revisions.length - 1].id)}
</span>
to <Id id={patch.revisions[patch.revisions.length - 1].id} />
</span>
{/if}
<span title={absoluteTimestamp(latestRevision.timestamp)}>
+6 -1
View File
@@ -61,7 +61,12 @@
<ShareButton slot="popover" />
</Popover>
{:else}
<Button variant="outline" size="regular" on:click={copy}>
<Button
variant="outline"
size="regular"
on:click={async () => {
await copy();
}}>
<IconSmall name={shareIcon} />
<span class="global-hide-on-small-desktop-down">Copy link</span>
</Button>
@@ -1,13 +1,14 @@
<script lang="ts">
import type { BaseUrl, Node, Project } from "@http-client";
import { capitalize } from "lodash";
import { isLocal } from "@app/lib/utils";
import IconButton from "@app/components/IconButton.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import NodeId from "@app/components/NodeId.svelte";
import Popover from "@app/components/Popover.svelte";
import ScopePolicyExplainer from "@app/components/ScopePolicyExplainer.svelte";
import { isLocal } from "@app/lib/utils";
import { capitalize } from "lodash";
export let disablePopovers: boolean = false;
export let project: Project;
@@ -86,7 +87,7 @@
<div class="nids">
{#each project.delegates as { id: nodeId, alias }}
<div style:width="fit-content">
<NodeId {alias} {nodeId} stylePopoverPositionLeft="-0.8rem" />
<NodeId {alias} {nodeId} />
</div>
{/each}
</div>
@@ -119,11 +120,5 @@
policy={node.config.policy} />
</div>
{/if}
<div class="item txt-overflow" style:padding-top="0.5rem">
Radicle version
<span class="txt-missing txt-overflow txt-monospace" title={node.version}>
{node.version}
</span>
</div>
</div>
</div>
+13 -9
View File
@@ -6,15 +6,14 @@
import { formatNodeId } from "@app/lib/utils";
import { httpdStore } from "@app/lib/httpd";
import NodeId from "@app/components/NodeId.svelte";
import Avatar from "@app/components/Avatar.svelte";
import Badge from "@app/components/Badge.svelte";
import Button from "@app/components/Button.svelte";
import DropdownList from "@app/components/DropdownList.svelte";
import DropdownListItem from "@app/components/DropdownList/DropdownListItem.svelte";
import Popover from "@app/components/Popover.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import Link from "@app/components/Link.svelte";
import Button from "@app/components/Button.svelte";
import Avatar from "@app/components/Avatar.svelte";
import Popover from "@app/components/Popover.svelte";
export let peers: Array<{ remote: Remote; selected: boolean; route: Route }>;
export let project: Project;
@@ -48,22 +47,27 @@
popoverPositionTop="2.5rem"
popoverBorderRadius="var(--border-radius-small)">
<Button
ariaLabel="Change peer"
slot="toggle"
let:expanded
let:toggle
styleBorderRadius="var(--border-radius-tiny) 0 0 var(--border-radius-tiny)"
on:click={toggle}
title="Change peer"
title={selectedPeer ? formatNodeId(selectedPeer.id) : "Change peer"}
disabled={!peers}>
{#if !selectedPeer}
<IconSmall name="delegate" />
{/if}
{#if selectedPeer}
<NodeId
nodeId={selectedPeer.id}
alias={selectedPeer.alias}
stylePopoverPositionLeft="-0.75rem" />
<div style:height="1rem">
<Avatar nodeId={selectedPeer.id} />
</div>
<span
style:font-family="var(--font-family-monospace)"
class:no-alias={!selectedPeer.alias}>
{selectedPeer.alias || formatNodeId(selectedPeer.id)}
</span>
{#if selectedPeer.delegate}
<Badge size="tiny" variant="delegate">
<IconSmall name="badge" />
@@ -5,8 +5,8 @@
import Badge from "@app/components/Badge.svelte";
import CloneButton from "@app/views/projects/Header/CloneButton.svelte";
import CopyableId from "@app/components/CopyableId.svelte";
import IconSmall from "@app/components/IconSmall.svelte";
import Id from "@app/components/Id.svelte";
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
import Link from "@app/components/Link.svelte";
import SeedButton from "@app/views/projects/Header/SeedButton.svelte";
@@ -90,7 +90,7 @@
</div>
</div>
<div class="id">
<CopyableId id={project.id} style="oid" />
<Id shorten={false} id={project.id} ariaLabel="project-id" />
</div>
</div>
<div class="description" use:twemoji>
@@ -1,22 +0,0 @@
<script lang="ts">
import type { BaseUrl } from "@http-client";
import { formatCommit } from "@app/lib/utils";
import Link from "@app/components/Link.svelte";
export let baseUrl: BaseUrl;
export let projectId: string;
export let commitId: string;
</script>
<Link
route={{
resource: "project.commit",
node: baseUrl,
project: projectId,
commit: commitId,
}}>
<span class="global-commit">
{formatCommit(commitId)}
</span>
</Link>
+2 -2
View File
@@ -33,7 +33,7 @@ test("copy to clipboard", async ({ page, browserName, context }) => {
// Project ID.
{
await page.locator(".id > .clipboard").click();
await page.getByLabel("project-id").click();
const clipboardContent = await page.evaluate<string>(
"navigator.clipboard.readText()",
);
@@ -63,7 +63,7 @@ test("copy to clipboard", async ({ page, browserName, context }) => {
await page.goto("/nodes/radicle.local");
// Node address.
{
await page.locator(".clipboard").first().click();
await page.getByRole("button", { name: "node-id" }).first().click();
await expectClipboard(`${nodeRemote}`, page);
}
+9 -9
View File
@@ -288,13 +288,13 @@ test("peer and branch switching", async ({ page }) => {
// Alice's peer.
{
await page.getByTitle("Change peer").click();
await page.getByLabel("Change peer").click();
await page
.getByRole("link", {
name: "alice delegate",
})
.click();
await expect(page.getByTitle("Change peer")).toHaveText("alice Delegate");
await expect(page.getByLabel("Change peer")).toHaveText("alice Delegate");
// Default `main` branch.
{
@@ -356,8 +356,8 @@ test("peer and branch switching", async ({ page }) => {
{
await page.getByRole("link", { name: "source-browsing" }).nth(1).click();
await expect(page.getByTitle("Change peer")).not.toContainText("alice");
await expect(page.getByTitle("Change peer")).not.toContainText("bob");
await expect(page.getByLabel("Change peer")).not.toContainText("alice");
await expect(page.getByLabel("Change peer")).not.toContainText("bob");
await expect(page.getByTitle("Change branch")).toBeVisible();
await expect(
@@ -372,10 +372,10 @@ test("peer and branch switching", async ({ page }) => {
// Bob's peer.
{
await page.getByTitle("Change peer").click();
await page.getByLabel("Change peer").click();
await page.getByRole("link", { name: "bob" }).click();
await expect(page.getByTitle("Change peer")).toContainText("bob");
await expect(page.getByTitle("Change peer")).not.toHaveText("delegate");
await expect(page.getByLabel("Change peer")).toContainText("bob");
await expect(page.getByLabel("Change peer")).not.toHaveText("delegate");
// Default `main` branch.
{
@@ -402,7 +402,7 @@ test("peer and branch switching", async ({ page }) => {
test("only one modal can be open at a time", async ({ page }) => {
await page.goto(sourceBrowsingUrl);
await page.getByTitle("Change peer").click();
await page.getByLabel("Change peer").click();
await page
.getByRole("link", {
name: "alice delegate",
@@ -427,7 +427,7 @@ test("only one modal can be open at a time", async ({ page }) => {
await expect(page.getByText("bob")).not.toBeVisible();
await expect(page.getByText("feature/branch")).toBeVisible();
await page.getByTitle("Change peer").click();
await page.getByLabel("Change peer").click();
await expect(page.getByText("Code font")).not.toBeVisible();
await expect(page.getByText("Use the Radicle CLI")).not.toBeVisible();
await expect(page.getByText("bob")).toBeVisible();
+2 -4
View File
@@ -13,7 +13,7 @@ const commitUrl = `${sourceBrowsingUrl}/commits/${bobHead}`;
test("navigation from commit list", async ({ page }) => {
await page.goto(sourceBrowsingUrl);
await page.getByTitle("Change peer").click();
await page.getByLabel("Change peer").click();
await page.getByRole("link", { name: "bob" }).click();
await page
.getByRole("link", { name: `Commits ${bobMainCommitCount}` })
@@ -43,9 +43,7 @@ test("modified file", async ({ page }) => {
// Commit header.
{
await expect(page.getByText("Update readme")).toBeVisible();
await expect(
page.getByRole("button", { name: shortBobHead }),
).toBeVisible();
await expect(page.getByLabel("commit-id")).toHaveText(shortBobHead);
}
// Diff header.
+6 -6
View File
@@ -20,14 +20,14 @@ test("peer and branch switching", async ({ page }) => {
// Alice's peer.
{
await page.getByTitle("Change peer").click();
await page.getByLabel("Change peer").click();
await page
.getByRole("link", {
name: "alice delegate",
})
.click();
await expect(page.getByTitle("Change peer")).toHaveText("alice Delegate");
await expect(page.getByLabel("Change peer")).toHaveText("alice Delegate");
await expect(page.getByText("Thursday, November 17, 2022")).toBeVisible();
await expect(page.locator(".list .teaser")).toHaveCount(
@@ -65,10 +65,10 @@ test("peer and branch switching", async ({ page }) => {
// Bob's peer.
{
await page.getByTitle("Change peer").click();
await page.getByLabel("Change peer").click();
await page.getByRole("link", { name: "bob" }).click();
await expect(page.getByTitle("Change peer")).toContainText("bob");
await expect(page.getByLabel("Change peer")).toContainText("bob");
await expect(page.getByText("Wednesday, December 21, 2022")).toBeVisible();
await expect(page.locator(".list").first().locator(".teaser")).toHaveCount(
@@ -155,9 +155,9 @@ test("relative timestamps", async ({ page }) => {
.getByRole("link", { name: `Commits ${aliceMainCommitCount}` })
.click();
await page.getByTitle("Change peer").click();
await page.getByLabel("Change peer").click();
await page.getByRole("link", { name: "bob" }).click();
await expect(page.getByTitle("Change peer")).toHaveText("bob");
await expect(page.getByLabel("Change peer")).toHaveText("bob");
const latestCommit = page.locator(".teaser").first();
await expect(latestCommit).toContainText(
`Bob Belcher committed ${shortBobHead} now`,