Skip to content

Commit

Permalink
persistent panels
Browse files Browse the repository at this point in the history
  • Loading branch information
djnicholson committed Oct 20, 2020
1 parent f8e3429 commit 22e483e
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 82 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
"publisher": "djnicholson",
"displayName": "Automatic web panel opener - webpanel.json",
"description": "Automatically opens web panels according to the webpanel.json file in the current workspace.",
"version": "1.0.2",
"version": "1.0.3",
"icon": "resources/logo.png",
"galleryBanner": {
"color": "#000000",
Expand Down
177 changes: 97 additions & 80 deletions src/extension/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,125 +3,142 @@ import * as nodeFetch from "node-fetch";
import * as path from "path";
import * as vscode from "vscode";

const PATTERN = "**/.vscode/webpanel.json";

const FLAG_ACCEPTING_MESSAGES = "accepting-messages";
const FLAG_PANEL_UP = "panel-up";

let fileSystemWatcher: vscode.FileSystemWatcher | null = null;

let panelsByUrl: { [url: string]: vscode.WebviewPanel } = {};

let active = false;

let context: vscode.ExtensionContext | null = null;

let loading: { url: string; panel: vscode.WebviewPanel }[] = [];
let urls: {
[url: string]: boolean;
} = {};

function ensurePanel(url: string) {
if (!active || !context) {
if (!context) {
return;
}
const existingPanel = panelsByUrl[url];
if (!existingPanel || !existingPanel.visible) {
const newPanel = vscode.window.createWebviewPanel(
`web-panel-${url}`,
url,
vscode.ViewColumn.Beside,
{ enableScripts: true, retainContextWhenHidden: true }
if (existingPanel) {
return;
}
const newPanel = vscode.window.createWebviewPanel(
`web-panel-${url}`,
url,
vscode.ViewColumn.Two,
{ enableScripts: true, retainContextWhenHidden: true }
);
newPanel.webview.html = fs
.readFileSync(
path.join(context.extensionPath, "dist", "panel", "index.html")
)
.toString()
.replace(
"[BASE_HREF]",
newPanel.webview
.asWebviewUri(
vscode.Uri.file(path.join(context.extensionPath, "dist", "panel"))
)
.toString() + "/"
);
newPanel.webview.html = fs
.readFileSync(
path.join(context.extensionPath, "dist", "panel", "index.html")
)
.toString()
.replace(
"[BASE_HREF]",
newPanel.webview
.asWebviewUri(
vscode.Uri.file(path.join(context.extensionPath, "dist", "panel"))
)
.toString() + "/"
newPanel.webview.onDidReceiveMessage(
() => ((newPanel as any)[FLAG_ACCEPTING_MESSAGES] = true)
);
newPanel.onDidDispose(() => delete panelsByUrl[url]);
panelsByUrl[url] = newPanel;
}

function extractUrls(webPanelJsonFile: vscode.Uri): string[] {
const result: string[] = [];
try {
const fileContents = fs.readFileSync(webPanelJsonFile.fsPath);
const urlList = JSON.parse(fileContents.toString());
if (!Array.isArray(urlList)) {
vscode.window.showErrorMessage(
"Your webpanel.json file should contain a single array of URLs."
);
newPanel.webview.onDidReceiveMessage(
() => ((newPanel as any)["accepting-messages"] = true)
} else {
result.push(...urlList);
}
} catch (e) {
vscode.window.showErrorMessage(
`Error processing webpanel.json file: ${e.message}`
);
newPanel.onDidDispose(() => delete panelsByUrl[url]);
panelsByUrl[url] = newPanel;
loading.push({ url, panel: newPanel });
}
return result;
}

async function loadUrls() {
if (!active) {
async function monitorPanels() {
if (!context) {
return;
}
try {
const toProcess = loading;
loading = [];
for (const _ of toProcess) {
const url = _.url;
const panel = _.panel;
const acceptingMessages = (panel as any)["accepting-messages"];
if (!acceptingMessages) {
console.log("web-panel", url, "Waiting for panel");
loading.push(_);
} else {
try {
await nodeFetch.default(url);
try {
panel.webview.postMessage({ url });
console.log("web-panel", url, "URL up");
} catch (e) {
console.log("web-panel", url, "Panel error", e.message);
for (const url of Object.getOwnPropertyNames(urls)) {
ensurePanel(url);
const panel = panelsByUrl[url];
if (panel) {
const acceptingMessages = (panel as any)[FLAG_ACCEPTING_MESSAGES];
const panelUp = (panel as any)[FLAG_PANEL_UP];
if (!panelUp) {
if (acceptingMessages) {
try {
await nodeFetch.default(url);
try {
panel.webview.postMessage({ url });
console.log("web-panel", url, "URL up");
(panel as any)[FLAG_PANEL_UP] = true;
} catch (e) {
console.log("web-panel", url, "Panel error", e.message);
}
} catch (e) {
console.log("web-panel", url, "Waiting for URL");
}
} else {
console.log("web-panel", url, "Waiting for panel to initialize");
}
} catch (e) {
console.log("web-panel", url, "Waiting for URL");
loading.push(_);
}
} else {
console.log("web-panel", url, "Waiting for panel to open");
}
}
} finally {
setTimeout(loadUrls, 1000);
setTimeout(monitorPanels, 1000);
}
}

function refreshWebPanelJson(file: vscode.Uri) {
if (!active || !context) {
return;
}
try {
const fileContents = fs.readFileSync(file.fsPath);
const urlList = JSON.parse(fileContents.toString());
if (!Array.isArray(urlList)) {
vscode.window.showErrorMessage(
"Your webpanel.json file should contain a single array of URLs."
);
} else {
for (const url of urlList) {
ensurePanel(url);
async function parseAllUrls() {
const urlsToRemove = { ...urls };
const webPanelJsonFiles = await vscode.workspace.findFiles(PATTERN);
for (const webPanelJsonFile of webPanelJsonFiles) {
const urlsThisFile = extractUrls(webPanelJsonFile);
for (const url of urlsThisFile) {
urls[url] = true;
if (!!urlsToRemove[url]) {
delete urlsToRemove[url];
}
}
} catch (e) {
vscode.window.showErrorMessage(
`Error processing webpanel.json file: ${e.message}`
);
}
for (const urlToRemove of Object.getOwnPropertyNames(urlsToRemove)) {
delete urls[urlToRemove];
}
}

export async function activate(extensionContext: vscode.ExtensionContext) {
context = extensionContext;
fileSystemWatcher?.dispose();
fileSystemWatcher = vscode.workspace.createFileSystemWatcher(
"**/.vscode/webpanel.json"
);
fileSystemWatcher.onDidChange(refreshWebPanelJson);
fileSystemWatcher.onDidCreate(refreshWebPanelJson);
active = true;
const runNow = await vscode.workspace.findFiles("**/.vscode/webpanel.json");
for (const file of runNow) {
refreshWebPanelJson(file);
}
loadUrls();
fileSystemWatcher = vscode.workspace.createFileSystemWatcher(PATTERN);
fileSystemWatcher.onDidChange(parseAllUrls);
fileSystemWatcher.onDidCreate(parseAllUrls);
await parseAllUrls();
await monitorPanels();
}

export function deactivate() {
active = false;
context = null;
fileSystemWatcher?.dispose();
fileSystemWatcher = null;
for (const url of Object.getOwnPropertyNames(panelsByUrl)) {
Expand Down
2 changes: 1 addition & 1 deletion src/panel/Frame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default function Frame() {
return (
<div style={{ height: "100%", display: "flex", flexDirection: "column" }}>
{!!iframeSrc && (
<iframe style={{ flex: "1" }} src={iframeSrc} ref={iframe} />
<iframe style={{ flex: "1", border: 0 }} src={iframeSrc} ref={iframe} />
)}
{!iframeSrc && (
<div
Expand Down

0 comments on commit 22e483e

Please sign in to comment.