Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added request monitor to browser extension #2763

Merged
merged 9 commits into from
Feb 15, 2025
Merged

Conversation

imolorhe
Copy link
Collaborator

@imolorhe imolorhe commented Feb 12, 2025

Added a devtools panel to monitor for GraphQL requests and allows opening the request in Altair.

Setup a web extension service, which sets up a listener for messages from the devtools panel. To import request data from the devtools panel, we open the Altair app, then send a message to the Altair app which is part of the extension (so can be considered an extension page) using the chrome.runtime.sendMessage method. The extension page processes the message and imports the request data into the Altair app.

To make sure the Altair app is loaded and ready to receive the message, we send a ping message to the Altair app, and wait for the pong message before sending the actual message. We also wait for the ready message from the Altair app in case it is not loaded yet to have received the ping message.

Checks

  • Ran yarn test-build
  • Updated relevant documentations
  • Updated matching config options in altair-static

Changes proposed in this pull request:

Summary by Sourcery

Add a GraphQL request monitor to the browser extension.

New Features:

  • Display GraphQL requests made by the current page in a devtools panel.
  • Open GraphQL requests from the devtools panel in the Altair GraphQL Client app.

Tests:

  • Add tests for the request monitor.

Copy link

sourcery-ai bot commented Feb 12, 2025

Reviewer's Guide by Sourcery

This pull request implements a new request monitor for the browser extension, allowing users to inspect GraphQL requests through a dedicated DevTools panel and import them into the Altair app. The changes include establishing a communication channel between the devtools panel and the Altair application using a ping/pong mechanism, refactoring the tab handling logic, adding a suite of new UI components to display and interact with monitored requests, and updating dependencies and configuration files.

Sequence diagram for Altair Import Request Messaging

sequenceDiagram
    participant U as User
    participant RM as Request Monitor UI
    participant OIA as openInAltair
    participant CR as Chrome Runtime
    participant WAS as WebExtensionsService
    participant AA as Altair App

    U->>RM: Click "Open in Altair"
    RM->>OIA: Invoke openInAltair()
    OIA->>CR: Call openAltairApp() [ensure Altair App tab]
    OIA->>CR: sendMessage({ type: 'ping' })
    CR-->>WAS: Deliver 'ping' message
    WAS->>CR: sendMessage({ type: 'pong' })
    Note right of OIA: Callback listener waits for 'pong' or 'ready'
    CR-->>OIA: deliver 'pong' (or 'ready')
    OIA->>CR: sendMessage({ type: 'import-window', window: data })
    CR-->>WAS: Deliver 'import-window' message
    WAS->>AA: Process import-window message
    AA->>AA: importWindowData(message.window)
    Note over AA: Request data imported into Altair app
Loading

File-Level Changes

Change Details Files
Implemented a new request monitor DevTools panel for GraphQL requests
  • Added a new devtools panel (monitor panel) with its own HTML and TSX entry points
  • Created UI components and CSS styles for the GraphQL requests monitor including Shell, TableList, TableDetails, and Accordion
  • Integrated a new hook (useGraphQLRequests) to capture and parse network request data in real time
packages/altair-crx/src/monitor/monitor_panel.tsx
packages/altair-crx/src/monitor/monitor_panel.html
packages/altair-crx/src/monitor/ui.css
packages/altair-crx/src/hooks/requests/use-requests.ts
packages/altair-crx/src/hooks/requests/mock-requests.ts
Established messaging and tab handling enhancements between the extension and Altair app
  • Refactored background tab handling to use helper functions (getTabId, openAltairApp, removeTabId)
  • Implemented a ping/pong mechanism to verify Altair’s readiness
  • Added messaging helpers to process 'ping', 'pong', 'ready', and 'import-window' messages
packages/altair-crx/src/background.ts
packages/altair-crx/src/helpers/tabs.ts
packages/altair-crx/src/helpers/messaging.ts
Updated dependency versions and extended package configurations
  • Modified pnpm-lock.yaml entries and updated dependency versions (e.g. rxjs, prettier, @tanstack/react-table)
  • Added new dependencies such as clsx, copy-to-clipboard, and vitest
  • Updated package.json and manifest configurations (including addition of devtools_page) for both altair-crx and altair-app
pnpm-lock.yaml
packages/altair-crx/package.json
packages/altair-app/package.json
packages/altair-crx/manifest.config.ts
packages/altair-crx/vite.config.ts
Developed new UI components for displaying and interacting with GraphQL requests
  • Introduced TableList and TableDetails components for listing requests and showing details
  • Built supporting components such as Accordion, Tabs, CodeSyntax, Button, JSONViewer, and response content handlers
  • Integrated sorting and column resizing using @tanstack/react-table for better presentation of request metadata
packages/altair-crx/src/components/table-list/table-list.tsx
packages/altair-crx/src/components/table-details/table-details.tsx
packages/altair-crx/src/components/accordion/accordion.tsx
packages/altair-crx/src/components/tabs/tabs.tsx
packages/altair-crx/src/components/code-syntax/code-syntax.tsx
packages/altair-crx/src/components/button/button.tsx
packages/altair-crx/src/components/json-viewer/json-viewer.tsx
packages/altair-crx/src/components/response-content/response-content.tsx
Enhanced WebExtensions connectivity within the Altair app
  • Added a new WebExtensionsService to handle incoming messages for importing request data
  • Modified Altair component to initiate connection with the WebExtensionsService at startup
  • Wired the service to respond to messages and trigger the import logic in the Altair app
packages/altair-app/src/app/modules/altair/services/webextensions/webextensions.service.ts
packages/altair-app/src/app/modules/altair/containers/altair/altair.component.ts
packages/altair-app/src/app/modules/altair/altair.module.ts
packages/altair-app/src/app/modules/altair/services/index.ts
Updated documentation for importing request data in the chrome extension
  • Extended DEV.md with a detailed explanation of the new request monitoring functionality and the message flow
DEV.md

Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!
  • Generate a plan of action for an issue: Comment @sourcery-ai plan on
    an issue to generate a plan of action for it.

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

Copy link

@sourcery-ai sourcery-ai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @imolorhe - I've reviewed your changes - here's some feedback:

Overall Comments:

  • Consider adding a visual indicator in the UI to show when the Altair app is ready to receive messages from the extension.
  • The pnpm-lock.yaml file has a lot of changes; consider reviewing them to ensure they are all intentional.
Here's what I looked at during the review
  • 🟡 General issues: 3 issues found
  • 🟢 Security: all looks good
  • 🟢 Testing: all looks good
  • 🟢 Complexity: all looks good
  • 🟢 Documentation: all looks good

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

await chrome.tabs.update(tabId, updateProperties);
};

export const openAltairApp = async () => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Refactored tab management using helper methods.

The abstraction for creating, focusing, and storing tab IDs improves code clarity. Consider handling errors, for example if chrome.tabs.get fails or storage session is unavailable.

Suggested implementation:

const focusTab = async (tabId: number) => {
  const updateProperties = { active: true };
  try {
    await chrome.tabs.update(tabId, updateProperties);
  } catch (error) {
    console.error(`Error focusing tab ${tabId}:`, error);
  }
};
export const getTabId = async () => {
  try {
    const data = await chrome.storage.session.get([ALTAIR_APP_TAB_ID_STORAGE_KEY]);
    return data[ALTAIR_APP_TAB_ID_STORAGE_KEY] as number | undefined;
  } catch (error) {
    console.error("Error retrieving tab ID from storage:", error);
    return undefined;
  }
};
const setTabId = async (tabId: number) => {
  try {
    await chrome.storage.session.set({ [ALTAIR_APP_TAB_ID_STORAGE_KEY]: tabId });
  } catch (error) {
    console.error(`Error setting tab ID ${tabId} in storage:`, error);
  }
};
export const removeTabId = async () => {
  try {
    await chrome.storage.session.remove(ALTAIR_APP_TAB_ID_STORAGE_KEY);
  } catch (error) {
    console.error("Error removing tab ID from storage:", error);
  }
};

};
browser.runtime.onMessage.addListener(callback);

setTimeout(() => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

question: Listener cleanup logic in openInAltair using setTimeout.

The removal of the message listener after 10 seconds is a pragmatic way to avoid stale listeners. Consider whether this timeout sufficiently covers slower initialization scenarios.

setRequests((prevRequests) => [...prevRequests, data]);
});

// TODO: Add cleanup logic
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issue (bug_risk): Event listener cleanup needs addressing.

The hook registers a listener on chrome.devtools.network.onRequestFinished but does not currently unregister it on component unmount. Implementing cleanup would prevent potential memory leaks.

const ast = parse(query);
return ast.definitions
.filter((def): def is OperationDefinitionNode =>
def.kind === Kind.OPERATION_DEFINITION && def.name ? true : false
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion (code-quality): Avoid unneeded ternary statements (simplify-ternary)

Suggested change
def.kind === Kind.OPERATION_DEFINITION && def.name ? true : false
!!(def.kind === Kind.OPERATION_DEFINITION && def.name)


ExplanationIt is possible to simplify certain ternary statements into either use of an || or !.
This makes the code easier to read, since there is no conditional logic.

Copy link

github-actions bot commented Feb 12, 2025

Visit the preview URL for this PR (updated for commit 6875782):

https://altair-gql--pr2763-imolorhe-add-crx-mon-3r66b5cv.web.app

(expires Wed, 19 Feb 2025 20:52:59 GMT)

🔥 via Firebase Hosting GitHub Action 🌎

Sign: 02d6323d75a99e532a38922862e269d63351a6cf

@imolorhe imolorhe added this pull request to the merge queue Feb 15, 2025
Merged via the queue into master with commit a97697f Feb 15, 2025
15 checks passed
@imolorhe imolorhe deleted the imolorhe/add-crx-monitor branch February 15, 2025 16:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant