feat(ui): add copy path actions (#3913)
This commit is contained in:
@@ -0,0 +1,168 @@
|
||||
---
|
||||
created: 2026-09-24
|
||||
status: implemented
|
||||
requirements:
|
||||
- REQ-UI-COPY-FILE-PATH-ACTIONS-001
|
||||
system_design:
|
||||
- ../../specs/ui/system-design/copy-file-path-actions.md
|
||||
legacy_specs: []
|
||||
---
|
||||
|
||||
# Implementation Plan: Copy File Path Actions
|
||||
|
||||
## Overview
|
||||
|
||||
Add Copy path to working-tree rows in the task Changes panel and replace Copy
|
||||
diff with Copy path in the Review diff toolbar. Implement the two surfaces
|
||||
together so they use the same repository-relative path meaning and clipboard
|
||||
behavior. Refuse to copy paths containing C0 or DEL ASCII control characters
|
||||
and report that outcome to prevent terminal input injection.
|
||||
|
||||
## Scope
|
||||
|
||||
### In scope
|
||||
|
||||
- Add Copy path to desktop hover and keyboard-focus actions for Changes rows.
|
||||
- Add Copy path to the existing touch action menu for Changes rows.
|
||||
- Replace Copy diff with Copy path in desktop and phone Review diff file actions.
|
||||
- Reuse `copyToClipboard` for safe paths and the existing `task:copyPath`
|
||||
translation.
|
||||
- Reject C0 and DEL ASCII control characters from every Copy path entry point
|
||||
and show localized refusal feedback.
|
||||
- Add focused unit and desktop/phone E2E coverage for the copied value and
|
||||
action reachability.
|
||||
|
||||
### Out of scope
|
||||
|
||||
- Copy diff controls in task diff toolbars, Monaco, or other editor surfaces.
|
||||
- Path normalization, repository data, Git behavior, APIs, or persistence.
|
||||
- Public documentation changes.
|
||||
|
||||
## Technical approach
|
||||
|
||||
- Extend `FileRowActions` and `TouchFileRowActions` with
|
||||
the same copy handler for `ChangedFile.path`. Stop propagation so
|
||||
copying does not open the diff. Ensure desktop actions become visible on
|
||||
keyboard focus as well as hover.
|
||||
- Replace the Review toolbar's desktop Copy diff button and phone menu item in
|
||||
`review-diff-toolbar.tsx`. Copy the current `filePath`,
|
||||
including the new path for renamed files.
|
||||
- Use `copyPathToClipboard` in both surfaces to reject paths with C0 or DEL
|
||||
ASCII control characters, then use `copyToClipboard` for safe paths. Use
|
||||
`task:copyPath` for localized accessible names and a localized refusal
|
||||
message for rejected paths.
|
||||
- Suppress the shared editor menu's absolute-worktree Copy path item in the
|
||||
Review toolbar menus, so the Review surface exposes one Copy path action with
|
||||
the repository-relative value. Keep those shared menus unchanged elsewhere.
|
||||
- Update existing row and Review toolbar unit tests, then extend the existing
|
||||
Changes and Review browser scenarios for desktop and phone.
|
||||
|
||||
## ASCII UI preview
|
||||
|
||||
UI-01: Changes panel working-tree file row, desktop pointer hover or keyboard
|
||||
focus. The path and statistics stay in the row; Copy path joins the existing
|
||||
secondary actions. Copy path and row activation are separate controls.
|
||||
|
||||
```text
|
||||
[go] browser/programme_test.go +12 -12 [M] [undo] [edit] [copy]
|
||||
```
|
||||
|
||||
UI-02: Changes panel working-tree file row, phone. Tapping the row opens the
|
||||
diff; the visible 44px menu trigger opens a menu whose rows are at least 44px.
|
||||
Copy path is a menu item, not a hover action.
|
||||
|
||||
```text
|
||||
[go] programme_test.go [+12 -12 M] [more]
|
||||
go/internal/.../browser
|
||||
|
||||
Menu: Full path
|
||||
Copy path
|
||||
Stage / Unstage
|
||||
Edit
|
||||
Discard
|
||||
```
|
||||
|
||||
UI-03: Review diff file toolbar, desktop. Copy path replaces Copy diff and
|
||||
copies the current repository-relative path.
|
||||
|
||||
```text
|
||||
[comment] path/to/programme_test.go +12/-12 [copy path] [external] [view] [edit] [...]
|
||||
```
|
||||
|
||||
UI-04: Review diff file toolbar, phone. The existing 44px action trigger opens
|
||||
the file menu; Copy path replaces Copy diff there. The diff keeps its existing
|
||||
single content scroll region.
|
||||
|
||||
```text
|
||||
Diff header: .../path/to/programme_test.go [status]
|
||||
[more]
|
||||
|
||||
Menu: Copy path
|
||||
Edit
|
||||
Preview / diff controls
|
||||
```
|
||||
|
||||
UI-05: If either surface receives a path containing a C0 or DEL ASCII control
|
||||
character, Copy path leaves the clipboard unchanged and shows a localized
|
||||
refusal notice. The notice does not change the row or active diff.
|
||||
|
||||
```text
|
||||
Copy path: refused
|
||||
Notice: This path contains control characters and cannot be copied.
|
||||
```
|
||||
|
||||
The drawings show action order, access, and hierarchy. Icon appearance and
|
||||
spacing are illustrative. UI-01 through UI-04 map to
|
||||
`AC-UI-COPY-FILE-PATH-ACTIONS-001.1` through `.4`; the
|
||||
targeted browser checks prove the copied value and desktop/phone access.
|
||||
UI-05 maps to `AC-UI-COPY-FILE-PATH-ACTIONS-001.6`.
|
||||
|
||||
## Tests
|
||||
|
||||
| Acceptance criterion | Evidence |
|
||||
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------- |
|
||||
| `AC-UI-COPY-FILE-PATH-ACTIONS-001.1`, `.5` | `components/task/changes-panel-file-row.test.tsx`: desktop and phone tests assert the exact path and no diff navigation |
|
||||
| `AC-UI-COPY-FILE-PATH-ACTIONS-001.2`, `.3`, `.5` | `components/review/review-diff-toolbar.test.tsx`: desktop copies the current path for a rename; phone copies its active path |
|
||||
| `AC-UI-COPY-FILE-PATH-ACTIONS-001.4` | Desktop and phone E2E checks below assert keyboard/pointer or menu reachability and 44px phone controls |
|
||||
| `AC-UI-COPY-FILE-PATH-ACTIONS-001.6` | Component suites reject newline, ESC, and DEL across all four entry points; utility tests cover the full C0/DEL range |
|
||||
|
||||
## E2E tests
|
||||
|
||||
- `tests/git/git-changes-panel.spec.ts` (chromium):
|
||||
`copies a changed file path without opening its diff`.
|
||||
- `tests/task/mobile-changes-panel.spec.ts` (mobile-chrome):
|
||||
`compact file rows preserve names and expose touch actions` also copies from
|
||||
the row menu.
|
||||
- `tests/review/review-file-status.spec.ts` (chromium):
|
||||
the Review status scenario copies the new path for a renamed file.
|
||||
- `tests/review/mobile-review-file-status.spec.ts` (mobile-chrome):
|
||||
the mobile header scenario copies the current path from its file menu.
|
||||
|
||||
Component tests also verify control-character paths are rejected from all four
|
||||
desktop and phone entry points with localized refusal feedback.
|
||||
|
||||
Each flow asserts the exact repository-relative clipboard value. The phone flows
|
||||
also assert the relevant menu or control has a 44px hit area and the page has no
|
||||
horizontal overflow.
|
||||
|
||||
## Work orders
|
||||
|
||||
- [x] [Task 01: Add copy path actions](task-01-copy-path-actions.md) (done)
|
||||
|
||||
## Verification results
|
||||
|
||||
- `pnpm exec vitest run components/task/changes-panel-file-row.test.tsx components/review/review-diff-toolbar.test.tsx lib/utils/copy-repository-path.test.ts`: passed (39 tests, including control-character rejection across all four desktop and phone entry points).
|
||||
- `pnpm e2e:run --host --project chromium tests/git/git-changes-panel.spec.ts tests/review/review-file-status.spec.ts`: passed (28 tests; production builds succeeded).
|
||||
- `pnpm e2e:run --no-build --host --project mobile-chrome tests/task/mobile-changes-panel.spec.ts tests/review/mobile-review-file-status.spec.ts`: passed (10 tests; using the production bundle built by the preceding managed mobile run).
|
||||
- After formatting, `pnpm run build` passed, and focused desktop and mobile E2E reruns each passed (2 tests per project).
|
||||
- Targeted ESLint, Prettier, typecheck, and `pnpm run i18n:ratchet`: passed.
|
||||
- `python3 scripts/list-docs.py validate`, `python3 scripts/lint-spec-files.py --all`, and `git diff --check`: passed.
|
||||
- After PR review remediation, the focused desktop Chromium E2E suite passed (28 tests) and the phone mobile-chrome suite passed (10 tests); both managed runs rebuilt the backend and Vite assets.
|
||||
- After remediation, web typecheck, targeted ESLint and Prettier, `i18n:check`, `i18n:ratchet`, specification validation and lint all passed.
|
||||
|
||||
## Risks
|
||||
|
||||
- The additional Changes row control must not reduce the visible path or
|
||||
overlap the trailing statistics at the panel's supported minimum width.
|
||||
- Renamed files must copy the current path from the diff header, not the
|
||||
previous path retained for rename context.
|
||||
@@ -0,0 +1,177 @@
|
||||
---
|
||||
id: "01-copy-path-actions"
|
||||
title: "Add copy path actions"
|
||||
status: done
|
||||
wave: 1
|
||||
depends_on: []
|
||||
plan: "plan.md"
|
||||
requirements:
|
||||
- REQ-UI-COPY-FILE-PATH-ACTIONS-001
|
||||
acceptance_criteria:
|
||||
- AC-UI-COPY-FILE-PATH-ACTIONS-001.1
|
||||
- AC-UI-COPY-FILE-PATH-ACTIONS-001.2
|
||||
- AC-UI-COPY-FILE-PATH-ACTIONS-001.3
|
||||
- AC-UI-COPY-FILE-PATH-ACTIONS-001.4
|
||||
- AC-UI-COPY-FILE-PATH-ACTIONS-001.5
|
||||
- AC-UI-COPY-FILE-PATH-ACTIONS-001.6
|
||||
system_design:
|
||||
- ../../specs/ui/system-design/copy-file-path-actions.md
|
||||
---
|
||||
|
||||
# Task 01: Add copy path actions
|
||||
|
||||
## Summary
|
||||
|
||||
Add Copy path to working-tree file rows in the Changes panel and replace the
|
||||
Review diff toolbar's Copy diff action with Copy path. Both actions copy the
|
||||
current repository-relative path through the shared clipboard helper when it
|
||||
contains no C0 or DEL ASCII control character. Unsafe paths are refused with
|
||||
localized feedback.
|
||||
|
||||
## In scope
|
||||
|
||||
- Add a Copy path action to desktop Changes row hover and keyboard-focus
|
||||
actions.
|
||||
- Add Copy path to the touch Changes row action menu without changing row-tap
|
||||
diff navigation.
|
||||
- Replace Copy diff in the desktop and phone Review diff file actions.
|
||||
- Refuse paths containing C0 or DEL ASCII control characters from each Copy
|
||||
path entry point and report the refusal.
|
||||
- Suppress the Review toolbar's existing absolute-worktree Copy path item so
|
||||
the repository-relative action is the single Copy path choice there.
|
||||
- Add focused unit and desktop/phone browser coverage for path value and access.
|
||||
- Add desktop/phone component coverage for control-character rejection.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Copy diff actions in task diff, Monaco, and other editor surfaces.
|
||||
- Path conversion, Git behavior, backend/API changes, and persistence.
|
||||
- Public documentation changes.
|
||||
|
||||
## Acceptance
|
||||
|
||||
- Changes row Copy path copies the exact repository-relative path on desktop
|
||||
and phone; using it does not open the diff.
|
||||
- Review diff exposes Copy path in place of Copy diff on desktop and phone and
|
||||
copies the active path, including the current path for a rename.
|
||||
- Paths with C0 or DEL ASCII control characters are not copied from either
|
||||
surface, and the UI reports the refusal.
|
||||
- Phone controls and menu items meet the 44px target requirement, and desktop
|
||||
row actions are available by keyboard focus as well as pointer hover.
|
||||
|
||||
## ASCII UI preview
|
||||
|
||||
UI-01 desktop and UI-02 phone from the
|
||||
[full preview](plan.md#ascii-ui-preview):
|
||||
|
||||
```text
|
||||
Desktop: [go] browser/programme_test.go +12 -12 [M] [undo] [edit] [copy]
|
||||
Phone: [go] programme_test.go [+12 -12 M] [more]
|
||||
go/internal/.../browser
|
||||
Menu: Full path / Copy path / Stage or Unstage / Edit / Discard
|
||||
```
|
||||
|
||||
UI-03 desktop and UI-04 phone from the
|
||||
[full preview](plan.md#ascii-ui-preview):
|
||||
|
||||
```text
|
||||
Desktop: [comment] path/to/programme_test.go [copy path] [external] [view] [...]
|
||||
Phone: Diff header .../path/to/programme_test.go [more]
|
||||
Menu: Copy path / Edit / Preview / diff controls
|
||||
```
|
||||
|
||||
UI-05 from the [full preview](plan.md#ascii-ui-preview) shows the refusal
|
||||
notice when a path contains a C0 or DEL ASCII control character. The clipboard
|
||||
and the selected row or diff remain unchanged.
|
||||
|
||||
```text
|
||||
Copy path: refused
|
||||
Notice: This path contains control characters and cannot be copied.
|
||||
```
|
||||
|
||||
AC-001.1 through AC-001.6 require the current repository-relative value for
|
||||
safe paths, separate row and copy actions, current rename path, desktop/phone
|
||||
access, and control-character rejection. The full plan preview defines fixed
|
||||
versus scrollable content and each control's placement.
|
||||
|
||||
## Verification
|
||||
|
||||
Run from the repository root after `pnpm install --frozen-lockfile` in `apps`:
|
||||
|
||||
```bash
|
||||
(cd apps/web && pnpm exec vitest run components/task/changes-panel-file-row.test.tsx components/review/review-diff-toolbar.test.tsx lib/utils/copy-repository-path.test.ts)
|
||||
(cd apps/web && pnpm e2e:run --host --project chromium tests/git/git-changes-panel.spec.ts tests/review/review-file-status.spec.ts)
|
||||
(cd apps/web && pnpm e2e:run --host --project mobile-chrome tests/task/mobile-changes-panel.spec.ts tests/review/mobile-review-file-status.spec.ts)
|
||||
(cd apps/web && pnpm exec eslint components/task/changes-panel-file-row.tsx components/task/changes-panel-touch-file-row.tsx components/review/review-diff-toolbar.tsx components/task/changes-panel-file-row.test.tsx components/review/review-diff-toolbar.test.tsx)
|
||||
(cd apps/web && pnpm run typecheck)
|
||||
(cd apps/web && pnpm run i18n:ratchet)
|
||||
```
|
||||
|
||||
## Files likely touched
|
||||
|
||||
- `apps/web/components/task/changes-panel-file-row.tsx`
|
||||
- `apps/web/components/task/changes-panel-touch-file-row.tsx`
|
||||
- `apps/web/components/task/changes-panel-file-row.test.tsx`
|
||||
- `apps/web/components/review/review-diff-toolbar.tsx`
|
||||
- `apps/web/components/review/review-diff-toolbar.test.tsx`
|
||||
- `apps/web/hooks/use-copy-repository-path.ts`
|
||||
- `apps/web/lib/utils/copy-repository-path.ts`
|
||||
- `apps/web/lib/utils/copy-repository-path.test.ts`
|
||||
- `apps/web/src/locales/*/task.json`
|
||||
- `apps/web/components/editors/file-actions-dropdown.tsx`
|
||||
- `apps/web/e2e/tests/git/git-changes-panel.spec.ts`
|
||||
- `apps/web/e2e/tests/task/mobile-changes-panel.spec.ts`
|
||||
- `apps/web/e2e/tests/review/review-file-status.spec.ts`
|
||||
- `apps/web/e2e/tests/review/mobile-review-file-status.spec.ts`
|
||||
|
||||
## Dependencies
|
||||
|
||||
None.
|
||||
|
||||
## Risks
|
||||
|
||||
Keep the Changes row statistics contained at the minimum panel width. Copy the
|
||||
current path for renamed files and retain the previous path only as context.
|
||||
|
||||
## Parallelism
|
||||
|
||||
`sequential`
|
||||
|
||||
## Inputs
|
||||
|
||||
- [Copy File Path Actions requirements](../../specs/ui/requirements/copy-file-path-actions.md)
|
||||
- [Copy File Path Actions system design](../../specs/ui/system-design/copy-file-path-actions.md)
|
||||
- Existing `copyToClipboard`, Changes row, touch action menu, and
|
||||
Review file toolbar patterns.
|
||||
|
||||
## Results
|
||||
|
||||
Implemented desktop and phone Copy path actions for Changes rows, replaced
|
||||
Copy diff in the Review toolbar, and suppressed the duplicate absolute-path
|
||||
copy item inside Review file menus.
|
||||
|
||||
Verification passed:
|
||||
|
||||
- Focused Vitest suites: 25 tests passed.
|
||||
- Desktop Chromium E2E: 28 tests passed; managed backend and Vite builds passed.
|
||||
- Mobile Chrome E2E: 10 tests passed after the menu animation settled before
|
||||
hit-area measurement.
|
||||
- After formatting, `pnpm run build` and focused desktop/mobile browser reruns
|
||||
passed (2 tests per project).
|
||||
- Targeted ESLint and Prettier, web typecheck, i18n ratchet, specification
|
||||
validation, specification lint, and `git diff --check` passed.
|
||||
|
||||
PR review remediation removed the unused Review toolbar `diff` prop, made the
|
||||
keyboard-focus E2E assertion find Copy path without a fixed Tab count, and
|
||||
added a shared C0/DEL path-copy guard with localized refusal feedback. The
|
||||
system design now has valid requirement-mapping anchors, and acceptance
|
||||
criterion AC-UI-COPY-FILE-PATH-ACTIONS-001.6 records the refusal contract.
|
||||
|
||||
Verification after remediation passed:
|
||||
|
||||
- Focused Changes row, Review toolbar, and path-copy utility Vitest suites: 39
|
||||
tests.
|
||||
- Desktop Chromium E2E: 28 tests; the managed backend and Vite builds passed.
|
||||
- Phone mobile-chrome E2E: 10 tests; the managed backend and Vite builds passed.
|
||||
- Web typecheck, targeted ESLint and Prettier, `i18n:check`,
|
||||
`i18n:ratchet`, specification validation and lint, and `git diff --check`.
|
||||
@@ -0,0 +1,64 @@
|
||||
---
|
||||
status: active
|
||||
system: ui
|
||||
created: 2026-09-24
|
||||
owners:
|
||||
- kandev
|
||||
---
|
||||
|
||||
# Copy File Path Actions Requirements
|
||||
|
||||
## Overview
|
||||
|
||||
People can open a changed file's diff but must select its path manually to copy
|
||||
it. The UI system owns the transient copy actions and their responsive
|
||||
presentation. Task and workspace systems continue to own the file and
|
||||
repository identities supplied to the UI.
|
||||
|
||||
## Requirements
|
||||
|
||||
### REQ-UI-COPY-FILE-PATH-ACTIONS-001: Copy a changed file path
|
||||
|
||||
**Intent:** Let people copy the repository-relative path of a changed file from
|
||||
the Changes list or its Review diff header.
|
||||
|
||||
**User story:** As a person reviewing file changes, I want to copy a file path
|
||||
directly so that I can reuse it without selecting the text.
|
||||
|
||||
#### Acceptance criteria
|
||||
|
||||
- **AC-UI-COPY-FILE-PATH-ACTIONS-001.1:** Given a working-tree file row in the
|
||||
Changes panel whose path has no C0 or DEL ASCII control character, when a
|
||||
user activates Copy path, the clipboard shall receive the exact
|
||||
repository-relative path represented by that row, and the action shall not
|
||||
open the file diff.
|
||||
- **AC-UI-COPY-FILE-PATH-ACTIONS-001.2:** Given a file in the Review diff
|
||||
panel whose path has no C0 or DEL ASCII control character, when the user
|
||||
activates Copy path, the clipboard shall receive the current
|
||||
repository-relative file path. Copy path shall replace Copy diff in that
|
||||
panel's file toolbar.
|
||||
- **AC-UI-COPY-FILE-PATH-ACTIONS-001.3:** For a renamed file, Copy path shall
|
||||
copy the current path shown by the file row or diff header when that path has
|
||||
no C0 or DEL ASCII control character. The previous path remains available
|
||||
only through the existing rename context.
|
||||
- **AC-UI-COPY-FILE-PATH-ACTIONS-001.4:** Copy path shall be keyboard and
|
||||
pointer reachable on desktop and touch reachable on phones. It shall not
|
||||
depend on hover as the only access path, and its phone controls shall have
|
||||
hit areas of at least 44px in both dimensions.
|
||||
- **AC-UI-COPY-FILE-PATH-ACTIONS-001.5:** The copied value shall not include a
|
||||
repository label or an absolute worktree path, including in a multi-repository
|
||||
task.
|
||||
- **AC-UI-COPY-FILE-PATH-ACTIONS-001.6:** Given a file path containing a C0 or
|
||||
DEL ASCII control character, when a user activates Copy path in the Changes
|
||||
panel or Review diff panel, the clipboard shall remain unchanged and the UI
|
||||
shall report that the path cannot be copied.
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Changing file-path data, repository routing, diff selection, or Git actions.
|
||||
- Copying the entire diff from other editor or diff surfaces.
|
||||
- Adding clipboard persistence or a new clipboard implementation.
|
||||
|
||||
## Implementation plans
|
||||
|
||||
- [Copy file path actions](../../../plans/copy-file-path-actions/plan.md)
|
||||
@@ -0,0 +1,136 @@
|
||||
---
|
||||
status: current
|
||||
system: ui
|
||||
requirements:
|
||||
- REQ-UI-COPY-FILE-PATH-ACTIONS-001
|
||||
---
|
||||
|
||||
# Copy File Path Actions System Design
|
||||
|
||||
## Purpose and boundaries
|
||||
|
||||
The UI system owns the transient copy controls and their desktop and phone
|
||||
presentation. Existing task and workspace data remains authoritative for file
|
||||
paths, repository identity, and diff selection. The change adds no backend
|
||||
contract, persistent state, or path conversion.
|
||||
|
||||
## Requirement mapping
|
||||
|
||||
| Criterion | Design section |
|
||||
| --------------------------------------------- | -------------------------------------------------------------------- |
|
||||
| `AC-UI-COPY-FILE-PATH-ACTIONS-001.1` | [Changes row action](#changes-row-action) |
|
||||
| `AC-UI-COPY-FILE-PATH-ACTIONS-001.2`, `001.3` | [Review diff action](#review-diff-action), [Path value](#path-value) |
|
||||
| `AC-UI-COPY-FILE-PATH-ACTIONS-001.4` | [Responsive composition](#responsive-composition) |
|
||||
| `AC-UI-COPY-FILE-PATH-ACTIONS-001.5` | [Path value](#path-value) |
|
||||
|
||||
## Components and responsibilities
|
||||
|
||||
- `ChangesPanel` continues to provide each working-tree
|
||||
`ChangedFile.path`.
|
||||
|
||||
### Changes row action
|
||||
|
||||
- `FileRowActions` in
|
||||
`apps/web/components/task/changes-panel-file-row.tsx` adds the
|
||||
desktop Copy path control beside existing row actions.
|
||||
- `TouchFileRowActions` in
|
||||
`apps/web/components/task/changes-panel-touch-file-row.tsx` adds
|
||||
Copy path to the existing row action menu. The row itself remains the primary
|
||||
diff action.
|
||||
|
||||
### Review diff action
|
||||
|
||||
- `DesktopFileDiffToolbar` and `MobileFileMenuItems` in
|
||||
`apps/web/components/review/review-diff-toolbar.tsx` replace the
|
||||
Review toolbar's Copy diff action with Copy path.
|
||||
- The shared file-action menus also offer Copy path, but that action copies an
|
||||
absolute worktree path. The Review toolbar suppresses that generic item in
|
||||
its desktop and phone menus so the Review surface has one unambiguous Copy
|
||||
path action. Other editor menus keep their existing behavior.
|
||||
- `copyToClipboard` in
|
||||
`apps/web/lib/utils/copy-to-clipboard.ts` remains the clipboard
|
||||
boundary, including its secure-context fallback.
|
||||
- The existing `task:copyPath` translation supplies the accessible
|
||||
name and tooltip. `task:copyPathWithControlCharacters` supplies refusal
|
||||
feedback when a path contains control characters.
|
||||
|
||||
## Path value
|
||||
|
||||
Copy path passes the repository-relative path already represented by the
|
||||
surface: `file.path` for a Changes row and the current
|
||||
`filePath` for the Review diff toolbar. It does not prepend the
|
||||
repository name, resolve a local filesystem root, or normalize the value. A
|
||||
renamed file copies its current path; the existing previous-path value remains
|
||||
reserved for rename cues and external links. Each copy action stops row-click
|
||||
propagation where applicable.
|
||||
|
||||
Paths containing C0 or DEL ASCII control characters are rejected before the
|
||||
clipboard write. For these paths the action reports the refusal and leaves the
|
||||
clipboard unchanged. Other paths are copied exactly as represented by the
|
||||
surface.
|
||||
|
||||
## Control flow
|
||||
|
||||
1. The row or active diff supplies its current path.
|
||||
2. The shared path-copy helper rejects values containing C0 or DEL ASCII
|
||||
control characters and reports the refusal.
|
||||
3. For other values, the helper calls the shared clipboard helper with the
|
||||
exact repository-relative path.
|
||||
4. The Changes row remains selected and the Review diff remains open.
|
||||
5. If the modern clipboard API is unavailable or rejects the write, the shared
|
||||
helper attempts its existing DOM fallback. The action remains available for
|
||||
retry if copying still fails.
|
||||
|
||||
## Responsive composition
|
||||
|
||||
- **Desktop Changes outcome:** the existing file row keeps its path and
|
||||
statistics layout. Copy path joins the row's hover actions and becomes
|
||||
visible while keyboard focus is within the actions. It does not replace the
|
||||
row's click-to-open behavior.
|
||||
- **Phone Changes entry point and surface:** the existing Changes bottom
|
||||
navigation opens `MobileChangesPanel`. The visible 44px row menu
|
||||
trigger exposes Copy path with the existing Stage/Unstage, Edit, and Discard
|
||||
actions. The row identity continues to open the diff.
|
||||
- **Nearest mobile exemplar:** `TouchFileRowActions` already presents
|
||||
temporary row actions in a responsive menu with 44px controls. Reuse that
|
||||
menu and its existing full-path label.
|
||||
- **Review diff outcome:** fine-pointer desktop keeps a direct Copy path icon
|
||||
in the file toolbar. Phone users open the existing 44px file-actions trigger
|
||||
and select Copy path from its menu.
|
||||
- **Shared behavior:** desktop and phone use the same path value and clipboard
|
||||
helper. No new scroll owner, drawer, saved preference, or page-level
|
||||
horizontal overflow is introduced.
|
||||
|
||||
## Failure and recovery
|
||||
|
||||
Clipboard writes use the shared helper and its current fallback. A failed
|
||||
attempt does not alter the selected file, current diff, or path value; users can
|
||||
retry from the same control. A path containing C0 or DEL ASCII control
|
||||
characters is not copied and displays localized refusal feedback. A normal
|
||||
clipboard failure remains available for retry from the same control.
|
||||
|
||||
## Persistence
|
||||
|
||||
None. Clipboard actions are transient.
|
||||
|
||||
## Security
|
||||
|
||||
Repository filenames are untrusted input. C0 and DEL ASCII control characters
|
||||
are refused before clipboard access to prevent a copied name from injecting
|
||||
additional terminal input. For other paths, only the repository-relative value
|
||||
already shown by the UI is copied. No filesystem root, credential, or
|
||||
repository label is added.
|
||||
|
||||
## Observability
|
||||
|
||||
No new logs or metrics are needed.
|
||||
|
||||
## Related specifications
|
||||
|
||||
- [Clipboard browser fallbacks](../../auth/requirements/secure-context-browser-fallbacks.md)
|
||||
- [Changes file row containment](../requirements/changes-file-row-containment.md)
|
||||
- [Review file status cues](../requirements/review-file-status.md)
|
||||
|
||||
## Implementation plan
|
||||
|
||||
- [Copy file path actions](../../../plans/copy-file-path-actions/plan.md)
|
||||
Reference in New Issue
Block a user