Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
srp-pawar committed May 30, 2024
2 parents bb2d74f + d770e56 commit a4a63b0
Show file tree
Hide file tree
Showing 678 changed files with 14,816 additions and 6,238 deletions.
14 changes: 14 additions & 0 deletions .github/workflows/ci-utils.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ on:
# see: https://securitylab.github.com/research/github-actions-preventing-pwn-requests/
# and: https://github.com/facebook/react-native/pull/34370/files
pull_request_target:
types: [opened, synchronize, reopened, closed]
permissions:
actions: write
checks: write
Expand All @@ -19,6 +20,7 @@ concurrency:
jobs:
danger-js:
runs-on: ubuntu-latest
if: github.event.action != 'closed'
steps:
- uses: actions/checkout@v4
- name: Install dependencies
Expand All @@ -27,3 +29,15 @@ jobs:
run: cd packages/twenty-utils && npx nx danger:ci
env:
DANGER_GITHUB_API_TOKEN: ${{ github.token }}

congratulate:
runs-on: ubuntu-latest
if: github.event.action == 'closed' && github.event.pull_request.merged == true
steps:
- uses: actions/checkout@v4
- name: Install dependencies
uses: ./.github/workflows/actions/yarn-install
- name: Run congratulate-dangerfile.js
run: cd packages/twenty-utils && npx nx danger:congratulate
env:
DANGER_GITHUB_API_TOKEN: ${{ secrets.GITHUB_TOKEN }}
4 changes: 2 additions & 2 deletions install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ if command -v nc &> /dev/null; then
done
fi

# Ask user if he wants to start the project
# Ask user if they want to start the project
read -p "🚀 Do you want to start the project now? (Y/n) " answer
if [ "$answer" = "n" ]; then
echo "✅ Project setup completed. Run 'docker compose up -d' to start."
Expand Down Expand Up @@ -148,7 +148,7 @@ function ask_open_browser {
fi
}

# Ask user if he wants to open the project
# Ask user if they want to open the project
# Running on macOS
if [[ $(uname) == "Darwin" ]]; then
ask_open_browser
Expand Down
10 changes: 8 additions & 2 deletions nx.json
Original file line number Diff line number Diff line change
Expand Up @@ -218,8 +218,14 @@
"executor": "nx:run-commands",
"options": {
"cwd": "{projectRoot}",
"command": "cross-var chromatic --project-token=$CHROMATIC_PROJECT_TOKEN --build-script-name={args.targetPackageJsonScript} {args.ci}",
"targetPackageJsonScript": "storybook:build:chromatic"
"commands": [
{
"command": "nx storybook:build {projectName} --configuration=test",
"forwardAllArgs": false
},
"cross-var chromatic --project-token=$CHROMATIC_PROJECT_TOKEN --storybook-build-dir=storybook-static {args.ci}"
],
"parallel": false
},
"configurations": {
"ci": {
Expand Down
8 changes: 6 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"@chakra-ui/accordion": "^2.3.0",
"@chakra-ui/system": "^2.6.0",
"@codesandbox/sandpack-react": "^2.13.5",
"@dagrejs/dagre": "^1.1.2",
"@docusaurus/core": "^3.1.0",
"@docusaurus/preset-classic": "^3.1.0",
"@emotion/react": "^11.11.1",
Expand Down Expand Up @@ -72,7 +73,7 @@
"bullmq": "^4.14.0",
"bytes": "^3.1.2",
"class-transformer": "^0.5.1",
"clsx": "^1.2.1",
"clsx": "^2.1.1",
"cross-env": "^7.0.3",
"crypto-js": "^4.2.0",
"danger-plugin-todos": "^1.3.1",
Expand Down Expand Up @@ -166,6 +167,7 @@
"react-router-dom": "^6.4.4",
"react-textarea-autosize": "^8.4.1",
"react-tooltip": "^5.13.1",
"reactflow": "^11.11.3",
"recoil": "^0.7.7",
"rehype-slug": "^6.0.0",
"remark-behead": "^3.1.0",
Expand All @@ -181,11 +183,12 @@
"tsup": "^8.0.1",
"type-fest": "4.10.1",
"typeorm": "^0.3.17",
"use-context-selector": "^2.0.0",
"use-debounce": "^10.0.0",
"uuid": "^9.0.0",
"vite-tsconfig-paths": "^4.2.1",
"xlsx-ugnis": "^0.19.3",
"zod": "^3.22.2"
"zod": "3.23.8"
},
"devDependencies": {
"@babel/core": "^7.14.5",
Expand Down Expand Up @@ -239,6 +242,7 @@
"@types/bytes": "^3.1.1",
"@types/chrome": "^0.0.267",
"@types/crypto-js": "^4.2.2",
"@types/dagre": "^0.7.52",
"@types/deep-equal": "^1.0.1",
"@types/express": "^4.17.13",
"@types/graphql-fields": "^1.3.6",
Expand Down
12 changes: 10 additions & 2 deletions packages/twenty-chrome-extension/codegen.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,17 @@
import { CodegenConfig } from '@graphql-codegen/cli';

const config: CodegenConfig = {
schema: ['http://localhost:3000/graphql'],
schema: [{
[`${import.meta.env.VITE_SERVER_BASE_URL}/graphql`]: {
// some of the mutations and queries require authorization (people or companies)
// so to regenrate the schema with types we need to pass a auth token
headers: {
Authorization: 'YOUR-TOKEN-HERE',
},
}
}],
overwrite: true,
documents: ['./src/**/*.ts', '!src/generated/**/*.*'],
documents: ['./src/**/*.ts', '!src/generated/**/*.*' ],
generates: {
'./src/generated/graphql.tsx': {
plugins: [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/options/index.tsx"></script>
<script type="module" src="/src/options/page-inaccessible-index.tsx"></script>
</body>
</html>
</html>
22 changes: 22 additions & 0 deletions packages/twenty-chrome-extension/sidepanel.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" href="/icons/android/android-launchericon-48-48.png" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Twenty</title>
<style>
/* Reset margin and padding */
html, body {
margin: 0;
padding: 0;
height: 100%; /* Ensure body takes full viewport height */
overflow: hidden; /* Prevents scrollbars from appearing */
}
</style>

</head>
<body>
<div id="app"></div>
<script type="module" src="/src/options/index.tsx"></script>
</body>
</html>
168 changes: 69 additions & 99 deletions packages/twenty-chrome-extension/src/background/index.ts
Original file line number Diff line number Diff line change
@@ -1,130 +1,100 @@
import Crypto from 'crypto-js';

import { openOptionsPage } from '~/background/utils/openOptionsPage';
import { exchangeAuthorizationCode } from '~/db/auth.db';
import { isDefined } from '~/utils/isDefined';

// Open options page programmatically in a new tab.
chrome.runtime.onInstalled.addListener((details) => {
if (details.reason === 'install') {
openOptionsPage();
}
});
// chrome.runtime.onInstalled.addListener((details) => {
// if (details.reason === 'install') {
// openOptionsPage();
// }
// });

// Open options page when extension icon is clicked.
chrome.action.onClicked.addListener((tab) => {
chrome.tabs.sendMessage(tab.id ?? 0, { action: 'TOGGLE' });
});
chrome.sidePanel.setPanelBehavior({ openPanelOnActionClick: true });

// This listens for an event from other parts of the extension, such as the content script, and performs the required tasks.
// The cases themselves are labelled such that their operations are reflected by their names.
chrome.runtime.onMessage.addListener((message, _, sendResponse) => {
switch (message.action) {
case 'getActiveTab': // e.g. "https://linkedin.com/company/twenty/"
chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (isDefined(tabs) && isDefined(tabs[0])) {
sendResponse({ tab: tabs[0] });
case 'getActiveTab': {
// e.g. "https://linkedin.com/company/twenty/"
chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
if (isDefined(tab) && isDefined(tab.id)) {
sendResponse({ tab });
}
});
break;
case 'openOptionsPage':
openOptionsPage();
}
case 'openSidepanel': {
chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
if (isDefined(tab) && isDefined(tab.id)) {
chrome.sidePanel.open({ tabId: tab.id });
}
});
break;
case 'CONNECT':
launchOAuth(({ status, message }) => {
sendResponse({ status, message });
}
case 'changeSidepanelUrl': {
chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
if (isDefined(tab) && isDefined(tab.id)) {
chrome.tabs.sendMessage(tab.id, {
action: 'changeSidepanelUrl',
message,
});
}
});
break;
}
default:
break;
}

return true;
});

const generateRandomString = (length: number) => {
const charset =
'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_';
let result = '';
for (let i = 0; i < length; i++) {
result += charset.charAt(Math.floor(Math.random() * charset.length));
}
return result;
};

const generateCodeVerifierAndChallenge = () => {
const codeVerifier = generateRandomString(32);
const hash = Crypto.SHA256(codeVerifier);
const codeChallenge = hash
.toString(Crypto.enc.Base64)
.replace(/\+/g, '-')
.replace(/\//g, '_')
.replace(/=+$/, '');

return { codeVerifier, codeChallenge };
};

const launchOAuth = (
callback: ({ status, message }: { status: boolean; message: string }) => void,
) => {
const { codeVerifier, codeChallenge } = generateCodeVerifierAndChallenge();
const redirectUrl = chrome.identity.getRedirectURL();
chrome.identity
.launchWebAuthFlow({
url: `${
import.meta.env.VITE_FRONT_BASE_URL
}/authorize?clientId=chrome&codeChallenge=${codeChallenge}&redirectUrl=${redirectUrl}`,
interactive: true,
})
.then((responseUrl) => {
if (typeof responseUrl === 'string') {
const url = new URL(responseUrl);
const authorizationCode = url.searchParams.get(
'authorizationCode',
) as string;
exchangeAuthorizationCode({
authorizationCode,
codeVerifier,
}).then((tokens) => {
if (isDefined(tokens)) {
chrome.storage.local.set({
loginToken: tokens.loginToken,
});

chrome.storage.local.set({
accessToken: tokens.accessToken,
});

chrome.storage.local.set({
refreshToken: tokens.refreshToken,
});

callback({ status: true, message: '' });

chrome.tabs.query({ active: true, currentWindow: true }, (tabs) => {
if (isDefined(tabs) && isDefined(tabs[0])) {
chrome.tabs.sendMessage(tabs[0].id ?? 0, {
action: 'AUTHENTICATED',
});
}
});
}
});
}
})
.catch((error) => {
callback({ status: false, message: error.message });
});
};

chrome.tabs.onUpdated.addListener((tabId, changeInfo, tab) => {
chrome.tabs.onUpdated.addListener(async (tabId, _, tab) => {
const isDesiredRoute =
tab.url?.match(/^https?:\/\/(?:www\.)?linkedin\.com\/company(?:\/\S+)?/) ||
tab.url?.match(/^https?:\/\/(?:www\.)?linkedin\.com\/in(?:\/\S+)?/);

if (changeInfo.status === 'complete' && tab.active) {
if (tab.active === true) {
if (isDefined(isDesiredRoute)) {
chrome.tabs.sendMessage(tabId, { action: 'executeContentScript' });
}
}

await chrome.sidePanel.setOptions({
tabId,
path: tab.url?.match(/^https?:\/\/(?:www\.)?linkedin\.com/)
? 'sidepanel.html'
: 'page-inaccessible.html',
enabled: true,
});
});

const setTokenStateFromCookie = (cookie: string) => {
const decodedValue = decodeURIComponent(cookie);
const tokenPair = JSON.parse(decodedValue);
if (isDefined(tokenPair)) {
chrome.storage.local.set({
isAuthenticated: true,
accessToken: tokenPair.accessToken,
refreshToken: tokenPair.refreshToken,
});
}
};

chrome.cookies.onChanged.addListener(async ({ cookie }) => {
if (cookie.name === 'tokenPair') {
setTokenStateFromCookie(cookie.value);
}
});

// This will only run the very first time the extension loads, after we have stored the
// cookiesRead variable to true, this will not allow to change the token state everytime background script runs
chrome.cookies.get(
{ name: 'tokenPair', url: `${import.meta.env.VITE_FRONT_BASE_URL}` },
async (cookie) => {
const store = await chrome.storage.local.get(['cookiesRead']);
if (isDefined(cookie) && !isDefined(store.cookiesRead)) {
setTokenStateFromCookie(cookie.value);
chrome.storage.local.set({ cookiesRead: true });
}
},
);

This file was deleted.

Loading

0 comments on commit a4a63b0

Please sign in to comment.