Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
49 changes: 26 additions & 23 deletions WebUI/src/main/ts/publishing/components/LogDetailsPanel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import {
} from "../logDetails";
import { reserveEditorWindow } from "../../editor/openEditorHost";
import {
logItemCanOpen,
openLogItemInEditor,
type OpenLogItemReason,
type OpenLogItemResult,
Expand Down Expand Up @@ -231,29 +232,31 @@ export function LogDetailsPanel({
{openError}
</p>
)}
<button
type="button"
style={buttonStyle}
data-testid="publish-log-open-editor"
disabled={opening}
onClick={() => {
const reserved = reserveEditorWindow();
setOpening(true);
setOpenError(null);
void openItem(selected.contentid, reserved)
.then((result) => {
if (!result.ok) {
setOpenError(openFailureMessage(result.reason));
}
})
.catch(() => {
setOpenError(message(MSG.PUBLISH_LOG_ITEM_OPEN_FAILED));
})
.finally(() => setOpening(false));
}}
>
{message(MSG.PUBLISH_LOG_OPEN_EDITOR)}
</button>
{logItemCanOpen(selected.contentid) && (
<button
type="button"
style={buttonStyle}
data-testid="publish-log-open-editor"
disabled={opening}
onClick={() => {
const reserved = reserveEditorWindow();
setOpening(true);
setOpenError(null);
void openItem(selected.contentid, reserved)
.then((result) => {
if (!result.ok) {
setOpenError(openFailureMessage(result.reason));
}
})
.catch(() => {
setOpenError(message(MSG.PUBLISH_LOG_ITEM_OPEN_FAILED));
})
.finally(() => setOpening(false));
}}
>
{message(MSG.PUBLISH_LOG_OPEN_EDITOR)}
</button>
)}
<button
type="button"
style={buttonStyle}
Expand Down
7 changes: 7 additions & 0 deletions WebUI/src/main/ts/publishing/openLogItemInEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ export interface OpenLogItemDeps {
) => Promise<boolean>;
}

/** True when the log row has a content id the editor can open (#4936). */
export function logItemCanOpen(
contentId: string | number | null | undefined,
): boolean {
return parseExplorerContentId(contentId ?? undefined) != null;
}

/** Map REST failures so 403/404 are not a successful editor open. */
export function logItemOpenErrorReason(err: unknown): OpenLogItemReason {
if (isApiError(err)) {
Expand Down
21 changes: 21 additions & 0 deletions WebUI/src/test/ts/publishing/openLogItemInEditor.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { describe, expect, it, vi } from "vitest";
import { LogDetailsPanel } from "@/publishing/components/LogDetailsPanel";
import {
logItemCanOpen,
logItemOpenErrorReason,
openLogItemInEditor,
} from "@/publishing/openLogItemInEditor";
Expand Down Expand Up @@ -75,6 +76,9 @@ describe("openLogItemInEditor", () => {
const result = await openLogItemInEditor(undefined, { probe });
expect(result.reason).toBe("missing_id");
expect(probe).not.toHaveBeenCalled();
expect(logItemCanOpen(undefined)).toBe(false);
expect(logItemCanOpen("")).toBe(false);
expect(logItemCanOpen(42)).toBe(true);
});
});

Expand Down Expand Up @@ -108,4 +112,21 @@ describe("LogDetailsPanel open in editor", () => {
});
expect(openItem).toHaveBeenCalledWith(42, null);
});

it("hides Open in editor when the row has no content id", () => {
render(
<LogDetailsPanel
details={{
SitePublishItem: [
{ status: "Success", operation: "publish", fileName: "orphan.html" },
],
}}
onClose={() => undefined}
/>,
);
fireEvent.click(screen.getByRole("button", { name: /item details/i }));
expect(screen.queryByTestId("publish-log-open-editor")).toBeNull();
expect(screen.getByTestId("publish-log-details")).toBeTruthy();
expect(screen.getByTestId("publish-log-item-detail")).toBeTruthy();
});
});
32 changes: 32 additions & 0 deletions docs/ai-generated/code-reviews/issue-4936-erlang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
## Summary

Machine analysis found **1** finding(s), **0** bug(s).

## Scope

- Base: origin/main
- Head: HEAD
- Files: 5 analyzed
- Persona: erlang 0.1.1
- Persona source: /home/nate/.local/share/mkd/agents/erlang

## Recommendation

approve

## Gate

- Blocking bugs: 0
- May commit/push: yes

## Issues

### Issue 1 -- Severity: suggestion

- File: product-docs/8.2/admin/publishing.md:205
- Rule: `llm.ollama-dev-coder`
- Tool: `llm`
- Description: The documentation should mention that the 'Open in editor' action is hidden for rows with no content id.
- Suggestion: Update the documentation to include a note about hiding the 'Open in editor' action for rows without a content id.
- Status: open

42 changes: 42 additions & 0 deletions docs/ai-generated/code-reviews/pr-4946-erlang.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<!--
Copyright (c) 2026 Intersoft Data Labs, Inc.
Licensed under the Apache License, Version 2.0.
-->

# Erlang review — PR #4946

Independent pre-merge review (not the author). mkd-code-review 0.1.18, pack percussion, --gate advisory, --git-base origin/main, models ollama-dev-coder.

## CLI stdout

## Summary

Machine analysis found **1** finding(s), **0** bug(s).

## Scope

- Base: origin/main
- Head: HEAD
- Files: 6 analyzed
- Persona: erlang 0.1.1
- Persona source: /home/nate/.local/share/mkd/agents/erlang

## Recommendation

approve

## Gate

- Blocking bugs: 0
- May commit/push: yes

## Issues

### Issue 1 -- Severity: suggestion

- File: product-docs/8.2/admin/publishing.md:205
- Rule: `llm.ollama-dev-coder`
- Tool: `llm`
- Description: The documentation should mention that the 'Open in editor' action is hidden for rows with no content id.
- Suggestion: Update the documentation to include a note about hiding the 'Open in editor' action for rows without a content id.
- Status: open
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,9 @@
*/

/**
* Playwright surface: #4766 / parent #4531 — PublishingShell log item
* Playwright surface: #4766 / #4936 / parent #4531 — PublishingShell log item
* opens the React content editor. 403/404 stay on the log detail.
* A row with no content id has no Open in editor action.
*
* Tags: @publishing-log-open-editor @publish @smoke
*
Expand Down Expand Up @@ -91,7 +92,7 @@ async function expectNoEditorPopup(popups) {
}
}

async function stubLogs(page, fieldsStatus) {
async function stubLogs(page, fieldsStatus, details = DETAILS) {
await page.route("**/sitemanage/pubstatus/logs**", async (route) => {
if (
isPubstatusLogsUrl(route.request().url()) &&
Expand All @@ -114,7 +115,7 @@ async function stubLogs(page, fieldsStatus) {
await route.fulfill({
status: 200,
contentType: "application/json",
body: JSON.stringify(DETAILS),
body: JSON.stringify(details),
});
return;
}
Expand Down Expand Up @@ -228,4 +229,40 @@ test.describe("PublishingShell open log item in editor (#4766)", () => {
);
expect(consoleErrors).toEqual([]);
});

test(`hides Open in editor when the row has no content id ${TAGS.join(" ")}`, async ({
page,
}) => {
const consoleErrors = [];
attachConsole(page, consoleErrors);
await stubLogs(page, 200, {
SitePublishItem: [
{
status: "Success",
operation: "publish",
fileName: "orphan.html",
},
],
});
const popups = [];
page.on("popup", (popup) => {
popups.push(popup);
});

await page.goto(publishingLogsUrl(BASE_URL), {
waitUntil: "domcontentloaded",
});
await expect(page.getByTestId("publishing-shell")).toBeVisible({
timeout: 30000,
});
await page.getByTestId("logs-filter-apply").click();
await page.getByRole("button", { name: "details" }).click();
await expect(page.getByTestId("publish-log-details")).toBeVisible();
await page.getByRole("button", { name: /item details/i }).click();
await expect(page.getByTestId("publish-log-item-detail")).toBeVisible();
await expect(page.getByTestId("publish-log-open-editor")).toHaveCount(0);
await expect(page.getByTestId("publish-log-details")).toBeVisible();
expect(popups).toEqual([]);
expect(consoleErrors).toEqual([]);
});
});
3 changes: 2 additions & 1 deletion product-docs/8.2/admin/publishing.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,8 @@ have their own text filter). From an item row, **view** then **Open in editor**
`GET …/itemmanagement/item/fields/{contentId}` and, on success, opens the React content editor
for that content id (`spa.jsp?entry=editor&contentId=…&mode=edit`). HTTP **403** (not allowed)
and **404** (item not found) stay on the log item detail as an error — they do not open a blank
editor window. A row with no content id cannot be opened.
editor window and the log list stays on screen. A row with no content id has no **Open in editor**
action.

### Filter current jobs by site (Status)

Expand Down
Loading