[codex] Polish issue composer and long document display (#4420)

## Thinking Path

> - Paperclip orchestrates AI agents for zero-human companies
> - Issue comments and documents are the main working surface where
operators and agents collaborate
> - File drops, markdown editing, and long issue descriptions need to
feel predictable because they sit directly in the task execution loop
> - The composer had edge cases around drag targets, attachment
feedback, image drops, and long markdown content crowding the page
> - This pull request polishes the issue composer, hardens markdown
editor regressions, and adds a fold curtain for long issue
descriptions/documents
> - The benefit is a calmer issue detail surface that handles uploads
and long work products without hiding state or breaking layout

## What Changed

- Scoped issue-composer drag/drop behavior so the composer owns file
drops without turning the whole thread into a competing drop target.
- Added clearer attachment upload feedback for non-image files and
image-drop stability coverage.
- Hardened markdown editor and markdown body handling around HTML-like
tag regressions.
- Added `FoldCurtain` and wired it into issue descriptions and issue
documents so long markdown previews can expand/collapse.
- Added Storybook coverage for the fold curtain state.

## Verification

- `pnpm exec vitest run ui/src/components/IssueChatThread.test.tsx
ui/src/components/MarkdownEditor.test.tsx
ui/src/components/MarkdownBody.test.tsx --config ui/vitest.config.ts`
passed: 3 files, 75 tests.
- `git diff --check public-gh/master..pap-2228-editor-composer-polish --
. ':(exclude)ui/storybook-static'` passed.
- Confirmed this PR does not include `pnpm-lock.yaml`.

## Risks

- Low-to-medium risk: this changes user-facing composer/drop behavior
and long markdown display.
- The fold curtain uses DOM measurement and `ResizeObserver`; reviewers
should check browser behavior for very long descriptions and documents.
- No database migrations.

> For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and
discuss it in `#dev` before opening the PR. Feature PRs that overlap
with planned core work may need to be redirected — check the roadmap
first. See `CONTRIBUTING.md`.

## Model Used

- OpenAI Codex coding agent based on GPT-5, with shell, git, Paperclip
API, and GitHub CLI tool use in the local Paperclip workspace.

## Checklist

- [x] I have included a thinking path that traces from project context
to this change
- [x] I have specified the model used (with version and capability
details)
- [x] I have checked ROADMAP.md and confirmed this PR does not duplicate
planned core work
- [x] I have run tests locally and they pass
- [x] I have added or updated tests where applicable
- [x] If this change affects the UI, I have included before/after
screenshots
- [x] I have updated relevant documentation to reflect my changes
- [x] I have considered and documented any risks above
- [x] I will address all Greptile and reviewer comments before
requesting merge

Note: screenshots were not newly captured during branch splitting; the
UI states are covered by component tests and a Storybook story.

---------

Co-authored-by: Claude Opus 4.7 <noreply@anthropic.com>
Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
Dotta
2026-04-24 14:12:41 -05:00
committed by GitHub
parent 8f1cd0474f
commit 77a72e28c2
10 changed files with 839 additions and 54 deletions
+15 -3
View File
@@ -3,6 +3,7 @@ import { cn } from "../lib/utils";
import { MarkdownBody } from "./MarkdownBody";
import { MarkdownEditor, type MarkdownEditorRef, type MentionOption } from "./MarkdownEditor";
import { useAutosaveIndicator } from "../hooks/useAutosaveIndicator";
import { FoldCurtain } from "./FoldCurtain";
interface InlineEditorProps {
value: string;
@@ -16,6 +17,8 @@ interface InlineEditorProps {
onDropFile?: (file: File) => Promise<void>;
mentions?: MentionOption[];
nullable?: boolean;
/** When true, long display-mode markdown is clipped with a fade curtain that expands on click. */
foldable?: boolean;
}
/** Shared padding so display and edit modes occupy the exact same box. */
@@ -51,6 +54,7 @@ export function InlineEditor({
imageUploadHandler,
onDropFile,
mentions,
foldable = false,
}: InlineEditorProps) {
const [editing, setEditing] = useState(false);
const [multilineEditing, setMultilineEditing] = useState(false);
@@ -282,9 +286,17 @@ export function InlineEditor({
aria-label={placeholder}
tabIndex={0}
>
<MarkdownBody className={cn("paperclip-edit-in-place-content", className)}>
{previewValue}
</MarkdownBody>
{foldable ? (
<FoldCurtain>
<MarkdownBody className={cn("paperclip-edit-in-place-content", className)}>
{previewValue}
</MarkdownBody>
</FoldCurtain>
) : (
<MarkdownBody className={cn("paperclip-edit-in-place-content", className)}>
{previewValue}
</MarkdownBody>
)}
</div>
);
}