Merge branch 'poc/preview' into release/v7.2.0

This commit is contained in:
Elio Struyf
2022-04-11 14:10:11 +02:00
6 changed files with 142 additions and 52 deletions
+55 -51
View File
@@ -1,14 +1,15 @@
import { Telemetry } from './../helpers/Telemetry';
import { SETTING_PREVIEW_HOST, SETTING_PREVIEW_PATHNAME, CONTEXT, TelemetryEvent } from './../constants';
import { SETTING_PREVIEW_HOST, SETTING_PREVIEW_PATHNAME, CONTEXT, TelemetryEvent, PreviewCommands } from './../constants';
import { ArticleHelper } from './../helpers/ArticleHelper';
import { join } from "path";
import { commands, env, Uri, ViewColumn, window } from "vscode";
import { Settings } from '../helpers';
import { Extension, Settings } from '../helpers';
import { PreviewSettings } from '../models';
import { format } from 'date-fns';
import { DateHelper } from '../helpers/DateHelper';
import { Article } from '.';
import { urlJoin } from 'url-join-ts';
import { WebviewHelper } from '@estruyf/vscode';
export class Preview {
@@ -81,59 +82,62 @@ export class Preview {
const cspSource = webView.webview.cspSource;
webView.webview.html = `<!DOCTYPE html>
<head>
<meta
http-equiv="Content-Security-Policy"
content="default-src 'none'; frame-src ${localhostUrl} ${cspSource} http: https:; img-src ${localhostUrl} ${cspSource} http: https:; script-src ${localhostUrl} ${cspSource} 'unsafe-inline'; style-src ${localhostUrl} ${cspSource} 'self' 'unsafe-inline' http: https:;"
/>
<style>
html,body {
margin: 0;
padding: 0;
background: white;
height: 100%;
width: 100%;
}
body {
margin: 0;
padding: 0;
webView.webview.onDidReceiveMessage(message => {
switch (message.command) {
case PreviewCommands.toVSCode.open:
if (message.data) {
commands.executeCommand('vscode.open', message.data);
}
return;
}
});
iframe {
width: 100%;
height: calc(100% - 30px);
border: 0;
margin-top: 30px;
}
.slug {
width: 100%;
position: fixed;
height: 30px;
display: flex;
align-items: center;
background-color: var(--vscode-editor-background);
border-bottom: 1px solid var(--vscode-focusBorder);
}
const dashboardFile = "dashboardWebView.js";
const localPort = `9000`;
const localServerUrl = `localhost:${localPort}`;
input {
color: var(--vscode-editor-foreground);
padding: 0.25rem 0.5rem;
background: none;
border: 0;
width: 100%;
}
</style>
</head>
<body>
<div class="slug">
<input type="text" value="${urlJoin(localhostUrl.toString(), slug || '')}" disabled />
</div>
<iframe src="${urlJoin(localhostUrl.toString(), slug || '')}" >
</body>
</html>`;
const nonce = WebviewHelper.getNonce();
const ext = Extension.getInstance();
const isProd = ext.isProductionMode;
const version = ext.getVersion();
const isBeta = ext.isBetaVersion();
const extensionUri = ext.extensionPath;
const csp = [
`default-src 'none';`,
`img-src ${localhostUrl} ${cspSource} http: https:;`,
`script-src ${isProd ? `'nonce-${nonce}'` : `http://${localServerUrl} http://0.0.0.0:${localPort}`} 'unsafe-eval'`,
`style-src ${cspSource} 'self' 'unsafe-inline' http: https:`,
`connect-src https://o1022172.ingest.sentry.io ${isProd ? `` : `ws://${localServerUrl} ws://0.0.0.0:${localPort} http://${localServerUrl} http://0.0.0.0:${localPort}`}`,
`frame-src ${localhostUrl} ${cspSource} http: https:;`,
];
let scriptUri = "";
if (isProd) {
scriptUri = webView.webview.asWebviewUri(Uri.joinPath(extensionUri, 'dist', dashboardFile)).toString();
} else {
scriptUri = `http://${localServerUrl}/${dashboardFile}`;
}
webView.webview.html = `
<!DOCTYPE html>
<html lang="en" style="width:100%;height:100%;margin:0;padding:0;">
<head>
<meta charset="UTF-8">
<meta http-equiv="Content-Security-Policy" content="${csp.join('; ')}">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Front Matter Preview</title>
</head>
<body style="width:100%;height:100%;margin:0;padding:0;overflow:hidden">
<div id="app" data-type="preview" data-url="${urlJoin(localhostUrl.toString(), slug || '')}" data-isProd="${isProd}" data-environment="${isBeta ? "BETA" : "main"}" data-version="${version.usedVersion}" style="width:100%;height:100%;margin:0;padding:0;"></div>
<script ${isProd ? `nonce="${nonce}"` : ""} src="${scriptUri}"></script>
</body>
</html>
`;
Telemetry.send(TelemetryEvent.openPreview);
}
+8
View File
@@ -0,0 +1,8 @@
export const PreviewCommands = {
toVSCode: {
open: `preview.open`
},
fromVSCode: {}
};
+1
View File
@@ -9,6 +9,7 @@ export * from './GeneralCommands';
export * from './Links';
export * from './LocalStore';
export * from './Navigation';
export * from './PreviewCommands';
export * from './TelemetryEvent';
export * from './charCode';
export * from './charMap';
@@ -0,0 +1,69 @@
import { Messenger } from '@estruyf/vscode/dist/client';
import { ExternalLinkIcon, RefreshIcon } from '@heroicons/react/outline';
import * as React from 'react';
import { useRef } from 'react';
import { PreviewCommands } from '../../../constants';
export interface IPreviewProps {
url: string | null;
}
export const Preview: React.FunctionComponent<IPreviewProps> = ({url}: React.PropsWithChildren<IPreviewProps>) => {
const iframeRef = useRef<HTMLIFrameElement>(null);
const onRefresh = () => {
if (iframeRef.current?.src) {
iframeRef.current.src = iframeRef.current.src;
}
};
const openInBrowser = () => {
Messenger.send(PreviewCommands.toVSCode.open, url);
};
return (
<div className='w-full h-full bg-white'>
<div
className="slug fixed w-full top-0 flex items-center"
style={{
height: "30px",
background: "var(--vscode-editor-background)",
borderBottom: "1px solid var(--vscode-focusBorder)"
}}
>
<input
type="text"
value={url || ""}
className="w-full h-full border-0 bg-transparent text-xs py-1 px-2"
style={{
color: "var(--vscode-editor-foreground)"
}}
disabled />
<div
className="actions absolute right-0 top-0 bottom-0 flex items-center space-x-2 px-2"
style={{
background: "var(--vscode-editor-background)",
}}
>
<button title="Refresh" onClick={onRefresh}>
<RefreshIcon className='w-4 h-4' aria-hidden="true" />
</button>
<button title="Open" onClick={openInBrowser} className="mr-2">
<ExternalLinkIcon className='w-4 h-4' aria-hidden="true" />
</button>
</div>
</div>
<iframe
ref={iframeRef}
src={url || ""}
className={`w-full border-0`}
style={{
height: "calc(100% - 30px)",
marginTop: "30px"
}}></iframe>
</div>
);
};
@@ -0,0 +1 @@
export * from './Preview';
+8 -1
View File
@@ -6,6 +6,7 @@ import * as Sentry from "@sentry/react";
import { Integrations } from "@sentry/tracing";
import { SENTRY_LINK } from "../constants";
import './styles.css';
import { Preview } from "./components/Preview";
declare const acquireVsCodeApi: <T = unknown>() => {
getState: () => T;
@@ -19,6 +20,8 @@ if (elm) {
const version = elm?.getAttribute("data-version");
const environment = elm?.getAttribute("data-environment");
const isProd = elm?.getAttribute("data-isProd");
const type = elm?.getAttribute("data-type");
const url = elm?.getAttribute("data-url");
if (isProd === "true") {
Sentry.init({
@@ -31,7 +34,11 @@ if (elm) {
});
}
render(<RecoilRoot><Dashboard showWelcome={!!welcome} /></RecoilRoot>, elm);
if (type === "preview") {
render(<Preview url={url} />, elm);
} else {
render(<RecoilRoot><Dashboard showWelcome={!!welcome} /></RecoilRoot>, elm);
}
}
// Webpack HMR