Skip to content

Commit

Permalink
feat(@lexical/devtools): Correct handling of the restricted tabs
Browse files Browse the repository at this point in the history
  • Loading branch information
StyleT committed Apr 23, 2024
1 parent 9b872b3 commit 9cff231
Show file tree
Hide file tree
Showing 10 changed files with 153 additions and 45 deletions.
1 change: 1 addition & 0 deletions packages/lexical-devtools/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ $ npm run dev
- Extension activity log: [chrome://extensions/?activity=eddfjidloofnnmloonifcjkpmfmlblab](chrome://extensions/?activity=eddfjidloofnnmloonifcjkpmfmlblab)
- Status of ServiceWorkers: [chrome://serviceworker-internals/?devtools](chrome://serviceworker-internals/?devtools)
- WXT Framework debugging: `DEBUG_WXT=1 npm run dev`
- If you detach the Dev Tools in a separate window, and press `Cmd+Option+I` while Dev Tools window is focused, you will invoke the Dev Tools for the Dev Tools window.

## Design

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/**
* Copyright (c) Meta Platforms, Inc. and affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
*/
import type {Tabs} from 'wxt/browser';
import type {StoreApi} from 'zustand';

import {IS_FIREFOX} from 'shared/environment';

import {ExtensionState} from '../../store';

export default class ActionIconWatchdog {
private constructor(
private readonly extensionStore: StoreApi<ExtensionState>,
) {}

static async start(store: StoreApi<ExtensionState>) {
return new ActionIconWatchdog(store).init();
}

async init() {
const tabs = await browser.tabs.query({});
await Promise.all(
tabs.map(this.checkAndHandleRestrictedPageIfSo.bind(this)),
);

browser.tabs.onCreated.addListener((tab) => {
this.checkAndHandleRestrictedPageIfSo(tab);
});

// Listen to URL changes on the active tab and update the DevTools icon.
browser.tabs.onUpdated.addListener(this.handleTabsUpdatedEvent.bind(this));
}

private async setIcon(
lexicalBuildType: 'restricted' | 'enabled',
tabId: number,
) {
const action = IS_FIREFOX ? browser.browserAction : browser.action;

await action.setIcon({
path: {
'128': browser.runtime.getURL(
lexicalBuildType === 'enabled'
? '/icon/128.png'
: '/icon/128-restricted.png',
),
'16': browser.runtime.getURL(
lexicalBuildType === 'enabled'
? '/icon/16.png'
: '/icon/16-restricted.png',
),
'32': browser.runtime.getURL(
lexicalBuildType === 'enabled'
? '/icon/32.png'
: '/icon/32-restricted.png',
),
'48': browser.runtime.getURL(
lexicalBuildType === 'enabled'
? '/icon/48.png'
: '/icon/48-restricted.png',
),
},
tabId: tabId,
});

if (lexicalBuildType === 'restricted') {
this.extensionStore.getState().markTabAsRestricted(tabId);
}
}

private handleTabsUpdatedEvent(
tabId: number,
_changeInfo: unknown,
tab: Tabs.Tab,
): void {
this.checkAndHandleRestrictedPageIfSo(tab);
}

private isRestrictedBrowserPage(url: string | undefined) {
return (
!url || ['chrome:', 'about:', 'file:'].includes(new URL(url).protocol)
);
}

private async checkAndHandleRestrictedPageIfSo(tab: Tabs.Tab) {
if (tab.id == null) {
return;
}

if (tab.id == null || this.isRestrictedBrowserPage(tab.url)) {
return this.setIcon('restricted', tab.id);
}

return this.setIcon('enabled', tab.id);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,11 @@
import {registerRPCService} from '@webext-pegasus/rpc';
import {initPegasusTransport} from '@webext-pegasus/transport/background';

import {initExtensionStoreBackend} from '../../store.ts';
import {
initExtensionStoreBackend,
useExtensionStore as extensionStore,
} from '../../store.ts';
import ActionIconWatchdog from './ActionIconWatchdog.ts';
import {getTabIDService} from './getTabIDService';

export default defineBackground(() => {
Expand All @@ -20,4 +24,6 @@ export default defineBackground(() => {
// Store initialization so other extension surfaces can use it
// as all changes go through background SW
initExtensionStoreBackend();

ActionIconWatchdog.start(extensionStore).catch(console.error);
});
14 changes: 0 additions & 14 deletions packages/lexical-devtools/src/entrypoints/popup/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -17,17 +17,3 @@ body {
margin: 0 auto;
padding: 1rem;
}

.logo {
height: 2em;
/* padding: 1.5em; */
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}

.card {
padding-top: 2em;
}
65 changes: 36 additions & 29 deletions packages/lexical-devtools/src/entrypoints/popup/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,10 @@
*/
import './App.css';

import {Box, Flex} from '@chakra-ui/react';
import * as React from 'react';
import {useState} from 'react';

import lexicalLogo from '@/public/lexical.svg';

import EditorsRefreshCTA from '../../components/EditorsRefreshCTA';
import {useExtensionStore} from '../../store';

Expand All @@ -27,38 +26,46 @@ function App({tabID}: Props) {
const lexicalCount = Object.keys(states ?? {}).length;

return (
<>
<div>
<a href="https://lexical.dev" target="_blank">
<img src={lexicalLogo} className="logo" alt="Lexical logo" />
</a>
</div>
<Flex direction="column">
{errorMessage !== '' ? (
<div className="card error">{errorMessage}</div>
<Box className="error" mb={2} color="red">
{errorMessage}
</Box>
) : null}
<div className="card">
{states === undefined ? (
<span>Loading...</span>
) : (
<Box>
{states === null ? (
<span>
Found <b>{lexicalCount}</b> editor{lexicalCount > 1 ? 's' : ''} on
the page
{lexicalCount > 0 ? (
<>
{' '}
&#x2705;
<br />
Open the developer tools, and "Lexical" tab will appear to the
right.
</>
) : null}
This is a restricted browser page. Lexical DevTools cannot access
this page.
</span>
) : states === undefined ? (
<span>Loading...</span>
) : (
<>
<Box>
Found <b>{lexicalCount}</b> editor
{lexicalCount > 1 || lexicalCount === 0 ? 's' : ''} on the page
{lexicalCount > 0 ? (
<>
{' '}
&#x2705;
<br />
Open the developer tools, and "Lexical" tab will appear to the
right.
</>
) : null}
</Box>

<Box mt={1}>
<EditorsRefreshCTA
tabID={tabID}
setErrorMessage={setErrorMessage}
/>
</Box>
</>
)}
<p>
<EditorsRefreshCTA tabID={tabID} setErrorMessage={setErrorMessage} />
</p>
</div>
</>
</Box>
</Flex>
);
}

Expand Down
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 9 additions & 1 deletion packages/lexical-devtools/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ import {SerializedRawEditorState} from './types';

export interface ExtensionState {
lexicalState: {
[tabID: number]: {[editorKey: string]: SerializedRawEditorState};
[tabID: number]: {[editorKey: string]: SerializedRawEditorState} | null;
};
selectedEditorKey: {
[tabID: number]: string | null;
};
markTabAsRestricted: (tabID: number) => void;
setStatesForTab: (
id: number,
states: {[editorKey: string]: SerializedRawEditorState},
Expand All @@ -32,6 +33,13 @@ export interface ExtensionState {
export const useExtensionStore = create<ExtensionState>()(
subscribeWithSelector((set) => ({
lexicalState: {},
markTabAsRestricted: (tabID: number) =>
set((state) => ({
lexicalState: {
...state.lexicalState,
[tabID]: null,
},
})),
selectedEditorKey: {},
setSelectedEditorKey: (tabID: number, editorKey: string | null) =>
set((state) => ({
Expand Down

0 comments on commit 9cff231

Please sign in to comment.