Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,21 @@
"DEBUGTELEMETRY": "v"
}
},
{
"name": "Launch Extension + web view",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
],
"outFiles": [
"${workspaceFolder}/dist/**/*.{js,mjs,cjs}",
],
"preLaunchTask": "Watch: ESBuild with Web View",
"env": {
"DEBUGTELEMETRY": "v"
}
},
{
"name": "Launch Extension + Docker",
"type": "extensionHost",
Expand Down
16 changes: 16 additions & 0 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,21 @@
},
"isBackground": true,
},
{
"label": "Watch: ESBuild with Web View",
"type": "shell",
"command": "npx",
"args": [
"concurrently",
"\"npm:build:esbuild -- --watch\"",
"\"npm:build:webview -- --watch\""
],
"isBackground": true,
"problemMatcher": "$esbuild-watch",
"presentation": {
"reveal": "always",
"focus": true
}
}
Comment on lines +43 to +58
Copy link
Contributor

Choose a reason for hiding this comment

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

I think you could build a compound task for this? I'm worried the problem matcher will get very confused.

]
}
82 changes: 27 additions & 55 deletions esbuild.views.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -5,100 +5,72 @@

import { isAutoDebug, isAutoWatch } from '@microsoft/vscode-azext-eng/esbuild';
import esbuild from 'esbuild';
import copy from 'esbuild-plugin-copy';
import path from 'path';
import { fileURLToPath } from 'url';

const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);

const outdir = './dist';
const outdir = path.resolve(__dirname, 'dist');

const commonConfig = {
entryPoints: {
views: path.resolve(__dirname, 'src/webviews/index.tsx'),
},

bundle: true,
outdir: './dist', //check if this is correct (may be diff now since we are using esbuild)
format: 'cjs',
outdir: outdir,
format: 'esm',
platform: 'browser', //todo: remove (platform is auto browser if not specified)
target: 'es2022',
sourcemap: isAutoWatch,
minify: !isAutoWatch,
metafile: isAutoDebug,
splitting: false,

inject: [path.resolve(__dirname, 'react-shim.js')], //todo: gotta create this react-shim.js
inject: [path.resolve(__dirname, 'react-shim.js')],

// todo: may need to check these
loader: {
'.ts': 'ts',
'.tsx': 'tsx',
'.css': 'css',
'.scss': 'css',
'.sass': 'css',
'.ttf': 'file',
'.ttf': 'dataurl',
'.woff': 'dataurl',
'.woff2': 'dataurl',
},

plugins: [
// todo do we need this? Added since esbuild does not support sass so we need to add the plugin but not sure if sass is needed
{
name: 'sass',
setup(build) {
import('sass').then((sass) => {
build.onLoad({ filter: /\.s[ac]ss$/ }, async (args) => {
const result = sass.compile(args.path);
return {
contents: result.css,
loader: 'css',
};
});
build.onLoad({ filter: /\.s[ac]ss$/ }, async (args) => {
const sass = await import('sass');
const result = sass.compile(args.path);
return {
contents: result.css,
loader: 'css',
};
});
},
},

// todo: make sure these file paths are still correct. They may be different now with using esbuild
copy({
assets: {
from: [
path.resolve(__dirname, 'node_modules/@vscode/codicons/dist/codicon.css'),
path.resolve(__dirname, 'node_modules/@vscode/codicons/dist/codicon.ttf'),
],
to: [
path.resolve(outdir, 'icons/codicon.css'),
path.resolve(outdir, 'icons/codicon.ttf'),
],
},
}),
],

logLevel: 'info'
};

const ctx = await esbuild.context({
...commonConfig,
outdir,
});

// Always do an initial rebuild to ensure views.js exists
await ctx.rebuild();

if (isAutoWatch) {
esbuild
.serve(
{
servedir: outdir, // todo esbuild only serves one directory so in order to copy the static then we would need to copy over into dist/static (this is done in webpack)
port: 8080,
host: '127.0.0.1',
headers: {
'Access-Control-Allow-Origin': '*',
'Access-Control-Allow-Methods': 'GET, POST, PUT, DELETE, PATCH, OPTIONS',
'Access-Control-Allow-Headers':
'X-Requested-With, content-type, Authorization',
},
},
{
...commonConfig,
publicPath: '/',
}
)
.then(() => {
console.log('Dev server running at http://127.0.0.1:8080');
})
.catch(() => process.exit(1));
await ctx.watch();
console.log('Watching webview bundle...');
await new Promise(() => { });
} else {
esbuild.build(commonConfig).catch(() => process.exit(1));
await ctx.rebuild();
await ctx.dispose();
}
14 changes: 7 additions & 7 deletions src/webviews/ConfirmationView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import { Button, createTableColumn, DataGrid, DataGridBody, DataGridCell, DataGridRow, TableCellLayout, Tooltip, type OnSelectionChangeData, type SelectionItemId, type TableColumnDefinition } from '@fluentui/react-components';
import * as React from 'react';
import { useContext, useState, type JSX } from 'react';
import './confirmationView.scss';
import './styles/confirmationView.scss';
import { type ConfirmationViewControllerType } from './ConfirmationViewController';
import { useConfiguration } from './useConfiguration';
import { ConfirmationViewCommands } from './webviewConstants';
Expand Down Expand Up @@ -53,18 +53,18 @@ export const ConfirmationView = (): JSX.Element => {
value: value,
commandName: commandName
});
}
};

const cancelClicked = () => {
vscodeApi.postMessage({
command: ConfirmationViewCommands.Cancel
})
});
};

const onChange = (_ev: React.MouseEvent<HTMLInputElement, MouseEvent>, data: OnSelectionChangeData) => {
setName(data.selectedItems.size > 0 ? 'Edit' : 'Confirm');
setSelectedItems(data.selectedItems.size > 0 ? createNewSetWithItem(data.selectedItems, false) : createNewSetWithItem(data.selectedItems, true));
}
};

const columnSizingOptions = {
name: {
Expand All @@ -75,7 +75,7 @@ export const ConfirmationView = (): JSX.Element => {
defaultWidth: 275,
minWidth: 275,
}
}
};

const columns: TableColumnDefinition<Item>[] = [
createTableColumn<Item>({
Expand Down Expand Up @@ -105,7 +105,7 @@ export const ConfirmationView = (): JSX.Element => {
</TableCellLayout >;
},
})
]
];

const DataGridComponent: React.FC<{
context: ConfirmationViewControllerType,
Expand Down Expand Up @@ -158,4 +158,4 @@ export const ConfirmationView = (): JSX.Element => {
</div>
</div>
);
}
};
4 changes: 2 additions & 2 deletions src/webviews/LoadingView.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
*--------------------------------------------------------------------------------------------*/

import { Spinner } from "@fluentui/react-components";
import './loadingView.scss';
import './styles/loadingView.scss';

export const LoadingView = () =>
<div className='loadingView'>
<Spinner labelPosition="below" label="Generating Copilot responses..." />
</div>
</div>;

51 changes: 15 additions & 36 deletions src/webviews/extension-server/WebviewBaseController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,11 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

/* eslint-disable @typescript-eslint/no-unsafe-member-access,@typescript-eslint/no-unsafe-assignment,@typescript-eslint/no-unsafe-call */
import { randomBytes } from 'crypto';
import * as path from 'path';
import * as vscode from 'vscode';
import { ext } from "../../extensionVariables";

const DEV_SERVER_HOST = 'http://localhost:8080';

/**
* WebviewBaseController is a class that manages a vscode.Webview and provides
* a way to communicate with it. It provides a way to register request handlers and reducers
Expand Down Expand Up @@ -44,41 +41,24 @@ export abstract class WebviewBaseController<Configuration> implements vscode.Dis
}

protected getDocumentTemplate(webview?: vscode.Webview) {
const isProduction = ext.context.extensionMode === vscode.ExtensionMode.Production;
const nonce = randomBytes(16).toString('base64');

const filename = 'views.js';
const uri = (...parts: string[]) => webview?.asWebviewUri(vscode.Uri.file(path.join(ext.context.extensionPath, ...parts))).toString(true);
const srcUri = isProduction ? uri('dist', filename) : `${DEV_SERVER_HOST}/${filename}`;

const codiconsUri = (...parts: string[]) => webview?.asWebviewUri(vscode.Uri.file(path.join(ext.context.extensionPath, ...parts))).toString(true);
const codiconsSrcUri = isProduction ? codiconsUri('dist', 'icons', 'codicon.css') : codiconsUri('node_modules', '@vscode', 'codicons', 'dist', 'codicon.css');
console.log(`codiconsSrcUri: ${codiconsSrcUri}`);
console.log(`srcUri: ${srcUri}`);

const csp = (
isProduction
? [
`form-action 'none';`,
`default-src ${webview?.cspSource};`,
`script-src ${webview?.cspSource} 'nonce-${nonce}';`,
`style-src ${webview?.cspSource} vscode-resource: 'unsafe-inline';`,
`img-src ${webview?.cspSource} data: vscode-resource:;`,
`connect-src ${webview?.cspSource} ws:;`,
`font-src ${webview?.cspSource};`,
`worker-src ${webview?.cspSource} blob:;`,
]
: [
`form-action 'none';`,
`default-src ${webview?.cspSource} ${DEV_SERVER_HOST};`,
`script-src ${webview?.cspSource} ${DEV_SERVER_HOST} 'nonce-${nonce}';`,
`style-src ${webview?.cspSource} ${DEV_SERVER_HOST} vscode-resource: 'unsafe-inline';`,
`img-src ${webview?.cspSource} ${DEV_SERVER_HOST} data: vscode-resource:;`,
`connect-src ${webview?.cspSource} ${DEV_SERVER_HOST} ws:;`,
`font-src ${webview?.cspSource} ${DEV_SERVER_HOST};`,
`worker-src ${webview?.cspSource} ${DEV_SERVER_HOST} blob:;`,
]
).join(' ');
const srcUri = uri('dist', filename);
const cssUri = uri('dist', 'views.css');

const csp = [
`form-action 'none';`,
`default-src ${webview?.cspSource};`,
`script-src ${webview?.cspSource} 'nonce-${nonce}';`,
`style-src ${webview?.cspSource} vscode-resource: 'unsafe-inline';`,
`img-src ${webview?.cspSource} data: vscode-resource:;`,
`connect-src ${webview?.cspSource} ws:;`,
`font-src ${webview?.cspSource} data:;`,
`worker-src ${webview?.cspSource} blob:;`,
]
.join(' ');

/**
* Note to code maintainers:
Expand All @@ -91,7 +71,7 @@ export abstract class WebviewBaseController<Configuration> implements vscode.Dis
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="${codiconsSrcUri}" rel="stylesheet" />
<link href="${cssUri}" rel="stylesheet" />
<meta // noinspection JSAnnotator
http-equiv="Content-Security-Policy" content="${csp}" />
</head>
Expand Down Expand Up @@ -123,7 +103,6 @@ export abstract class WebviewBaseController<Configuration> implements vscode.Dis
*/
public dispose() {
this._onDisposed.fire();
// eslint-disable-next-line @typescript-eslint/no-unsafe-return
this._disposables.forEach((d) => d.dispose());
this._isDisposed = true;
}
Expand Down
2 changes: 1 addition & 1 deletion src/webviews/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import './styles/global.scss';

import * as React from 'react';
// eslint-disable-next-line import/no-internal-modules
import { createRoot } from 'react-dom/client';
import { type WebviewApi } from 'vscode-webview';
import { DynamicThemeProvider } from './theme/DynamicThemeProvider';
Expand Down
10 changes: 10 additions & 0 deletions src/webviews/styles/global.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
@import '@vscode/codicons/dist/codicon.css';

.codicon,
.codicon::before {
font-family: codicon !important;
}
File renamed without changes.