Skip to content

ENG-1886 Send feedback button in Obsidian#1181

Open
trangdoan982 wants to merge 3 commits into
mainfrom
eng-1886-send-feedback-button-in-obsidian
Open

ENG-1886 Send feedback button in Obsidian#1181
trangdoan982 wants to merge 3 commits into
mainfrom
eng-1886-send-feedback-button-in-obsidian

Conversation

@trangdoan982

@trangdoan982 trangdoan982 commented Jun 30, 2026

Copy link
Copy Markdown
Member

https://www.loom.com/share/0c8218528a58485bbb717da9158f8745

Summary

  • Adds a Send feedback button to the plugin info badge in General Settings, styled to match the existing Community/Docs links
  • Opens a native Obsidian modal (FeedbackModal) with: screenshot attachment, email (with inline format validation), title (required), description (optional), and feedback type dropdown
  • On submit, POSTs to POST /api/feedback on the website, which creates a Linear triage issue and attaches any screenshot directly to the issue via Linear's file upload API
  • Endpoint URL is environment-driven via the existing NEXT_API_ROOT build-time injection

Test plan

  • Add LINEAR_API_KEY=lin_api_... to apps/website/.env
  • Open Obsidian settings → General → click "Send feedback" in the info badge
  • Verify modal opens with all fields, labels, and required indicators
  • Submit with an invalid email — confirm inline error appears on the field
  • Attach a screenshot — confirm thumbnail preview appears and can be removed
  • Submit valid feedback — confirm Linear triage issue is created with screenshot attached
  • Confirm success notice appears and modal closes

🤖 Generated with Claude Code


Open in Devin Review

@linear-code

linear-code Bot commented Jun 30, 2026

Copy link
Copy Markdown

ENG-1886

@supabase

supabase Bot commented Jun 30, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project zytfjzqyijgagqxrzbmz because there are no changes detected in packages/database/supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@vercel

vercel Bot commented Jun 30, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
discourse-graph Ready Ready Preview, Comment Jun 30, 2026 11:12pm

Request Review

@graphite-app

graphite-app Bot commented Jun 30, 2026

Copy link
Copy Markdown
Contributor

PR size/scope check

This PR is over our review-size guideline.

  • Recommended: ~200 lines changed
  • Acceptable limit: up to 400 lines when well-scoped/self-contained
  • Preferred file count: fewer than 5 files

Please split this into smaller PRs unless there is a clear reason the changes need to land together.

If keeping it as one PR, please add a brief justification covering:

  • What single problem this PR solves
  • Why the files/changes are coupled

@devin-ai-integration devin-ai-integration Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Devin Review found 6 potential issues.

Open in Devin Review

Comment thread apps/website/app/api/feedback/route.ts
Comment thread apps/obsidian/src/components/FeedbackModal.tsx
Comment thread apps/obsidian/src/components/FeedbackModal.tsx Outdated
Comment thread apps/website/app/api/feedback/route.ts
Comment thread apps/website/app/api/feedback/route.ts
Comment thread apps/website/app/api/feedback/route.ts
@trangdoan982 trangdoan982 force-pushed the eng-1886-send-feedback-button-in-obsidian branch from 803dfbf to f9645dd Compare June 30, 2026 22:30
Adds a "Send feedback" button to the plugin's info section that opens a
modal form. Users can attach a screenshot, fill in email, title,
description, and feedback type, then submit — which creates a Linear
triage issue via the website API route.

Co-Authored-By: Claude Sonnet 4.6 (1M context) <noreply@anthropic.com>
Refactor feedback API helpers to use object params, declare LINEAR_API_KEY
in turbo.json, and make OPTIONS sync to satisfy eslint.

Co-authored-by: Cursor <cursoragent@cursor.com>
Comment thread apps/website/app/api/feedback/route.ts
@mdroidian

Copy link
Copy Markdown
Member

@codex review

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 46fa9d0362

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

import { StrictMode, useState, useRef, useEffect } from "react";
import type DiscourseGraphPlugin from "~/index";

const FEEDBACK_ENDPOINT = `${process.env.NEXT_API_ROOT}/feedback`;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Add a production fallback for the endpoint

When the plugin is built through the documented Obsidian publish path, apps/obsidian/scripts/publish.ts invokes pnpm run build directly and the README only requires an Obsidian release token, so dbEnv.NEXT_API_ROOT is empty unless the publisher manually supplies extra env. This constant then compiles to /feedback; in Obsidian there is no website origin for that relative URL, so the new Send feedback flow fails in published builds. Please default to the production API URL or make the publish/build path set NEXT_API_ROOT.

Useful? React with 👍 / 👎.

Comment on lines +206 to +207
if (payload.screenshot) {
await uploadScreenshotToLinear(apiKey, issue.id, payload.screenshot);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Avoid reporting failure after creating the issue

If screenshot upload or attachment fails after createIssue succeeds, this await throws into the catch block and the API returns 500. The modal then tells the user the submission failed, but a Linear issue was already created, so retrying creates duplicate triage issues for the same feedback. Consider treating attachment failure separately or making the operation idempotent.

Useful? React with 👍 / 👎.

@mdroidian mdroidian left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The two codex comments are worth addressing, especially the first one.

We'll need to add LINEAR_API_KEY to vercel env's, so could you create a follow-up ticket for that and tag me in it please?

Note: this makes POST /api/feedback an unauthenticated public endpoint that creates Linear tickets, with no server-side abuse mitigation.

Right now the route only checks that title is present before calling createIssue(...). The Obsidian modal has client-side email/title validation, but a bot can skip that and POST directly. CORS also does not protect this endpoint from non-browser clients.

I've created a linear ticket to further look into this, Otherwise someone can script this endpoint and flood Linear with tickets.

Right now it's fairly low risk, so I won't block on it.

type FeedbackType = "feedback" | "bug_report" | "feature_request";

const FEEDBACK_TYPE_LABELS: Record<FeedbackType, string> = {
bug_report: "Bug report",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

camelCase


const FEEDBACK_TYPE_LABELS: Record<FeedbackType, string> = {
bug_report: "Bug report",
feature_request: "Feature request",

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

camelCase

pluginVersion: plugin.manifest.version,
};

console.log("[FeedbackModal] POST", FEEDBACK_ENDPOINT, payload);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

body: JSON.stringify(payload),
});

console.log("[FeedbackModal] response status:", response.status);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

});

console.log("[FeedbackModal] response status:", response.status);
console.log("[FeedbackModal] response body:", response.json);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove

{/* Feedback type */}
<select
value={feedbackType}
onChange={(e) => setFeedbackType(e.target.value as FeedbackType)}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to assert here?

onChange={(e) => setFeedbackType(e.target.value as FeedbackType)}
className={selectClass}
>
{(Object.keys(FEEDBACK_TYPE_LABELS) as FeedbackType[]).map((type) => (

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to assert here?

const LINEAR_TEAM_ID = "e69757b7-976a-4567-836f-16f8a4d59df2"; // Engineering team
const LINEAR_TRIAGE_STATE_ID = "b4d95c83-3020-4f2a-9f38-5de042c66f6b"; // Triage status

type FeedbackType = "feedback" | "bug_report" | "feature_request";

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

camelCase

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants