mirror of
https://seed.radicle.dev/rad:z4V1sjrXqjvFdnCUbxPFqd5p4DtH5.git
synced 2026-11-15 19:30:38 +08:00
Add editing of revisions
This commit is contained in:
@@ -19,6 +19,7 @@
|
||||
import DropdownListItem from "@app/components/DropdownList/DropdownListItem.svelte";
|
||||
import ErrorMessage from "@app/components/ErrorMessage.svelte";
|
||||
import ExpandButton from "@app/components/ExpandButton.svelte";
|
||||
import ExtendedTextarea from "@app/components/ExtendedTextarea.svelte";
|
||||
import IconButton from "@app/components/IconButton.svelte";
|
||||
import IconSmall from "@app/components/IconSmall.svelte";
|
||||
import Link from "@app/components/Link.svelte";
|
||||
@@ -46,7 +47,8 @@
|
||||
export let previousRevId: string | undefined = undefined;
|
||||
export let previousRevOid: string | undefined = undefined;
|
||||
export let first: boolean;
|
||||
export let canEditComment: (author: string) => true | undefined;
|
||||
export let canEdit: (author: string) => true | undefined;
|
||||
export let editRevision: ((description: string) => Promise<void>) | undefined;
|
||||
export let editComment:
|
||||
| ((commentId: string, body: string, embeds: Embed[]) => Promise<void>)
|
||||
| undefined;
|
||||
@@ -95,9 +97,12 @@
|
||||
}
|
||||
}
|
||||
|
||||
type State = "read" | "submit" | "edit";
|
||||
|
||||
let response: DiffResponse | undefined = undefined;
|
||||
let error: any | undefined = undefined;
|
||||
let loading: boolean = false;
|
||||
let revisionState: State = "read";
|
||||
|
||||
onMount(async () => {
|
||||
try {
|
||||
@@ -194,7 +199,6 @@
|
||||
font-size: var(--font-size-small);
|
||||
}
|
||||
.timestamp {
|
||||
margin-left: auto;
|
||||
font-size: var(--font-size-small);
|
||||
color: var(--color-fill-gray);
|
||||
}
|
||||
@@ -382,14 +386,39 @@
|
||||
{utils.formatObjectId(revisionId)}
|
||||
</span>
|
||||
{/if}
|
||||
|
||||
<div
|
||||
class="timestamp"
|
||||
title={utils.absoluteTimestamp(revisionTimestamp)}>
|
||||
{utils.formatTimestamp(revisionTimestamp)}
|
||||
<div style="display: flex; gap: 0.5rem; margin-left: auto;">
|
||||
{#if canEdit(revisionAuthor.id) && editRevision && revisionState === "read"}
|
||||
<IconButton
|
||||
title="edit revision"
|
||||
on:click={() => (revisionState = "edit")}>
|
||||
<IconSmall name="edit" />
|
||||
</IconButton>
|
||||
{/if}
|
||||
<div
|
||||
class="timestamp"
|
||||
title={utils.absoluteTimestamp(revisionTimestamp)}>
|
||||
{utils.formatTimestamp(revisionTimestamp)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{#if revisionDescription && !first}
|
||||
{#if editRevision && revisionState !== "read"}
|
||||
{@const editRevision_ = editRevision}
|
||||
<ExtendedTextarea
|
||||
rawPath={rawPath(revisionId)}
|
||||
body={revisionDescription}
|
||||
submitCaption="Save"
|
||||
submitInProgress={revisionState === "submit"}
|
||||
placeholder="Leave a description"
|
||||
on:close={() => (revisionState = "read")}
|
||||
on:submit={async ({ detail: { comment } }) => {
|
||||
revisionState = "submit";
|
||||
try {
|
||||
await editRevision_(comment);
|
||||
} finally {
|
||||
revisionState = "read";
|
||||
}
|
||||
}} />
|
||||
{:else if revisionDescription && !first}
|
||||
<div class="revision-description txt-small">
|
||||
<Markdown
|
||||
rawPath={rawPath(projectHead)}
|
||||
@@ -433,7 +462,7 @@
|
||||
enableAttachments
|
||||
thread={element.inner}
|
||||
rawPath={rawPath(projectHead)}
|
||||
{canEditComment}
|
||||
canEditComment={canEdit}
|
||||
{editComment}
|
||||
{createReply}
|
||||
{handleReaction} />
|
||||
@@ -460,6 +489,7 @@
|
||||
</span>
|
||||
|
||||
<div
|
||||
style="margin-left: auto"
|
||||
class="timestamp"
|
||||
title={utils.absoluteTimestamp(revisionTimestamp)}>
|
||||
{utils.formatTimestamp(revisionTimestamp)}
|
||||
|
||||
@@ -93,22 +93,8 @@
|
||||
["Convert to draft", { status: "draft" }],
|
||||
];
|
||||
|
||||
async function editPatch(
|
||||
sessionId: string,
|
||||
title: string,
|
||||
description: string,
|
||||
) {
|
||||
async function editPatch(sessionId: string, title: string) {
|
||||
try {
|
||||
await api.project.updatePatch(
|
||||
project.id,
|
||||
patch.id,
|
||||
{
|
||||
type: "revision.edit",
|
||||
revision: patch.id,
|
||||
description,
|
||||
},
|
||||
sessionId,
|
||||
);
|
||||
await api.project.updatePatch(
|
||||
project.id,
|
||||
patch.id,
|
||||
@@ -120,9 +106,43 @@
|
||||
modal.show({
|
||||
component: ErrorModal,
|
||||
props: {
|
||||
title: "Patch editing failed",
|
||||
title: "Patch title editing failed",
|
||||
subtitle: [
|
||||
"There was an error while updating the patch.",
|
||||
"There was an error while updating the title of this patch.",
|
||||
"Check your radicle-httpd logs for details.",
|
||||
],
|
||||
error: {
|
||||
message: error.message,
|
||||
stack: error.stack,
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
} finally {
|
||||
await refreshPatch();
|
||||
}
|
||||
}
|
||||
|
||||
async function editRevision(
|
||||
sessionId: string,
|
||||
revisionId: string,
|
||||
description: string,
|
||||
) {
|
||||
try {
|
||||
await api.project.updatePatch(
|
||||
project.id,
|
||||
patch.id,
|
||||
{ type: "revision.edit", revision: revisionId, description },
|
||||
sessionId,
|
||||
);
|
||||
} catch (error) {
|
||||
if (error instanceof Error) {
|
||||
modal.show({
|
||||
component: ErrorModal,
|
||||
props: {
|
||||
title: "Revision editing failed",
|
||||
subtitle: [
|
||||
"There was an error while updating the revision.",
|
||||
"Check your radicle-httpd logs for details.",
|
||||
],
|
||||
error: {
|
||||
@@ -693,15 +713,13 @@
|
||||
submitCaption="Save"
|
||||
submitInProgress={patchState === "submit"}
|
||||
placeholder="Leave a description"
|
||||
on:close={() => {
|
||||
patchState = "read";
|
||||
void refreshPatch();
|
||||
}}
|
||||
on:close={() => (patchState = "read")}
|
||||
on:submit={async ({ detail: { comment } }) => {
|
||||
patchState = "submit";
|
||||
if (session) {
|
||||
try {
|
||||
await editPatch(session.id, patch.title, comment);
|
||||
await editPatch(session.id, patch.title);
|
||||
await editRevision(session.id, patch.id, comment);
|
||||
} finally {
|
||||
patchState = "read";
|
||||
}
|
||||
@@ -850,11 +868,13 @@
|
||||
projectHead={project.head}
|
||||
{...revision}
|
||||
first={index === 0}
|
||||
canEditComment={partial(
|
||||
canEdit={partial(
|
||||
role.isDelegateOrAuthor,
|
||||
session?.publicKey,
|
||||
project.delegates,
|
||||
)}
|
||||
editRevision={session &&
|
||||
partial(editRevision, session.id, revision.revisionId)}
|
||||
editComment={session &&
|
||||
partial(editComment, session.id, revision.revisionId)}
|
||||
handleReaction={session &&
|
||||
|
||||
@@ -226,3 +226,54 @@ test("edit patch", async ({ page, authenticatedPeer }) => {
|
||||
page.getByText("This is a modified patch description"),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
test("edit revision", async ({ page, authenticatedPeer }) => {
|
||||
const { rid, projectFolder } = await createProject(authenticatedPeer, {
|
||||
name: "edit-revision",
|
||||
});
|
||||
await authenticatedPeer.git(["switch", "-c", "edit-revision"], {
|
||||
cwd: projectFolder,
|
||||
});
|
||||
await authenticatedPeer.git(
|
||||
[
|
||||
"commit",
|
||||
"--allow-empty",
|
||||
"-m",
|
||||
"Some patch title",
|
||||
"-m",
|
||||
"This should be a description",
|
||||
],
|
||||
{
|
||||
cwd: projectFolder,
|
||||
},
|
||||
);
|
||||
const patchId = extractPatchId(
|
||||
await authenticatedPeer.git(["push", "rad", "HEAD:refs/patches"], {
|
||||
cwd: projectFolder,
|
||||
}),
|
||||
);
|
||||
await authenticatedPeer.git(
|
||||
[
|
||||
"commit",
|
||||
"--allow-empty",
|
||||
"-m",
|
||||
"Let's create a new revision",
|
||||
"-m",
|
||||
"More descriptions",
|
||||
],
|
||||
{
|
||||
cwd: projectFolder,
|
||||
},
|
||||
);
|
||||
await authenticatedPeer.git(["push", "rad"], { cwd: projectFolder });
|
||||
|
||||
await page.goto(`${authenticatedPeer.ridUrl(rid)}/patches/${patchId}`);
|
||||
await page.getByRole("button", { name: "edit revision" }).click();
|
||||
await page
|
||||
.getByPlaceholder("Leave a description")
|
||||
.fill("This is an edited second revision");
|
||||
await page.getByRole("button", { name: "Save" }).click();
|
||||
await expect(
|
||||
page.getByText("This is an edited second revision"),
|
||||
).toBeVisible();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user