From fc8b36527828bb0b8dac6fd4211cbde2a7589bab Mon Sep 17 00:00:00 2001 From: snyk-bot Date: Sat, 2 Sep 2023 01:47:21 +0000 Subject: [PATCH 001/147] fix: upgrade airtable from 0.11.6 to 0.12.1 Snyk has created this PR to upgrade airtable from 0.11.6 to 0.12.1. See this package in npm: https://www.npmjs.com/package/airtable See this project in Snyk: https://app.snyk.io/org/baristageek/project/0810254a-0f29-45a6-ac58-76b132da4c39?utm_source=github&utm_medium=referral&page=upgrade-pr --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index a8a9de62d..f593ca123 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,7 @@ "@stripe/react-stripe-js": "^1.10.0", "@stripe/stripe-js": "^1.36.0", "@vercel/analytics": "^1.0.0", - "airtable": "^0.11.0", + "airtable": "^0.12.1", "applicationinsights": "^2.5.1", "client-only": "0.0.1", "md-to-adf": "^0.6.4", From b9029f639790e69ed5f0d17beae8019ce016c011 Mon Sep 17 00:00:00 2001 From: Esteban Dalel R Date: Mon, 4 Sep 2023 11:44:03 -0500 Subject: [PATCH 002/147] Fix/v2.0.0 merge conflicts (#278) * Feature/posthog frontend (#242) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Frontend analytics * Change export * Fix export * Fix export * Feature/posthog backend (#243) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Create posthog.ts * Add types, move to utils * Capture posthog event * Change export * Fix export * Fix export * Check dev env * Move discord * Use standard var * Better error handling * Delete discord * Move Sendgrid to app router * Fix export * Upgrade routes to return 400 on missing params * Add status codes * Check status returned * Test settings getter * Feature/posthog frontend (#242) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Frontend analytics * Change export * Fix export * Fix export * Feature/posthog backend (#243) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Create posthog.ts * Add types, move to utils * Capture posthog event * Change export * Fix export * Fix export * Check dev env * Extract response types * Use responseTypes * Fix settings to use data response * Early return if no apiKey * Add error events * Remove event logging * Use request URL to pass to posthog * Extract tracking * Use tracker object * Move to route * Fix typo * Create route groups * Fix imports * Delete layout.tsx * Delete discord * Use correct posthog * Fix hover * Update route.ts * Delete getContext.ts * delete unused folders --- tests/api/user/settings.test.ts | 1 + utils/services/loading.tsx | 22 ------------ utils/services/loginArray.tsx | 59 --------------------------------- utils/services/page.tsx | 42 ----------------------- 4 files changed, 1 insertion(+), 123 deletions(-) delete mode 100644 utils/services/loading.tsx delete mode 100644 utils/services/loginArray.tsx delete mode 100644 utils/services/page.tsx diff --git a/tests/api/user/settings.test.ts b/tests/api/user/settings.test.ts index 70dbfc85d..e88ddb31c 100644 --- a/tests/api/user/settings.test.ts +++ b/tests/api/user/settings.test.ts @@ -14,6 +14,7 @@ mockedGetUserSettings.mockResolvedValue({ ConfluenceDocs: 5, }, }); + describe("User Route POST function", () => { it("returns an error when email parameter is missing", async () => { // Mocking request object diff --git a/utils/services/loading.tsx b/utils/services/loading.tsx deleted file mode 100644 index 7c3403d1c..000000000 --- a/utils/services/loading.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import TimeToRedirect from "../../components/redirect"; - -export default function LoadingConnectedService() { - return ( -
-
-

- You have logged in with Service as Tulia in the team Watermelon -

-
- watermelon placeholder -
- -

If you are not redirected, please click here

-
-
- ); -} diff --git a/utils/services/loginArray.tsx b/utils/services/loginArray.tsx deleted file mode 100644 index cbcd6d076..000000000 --- a/utils/services/loginArray.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import SlackLoginLink from "../../components/SlackLoginLink"; -import NotionLoginLink from "../../components/NotionLoginLink"; -import ConfluenceLoginLink from "../../components/ConfluenceLoginLink"; -import JiraLoginLink from "../../components/JiraLoginLink"; -import GitHubLoginLink from "../../components/GitHubLoginLink"; -import LinearLoginLink from "../../components/LinearLoginLink"; -import BitbucketLoginLink from "../../components/BitbucketLoginLink"; -import GitLabLoginLink from "../../components/GitLabLoginLink"; -export default function LoginArray({ nameList, userEmail, userData }) { - const services = [ - { - name: "Jira", - dataProp: "jira_data", - loginComponent: , - }, - { - name: "Linear", - dataProp: "linear_data", - loginComponent: , - }, - { - name: "Slack", - dataProp: "slack_data", - loginComponent: , - }, - { - name: "Confluence", - dataProp: "confluence_data", - loginComponent: , - }, - { - name: "Notion", - dataProp: "notion_data", - loginComponent: , - }, - { - name: "GitHub", - dataProp: "github_data", - loginComponent: , - }, - { - name: "Bitbucket", - dataProp: "bitbucket_data", - loginComponent: , - }, - { - name: "GitLab", - dataProp: "gitlab_data", - loginComponent: , - }, - ]; - const loginArray = services - .filter((service) => nameList.includes(service.name)) - .map((service) => - userData?.[service.dataProp] ? null : service.loginComponent - ) - .filter((component) => component !== null); - return loginArray; -} diff --git a/utils/services/page.tsx b/utils/services/page.tsx deleted file mode 100644 index 604926dbc..000000000 --- a/utils/services/page.tsx +++ /dev/null @@ -1,42 +0,0 @@ -import Link from "next/link"; -import TimeToRedirect from "../../components/redirect"; - -export default function ConnectedService({ - serviceName, - displayName, - teamName, - avatarUrl, - loginArray, - error, -}) { - return ( -
-
-

- You have logged in with {serviceName} as {displayName} in the team{" "} - {teamName} -

-
- linear user image -
- -

- If you are not redirected, please click here -

- {loginArray.length ? ( -
-

You might also be interested:

- {loginArray.map((login) => ( - <>{login} - ))} -
- ) : null} - {error &&

{error}

} -
-
- ); -} From 9a29a68bf062617fde23cf4c25237f301ad1af82 Mon Sep 17 00:00:00 2001 From: baristaGeek Date: Tue, 5 Sep 2023 09:43:06 -0500 Subject: [PATCH 003/147] Build a prompt that produces the desired results --- app/api/extension/getContext/route.ts | 6 +++++ utils/actions/flagPullRequest.ts | 39 +++++++++++++++++++++++++++ 2 files changed, 45 insertions(+) create mode 100644 utils/actions/flagPullRequest.ts diff --git a/app/api/extension/getContext/route.ts b/app/api/extension/getContext/route.ts index 75637cfbb..165940106 100644 --- a/app/api/extension/getContext/route.ts +++ b/app/api/extension/getContext/route.ts @@ -17,6 +17,7 @@ import { } from "../../../../utils/api/responses"; import executeRequest from "../../../../utils/db/azuredb"; import getOpenAISummary from "../../../../utils/actions/getOpenAISummary"; +import flagPulRequest from "../../../../utils/actions/flagPullRequest"; import { StandardProcessedDataArray } from "../../../../types/watermelon"; function replaceSpecialChars(inputString) { const specialChars = /[!"#$%&/()=?_"{}¨*]/g; // Edit this list to include or exclude characters @@ -141,6 +142,11 @@ export async function POST(request: Request) { }, ]; + const prRating = await flagPulRequest({ + prTitle: "WM-85: Enhance JQL Query to find most relevant Jira ticket", + businessLogicSummary: WatermelonAISummary, + }) + successPosthogTracking({ url: request.url, email: req.email, diff --git a/utils/actions/flagPullRequest.ts b/utils/actions/flagPullRequest.ts new file mode 100644 index 000000000..5d0477a62 --- /dev/null +++ b/utils/actions/flagPullRequest.ts @@ -0,0 +1,39 @@ +import { StandardProcessedDataArray } from "../../types/watermelon"; + +const { Configuration, OpenAIApi } = require("openai"); + +const configuration = new Configuration({ + apiKey: process.env.OPEN_AI_KEY, +}); +const openai = new OpenAIApi(configuration); +export default async function flagPullRequest({ + prTitle, + businessLogicSummary +}: { + prTitle?: string; + businessLogicSummary?: string; +}) { + + const prompt = `The goal of this PR is to: ${prTitle}. \n The information related to this PR is: ${businessLogicSummary}. \n On a scale of 1(very different)-10(very similar), how similar the PR's goal and the PR's related information are? Take into account semantics. Don't explain your reasoning, just print the rating. Don't give a range for the rating, print a single value.` + + try { + const completion = await openai.createChatCompletion({ + model: "gpt-3.5-turbo-16k", + messages: [ + { + role: "system", + content: + prompt, + }, + { role: "user", content: prompt }, + ], + }); + console.log("pr title: " + prTitle); + console.log("business logic summary: " + businessLogicSummary); + console.log("OpenAI Rating: " + completion.data.choices[0].message.content); + return completion.data.choices[0].message.content; + } catch (error) { + console.log(error); + return "Error" + error; + } +} From 86c81f779a3e1ef0ba184b52fcb7b28d7380e50b Mon Sep 17 00:00:00 2001 From: baristaGeek Date: Tue, 5 Sep 2023 12:32:27 -0500 Subject: [PATCH 004/147] Flag PRs --- app/api/extension/getContext/route.ts | 16 ++++++- utils/actions/flagPullRequest.ts | 64 +++++++++++++-------------- utils/actions/ratePullRequest.ts | 39 ++++++++++++++++ 3 files changed, 84 insertions(+), 35 deletions(-) create mode 100644 utils/actions/ratePullRequest.ts diff --git a/app/api/extension/getContext/route.ts b/app/api/extension/getContext/route.ts index 165940106..e6c581f00 100644 --- a/app/api/extension/getContext/route.ts +++ b/app/api/extension/getContext/route.ts @@ -17,8 +17,10 @@ import { } from "../../../../utils/api/responses"; import executeRequest from "../../../../utils/db/azuredb"; import getOpenAISummary from "../../../../utils/actions/getOpenAISummary"; -import flagPulRequest from "../../../../utils/actions/flagPullRequest"; +import ratePullRequest from "../../../../utils/actions/ratePullRequest"; import { StandardProcessedDataArray } from "../../../../types/watermelon"; +import flagPullRequest from "../../../../utils/actions/flagPullRequest"; + function replaceSpecialChars(inputString) { const specialChars = /[!"#$%&/()=?_"{}¨*]/g; // Edit this list to include or exclude characters return inputString.toLowerCase().replace(specialChars, " "); @@ -142,11 +144,21 @@ export async function POST(request: Request) { }, ]; - const prRating = await flagPulRequest({ + const prRating = await ratePullRequest({ prTitle: "WM-85: Enhance JQL Query to find most relevant Jira ticket", businessLogicSummary: WatermelonAISummary, }) + if (prRating >= 9) { + // flag PR as safe to merge + flagPullRequest({ + repo: repo, + owner: owner, + issue_number: 275, + github_token + }) + } + successPosthogTracking({ url: request.url, email: req.email, diff --git a/utils/actions/flagPullRequest.ts b/utils/actions/flagPullRequest.ts index 5d0477a62..20c394624 100644 --- a/utils/actions/flagPullRequest.ts +++ b/utils/actions/flagPullRequest.ts @@ -1,39 +1,37 @@ -import { StandardProcessedDataArray } from "../../types/watermelon"; +import { Octokit } from "octokit"; -const { Configuration, OpenAIApi } = require("openai"); +async function flagPullRequest({ + repo, + owner, + issue_number, + github_token, +}): Promise { + if (!github_token) { + return { error: "no github token" }; + } else { + const octokit = new Octokit({ + auth: github_token, + }); -const configuration = new Configuration({ - apiKey: process.env.OPEN_AI_KEY, -}); -const openai = new OpenAIApi(configuration); -export default async function flagPullRequest({ - prTitle, - businessLogicSummary -}: { - prTitle?: string; - businessLogicSummary?: string; -}) { + const labelsInPR = await octokit.rest.issues.listLabelsOnIssue({ + owner, + repo, + issue_number, + }); - const prompt = `The goal of this PR is to: ${prTitle}. \n The information related to this PR is: ${businessLogicSummary}. \n On a scale of 1(very different)-10(very similar), how similar the PR's goal and the PR's related information are? Take into account semantics. Don't explain your reasoning, just print the rating. Don't give a range for the rating, print a single value.` + if (labelsInPR.data.some((label) => label.name === "safe-to-merge")) { + return { message: "PR already flagged as safe to merge" }; + } else { + await octokit.rest.issues.addLabels({ + owner, + repo, + issue_number, + labels: ["🍉 Safe to Merge"], + }); - try { - const completion = await openai.createChatCompletion({ - model: "gpt-3.5-turbo-16k", - messages: [ - { - role: "system", - content: - prompt, - }, - { role: "user", content: prompt }, - ], - }); - console.log("pr title: " + prTitle); - console.log("business logic summary: " + businessLogicSummary); - console.log("OpenAI Rating: " + completion.data.choices[0].message.content); - return completion.data.choices[0].message.content; - } catch (error) { - console.log(error); - return "Error" + error; + return { message: "PR flagged as safe to merge" }; + } } } + +export default flagPullRequest; diff --git a/utils/actions/ratePullRequest.ts b/utils/actions/ratePullRequest.ts new file mode 100644 index 000000000..5d0477a62 --- /dev/null +++ b/utils/actions/ratePullRequest.ts @@ -0,0 +1,39 @@ +import { StandardProcessedDataArray } from "../../types/watermelon"; + +const { Configuration, OpenAIApi } = require("openai"); + +const configuration = new Configuration({ + apiKey: process.env.OPEN_AI_KEY, +}); +const openai = new OpenAIApi(configuration); +export default async function flagPullRequest({ + prTitle, + businessLogicSummary +}: { + prTitle?: string; + businessLogicSummary?: string; +}) { + + const prompt = `The goal of this PR is to: ${prTitle}. \n The information related to this PR is: ${businessLogicSummary}. \n On a scale of 1(very different)-10(very similar), how similar the PR's goal and the PR's related information are? Take into account semantics. Don't explain your reasoning, just print the rating. Don't give a range for the rating, print a single value.` + + try { + const completion = await openai.createChatCompletion({ + model: "gpt-3.5-turbo-16k", + messages: [ + { + role: "system", + content: + prompt, + }, + { role: "user", content: prompt }, + ], + }); + console.log("pr title: " + prTitle); + console.log("business logic summary: " + businessLogicSummary); + console.log("OpenAI Rating: " + completion.data.choices[0].message.content); + return completion.data.choices[0].message.content; + } catch (error) { + console.log(error); + return "Error" + error; + } +} From 4d0b5bcf1c1a397eab5d32ed55fcf83a686eb821 Mon Sep 17 00:00:00 2001 From: baristaGeek Date: Tue, 5 Sep 2023 12:40:07 -0500 Subject: [PATCH 005/147] Change comparison string for detecting already labeled PRs --- utils/actions/flagPullRequest.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/utils/actions/flagPullRequest.ts b/utils/actions/flagPullRequest.ts index 20c394624..59cf3d642 100644 --- a/utils/actions/flagPullRequest.ts +++ b/utils/actions/flagPullRequest.ts @@ -19,7 +19,7 @@ async function flagPullRequest({ issue_number, }); - if (labelsInPR.data.some((label) => label.name === "safe-to-merge")) { + if (labelsInPR.data.some((label) => label.name === "🍉 Safe to Merge")) { return { message: "PR already flagged as safe to merge" }; } else { await octokit.rest.issues.addLabels({ From 1d246b0b83abd04ecf23fa1e8442eb46de568309 Mon Sep 17 00:00:00 2001 From: Esteban Dalel R Date: Tue, 5 Sep 2023 13:35:29 -0500 Subject: [PATCH 006/147] Fix/double cloud id getting (#271) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Change export * Fix export * Fix export * Upgrade routes to return 400 on missing params * Add status codes * Check status returned * Test settings getter * Feature/posthog frontend (#242) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Frontend analytics * Change export * Fix export * Fix export * Feature/posthog backend (#243) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Create posthog.ts * Add types, move to utils * Capture posthog event * Change export * Fix export * Fix export * Check dev env * Extract response types * Use responseTypes * Fix settings to use data response * Early return if no apiKey * Add error events * Remove event logging * Use request URL to pass to posthog * Extract tracking * Use tracker object * Move to route * Fix typo * Add missing params test * Create route groups * Fix imports * Delete layout.tsx * Move discord * Use standard var * Delete getAllData.ts * Delete discord * Upgrade routes to return 400 on missing params * Add status codes * Check status returned * Test settings getter * Feature/posthog frontend (#242) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Frontend analytics * Change export * Fix export * Fix export * Extract response types * Use responseTypes * Fix settings to use data response * Early return if no apiKey * Add error events * Remove event logging * Use request URL to pass to posthog * Extract tracking * Use tracker object * Move to route * Fix typo * Add missing params test * Use missing params function * Use missingparams tracker * Fix imports * Change required params to be only search text * Move to pages * Move imports * Use correct params * Fixes to notion fetching * Move to app folder * Add posthog tracking * Fix confluence number, slack usage * Move Context route * Fix API * Remove gitSystem * Add AI Summary * Fix types, remove logging * Remove unused file * Remove pages folder * Fix response error * Fix placeholder * Fix imports, placeholder * Move discord * Use standard var * Better error handling * Delete discord * Move Sendgrid to app router * Fix export * Upgrade routes to return 400 on missing params * Add status codes * Check status returned * Test settings getter * Feature/posthog frontend (#242) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Frontend analytics * Change export * Fix export * Fix export * Feature/posthog backend (#243) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Create posthog.ts * Add types, move to utils * Capture posthog event * Change export * Fix export * Fix export * Check dev env * Extract response types * Use responseTypes * Fix settings to use data response * Early return if no apiKey * Add error events * Remove event logging * Use request URL to pass to posthog * Extract tracking * Use tracker object * Move to route * Fix typo * Create route groups * Fix imports * Delete layout.tsx * Add intellij files * Stop double cloudid getting * Delete loading.tsx * Fix params * Fix params * Fix imports * Update CONTRIBUTING.md * Add explanation --- .gitignore | 1 + CONTRIBUTING.md | 16 ++++++------ app/api/actions/github/route.ts | 7 +++--- app/api/extension/getContext/route.ts | 6 ++--- app/api/hover/getHoverData/route.ts | 6 ++--- app/providers.tsx | 1 - types/watermelon.ts | 3 +++ utils/actions/getConfluence.ts | 21 ++++++++-------- utils/actions/getJira.ts | 26 ++++++++++++++------ utils/confluence/getFreshConfluenceTokens.ts | 7 ++++-- utils/jira/refreshTokens.ts | 3 +++ 11 files changed, 58 insertions(+), 39 deletions(-) diff --git a/.gitignore b/.gitignore index 7f65eecd4..7562f53c0 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ yarn.lock .env .env*.local .fleet/settings.json +.idea \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index a9ff0f20e..e7b33a411 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,11 +1,15 @@ # Contributing + We discuss both on GitHub Issues and [Discord](discord.gg/H4AE6b9442). ## Contributing to Watermelon's Passive Documentation Search Engine -Anyone is free to contribute changes to any file in this repository. You don't need to ask for permission or get in line. If you see an issue that's open and it seems interesting to you, feel free to pick it up. Your solution may be better. Open-source is beautiful. + +Anyone is free to contribute changes to any file in this repository. You don't need to ask for permission or get in line. If you see an issue that's open and it seems interesting to you, feel free to pick it up. Your solution may be better. Open-source is beautiful. + > Exception: If your contribution makes [paid Watermelon feature](https://watermelontools.com/pricing/) available for free, we are unlikely to accept it. Consult us beforehand for a definitive answer. ## Running the Passive Documentation Search Engine Locally + To start developing, clone and: ``` @@ -20,13 +24,6 @@ npm i npm run dev ``` -Or with npm - -``` -npm i -npm run dev -``` - (Check your node version, we recommend 18) We use a recent version of Next. You may refer to the documentation at https://nextjs.org/docs/. @@ -68,14 +65,15 @@ First, we use oauth so you need to ensure that the service supports it. Remember that there are several procedures in our db to replicate. ## Issues + If there's something you'd like to see please [open an issue](https://github.com/watermelontools/watermelon/issues/new). ## PRs + We love community contributions. Please fork the repo and send a PR our way. Remember, we'll discuss it publicly, it's a great opportunity to learn. ### Resources -#### - [Octokit (SDK for GitHub)](https://octokit.github.io/) diff --git a/app/api/actions/github/route.ts b/app/api/actions/github/route.ts index b99949d23..9410f7cce 100644 --- a/app/api/actions/github/route.ts +++ b/app/api/actions/github/route.ts @@ -343,12 +343,13 @@ export async function POST(request: Request) { token: jira_token, refresh_token: jira_refresh_token, randomWords, + cloudId, amount: JiraTickets, }), getConfluence({ - confluence_token, - confluence_refresh_token, - confluence_id, + token: confluence_token, + refresh_token: confluence_refresh_token, + cloudId: confluence_id, user: user_email, randomWords, amount: ConfluencePages, diff --git a/app/api/extension/getContext/route.ts b/app/api/extension/getContext/route.ts index 75637cfbb..f89528832 100644 --- a/app/api/extension/getContext/route.ts +++ b/app/api/extension/getContext/route.ts @@ -99,9 +99,9 @@ export async function POST(request: Request) { amount: JiraTickets, }), getConfluence({ - confluence_token, - confluence_refresh_token, - confluence_id, + token: confluence_token, + refresh_token: confluence_refresh_token, + cloudId: confluence_id, user: user_email, randomWords, amount: ConfluencePages, diff --git a/app/api/hover/getHoverData/route.ts b/app/api/hover/getHoverData/route.ts index 03c177ddc..bd90a0e39 100644 --- a/app/api/hover/getHoverData/route.ts +++ b/app/api/hover/getHoverData/route.ts @@ -88,9 +88,9 @@ export async function POST(request: Request) { amount: 1, }), getConfluence({ - confluence_token, - confluence_refresh_token, - confluence_id, + token: confluence_token, + refresh_token: confluence_refresh_token, + cloudId: confluence_id, user: user_email, randomWords, amount: 1, diff --git a/app/providers.tsx b/app/providers.tsx index fc6e164bb..960097a67 100644 --- a/app/providers.tsx +++ b/app/providers.tsx @@ -1,4 +1,3 @@ - "use client"; import posthog from "posthog-js"; import { PostHogProvider } from "posthog-js/react"; diff --git a/types/watermelon.ts b/types/watermelon.ts index fa2bb9f30..b2cbbd1bc 100644 --- a/types/watermelon.ts +++ b/types/watermelon.ts @@ -17,6 +17,9 @@ export type StandardAPIInput = { repo?: string; randomWords?: string[]; }; +export interface AtlassianAPIInput extends StandardAPIInput { + cloudId?: string; +} export type StandardProcessedDataArray = { title: string; body?: string; diff --git a/utils/actions/getConfluence.ts b/utils/actions/getConfluence.ts index 5c2a22b23..dc74aeca4 100644 --- a/utils/actions/getConfluence.ts +++ b/utils/actions/getConfluence.ts @@ -1,4 +1,4 @@ -import { StandardAPIResponse } from "../../types/watermelon"; +import { AtlassianAPIInput, StandardAPIResponse } from "../../types/watermelon"; import getFreshConfluenceTokens from "../confluence/getFreshConfluenceTokens"; function removeSpecialChars(inputString) { @@ -28,28 +28,27 @@ async function fetchFromConfluence(cql, amount, accessToken, confluence_id) { } async function getConfluence({ - confluence_token, - confluence_refresh_token, - confluence_id, + token, + refresh_token, + cloudId, user, randomWords, amount = 3, -}): Promise { +}: AtlassianAPIInput): Promise { // Error handling - if (!confluence_token || !confluence_refresh_token) - return { error: "no confluence token" }; + if (!token || !refresh_token) return { error: "no confluence token" }; if (!user) return { error: "no user" }; - if (!confluence_id) return { error: "no confluence cloudId" }; + if (!cloudId) return { error: "no confluence cloudId" }; // Refresh tokens const newAccessTokens = await getFreshConfluenceTokens({ - confluence_refresh_token, + refresh_token, user, }); if (!newAccessTokens.access_token) return { error: "no confluence token" }; // Constructing search query const cleanRandomWords = Array.from( - new Set(randomWords.map((word) => removeSpecialChars(word))) + new Set(randomWords?.map((word) => removeSpecialChars(word))) ); const titleQuery = cleanRandomWords .map((word) => `title ~ "${word}"`) @@ -65,7 +64,7 @@ async function getConfluence({ cql, amount, newAccessTokens.access_token, - confluence_id + cloudId ); return { fullData: results, diff --git a/utils/actions/getJira.ts b/utils/actions/getJira.ts index 3fb44095e..729d674c6 100644 --- a/utils/actions/getJira.ts +++ b/utils/actions/getJira.ts @@ -1,4 +1,4 @@ -import { StandardAPIInput } from "../../types/watermelon"; +import { AtlassianAPIInput } from "../../types/watermelon"; import getJiraOrganization from "../../utils/db/jira/getOrganization"; import getFreshJiraTokens from "../jira/getFreshJiraTokens"; @@ -51,7 +51,8 @@ async function getJira({ refresh_token, randomWords, amount = 3, -}: StandardAPIInput) { + cloudId, +}: AtlassianAPIInput) { if (!token || !refresh_token) return { error: "no jira token" }; if (!user) return { error: "no user" }; @@ -61,9 +62,12 @@ async function getJira({ }); if (!newAccessTokens?.access_token) return { error: "no jira token" }; - - const { jira_id } = await getJiraOrganization(user); - if (!jira_id) return { error: "no Jira cloudId" }; + let fetchedCloudId; + if (!cloudId) { + const { jira_id } = await getJiraOrganization(user); + if (!jira_id) return { error: "no Jira cloudId" }; + fetchedCloudId = jira_id; + } const cleanRandomWords = Array.from( new Set(randomWords?.map((word) => removeSpecialChars(word))) @@ -78,8 +82,16 @@ async function getJira({ try { const [results, serverInfo] = await Promise.all([ - fetchJiraData(jql, jira_id, newAccessTokens.access_token, amount), - getJiraServerInfo(jira_id, newAccessTokens.access_token), + fetchJiraData( + jql, + cloudId || fetchedCloudId, + newAccessTokens.access_token, + amount + ), + getJiraServerInfo( + cloudId || fetchedCloudId, + newAccessTokens.access_token + ), ]); results.forEach((element, index) => { results[index].serverInfo = serverInfo; diff --git a/utils/confluence/getFreshConfluenceTokens.ts b/utils/confluence/getFreshConfluenceTokens.ts index 888c915ff..5cb54ac59 100644 --- a/utils/confluence/getFreshConfluenceTokens.ts +++ b/utils/confluence/getFreshConfluenceTokens.ts @@ -26,6 +26,9 @@ async function updateTokensFromConfluence({ }: { refresh_token: string; }): Promise<{ access_token: string; refresh_token: string }> { + // as stated in the atlassian docs, we need to refresh the access token every use + // https://developer.atlassian.com/cloud/jira/platform/oauth-2-3lo-apps/#how-do-i-get-a-new-access-token--if-my-access-token-expires-or-is-revoked- + // the refresh token, once used needs to be refreshed too try { let newAccessTokens = await fetch( "https://auth.atlassian.com/oauth/token", @@ -56,9 +59,9 @@ async function updateTokensFromConfluence({ } } -async function getFreshConfluenceTokens({ confluence_refresh_token, user }) { +async function getFreshConfluenceTokens({ refresh_token, user }) { const newAccessTokens = await updateTokensFromConfluence({ - refresh_token: confluence_refresh_token, + refresh_token: refresh_token, }); if (!newAccessTokens?.access_token) { diff --git a/utils/jira/refreshTokens.ts b/utils/jira/refreshTokens.ts index ec004f9b6..caf6d2e9e 100644 --- a/utils/jira/refreshTokens.ts +++ b/utils/jira/refreshTokens.ts @@ -4,6 +4,9 @@ import getAPIAccessInfo from "../db/jira/getAPIAccessInfo"; export default async ({ user }) => { try { + // as stated in the atlassian docs, we need to refresh the access token every use + // https://developer.atlassian.com/cloud/jira/platform/oauth-2-3lo-apps/#how-do-i-get-a-new-access-token--if-my-access-token-expires-or-is-revoked- + // the refresh token, once used needs to be refreshed too let { refresh_token, cloudId } = await getAPIAccessInfo(user); let newAccessTokens = await updateTokensFromJira({ refresh_token }); await updateTokens({ From 835e833b27d91de459e18751eba152912fd91318 Mon Sep 17 00:00:00 2001 From: baristaGeek Date: Tue, 5 Sep 2023 15:23:27 -0500 Subject: [PATCH 007/147] Change hardcoded pr title and number to the ones stored on GitHubPRs[0 --- app/api/extension/getContext/route.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/app/api/extension/getContext/route.ts b/app/api/extension/getContext/route.ts index e6c581f00..88b063eaa 100644 --- a/app/api/extension/getContext/route.ts +++ b/app/api/extension/getContext/route.ts @@ -145,16 +145,16 @@ export async function POST(request: Request) { ]; const prRating = await ratePullRequest({ - prTitle: "WM-85: Enhance JQL Query to find most relevant Jira ticket", + prTitle: GitHubPRs[0].title, businessLogicSummary: WatermelonAISummary, }) if (prRating >= 9) { // flag PR as safe to merge - flagPullRequest({ - repo: repo, - owner: owner, - issue_number: 275, + await flagPullRequest({ + repo, + owner, + issue_number: GitHubPRs[0].number, github_token }) } From aa3ce80021289c2017a3c2f238b1012b9bbd1dc4 Mon Sep 17 00:00:00 2001 From: baristaGeek Date: Tue, 5 Sep 2023 15:24:05 -0500 Subject: [PATCH 008/147] Remove console logs --- utils/actions/ratePullRequest.ts | 3 --- 1 file changed, 3 deletions(-) diff --git a/utils/actions/ratePullRequest.ts b/utils/actions/ratePullRequest.ts index 5d0477a62..1ea3439f6 100644 --- a/utils/actions/ratePullRequest.ts +++ b/utils/actions/ratePullRequest.ts @@ -28,9 +28,6 @@ export default async function flagPullRequest({ { role: "user", content: prompt }, ], }); - console.log("pr title: " + prTitle); - console.log("business logic summary: " + businessLogicSummary); - console.log("OpenAI Rating: " + completion.data.choices[0].message.content); return completion.data.choices[0].message.content; } catch (error) { console.log(error); From 6bbba41540cbb70ef97bb0522d5b974aabdd5a75 Mon Sep 17 00:00:00 2001 From: Esteban Dalel R Date: Wed, 6 Sep 2023 10:47:13 -0500 Subject: [PATCH 009/147] Chore/delete unused files (#283) * Feature/posthog frontend (#242) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Frontend analytics * Change export * Fix export * Fix export * Feature/posthog backend (#243) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Create posthog.ts * Add types, move to utils * Capture posthog event * Change export * Fix export * Fix export * Check dev env * Move discord * Use standard var * Better error handling * Delete discord * Move Sendgrid to app router * Fix export * Upgrade routes to return 400 on missing params * Add status codes * Check status returned * Test settings getter * Feature/posthog frontend (#242) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Frontend analytics * Change export * Fix export * Fix export * Feature/posthog backend (#243) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Create posthog.ts * Add types, move to utils * Capture posthog event * Change export * Fix export * Fix export * Check dev env * Extract response types * Use responseTypes * Fix settings to use data response * Early return if no apiKey * Add error events * Remove event logging * Use request URL to pass to posthog * Extract tracking * Use tracker object * Move to route * Fix typo * Create route groups * Fix imports * Delete layout.tsx * Feature/posthog frontend (#242) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Frontend analytics * Change export * Fix export * Fix export * Move discord * Use standard var * Better error handling * Delete discord * Move Sendgrid to app router * Fix export * Upgrade routes to return 400 on missing params * Add status codes * Check status returned * Test settings getter * Feature/posthog frontend (#242) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Frontend analytics * Change export * Fix export * Fix export * Feature/posthog backend (#243) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Create posthog.ts * Add types, move to utils * Capture posthog event * Change export * Fix export * Fix export * Check dev env * Extract response types * Use responseTypes * Fix settings to use data response * Early return if no apiKey * Add error events * Remove event logging * Use request URL to pass to posthog * Extract tracking * Use tracker object * Move to route * Fix typo * Create route groups * Fix imports * Delete layout.tsx * Update route.ts * Delete discord * Remove discord * Delete discord * Delete discord * Remove pages folder * Delete azureAppInsights.ts * Remove unused files * Restore needed file * Fix user getting in index --- .../analytics/vsmarketplace/update/route.ts | 7 +- app/api/stripe/createSubscription/route.ts | 8 ++- components/DiscordLoginLink.tsx | 19 ----- components/loginGrid.tsx | 21 ------ utils/analytics/azureAppInsights.ts | 17 ----- utils/api/getAllUserData.ts | 15 ---- utils/api/getAllUserPublicData.ts | 2 +- utils/api/getBitbucketInfo.ts | 16 ----- utils/api/getDiscordInfo.ts | 15 ---- utils/api/getGitHubInfo.ts | 15 ---- utils/api/getGitLabInfo.ts | 15 ---- utils/api/getJiraInfo.ts | 13 ---- utils/api/getPaymentInfo.ts | 21 ------ utils/api/getSlackInfo.ts | 15 ---- utils/bitbucket/getUserData.ts | 16 ----- utils/db/bitbucket/getUser.ts | 13 ---- utils/db/discord/getAPIAccessInfo.ts | 14 ---- utils/db/discord/getUser.ts | 13 ---- utils/db/discord/saveUser.ts | 16 ----- utils/db/discord/updateTokens.ts | 22 ------ utils/db/gitlab/getUser.ts | 13 ---- utils/discord/refreshTokens.ts | 19 ----- utils/discord/updateTokens.ts | 34 --------- utils/gitlab/getAllIssues.ts | 18 ----- utils/gitlab/getAssignedIssues.ts | 25 ------- utils/gitlab/getCreatorIssues.ts | 25 ------- utils/gitlab/getIssue.ts | 29 -------- utils/gitlab/getIssueComments.ts | 34 --------- utils/gitlab/getIssuesByCommits.ts | 70 ------------------- utils/gitlab/postCommentOnIssue.ts | 39 ----------- utils/jira/commentOnJiraTicket.ts | 62 ---------------- utils/jira/getAssignedTickets.ts | 42 ----------- utils/jira/getUserId.js | 33 --------- utils/slack/addMessageToThread.ts | 46 ------------ utils/slack/getConversationReplies.ts | 54 -------------- utils/slack/sendMessageToChannel.ts | 38 ---------- 36 files changed, 12 insertions(+), 862 deletions(-) delete mode 100644 components/DiscordLoginLink.tsx delete mode 100644 utils/analytics/azureAppInsights.ts delete mode 100644 utils/api/getAllUserData.ts delete mode 100644 utils/api/getBitbucketInfo.ts delete mode 100644 utils/api/getDiscordInfo.ts delete mode 100644 utils/api/getGitHubInfo.ts delete mode 100644 utils/api/getGitLabInfo.ts delete mode 100644 utils/api/getJiraInfo.ts delete mode 100644 utils/api/getPaymentInfo.ts delete mode 100644 utils/api/getSlackInfo.ts delete mode 100644 utils/bitbucket/getUserData.ts delete mode 100644 utils/db/bitbucket/getUser.ts delete mode 100644 utils/db/discord/getAPIAccessInfo.ts delete mode 100644 utils/db/discord/getUser.ts delete mode 100644 utils/db/discord/saveUser.ts delete mode 100644 utils/db/discord/updateTokens.ts delete mode 100644 utils/db/gitlab/getUser.ts delete mode 100644 utils/discord/refreshTokens.ts delete mode 100644 utils/discord/updateTokens.ts delete mode 100644 utils/gitlab/getAllIssues.ts delete mode 100644 utils/gitlab/getAssignedIssues.ts delete mode 100644 utils/gitlab/getCreatorIssues.ts delete mode 100644 utils/gitlab/getIssue.ts delete mode 100644 utils/gitlab/getIssueComments.ts delete mode 100644 utils/gitlab/getIssuesByCommits.ts delete mode 100644 utils/gitlab/postCommentOnIssue.ts delete mode 100644 utils/jira/commentOnJiraTicket.ts delete mode 100644 utils/jira/getAssignedTickets.ts delete mode 100644 utils/jira/getUserId.js delete mode 100644 utils/slack/addMessageToThread.ts delete mode 100644 utils/slack/getConversationReplies.ts delete mode 100644 utils/slack/sendMessageToChannel.ts diff --git a/app/api/analytics/vsmarketplace/update/route.ts b/app/api/analytics/vsmarketplace/update/route.ts index 089f35d75..aa40c7be5 100644 --- a/app/api/analytics/vsmarketplace/update/route.ts +++ b/app/api/analytics/vsmarketplace/update/route.ts @@ -2,7 +2,7 @@ import { NextResponse } from "next/server"; import validateParams from "../../../../../utils/api/validateParams"; import Airtable from "airtable"; import { missingParamsResponse } from "../../../../../utils/api/responses"; -import { missingParamsPosthogTracking } from "../../../../../utils/api/posthogTracking"; +import posthog from "../../../../../utils/posthog/posthog"; Airtable.configure({ endpointUrl: "https://api.airtable.com", apiKey: process.env.AIRTABLE_API_KEY, @@ -33,7 +33,10 @@ export async function POST(request: Request) { const { missingParams } = validateParams(req, ["dailyStats"]); if (missingParams.length > 0) { - missingParamsPosthogTracking({ missingParams, url: request.url }); + posthog.capture({ + event: `${request.url}-missing-params`, + properties: missingParams, + }); return missingParamsResponse({ missingParams }); } const { dailyStats } = req; diff --git a/app/api/stripe/createSubscription/route.ts b/app/api/stripe/createSubscription/route.ts index 1afa680b8..d1c8d49d3 100644 --- a/app/api/stripe/createSubscription/route.ts +++ b/app/api/stripe/createSubscription/route.ts @@ -2,7 +2,8 @@ import { NextResponse } from "next/server"; import Stripe from "stripe"; import { missingParamsResponse } from "../../../../utils/api/responses"; import validateParams from "../../../../utils/api/validateParams"; -import { missingParamsPosthogTracking } from "../../../../utils/api/posthogTracking"; +import posthog from "../../../../utils/posthog/posthog"; + const stripe = new Stripe(process.env.NEXT_PUBLIC_STRIPE_SECRET_KEY!, { apiVersion: "2022-08-01", }); @@ -12,7 +13,10 @@ export async function POST(request: Request) { const { missingParams } = validateParams(req, ["email"]); if (missingParams.length > 0) { - missingParamsPosthogTracking({ missingParams, url: request.url }); + posthog.capture({ + event: `${request.url}-missing-params`, + properties: missingParams, + }); return missingParamsResponse({ missingParams }); } try { diff --git a/components/DiscordLoginLink.tsx b/components/DiscordLoginLink.tsx deleted file mode 100644 index e8bb44b0b..000000000 --- a/components/DiscordLoginLink.tsx +++ /dev/null @@ -1,19 +0,0 @@ -import Link from "next/link"; - -const DiscordLoginLink = ({ userEmail }) => ( -
- -
- -
-

Login to Discord

-

View your Messages from the selected Server

-
-
- -
-); -export default DiscordLoginLink; diff --git a/components/loginGrid.tsx b/components/loginGrid.tsx index 47d1e3ac4..784516c75 100644 --- a/components/loginGrid.tsx +++ b/components/loginGrid.tsx @@ -5,7 +5,6 @@ import GitHubLoginLink from "../components/GitHubLoginLink"; import GitLabLoginLink from "../components/GitLabLoginLink"; import BitbucketLoginLink from "../components/BitbucketLoginLink"; import LinearLoginLink from "../components/LinearLoginLink"; -import DiscordLoginLink from "./DiscordLoginLink"; import NotionLoginLink from "./NotionLoginLink"; import ConfluenceLoginLink from "./ConfluenceLoginLink"; type LoginGridProps = { @@ -19,7 +18,6 @@ function LoginGrid({ userEmail, data }) { let slackUserData: null | LoginGridProps = null; let jiraUserData: null | LoginGridProps = null; let confluenceUserData: null | LoginGridProps = null; - let discordUserData: null | LoginGridProps = null; let notionUserData: null | LoginGridProps = null; let linearUserData: null | LoginGridProps = null; if (data?.github_data) { @@ -40,9 +38,6 @@ function LoginGrid({ userEmail, data }) { if (data?.confluence_data) { confluenceUserData = JSON.parse(data.confluence_data); } - if (data?.discord_data) { - discordUserData = JSON.parse(data.discord_data); - } if (data?.notion_data) { notionUserData = JSON.parse(data.notion_data); } @@ -202,22 +197,6 @@ function LoginGrid({ userEmail, data }) { )} - {/* - DISCORD DOES NOT ALLOW MESSAGE SEARCH, DEVELOPMENT PAUSED FOR NOW - MAYBE READ THE LAST FEW DAYS? -
- {discordUserData?.user_displayname ? ( - - ) : ( - - )} -
*/}
diff --git a/utils/analytics/azureAppInsights.ts b/utils/analytics/azureAppInsights.ts deleted file mode 100644 index a8503f7a8..000000000 --- a/utils/analytics/azureAppInsights.ts +++ /dev/null @@ -1,17 +0,0 @@ -const appInsights = require("applicationinsights"); -const instrumentationKey = - "InstrumentationKey=bb2eac7f-33dd-426c-92c5-4dd922b2befb;IngestionEndpoint=https://eastus-8.in.applicationinsights.azure.com/;LiveEndpoint=https://eastus.livediagnostics.monitor.azure.com/"; - -appInsights - .setup(instrumentationKey) - .setAutoDependencyCorrelation(true) - .setAutoCollectRequests(true) - .setAutoCollectPerformance(true) - .setAutoCollectExceptions(true) - .setAutoCollectDependencies(true) - .setAutoCollectConsole(true) - .start(); -let client = appInsights.defaultClient; -export function trackEvent({ name, properties }) { - client.trackEvent({ name, properties }); -} diff --git a/utils/api/getAllUserData.ts b/utils/api/getAllUserData.ts deleted file mode 100644 index 9fc442758..000000000 --- a/utils/api/getAllUserData.ts +++ /dev/null @@ -1,15 +0,0 @@ -const getAllUserData = async (userEmail: string) => { - const data = await fetch("/api/user/getAllPublicUserData", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - userEmail, - }), - }) - .then((res) => res.json()) - .catch((err) => console.error(err)); - return data; -}; -export default getAllUserData; diff --git a/utils/api/getAllUserPublicData.ts b/utils/api/getAllUserPublicData.ts index 3edeeca73..d53487853 100644 --- a/utils/api/getAllUserPublicData.ts +++ b/utils/api/getAllUserPublicData.ts @@ -1,6 +1,6 @@ import "server-only"; import getAllPublicUserData from "../db/user/getAllPublicUserData"; export default async function getData({ userEmail }) { - let dbUser = await getAllPublicUserData(userEmail); + let dbUser = await getAllPublicUserData({ email: userEmail }); return dbUser; } diff --git a/utils/api/getBitbucketInfo.ts b/utils/api/getBitbucketInfo.ts deleted file mode 100644 index 53147429e..000000000 --- a/utils/api/getBitbucketInfo.ts +++ /dev/null @@ -1,16 +0,0 @@ -const getBitbucketInfo = async (userEmail: string) => { - console.log(userEmail); - const data = await fetch("/api/bitbucket/getUser", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email: userEmail, - }), - }) - .then((res) => res.json()) - .catch((err) => console.error(err)); - return data; -}; -export default getBitbucketInfo; diff --git a/utils/api/getDiscordInfo.ts b/utils/api/getDiscordInfo.ts deleted file mode 100644 index 152a81d02..000000000 --- a/utils/api/getDiscordInfo.ts +++ /dev/null @@ -1,15 +0,0 @@ -const getDiscordInfo = async (userEmail: string) => { - const data = await fetch("/api/discord/getUser", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email: userEmail, - }), - }) - .then((res) => res.json()) - .catch((err) => console.log(err)); - return data; -}; -export default getDiscordInfo; diff --git a/utils/api/getGitHubInfo.ts b/utils/api/getGitHubInfo.ts deleted file mode 100644 index 71e29834f..000000000 --- a/utils/api/getGitHubInfo.ts +++ /dev/null @@ -1,15 +0,0 @@ -const getGitHubInfo = async (userEmail: string) => { - const data = await fetch("/api/github/getUser", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - user: userEmail, - }), - }) - .then((res) => res.json()) - .catch((err) => console.error(err)); - return data; -}; -export default getGitHubInfo; diff --git a/utils/api/getGitLabInfo.ts b/utils/api/getGitLabInfo.ts deleted file mode 100644 index 55c3dd90b..000000000 --- a/utils/api/getGitLabInfo.ts +++ /dev/null @@ -1,15 +0,0 @@ -const getGitLabInfo = async (userEmail: string) => { - const data = await fetch("/api/gitlab/getUser", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - user: userEmail, - }), - }) - .then((res) => res.json()) - .catch((err) => console.error(err)); - return data; -}; -export default getGitLabInfo; diff --git a/utils/api/getJiraInfo.ts b/utils/api/getJiraInfo.ts deleted file mode 100644 index 47a11dcdc..000000000 --- a/utils/api/getJiraInfo.ts +++ /dev/null @@ -1,13 +0,0 @@ -const getJiraInfo = async (userEmail: string) => { - const data = await fetch("/api/jira/getUser", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - user: userEmail, - }), - }).then((res) => res.json()); - return data; -}; -export default getJiraInfo; diff --git a/utils/api/getPaymentInfo.ts b/utils/api/getPaymentInfo.ts deleted file mode 100644 index 421640674..000000000 --- a/utils/api/getPaymentInfo.ts +++ /dev/null @@ -1,21 +0,0 @@ -const getPaymentInfo = async (email: string) => { - const data = await fetch("/api/payments/getByEmail", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - email, - }), - }) - .then((res) => res.json()) - .then((data) => { - if (data.email) { - return true; - } else { - return false; - } - }); - return data; -}; -export default getPaymentInfo; diff --git a/utils/api/getSlackInfo.ts b/utils/api/getSlackInfo.ts deleted file mode 100644 index 4587c4e73..000000000 --- a/utils/api/getSlackInfo.ts +++ /dev/null @@ -1,15 +0,0 @@ -const getSlackInfo = async (userEmail: string) => { - const data = await fetch("/api/slack/getUser", { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - user: userEmail, - }), - }) - .then((res) => res.json()) - .catch((err) => console.error(err)); - return data; -}; -export default getSlackInfo; diff --git a/utils/bitbucket/getUserData.ts b/utils/bitbucket/getUserData.ts deleted file mode 100644 index 5cc1b59b0..000000000 --- a/utils/bitbucket/getUserData.ts +++ /dev/null @@ -1,16 +0,0 @@ -export default async ({ code }) => { - try { - let response = await fetch("https://api.bitbucket.org/2.0/user", { - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - }, - body: `grant_type=authorization_code&code=${code}`, - }); - let data = await response.json(); - return data; - } catch (error) { - console.error(error); - return error; - } -}; diff --git a/utils/db/bitbucket/getUser.ts b/utils/db/bitbucket/getUser.ts deleted file mode 100644 index 6e0e43ad5..000000000 --- a/utils/db/bitbucket/getUser.ts +++ /dev/null @@ -1,13 +0,0 @@ -import executeRequest from "../azuredb"; - -export default async function getUser(email): Promise { - try { - let data = await executeRequest( - `EXEC dbo.get_bitbucket_user @watermelon_user = '${email}'` - ); - return data; - } catch (err) { - console.error(err); - return err; - } -} diff --git a/utils/db/discord/getAPIAccessInfo.ts b/utils/db/discord/getAPIAccessInfo.ts deleted file mode 100644 index 8c165d141..000000000 --- a/utils/db/discord/getAPIAccessInfo.ts +++ /dev/null @@ -1,14 +0,0 @@ -import executeRequest from "../azuredb"; -export default async function getAPIAccessInfo(user: string): Promise<{ - access_token: string; - refresh_token: string; -}> { - try { - let query = `EXEC dbo.get_discord_tokens @watermelon_user='${user}'`; - let resp = await executeRequest(query); - return resp; - } catch (error) { - console.error(error); - return error; - } -} diff --git a/utils/db/discord/getUser.ts b/utils/db/discord/getUser.ts deleted file mode 100644 index 5c54d5399..000000000 --- a/utils/db/discord/getUser.ts +++ /dev/null @@ -1,13 +0,0 @@ -import executeRequest from "../azuredb"; - -export default async function getUser(email): Promise { - try { - let data = await executeRequest( - `EXEC dbo.get_discord_user @watermelon_user = '${email}'` - ); - return data; - } catch (err) { - console.error(err); - return err; - } -} diff --git a/utils/db/discord/saveUser.ts b/utils/db/discord/saveUser.ts deleted file mode 100644 index acc5df3e6..000000000 --- a/utils/db/discord/saveUser.ts +++ /dev/null @@ -1,16 +0,0 @@ -import executeRequest from "../azuredb"; - -export default async ({ - access_token, - refresh_token, - username, - id, - avatar_url, - scope, - watermelon_user, - email, -}) => { - let query = `EXEC dbo.create_discord @watermelon_user='${watermelon_user}', @username='${username}', @id='${id}', @avatar_url='${avatar_url}', @scope='${scope}', @email='${email}', @access_token='${access_token}', @refresh_token='${refresh_token}'`; - let resp = await executeRequest(query); - return resp; -}; diff --git a/utils/db/discord/updateTokens.ts b/utils/db/discord/updateTokens.ts deleted file mode 100644 index 1075cf39a..000000000 --- a/utils/db/discord/updateTokens.ts +++ /dev/null @@ -1,22 +0,0 @@ -import executeRequest from "../azuredb"; - -export default async function updateTokens({ - user, - access_token, - refresh_token, -}: { - user: string; - access_token: string; - refresh_token: string; -}): Promise { - try { - if (user && access_token && refresh_token) { - let query = `EXEC dbo.update_discord_tokens @user='${user}', @access_token='${access_token}', @refresh_token='${refresh_token}'`; - let resp = await executeRequest(query); - return resp; - } - } catch (error) { - console.error(error); - return error; - } -} diff --git a/utils/db/gitlab/getUser.ts b/utils/db/gitlab/getUser.ts deleted file mode 100644 index 8d3bdbe14..000000000 --- a/utils/db/gitlab/getUser.ts +++ /dev/null @@ -1,13 +0,0 @@ -import executeRequest from "../azuredb"; - -export default async function getUser(user): Promise { - try { - let data = await executeRequest( - `EXEC dbo.get_gitlab_user @watermelon_user = '${user}'` - ); - return data; - } catch (err) { - console.error(err); - return err; - } -} diff --git a/utils/discord/refreshTokens.ts b/utils/discord/refreshTokens.ts deleted file mode 100644 index ce8106d91..000000000 --- a/utils/discord/refreshTokens.ts +++ /dev/null @@ -1,19 +0,0 @@ -import updateTokens from "../db/discord/updateTokens"; -import updateTokensFromDiscord from "./updateTokens"; -import getAPIAccessInfo from "../db/discord/getAPIAccessInfo"; - -export default async ({ user }) => { - try { - let { refresh_token } = await getAPIAccessInfo(user); - let newAccessTokens = await updateTokensFromDiscord({ refresh_token }); - await updateTokens({ - access_token: newAccessTokens.access_token, - refresh_token: newAccessTokens.refresh_token, - user, - }); - return { access_token: newAccessTokens.access_token }; - } catch (error) { - console.error(error); - return error; - } -}; diff --git a/utils/discord/updateTokens.ts b/utils/discord/updateTokens.ts deleted file mode 100644 index f4e854e42..000000000 --- a/utils/discord/updateTokens.ts +++ /dev/null @@ -1,34 +0,0 @@ -export default async function updateTokens({ - refresh_token, -}: { - refresh_token: string; -}): Promise<{ access_token: string; refresh_token: string }> { - try { - let newAccessTokens = await fetch( - "https://discord.com/api/v10/oauth/token", - { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - grant_type: "refresh_token", - client_id: process.env.DISCORD_CLIENT_ID, - client_secret: process.env.DISCORD_CLIENT_SECRET, - refresh_token: refresh_token, - }), - } - ) - .then((response) => response.json()) - .catch((error) => { - console.error(error); - }); - return { - access_token: newAccessTokens.access_token, - refresh_token: newAccessTokens.refresh_token, - }; - } catch (error) { - console.error(error); - return error; - } -} diff --git a/utils/gitlab/getAllIssues.ts b/utils/gitlab/getAllIssues.ts deleted file mode 100644 index f3bc266d4..000000000 --- a/utils/gitlab/getAllIssues.ts +++ /dev/null @@ -1,18 +0,0 @@ -export default async function getAssignedIssues({ access_token }) { - try { - return await fetch(`https://gitlab.com/api/v4/issues`, { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${access_token}`, - }, - }) - .then((response) => response.json()) - .catch((error) => { - console.error(error); - }); - } catch (error) { - console.error(error); - return error; - } -} diff --git a/utils/gitlab/getAssignedIssues.ts b/utils/gitlab/getAssignedIssues.ts deleted file mode 100644 index b4207ce4d..000000000 --- a/utils/gitlab/getAssignedIssues.ts +++ /dev/null @@ -1,25 +0,0 @@ -export default async function getAssignedIssues({ - userId, - access_token, - project_id, -}) { - try { - return await fetch( - `https://gitlab.com/api/v4/projects/${project_id}/issues?assignee_id=${userId}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${access_token}`, - }, - } - ) - .then((response) => response.json()) - .catch((error) => { - console.error(error); - }); - } catch (error) { - console.error(error); - return error; - } -} diff --git a/utils/gitlab/getCreatorIssues.ts b/utils/gitlab/getCreatorIssues.ts deleted file mode 100644 index 273fdb327..000000000 --- a/utils/gitlab/getCreatorIssues.ts +++ /dev/null @@ -1,25 +0,0 @@ -export default async function getCreatorIssues({ - userId, - access_token, - project_id, -}) { - try { - return await fetch( - `https://gitlab.com/api/v4/projects/${project_id}/issues?author_id=${userId}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${access_token}`, - }, - } - ) - .then((response) => response.json()) - .catch((error) => { - console.error(error); - }); - } catch (error) { - console.error(error); - return error; - } -} diff --git a/utils/gitlab/getIssue.ts b/utils/gitlab/getIssue.ts deleted file mode 100644 index 00e09f7b3..000000000 --- a/utils/gitlab/getIssue.ts +++ /dev/null @@ -1,29 +0,0 @@ -export default async function getIssue({ - access_token, - issue_iid, - project_id, -}: { - access_token: string; - issue_iid: string; - project_id: string; -}): Promise<{ any }> { - try { - return await fetch( - `https://gitlab.com/api/v4/projects/${project_id}/issues/${issue_iid}`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${access_token}`, - }, - } - ) - .then((response) => response.json()) - .catch((error) => { - console.error(error); - }); - } catch (error) { - console.error(error); - return error; - } -} diff --git a/utils/gitlab/getIssueComments.ts b/utils/gitlab/getIssueComments.ts deleted file mode 100644 index 7233a55b6..000000000 --- a/utils/gitlab/getIssueComments.ts +++ /dev/null @@ -1,34 +0,0 @@ -export default async function getIssue({ - access_token, - issue_iid, - owner, - project_name, -}: { - access_token: string; - issue_iid: string; - owner: string; - project_name: string; -}): Promise<{ any }> { - try { - const urlEncodedProjectPath = encodeURIComponent( - `${owner}/${project_name}` - ); - return await fetch( - `https://gitlab.com/api/v4/projects/${urlEncodedProjectPath}/issues/${issue_iid}/notes`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${access_token}`, - }, - } - ) - .then((response) => response.json()) - .catch((error) => { - console.error(error); - }); - } catch (error) { - console.error(error); - return error; - } -} diff --git a/utils/gitlab/getIssuesByCommits.ts b/utils/gitlab/getIssuesByCommits.ts deleted file mode 100644 index a85204d1c..000000000 --- a/utils/gitlab/getIssuesByCommits.ts +++ /dev/null @@ -1,70 +0,0 @@ -async function getMergeRequestsForCommit( - access_token: string, - owner: string, - project_name: string, - commit: string -) { - try { - const urlEncodedProjectPath = encodeURIComponent( - `${owner}/${project_name}` - ); - return await fetch( - `https://gitlab.com/api/v4/projects/${urlEncodedProjectPath}/repository/commits/${commit}/merge_requests`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${access_token}`, - }, - } - ) - .then((response) => response.json()) - .then((data) => data) - .catch((error) => { - console.error(error); - }); - } catch (error) { - console.error(error); - return error; - } -} - -export default async function getIssuesByCommits({ - access_token, - commitList, - owner, - project_name, -}: { - access_token: string; - commitList: string; - project_name: string; - owner: string; -}) { - let localCommitList = commitList.split(","); - const requests = localCommitList.map((commit) => - getMergeRequestsForCommit(access_token, owner, project_name, commit) - ); - const responses = await Promise.all(requests); - let commentsPromises = responses.map(async (response, index) => { - return await fetch( - `https://gitlab.com/api/v4/projects/${response[0].project_id}/merge_requests/${response[0].iid}/notes`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${access_token}`, - }, - } - ) - .then((commentResp) => commentResp.json()) - .then((data) => { - responses[index][0].comments = data; - return responses; - }) - .catch((error) => { - console.error(error); - }); - }); - await Promise.allSettled(commentsPromises); - return responses.flatMap((response) => response); -} diff --git a/utils/gitlab/postCommentOnIssue.ts b/utils/gitlab/postCommentOnIssue.ts deleted file mode 100644 index efba56382..000000000 --- a/utils/gitlab/postCommentOnIssue.ts +++ /dev/null @@ -1,39 +0,0 @@ -export default async function postCommentOnIssue({ - access_token, - issue_iid, - owner, - project_name, - comment_body, -}: { - access_token: string; - issue_iid: string; - owner: string; - project_name: string; - comment_body: string; -}): Promise<{ any }> { - try { - const urlEncodedProjectPath = encodeURIComponent( - `${owner}/${project_name}` - ); - return await fetch( - `https://gitlab.com/api/v4/projects/${urlEncodedProjectPath}/issues/${issue_iid}/notes`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - Authorization: `Bearer ${access_token}`, - }, - body: JSON.stringify({ - body: "🍉 " + comment_body, - }), - } - ) - .then((response) => response.json()) - .catch((error) => { - console.error(error); - }); - } catch (error) { - console.error(error); - return error; - } -} diff --git a/utils/jira/commentOnJiraTicket.ts b/utils/jira/commentOnJiraTicket.ts deleted file mode 100644 index 2df9cc034..000000000 --- a/utils/jira/commentOnJiraTicket.ts +++ /dev/null @@ -1,62 +0,0 @@ -import fnTranslate from "md-to-adf"; - -export default async function handler({ - issueIdOrKey, - text, - access_token, - cloudId, -}: { - issueIdOrKey: string; - text: string; - access_token: string; - cloudId: string; -}) { - if (!cloudId) { - return { error: "no cloudId" }; - } - if (!access_token) { - return { error: "no access_token" }; - } - if (!issueIdOrKey) { - return { error: "no issueIdOrKey" }; - } - if (!text) { - return { error: "no text" }; - } - let bodyToSend = JSON.stringify({ - body: { - type: "doc", - version: 1, - content: [ - { - type: "paragraph", - content: [ - { - text: "🍉 " + text, - type: "text", - }, - ], - }, - ], - }, - }); - console.log(fnTranslate(text)); - try { - return await fetch( - `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/issue/${issueIdOrKey}/comment`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - "Accept-Encoding": "deflate", - Accept: "application/json", - Authorization: `Bearer ${access_token}`, - }, - body: bodyToSend, - } - ).then((res) => res.json()); - } catch (error) { - console.error(error); - return error; - } -} diff --git a/utils/jira/getAssignedTickets.ts b/utils/jira/getAssignedTickets.ts deleted file mode 100644 index 5a68b6842..000000000 --- a/utils/jira/getAssignedTickets.ts +++ /dev/null @@ -1,42 +0,0 @@ -import getUserId from "./getUserId"; - -export default async function handler(req, res) { - let userID = getUserId(); - let { cloudId, access_token } = req.body; - let returnVal; - if (!cloudId) { - res.send({ error: "no cloudId" }); - } - if (!access_token) { - res.send({ error: "no access_token" }); - } - try { - await fetch( - `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/search`, - { - method: "POST", - headers: { - "Content-Type": "application/json", - Accept: "application/json", - Authorization: `Bearer ${access_token}`, - }, - body: JSON.stringify({ - jql: `assignee = ${userID}`, - fields: ["summary", "status", "assignee", "created", "updated"], - }), - } - ) - .then((res) => { - console.log(res.body); - res.json(); - }) - .then((resJson) => { - console.log(resJson); - returnVal = resJson; - }); - return res.send(returnVal); - } catch (error) { - console.error(error); - return res.send(error); - } -} diff --git a/utils/jira/getUserId.js b/utils/jira/getUserId.js deleted file mode 100644 index 97234866f..000000000 --- a/utils/jira/getUserId.js +++ /dev/null @@ -1,33 +0,0 @@ -var zlib = require("zlib"); -export default async function getUserId(req, res) { - let { cloudId, access_token } = req.body; - let returnVal; - if (!cloudId) { - res.send({ error: "no cloudId" }); - } - if (!access_token) { - res.send({ error: "no access_token" }); - } - await fetch( - `https://api.atlassian.com/ex/jira/${cloudId}/rest/api/3/myself`, - { - method: "GET", - headers: { - "Content-Type": "application/json", - Accept: "application/json", - Authorization: `Bearer ${access_token}`, - }, - } - ) - .then((res) => { - console.log(res.body); - var output = zlib.inflate(res.body); - console.log(output); - res.json(); - }) - .then((resJson) => { - console.log(resJson); - returnVal = resJson.accountId; - }); - return (returnVal); -} diff --git a/utils/slack/addMessageToThread.ts b/utils/slack/addMessageToThread.ts deleted file mode 100644 index eb0059de4..000000000 --- a/utils/slack/addMessageToThread.ts +++ /dev/null @@ -1,46 +0,0 @@ -export default async function handler({ - channelId, - text, - user_token, - threadTS, - broadcast, -}: { - channelId: string; - text: string; - user_token: string; - threadTS: string; - broadcast?: boolean; -}) { - if (!channelId) { - return { error: "no channelId" }; - } - if (!text) { - return { error: "no text" }; - } - if (!user_token) { - return { error: "no user_token" }; - } - if (!threadTS) { - return { error: "no threadTS" }; - } - try { - return await fetch(`https://slack.com/api/chat.postMessage`, { - method: "POST", - headers: { - "Content-Type": "application/json; charset=utf-8", - "Accept-Encoding": "deflate", - Accept: "application/json", - Authorization: `Bearer ${user_token}`, - }, - body: JSON.stringify({ - channel: channelId, - text: text, - thread_ts: threadTS, - reply_broadcast: broadcast, - }), - }).then((res) => res.json()); - } catch (error) { - console.error(error); - return error; - } -} diff --git a/utils/slack/getConversationReplies.ts b/utils/slack/getConversationReplies.ts deleted file mode 100644 index e5999098f..000000000 --- a/utils/slack/getConversationReplies.ts +++ /dev/null @@ -1,54 +0,0 @@ -export default async function handler({ - channelId, - ts, - user_token, -}: { - channelId: string; - ts: string; - user_token: string; -}) { - if (!channelId) { - return { error: "no channelId" }; - } - if (!ts) { - return { error: "no ts" }; - } - if (!user_token) { - return { error: "no user_token" }; - } - try { - const replies = await fetch(`https://slack.com/api/conversations.replies`, { - method: "POST", - headers: { - "Content-Type": "application/x-www-form-urlencoded", - "Accept-Encoding": "deflate", - Accept: "application/json", - Authorization: `Bearer ${user_token}`, - }, - body: `channel=${channelId}&ts=${ts}&include_all_metadata=true`, - }).then((res) => res.json()); - const promises = replies.messages.map(async (element, index) => { - return await fetch( - `https://slack.com/api/users.info?user=${element.user}`, - { - method: "GET", - headers: { - "Content-Type": "application/json; charset=utf-8", - "Accept-Encoding": "deflate", - Accept: "application/json", - Authorization: `Bearer ${user_token}`, - }, - } - ) - .then((res) => res.json()) - .then((json) => { - replies.messages[index].userInfo = json; - }); - }); - await Promise.allSettled(promises); - return replies; - } catch (error) { - console.error(error); - return error; - } -} diff --git a/utils/slack/sendMessageToChannel.ts b/utils/slack/sendMessageToChannel.ts deleted file mode 100644 index d4dc6e02b..000000000 --- a/utils/slack/sendMessageToChannel.ts +++ /dev/null @@ -1,38 +0,0 @@ -export default async function handler({ - channelId, - text, - user_token, -}: { - channelId: string; - text: string; - user_token: string; -}) { - if (!channelId) { - return { error: "no channelId" }; - } - if (!text) { - return { error: "no text" }; - } - if (!user_token) { - return { error: "no user_token" }; - } - - try { - return await fetch(`https://slack.com/api/chat.postMessage`, { - method: "POST", - headers: { - "Content-Type": "application/json; charset=utf-8", - "Accept-Encoding": "deflate", - Accept: "application/json", - Authorization: `Bearer ${user_token}`, - }, - body: JSON.stringify({ - channel: channelId, - text: "🍉 " + text, - }), - }).then((res) => res.json()); - } catch (error) { - console.error(error); - return error; - } -} From b174fd60ddb997b0c2866565ee43aee6d9a2cb73 Mon Sep 17 00:00:00 2001 From: Esteban Dalel R Date: Wed, 6 Sep 2023 18:42:44 -0500 Subject: [PATCH 010/147] Feature/new integrations script (#272) * Move discord * Use standard var * Better error handling * Delete discord * Move Sendgrid to app router * Fix export * Upgrade routes to return 400 on missing params * Add status codes * Check status returned * Test settings getter * Feature/posthog frontend (#242) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Frontend analytics * Change export * Fix export * Fix export * Feature/posthog backend (#243) * Create param validator * Move discord * Move user settings getter to app router * Use standard var * move getAllPublicUserData to app router * Better error handling * Delete getAllData.ts * Delete discord * Throw errors * Handle error throwing * Move updateSettings to app router * Update confluence.svg * Configure jest * Create settings.test.ts * Create updateSettings.test.ts * Add getting test * Use generalized validator * Move Stripe to app router * Move Sendgrid to app router * Move vscode to airtable Analytics to app router * Create posthog.ts * Add types, move to utils * Capture posthog event * Change export * Fix export * Fix export * Check dev env * Extract response types * Use responseTypes * Fix settings to use data response * Early return if no apiKey * Add error events * Remove event logging * Use request URL to pass to posthog * Extract tracking * Use tracker object * Move to route * Fix typo * Create route groups * Fix imports * Delete layout.tsx * Create AsanaLoginLink.tsx * Create guide to adding a new Oauth service * Add asana * Add asana * Add asana * Add SQL for new services * Add env vars sections * Update CONTRIBUTING.md * Add lang descriptors * Create script to allow quick integrations * Update CONTRIBUTING.md * Delete discord * Fix tracking * Fix import * Fix import * Roll back hover to dev * Fix tracking * Fix typo * Extract service list * Use correct prop * Simplify code * Data reorg * Fix param for getting user data * Update CONTRIBUTING.md * Improve text * Improve SQL section * Update CONTRIBUTING.md * Add last steps --- CONTRIBUTING.md | 166 ++++++++++- app/(loggedIn)/atlassian/loading.tsx | 2 +- app/(loggedIn)/atlassian/page.tsx | 2 +- app/(loggedIn)/bitbucket/loading.tsx | 2 +- app/(loggedIn)/bitbucket/page.tsx | 2 +- app/(loggedIn)/github/loading.tsx | 2 +- app/(loggedIn)/github/page.tsx | 2 +- app/(loggedIn)/gitlab/loading.tsx | 2 +- app/(loggedIn)/gitlab/page.tsx | 2 +- app/(loggedIn)/jira/loading.tsx | 2 +- app/(loggedIn)/jira/page.tsx | 2 +- app/(loggedIn)/linear/loading.tsx | 2 +- app/(loggedIn)/linear/page.tsx | 2 +- app/(loggedIn)/notion/loading.tsx | 2 +- app/(loggedIn)/notion/page.tsx | 2 +- app/(loggedIn)/page.tsx | 3 +- app/(loggedIn)/settings/form.tsx | 56 +++- app/(loggedIn)/slack/loading.tsx | 2 +- app/(loggedIn)/slack/page.tsx | 2 +- app/(loggedIn)/vscode-insiders/page.tsx | 2 +- app/(loggedIn)/vscode/page.tsx | 2 +- app/(loggedIn)/vscodium/page.tsx | 2 +- app/api/stripe/createSubscription/route.ts | 3 +- components/AsanaLoginLink.tsx | 19 ++ components/loginGrid.tsx | 329 +++++++-------------- components/services/loginArray.tsx | 6 + newIntegration.sh | 139 +++++++++ next-env.d.ts | 1 - utils/api/getAllUserPublicData.ts | 5 +- 29 files changed, 499 insertions(+), 266 deletions(-) create mode 100644 components/AsanaLoginLink.tsx create mode 100755 newIntegration.sh diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e7b33a411..90c3b3b1c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -12,29 +12,29 @@ Anyone is free to contribute changes to any file in this repository. You don't n To start developing, clone and: -``` +```bash yarn yarn dev ``` Or with npm -``` +```bash npm i npm run dev ``` (Check your node version, we recommend 18) -We use a recent version of Next. You may refer to the documentation at https://nextjs.org/docs/. +We use a recent version of Next. You may refer to the [documentation](https://nextjs.org/docs/). This repo is automatically deployed on vercel to [app.watermelontools.com](app.watermelontools.com) on merges to `main`. All the backend lives as serverless functions under `api`, with the route being the filename. -We now use the new app router for some features. +We now use the new app router for _all_ features. -As we now use OAuth2.0, local development cannot be done on new integrations. +As we use OAuth2.0, local development cannot be done on new integrations. All environment vars are on vercel, the committer is responsible for correct deployments. @@ -52,7 +52,7 @@ We have a `utils` folder that includes all the business logic. We have an `api` The developer has to match the `utils` folder structure to the `api` route schema. This makes it easier to maintain. -> As an example, we have `utils/user/getProfile.ts` that is imported in `pages/api/user/getProfile.ts` and returns a `types/UserProfile.ts`. In the database, you will find a _user_ table with all the data on the type. +> As an example, we have `utils/user/getProfile.ts` that is imported in `app/api/user/getProfile.ts` and returns a `types/UserProfile.ts`. In the database, you will find a _user_ table with all the data on the type. We do all of this as a security measure. We don't want data exposed and we consider our backend safe. @@ -64,6 +64,160 @@ First, we use oauth so you need to ensure that the service supports it. Remember that there are several procedures in our db to replicate. +The steps to do so are: + +- Publicly announce the new integration + > serviceName refers to the shortname, like `github` or `gitlab`, lowercase + > ServiceReadableName refers to the name of the service and it's use in the UI, like `GitHubPRs` or `LinearTasks` +- Set the necesary vercel env vars + > usually `SERVICE_CLIENT_SECRET` and `SERVICE_CLIENT_ID` +- Create the table in our DB + + > **This is sketch of a possible new table** + > + > _Add any other required columns as needed_ + +```sql + CREATE TABLE serviceName ( + id INT PRIMARY KEY, + name VARCHAR(255), + email VARCHAR(255), + updated_at DATETIME DEFAULT GETDATE() NOT NULL, + created_at DATETIME DEFAULT GETDATE() NOT NULL, + access_token VARCHAR(255), + refresh_token VARCHAR(255), + avatar_url VARCHAR(255), + workspace VARCHAR(255), + workspace_image VARCHAR(255), + watermelon_user VARCHAR(255), + deleted BIT DEFAULT 0 NULL, + deleted_at DATETIME DEFAULT GETDATE() NULL, + FOREIGN KEY (watermelon_user) REFERENCES watermelon.dbo.users(id) + ); +``` + +- Edit the userSettings table + + ```sql + ALTER TABLE userSettings ADD ServiceReadableName INT DEFAULT 3;` + ``` + + ```sql + UPDATE userSettings SET ServiceReadableName = 3 WHERE ServiceReadableName IS NULL; + ``` + +- Create the necessary procedures +- Setting the information for the user using `create_serviceName` + + ```sql + CREATE PROCEDURE dbo.create_serviceName + @access_token varchar(255), + @id varchar(255), + @name varchar(255), + @displayName varchar(255), + @email varchar(255), + @avatarUrl varchar(255), + @team_id varchar(255), + @team_name varchar(255), + @watermelon_user varchar(255) + AS + DECLARE @insertTable TABLE ( + access_token varchar(255), + id varchar(255), + name varchar(255), + displayName varchar(255), + email varchar(255), + avatarUrl varchar(255), + team_id varchar(255), + team_name varchar(255), + watermelon_user varchar(255) + ) + + DECLARE @wmid VARCHAR(255) = ( + SELECT + id + FROM + dbo.users + WHERE + email = @watermelon_user + ) + + INSERT + INTO + dbo.serviceName + ( + access_token, + id, + name, + displayName, + email, + avatarUrl, + team_id, + team_name, + watermelon_user + ) + OUTPUT + inserted.access_token, + inserted.id, + inserted.name, + inserted.displayName, + inserted.email, + inserted.avatarUrl, + inserted.team_id, + inserted.team_name, + inserted.watermelon_user + INTO + @insertTable + VALUES + ( + @access_token, + @id, + @name, + @displayName, + @email, + @avatarUrl, + @team_id, + @team_name, + @wmid + ) + + SELECT + * + FROM + @insertTable + FOR JSON PATH, + WITHOUT_ARRAY_WRAPPER + + ``` + +- Fetching the settings is unchanged as we use the same procedure for all services +- Edit the settings getter +- Fetching the tokens + + - Edit the procedure `get_all_user_tokens` to match the service + - Edit the procedure `get_all_tokens_from_gh_username` to match the service + +- Create a `ServiceLoginLink.ts` component in the `components` folder +- Add the service to the `loginArray.tsx` file +- Add the service to the `loginGrid.tsx` file in the correct section +- Add the service to `form.tsx` under _settings_ + +- Run the `newIntegration.sh` script which will: + + - Create the service folder under `(loggedIn)` + - Copy the `loading.tsx` from any other service + - Create the function under `/utils/db/service/saveUser` that you need to complete + - Populate the `page.tsx` file to be finished the correct service parameters + - Create an empty getter in `/utils/actions` + +- Now you need to edit the `page.tsx` file to match the service +- Get the data in the `getService.tsx` file under actions +- Add to the action log +- Pass the data to the AI in `utils/actions/getOpenAISummary.ts` file +- Return the data as Markdown in `api/actions/github/route.tsx` +- Return one result in `api/hover/route.tsx` +- Return the settings decided results in `api/extension/route.tsx` + ## Issues If there's something you'd like to see please [open an issue](https://github.com/watermelontools/watermelon/issues/new). diff --git a/app/(loggedIn)/atlassian/loading.tsx b/app/(loggedIn)/atlassian/loading.tsx index 4d2a4cea8..b7bed5f08 100644 --- a/app/(loggedIn)/atlassian/loading.tsx +++ b/app/(loggedIn)/atlassian/loading.tsx @@ -1,5 +1,5 @@ import LoadingConnectedService from "../../../components/services/loading"; -export default function loadingConnetedService() { +export default function loadingConnectedService() { return ; } diff --git a/app/(loggedIn)/atlassian/page.tsx b/app/(loggedIn)/atlassian/page.tsx index 1513eb00d..39adecc3d 100644 --- a/app/(loggedIn)/atlassian/page.tsx +++ b/app/(loggedIn)/atlassian/page.tsx @@ -23,7 +23,7 @@ export default async function ServicePage({ // change service name const serviceName = isConfluence ? "Confluence" : "Jira"; const [userData, serviceToken] = await Promise.all([ - getAllPublicUserData({ userEmail }).catch((e) => { + getAllPublicUserData({ email: userEmail }).catch((e) => { console.error(e); return null; }), diff --git a/app/(loggedIn)/bitbucket/loading.tsx b/app/(loggedIn)/bitbucket/loading.tsx index 4d2a4cea8..b7bed5f08 100644 --- a/app/(loggedIn)/bitbucket/loading.tsx +++ b/app/(loggedIn)/bitbucket/loading.tsx @@ -1,5 +1,5 @@ import LoadingConnectedService from "../../../components/services/loading"; -export default function loadingConnetedService() { +export default function loadingConnectedService() { return ; } diff --git a/app/(loggedIn)/bitbucket/page.tsx b/app/(loggedIn)/bitbucket/page.tsx index 0866bbc0f..6af2f51e2 100644 --- a/app/(loggedIn)/bitbucket/page.tsx +++ b/app/(loggedIn)/bitbucket/page.tsx @@ -21,7 +21,7 @@ export default async function ServicePage({ // change service name const serviceName = "Bitbucket"; const [userData, serviceToken] = await Promise.all([ - getAllPublicUserData({ userEmail }).catch((e) => { + getAllPublicUserData({ email: userEmail }).catch((e) => { console.error(e); return null; }), diff --git a/app/(loggedIn)/github/loading.tsx b/app/(loggedIn)/github/loading.tsx index 4d2a4cea8..b7bed5f08 100644 --- a/app/(loggedIn)/github/loading.tsx +++ b/app/(loggedIn)/github/loading.tsx @@ -1,5 +1,5 @@ import LoadingConnectedService from "../../../components/services/loading"; -export default function loadingConnetedService() { +export default function loadingConnectedService() { return ; } diff --git a/app/(loggedIn)/github/page.tsx b/app/(loggedIn)/github/page.tsx index 35627cc72..303a4dbb7 100644 --- a/app/(loggedIn)/github/page.tsx +++ b/app/(loggedIn)/github/page.tsx @@ -21,7 +21,7 @@ export default async function ServicePage({ // change service name const serviceName = "GitHub"; const [userData, serviceToken] = await Promise.all([ - getAllPublicUserData({ userEmail }).catch((e) => { + getAllPublicUserData({ email: userEmail }).catch((e) => { console.error(e); return null; }), diff --git a/app/(loggedIn)/gitlab/loading.tsx b/app/(loggedIn)/gitlab/loading.tsx index 4d2a4cea8..b7bed5f08 100644 --- a/app/(loggedIn)/gitlab/loading.tsx +++ b/app/(loggedIn)/gitlab/loading.tsx @@ -1,5 +1,5 @@ import LoadingConnectedService from "../../../components/services/loading"; -export default function loadingConnetedService() { +export default function loadingConnectedService() { return ; } diff --git a/app/(loggedIn)/gitlab/page.tsx b/app/(loggedIn)/gitlab/page.tsx index 85ce546b1..9a5d4239b 100644 --- a/app/(loggedIn)/gitlab/page.tsx +++ b/app/(loggedIn)/gitlab/page.tsx @@ -21,7 +21,7 @@ export default async function ServicePage({ // change service name const serviceName = "GitLab"; const [userData, serviceToken] = await Promise.all([ - getAllPublicUserData({ userEmail }).catch((e) => { + getAllPublicUserData({ email: userEmail }).catch((e) => { console.error(e); return null; }), diff --git a/app/(loggedIn)/jira/loading.tsx b/app/(loggedIn)/jira/loading.tsx index 4d2a4cea8..b7bed5f08 100644 --- a/app/(loggedIn)/jira/loading.tsx +++ b/app/(loggedIn)/jira/loading.tsx @@ -1,5 +1,5 @@ import LoadingConnectedService from "../../../components/services/loading"; -export default function loadingConnetedService() { +export default function loadingConnectedService() { return ; } diff --git a/app/(loggedIn)/jira/page.tsx b/app/(loggedIn)/jira/page.tsx index 693452624..1ccb18e91 100644 --- a/app/(loggedIn)/jira/page.tsx +++ b/app/(loggedIn)/jira/page.tsx @@ -21,7 +21,7 @@ export default async function ServicePage({ // change service name const serviceName = "Jira"; const [userData, serviceToken] = await Promise.all([ - getAllPublicUserData({ userEmail }).catch((e) => { + getAllPublicUserData({ email: userEmail }).catch((e) => { console.error(e); return null; }), diff --git a/app/(loggedIn)/linear/loading.tsx b/app/(loggedIn)/linear/loading.tsx index 4d2a4cea8..b7bed5f08 100644 --- a/app/(loggedIn)/linear/loading.tsx +++ b/app/(loggedIn)/linear/loading.tsx @@ -1,5 +1,5 @@ import LoadingConnectedService from "../../../components/services/loading"; -export default function loadingConnetedService() { +export default function loadingConnectedService() { return ; } diff --git a/app/(loggedIn)/linear/page.tsx b/app/(loggedIn)/linear/page.tsx index 5ac5d73f8..d2f56efd8 100644 --- a/app/(loggedIn)/linear/page.tsx +++ b/app/(loggedIn)/linear/page.tsx @@ -21,7 +21,7 @@ export default async function ServicePage({ // change service name const serviceName = "Linear"; const [userData, serviceToken] = await Promise.all([ - getAllPublicUserData({ userEmail }).catch((e) => { + getAllPublicUserData({ email: userEmail }).catch((e) => { console.error(e); return null; }), diff --git a/app/(loggedIn)/notion/loading.tsx b/app/(loggedIn)/notion/loading.tsx index 4d2a4cea8..b7bed5f08 100644 --- a/app/(loggedIn)/notion/loading.tsx +++ b/app/(loggedIn)/notion/loading.tsx @@ -1,5 +1,5 @@ import LoadingConnectedService from "../../../components/services/loading"; -export default function loadingConnetedService() { +export default function loadingConnectedService() { return ; } diff --git a/app/(loggedIn)/notion/page.tsx b/app/(loggedIn)/notion/page.tsx index d86b9adb1..a647a3e5e 100644 --- a/app/(loggedIn)/notion/page.tsx +++ b/app/(loggedIn)/notion/page.tsx @@ -21,7 +21,7 @@ export default async function ServicePage({ // change service name const serviceName = "Notion"; const [userData, serviceToken] = await Promise.all([ - getAllPublicUserData({ userEmail }).catch((e) => { + getAllPublicUserData({ email: userEmail }).catch((e) => { console.error(e); return null; }), diff --git a/app/(loggedIn)/page.tsx b/app/(loggedIn)/page.tsx index b97459420..becd20dfc 100644 --- a/app/(loggedIn)/page.tsx +++ b/app/(loggedIn)/page.tsx @@ -13,10 +13,11 @@ async function HomePage({}) { const userEmail = session?.user?.email; const userName = session?.user?.name; // if not logged in, do not show anything - const data = await getAllPublicUserData({ userEmail }).catch((e) => { + const data = await getAllPublicUserData({ email: userEmail }).catch((e) => { console.error(e); return null; }); + console.log(data); const comingSoon = [ "PHPStorm", "IntelliJ", diff --git a/app/(loggedIn)/settings/form.tsx b/app/(loggedIn)/settings/form.tsx index 873df43ac..d4c61d69a 100644 --- a/app/(loggedIn)/settings/form.tsx +++ b/app/(loggedIn)/settings/form.tsx @@ -10,15 +10,41 @@ export default function form({ userEmail }) { let settings = await getUserSettings(userEmail); setFormState(settings); }; - const [formState, setFormState] = useState({ - JiraTickets: 3, - SlackMessages: 3, - GitHubPRs: 3, - NotionPages: 3, - LinearTickets: 3, - ConfluenceDocs: 3, + const services = [ + { + valueLabel: "JiraTickets", + label: "Jira Tickets", + }, + { + valueLabel: "SlackMessages", + label: "Slack Messages", + }, + { + valueLabel: "GitHubPRs", + label: "GitHub PRs", + }, + { + valueLabel: "NotionPages", + label: "Notion Pages", + }, + { + valueLabel: "LinearTickets", + label: "Linear Tickets", + }, + { + valueLabel: "ConfluenceDocs", + label: "Confluence Docs", + }, + { + valueLabel: "AsanaTasks", + label: "Asana Tasks", + }, + ]; + let defaultState = { AISummary: 1, - }); + }; + services.map((service) => (defaultState[service.valueLabel] = 3)); + const [formState, setFormState] = useState(defaultState); const handleSubmit = async () => { setSaveDisabled(true); try { @@ -66,13 +92,13 @@ export default function form({ userEmail }) { } return (
- - - - - - - + {services.map((service) => ( + + ))}
AI Summary:
+ +
- {saveDisabled ? "Saving..." : "Save"} - + + +
); } diff --git a/app/api/actions/github/route.ts b/app/api/actions/github/route.ts index ccc2b1c94..834bf7526 100644 --- a/app/api/actions/github/route.ts +++ b/app/api/actions/github/route.ts @@ -26,8 +26,6 @@ import randomText from "../../../../utils/actions/markdownHelpers/randomText"; import createTeamAndMatchUser from "../../../../utils/db/teams/createTeamAndMatchUser"; import sendUninstall from "../../../../utils/sendgrid/sendUninstall"; - - const app = new App({ appId: process.env.GITHUB_APP_ID!, privateKey: process.env.GITHUB_PRIVATE_KEY!, @@ -70,7 +68,7 @@ export async function POST(request: Request) { if (pull_request.user.type === "Bot") { return new Response("We don't comment on bot PRs", { - status: 400 + status: 400, }); } @@ -313,6 +311,9 @@ export async function POST(request: Request) { watermelon_user, AISummary, user_email, + ResponseTexts, + CodeComments, + Badges, } = serviceAnswers; if (error) { return failedToFetchResponse({ @@ -381,42 +382,49 @@ export async function POST(request: Request) { textToWrite += generalMarkdownHelper({ value: github, userLogin, + ResponseTexts, systemName: "GitHub", systemResponseName: "GitHub PRs", }); textToWrite += generalMarkdownHelper({ value: jira, userLogin, + ResponseTexts, systemName: "Jira", systemResponseName: "Jira Tickets", }); textToWrite += generalMarkdownHelper({ value: confluence, userLogin, + ResponseTexts, systemName: "Confluence", systemResponseName: "Confluence Docs", }); textToWrite += generalMarkdownHelper({ value: slack, userLogin, + ResponseTexts, systemName: "Slack", systemResponseName: "Slack Threads", }); textToWrite += generalMarkdownHelper({ value: notion, userLogin, + ResponseTexts, systemName: "Notion", systemResponseName: "Notion Pages", }); textToWrite += generalMarkdownHelper({ value: linear, userLogin, + ResponseTexts, systemName: "Linear", systemResponseName: "Linear Tickets", }); textToWrite += generalMarkdownHelper({ value: asana, userLogin, + ResponseTexts, systemName: "Asana", systemResponseName: "Asana Tasks", }); @@ -428,27 +436,31 @@ export async function POST(request: Request) { textToWrite += randomText(); Promise.all([ // Detect console.logs and its equivalent in other languages - detectConsoleLogs({ - prTitle: title, - businessLogicSummary, - repo, - owner, - issue_number: number, - installationId, - reqUrl: request.url, - reqEmail: req.email, - }), + CodeComments + ? detectConsoleLogs({ + prTitle: title, + businessLogicSummary, + repo, + owner, + issue_number: number, + installationId, + reqUrl: request.url, + reqEmail: req.email, + }) + : null, // Make Watermelon Review the PR's business logic here by comparing the title with the AI-generated summary - labelPullRequest({ - prTitle: title, - businessLogicSummary, - repo, - owner, - issue_number: number, - installationId, - reqUrl: request.url, - reqEmail: req.email, - }), + Badges + ? labelPullRequest({ + prTitle: title, + businessLogicSummary, + repo, + owner, + issue_number: number, + installationId, + reqUrl: request.url, + reqEmail: req.email, + }) + : null, addActionLog({ randomWords, github, @@ -557,7 +569,9 @@ export async function POST(request: Request) { // Find our bot's comment let botComment = comments.data.find((comment) => { - return comment?.user?.login.includes("watermelon-copilot-for-code-review"); + return comment?.user?.login.includes( + "watermelon-copilot-for-code-review" + ); }); // Update the existing comment diff --git a/components/Navbar.tsx b/components/Navbar.tsx index f122cbc74..b8d80a74f 100644 --- a/components/Navbar.tsx +++ b/components/Navbar.tsx @@ -13,9 +13,19 @@ export default function Navbar({ children }: { children: React.ReactNode }) { { href: "/api/auth/signout", label: "Logout", onClick: signOut }, ]; return ( -
-