Skip to content
This repository has been archived by the owner on Mar 12, 2024. It is now read-only.

Commit

Permalink
Update dev branch (#219)
Browse files Browse the repository at this point in the history
* improve logging

* Redraw confirmation page

* Add logo to login

* Add theming

* Create NotionLoginLink.tsx

* Create notion.tsx

* Add notion

* log returned json

* even more logging

* Remove logging, fix token getting

* fix broken deploy

* ad logging

* encode in base64 the auth

* Remove notion login link temporarily

* Remove discord login

* Save to the DB

* Fix object to save

* Await saving the user

* Fix service name, get user

* Fix path

* Fix user saving

* Debug logging

* send correct props

* Add notion back

* Add notion querying

* Add logging of result

* Fix getting of issue comments

* correctly pass props to notion (#179)

* correctly pass props to notion

* Update README.md

* fix undefined id error

* Fix logging

* Add better error logging

* Fix error due to no notion version

* Fix result returning

* add logging

* Fix logging

* Add notion to settings

* Add notion to app

* fix newline

* Remove extra character

* Add page image support

* fix title

* fix image display

* fix no token error

* Filter out private messages

* Allow getting less than standard results

* Create getHoverData.ts

* fix token passing

* Fix typo

* Now uses commitTitle

* Add new users to Sendgrid contact list

* Scrub action for app

* Fixes to slack matches

* Fix/remove action (#178)

* Delete watermelon.yml

* Change dropdown link

* Change login link

* Change dashboard link

* small fixes

* Move text writers to helpers

* Fix comment editing

* Export helpers

* Add necessary imports

* Change logging

* Add non-registered user response

* Earlier counting of action uses

* reduce logging

* Add counting to comment

* Add error checking

* Add check for open repos

* Add error writing

* Extract count markdown

* Fix/typings improvements (#183)

* Add typings

* Fix possible nulls

* Add LoginGridProps type

* Fix possible null

* remove breaklines

* Add export

* Add import

* Update README.md, add title (#180)

* Update README.md, add title

* Update README.md

* Update README.md

* Update README.md (#181)

* Chore/codebase typings and nulls (#185)

* Allow max to be 5

* check nulls

* add typings

* fix possible null

* Add typings

* Add linear link for oauth

* Feature/linear (#186)

* Allow max to be 5

* Create linear.tsx

* Feature/linear (#187)

* Allow max to be 5

* Create linear.tsx

* Update linear.tsx

* Add logging

* improve logging

* Fix linear link

* Change encoding of request

* Fix body of request

* Fix userquery

* Save user, pass team name

* remove unused code

* logging

* try text

* Create LinearLoginLink.tsx

* Try new body

* Update linear.tsx

* Fix logo

* Create linear.svg

* add content type

* Add linear

* try fix

* Fix data matching

* Fix team

* Removed unused link

* Fix email

* Feature/team and navbar  (#182)

* add server-only

* add client-only

* Move to RSC

* remove logging

* fix typings

* fix typings

* add LoginGridProps

* Fix possibly null

* Add types

* Check nulls

* fix possible nulls

* ignore errors in lightly used api

* Set conditionally

* Check null

* check null

* fix typings

* fix null errors

* fix null

* add typings

* fix props passing

* Add typing

* Add typing

* fix typings

* Fix typing errors

* use nonnull assertion

* Add styles

* Move to app folder

* Adhere to app api route

* Make it non default

* upgrade next-auth

* restore session provider

* Fixes in adapter

* move auth to pages to test use

* Fix login route

* fix import

* Pass authprovider

* Added sidebar test

* Add sidebar

* Fix navbar, extract navbar

* Fix layout

* Hide elements if no session

* Update Navbar.tsx

* Fix layout

* Make app dark

* Extract form

* Extract navbar

* Move to app

* Move layout out

* Remove logging

* REmove logging

* Move logingrid to RSC

* Remove logingrid

* Add layout

* Remove logging

* Remove logging

* Create getTeammates.ts

* Create Team page

* Fix heading

* Delete github.tsx

* Move to App router

* Update README.md, add title (#180)

* Update README.md, add title

* Update README.md

* Update README.md

* Update README.md (#181)

* Move to RSC

* Fix Try app ui

* Remove data logging

* Make card details a page

* Move layout to master layout

* Fix type

* Fix layout order

* Remove billing link

* log response

* Move back to pages

* Add search params to billing page

* Create loading.tsx

* Get settings on load

* Adde repo owner and number to charge

* Pass number from param

* Force prompt

* fix params

* Add payment success page

* Add billing link to navbar

* Remove text that explains repo and seats in Card Elements

* Add texts that explains purchase amount

* Add linear to form (#190)

* Add linear to form

* Add Linear to query

* Create getLinear.ts

* Add linear fetching

* Change query to add limit

* Add logging

* Fix search terms

* Improve logging

* Update linear.ts

* Add linear to app (#192)

* Create linear.ts

* add no token handling

* Check nulls

* Fix search terms

* export module

* Naming fixes

* manage empty results

* Fix text

* Fix newline

* Code fixes

* Fix undefined team count

* Add teammates  (#193)

* Add button

* Code cleanup

* Create page.tsx

* Execute request on landing

* fix empty teammates

* fix null teammates

* add logging

* better logging

* Fix params

* Rmove logging

* Get team and copy to clipboard

* paralelize requests, shorten code

* send correct object

* Add interaction

* Add plaintext to copy

* Fix url

* Create loading.tsx

* Check for data before render

* Add catch to data fetch

* Fix return

* Update layout.tsx

* Update loading.tsx

* Update loading.tsx

* Update loading.tsx

* Move app link up

* fix button text

* Glow up

* Create loading.tsx

* Change email to info

* Create sendTeammateInvite.ts

* Add emailer form

* Fix template id

* Fix sending handler

* Move to API call

* Update sendInviteForm.tsx

* Update sendTeammateInvite.ts

* Cleanup

* Create loading.tsx

* Remove params

* Feature/save gh response (#194)

* Add saving query

* fix randomwords

* Improve logging

* stringify responses

* Check nulls

* Fix count number in log saving

* Correct wm user

* Extract to function (#196)

* Create addActionLog.ts

* Use extracted method

* Reduce file size

* Remove logging

* Reorg imports (#197)

* Reorg imports

* Update github.ts

* Update github.ts

* Feature/extract gh action loggin (#198)

* Create addActionLog.ts

* Use extracted method

* Reduce file size

* Remove logging

* fix id for team

* Fix saved string

* Feature/extract gh action loggin (#200)

* Create addActionLog.ts

* Use extracted method

* Reduce file size

* Remove logging

* fix id for team

* Fix saved string

* Add replacing of apostrophe to fix query

* add \n to AI summary error (#199)

* add \n to AI summary error

* Update github.ts

* Feature/extract gh action logging (#202)

* Feature/page titles (#203)

* Delete sidebar.tsx (#201)

* Feature/posthog analytics (#204)

* Add posthogjs

* Create providers.tsx

* Add posthog

* Add posthognode

* Create posthogTracker.ts

* Add tracker to gh action

* make posthog early

* fix list filtering

* Rename tracker

* Add tracker

* Add tracker

* Streamline data fetching

* Add tracker

* Feature/confluence login (#206)

* Create ConfluenceLoginLink.tsx

* Add confluence

* Create atlassian page

* Remove primer

* Add primer

* change link

* Fix link

* fix link, text

* Emergency removal of posthog

* REmove all posthog instances

* Correct redirect uri

* better logging

* Update atlassian.tsx

* conditionally add pic

* add logging

* Add discrimination to jira and confluence

* Save confluence

* fix link

* Fix img

* debug logging

* Fix query

* Debug logging

* change grant typ

* Go back a grant type

* change logging

* Fix url

* Some more data wrangling

* fix saving

* Fix image

* Reorg dashboard

* Add coming soon ides

* Style navbar better

* Make sidebar sticky, add logout button

* Add workspace query

* Ignore name

* Remove unused code

* ignore calling

* try other import to release

* Move email to client

* Change logging

* fix obj accessing

* Add workspace, request emails

* Add email, optimize requests

* fix query

* Get refresh token on login

* Add confluence

* Improve logging

* reduce logging

* Better logging

* Create confluence.ts

* Add confluence

* Fix value

* Create confluence.ts

* Add logging

* logging

* Check if null

* Fix nulls

* Change how tokens are updated

* Rename

* Fixes to query executing

* Rename action

* Fixes and error handling

* Fix missing param

* Add offline access scope

* Several fixes to tokens

* Logging improvements

* Delete test Api

* Reduce throwing

* Print full payload in this repo

* Stringify full response

* Remove data dumping

* Change pricing calculation and text to

* Update README.md (#207)

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Feature/confluence settings (#211)

* Make all unlogged services lose title

* Create watermelon.ts

* Use standard type

* use standard types

* Use standard types

* Create general case helper

* Make code more readable

* Allow number to be a string, like a slack channel

* Add possible body

* Standardize helpers

* Remove unused helpers

* Add possible image element

* Remove unused code

* use standard response

* remove logging, fix text

* Fix token errors in confluence

* Better responses on success and failure

* Check nulls

* Add max results

* Add limit using amount

* create StandardAPIInput

* Fix type

* Create OptionDropdown component

* Change to max 5

* Fix code

* Make it component based, add confluence

* Remove component unused

* Fix loading page

* Feature/standard api responses (#209)

* Make all unlogged services lose title

* Create watermelon.ts

* Use standard type

* use standard types

* Use standard types

* Create general case helper

* Make code more readable

* Allow number to be a string, like a slack channel

* Add possible body

* Standardize helpers

* Remove unused helpers

* Add possible image element

* Remove unused code

* use standard response

* remove logging, fix text

* Fix token errors in confluence

* Better responses on success and failure

* Check nulls

* Add max results

* Add limit using amount

* create StandardAPIInput

* Fix type

* Create OptionDropdown component

* Change to max 5

* Fix code

* Removed unused element

* Reduce code size

* Add confluence

* Reduce code

* Further reduce code

* Remove unneeded brackets

* Fix links (#215)

* Create LICENSE (#216)

Adding an Apache 2.0 license with a Commons clause to this repo to be able to make it source-available and become a buyer based open core company

* Feature/all uses approuter (#217)

* Use const instead of let

* Change to app router

* export page

* Fix redirect with client component

* redirect instead of opening new window

* Test suggesting other services

* Fix file

* fix json

* Fix suggestions UI

* Correctly use ternary

* Fix small error

* Create loading.tsx

---------

Co-authored-by: baristaGeek <estebanvargas94@gmail.com>
  • Loading branch information
EstebanDalelR and baristaGeek committed Aug 3, 2023
1 parent 6f42b81 commit 3c8598b
Show file tree
Hide file tree
Showing 4 changed files with 462 additions and 22 deletions.
88 changes: 66 additions & 22 deletions app/linear/page.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
import Link from "next/link";
import { getServerSession } from "next-auth";
//change this to import correctly

import saveUserInfo from "../../utils/db/linear/saveUser";

import { authOptions } from "../api/auth/[...nextauth]/route";
import TimeToRedirect from "../../components/redirect";
import getAllPublicUserData from "../../utils/api/getAllUserPublicData";

import ConnectedService from "../../utils/services/page";
import LoginArray from "../../utils/services/loginArray";
import SlackLoginLink from "../../components/SlackLoginLink";
import NotionLoginLink from "../../components/NotionLoginLink";
import ConfluenceLoginLink from "../../components/ConfluenceLoginLink";
import GitHubLoginLink from "../../components/GitHubLoginLink";

export default async function ServicePage({
export default async function Linear({
searchParams,
}: {
searchParams: { [key: string]: string | string[] | undefined };
Expand All @@ -18,14 +22,12 @@ export default async function ServicePage({
const userName = session?.user?.name;
const { code, state } = searchParams;
let error = "";
// change service name
const serviceName = "Linear";
const [userData, serviceToken] = await Promise.all([

const [userData, linearToken] = await Promise.all([
getAllPublicUserData({ userEmail }).catch((e) => {
console.error(e);
return null;
}),
// change this fetch
fetch(`https://api.linear.app/oauth/token`, {
method: "POST",
headers: {
Expand All @@ -36,11 +38,35 @@ export default async function ServicePage({
}),
]);

// the recommended services should not be of the same category as the current one
const nameList = ["GitHub", "Slack", "Notion", "Confluence"];
const loginArray = LoginArray({ nameList, userEmail, userData });
const services = [
{
name: "GitHub",
dataProp: "github_data",
loginComponent: <GitHubLoginLink userEmail={userEmail} />,
},
{
name: "Slack",
dataProp: "slack_data",
loginComponent: <SlackLoginLink userEmail={userEmail} />,
},
{
name: "Confluence",
dataProp: "confluence_data",
loginComponent: <ConfluenceLoginLink userEmail={userEmail} />,
},
{
name: "Notion",
dataProp: "notion_data",
loginComponent: <NotionLoginLink userEmail={userEmail} />,
},
];
const loginArray = services
.map((service) =>
userData?.[service.dataProp] ? null : service.loginComponent
)
.filter((component) => component !== null);

const json = await serviceToken.json();
const json = await linearToken.json();
if (json.error) {
error = json.error;
} else {
Expand All @@ -49,7 +75,6 @@ export default async function ServicePage({
"query Me {\nviewer {\n id,\n name,\n displayName, email,\n avatarUrl\n},\nteams {\n nodes {\n id,\n name\n }\n}\n}",
variables: {},
});
// get user correctly
let user = await fetch(`https://api.linear.app/graphql`, {
method: "POST",
headers: {
Expand All @@ -60,7 +85,6 @@ export default async function ServicePage({
});
let userText = await user.text();
let userJson = JSON.parse(userText).data;
// save user correctly
await saveUserInfo({
access_token: json.access_token,
id: userJson.viewer.id,
Expand All @@ -74,14 +98,34 @@ export default async function ServicePage({
});

return (
<ConnectedService
serviceName={serviceName}
displayName={userJson.viewer.displayName}
teamName={userJson.teams.nodes[0].name}
avatarUrl={userJson.viewer.avatarUrl}
loginArray={loginArray}
error={error}
/>
<div className="Box" style={{ maxWidth: "100ch", margin: "auto" }}>
<div className="Subhead">
<h2 className="Subhead-heading px-2">
You have logged in with Linear as {userJson.viewer.displayName} in
the team {userJson.teams.nodes[0].name}
</h2>
</div>
<img
src={userJson.viewer.avatarUrl}
alt="linear user image"
className="avatar avatar-8"
/>
<div>
<TimeToRedirect url={"/"} />
<p>
If you are not redirected, please click <Link href="/">here</Link>
</p>
{loginArray.length ? (
<div>
<h3>You might also be interested: </h3>
{loginArray.map((login) => (
<>{login}</>
))}
</div>
) : null}
{error && <p>{error}</p>}
</div>
</div>
);
}
}
155 changes: 155 additions & 0 deletions pages/atlassian.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import Link from "next/link";
import saveJiraUserInfo from "../utils/db/jira/saveUserInfo";
import saveConfluenceUserInfo from "../utils/db/confluence/saveUserInfo";
import GitHubLoginLink from "../components/GitHubLoginLink";
export default function Jira({ organization, avatar_url, userEmail, error }) {
const [timeToRedirect, setTimeToRedirect] = useState(10);
const router = useRouter();
useEffect(() => {
const interval = setInterval(() => {
setTimeToRedirect(timeToRedirect - 1);
if (timeToRedirect === 0) {
router.push("/");
}
}, 1000);
return () => clearInterval(interval);
}, [timeToRedirect]);
let isConfluence = userEmail.startsWith("c");

return (
<div className="Box" style={{ maxWidth: "100ch", margin: "auto" }}>
<div className="Subhead">
<h2 className="Subhead-heading px-2">
You have logged in with {isConfluence ? "Confluence" : "Jira"} to{" "}
{organization}
</h2>
</div>
<img
src={avatar_url}
alt={`${isConfluence ? "Confluence" : "Jira"} organization image`}
className="avatar avatar-8"
/>
<div>
<p className="text-emphasized">We recommend you login to GitHub</p>
<GitHubLoginLink userEmail={userEmail} />
</div>
<div>
<p>You will be redirected in {timeToRedirect}...</p>
<p>
If you are not redirected, please click <Link href="/">here</Link>
</p>
{error && <p>{error}</p>}
</div>
</div>
);
}
export async function getServerSideProps(context) {
let f;

if (context.query.code) {
f = await fetch(`https://auth.atlassian.com/oauth/token`, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({
grant_type: "authorization_code",
code: context.query.code,
redirect_uri: "https://app.watermelontools.com/atlassian",
client_id: process.env.NEXT_PUBLIC_JIRA_CLIENT_ID,
client_secret: process.env.JIRA_CLIENT_SECRET,
}),
});
} else
return {
props: {
error: "no code",
},
};
const json = await f.json();
if (json.error) {
console.error("Atlassian error", json);
return {
props: {
error: json.error,
},
};
} else {
const { access_token } = json;
const orgInfo = await fetch(
"https://api.atlassian.com/oauth/token/accessible-resources",
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${access_token}`,
},
}
);
const orgInfoJson = await orgInfo.json();
let isConfluence = context.query.state.startsWith("c");
if (isConfluence) {
const userInfo = await fetch(
`https://api.atlassian.com/ex/confluence/${orgInfoJson[0].id}/rest/api/user/current`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${access_token}`,
},
}
);
const userInfoJson = await userInfo.json();
await saveConfluenceUserInfo({
access_token: json.access_token,
refresh_token: json.refresh_token,
confluence_id: orgInfoJson[0].id,
organization: orgInfoJson[0].name,
url: orgInfoJson[0].url,
org_avatar_url: orgInfoJson[0].avatarUrl,
scopes: orgInfoJson[0].scopes,
watermelon_user: context.query.state.slice(1),
user_email: userInfoJson.email,
user_avatar_url:
orgInfoJson[0].url + userInfoJson?.profilePicture?.path,
user_id: userInfoJson.accountId,
user_displayname: userInfoJson.displayName,
});
} else {
const userInfo = await fetch(
`https://api.atlassian.com/ex/jira/${orgInfoJson[0].id}/rest/api/3/myself`,
{
method: "GET",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${access_token}`,
},
}
);
const userInfoJson = await userInfo.json();
await saveJiraUserInfo({
access_token: json.access_token,
refresh_token: json.refresh_token,
jira_id: orgInfoJson[0].id,
organization: orgInfoJson[0].name,
url: orgInfoJson[0].url,
org_avatar_url: orgInfoJson[0].avatarUrl,
scopes: orgInfoJson[0].scopes,
watermelon_user: context.query.state.slice(1),
user_email: userInfoJson.emailAddress,
user_avatar_url: userInfoJson?.avatarUrls?.["48x48"],
user_id: userInfoJson.accountId,
user_displayname: userInfoJson.displayName,
});
}
return {
props: {
userEmail: context.query.state,
organization: orgInfoJson[0]?.name,
avatar_url: orgInfoJson[0]?.avatarUrl,
},
};
}
}
99 changes: 99 additions & 0 deletions pages/discord.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import { useEffect, useState } from "react";
import { useRouter } from "next/router";
import Link from "next/link";
import JiraLoginLink from "../components/JiraLoginLink";
import saveUser from "../utils/db/discord/saveUser";
export default function Discord({ userData, userEmail, error }) {
const [timeToRedirect, setTimeToRedirect] = useState(10);
const router = useRouter();
useEffect(() => {
const interval = setInterval(() => {
setTimeToRedirect(timeToRedirect - 1);
if (timeToRedirect === 0) {
router.push("/");
}
}, 1000);
return () => clearInterval(interval);
}, [timeToRedirect]);

return (
<div className="Box" style={{ maxWidth: "100ch", margin: "auto" }}>
<div className="Subhead">
<h2 className="Subhead-heading px-2">
You have logged in with Discord as {userData.username}
</h2>
<img
src={`https://cdn.discordapp.com/avatars/${userData.id}/${userData.avatar}`}
alt="github user image"
className="avatar avatar-8"
/>
</div>

<div>
<p className="text-emphasized">We recommend you login to Jira</p>
<JiraLoginLink userEmail={userEmail} />
</div>
<div>
<p>You will be redirected in {timeToRedirect}...</p>
<p>
If you are not redirected, please click <Link href="/">here</Link>
</p>
{error && <p>{error}</p>}
</div>
</div>
);
}

export async function getServerSideProps(context) {
let f;
if (context.query.code) {
const API_ENDPOINT = "https://discord.com/api/v10";
const CLIENT_ID = process.env.DISCORD_CLIENT_ID;
const CLIENT_SECRET = process.env.DISCORD_CLIENT_SECRET;
const REDIRECT_URI = "https://app.watermelontools.com/discord";
const data = {
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
grant_type: "authorization_code",
code: context.query.code,
redirect_uri: REDIRECT_URI,
};
const headers = {
"Content-Type": "application/x-www-form-urlencoded",
};
const response = await fetch(`${API_ENDPOINT}/oauth2/token`, {
method: "POST",
headers: headers,
body: new URLSearchParams(data.toString()),
});
const json = await response.json();
const user = await fetch(`${API_ENDPOINT}/users/@me`, {
headers: {
Authorization: `Bearer ${json.access_token}`,
},
});

const userJson = await user.json();
await saveUser({
access_token: json.access_token,
scope: json.scope,
username: userJson.username,
id: userJson.id,
avatar_url: userJson.avatar,
watermelon_user: context.query.state,
email: userJson.email,
refresh_token: json.refresh_token,
});
return {
props: {
userData: userJson,
userEmail: context.query.state,
},
};
} else
return {
props: {
error: "no code",
},
};
}
Loading

0 comments on commit 3c8598b

Please sign in to comment.