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
217 lines
6.0 KiB
TypeScript
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({}),
|
|
};
|
|
};
|