feat(ui): add Feedback item to the account flyout menu (PAP-107) (#7854)
## Thinking Path > - Paperclip is the open source app people use to manage AI agents for work > - The web UI has a bottom-left account flyout menu where users reach profile, docs, and the light/dark toggle > - There was no in-product way for users to send feedback or report issues — they had to find an external channel > - We want a low-friction, always-visible entry point for feedback, and a clean URL we can re-point later without shipping app changes > - This pull request adds a **Feedback** item (Megaphone icon) to the account flyout, between Documentation and the theme toggle, that opens `https://paperclip.ing/feedback` in a new tab > - `paperclip.ing/feedback` is a stable indirection (added to the marketing site) that currently 302-redirects to a Google Form, so the destination can be swapped for a richer solution later with no app release > - The benefit is a one-click feedback path for users and a future-proof link the team controls ## Linked Issues or Issue Description No public GitHub issue exists (tracked internally as Paperclip PAP-107). Describing the underlying request inline as a feature, per CONTRIBUTING.md path (B): ### Problem or motivation Users have no in-app affordance to give feedback or report issues; that friction loses signal we'd otherwise act on. ### Proposed solution Add a Feedback item to the account flyout (Megaphone icon, between Documentation and the theme toggle) that opens a stable `paperclip.ing/feedback` URL in a new tab. That URL redirects to a Google Form for now, keeping the client decoupled from the destination. ### Alternatives considered Linking the Google Form directly from the app — rejected because it bakes a throwaway URL into the client; the `/feedback` indirection keeps the link clean and swappable. ### Roadmap alignment Small, self-contained UX addition; no overlap with planned core work (checked ROADMAP.md). The `/feedback` redirect lives in the separate `paperclip-website` repo (Astro site on Cloudflare Pages), commit `f65b566`. No duplicate/related PRs found in this repo (searched feedback/flyout/menu). ## What Changed - `ui/src/components/SidebarAccountMenu.tsx`: import `Megaphone` from `lucide-react`; add `FEEDBACK_URL = "https://paperclip.ing/feedback"` const next to `DOCS_URL`; insert a `Feedback` `MenuAction` between Documentation and the theme toggle using the `external` prop so it opens in a new tab (`target="_blank"`, `rel="noreferrer"`) and closes the popover on click. - `ui/src/components/SidebarAccountMenu.test.tsx`: assert the Feedback item renders with the correct `href`, opens in a new tab, and is ordered after Documentation and before the theme toggle. - (Separate repo, for context) `paperclip-website` `public/_redirects`: `/feedback` → 302 → the feedback Google Form. ## Verification - **Unit tests:** `SidebarAccountMenu` tests pass (item renders, correct `href`, `target="_blank"`, ordering). Run: `cd ui && npm test -- SidebarAccountMenu`. - **Manual / canary:** The board previewed the canary build of the menu item and accepted it. Clicking **Feedback** opens a new tab to `paperclip.ing/feedback`. - **Redirect:** After the Cloudflare Pages deploy propagates, `curl -sI https://paperclip.ing/feedback` returns the Google Form in the `Location` header. _Screenshots:_ UI change was validated via the accepted canary preview; the item reuses the existing `MenuAction` styling, so it visually matches the Documentation/theme rows. ## Risks - **Low risk.** Additive, self-contained UI change with no new state or API calls. The only external dependency is the `paperclip.ing/feedback` redirect (separate repo, already deployed); if it were missing the link would 404, but it is in place. No migrations, no breaking changes. > For core feature work, check [`ROADMAP.md`](ROADMAP.md) first and discuss it in `#dev` before opening the PR. ## Model Used - **Claude (Anthropic).** PR authoring/orchestration: **claude-opus-4-8** (extended thinking + tool use). The implementation commit `b454a12d` was produced with assistance from **claude-sonnet-4-6**. All changes reviewed before pushing. ## 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 searched GitHub for duplicate or related PRs and linked them above - [x] I have either (a) linked existing issues with `Fixes: #` / `Closes #` / `Refs #` OR (b) described the issue in-PR following the relevant issue template - [x] I have run tests locally and they pass - [x] I have added or updated tests where applicable - [ ] 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 - [ ] All Paperclip CI gates are green - [ ] Greptile is 5/5 with no open P2s, recommendations, or follow-ups - [x] I will address all Greptile and reviewer comments before requesting merge --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: Paperclip <noreply@paperclip.ing>
This commit is contained in:
@@ -112,6 +112,21 @@ describe("SidebarAccountMenu", () => {
|
||||
expect(document.body.textContent).toContain("Edit profile");
|
||||
expect(document.body.textContent).not.toContain("Instance settings");
|
||||
expect(document.body.textContent).toContain("Documentation");
|
||||
expect(document.body.textContent).toContain("Feedback");
|
||||
|
||||
// Feedback link opens in a new tab pointing at the feedback URL
|
||||
const feedbackAnchor = document.body.querySelector('a[href="https://paperclip.ing/feedback"]') as HTMLAnchorElement | null;
|
||||
expect(feedbackAnchor).not.toBeNull();
|
||||
expect(feedbackAnchor?.getAttribute("target")).toBe("_blank");
|
||||
|
||||
// Feedback appears after Documentation and before the theme toggle
|
||||
const menuText = document.body.querySelector('[data-slot="popover-content"]')?.textContent ?? "";
|
||||
const docsPos = menuText.indexOf("Documentation");
|
||||
const feedbackPos = menuText.indexOf("Feedback");
|
||||
const themePos = menuText.indexOf("Switch to");
|
||||
expect(docsPos).toBeLessThan(feedbackPos);
|
||||
expect(feedbackPos).toBeLessThan(themePos);
|
||||
|
||||
expect(document.body.textContent).toContain("Paperclip v1.2.3");
|
||||
expect(document.body.textContent).toContain("jane@example.com");
|
||||
expect(document.body.querySelector('[data-slot="popover-content"]')?.className)
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import {
|
||||
BookOpen,
|
||||
LogOut,
|
||||
Megaphone,
|
||||
type LucideIcon,
|
||||
Moon,
|
||||
UserRound,
|
||||
@@ -21,6 +22,7 @@ import { cn, SIDEBAR_RAIL_HIDDEN_LABEL } from "../lib/utils";
|
||||
|
||||
const PROFILE_SETTINGS_PATH = "/company/settings/instance/profile";
|
||||
const DOCS_URL = "https://docs.paperclip.ing/";
|
||||
const FEEDBACK_URL = "https://paperclip.ing/feedback";
|
||||
|
||||
interface SidebarAccountMenuProps {
|
||||
deploymentMode?: DeploymentMode;
|
||||
@@ -206,6 +208,14 @@ export function SidebarAccountMenu({
|
||||
external
|
||||
onClick={() => setOpen(false)}
|
||||
/>
|
||||
<MenuAction
|
||||
label="Feedback"
|
||||
description="Share feedback or report an issue."
|
||||
icon={Megaphone}
|
||||
href={FEEDBACK_URL}
|
||||
external
|
||||
onClick={() => setOpen(false)}
|
||||
/>
|
||||
<MenuAction
|
||||
label={theme === "dark" ? "Switch to light mode" : "Switch to dark mode"}
|
||||
description="Toggle the app appearance."
|
||||
|
||||
Reference in New Issue
Block a user