Files
react-test/netlify/functions/feedback-management.mts
how2ice 005cf56baf
Some checks failed
No response / noResponse (push) Has been cancelled
CI / Continuous releases (push) Has been cancelled
CI / test-dev (macos-latest) (push) Has been cancelled
CI / test-dev (ubuntu-latest) (push) Has been cancelled
CI / test-dev (windows-latest) (push) Has been cancelled
Maintenance / main (push) Has been cancelled
Scorecards supply-chain security / Scorecards analysis (push) Has been cancelled
CodeQL / Analyze (push) Has been cancelled
init project
2025-12-12 14:26:25 +09:00

217 lines
6.0 KiB
TypeScript

import querystring from 'node:querystring';
import { App, AwsLambdaReceiver, BlockAction, ButtonAction } from '@slack/bolt';
import { Handler } from '@netlify/functions';
const X_FEEBACKS_CHANNEL_ID = 'C04U3R2V9UK';
const JOY_FEEBACKS_CHANNEL_ID = 'C050VE13HDL';
const TOOLPAD_FEEBACKS_CHANNEL_ID = 'C050MHU703Z';
const CORE_FEEBACKS_CHANNEL_ID = 'C041SDSF32L';
const BASE_UI_FEEBACKS_CHANNEL_ID = 'C075LJG1LMP';
const MATERIAL_UI_FEEBACKS_CHANNEL_ID = 'C0757QYLK7V';
// const PIGMENT_CSS_FEEBACKS_CHANNEL_ID = 'C074TBW0JKZ';
const X_GRID_FEEBACKS_CHANNEL_ID = 'C0757R0KW67';
const X_CHARTS_FEEBACKS_CHANNEL_ID = 'C0757UBND98';
const X_EXPLORE_FEEBACKS_CHANNEL_ID = 'C074TBYQK2T';
// const DESIGN_KITS_FEEBACKS_CHANNEL_ID = 'C075ADGN0UU';
// The design feedback alert was removed in https://github.com/mui/material-ui/pull/39691
// This dead code is here to simplify the creation of special feedback channel
const DESIGN_FEEDBACKS_CHANNEL_ID = 'C05HHSFH2QJ';
export type MuiProductId =
| 'null'
| 'base-ui'
| 'material-ui'
| 'joy-ui'
| 'system'
| 'docs-infra'
| 'docs'
| 'x-data-grid'
| 'x-date-pickers'
| 'x-charts'
| 'x-tree-view'
| 'toolpad-studio'
| 'toolpad-core';
const getSlackChannelId = (
url: string,
productId: MuiProductId,
specialCases: { isDesignFeedback?: boolean },
) => {
const { isDesignFeedback } = specialCases;
if (isDesignFeedback) {
return DESIGN_FEEDBACKS_CHANNEL_ID;
}
switch (productId) {
case 'base-ui':
return BASE_UI_FEEBACKS_CHANNEL_ID;
case 'material-ui':
case 'system':
return MATERIAL_UI_FEEBACKS_CHANNEL_ID;
case 'joy-ui':
return JOY_FEEBACKS_CHANNEL_ID;
case 'x-data-grid':
return X_GRID_FEEBACKS_CHANNEL_ID;
case 'x-date-pickers':
case 'x-tree-view':
return X_EXPLORE_FEEBACKS_CHANNEL_ID;
case 'x-charts':
return X_CHARTS_FEEBACKS_CHANNEL_ID;
case 'toolpad-studio':
case 'toolpad-core':
return TOOLPAD_FEEBACKS_CHANNEL_ID;
default:
break;
}
// Fallback
if (url.includes('/x/')) {
return X_FEEBACKS_CHANNEL_ID;
}
return CORE_FEEBACKS_CHANNEL_ID;
};
// Setup of the slack bot (taken from https://slack.dev/bolt-js/deployments/aws-lambda)
const awsLambdaReceiver = new AwsLambdaReceiver({
signingSecret: process.env.SLACK_SIGNING_SECRET!,
});
const app = new App({
token: process.env.SLACK_BOT_TOKEN,
receiver: awsLambdaReceiver,
signingSecret: process.env.SLACK_SIGNING_SECRET,
});
// Define slack actions to answer
app.action<BlockAction<ButtonAction>>('delete_action', async ({ ack, body, client, logger }) => {
try {
await ack();
const { channel, message } = body;
const channelId = channel?.id;
if (!channelId) {
throw new Error('feedback-management: Unknown channel Id');
}
await client.chat.delete({
channel: channelId,
ts: message!.ts,
as_user: true,
token: process.env.SLACK_BOT_TOKEN,
});
} catch (error) {
logger.error(JSON.stringify(error, null, 2));
}
});
export const handler: Handler = async (event, context, callback) => {
if (event.httpMethod !== 'POST') {
return { statusCode: 404 };
}
try {
const { payload } = querystring.parse(event.body ?? '') as { payload: any };
const data = JSON.parse(payload);
if (data.callback_id === 'send_feedback') {
// We send the feedback to the appropriate slack channel
const {
rating,
comment,
currentLocationURL,
commentSectionURL: inCommentSectionURL,
commentSectionTitle,
githubRepo,
productId,
} = data;
// The design feedback alert was removed in https://github.com/mui/material-ui/pull/39691
// This dead code is here to simplify the creation of special feedback channel
const isDesignFeedback = inCommentSectionURL.includes('#new-docs-api-feedback');
const commentSectionURL = isDesignFeedback ? '' : inCommentSectionURL;
const simpleSlackMessage = [
`New comment ${rating === 1 ? '👍' : ''}${rating === 0 ? '👎' : ''}`,
`>${comment.split('\n').join('\n>')}`,
`sent from ${currentLocationURL}${
commentSectionTitle ? ` (from section <${commentSectionURL}|${commentSectionTitle})>` : ''
}`,
].join('\n\n');
const githubNewIssueParams = new URLSearchParams({
title: '[ ] Docs feedback',
body: `Feedback received:
${comment}
from ${commentSectionURL}
`,
});
await app.client.chat.postMessage({
channel: getSlackChannelId(currentLocationURL, productId, { isDesignFeedback }),
text: simpleSlackMessage, // Fallback for notification
blocks: [
{
type: 'section',
text: {
type: 'mrkdwn',
text: simpleSlackMessage,
},
},
{
type: 'actions',
elements: [
{
type: 'button',
text: {
type: 'plain_text',
text: 'Create issue',
emoji: true,
},
url: `${githubRepo}/issues/new?${githubNewIssueParams}`,
},
{
type: 'button',
text: {
type: 'plain_text',
text: 'Delete',
},
value: JSON.stringify({
comment,
currentLocationURL,
commentSectionURL,
}),
style: 'danger',
action_id: 'delete_action',
},
],
},
],
as_user: true,
unfurl_links: false,
unfurl_media: false,
});
} else {
const awsHandler = await awsLambdaReceiver.start();
// @ts-ignore
return awsHandler(event, context, callback);
}
} catch (error) {
// eslint-disable-next-line no-console
console.log(JSON.stringify(error, null, 2));
return {
statusCode: 500,
body: JSON.stringify({}),
};
}
return {
statusCode: 200,
body: JSON.stringify({}),
};
};