Additional Features
Feedback
Receive feedback from your users
Overview
Feedback is crucial for knowing what your reader thinks, and help you to further improve documentation content.
Installation
Install it using Fumadocs CLI.
npx @fumadocs/cli@latest add feedbackUsage
Now add the <Feedback /> component to your docs page:
import { DocsPage } from 'fumadocs-ui/page';
import { Feedback } from '@/components/feedback';
import posthog from 'posthog-js';
export default async function Page() {
return (
<DocsPage>
{/* at the bottom of page */}
<Feedback
onRateAction={async (url, feedback) => {
'use server';
await posthog.capture('on_rate_docs', feedback);
}}
/>
</DocsPage>
);
}onRateAction: fired when user submit feedback.
You can specify a server action, or any function (in client component). Such as reporting user feedback as a on_rate_docs event on PostHog.
Integrating with GitHub Discussion
To report your feedback to GitHub Discussion, make a custom onRateAction.
You can copy this server action as a starting point:
import { App, Octokit } from 'octokit';
import type { ActionResponse, Feedback } from '@/components/feedback';
export const repo = 'fumadocs';
export const owner = 'fuma-nama';
export const DocsCategory = 'Docs Feedback';
let instance: Octokit | undefined;
async function getOctokit(): Promise<Octokit> {
if (instance) return instance;
const appId = process.env.GITHUB_APP_ID;
const privateKey = process.env.GITHUB_APP_PRIVATE_KEY;
if (!appId || !privateKey) {
throw new Error(
'No GitHub keys provided for Github app, docs feedback feature will not work.',
);
}
const app = new App({
appId,
privateKey,
});
const { data } = await app.octokit.request(
'GET /repos/{owner}/{repo}/installation',
{
owner,
repo,
headers: {
'X-GitHub-Api-Version': '2022-11-28',
},
},
);
instance = await app.getInstallationOctokit(data.id);
return instance;
}
interface RepositoryInfo {
id: string;
discussionCategories: {
nodes: {
id: string;
name: string;
}[];
};
}
let cachedDestination: RepositoryInfo | undefined;
async function getFeedbackDestination() {
if (cachedDestination) return cachedDestination;
const octokit = await getOctokit();
const {
repository,
}: {
repository: RepositoryInfo;
} = await octokit.graphql(`
query {
repository(owner: "${owner}", name: "${repo}") {
id
discussionCategories(first: 25) {
nodes { id name }
}
}
}
`);
return (cachedDestination = repository);
}
export async function onRateAction(
url: string,
feedback: Feedback,
): Promise<ActionResponse> {
'use server';
const octokit = await getOctokit();
const destination = await getFeedbackDestination();
if (!octokit || !destination)
throw new Error('GitHub comment integration is not configured.');
const category = destination.discussionCategories.nodes.find(
(category) => category.name === DocsCategory,
);
if (!category)
throw new Error(
`Please create a "${DocsCategory}" category in GitHub Discussion`,
);
const title = `Feedback for ${url}`;
const body = `[${feedback.opinion}] ${feedback.message}\n\n> Forwarded from user feedback.`;
let {
search: {
nodes: [discussion],
},
}: {
search: {
nodes: { id: string; url: string }[];
};
} = await octokit.graphql(`
query {
search(type: DISCUSSION, query: ${JSON.stringify(`${title} in:title repo:${owner}/${repo} author:@me`)}, first: 1) {
nodes {
... on Discussion { id, url }
}
}
}`);
if (discussion) {
await octokit.graphql(`
mutation {
addDiscussionComment(input: { body: ${JSON.stringify(body)}, discussionId: "${discussion.id}" }) {
comment { id }
}
}`);
} else {
const result: {
discussion: { id: string; url: string };
} = await octokit.graphql(`
mutation {
createDiscussion(input: { repositoryId: "${destination.id}", categoryId: "${category!.id}", body: ${JSON.stringify(body)}, title: ${JSON.stringify(title)} }) {
discussion { id, url }
}
}`);
discussion = result.discussion;
}
return {
githubUrl: discussion.url,
};
}- Create your own GitHub App and obtain its app ID and private key.
- Fill required environment variables.
- Replace constants like
owner,repo, andDocsCategory.
How is this guide?
Last updated on
