Skip to content

Commit 45284d9

Browse files
committed
refactor(pplx:ext)
1 parent 4b175be commit 45284d9

File tree

101 files changed

+1556
-658
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+1556
-658
lines changed

perplexity/extension/.gitignore

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,6 @@ unimport.d.ts
2929
/release/*.zip
3030
/release/*.xpi
3131
/release/*.crx
32-
/release/*-firefox
32+
/release/*-firefox
33+
34+
dom-selectors.json
Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,20 @@
11
import { expect } from "@playwright/test";
22

3+
import { DomSelectorsRegistry } from "@/data/dom-selectors-registry";
34
import { ENDPOINTS } from "@/services/pplx-api/endpoints";
4-
import { DOM_SELECTORS } from "@/utils/dom-selectors";
55
import { E2E_CONFIG } from "~/e2e/config";
66
import { BasePage } from "~/e2e/pages/base.page";
77

8-
export class HomePage extends BasePage {
8+
export class HomePage extends BasePage implements Extracted {
99
async load(): Promise<void> {
1010
await this.navigateTo(ENDPOINTS.HOME);
1111
await expect(this.page).toHaveTitle(/Perplexity/);
1212
}
1313

1414
async verifyKeyElements(): Promise<void> {
15-
const heading = this.page.locator(DOM_SELECTORS.QUERY_BOX.TEXTAREA.MAIN);
15+
const heading = this.page.locator(
16+
DomSelectorsRegistry.cachedSync.QUERY_BOX.TEXTAREA.MAIN,
17+
);
1618
await expect(heading).toBeVisible({
1719
timeout: E2E_CONFIG.TIMEOUTS.HEADING_VISIBLE,
1820
});
@@ -22,3 +24,9 @@ export class HomePage extends BasePage {
2224
await this.verifyKeyElements();
2325
}
2426
}
27+
28+
interface Extracted {
29+
load(): Promise<void>;
30+
verifyKeyElements(): Promise<void>;
31+
verifyHomepageLoad(): Promise<void>;
32+
}

perplexity/extension/e2e/tests/pro/query-box.spec.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import { expect } from "@playwright/test";
22

3-
import { languageModels } from "@/plugins/_core/misc/remote-language-models.loader";
4-
import { TEST_ID_SELECTORS } from "@/utils/dom-selectors";
3+
import { DomSelectorsRegistry } from "@/data/dom-selectors-registry";
4+
import { PplxLanguageModel } from "@/data/plugins/query-box/language-model-selector/language-models";
55
import { sleep } from "@/utils/utils";
66
import { HomePage } from "~/e2e/pages/home.page";
77
import { test } from "~/e2e/tests/pro/context.fixtures";
@@ -13,7 +13,7 @@ test.describe("Query box", () => {
1313
await homePage.load();
1414

1515
const languageModelSelector = page.locator(
16-
`[data-testid="${TEST_ID_SELECTORS.QUERY_BOX.LANGUAGE_MODEL_SELECTOR}"]`,
16+
`[data-testid="${DomSelectorsRegistry.testIds.QUERY_BOX.LANGUAGE_MODEL_SELECTOR}"]`,
1717
);
1818

1919
await expect(languageModelSelector).toBeVisible();
@@ -24,7 +24,7 @@ test.describe("Query box", () => {
2424
await homePage.load();
2525

2626
const languageModelSelector = page.locator(
27-
`[data-testid="${TEST_ID_SELECTORS.QUERY_BOX.LANGUAGE_MODEL_SELECTOR}"]`,
27+
`[data-testid="${DomSelectorsRegistry.testIds.QUERY_BOX.LANGUAGE_MODEL_SELECTOR}"]`,
2828
);
2929

3030
await languageModelSelector.click();
@@ -38,13 +38,13 @@ test.describe("Query box", () => {
3838
await homePage.load();
3939

4040
const languageModelSelector = page.locator(
41-
`[data-testid="${TEST_ID_SELECTORS.QUERY_BOX.LANGUAGE_MODEL_SELECTOR}"]`,
41+
`[data-testid="${DomSelectorsRegistry.testIds.QUERY_BOX.LANGUAGE_MODEL_SELECTOR}"]`,
4242
);
4343

4444
await languageModelSelector.click();
4545

4646
const claudeOption = page
47-
.locator(`text=${languageModels?.[1]?.label}`)
47+
.locator(`text=${PplxLanguageModel.allModels?.[1]?.label}`)
4848
.first();
4949
await claudeOption.click();
5050

@@ -53,7 +53,7 @@ test.describe("Query box", () => {
5353
await languageModelSelector.click();
5454

5555
const gpt4oOption = page
56-
.locator(`text=${languageModels?.[0]?.label}`)
56+
.locator(`text=${PplxLanguageModel.allModels?.[0]?.label}`)
5757
.first();
5858
await gpt4oOption.click();
5959
});

perplexity/extension/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "pplx-ext",
3-
"version": "1.11.2",
3+
"version": "1.12.0",
44
"author": "pnd280",
55
"dependencies": {
66
"@ark-ui/react": "^5.6.0",
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
## Improvements
2+
3+
- Many minor changes to improve the loading performance and the reliability of the extension against changes from Perplexity

perplexity/extension/release/cli/create-release-note.js

Lines changed: 73 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -41,8 +41,6 @@ async function main() {
4141
`Changelog file ${chalk.yellowBright(changelogFile)} already exists`,
4242
);
4343
} else {
44-
// const releaseNote = generateFooter(extVersion);
45-
4644
fs.writeFileSync(changelogFile, "");
4745
logger.success(
4846
`Created empty changelog file ${chalk.yellowBright(changelogFile)}`,
@@ -53,47 +51,97 @@ async function main() {
5351
{
5452
type: "confirm",
5553
name: "createRelease",
56-
message: `Create a new GitHub release for version ${extVersion}? Remember to commit and push your changes (including the newly created changelog file) before proceeding.`,
54+
message: `Commit and push your changes (including the newly created changelog file) before proceeding!\nCreate a new GitHub release for version ${extVersion}?`,
5755
default: false,
5856
},
5957
]);
6058

6159
if (createRelease) {
6260
const tagName = `${packageJson.name}@${extVersion}`;
61+
const crxPath = `../${extVersion}-chrome.crx`;
62+
const xpiPath = `../${extVersion}-firefox.xpi`;
6363

64-
const temptChangelogFile = `${changelogFile}.tmp`;
65-
const releaseNote = fs.readFileSync(changelogFile, "utf8");
66-
fs.writeFileSync(
67-
temptChangelogFile,
68-
releaseNote + "\n\n" + generateFooter(extVersion),
69-
);
64+
const crxExists = fs.existsSync(crxPath);
65+
const xpiExists = fs.existsSync(xpiPath);
66+
67+
let proceedWithRelease = true;
7068

71-
const command = `gh release create "${tagName}" -t "${tagName}" --notes-file ${temptChangelogFile} ../${extVersion}-chrome.crx ../${extVersion}-firefox.xpi`;
69+
if (!crxExists || !xpiExists) {
70+
const missingFiles = [];
71+
if (!crxExists) missingFiles.push("Chrome extension (CRX)");
72+
if (!xpiExists) missingFiles.push("Firefox extension (XPI)");
7273

73-
const execAsync = promisify(exec);
74+
const { proceed } = await inquirer.prompt([
75+
{
76+
type: "confirm",
77+
name: "proceed",
78+
message: `The following files are missing: ${missingFiles.join(", ")}. Do you want to proceed with creating the release without them?`,
79+
default: false,
80+
},
81+
]);
7482

75-
try {
76-
const { stdout } = await execAsync(command);
77-
console.log(stdout);
83+
proceedWithRelease = proceed;
84+
}
7885

79-
logger.success(`Created release ${chalk.yellowBright(tagName)}`);
80-
logger.detail(
81-
`https://github.com/pnd280/complexity/releases/tag/${tagName}`,
86+
if (proceedWithRelease) {
87+
const temptChangelogFile = `${changelogFile}.tmp`;
88+
const releaseNote = fs.readFileSync(changelogFile, "utf8");
89+
90+
let footerContent;
91+
try {
92+
footerContent = generateFooter(extVersion, crxExists, xpiExists);
93+
} catch (error) {
94+
logger.error(`Failed to generate footer: ${error.message}`);
95+
return;
96+
}
97+
98+
fs.writeFileSync(
99+
temptChangelogFile,
100+
releaseNote + "\n\n" + footerContent,
82101
);
83-
} catch (error) {
84-
logger.error(`Failed to create GitHub release: ${error.message}`);
85-
process.exit(1);
86-
} finally {
87-
fs.unlinkSync(temptChangelogFile);
102+
103+
let command = `gh release create "${tagName}" -t "${tagName}" --notes-file ${temptChangelogFile}`;
104+
105+
if (crxExists) {
106+
command += ` "${crxPath}"`;
107+
}
108+
109+
if (xpiExists) {
110+
command += ` "${xpiPath}"`;
111+
}
112+
113+
const execAsync = promisify(exec);
114+
115+
try {
116+
const { stdout } = await execAsync(command);
117+
console.log(stdout);
118+
119+
logger.success(`Created release ${chalk.yellowBright(tagName)}`);
120+
logger.detail(
121+
`https://github.com/pnd280/complexity/releases/tag/${tagName}`,
122+
);
123+
} catch (error) {
124+
logger.error(`Failed to create GitHub release: ${error.message}`);
125+
process.exit(1);
126+
} finally {
127+
fs.unlinkSync(temptChangelogFile);
128+
}
129+
} else {
130+
logger.info("Release creation cancelled.");
88131
}
89132
}
90133
}
91134

92-
function generateFooter(version) {
135+
function generateFooter(version, crxExists = true, xpiExists = true) {
93136
try {
94137
const footerTemplate = fs.readFileSync(FOOTER_TEMPLATE_PATH, "utf8");
95-
const crxHash = md5sum(`../${version}-chrome.crx`);
96-
const xpiHash = md5sum(`../${version}-firefox.xpi`);
138+
139+
const crxHash = crxExists
140+
? md5sum(`../${version}-chrome.crx`)
141+
: "File not available";
142+
const xpiHash = xpiExists
143+
? md5sum(`../${version}-firefox.xpi`)
144+
: "File not available";
97145

98146
return footerTemplate
99147
.replace("$CRX_HASH", crxHash)

perplexity/extension/src/app.config.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,12 @@ const APP_CONFIG = {
2626
globalExcludeMatches: [
2727
"https://stripe.perplexity.ai/*",
2828
"https://*.perplexity.ai/p/api/*",
29-
"https://*.perplexity.ai/hub/*",
3029
"https://*.perplexity.ai/rest/*",
3130
"https://*.perplexity.ai/api/*",
3231
"https://*.labs.perplexity.ai/*",
3332
"https://*.docs.perplexity.ai/*",
33+
"https://*.perplexity.ai/hub/*",
34+
"https://*.perplexity.ai/changelog/*",
3435
],
3536
},
3637
};

perplexity/extension/src/components/SettingsDashboardLink.tsx

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,30 +3,36 @@ import { sendMessage } from "webext-bridge/content-script";
33
import Cplx from "@/components/icons/Cplx";
44
import FaArrowUpRight from "@/components/icons/FaArrowUpRight";
55
import { Portal } from "@/components/ui/portal";
6+
import { DomSelectorsRegistry } from "@/data/dom-selectors-registry";
7+
import { useIsMobileStore } from "@/hooks/use-is-mobile-store";
68
import { useSettingsPageDomObserverStore } from "@/plugins/_core/dom-observers/settings-page/store";
7-
import { DOM_SELECTORS, INTERNAL_ATTRIBUTES } from "@/utils/dom-selectors";
89

910
export function SettingsDashboardLink() {
11+
const isMobile = useIsMobileStore((store) => store.isMobile);
12+
1013
const $sidebarWrapper = useSettingsPageDomObserverStore(
1114
(store) => store.$sidebarWrapper,
15+
isMobile ? undefined : deepEqual,
1216
);
1317

1418
const portalContainer = useMemo(() => {
1519
if ($sidebarWrapper == null || !$sidebarWrapper.length) return null;
1620

1721
const $existingContainer = $sidebarWrapper.find(
18-
`[data-cplx-component="${INTERNAL_ATTRIBUTES.SETTINGS_PAGE.CPLX_DASHBOARD_LINK}"]`,
22+
`[data-cplx-component="${DomSelectorsRegistry.internalAttributes.SETTINGS_PAGE.CPLX_DASHBOARD_LINK}"]`,
1923
);
2024

2125
if ($existingContainer[0]) return $existingContainer[0];
2226

2327
const $portalContainer = $("<div>")
2428
.internalComponentAttr(
25-
INTERNAL_ATTRIBUTES.SETTINGS_PAGE.CPLX_DASHBOARD_LINK,
29+
DomSelectorsRegistry.internalAttributes.SETTINGS_PAGE
30+
.CPLX_DASHBOARD_LINK,
2631
)
2732
.insertAfter(
2833
$sidebarWrapper.find(
29-
DOM_SELECTORS.SETTINGS_PAGE.SIDEBAR_CHILD.BACK_BUTTON,
34+
DomSelectorsRegistry.cachedSync.SETTINGS_PAGE.SIDEBAR_CHILD
35+
.BACK_BUTTON,
3036
),
3137
);
3238

perplexity/extension/src/components/ui/command.tsx

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ const Command = ({
1111
}: React.ComponentProps<typeof CommandPrimitive>) => (
1212
<CommandPrimitive
1313
className={cn(
14-
"x:flex x:h-full x:w-full x:flex-col x:overflow-hidden x:rounded-md x:bg-popover x:text-popover-foreground",
14+
"x:flex x:h-full x:w-full x:flex-col x:overflow-hidden x:rounded-lg x:bg-popover x:text-popover-foreground",
1515
className,
1616
)}
1717
{...props}
@@ -70,7 +70,7 @@ const CommandInput = ({
7070
)}
7171
<CommandPrimitive.Input
7272
className={cn(
73-
"x:flex x:h-11 x:w-full x:rounded-md x:bg-transparent x:py-3 x:text-sm x:outline-none x:placeholder:text-muted-foreground x:disabled:cursor-not-allowed x:disabled:opacity-50",
73+
"x:flex x:h-11 x:w-full x:rounded-lg x:bg-transparent x:py-3 x:text-sm x:outline-none x:placeholder:text-muted-foreground x:disabled:cursor-not-allowed x:disabled:opacity-50",
7474
inputClassName,
7575
)}
7676
{...props}
@@ -139,7 +139,7 @@ const CommandItem = ({
139139
}: React.ComponentProps<typeof CommandPrimitive.Item>) => (
140140
<CommandPrimitive.Item
141141
className={cn(
142-
"x:relative x:flex x:cursor-pointer x:items-center x:rounded-md x:px-2 x:py-1.5 x:text-xs x:text-muted-foreground x:outline-none x:select-none x:aria-selected:bg-primary-foreground x:aria-selected:text-primary x:data-[disabled=true]:pointer-events-none x:data-[disabled=true]:opacity-50",
142+
"x:relative x:flex x:cursor-pointer x:items-center x:rounded-lg x:px-2 x:py-1.5 x:text-xs x:text-muted-foreground x:outline-none x:select-none x:aria-selected:bg-primary-foreground x:aria-selected:text-primary x:data-[disabled=true]:pointer-events-none x:data-[disabled=true]:opacity-50",
143143
className,
144144
)}
145145
{...props}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import * as fs from "fs";
2+
import * as path from "path";
3+
4+
import { describe, it } from "vitest";
5+
6+
import { DOM_SELECTORS } from "@/data/dom-selectors-registry/dom-selectors";
7+
8+
/**
9+
* This is a test file that not for testing anything but exports DOM selectors to JSON for the CDN.
10+
* Vitest will run this during the build process.
11+
*/
12+
describe("DOM selectors", () => {
13+
it("syncs DOM selectors to JSON file", () => {
14+
try {
15+
const rootDir = process.cwd();
16+
const cdnTemplatePath = path.join(rootDir, "cdn-template");
17+
const outputPath = path.join(cdnTemplatePath, "dom-selectors.json");
18+
19+
if (!fs.existsSync(cdnTemplatePath)) {
20+
console.warn(
21+
"cdn-template folder does not exist, skipping DOM selectors sync",
22+
);
23+
return;
24+
}
25+
26+
if (fs.existsSync(outputPath)) {
27+
fs.unlinkSync(outputPath);
28+
}
29+
30+
fs.writeFileSync(outputPath, JSON.stringify(DOM_SELECTORS));
31+
console.log("DOM selectors successfully synced to JSON file");
32+
} catch (error) {
33+
console.error(`Failed to sync DOM selectors: ${error}`);
34+
throw error;
35+
}
36+
});
37+
});

0 commit comments

Comments
 (0)