mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-10-24 22:30:35 +08:00
Refactor CobHeader
This commit is contained in:
@@ -1,35 +1,7 @@
|
||||
<script lang="ts" strictEvents>
|
||||
import { createEventDispatcher } from "svelte";
|
||||
|
||||
<script lang="ts">
|
||||
import * as utils from "@app/lib/utils";
|
||||
|
||||
import IconSmall from "@app/components/IconSmall.svelte";
|
||||
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
|
||||
import TextInput from "@app/components/TextInput.svelte";
|
||||
import IconButton from "@app/components/IconButton.svelte";
|
||||
|
||||
export let preview: boolean = false;
|
||||
export let mode: "readCreate" | "readWrite" | "readOnly" = "readOnly";
|
||||
export let id: string | undefined = undefined;
|
||||
export let title: string = "";
|
||||
export let editTitle: ((title: string) => Promise<void>) | undefined =
|
||||
undefined;
|
||||
|
||||
async function handleTitleEdit() {
|
||||
if (editTitle) {
|
||||
mode = "readOnly";
|
||||
submitNewTitle = true;
|
||||
try {
|
||||
await editTitle(title);
|
||||
} finally {
|
||||
submitNewTitle = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const dispatch = createEventDispatcher<{ refresh: null }>();
|
||||
|
||||
let submitNewTitle = false;
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -40,17 +12,6 @@
|
||||
padding: 1.5rem;
|
||||
border-radius: var(--border-radius-small);
|
||||
}
|
||||
.title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: var(--font-size-large);
|
||||
font-weight: var(--font-weight-medium);
|
||||
height: 2.5rem;
|
||||
}
|
||||
.subtitle {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
@@ -72,58 +33,11 @@
|
||||
margin-top: 1rem;
|
||||
word-break: break-word;
|
||||
}
|
||||
.edit-buttons {
|
||||
display: flex;
|
||||
gap: 0.25rem;
|
||||
}
|
||||
</style>
|
||||
|
||||
<div class="header">
|
||||
<div class="summary">
|
||||
{#if (editTitle && !preview && mode === "readWrite") || (!preview && mode === "readCreate")}
|
||||
<div><slot name="icon" /></div>
|
||||
<TextInput
|
||||
placeholder="Title"
|
||||
bind:value={title}
|
||||
showKeyHint={mode === "readWrite" && Boolean(id)}
|
||||
on:submit={handleTitleEdit} />
|
||||
{:else if title}
|
||||
<div class="title">
|
||||
<div><slot name="icon" /></div>
|
||||
<InlineMarkdown fontSize="medium" content={title} />
|
||||
</div>
|
||||
{:else}
|
||||
<span class="txt-missing">No title</span>
|
||||
{/if}
|
||||
<!-- When creating a new COB id is undefined -->
|
||||
{#if editTitle && id}
|
||||
<div class="edit-buttons">
|
||||
{#if mode === "readWrite"}
|
||||
<IconButton
|
||||
title="save title"
|
||||
loading={submitNewTitle}
|
||||
on:click={handleTitleEdit}>
|
||||
<IconSmall name={"checkmark"} />
|
||||
</IconButton>
|
||||
<IconButton
|
||||
title="dismiss changes"
|
||||
loading={submitNewTitle}
|
||||
on:click={() => {
|
||||
dispatch("refresh");
|
||||
mode = "readOnly";
|
||||
}}>
|
||||
<IconSmall name={"cross"} />
|
||||
</IconButton>
|
||||
{:else}
|
||||
<IconButton
|
||||
title="edit title"
|
||||
loading={submitNewTitle}
|
||||
on:click={() => (mode = "readWrite")}>
|
||||
<IconSmall name={"edit"} />
|
||||
</IconButton>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<slot name="title" />
|
||||
</div>
|
||||
<div class="subtitle">
|
||||
<slot name="state" />
|
||||
|
||||
@@ -25,12 +25,14 @@
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import IconButton from "@app/components/IconButton.svelte";
|
||||
import IconSmall from "@app/components/IconSmall.svelte";
|
||||
import InlineMarkdown from "@app/components/InlineMarkdown.svelte";
|
||||
import LabelInput from "./Cob/LabelInput.svelte";
|
||||
import Layout from "./Layout.svelte";
|
||||
import Markdown from "@app/components/Markdown.svelte";
|
||||
import NodeId from "@app/components/NodeId.svelte";
|
||||
import ReactionSelector from "@app/components/ReactionSelector.svelte";
|
||||
import Reactions from "@app/components/Reactions.svelte";
|
||||
import TextInput from "@app/components/TextInput.svelte";
|
||||
import ThreadComponent from "@app/components/Thread.svelte";
|
||||
|
||||
export let baseUrl: BaseUrl;
|
||||
@@ -192,7 +194,13 @@
|
||||
}
|
||||
}
|
||||
|
||||
async function editTitle(sessionId: string, title: string) {
|
||||
async function editIssue(
|
||||
sessionId: string,
|
||||
title: string,
|
||||
id: string,
|
||||
body: string,
|
||||
embeds: Embed[],
|
||||
) {
|
||||
try {
|
||||
await api.project.updateIssue(
|
||||
project.id,
|
||||
@@ -200,12 +208,18 @@
|
||||
{ type: "edit", title },
|
||||
sessionId,
|
||||
);
|
||||
await api.project.updateIssue(
|
||||
project.id,
|
||||
issue.id,
|
||||
{ type: "comment.edit", id, body, embeds },
|
||||
sessionId,
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
modal.show({
|
||||
component: ErrorModal,
|
||||
props: {
|
||||
title: "Issue title editing failed",
|
||||
title: "Issue editing failed",
|
||||
subtitle: [
|
||||
"There was an error while updating the issue.",
|
||||
"Check your radicle-httpd logs for details.",
|
||||
@@ -374,7 +388,7 @@
|
||||
|
||||
let assigneeState: State = "read";
|
||||
let labelState: State = "read";
|
||||
let descriptionState: State = "read";
|
||||
let issueState: State = "read";
|
||||
</script>
|
||||
|
||||
<style>
|
||||
@@ -407,6 +421,17 @@
|
||||
flex-wrap: nowrap;
|
||||
gap: 0.5rem;
|
||||
}
|
||||
.title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: var(--font-size-large);
|
||||
font-weight: var(--font-weight-medium);
|
||||
height: 2.5rem;
|
||||
}
|
||||
.reactions {
|
||||
display: flex;
|
||||
gap: 0.5rem;
|
||||
@@ -440,24 +465,39 @@
|
||||
<Layout {baseUrl} {project} {tracking} activeTab="issues">
|
||||
<div class="issue">
|
||||
<div style="display: flex; flex-direction: column; gap: 1.5rem;">
|
||||
<CobHeader
|
||||
id={issue.id}
|
||||
title={issue.title}
|
||||
editTitle={session &&
|
||||
role.isDelegateOrAuthor(
|
||||
session.publicKey,
|
||||
project.delegates,
|
||||
issue.author.id,
|
||||
) &&
|
||||
partial(editTitle, session.id)}
|
||||
on:refresh={refreshIssue}>
|
||||
<svelte:fragment slot="icon">
|
||||
<div
|
||||
class="state"
|
||||
class:closed={issue.state.status === "closed"}
|
||||
class:open={issue.state.status === "open"}>
|
||||
<Icon name="issue" />
|
||||
</div>
|
||||
<CobHeader id={issue.id}>
|
||||
<svelte:fragment slot="title">
|
||||
{#if issueState !== "read"}
|
||||
<div
|
||||
class="state"
|
||||
class:closed={issue.state.status === "closed"}
|
||||
class:open={issue.state.status === "open"}>
|
||||
<Icon name="issue" />
|
||||
</div>
|
||||
<TextInput
|
||||
placeholder="Title"
|
||||
bind:value={issue.title}
|
||||
showKeyHint={false} />
|
||||
{:else if !issue.title}
|
||||
<span class="txt-missing">No title</span>
|
||||
{:else}
|
||||
<div class="title">
|
||||
<div
|
||||
class="state"
|
||||
class:closed={issue.state.status === "closed"}
|
||||
class:open={issue.state.status === "open"}>
|
||||
<Icon name="issue" />
|
||||
</div>
|
||||
<InlineMarkdown fontSize="medium" content={issue.title} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if session && role.isDelegateOrAuthor(session.publicKey, project.delegates, issue.author.id) && issueState === "read"}
|
||||
<IconButton
|
||||
title="edit issue"
|
||||
on:click={() => (issueState = "edit")}>
|
||||
<IconSmall name={"edit"} />
|
||||
</IconButton>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="state">
|
||||
{#if issue.state.status === "open"}
|
||||
@@ -472,21 +512,30 @@
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<div slot="description">
|
||||
{#if descriptionState !== "read"}
|
||||
{#if issueState !== "read"}
|
||||
<ExtendedTextarea
|
||||
enableAttachments
|
||||
body={issue.discussion[0].body}
|
||||
submitCaption="Save"
|
||||
submitInProgress={descriptionState === "submit"}
|
||||
submitInProgress={issueState === "submit"}
|
||||
placeholder="Leave a description"
|
||||
on:close={() => (descriptionState = "read")}
|
||||
on:close={() => {
|
||||
issueState = "read";
|
||||
void refreshIssue();
|
||||
}}
|
||||
on:submit={async ({ detail: { comment, embeds } }) => {
|
||||
if (session) {
|
||||
try {
|
||||
descriptionState = "submit";
|
||||
await editComment(session.id, issue.id, comment, embeds);
|
||||
issueState = "submit";
|
||||
await editIssue(
|
||||
session.id,
|
||||
issue.title,
|
||||
issue.id,
|
||||
comment,
|
||||
embeds,
|
||||
);
|
||||
} finally {
|
||||
descriptionState = "read";
|
||||
issueState = "read";
|
||||
}
|
||||
}
|
||||
}} />
|
||||
@@ -499,13 +548,6 @@
|
||||
baseUrl,
|
||||
project.head,
|
||||
)} />
|
||||
{#if role.isDelegateOrAuthor(session?.publicKey, project.delegates, issue.author.id)}
|
||||
<IconButton
|
||||
title="edit description"
|
||||
on:click={() => (descriptionState = "edit")}>
|
||||
<IconSmall name="edit" />
|
||||
</IconButton>
|
||||
{/if}
|
||||
</div>
|
||||
{/if}
|
||||
<div class="reactions">
|
||||
|
||||
@@ -11,16 +11,17 @@
|
||||
|
||||
import AssigneeInput from "@app/views/projects/Cob/AssigneeInput.svelte";
|
||||
import AuthenticationErrorModal from "@app/modals/AuthenticationErrorModal.svelte";
|
||||
import NodeId from "@app/components/NodeId.svelte";
|
||||
import Badge from "@app/components/Badge.svelte";
|
||||
import Button from "@app/components/Button.svelte";
|
||||
import CobHeader from "@app/views/projects/Cob/CobHeader.svelte";
|
||||
import ErrorMessage from "@app/components/ErrorMessage.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";
|
||||
import Markdown from "@app/components/Markdown.svelte";
|
||||
import NodeId from "@app/components/NodeId.svelte";
|
||||
import TextInput from "@app/components/TextInput.svelte";
|
||||
import Textarea from "@app/components/Textarea.svelte";
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
|
||||
export let baseUrl: BaseUrl;
|
||||
export let project: Project;
|
||||
@@ -126,9 +127,6 @@
|
||||
flex: 2;
|
||||
padding-right: 1rem;
|
||||
}
|
||||
.open {
|
||||
color: var(--color-fill-success);
|
||||
}
|
||||
.author {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -154,11 +152,18 @@
|
||||
{#if session}
|
||||
<div class="form">
|
||||
<div class="editor">
|
||||
<CobHeader mode="readCreate" {preview} bind:title={issueTitle}>
|
||||
<svelte:fragment slot="icon">
|
||||
<div class="open">
|
||||
<Icon name="issue" />
|
||||
</div>
|
||||
<CobHeader>
|
||||
<svelte:fragment slot="title">
|
||||
{#if !preview}
|
||||
<TextInput
|
||||
placeholder="Title"
|
||||
bind:value={issueTitle}
|
||||
showKeyHint={false} />
|
||||
{:else if issueTitle}
|
||||
<InlineMarkdown fontSize="medium" content={issueTitle} />
|
||||
{:else}
|
||||
<span class="txt-missing">No title</span>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="state">
|
||||
{#if preview}
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
import Icon from "@app/components/Icon.svelte";
|
||||
import IconButton from "@app/components/IconButton.svelte";
|
||||
import IconSmall from "@app/components/IconSmall.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";
|
||||
import Link from "@app/components/Link.svelte";
|
||||
@@ -72,6 +73,7 @@
|
||||
import Popover, { closeFocused } from "@app/components/Popover.svelte";
|
||||
import Radio from "@app/components/Radio.svelte";
|
||||
import RevisionComponent from "@app/views/projects/Cob/Revision.svelte";
|
||||
import TextInput from "@app/components/TextInput.svelte";
|
||||
|
||||
export let baseUrl: BaseUrl;
|
||||
export let patch: Patch;
|
||||
@@ -87,41 +89,11 @@
|
||||
["Convert to draft", { status: "draft" }],
|
||||
];
|
||||
|
||||
async function editTitle(sessionId: string, title: string) {
|
||||
try {
|
||||
await api.project.updatePatch(
|
||||
project.id,
|
||||
patch.id,
|
||||
{
|
||||
type: "edit",
|
||||
title,
|
||||
target: "delegates",
|
||||
},
|
||||
sessionId,
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
modal.show({
|
||||
component: ErrorModal,
|
||||
props: {
|
||||
title: "Patch title editing failed",
|
||||
subtitle: [
|
||||
"There was an error while updating the issue.",
|
||||
"Check your radicle-httpd logs for details.",
|
||||
],
|
||||
error: {
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
await refreshPatch();
|
||||
}
|
||||
}
|
||||
|
||||
async function editDescription(sessionId: string, description: string) {
|
||||
async function editPatch(
|
||||
sessionId: string,
|
||||
title: string,
|
||||
description: string,
|
||||
) {
|
||||
try {
|
||||
await api.project.updatePatch(
|
||||
project.id,
|
||||
@@ -133,14 +105,20 @@
|
||||
},
|
||||
sessionId,
|
||||
);
|
||||
await api.project.updatePatch(
|
||||
project.id,
|
||||
patch.id,
|
||||
{ type: "edit", title, target: "delegates" },
|
||||
sessionId,
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
modal.show({
|
||||
component: ErrorModal,
|
||||
props: {
|
||||
title: "Patch description editing failed",
|
||||
title: "Patch editing failed",
|
||||
subtitle: [
|
||||
"There was an error while updating the issue.",
|
||||
"There was an error while updating the patch.",
|
||||
"Check your radicle-httpd logs for details.",
|
||||
],
|
||||
error: {
|
||||
@@ -477,7 +455,7 @@
|
||||
|
||||
type State = "read" | "submit" | "edit";
|
||||
|
||||
let descriptionState: State = "read";
|
||||
let patchState: State = "read";
|
||||
let labelState: State = "read";
|
||||
|
||||
let revisionId: string;
|
||||
@@ -562,6 +540,17 @@
|
||||
border-radius: var(--border-radius-small);
|
||||
height: fit-content;
|
||||
}
|
||||
.title {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-size: var(--font-size-large);
|
||||
font-weight: var(--font-weight-medium);
|
||||
height: 2.5rem;
|
||||
}
|
||||
.commit-list {
|
||||
border: 1px solid var(--color-border-hint);
|
||||
border-radius: var(--border-radius-small);
|
||||
@@ -615,12 +604,6 @@
|
||||
display: flex;
|
||||
width: 100%;
|
||||
}
|
||||
.edit-buttons {
|
||||
display: flex;
|
||||
margin-left: auto;
|
||||
margin-top: auto;
|
||||
margin-bottom: auto;
|
||||
}
|
||||
.diff-button-range {
|
||||
font-family: var(--font-family-monospace);
|
||||
font-weight: var(--font-weight-bold);
|
||||
@@ -648,26 +631,43 @@
|
||||
<Layout {baseUrl} {project} {tracking} activeTab="patches">
|
||||
<div class="patch">
|
||||
<div>
|
||||
<CobHeader
|
||||
id={patch.id}
|
||||
title={patch.title}
|
||||
editTitle={session &&
|
||||
role.isDelegateOrAuthor(
|
||||
session.publicKey,
|
||||
project.delegates,
|
||||
patch.author.id,
|
||||
) &&
|
||||
partial(editTitle, session.id)}
|
||||
on:refresh={refreshPatch}>
|
||||
<svelte:fragment slot="icon">
|
||||
<div
|
||||
class="state"
|
||||
class:draft={patch.state.status === "draft"}
|
||||
class:open={patch.state.status === "open"}
|
||||
class:merged={patch.state.status === "merged"}
|
||||
class:archived={patch.state.status === "archived"}>
|
||||
<Icon name="patch" />
|
||||
</div>
|
||||
<CobHeader id={patch.id}>
|
||||
<svelte:fragment slot="title">
|
||||
{#if patchState !== "read"}
|
||||
<div
|
||||
class="state"
|
||||
class:draft={patch.state.status === "draft"}
|
||||
class:open={patch.state.status === "open"}
|
||||
class:merged={patch.state.status === "merged"}
|
||||
class:archived={patch.state.status === "archived"}>
|
||||
<Icon name="patch" />
|
||||
</div>
|
||||
<TextInput
|
||||
placeholder="Title"
|
||||
bind:value={patch.title}
|
||||
showKeyHint={false} />
|
||||
{:else if !patch.title}
|
||||
<span class="txt-missing">No title</span>
|
||||
{:else}
|
||||
<div class="title">
|
||||
<div
|
||||
class="state"
|
||||
class:draft={patch.state.status === "draft"}
|
||||
class:open={patch.state.status === "open"}
|
||||
class:merged={patch.state.status === "merged"}
|
||||
class:archived={patch.state.status === "archived"}>
|
||||
<Icon name="patch" />
|
||||
</div>
|
||||
<InlineMarkdown fontSize="medium" content={patch.title} />
|
||||
</div>
|
||||
{/if}
|
||||
{#if session && role.isDelegateOrAuthor(session.publicKey, project.delegates, patch.author.id) && patchState === "read"}
|
||||
<IconButton
|
||||
title="edit patch"
|
||||
on:click={() => (patchState = "edit")}>
|
||||
<IconSmall name={"edit"} />
|
||||
</IconButton>
|
||||
{/if}
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="state">
|
||||
<Badge size="small" variant={badgeColor(patch.state.status)}>
|
||||
@@ -676,20 +676,23 @@
|
||||
</svelte:fragment>
|
||||
<svelte:fragment slot="description">
|
||||
<div class="revision-description">
|
||||
{#if session && descriptionState !== "read"}
|
||||
{#if session && patchState !== "read"}
|
||||
<ExtendedTextarea
|
||||
body={newDescription}
|
||||
submitCaption="Save"
|
||||
submitInProgress={descriptionState === "submit"}
|
||||
submitInProgress={patchState === "submit"}
|
||||
placeholder="Leave a description"
|
||||
on:close={() => (descriptionState = "read")}
|
||||
on:close={() => {
|
||||
patchState = "read";
|
||||
void refreshPatch();
|
||||
}}
|
||||
on:submit={async ({ detail: { comment } }) => {
|
||||
descriptionState = "submit";
|
||||
patchState = "submit";
|
||||
if (session) {
|
||||
try {
|
||||
await editDescription(session.id, comment);
|
||||
await editPatch(session.id, patch.title, comment);
|
||||
} finally {
|
||||
descriptionState = "read";
|
||||
patchState = "read";
|
||||
}
|
||||
}
|
||||
}} />
|
||||
@@ -704,15 +707,6 @@
|
||||
{:else}
|
||||
<span class="txt-missing">No description available</span>
|
||||
{/if}
|
||||
{#if role.isDelegateOrAuthor(session?.publicKey, project.delegates, patch.author.id) && descriptionState === "read"}
|
||||
<div class="edit-buttons">
|
||||
<IconButton
|
||||
title="edit description"
|
||||
on:click={() => (descriptionState = "edit")}>
|
||||
<IconSmall name={"edit"} />
|
||||
</IconButton>
|
||||
</div>
|
||||
{/if}
|
||||
</div>
|
||||
</svelte:fragment>
|
||||
<div class="author" slot="author">
|
||||
|
||||
@@ -48,11 +48,11 @@ test("test issue editing failing", async ({ page, authenticatedPeer }) => {
|
||||
await expect(page.getByText("Comment creation failed")).toBeVisible();
|
||||
});
|
||||
|
||||
test("edit title", async ({ page, authenticatedPeer }) => {
|
||||
test("edit issue", async ({ page, authenticatedPeer }) => {
|
||||
await page.goto(authenticatedPeer.uiUrl());
|
||||
const { rid, projectFolder } = await createProject(
|
||||
authenticatedPeer,
|
||||
"edit-title",
|
||||
"edit-issue",
|
||||
);
|
||||
await authenticatedPeer.rad(
|
||||
[
|
||||
@@ -61,78 +61,51 @@ test("edit title", async ({ page, authenticatedPeer }) => {
|
||||
"--title",
|
||||
"This is an issue to edit its title",
|
||||
"--description",
|
||||
"We'll give it a title and edit it.",
|
||||
"We'll give it a description and edit it.",
|
||||
],
|
||||
{ cwd: projectFolder },
|
||||
);
|
||||
await page.goto(
|
||||
`${authenticatedPeer.uiUrl()}/${rid}/issues/616e240787b6527780636caae581ca9975060733`,
|
||||
`${authenticatedPeer.uiUrl()}/${rid}/issues/df476a2b747a782c20991a258bfb7fc726cb4b0b`,
|
||||
);
|
||||
|
||||
await expect(
|
||||
page.getByText("This is an issue to edit its title"),
|
||||
).toBeVisible();
|
||||
await expect(page.getByPlaceholder("Title")).toBeHidden();
|
||||
|
||||
await page.getByRole("button", { name: "edit title" }).click();
|
||||
await page
|
||||
.getByPlaceholder("Title")
|
||||
.fill("This is a modified issue title to be dismissed");
|
||||
await page.getByRole("button", { name: "dismiss changes" }).click();
|
||||
await expect(
|
||||
page.getByText("This is an issue to edit its title"),
|
||||
).toBeVisible();
|
||||
|
||||
await page.getByRole("button", { name: "edit title" }).click();
|
||||
await page.getByPlaceholder("Title").fill("This is a modified issue title");
|
||||
await page.getByRole("button", { name: "save title" }).click();
|
||||
await expect(page.getByRole("button", { name: "save title" })).toBeHidden();
|
||||
await page.reload();
|
||||
await expect(page.getByText("This is a modified issue title")).toBeVisible();
|
||||
});
|
||||
|
||||
test("edit description", async ({ page, authenticatedPeer }) => {
|
||||
await page.goto(authenticatedPeer.uiUrl());
|
||||
const { rid, projectFolder } = await createProject(
|
||||
authenticatedPeer,
|
||||
"edit-description",
|
||||
);
|
||||
await authenticatedPeer.rad(
|
||||
[
|
||||
"issue",
|
||||
"open",
|
||||
"--title",
|
||||
"This is an issue to edit its description",
|
||||
"--description",
|
||||
"We'll give it a description and edit it.",
|
||||
],
|
||||
{ cwd: projectFolder },
|
||||
);
|
||||
await page.goto(
|
||||
`${authenticatedPeer.uiUrl()}/${rid}/issues/335e2823a71ac91203913a484dd771fd79f75139`,
|
||||
);
|
||||
|
||||
await expect(
|
||||
page.getByText("We'll give it a description and edit it."),
|
||||
).toBeVisible();
|
||||
await expect(page.getByPlaceholder("Leave a description")).toBeHidden();
|
||||
|
||||
await page.getByRole("button", { name: "edit description" }).click();
|
||||
await page.getByRole("button", { name: "edit issue" }).click();
|
||||
await page
|
||||
.getByPlaceholder("Title")
|
||||
.fill("This is a modified issue title to be dismissed");
|
||||
await page
|
||||
.getByPlaceholder("Leave a description")
|
||||
.fill("This is a modified issue description to be dismissed");
|
||||
await page.getByRole("button", { name: "Cancel" }).click();
|
||||
await expect(
|
||||
page.getByText("This is an issue to edit its title"),
|
||||
).toBeVisible();
|
||||
await expect(
|
||||
page.getByText("We'll give it a description and edit it."),
|
||||
).toBeVisible();
|
||||
|
||||
await page.getByRole("button", { name: "edit description" }).click();
|
||||
await page.getByRole("button", { name: "edit issue" }).click();
|
||||
await page.getByPlaceholder("Title").fill("This is a modified issue title");
|
||||
await page
|
||||
.getByPlaceholder("Leave a description")
|
||||
.fill("This is a modified issue description");
|
||||
await page.getByRole("button", { name: "Save" }).click();
|
||||
await expect(page.getByRole("button", { name: "Save" })).toBeHidden();
|
||||
await page.reload();
|
||||
await expect(page.getByText("This is a modified issue title")).toBeVisible();
|
||||
await expect(
|
||||
page.getByText("This is a modified issue description"),
|
||||
).toBeVisible();
|
||||
await page.reload({ waitUntil: "networkidle" });
|
||||
await expect(page.getByText("This is a modified issue title")).toBeVisible();
|
||||
await expect(
|
||||
page.getByText("This is a modified issue description"),
|
||||
).toBeVisible();
|
||||
|
||||
@@ -163,16 +163,23 @@ test("change patch state", async ({ page, authenticatedPeer }) => {
|
||||
await expect(page.getByRole("button", { name: "0 patches" })).toBeVisible();
|
||||
});
|
||||
|
||||
test("edit title", async ({ page, authenticatedPeer }) => {
|
||||
test("edit patch", async ({ page, authenticatedPeer }) => {
|
||||
const { rid, projectFolder } = await createProject(
|
||||
authenticatedPeer,
|
||||
"edit-title",
|
||||
"edit-patch",
|
||||
);
|
||||
await authenticatedPeer.git(["switch", "-c", "edit-title"], {
|
||||
await authenticatedPeer.git(["switch", "-c", "edit-patch"], {
|
||||
cwd: projectFolder,
|
||||
});
|
||||
await authenticatedPeer.git(
|
||||
["commit", "--allow-empty", "-m", "Some patch title"],
|
||||
[
|
||||
"commit",
|
||||
"--allow-empty",
|
||||
"-m",
|
||||
"Some patch title",
|
||||
"-m",
|
||||
"This should be a description",
|
||||
],
|
||||
{
|
||||
cwd: projectFolder,
|
||||
},
|
||||
@@ -185,62 +192,36 @@ test("edit title", async ({ page, authenticatedPeer }) => {
|
||||
await page.goto(`${authenticatedPeer.uiUrl()}/${rid}/patches/${patchId}`);
|
||||
|
||||
const titleLocator = page.getByText("Some patch title").first();
|
||||
const descriptionLocator = page.getByText("This should be a description");
|
||||
await expect(titleLocator).toBeVisible();
|
||||
await expect(descriptionLocator).toBeVisible();
|
||||
await expect(page.getByPlaceholder("Title")).toBeHidden();
|
||||
await expect(page.getByPlaceholder("Leave a description")).toBeHidden();
|
||||
|
||||
await page.getByRole("button", { name: "edit title" }).click();
|
||||
await page.getByRole("button", { name: "edit patch" }).click();
|
||||
await page
|
||||
.getByPlaceholder("Title")
|
||||
.fill("This is a modified patch title to be dismissed");
|
||||
await page.getByRole("button", { name: "dismiss changes" }).click();
|
||||
await expect(titleLocator).toBeVisible();
|
||||
|
||||
await page.getByRole("button", { name: "edit title" }).click();
|
||||
await page.getByPlaceholder("Title").fill("This is a modified patch title");
|
||||
await page.getByRole("button", { name: "save title" }).click();
|
||||
await expect(page.getByRole("button", { name: "save title" })).toBeHidden();
|
||||
await page.reload();
|
||||
await expect(page.getByText("This is a modified patch title")).toBeVisible();
|
||||
});
|
||||
|
||||
test("edit description", async ({ page, authenticatedPeer }) => {
|
||||
const { rid, projectFolder } = await createProject(
|
||||
authenticatedPeer,
|
||||
"edit-description",
|
||||
);
|
||||
await authenticatedPeer.git(["switch", "-c", "edit-description"], {
|
||||
cwd: projectFolder,
|
||||
});
|
||||
await authenticatedPeer.git(
|
||||
["commit", "--allow-empty", "-m", "Some patch title"],
|
||||
{
|
||||
cwd: projectFolder,
|
||||
},
|
||||
);
|
||||
const patchId = extractPatchId(
|
||||
await authenticatedPeer.git(["push", "rad", "HEAD:refs/patches"], {
|
||||
cwd: projectFolder,
|
||||
}),
|
||||
);
|
||||
await page.goto(`${authenticatedPeer.uiUrl()}/${rid}/patches/${patchId}`);
|
||||
|
||||
await expect(page.getByText("No description available")).toBeVisible();
|
||||
await expect(page.getByPlaceholder("Leave a description")).toBeHidden();
|
||||
|
||||
await page.getByRole("button", { name: "edit description" }).click();
|
||||
await page
|
||||
.getByPlaceholder("Leave a description")
|
||||
.fill("This is a modified patch description to be dismissed");
|
||||
await page.getByRole("button", { name: "Cancel" }).click();
|
||||
await expect(page.getByText("No description available")).toBeVisible();
|
||||
await expect(titleLocator).toBeVisible();
|
||||
await expect(descriptionLocator).toBeVisible();
|
||||
|
||||
await page.getByRole("button", { name: "edit description" }).click();
|
||||
await page.getByRole("button", { name: "edit patch" }).click();
|
||||
await page.getByPlaceholder("Title").fill("This is a modified patch title");
|
||||
await page
|
||||
.getByPlaceholder("Leave a description")
|
||||
.fill("This is a modified patch description");
|
||||
await page.getByRole("button", { name: "Save" }).click();
|
||||
await expect(page.getByRole("button", { name: "Save" })).toBeHidden();
|
||||
await expect(page.getByText("This is a modified patch title")).toBeVisible();
|
||||
await expect(
|
||||
page.getByText("This is a modified patch description"),
|
||||
).toBeVisible();
|
||||
await page.reload();
|
||||
await expect(page.getByText("This is a modified patch title")).toBeVisible();
|
||||
await expect(
|
||||
page.getByText("This is a modified patch description"),
|
||||
).toBeVisible();
|
||||
|
||||
Reference in New Issue
Block a user