Inital platform relayering (#6385)

* moving test files and inital refactoring

* relayer extension host code

* fix imports

* make insights work

* relayer dashboard

* relayer notebooks

* moveing more code around

* formatting

* accept angular as browser

* fix serializer

* add missing files

* remove declarations from extensions

* fix build errors

* more relayering

* change urls to relative to help code relayering

* remove layering to prep for merge

* fix hygiene errors

* fix hygiene errors

* fix tests
This commit is contained in:
Anthony Dresser
2019-07-18 17:29:17 -07:00
committed by GitHub
parent 45c13116de
commit c23738f935
576 changed files with 2090 additions and 2788 deletions

View File

@@ -0,0 +1,139 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.notebookEditor .editor-toolbar {
border-bottom-width: 1px;
border-bottom-style: solid;
}
.notebookEditor .notebook-cell {
margin: 10px 20px 10px;
border-width: 1px;
border-style: solid;
border-radius: 3px;
}
.notebookEditor .notebook-info-label {
padding-right: 5px;
text-align: center;
display: flex;
align-items: center;
}
.notebookEditor .actionbar-container .monaco-action-bar > ul.actions-container {
padding-top: 4px;
padding-bottom: 4px;
min-height: 21px;
}
.notebookEditor .actions-container .action-item .notebook-button {
display: inline-block;
width: 100%;
padding: 0px;
text-align: center;
cursor: pointer;
padding-left: 18px;
background-size: 13px;
margin-right: 20px;
font-size: 13px;
height: 21px;
}
.notebookEditor .labelOnLeftContainer {
min-width: 100px;
max-width: 250px;
margin-right: 20px;
font-size: 13px;
text-align: center;
vertical-align: bottom;
}
.notebookEditor .notebook-button.icon-add{
background-image: url("./media/light/add.svg");
}
.vs-dark .notebookEditor .notebook-button.icon-add,
.hc-black .notebookEditor .notebook-button.icon-add{
background-image: url("./media/dark/add_inverse.svg");
}
.notebookEditor .notebook-button.icon-run-cells{
background-image: url("./media/light/run_cells.svg");
}
.vs-dark .notebookEditor .notebook-button.icon-run-cells,
.hc-black .notebookEditor .notebook-button.icon-run-cells{
background-image: url("./media/dark/run_cells_inverse.svg");
}
.notebookEditor .notebook-button.icon-trusted{
background-image: url("./media/light/trusted.svg");
}
.vs-dark .notebookEditor .notebook-button.icon-trusted,
.hc-black .notebookEditor .notebook-button.icon-trusted{
background-image: url("./media/dark/trusted_inverse.svg");
}
.notebookEditor .notebook-button.icon-notTrusted{
background-image: url("./media/light/nottrusted.svg");
}
.vs-dark .notebookEditor .notebook-button.icon-notTrusted,
.hc-black .notebookEditor .notebook-button.icon-notTrusted{
background-image: url("./media/dark/nottrusted_inverse.svg");
}
.notebookEditor .notebook-button.icon-clear-results{
background-image: url("./media/light/clear_results.svg");
}
.vs-dark .notebookEditor .notebook-button.icon-clear-results,
.hc-black .notebookEditor .notebook-button.icon-clear-results{
background-image: url("./media/dark/clear_results_inverse.svg");
}
.moreActions .action-label.icon.toggle-more {
height: 20px;
width: 20px;
}
.moreActions.actionhidden {
visibility: hidden
}
.notebookEditor .notebook-cellTable {
margin-left: 20px;
margin-top: 10px;
margin-bottom: 10px;
}
.notebookEditor .notebook-cellTable .ui-widget-content.slick-row {
border-left: 1px silver dotted;
}
.notebookEditor .notebook-cellTable .slick-viewport {
min-height: 39px;
}
.monaco-workbench .notebook-action.new-notebook {
background: url('./media/light/new_notebook.svg') center center no-repeat;
}
.vs-dark .monaco-workbench .notebook-action.new-notebook,
.hc-black .monaco-workbench .notebook-action.new-notebook {
background: url('./media/dark/new_notebook_inverse.svg') center center no-repeat;
}
.notebookEditor .book-nav {
display: flex;
align-items: center;
justify-content: flex-start;
margin: 25px;
}
.notebookEditor .book-nav .dialog-message-button {
min-width: 100px;
margin-right: 10px;
}

View File

@@ -0,0 +1,273 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./notebook';
import { registerThemingParticipant, ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
import { SIDE_BAR_BACKGROUND, SIDE_BAR_SECTION_HEADER_BACKGROUND, EDITOR_GROUP_HEADER_TABS_BACKGROUND } from 'vs/workbench/common/theme';
import { activeContrastBorder, contrastBorder, buttonBackground, textLinkForeground, textLinkActiveForeground, textPreformatForeground, textBlockQuoteBackground, textBlockQuoteBorder, buttonForeground } from 'vs/platform/theme/common/colorRegistry';
import { editorLineHighlight, editorLineHighlightBorder } from 'vs/editor/common/view/editorColorRegistry';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { BareResultsGridInfo, getBareResultsGridInfoStyles } from 'sql/workbench/parts/query/browser/queryResultsEditor';
import { getZoomLevel } from 'vs/base/browser/browser';
import * as types from 'vs/base/common/types';
export function registerNotebookThemes(overrideEditorThemeSetting: boolean, configurationService: IConfigurationService): IDisposable {
return registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
let lightBoxShadow = '0px 4px 6px 0px rgba(0, 0, 0, 0.14)';
let darkBoxShadow = '0px 4px 6px 0px rgba(0, 0, 0, 1)';
let addBorderToInactiveCodeCells = true;
// Book Navigation Buttons
const buttonForegroundColor = theme.getColor(buttonForeground);
const buttonBackgroundColor = theme.getColor(buttonBackground);
if (buttonForegroundColor && buttonBackgroundColor) {
collector.addRule(`
.notebookEditor .book-nav .dialog-message-button .monaco-text-button {
border-color: ${buttonBackgroundColor} !important;
background-color: ${buttonForegroundColor} !important;
color: ${buttonBackgroundColor} !important;
border-width: 1px;
border-style: solid;
}
`);
}
// Active border
const activeBorder = theme.getColor(buttonBackground);
if (activeBorder) {
collector.addRule(`
.notebookEditor .notebook-cell.active {
border-color: ${activeBorder};
border-width: 1px;
}
`);
}
// Box shadow handling
collector.addRule(`
.notebookEditor .notebook-cell.active {
box-shadow: ${lightBoxShadow};
}
.vs-dark .notebookEditor .notebook-cell.active {
box-shadow: ${darkBoxShadow};
}
.hc-black .notebookEditor .notebook-cell.active {
box-shadow: 0;
}
.notebookEditor .notebook-cell.active:hover {
border-color: ${activeBorder};
}
.notebookEditor .notebook-cell:hover:not(.active) {
box-shadow: ${lightBoxShadow};
}
.vs-dark .notebookEditor .notebook-cell:hover:not(.active) {
box-shadow: ${darkBoxShadow};
}
.hc-black .notebookEditor .notebook-cell:hover:not(.active) {
box-shadow: 0;
}
`);
const inactiveBorder = theme.getColor(SIDE_BAR_BACKGROUND);
const sidebarColor = theme.getColor(SIDE_BAR_SECTION_HEADER_BACKGROUND);
const notebookLineHighlight = theme.getColor(EDITOR_GROUP_HEADER_TABS_BACKGROUND);
// Code editor style overrides - only applied if user chooses this as preferred option
if (overrideEditorThemeSetting) {
let lineHighlight = theme.getColor(editorLineHighlight);
if (!lineHighlight || lineHighlight.isTransparent()) {
// Use notebook color override
lineHighlight = notebookLineHighlight;
if (lineHighlight) {
collector.addRule(`code-component .monaco-editor .view-overlays .current-line { background-color: ${lineHighlight}; border: 0px; }`);
}
} // else do nothing as current theme's line highlight will work
if (theme.defines(editorLineHighlightBorder) && theme.type !== 'hc') {
// We need to clear out the border because we do not want to show it for notebooks
// Override values only for the children of code-component so regular editors aren't affected
collector.addRule(`code-component .monaco-editor .view-overlays .current-line { border: 0px; }`);
}
// Override code editor background if color is defined
let codeBackground = inactiveBorder; // theme.getColor(EDITOR_GROUP_HEADER_TABS_BACKGROUND);
if (codeBackground) {
// Main background
collector.addRule(`.notebook-cell:not(.active) code-component { background-color: ${codeBackground}; }`);
collector.addRule(`
.notebook-cell:not(.active) code-component .monaco-editor,
.notebook-cell:not(.active) code-component .monaco-editor-background,
.notebook-cell:not(.active) code-component .monaco-editor .inputarea.ime-input
{
background-color: ${codeBackground};
}`);
// Margin background will be the same (may override some styles)
collector.addRule(`.notebook-cell:not(.active) code-component .monaco-editor .margin { background-color: ${codeBackground}; }`);
addBorderToInactiveCodeCells = false;
}
}
// Inactive border
if (inactiveBorder) {
// Standard notebook cell behavior
collector.addRule(`
.notebookEditor .notebook-cell {
border-color: transparent;
border-width: 1px;
}
.notebookEditor .notebook-cell.active {
border-width: 1px;
}
.notebookEditor .notebook-cell:hover {
border-color: ${inactiveBorder};
border-width: 1px;
}
`);
// Ensure there's always a line between editor and output
collector.addRule(`
.notebookEditor .notebook-cell.active code-component {
border-color: ${inactiveBorder};
border-width: 0px 0px 1px 0px;
border-style: solid;
border-radius: 0;
}
`);
if (addBorderToInactiveCodeCells) {
// Sets a border for the editor component if we don't have a custom line color for editor instead
collector.addRule(`
.notebookEditor .notebook-cell code-component {
border-color: ${inactiveBorder};
border-width: 1px;
border-style: solid;
border-radius: 3px 3px 3px 3px;
}
.notebookEditor .notebook-cell:hover code-component {
border-width: 0px 0px 1px 0px;
border-radius: 0px;
}
`);
}
}
// Sidebar and cell outline toolbar color set only when active
collector.addRule(`
.notebook-cell.active code-component .toolbar {
background-color: ${sidebarColor};
}
`);
// Styling with Outline color (e.g. high contrast theme)
const outline = theme.getColor(activeContrastBorder);
const hcOutline = theme.getColor(contrastBorder);
if (outline) {
collector.addRule(`
.hc-black .notebookEditor .notebook-cell:not(.active) code-component {
border-color: ${hcOutline};
border-width: 0px 0px 1px 0px;
}
.hc-black .notebookEditor .notebook-cell.active code-component {
border-color: ${outline};
border-width: 0px 0px 1px 0px;
}
.hc-black .notebookEditor .notebook-cell:not(.active) {
outline-color: ${hcOutline};
outline-width: 1px;
outline-style: solid;
}
.notebookEditor .notebook-cell.active {
outline-color: ${outline};
outline-width: 1px;
outline-style: solid;
}
`);
}
// Styling for all links in notebooks
const linkForeground = theme.getColor(textLinkForeground);
if (linkForeground) {
collector.addRule(`
.notebookEditor .scrollable a {
color: ${linkForeground};
}
`);
}
// Styling for tables in notebooks
const borderColor = theme.getColor(SIDE_BAR_BACKGROUND);
if (borderColor) {
collector.addRule(`
.notebookEditor text-cell-component tbody tr:nth-child(odd) {
background: ${borderColor};
}
`);
}
// Styling for markdown cells & links in notebooks.
// This matches the values used by default in all web views
if (linkForeground) {
collector.addRule(`
.notebookEditor a:link {
color: ${linkForeground};
}
`);
}
let activeForeground = theme.getColor(textLinkActiveForeground);
if (activeForeground) {
collector.addRule(`
.notebookEditor a:hover {
color: ${activeForeground};
}
`);
}
let preformatForeground = theme.getColor(textPreformatForeground);
if (preformatForeground) {
collector.addRule(`
.notebook-preview code {
color: ${preformatForeground};
}
`);
}
let blockQuoteBackground = theme.getColor(textBlockQuoteBackground);
let blockQuoteBorder = theme.getColor(textBlockQuoteBorder);
if (preformatForeground) {
collector.addRule(`
.notebookEditor blockquote {
background: ${blockQuoteBackground};
border-color: ${blockQuoteBorder};
}
`);
}
// Results grid options. Putting these here since query editor only adds them on query editor load.
// We may want to remove from query editor as it can just live here and be loaded once, instead of once
// per editor group which is inefficient
let rawOptions = BareResultsGridInfo.createFromRawSettings(configurationService.getValue('resultsGrid'), getZoomLevel());
let cssRuleText = '';
if (types.isNumber(rawOptions.cellPadding)) {
cssRuleText = rawOptions.cellPadding + 'px';
} else {
cssRuleText = rawOptions.cellPadding.join('px ') + 'px;';
}
collector.addRule(`.grid-panel .monaco-table .slick-cell {
padding: ${cssRuleText}
}
.grid-panel .monaco-table, .message-tree {
${getBareResultsGridInfoStyles(rawOptions)}
}`);
});
}

View File

@@ -0,0 +1,138 @@
/*-----------------------------------------------------------------------------
| Copyright (c) Jupyter Development Team.
| Distributed under the terms of the Modified BSD License.
|----------------------------------------------------------------------------*/
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
import { Table } from 'sql/base/browser/ui/table/table';
import { textFormatter } from 'sql/base/browser/ui/table/formatters';
import { RowNumberColumn } from 'sql/base/browser/ui/table/plugins/rowNumberColumn.plugin';
import { escape } from 'sql/base/common/strings';
import { IDataResource } from 'sql/workbench/services/notebook/sql/sqlSessionManager';
import { attachTableStyler } from 'sql/platform/theme/common/styler';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { MouseWheelSupport } from 'sql/base/browser/ui/table/plugins/mousewheelTableScroll.plugin';
import { AutoColumnSize } from 'sql/base/browser/ui/table/plugins/autoSizeColumns.plugin';
import { AdditionalKeyBindings } from 'sql/base/browser/ui/table/plugins/additionalKeyBindings.plugin';
import { RESULTS_GRID_DEFAULTS } from 'sql/workbench/parts/query/common/resultsGridContribution';
/**
* Render DataResource as a grid into a host node.
*
* @params options - The options for rendering.
*
* @returns A promise which resolves when rendering is complete.
*/
export function renderDataResource(
options: renderDataResource.IRenderOptions
): Promise<void> {
// Unpack the options.
let { host, source } = options;
let sourceObject: IDataResource = JSON.parse(source);
// Before doing anything, avoid re-rendering the table multiple
// times (as can be the case when going untrusted -> trusted)
while (host.firstChild) {
host.removeChild(host.firstChild);
}
// Now create the table container
let tableContainer = document.createElement('div');
tableContainer.className = 'notebook-cellTable';
const BOTTOM_PADDING_AND_SCROLLBAR = 14;
let tableResultsData = new TableDataView();
let columns: string[] = sourceObject.schema.fields.map(val => val.name);
// Table object requires passed in columns to be of datatype Slick.Column
let columnsTransformed = transformColumns(columns);
// In order to show row numbers, we need to put the row number column
// ahead of all of the other columns, and register the plugin below
let rowNumberColumn = new RowNumberColumn({ numberOfRows: source.length });
columnsTransformed.unshift(rowNumberColumn.getColumnDefinition());
let transformedData = transformData(sourceObject.data, columnsTransformed);
tableResultsData.push(transformedData);
let detailTable = new Table(tableContainer, {
dataProvider: tableResultsData, columns: columnsTransformed
}, {
rowHeight: RESULTS_GRID_DEFAULTS.rowHeight,
forceFitColumns: false,
defaultColumnWidth: 120
});
detailTable.registerPlugin(rowNumberColumn);
detailTable.registerPlugin(new MouseWheelSupport());
detailTable.registerPlugin(new AutoColumnSize({ autoSizeOnRender: true }));
detailTable.registerPlugin(new AdditionalKeyBindings());
let numRows = detailTable.grid.getDataLength();
// Need to include column headers and scrollbar, so that's why 1 needs to be added
let rowsHeight = (numRows + 1) * RESULTS_GRID_DEFAULTS.rowHeight + BOTTOM_PADDING_AND_SCROLLBAR + numRows;
// if no rows are in the grid, set height to 100% of the container's height
if (numRows === 0) {
tableContainer.style.height = '100%';
} else {
// Set the height dynamically if the grid's height is < 500px high; otherwise, set height to 500px
tableContainer.style.height = rowsHeight >= 500 ? '500px' : rowsHeight.toString() + 'px';
}
attachTableStyler(detailTable, options.themeService);
host.appendChild(tableContainer);
detailTable.resizeCanvas();
// Return the rendered promise.
return Promise.resolve(undefined);
}
// SlickGrid requires columns and data to be in a very specific format; this code was adapted from tableInsight.component.ts
export function transformData(rows: any[], columns: Slick.Column<any>[]): { [key: string]: string }[] {
return rows.map(row => {
let dataWithSchema = {};
Object.keys(row).forEach((val, index) => {
let displayValue = String(Object.values(row)[index]);
// Since the columns[0] represents the row number, start at 1
dataWithSchema[columns[index + 1].field] = {
displayValue: displayValue,
ariaLabel: escape(displayValue),
isNull: false
};
});
return dataWithSchema;
});
}
export function transformColumns(columns: string[]): Slick.Column<any>[] {
return columns.map((col, index) => {
return <Slick.Column<any>>{
name: col,
id: col,
field: index.toString(),
formatter: textFormatter
};
});
}
/**
* The namespace for the `renderDataResource` function statics.
*/
export namespace renderDataResource {
/**
* The options for the `renderDataResource` function.
*/
export interface IRenderOptions {
/**
* The host node for the rendered LaTeX.
*/
host: HTMLElement;
/**
* The DataResource source to render.
*/
source: string;
/**
* Theme service used to react to theme change events
*/
themeService?: IThemeService;
}
}