Skip to content

Commit

Permalink
Merge branch 'main' into feat/delete-link-from-links-field
Browse files Browse the repository at this point in the history
  • Loading branch information
charlesBochet committed May 22, 2024
2 parents 2b04b90 + beaaf33 commit 309cb19
Show file tree
Hide file tree
Showing 121 changed files with 3,148 additions and 1,938 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 }}
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,10 @@
"@types/lodash.camelcase": "^4.3.7",
"@types/lodash.merge": "^4.6.7",
"@types/lodash.pick": "^4.3.7",
"@types/mailparser": "^3.4.4",
"@types/nodemailer": "^6.4.14",
"@types/passport-microsoft": "^1.0.3",
"add": "^2.0.6",
"addressparser": "^1.0.1",
"afterframe": "^1.0.2",
"apollo-server-express": "^3.12.0",
"apollo-upload-client": "^17.0.0",
Expand Down Expand Up @@ -95,6 +95,7 @@
"graphql-fields": "^2.0.3",
"graphql-middleware": "^6.1.35",
"graphql-rate-limit": "^3.3.0",
"graphql-scalars": "^1.23.0",
"graphql-subscriptions": "2.0.0",
"graphql-tag": "^2.12.6",
"graphql-type-json": "^0.3.2",
Expand Down Expand Up @@ -126,7 +127,6 @@
"lodash.snakecase": "^4.1.1",
"lodash.upperfirst": "^4.3.1",
"luxon": "^3.3.0",
"mailparser": "^3.6.5",
"microdiff": "^1.3.2",
"nest-commander": "^3.12.0",
"next": "14.0.4",
Expand Down Expand Up @@ -232,6 +232,7 @@
"@swc/helpers": "~0.5.2",
"@testing-library/jest-dom": "^6.1.5",
"@testing-library/react": "14.0.0",
"@types/addressparser": "^1.0.3",
"@types/apollo-upload-client": "^17.0.2",
"@types/bcrypt": "^5.0.0",
"@types/better-sqlite3": "^7.6.8",
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>
80 changes: 53 additions & 27 deletions packages/twenty-chrome-extension/src/background/index.ts
Original file line number Diff line number Diff line change
@@ -1,40 +1,55 @@
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();
break;
case 'CONNECT':
}
case 'launchOAuth': {
launchOAuth(({ status, message }) => {
sendResponse({ status, message });
});
break;
}
case 'openSidepanel': {
chrome.tabs.query({ active: true, currentWindow: true }, ([tab]) => {
if (isDefined(tab) && isDefined(tab.id)) {
chrome.sidePanel.open({ tabId: tab.id });
}
});
break;
}
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;
}
Expand Down Expand Up @@ -101,13 +116,16 @@ const launchOAuth = (

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',
});
}
});
chrome.tabs.query(
{ active: true, currentWindow: true },
([tab]) => {
if (isDefined(tab) && isDefined(tab.id)) {
chrome.tabs.sendMessage(tab.id, {
action: 'executeContentScript',
});
}
},
);
}
});
}
Expand All @@ -117,14 +135,22 @@ const launchOAuth = (
});
};

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,
});
});

This file was deleted.

34 changes: 18 additions & 16 deletions packages/twenty-chrome-extension/src/contentScript/createButton.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import { isDefined } from '~/utils/isDefined';

interface CustomDiv extends HTMLDivElement {
onClickHandler: (newHandler: () => void) => void;
}

export const createDefaultButton = (
buttonId: string,
onClickHandler?: () => void,
buttonText = '',
) => {
const btn = document.getElementById(buttonId);
): CustomDiv => {
const btn = document.getElementById(buttonId) as CustomDiv;
if (isDefined(btn)) return btn;
const div = document.createElement('div');
const div = document.createElement('div') as CustomDiv;
const img = document.createElement('img');
const span = document.createElement('span');

Expand Down Expand Up @@ -52,19 +55,18 @@ export const createDefaultButton = (
Object.assign(div.style, divStyles);
});

// Handle the click event.
div.addEventListener('click', async (e) => {
e.preventDefault();
const store = await chrome.storage.local.get();

// If an api key is not set, the options page opens up to allow the user to configure an api key.
if (!store.accessToken) {
chrome.runtime.sendMessage({ action: 'openOptionsPage' });
return;
}
div.onClickHandler = (newHandler) => {
div.onclick = async () => {
const store = await chrome.storage.local.get();

onClickHandler?.();
});
// If an api key is not set, the options page opens up to allow the user to configure an api key.
if (!store.accessToken) {
chrome.runtime.sendMessage({ action: 'openSidepanel' });
return;
}
newHandler();
};
};

div.id = buttonId;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { createDefaultButton } from '~/contentScript/createButton';
import changeSidePanelUrl from '~/contentScript/utils/changeSidepanelUrl';
import extractCompanyLinkedinLink from '~/contentScript/utils/extractCompanyLinkedinLink';
import extractDomain from '~/contentScript/utils/extractDomain';
import { createCompany, fetchCompany } from '~/db/company.db';
Expand Down Expand Up @@ -71,27 +72,19 @@ export const addCompany = async () => {
const companyURL = extractCompanyLinkedinLink(activeTab.url);
companyInputData.linkedinLink = { url: companyURL, label: companyURL };

const company = await createCompany(companyInputData);
return company;
const companyId = await createCompany(companyInputData);

if (isDefined(companyId)) {
await changeSidePanelUrl(
`${import.meta.env.VITE_FRONT_BASE_URL}/object/company/${companyId}`,
);
}

return companyId;
};

export const insertButtonForCompany = async () => {
const companyButtonDiv = createDefaultButton(
'twenty-company-btn',
async () => {
if (isDefined(companyButtonDiv)) {
const companyBtnSpan = companyButtonDiv.getElementsByTagName('span')[0];
companyBtnSpan.textContent = 'Saving...';
const company = await addCompany();
if (isDefined(company)) {
companyBtnSpan.textContent = 'Saved';
Object.assign(companyButtonDiv.style, { pointerEvents: 'none' });
} else {
companyBtnSpan.textContent = 'Try again';
}
}
},
);
const companyButtonDiv = createDefaultButton('twenty-company-btn');

const parentDiv: HTMLDivElement | null = document.querySelector(
'.org-top-card-primary-actions__inner',
Expand All @@ -105,13 +98,35 @@ export const insertButtonForCompany = async () => {
parentDiv.prepend(companyButtonDiv);
}

const companyBtnSpan = companyButtonDiv.getElementsByTagName('span')[0];
const companyButtonSpan = companyButtonDiv.getElementsByTagName('span')[0];
const company = await checkIfCompanyExists();

const openCompanyOnSidePanel = (companyId: string) => {
companyButtonSpan.textContent = 'View in Twenty';
companyButtonDiv.onClickHandler(async () => {
await changeSidePanelUrl(
`${import.meta.env.VITE_FRONT_BASE_URL}/object/company/${companyId}`,
);
chrome.runtime.sendMessage({ action: 'openSidepanel' });
});
};

if (isDefined(company)) {
companyBtnSpan.textContent = 'Saved';
Object.assign(companyButtonDiv.style, { pointerEvents: 'none' });
await changeSidePanelUrl(
`${import.meta.env.VITE_FRONT_BASE_URL}/object/company/${company.id}`,
);
if (isDefined(company.id)) openCompanyOnSidePanel(company.id);
} else {
companyBtnSpan.textContent = 'Add to Twenty';
companyButtonSpan.textContent = 'Add to Twenty';

companyButtonDiv.onClickHandler(async () => {
companyButtonSpan.textContent = 'Saving...';
const companyId = await addCompany();
if (isDefined(companyId)) {
openCompanyOnSidePanel(companyId);
} else {
companyButtonSpan.textContent = 'Try again';
}
});
}
};
Loading

0 comments on commit 309cb19

Please sign in to comment.