mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-16 10:58:30 -05:00
initial PR for table designer feature (#17200)
* wip * wire up e2e * hook up styler and add as dataprotocal feature * designer child component rendering * table component updates * styler and selectbox column editor * fix editor size and dupe component creation issue * fix checkbox column and add more testing data * properties pane * only rerender when needed * properties pane update * update commands * cleanup for PR * revert unwanted changes * Adding a few tests for Add SQL binding (#17079) * initial changes * add a couple more tests * LEGO: check in for main to temporary branch. (#17089) * LEGO: check in for main to temporary branch. (#17091) Co-authored-by: kburtram <karlb@microsoft.com> * Adds autorest-based SQL Project generation to SQL Database Projects extension (#17078) * Initial changes * checkpoint * Constructing project with post deployment script * Correcting to intentionally read from cached list of projects * Adding activation event, fixing fresh workspace bug * Convert netcoreTool and autorestHelper to share a helper class for streamed command * Include npm package version to force update * test checkpoint * Unit tests * Added contextual quickpicks for autorest dialogs * Adding projectController test * Added projectController test, some refactoring for testability * Merge branch 'main' into benjin/autorest * Fixing 'which' import * PR feedback * Fixing tests * Adding additional information for when project provider tests fail * Hopefully fixing failing tests (unable to repro locally) * Adding Generate Project item to workspace menu * PR feedback * LEGO: check in for main to temporary branch. (#17097) * added sql database projects strings (#17100) * Set kernelAlias in startSession when isValidConnection is truthy (#17102) * PR follow-up comments (#17113) * Change recompare message after changing options to modal (#17103) * Change recompare message to modal * change options to yes and no * Remove commented code block in git extension (#17116) * Remove commented code block in git extension * Add SQL CARBON EDIT tag * [Loc] Small change to generatingProjectFailed (#17118) * Add Null Shortcut and added NULL text for default NULL value. (#17085) * added test key event * added null function to tryHandleKeyEvent * added null formatting * added working null insert. * added editDataGridPanel string null support * Bump nth-check from 2.0.0 to 2.0.1 in /build (#17115) Bumps [nth-check](https://github.com/fb55/nth-check) from 2.0.0 to 2.0.1. - [Release notes](https://github.com/fb55/nth-check/releases) - [Commits](https://github.com/fb55/nth-check/compare/v2.0.0...v2.0.1) --- updated-dependencies: - dependency-name: nth-check dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Add excludeFlags to extenson marketplace query (#17121) * Add excludeFlags to extenson marketplace query * Remove dead code * Remove extraneous blank line * Address code review feedback * Adding Derived Columns to ADS Flatfile Import (#16795) * Adding derived column boilerplate * brandan preliminary frontend changes * empty commit * added new param * updating contracts, dialogue changes * utils changes, saving timeout attempt * pushing for aasim * Cleaning up code and fixing the issue in theory * changing button, did not solve independent scroll * Fixing the scroll bar issue * updating flat file service * adding override keyword to overrriden method * improving UI * pushing changes associated with resolved comments * localizing strings, editing comments * all comments resolved * Fixing a test * updating import package Updating azure MFA bug * Clearing navigation validator Fixing broken table name change * fixed prose test * removing unused code from tests * Fixed PR comments * Fixing some PR comments * WIP * Fixing transformation code and create derived column dialog styling * removing unused code * Adding comment for console log * fixed table styling * Adding some aria labels * Fixed some code cleanup issues * update import service Co-authored-by: Aasim Khan <aasimkhan30@gmail.com> Co-authored-by: bnhoule <t-bhoule@microsoft.com> * Change keybindings for copying query with Results (#17127) Co-authored-by: Monica Gupta <mogupt@microsoft.com> * sql proj - publish to docker improvements (#17124) * Add AAD token expiration handling for query runner (#17117) * Add AAD token refresh for notebook * move token refresh to query management and remove previous refresh calls * Add guids to RunAll and RunCell events (#17123) Add guids to RunAll and RunCell events * add error banner for failed migration cutover and cancel migration (#17106) * [Loc] update to sql migration, database projects and import extension strings (#17130) * Apply optional storage class settings in sql mi create command (#17129) * Make storage classes optional * Fix notebook to use storage class options Co-authored-by: Charmaine Chan <chachan@microsoft.com> * Add support for adding new setting in local.settings.json in add SQL binding quickpick (#17093) * be able to add new setting in local.settings.json * cleanup * addressing comments * remove todo comment * addressing comments * update some strings to uris * bump version of sqltoolsservice (#17133) * mark schema compare tests as unstable (#17140) * [Loc] Update for arc and sql-database-projects (#17148) * ML extension vbump (#17143) * Configure docker image and web smoke tests for ADSWeb. (#17136) * Adjusts timeout period * Revert "Adjusts timeout period" This reverts commit 0f372eae2a4611554093b6c09f1ff6c451132e19. * Adds firefox as browser option * Corrects yaml smoke test script * Resets args array to original values * Corrects build path * Resolves ignoring browser option error * continue even after writing to stderr * Adjusts smoke test (browser) script * More adjustments to smoke test script * Corrects server path * Uses build variable directly in build path * Specifies browser type since cannot be ignored error * Adds browser option * Updates web build image and corrects smoke test exe command * Removes commented out task * Updates dockerfile to support web smoketests * Removes failOnStderr flag * Use curl instead of wget in Dockerfile * Fixed a bug with cancling publish (#17160) * Save And Close Functionality (#17000) * save and close * wip * working save and close * cleanup * pr changes * pr changes * fix capitalization * fix build * pr fix * Added dynamic options for SQL MIAA Deployment Wizard and updated checkbox field (#17119) * Dynamic enablement * Added new package.json field for dynamic options and corresponding functions and classes. * Enabled dynamic options non-generalized and changed formatting of checkbox to have label on the left. * Added setOptions under InputComponentInfo for generalization, comments under checkbox component, and changed Replicas to High Availability to reflect parity in portal. * fix unit test Co-authored-by: Candice Ye <canye@microsoft.com> Co-authored-by: Alan Ren <alanren@microsoft.com> * LEGO: check in for main to temporary branch. (#17168) * [Loc] added new arc strings and fix for sql-database-projects lcl file for Japanese (#17171) * [Loc] added new arc strings and fix for sql-database-projects xlf * removed newline * Port of Vscode fix for colors too close (#17146) * default light colors list.focusHighlightForeground too close to list.activeSelectionBackground. Fixes #127597 * remove activeSelectionBackground from theme-carbon as it conflicts with vscode. * remove dark carbon background Co-authored-by: Martin Aeschlimann <martinae@microsoft.com> * Markdown Horizontal Scrollbar Fix (#17083) * dynamically change horizontal scrollbar * working horizontal scrollbar * created new event to handle both scrollbar and mouse wheel * only show scrollbar when needed * LEGO: check in for main to temporary branch. (#17181) * Bump axios to 0.21.4 (#17161) * Kusto version bump to 0.5.6 (#17114) * Bumped Kusto toolsservice version to 125 and bumped version to 0.5.6 * Changed netcoreapp3.1 to net5.0 in Kusto config.json * AzureMonitor bump ToolService version and extension version. (#17174) * Bump concat-with-sourcemaps from 1.0.4 to 1.1.0 (#17158) Bumps [concat-with-sourcemaps](https://github.com/floridoo/concat-with-sourcemaps) from 1.0.4 to 1.1.0. - [Release notes](https://github.com/floridoo/concat-with-sourcemaps/releases) - [Commits](https://github.com/floridoo/concat-with-sourcemaps/commits) --- updated-dependencies: - dependency-name: concat-with-sourcemaps dependency-type: indirect ... Signed-off-by: dependabot[bot] <support@github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> * Update service downloader to 0.2.3 (#17186) * Notebook Views grid fixes (#17170) * update data workspace restart ADS to open workspace message (#17188) * update message * update string * Add back "Remove Project" (#17178) * remove project working with full paths * use relative paths * const * addressing comments * Bump github-auth axios to 0.21.4 (#17189) * LEGO: check in for main to temporary branch. (#17192) * LEGO: check in for main to temporary branch. (#17190) Co-authored-by: kburtram <karlb@microsoft.com> * [Loc] Add a small change to dataworkspace (#17194) * added bump to sqltoolsservice version (#17195) * Check if file is dirty before adding sql binding (#17175) * check if file is dirty before adding sql binding * Addressing comments * Add vertical scroll bar to Preview in Split View (#17164) * reset max height * add editor height * set md editor height * Split up NotebookProvider into separate providers for handling file serialization and cell execution. (#17176) * fix floating promises * pr comments * reuse component definition * comments * fix error Co-authored-by: Kim Santiago <31145923+kisantia@users.noreply.github.com> Co-authored-by: csigs <csigs@users.noreply.github.com> Co-authored-by: kburtram <karlb@microsoft.com> Co-authored-by: Benjin Dubishar <benjin.dubishar@gmail.com> Co-authored-by: Alex Ma <alma1@microsoft.com> Co-authored-by: Justin M <63619224+JustinMDotNet@users.noreply.github.com> Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: bnhoule <52506119+bnhoule@users.noreply.github.com> Co-authored-by: Aasim Khan <aasimkhan30@gmail.com> Co-authored-by: bnhoule <t-bhoule@microsoft.com> Co-authored-by: Monica Gupta <scorpio90m@gmail.com> Co-authored-by: Monica Gupta <mogupt@microsoft.com> Co-authored-by: Leila Lali <llali@microsoft.com> Co-authored-by: Hai Cao <hacao@microsoft.com> Co-authored-by: Daniel Grajeda <dagrajed@microsoft.com> Co-authored-by: brian-harris <61598682+brian-harris@users.noreply.github.com> Co-authored-by: Charmaine Chan <69230572+charmainewkchan@users.noreply.github.com> Co-authored-by: Charmaine Chan <chachan@microsoft.com> Co-authored-by: Lewis Sanchez <87730006+lewis-sanchez@users.noreply.github.com> Co-authored-by: Christopher Suh <chsuh@microsoft.com> Co-authored-by: Candice Ye <candiceye@berkeley.edu> Co-authored-by: Candice Ye <canye@microsoft.com> Co-authored-by: Martin Aeschlimann <martinae@microsoft.com> Co-authored-by: Vasu Bhog <vabhog@microsoft.com> Co-authored-by: Charles Gagnon <chgagnon@microsoft.com> Co-authored-by: Barbara Valdez <34872381+barbaravaldez@users.noreply.github.com> Co-authored-by: Cory Rivera <corivera@microsoft.com>
This commit is contained in:
@@ -126,6 +126,16 @@
|
|||||||
"command": "mssql.showLogFile",
|
"command": "mssql.showLogFile",
|
||||||
"category": "MSSQL",
|
"category": "MSSQL",
|
||||||
"title": "%title.showLogFile%"
|
"title": "%title.showLogFile%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mssql.newTable",
|
||||||
|
"category": "MSSQL",
|
||||||
|
"title": "%title.newTable%"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mssql.designTable",
|
||||||
|
"category": "MSSQL",
|
||||||
|
"title": "%title.designTable%"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"outputChannels": [
|
"outputChannels": [
|
||||||
@@ -427,6 +437,14 @@
|
|||||||
{
|
{
|
||||||
"command": "mssqlCluster.task.openClusterDashboard",
|
"command": "mssqlCluster.task.openClusterDashboard",
|
||||||
"when": "false"
|
"when": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mssql.newTable",
|
||||||
|
"when": "false"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"command": "mssql.designTable",
|
||||||
|
"when": "false"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"objectExplorer/item/context": [
|
"objectExplorer/item/context": [
|
||||||
|
|||||||
@@ -183,5 +183,8 @@
|
|||||||
"databasesListProperties.status": "Status",
|
"databasesListProperties.status": "Status",
|
||||||
"databasesListProperties.size": "Size (MB)",
|
"databasesListProperties.size": "Size (MB)",
|
||||||
"databasesListProperties.lastBackup": "Last backup",
|
"databasesListProperties.lastBackup": "Last backup",
|
||||||
"objectsListProperties.name": "Name"
|
"objectsListProperties.name": "Name",
|
||||||
|
|
||||||
|
"title.newTable": "New Table",
|
||||||
|
"title.designTable": "Design"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1024,3 +1024,21 @@ export namespace GetSqlMigrationAssessmentItemsRequest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------- <Sql Migration> -----------------------------
|
// ------------------------------- <Sql Migration> -----------------------------
|
||||||
|
|
||||||
|
// ------------------------------- < Table Designer > ------------------------------------
|
||||||
|
|
||||||
|
export interface TableDesignerEditRequestParams {
|
||||||
|
tableInfo: azdata.designers.TableInfo,
|
||||||
|
tableChangeInfo: azdata.designers.DesignerEdit,
|
||||||
|
data: azdata.designers.DesignerData
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace GetTableDesignerInfoRequest {
|
||||||
|
export const type = new RequestType<azdata.designers.TableInfo, azdata.designers.TableDesignerInfo, void, void>('tabledesigner/gettabledesignerinfo');
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace ProcessTableDesignerEditRequest {
|
||||||
|
export const type = new RequestType<TableDesignerEditRequestParams, azdata.designers.DesignerEditResult, void, void>('tabledesigner/processedit');
|
||||||
|
}
|
||||||
|
|
||||||
|
// ------------------------------- < Table Designer > ------------------------------------
|
||||||
|
|||||||
@@ -1082,3 +1082,61 @@ export class ProfilerFeature extends SqlOpsFeature<undefined> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Table Designer Feature
|
||||||
|
* TODO: Move this feature to data protocol client repo once stablized
|
||||||
|
*/
|
||||||
|
export class TableDesignerFeature extends SqlOpsFeature<undefined> {
|
||||||
|
private static readonly messagesTypes: RPCMessageType[] = [
|
||||||
|
contracts.ProcessTableDesignerEditRequest.type,
|
||||||
|
];
|
||||||
|
constructor(client: SqlOpsDataClient) {
|
||||||
|
super(client, TableDesignerFeature.messagesTypes);
|
||||||
|
}
|
||||||
|
|
||||||
|
public fillClientCapabilities(capabilities: ClientCapabilities): void {
|
||||||
|
}
|
||||||
|
|
||||||
|
public initialize(capabilities: ServerCapabilities): void {
|
||||||
|
this.register(this.messages, {
|
||||||
|
id: UUID.generateUuid(),
|
||||||
|
registerOptions: undefined
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
protected registerProvider(options: undefined): Disposable {
|
||||||
|
const client = this._client;
|
||||||
|
|
||||||
|
const getTableDesignerInfo = async (tableInfo: azdata.designers.TableInfo): Promise<azdata.designers.TableDesignerInfo> => {
|
||||||
|
try {
|
||||||
|
return client.sendRequest(contracts.GetTableDesignerInfoRequest.type, tableInfo);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
client.logFailedRequest(contracts.GetTableDesignerInfoRequest.type, e);
|
||||||
|
return Promise.reject(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const processTableEdit = async (tableInfo: azdata.designers.TableInfo, data: azdata.designers.DesignerData, tableChangeInfo: azdata.designers.DesignerEdit): Promise<azdata.designers.DesignerEditResult> => {
|
||||||
|
let params: contracts.TableDesignerEditRequestParams = {
|
||||||
|
tableInfo: tableInfo,
|
||||||
|
data: data,
|
||||||
|
tableChangeInfo: tableChangeInfo
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
return client.sendRequest(contracts.ProcessTableDesignerEditRequest.type, params);
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
client.logFailedRequest(contracts.ProcessTableDesignerEditRequest.type, e);
|
||||||
|
return Promise.reject(e);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return azdata.dataprotocol.registerTableDesignerProvider({
|
||||||
|
providerId: client.providerId,
|
||||||
|
getTableDesignerInfo,
|
||||||
|
processTableEdit
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ import { promises as fs } from 'fs';
|
|||||||
import { IconPathHelper } from './iconHelper';
|
import { IconPathHelper } from './iconHelper';
|
||||||
import * as nls from 'vscode-nls';
|
import * as nls from 'vscode-nls';
|
||||||
import { INotebookConvertService } from './notebookConvert/notebookConvertService';
|
import { INotebookConvertService } from './notebookConvert/notebookConvertService';
|
||||||
|
import { registerTableDesignerCommands } from './tableDesigner/tableDesigner';
|
||||||
|
|
||||||
const localize = nls.loadMessageBundle();
|
const localize = nls.loadMessageBundle();
|
||||||
const msgSampleCodeDataFrame = localize('msgSampleCodeDataFrame', "This sample code loads the file into a data frame and shows the first 10 results.");
|
const msgSampleCodeDataFrame = localize('msgSampleCodeDataFrame', "This sample code loads the file into a data frame and shows the first 10 results.");
|
||||||
@@ -104,6 +105,8 @@ export async function activate(context: vscode.ExtensionContext): Promise<IExten
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
registerTableDesignerCommands(appContext);
|
||||||
|
|
||||||
return createMssqlApi(appContext, server);
|
return createMssqlApi(appContext, server);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
30
extensions/mssql/src/tableDesigner/tableDesigner.ts
Normal file
30
extensions/mssql/src/tableDesigner/tableDesigner.ts
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { AppContext } from '../appContext';
|
||||||
|
import * as azdata from 'azdata';
|
||||||
|
import * as vscode from 'vscode';
|
||||||
|
import { sqlProviderName } from '../constants';
|
||||||
|
|
||||||
|
export function registerTableDesignerCommands(appContext: AppContext) {
|
||||||
|
appContext.extensionContext.subscriptions.push(vscode.commands.registerCommand('mssql.newTable', async (context: azdata.ObjectExplorerContext) => {
|
||||||
|
await azdata.designers.openTableDesigner(sqlProviderName, {
|
||||||
|
server: context.connectionProfile.serverName,
|
||||||
|
database: context.connectionProfile.databaseName,
|
||||||
|
isNewTable: true
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
appContext.extensionContext.subscriptions.push(vscode.commands.registerCommand('mssql.designTable', async (context: azdata.ObjectExplorerContext) => {
|
||||||
|
await azdata.designers.openTableDesigner(sqlProviderName, {
|
||||||
|
server: context.connectionProfile.serverName,
|
||||||
|
database: context.connectionProfile.databaseName,
|
||||||
|
isNewTable: false,
|
||||||
|
name: context.nodeInfo.metadata.name,
|
||||||
|
schema: context.nodeInfo.metadata.schema
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
}
|
||||||
267
src/sql/azdata.proposed.d.ts
vendored
267
src/sql/azdata.proposed.d.ts
vendored
@@ -988,4 +988,271 @@ declare module 'azdata' {
|
|||||||
*/
|
*/
|
||||||
unsupportedVersionMessage?: string;
|
unsupportedVersionMessage?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum DataProviderType {
|
||||||
|
TableDesignerProvider = 'TableDesignerProvider'
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace dataprotocol {
|
||||||
|
export function registerTableDesignerProvider(provider: designers.TableDesignerProvider): vscode.Disposable;
|
||||||
|
}
|
||||||
|
|
||||||
|
export namespace designers {
|
||||||
|
/**
|
||||||
|
* Open a table designer window.
|
||||||
|
* @param providerId The table designer provider Id.
|
||||||
|
* @param tableInfo The table information. The object will be passed back to the table designer provider as the unique identifier for the table.
|
||||||
|
*/
|
||||||
|
export function openTableDesigner(providerId: string, tableInfo: TableInfo): Thenable<void>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Definition for the table designer provider.
|
||||||
|
*/
|
||||||
|
export interface TableDesignerProvider extends DataProvider {
|
||||||
|
/**
|
||||||
|
* Gets the table designer information for the specified table.
|
||||||
|
* @param table the table information.
|
||||||
|
*/
|
||||||
|
getTableDesignerInfo(table: TableInfo): Thenable<TableDesignerInfo>;
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param table the table information
|
||||||
|
* @param data the object contains the state of the table designer
|
||||||
|
* @param tableChangeInfo the information about the change user made through the UI.
|
||||||
|
*/
|
||||||
|
processTableEdit(table: TableInfo, data: DesignerData, tableChangeInfo: DesignerEdit): Thenable<DesignerEditResult>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The information of the table.
|
||||||
|
*/
|
||||||
|
export interface TableInfo {
|
||||||
|
/**
|
||||||
|
* The server name.
|
||||||
|
*/
|
||||||
|
server: string;
|
||||||
|
/**
|
||||||
|
* The database name
|
||||||
|
*/
|
||||||
|
database: string;
|
||||||
|
/**
|
||||||
|
* The schema name, only required for existing table.
|
||||||
|
*/
|
||||||
|
schema?: string;
|
||||||
|
/**
|
||||||
|
* The table name, only required for existing table.
|
||||||
|
*/
|
||||||
|
name?: string;
|
||||||
|
/**
|
||||||
|
* A boolean value indicates whether a new table is being designed.
|
||||||
|
*/
|
||||||
|
isNewTable: boolean;
|
||||||
|
/**
|
||||||
|
* Extension can store additional information that the provider needs to uniquely identify a table.
|
||||||
|
*/
|
||||||
|
[key: string]: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The information to populate the table designer UI.
|
||||||
|
*/
|
||||||
|
export interface TableDesignerInfo {
|
||||||
|
/**
|
||||||
|
* The view definition.
|
||||||
|
*/
|
||||||
|
view: TableDesignerView;
|
||||||
|
/**
|
||||||
|
* The data model.
|
||||||
|
*/
|
||||||
|
data: DesignerData;
|
||||||
|
/**
|
||||||
|
* The supported column types
|
||||||
|
*/
|
||||||
|
columnTypes: string[];
|
||||||
|
/**
|
||||||
|
* The list of schemas in the database.
|
||||||
|
*/
|
||||||
|
schemas: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Name of the common table properties.
|
||||||
|
* Extensions can use the names to access the designer data.
|
||||||
|
*/
|
||||||
|
export enum TableProperty {
|
||||||
|
Columns = 'columns',
|
||||||
|
Description = 'description',
|
||||||
|
Name = 'name',
|
||||||
|
Schema = 'schema',
|
||||||
|
Script = 'script'
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Name of the common table column properties.
|
||||||
|
* Extensions can use the names to access the designer data.
|
||||||
|
*/
|
||||||
|
export enum TableColumnProperty {
|
||||||
|
AllowNulls = 'allowNulls',
|
||||||
|
DefaultValue = 'defaultValue',
|
||||||
|
Length = 'length',
|
||||||
|
Name = 'name',
|
||||||
|
Type = 'type'
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The table designer view definition
|
||||||
|
*/
|
||||||
|
export interface TableDesignerView {
|
||||||
|
/**
|
||||||
|
* Additional table properties. Common table properties are handled by Azure Data Studio. see {@link TableProperty}
|
||||||
|
*/
|
||||||
|
additionalTableProperties?: DesignerDataPropertyInfo[];
|
||||||
|
/**
|
||||||
|
* Additional table column properties.Common table properties are handled by Azure Data Studio. see {@link TableColumnProperty}
|
||||||
|
*/
|
||||||
|
addtionalTableColumnProperties?: DesignerDataPropertyInfo[];
|
||||||
|
/**
|
||||||
|
* Additional tabs.
|
||||||
|
*/
|
||||||
|
addtionalTabs?: DesignerTab[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data model object of the designer.
|
||||||
|
*/
|
||||||
|
export interface DesignerData {
|
||||||
|
[key: string]: InputBoxProperties | CheckBoxProperties | DropDownProperties | DesignerTableProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition of a designer tab
|
||||||
|
*/
|
||||||
|
export interface DesignerTab {
|
||||||
|
/**
|
||||||
|
* The title of the tab
|
||||||
|
*/
|
||||||
|
title: string;
|
||||||
|
/**
|
||||||
|
* the components to be displayed in this tab.
|
||||||
|
*/
|
||||||
|
components: DesignerDataPropertyInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The definition of the property in the designer.
|
||||||
|
*/
|
||||||
|
export interface DesignerDataPropertyInfo {
|
||||||
|
/**
|
||||||
|
* The property name
|
||||||
|
*/
|
||||||
|
propertyName: string;
|
||||||
|
/**
|
||||||
|
* The component type
|
||||||
|
*/
|
||||||
|
componentType: DesignerComponentTypeName;
|
||||||
|
/**
|
||||||
|
* The group name, properties with the same group name will be displayed under the same group on the UI.
|
||||||
|
*/
|
||||||
|
group?: string;
|
||||||
|
/**
|
||||||
|
* The properties of the component.
|
||||||
|
*/
|
||||||
|
componentProperties: InputBoxProperties | CheckBoxProperties | DropDownProperties | DesignerTableProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The child component types supported by designer.
|
||||||
|
*/
|
||||||
|
export type DesignerComponentTypeName = 'input' | 'checkbox' | 'dropdown' | 'table';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The properties for the table component in the designer.
|
||||||
|
*/
|
||||||
|
export interface DesignerTableProperties extends ComponentProperties {
|
||||||
|
/**
|
||||||
|
* the name of the properties to be displayed, properties not in this list will be accessible in properties pane.
|
||||||
|
*/
|
||||||
|
columns?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The display name of the object type
|
||||||
|
*/
|
||||||
|
objectTypeDisplayName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the properties of the table data item
|
||||||
|
*/
|
||||||
|
itemProperties?: DesignerDataPropertyInfo[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data to be displayed.
|
||||||
|
*/
|
||||||
|
data?: DesignerTableComponentDataItem[];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The data item of the designer's table component.
|
||||||
|
*/
|
||||||
|
export interface DesignerTableComponentDataItem {
|
||||||
|
[key: string]: InputBoxProperties | CheckBoxProperties | DropDownProperties | DesignerTableProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Type of the edit originated from the designer UI.
|
||||||
|
*/
|
||||||
|
export enum DesignerEditType {
|
||||||
|
/**
|
||||||
|
* Add a row to a table
|
||||||
|
*/
|
||||||
|
Add = 0,
|
||||||
|
/**
|
||||||
|
* Remove a row from a table
|
||||||
|
*/
|
||||||
|
Remove = 1,
|
||||||
|
/**
|
||||||
|
* Update a property
|
||||||
|
*/
|
||||||
|
Update = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Information of the edit originated from the designer UI.
|
||||||
|
*/
|
||||||
|
export interface DesignerEdit {
|
||||||
|
/**
|
||||||
|
* The edit type
|
||||||
|
*/
|
||||||
|
type: DesignerEditType;
|
||||||
|
/**
|
||||||
|
* the property that was edited
|
||||||
|
*/
|
||||||
|
property: DesignerEditIdentifier;
|
||||||
|
/**
|
||||||
|
* the new value
|
||||||
|
*/
|
||||||
|
value: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The identifier of a property. The value is string typed if the property belongs to the root object, otherwise the type of the value is an object.
|
||||||
|
*/
|
||||||
|
export type DesignerEditIdentifier = string | { parentProperty: string, index: number, property: string };
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The result returned by the table designer provider after handling an edit request.
|
||||||
|
*/
|
||||||
|
export interface DesignerEditResult {
|
||||||
|
/**
|
||||||
|
* The data model object.
|
||||||
|
*/
|
||||||
|
data: DesignerData;
|
||||||
|
/**
|
||||||
|
* Whether the current state is valid.
|
||||||
|
*/
|
||||||
|
isValid: boolean;
|
||||||
|
/**
|
||||||
|
* Error messages of current state, and the property the caused the error.
|
||||||
|
*/
|
||||||
|
errors?: { message: string, property?: DesignerEditIdentifier }[];
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
480
src/sql/base/browser/ui/designer/designer.ts
Normal file
480
src/sql/base/browser/ui/designer/designer.ts
Normal file
@@ -0,0 +1,480 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { DesignerComponentInput, DesignerEditType, DesignerTab, DesignerEdit, DesignerEditIdentifier, DesignerData, DesignerDataPropertyInfo, DesignerTableComponentRowData, DesignerTableProperties, InputBoxProperties, DropDownProperties, CheckBoxProperties, DesignerComponentTypeName } from 'sql/base/browser/ui/designer/interfaces';
|
||||||
|
import { IPanelTab, ITabbedPanelStyles, TabbedPanel } from 'sql/base/browser/ui/panel/panel';
|
||||||
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
|
import { Event } from 'vs/base/common/event';
|
||||||
|
import { Orientation, Sizing, SplitView } from 'vs/base/browser/ui/splitview/splitview';
|
||||||
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
import { IInputBoxStyles, InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
|
||||||
|
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
|
||||||
|
import 'vs/css!./media/designer';
|
||||||
|
import { ITableStyles } from 'sql/base/browser/ui/table/interfaces';
|
||||||
|
import { IThemable } from 'vs/base/common/styler';
|
||||||
|
import { Checkbox, ICheckboxStyles } from 'sql/base/browser/ui/checkbox/checkbox';
|
||||||
|
import { Table } from 'sql/base/browser/ui/table/table';
|
||||||
|
import { ISelectBoxStyles, SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
|
||||||
|
import { TableDataView } from 'sql/base/browser/ui/table/tableDataView';
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
|
import { TableCellEditorFactory } from 'sql/base/browser/ui/table/tableCellEditorFactory';
|
||||||
|
import { CheckBoxColumn } from 'sql/base/browser/ui/table/plugins/checkboxColumn.plugin';
|
||||||
|
import { DesignerTabPanelView } from 'sql/base/browser/ui/designer/designerTabPanelView';
|
||||||
|
import { DesignerPropertiesPane, PropertiesPaneObjectContext } from 'sql/base/browser/ui/designer/designerPropertiesPane';
|
||||||
|
|
||||||
|
export interface IDesignerStyle {
|
||||||
|
tabbedPanelStyles?: ITabbedPanelStyles;
|
||||||
|
inputBoxStyles?: IInputBoxStyles;
|
||||||
|
tableStyles?: ITableStyles;
|
||||||
|
selectBoxStyles?: ISelectBoxStyles;
|
||||||
|
checkboxStyles?: ICheckboxStyles;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DesignerUIComponent = InputBox | Checkbox | Table<Slick.SlickData> | SelectBox;
|
||||||
|
|
||||||
|
export type CreateComponentFunc = (container: HTMLElement, component: DesignerDataPropertyInfo, editIdentifier: DesignerEditIdentifier) => DesignerUIComponent;
|
||||||
|
export type SetComponentValueFunc = (definition: DesignerDataPropertyInfo, component: DesignerUIComponent, data: DesignerData) => void;
|
||||||
|
|
||||||
|
export class Designer extends Disposable implements IThemable {
|
||||||
|
|
||||||
|
private _horizontalSplitViewContainer: HTMLElement;
|
||||||
|
private _verticalSplitViewContainer: HTMLElement;
|
||||||
|
private _tabbedPanelContainer: HTMLElement;
|
||||||
|
private _editorContainer: HTMLElement;
|
||||||
|
private _horizontalSplitView: SplitView;
|
||||||
|
private _verticalSplitView: SplitView;
|
||||||
|
private _tabbedPanel: TabbedPanel;
|
||||||
|
private _contentContainer: HTMLElement;
|
||||||
|
private _topContentContainer: HTMLElement;
|
||||||
|
private _propertiesPaneContainer: HTMLElement;
|
||||||
|
private _styles: IDesignerStyle = {};
|
||||||
|
private _supressEditProcessing: boolean = false;
|
||||||
|
private _componentMap = new Map<string, { defintion: DesignerDataPropertyInfo, component: DesignerUIComponent }>();
|
||||||
|
private _input: DesignerComponentInput;
|
||||||
|
private _tableCellEditorFactory: TableCellEditorFactory;
|
||||||
|
private _propertiesPane: DesignerPropertiesPane;
|
||||||
|
|
||||||
|
constructor(private readonly _container: HTMLElement,
|
||||||
|
private readonly _contextViewProvider: IContextViewProvider) {
|
||||||
|
super();
|
||||||
|
this._tableCellEditorFactory = new TableCellEditorFactory(
|
||||||
|
{
|
||||||
|
valueGetter: (item, column): string => {
|
||||||
|
return item[column.field].value;
|
||||||
|
},
|
||||||
|
valueSetter: async (context: string, row: number, item: DesignerTableComponentRowData, column: Slick.Column<Slick.SlickData>, value: string): Promise<void> => {
|
||||||
|
await this.handleEdit({
|
||||||
|
type: DesignerEditType.Update,
|
||||||
|
property: {
|
||||||
|
parentProperty: context,
|
||||||
|
index: row,
|
||||||
|
property: column.field
|
||||||
|
},
|
||||||
|
value: value
|
||||||
|
});
|
||||||
|
},
|
||||||
|
optionsGetter: (item, column): string[] => {
|
||||||
|
return item[column.field].options;
|
||||||
|
},
|
||||||
|
editorStyler: (component) => {
|
||||||
|
this.styleComponent(component);
|
||||||
|
}
|
||||||
|
}, this._contextViewProvider
|
||||||
|
);
|
||||||
|
this._verticalSplitViewContainer = DOM.$('.designer-component');
|
||||||
|
this._horizontalSplitViewContainer = DOM.$('.container');
|
||||||
|
this._contentContainer = DOM.$('.content-container');
|
||||||
|
this._topContentContainer = DOM.$('.top-content-container.components-grid');
|
||||||
|
this._tabbedPanelContainer = DOM.$('.tabbed-panel-container');
|
||||||
|
this._editorContainer = DOM.$('.editor-container');
|
||||||
|
this._propertiesPaneContainer = DOM.$('.properties-container');
|
||||||
|
this._verticalSplitView = new SplitView(this._verticalSplitViewContainer, { orientation: Orientation.VERTICAL });
|
||||||
|
this._horizontalSplitView = new SplitView(this._horizontalSplitViewContainer, { orientation: Orientation.HORIZONTAL });
|
||||||
|
this._tabbedPanel = new TabbedPanel(this._tabbedPanelContainer);
|
||||||
|
this._container.appendChild(this._verticalSplitViewContainer);
|
||||||
|
this._contentContainer.appendChild(this._topContentContainer);
|
||||||
|
this._contentContainer.appendChild(this._tabbedPanelContainer);
|
||||||
|
this._verticalSplitView.addView({
|
||||||
|
element: this._horizontalSplitViewContainer,
|
||||||
|
layout: size => {
|
||||||
|
this.layoutTabbedPanel();
|
||||||
|
},
|
||||||
|
minimumSize: 200,
|
||||||
|
maximumSize: Number.POSITIVE_INFINITY,
|
||||||
|
onDidChange: Event.None
|
||||||
|
}, Sizing.Distribute);
|
||||||
|
|
||||||
|
this._verticalSplitView.addView({
|
||||||
|
element: this._editorContainer,
|
||||||
|
layout: size => { },
|
||||||
|
minimumSize: 100,
|
||||||
|
maximumSize: Number.POSITIVE_INFINITY,
|
||||||
|
onDidChange: Event.None
|
||||||
|
}, Sizing.Distribute);
|
||||||
|
|
||||||
|
this._horizontalSplitView.addView({
|
||||||
|
element: this._contentContainer,
|
||||||
|
layout: size => {
|
||||||
|
this.layoutTabbedPanel();
|
||||||
|
},
|
||||||
|
minimumSize: 200,
|
||||||
|
maximumSize: Number.POSITIVE_INFINITY,
|
||||||
|
onDidChange: Event.None
|
||||||
|
}, Sizing.Distribute);
|
||||||
|
|
||||||
|
this._horizontalSplitView.addView({
|
||||||
|
element: this._propertiesPaneContainer,
|
||||||
|
layout: size => { },
|
||||||
|
minimumSize: 200,
|
||||||
|
maximumSize: Number.POSITIVE_INFINITY,
|
||||||
|
onDidChange: Event.None
|
||||||
|
}, Sizing.Distribute);
|
||||||
|
|
||||||
|
this._propertiesPane = new DesignerPropertiesPane(this._propertiesPaneContainer, (container, component, identifier) => {
|
||||||
|
return this.createComponent(container, component, identifier, false, false);
|
||||||
|
}, (definition, component, data) => {
|
||||||
|
this.setComponentValue(definition, component, data);
|
||||||
|
}, (component) => {
|
||||||
|
this.styleComponent(component);
|
||||||
|
});
|
||||||
|
const editor = DOM.$('div');
|
||||||
|
editor.innerText = 'script pane placeholder';
|
||||||
|
this._editorContainer.appendChild(editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private styleComponent(component: TabbedPanel | InputBox | Checkbox | Table<Slick.SlickData> | SelectBox): void {
|
||||||
|
if (component instanceof InputBox) {
|
||||||
|
component.style(this._styles.inputBoxStyles);
|
||||||
|
} else if (component instanceof Checkbox) {
|
||||||
|
component.style(this._styles.checkboxStyles);
|
||||||
|
} else if (component instanceof TabbedPanel) {
|
||||||
|
component.style(this._styles.tabbedPanelStyles);
|
||||||
|
} else if (component instanceof Table) {
|
||||||
|
component.style(this._styles.tableStyles);
|
||||||
|
} else {
|
||||||
|
component.style(this._styles.selectBoxStyles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public style(styles: IDesignerStyle): void {
|
||||||
|
this._styles = styles;
|
||||||
|
this._componentMap.forEach((value, key, map) => {
|
||||||
|
if (value.component.style) {
|
||||||
|
this.styleComponent(value.component);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
this._propertiesPane.style();
|
||||||
|
this._verticalSplitView.style({
|
||||||
|
separatorBorder: styles.selectBoxStyles.selectBorder
|
||||||
|
});
|
||||||
|
|
||||||
|
this._horizontalSplitView.style({
|
||||||
|
separatorBorder: styles.selectBoxStyles.selectBorder
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public layout(dimension: DOM.Dimension) {
|
||||||
|
this._verticalSplitView.layout(dimension.height);
|
||||||
|
this._horizontalSplitView.layout(dimension.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public async setInput(input: DesignerComponentInput): Promise<void> {
|
||||||
|
this._input = input;
|
||||||
|
await this.initializeDesignerView();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async initializeDesignerView(): Promise<void> {
|
||||||
|
this._propertiesPane.clear();
|
||||||
|
DOM.clearNode(this._topContentContainer);
|
||||||
|
const view = await this._input.getView();
|
||||||
|
if (view.components) {
|
||||||
|
view.components.forEach(component => {
|
||||||
|
this.createComponent(this._topContentContainer, component, component.propertyName, true, true);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this._tabbedPanel.clearTabs();
|
||||||
|
view.tabs.forEach(tab => {
|
||||||
|
this._tabbedPanel.pushTab(this.createTabView(tab));
|
||||||
|
});
|
||||||
|
this.layoutTabbedPanel();
|
||||||
|
await this.updateComponentValues();
|
||||||
|
}
|
||||||
|
|
||||||
|
private layoutTabbedPanel() {
|
||||||
|
this._tabbedPanel.layout(new DOM.Dimension(this._tabbedPanelContainer.clientWidth, this._tabbedPanelContainer.clientHeight));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async updateComponentValues(): Promise<void> {
|
||||||
|
const data = await this._input.getData();
|
||||||
|
// data[ScriptPropertyName] -- todo- set the script editor
|
||||||
|
this._componentMap.forEach((value) => {
|
||||||
|
this.setComponentValue(value.defintion, value.component, data);
|
||||||
|
});
|
||||||
|
|
||||||
|
let type: string;
|
||||||
|
let components: DesignerDataPropertyInfo[];
|
||||||
|
let inputData: DesignerData;
|
||||||
|
let context: PropertiesPaneObjectContext;
|
||||||
|
const currentContext = this._propertiesPane.context;
|
||||||
|
if (currentContext === 'root' || currentContext === undefined) {
|
||||||
|
context = 'root';
|
||||||
|
components = [];
|
||||||
|
this._componentMap.forEach(value => {
|
||||||
|
components.push(value.defintion);
|
||||||
|
});
|
||||||
|
type = this._input.objectTypeDisplayName;
|
||||||
|
inputData = data;
|
||||||
|
} else {
|
||||||
|
context = currentContext;
|
||||||
|
const tableData = data[currentContext.parentProperty] as DesignerTableProperties;
|
||||||
|
const tableProperties = this._componentMap.get(currentContext.parentProperty).defintion.componentProperties as DesignerTableProperties;
|
||||||
|
inputData = tableData.data[currentContext.index] as DesignerData;
|
||||||
|
components = tableProperties.itemProperties;
|
||||||
|
type = tableProperties.objectTypeDisplayName;
|
||||||
|
}
|
||||||
|
this._propertiesPane.show({
|
||||||
|
context: context,
|
||||||
|
type: type,
|
||||||
|
components: components,
|
||||||
|
data: inputData
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async handleEdit(edit: DesignerEdit): Promise<void> {
|
||||||
|
if (this._supressEditProcessing) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
await this.applyEdit(edit);
|
||||||
|
const result = await this._input.processEdit(edit);
|
||||||
|
if (result.isValid) {
|
||||||
|
this._supressEditProcessing = true;
|
||||||
|
await this.updateComponentValues();
|
||||||
|
this._supressEditProcessing = false;
|
||||||
|
} else {
|
||||||
|
//TODO: add error notification
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async applyEdit(edit: DesignerEdit): Promise<void> {
|
||||||
|
const data = await this._input.getData();
|
||||||
|
switch (edit.type) {
|
||||||
|
case DesignerEditType.Update:
|
||||||
|
if (typeof edit.property === 'string') {
|
||||||
|
// if the type of the property is string then the property is a top level property
|
||||||
|
const componentData = data[edit.property];
|
||||||
|
const componentType = this._componentMap.get(edit.property).defintion.componentType;
|
||||||
|
this.setComponentData(componentType, componentData, edit.value);
|
||||||
|
} else {
|
||||||
|
const columnPropertyName = edit.property.property;
|
||||||
|
const tableInfo = this._componentMap.get(edit.property.parentProperty).defintion.componentProperties as DesignerTableProperties;
|
||||||
|
const tableProperties = data[edit.property.parentProperty] as DesignerTableProperties;
|
||||||
|
const componentData = tableProperties.data[edit.property.index][columnPropertyName];
|
||||||
|
const itemProperty = tableInfo.itemProperties.find(property => property.propertyName === columnPropertyName);
|
||||||
|
if (itemProperty) {
|
||||||
|
this.setComponentData(itemProperty.componentType, componentData, edit.value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private setComponentData(componentType: DesignerComponentTypeName, componentData: any, value: any): void {
|
||||||
|
switch (componentType) {
|
||||||
|
case 'checkbox':
|
||||||
|
(<CheckBoxProperties>componentData).checked = value;
|
||||||
|
break;
|
||||||
|
case 'dropdown':
|
||||||
|
(<DropDownProperties>componentData).value = value;
|
||||||
|
break;
|
||||||
|
case 'input':
|
||||||
|
(<InputBoxProperties>componentData).value = value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private createTabView(tab: DesignerTab): IPanelTab {
|
||||||
|
const view = new DesignerTabPanelView(tab, (container, component, identifier) => {
|
||||||
|
return this.createComponent(container, component, identifier, true, false);
|
||||||
|
});
|
||||||
|
return {
|
||||||
|
identifier: tab.title,
|
||||||
|
title: tab.title,
|
||||||
|
view: view
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private setComponentValue(definition: DesignerDataPropertyInfo, component: DesignerUIComponent, data: DesignerData): void {
|
||||||
|
this._supressEditProcessing = true;
|
||||||
|
switch (definition.componentType) {
|
||||||
|
case 'input':
|
||||||
|
const input = component as InputBox;
|
||||||
|
const inputData = data[definition.propertyName] as InputBoxProperties;
|
||||||
|
input.setEnabled(inputData.enabled ?? true);
|
||||||
|
input.value = inputData.value?.toString() ?? '';
|
||||||
|
break;
|
||||||
|
case 'table':
|
||||||
|
const table = component as Table<Slick.SlickData>;
|
||||||
|
const tableDataView = table.getData() as TableDataView<Slick.SlickData>;
|
||||||
|
tableDataView.clear();
|
||||||
|
tableDataView.push((data[definition.propertyName] as DesignerTableProperties).data);
|
||||||
|
table.rerenderGrid();
|
||||||
|
break;
|
||||||
|
case 'checkbox':
|
||||||
|
const checkbox = component as Checkbox;
|
||||||
|
const checkboxData = data[definition.propertyName] as CheckBoxProperties;
|
||||||
|
if (checkboxData.enabled === false) {
|
||||||
|
checkbox.disable();
|
||||||
|
} else {
|
||||||
|
checkbox.enable();
|
||||||
|
}
|
||||||
|
checkbox.checked = checkboxData.checked;
|
||||||
|
break;
|
||||||
|
case 'dropdown':
|
||||||
|
const dropdown = component as SelectBox;
|
||||||
|
const defaultDropdownData = definition.componentProperties as DropDownProperties;
|
||||||
|
const dropdownData = data[definition.propertyName] as DropDownProperties;
|
||||||
|
if (dropdownData.enabled === false) {
|
||||||
|
dropdown.disable();
|
||||||
|
} else {
|
||||||
|
dropdown.enable();
|
||||||
|
}
|
||||||
|
const options = (dropdownData.values || defaultDropdownData.values || []) as string[];
|
||||||
|
dropdown.setOptions(options);
|
||||||
|
const idx = options?.indexOf(dropdownData.value as string);
|
||||||
|
if (idx > -1) {
|
||||||
|
dropdown.select(idx);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
this._supressEditProcessing = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private createComponent(container: HTMLElement, componentDefinition: DesignerDataPropertyInfo, editIdentifier: DesignerEditIdentifier, addToComponentMap: boolean, setWidth: boolean): DesignerUIComponent {
|
||||||
|
const componentContainerClass = componentDefinition.componentType === 'table' ? '.full-row' : '';
|
||||||
|
const labelContainer = container.appendChild(DOM.$(componentContainerClass));
|
||||||
|
labelContainer.appendChild(DOM.$('span.component-label')).innerText = (componentDefinition.componentType === 'checkbox' || componentDefinition.componentProperties?.title === undefined) ? '' : componentDefinition.componentProperties.title;
|
||||||
|
const componentDiv = container.appendChild(DOM.$(componentContainerClass));
|
||||||
|
let component: DesignerUIComponent;
|
||||||
|
switch (componentDefinition.componentType) {
|
||||||
|
case 'input':
|
||||||
|
const inputProperties = componentDefinition.componentProperties as InputBoxProperties;
|
||||||
|
const input = new InputBox(componentDiv, this._contextViewProvider, {
|
||||||
|
ariaLabel: inputProperties.title,
|
||||||
|
type: inputProperties.inputType,
|
||||||
|
});
|
||||||
|
input.onDidChange(async (newValue) => {
|
||||||
|
await this.handleEdit({ type: DesignerEditType.Update, property: editIdentifier, value: newValue });
|
||||||
|
});
|
||||||
|
if (setWidth && inputProperties.width !== undefined) {
|
||||||
|
input.width = inputProperties.width as number;
|
||||||
|
}
|
||||||
|
component = input;
|
||||||
|
break;
|
||||||
|
case 'dropdown':
|
||||||
|
const dropdownProperties = componentDefinition.componentProperties as DropDownProperties;
|
||||||
|
const dropdown = new SelectBox(dropdownProperties.values as string[], undefined, this._contextViewProvider, undefined);
|
||||||
|
dropdown.render(componentDiv);
|
||||||
|
dropdown.selectElem.style.height = '25px';
|
||||||
|
dropdown.onDidSelect(async (e) => {
|
||||||
|
await this.handleEdit({ type: DesignerEditType.Update, property: editIdentifier, value: e.selected });
|
||||||
|
});
|
||||||
|
component = dropdown;
|
||||||
|
break;
|
||||||
|
case 'checkbox':
|
||||||
|
const checkboxProperties = componentDefinition.componentProperties as CheckBoxProperties;
|
||||||
|
const checkbox = new Checkbox(componentDiv, {
|
||||||
|
label: checkboxProperties.title
|
||||||
|
});
|
||||||
|
checkbox.onChange(async (newValue) => {
|
||||||
|
await this.handleEdit({ type: DesignerEditType.Update, property: editIdentifier, value: newValue });
|
||||||
|
});
|
||||||
|
component = checkbox;
|
||||||
|
break;
|
||||||
|
case 'table':
|
||||||
|
const tableProperties = componentDefinition.componentProperties as DesignerTableProperties;
|
||||||
|
const table = new Table(componentDiv, {
|
||||||
|
dataProvider: new TableDataView()
|
||||||
|
}, {
|
||||||
|
editable: true,
|
||||||
|
autoEdit: true,
|
||||||
|
dataItemColumnValueExtractor: (data: any, column: Slick.Column<Slick.SlickData>): string => {
|
||||||
|
return data[column.field].value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
table.columns = tableProperties.columns.map(propName => {
|
||||||
|
const propertyDefinition = tableProperties.itemProperties.find(item => item.propertyName === propName);
|
||||||
|
switch (propertyDefinition.componentType) {
|
||||||
|
case 'checkbox':
|
||||||
|
const checkboxColumn = new CheckBoxColumn({
|
||||||
|
field: propertyDefinition.propertyName,
|
||||||
|
name: propertyDefinition.componentProperties.title,
|
||||||
|
width: propertyDefinition.componentProperties.width as number
|
||||||
|
});
|
||||||
|
table.registerPlugin(checkboxColumn);
|
||||||
|
checkboxColumn.onChange(async (e) => {
|
||||||
|
await this.handleEdit({
|
||||||
|
type: DesignerEditType.Update,
|
||||||
|
property: {
|
||||||
|
parentProperty: componentDefinition.propertyName,
|
||||||
|
index: e.row,
|
||||||
|
property: propertyDefinition.propertyName
|
||||||
|
},
|
||||||
|
value: e.value
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return checkboxColumn.definition;
|
||||||
|
case 'dropdown':
|
||||||
|
const dropdownProperties = propertyDefinition.componentProperties as DropDownProperties;
|
||||||
|
return {
|
||||||
|
name: dropdownProperties.title,
|
||||||
|
field: propertyDefinition.propertyName,
|
||||||
|
editor: this._tableCellEditorFactory.getSelectBoxEditorClass(componentDefinition.propertyName, dropdownProperties.values as string[]),
|
||||||
|
width: dropdownProperties.width as number
|
||||||
|
};
|
||||||
|
default:
|
||||||
|
const inputProperties = propertyDefinition.componentProperties as InputBoxProperties;
|
||||||
|
return {
|
||||||
|
name: inputProperties.title,
|
||||||
|
field: propertyDefinition.propertyName,
|
||||||
|
editor: this._tableCellEditorFactory.getTextEditorClass(componentDefinition.propertyName, inputProperties.inputType),
|
||||||
|
width: inputProperties.width as number
|
||||||
|
};
|
||||||
|
}
|
||||||
|
});
|
||||||
|
table.layout(new DOM.Dimension(container.clientWidth, container.clientHeight));
|
||||||
|
table.grid.onBeforeEditCell.subscribe((e, data): boolean => {
|
||||||
|
return data.item[data.column.field].enabled !== false;
|
||||||
|
});
|
||||||
|
table.grid.onActiveCellChanged.subscribe((e, data) => {
|
||||||
|
this._propertiesPane.show({
|
||||||
|
context: {
|
||||||
|
parentProperty: componentDefinition.propertyName,
|
||||||
|
index: data.row
|
||||||
|
},
|
||||||
|
type: tableProperties.objectTypeDisplayName,
|
||||||
|
components: tableProperties.itemProperties,
|
||||||
|
data: table.getData().getItem(data.row)
|
||||||
|
});
|
||||||
|
});
|
||||||
|
component = table;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error(localize('tableDesigner.unknownComponentType', "The component type: {0} is not supported", componentDefinition.componentType));
|
||||||
|
}
|
||||||
|
if (addToComponentMap) {
|
||||||
|
this._componentMap.set(componentDefinition.propertyName, {
|
||||||
|
defintion: componentDefinition,
|
||||||
|
component: component
|
||||||
|
});
|
||||||
|
}
|
||||||
|
this.styleComponent(component);
|
||||||
|
return component;
|
||||||
|
}
|
||||||
|
}
|
||||||
85
src/sql/base/browser/ui/designer/designerPropertiesPane.ts
Normal file
85
src/sql/base/browser/ui/designer/designerPropertiesPane.ts
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { CreateComponentFunc, DesignerUIComponent, SetComponentValueFunc } from 'sql/base/browser/ui/designer/designer';
|
||||||
|
import { DesignerData, DesignerEditIdentifier, DesignerDataPropertyInfo, InputBoxProperties, NameProperty } from 'sql/base/browser/ui/designer/interfaces';
|
||||||
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
|
import { equals } from 'vs/base/common/objects';
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
|
|
||||||
|
export type PropertiesPaneObjectContext = 'root' | {
|
||||||
|
parentProperty: string;
|
||||||
|
index: number;
|
||||||
|
};
|
||||||
|
|
||||||
|
export interface ObjectInfo {
|
||||||
|
context: PropertiesPaneObjectContext;
|
||||||
|
type: string;
|
||||||
|
components: DesignerDataPropertyInfo[];
|
||||||
|
data: DesignerData;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class DesignerPropertiesPane {
|
||||||
|
private _titleElement: HTMLElement;
|
||||||
|
private _contentElement: HTMLElement;
|
||||||
|
private _currentContext?: PropertiesPaneObjectContext;
|
||||||
|
private _componentMap = new Map<string, { defintion: DesignerDataPropertyInfo, component: DesignerUIComponent }>();
|
||||||
|
|
||||||
|
constructor(container: HTMLElement, private _createComponent: CreateComponentFunc, private _setComponentValue: SetComponentValueFunc, private _styleComponent: (component: DesignerUIComponent) => void) {
|
||||||
|
const titleContainer = container.appendChild(DOM.$('.title-container'));
|
||||||
|
this._titleElement = titleContainer.appendChild(DOM.$('div'));
|
||||||
|
this._contentElement = container.appendChild(DOM.$('.properties-content.components-grid'));
|
||||||
|
this._titleElement.innerText = localize('tableDesigner.propertiesPaneTitle', "Properties");
|
||||||
|
}
|
||||||
|
|
||||||
|
public get context(): PropertiesPaneObjectContext | undefined {
|
||||||
|
return this._currentContext;
|
||||||
|
}
|
||||||
|
|
||||||
|
public clear(): void {
|
||||||
|
this._componentMap.forEach((value) => {
|
||||||
|
value.component.dispose();
|
||||||
|
});
|
||||||
|
this._componentMap.clear();
|
||||||
|
DOM.clearNode(this._contentElement);
|
||||||
|
this._currentContext = undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
public style() {
|
||||||
|
this._componentMap.forEach((value) => {
|
||||||
|
this._styleComponent(value.component);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public show(item: ObjectInfo): void {
|
||||||
|
if (!equals(item.context, this._currentContext)) {
|
||||||
|
this.clear();
|
||||||
|
this._currentContext = item.context;
|
||||||
|
item.components.forEach((value) => {
|
||||||
|
// todo: handle table type in properties pane
|
||||||
|
if (value.componentType !== 'table') {
|
||||||
|
const editIdentifier: DesignerEditIdentifier = this._currentContext === 'root' ? value.propertyName : {
|
||||||
|
parentProperty: this._currentContext.parentProperty,
|
||||||
|
index: this._currentContext.index,
|
||||||
|
property: value.propertyName
|
||||||
|
};
|
||||||
|
const component = this._createComponent(this._contentElement, value, editIdentifier);
|
||||||
|
this._componentMap.set(value.propertyName, {
|
||||||
|
component: component,
|
||||||
|
defintion: value
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const name = (<InputBoxProperties>item.data[NameProperty])?.value ?? '';
|
||||||
|
this._titleElement.innerText = localize({
|
||||||
|
key: 'tableDesigner.propertiesPaneTitleWithContext',
|
||||||
|
comment: ['{0} is the place holder for object type', '{1} is the place holder for object name']
|
||||||
|
}, "Properties - {0} {1}", item.type, name);
|
||||||
|
this._componentMap.forEach((value) => {
|
||||||
|
this._setComponentValue(value.defintion, value.component, item.data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
36
src/sql/base/browser/ui/designer/designerTabPanelView.ts
Normal file
36
src/sql/base/browser/ui/designer/designerTabPanelView.ts
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { DesignerTab } from 'sql/base/browser/ui/designer/interfaces';
|
||||||
|
import { IPanelView } from 'sql/base/browser/ui/panel/panel';
|
||||||
|
import { Table } from 'sql/base/browser/ui/table/table';
|
||||||
|
import { Disposable } from 'vs/base/common/lifecycle';
|
||||||
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
|
import { CreateComponentFunc } from 'sql/base/browser/ui/designer/designer';
|
||||||
|
|
||||||
|
export class DesignerTabPanelView extends Disposable implements IPanelView {
|
||||||
|
private _componentsContainer: HTMLElement;
|
||||||
|
private _tables: Table<Slick.SlickData>[] = [];
|
||||||
|
constructor(private readonly _tab: DesignerTab, private _createComponent: CreateComponentFunc) {
|
||||||
|
super();
|
||||||
|
this._componentsContainer = DOM.$('.components-grid');
|
||||||
|
this._tab.components.forEach(componentDefition => {
|
||||||
|
const component = this._createComponent(this._componentsContainer, componentDefition, componentDefition.propertyName);
|
||||||
|
if (componentDefition.componentType === 'table') {
|
||||||
|
this._tables.push(component as Table<Slick.SlickData>);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
render(container: HTMLElement): void {
|
||||||
|
container.appendChild(this._componentsContainer);
|
||||||
|
}
|
||||||
|
|
||||||
|
layout(dimension: DOM.Dimension): void {
|
||||||
|
this._tables.forEach(table => {
|
||||||
|
table.layout(new DOM.Dimension(dimension.width - 10, dimension.height - 20));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
126
src/sql/base/browser/ui/designer/interfaces.ts
Normal file
126
src/sql/base/browser/ui/designer/interfaces.ts
Normal file
@@ -0,0 +1,126 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
export interface DesignerComponentInput {
|
||||||
|
/**
|
||||||
|
* Gets the object type display name.
|
||||||
|
*/
|
||||||
|
|
||||||
|
readonly objectTypeDisplayName: string;
|
||||||
|
/**
|
||||||
|
* Gets the designer view specification.
|
||||||
|
*/
|
||||||
|
getView(): Promise<DesignerView>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the data.
|
||||||
|
*/
|
||||||
|
getData(): Promise<DesignerData>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the edit made in the designer.
|
||||||
|
* @param edit the information about the edit.
|
||||||
|
*/
|
||||||
|
processEdit(edit: DesignerEdit): Promise<DesignerEditResult>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const NameProperty = 'name';
|
||||||
|
export const ScriptProperty = 'script';
|
||||||
|
|
||||||
|
export interface DesignerView {
|
||||||
|
components?: DesignerDataPropertyInfo[]
|
||||||
|
tabs: DesignerTab[];
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export interface DesignerTab {
|
||||||
|
title: string;
|
||||||
|
components: DesignerDataPropertyInfo[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DesignerData {
|
||||||
|
[key: string]: InputBoxProperties | CheckBoxProperties | DropDownProperties | DesignerTableProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DesignerDataPropertyInfo {
|
||||||
|
propertyName: string;
|
||||||
|
componentType: DesignerComponentTypeName;
|
||||||
|
group?: string;
|
||||||
|
componentProperties?: InputBoxProperties | CheckBoxProperties | DropDownProperties | DesignerTableProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DesignerComponentTypeName = 'input' | 'checkbox' | 'dropdown' | 'table';
|
||||||
|
|
||||||
|
export interface ComponentProperties {
|
||||||
|
title?: string;
|
||||||
|
|
||||||
|
ariaLabel?: string;
|
||||||
|
|
||||||
|
width?: number | string;
|
||||||
|
|
||||||
|
enabled?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CategoryValue {
|
||||||
|
displayName: string;
|
||||||
|
name: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DropDownProperties extends ComponentProperties {
|
||||||
|
value?: string | CategoryValue;
|
||||||
|
values?: string[] | CategoryValue[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CheckBoxProperties extends ComponentProperties {
|
||||||
|
checked?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface InputBoxProperties extends ComponentProperties {
|
||||||
|
value?: string;
|
||||||
|
inputType?: 'text' | 'number';
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DesignerTableProperties extends ComponentProperties {
|
||||||
|
/**
|
||||||
|
* the name of the properties to be displayed, properties not in this list will be accessible in details view.
|
||||||
|
*/
|
||||||
|
columns?: string[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The display name of the object type
|
||||||
|
*/
|
||||||
|
objectTypeDisplayName: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* the properties of the table data item
|
||||||
|
*/
|
||||||
|
itemProperties?: DesignerDataPropertyInfo[];
|
||||||
|
|
||||||
|
data?: DesignerTableComponentRowData[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DesignerTableComponentRowData {
|
||||||
|
[key: string]: InputBoxProperties | CheckBoxProperties | DropDownProperties | DesignerTableProperties;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export enum DesignerEditType {
|
||||||
|
Add = 0,
|
||||||
|
Remove = 1,
|
||||||
|
Update = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DesignerEdit {
|
||||||
|
type: DesignerEditType;
|
||||||
|
property: DesignerEditIdentifier;
|
||||||
|
value: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type DesignerEditIdentifier = string | { parentProperty: string, index: number, property: string };
|
||||||
|
|
||||||
|
export interface DesignerEditResult {
|
||||||
|
isValid: boolean;
|
||||||
|
errors?: { message: string, property?: DesignerEditIdentifier }[];
|
||||||
|
}
|
||||||
77
src/sql/base/browser/ui/designer/media/designer.css
Normal file
77
src/sql/base/browser/ui/designer/media/designer.css
Normal file
@@ -0,0 +1,77 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.designer-component, .designer-component .container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.designer-component .content-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
border-right-width: 1px;
|
||||||
|
border-right-style: solid;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.designer-component .top-content-container {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.designer-component .editor-container {
|
||||||
|
border-top-width: 1px;
|
||||||
|
border-top-style: solid;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.designer-component .tabbed-panel-container {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
.designer-component .properties-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
overflow: hidden;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.designer-component .properties-container .title-container {
|
||||||
|
padding: 5px;
|
||||||
|
flex: 0 0 auto;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.designer-component .properties-container .properties-content {
|
||||||
|
flex: 1 1 auto;
|
||||||
|
overflow-y: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.designer-component .component-label {
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
|
|
||||||
|
.designer-component .components-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: max-content auto; /* label, component*/
|
||||||
|
grid-template-rows: max-content;
|
||||||
|
grid-gap: 5px;
|
||||||
|
padding: 5px;
|
||||||
|
align-content: start;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
.designer-component .components-grid .full-row {
|
||||||
|
grid-area: span 1 / span 2; /* spans 1 row and 2 columns*/
|
||||||
|
}
|
||||||
|
|
||||||
|
.designer-component .monaco-table .slick-cell.editable {
|
||||||
|
padding: 0px;
|
||||||
|
border-width: 0px;
|
||||||
|
}
|
||||||
@@ -61,7 +61,7 @@ export class InputBox extends vsInputBox {
|
|||||||
if (_sqlOptions && _sqlOptions.type === 'textarea') {
|
if (_sqlOptions && _sqlOptions.type === 'textarea') {
|
||||||
this._isTextAreaInput = true;
|
this._isTextAreaInput = true;
|
||||||
}
|
}
|
||||||
this.required = !!this._sqlOptions.required;
|
this.required = !!this._sqlOptions?.required;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override style(styles: IInputBoxStyles): void {
|
public override style(styles: IInputBoxStyles): void {
|
||||||
@@ -171,4 +171,9 @@ export class InputBox extends vsInputBox {
|
|||||||
}
|
}
|
||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override set width(width: number) {
|
||||||
|
super.width = width;
|
||||||
|
this.element.style.width = 'fit-content';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -248,6 +248,12 @@ export class TabbedPanel extends Disposable {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public clearTabs(): void {
|
||||||
|
this._tabMap.forEach((value, key, map) => {
|
||||||
|
this.removeTab(key);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public removeTab(tab: PanelTabIdentifier) {
|
public removeTab(tab: PanelTabIdentifier) {
|
||||||
const actualTab = this._tabMap.get(tab);
|
const actualTab = this._tabMap.get(tab);
|
||||||
if (!actualTab) {
|
if (!actualTab) {
|
||||||
|
|||||||
110
src/sql/base/browser/ui/table/plugins/checkboxColumn.plugin.ts
Normal file
110
src/sql/base/browser/ui/table/plugins/checkboxColumn.plugin.ts
Normal file
@@ -0,0 +1,110 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* 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!./media/checkboxColumn.plugin';
|
||||||
|
import { BaseTableColumnOptions, TableColumn } from 'sql/base/browser/ui/table/plugins/tableColumn';
|
||||||
|
import { escape } from 'sql/base/common/strings';
|
||||||
|
import { Emitter } from 'vs/base/common/event';
|
||||||
|
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||||
|
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||||
|
|
||||||
|
export interface CheckBoxCellValue {
|
||||||
|
enabled?: boolean;
|
||||||
|
checked: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CheckBoxChangedEventArgs<T extends Slick.SlickData> {
|
||||||
|
item: T;
|
||||||
|
row: number;
|
||||||
|
column: number;
|
||||||
|
value: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface CheckBoxColumnOptions extends BaseTableColumnOptions {
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CheckBoxColumn<T extends Slick.SlickData> implements Slick.Plugin<T>, TableColumn<T> {
|
||||||
|
private _handler = new Slick.EventHandler();
|
||||||
|
private _grid!: Slick.Grid<T>;
|
||||||
|
private _onChange = new Emitter<CheckBoxChangedEventArgs<T>>();
|
||||||
|
public onChange = this._onChange.event;
|
||||||
|
|
||||||
|
constructor(private options: CheckBoxColumnOptions) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(grid: Slick.Grid<T>): void {
|
||||||
|
this._grid = grid;
|
||||||
|
this._handler.subscribe(grid.onClick, (e: DOMEvent, args: Slick.OnClickEventArgs<T>) => this.handleClick(args));
|
||||||
|
this._handler.subscribe(grid.onKeyDown, (e: DOMEvent, args: Slick.OnKeyDownEventArgs<T>) => this.handleKeyboardEvent(e as KeyboardEvent, args));
|
||||||
|
this._handler.subscribe(grid.onActiveCellChanged, (e: DOMEvent, args: Slick.OnActiveCellChangedEventArgs<T>) => { this.handleActiveCellChanged(args); });
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy(): void {
|
||||||
|
this._handler.unsubscribeAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
public get definition(): Slick.Column<T> {
|
||||||
|
return {
|
||||||
|
id: this.options.field,
|
||||||
|
formatter: (row: number, cell: number, value: any, columnDef: Slick.Column<T>, dataContext: T): string => {
|
||||||
|
const cellValue = dataContext[columnDef.field] as CheckBoxCellValue;
|
||||||
|
const escapedTitle = escape(columnDef.name ?? '');
|
||||||
|
const disabledAttribute = cellValue.enabled === false ? 'disabled' : '';
|
||||||
|
const checkedAttribute = cellValue.checked ? 'checked' : '';
|
||||||
|
return `<input type="checkbox" tabindex=-1 title="${escapedTitle}" aria-label="${escapedTitle}" ${checkedAttribute} ${disabledAttribute}/>`;
|
||||||
|
},
|
||||||
|
field: this.options.field,
|
||||||
|
name: this.options.name,
|
||||||
|
resizable: this.options.resizable,
|
||||||
|
cssClass: 'slick-plugin-checkbox-column'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private getCheckbox(): HTMLInputElement {
|
||||||
|
const cellElement = this._grid.getActiveCellNode();
|
||||||
|
return cellElement.children[0] as HTMLInputElement;
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleActiveCellChanged(args: Slick.OnActiveCellChangedEventArgs<T>): void {
|
||||||
|
if (this.isCurrentColumn(args.cell)) {
|
||||||
|
this.getCheckbox().focus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleClick(args: Slick.OnClickEventArgs<T>): void {
|
||||||
|
if (this.isCurrentColumn(args.cell)) {
|
||||||
|
setTimeout(() => {
|
||||||
|
this.fireOnChangeEvent();
|
||||||
|
}, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleKeyboardEvent(e: KeyboardEvent, args: Slick.OnKeyDownEventArgs<T>): void {
|
||||||
|
let event = new StandardKeyboardEvent(e);
|
||||||
|
if (event.equals(KeyCode.Space) && this.isCurrentColumn(args.cell)) {
|
||||||
|
this.fireOnChangeEvent();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fireOnChangeEvent(): void {
|
||||||
|
const cell = this._grid.getActiveCell();
|
||||||
|
const checked = this.getCheckbox().checked;
|
||||||
|
const item = this._grid.getDataItem(cell.row);
|
||||||
|
const cellValue = item[this.options.field] as CheckBoxCellValue;
|
||||||
|
if (checked !== cellValue.checked) {
|
||||||
|
this._onChange.fire({
|
||||||
|
row: cell.row,
|
||||||
|
column: cell.cell,
|
||||||
|
value: checked,
|
||||||
|
item: item
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private isCurrentColumn(columnIndex: number): boolean {
|
||||||
|
return this._grid.getColumns()[columnIndex]?.id === this.definition.id;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,13 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
.slick-plugin-checkbox-column {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.slick-plugin-checkbox-column > input{
|
||||||
|
margin: 0px;
|
||||||
|
vertical-align: middle;
|
||||||
|
}
|
||||||
172
src/sql/base/browser/ui/table/tableCellEditorFactory.ts
Normal file
172
src/sql/base/browser/ui/table/tableCellEditorFactory.ts
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
import { InputBox } from 'sql/base/browser/ui/inputBox/inputBox';
|
||||||
|
import { SelectBox } from 'sql/base/browser/ui/selectBox/selectBox';
|
||||||
|
import { getCodeForKeyCode } from 'vs/base/browser/keyboardEvent';
|
||||||
|
import { IContextViewProvider } from 'vs/base/browser/ui/contextview/contextview';
|
||||||
|
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||||
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
|
|
||||||
|
export interface ITableCellEditorOptions {
|
||||||
|
valueGetter?: (item: Slick.SlickData, column: Slick.Column<Slick.SlickData>) => string,
|
||||||
|
valueSetter?: (context: any, row: number, item: Slick.SlickData, column: Slick.Column<Slick.SlickData>, value: string) => Promise<void>,
|
||||||
|
optionsGetter?: (item: Slick.SlickData, column: Slick.Column<Slick.SlickData>) => string[],
|
||||||
|
editorStyler: (component: InputBox | SelectBox) => void
|
||||||
|
}
|
||||||
|
|
||||||
|
export class TableCellEditorFactory {
|
||||||
|
private _options: ITableCellEditorOptions;
|
||||||
|
|
||||||
|
constructor(options: ITableCellEditorOptions, private _contextViewProvider: IContextViewProvider) {
|
||||||
|
this._options = {
|
||||||
|
valueGetter: options.valueGetter ?? function (item, column) {
|
||||||
|
return item[column.field];
|
||||||
|
},
|
||||||
|
valueSetter: options.valueSetter ?? async function (context, row, item, column, value): Promise<void> {
|
||||||
|
item[column.field] = value;
|
||||||
|
},
|
||||||
|
optionsGetter: options.optionsGetter ?? function (item, column) {
|
||||||
|
return [];
|
||||||
|
},
|
||||||
|
editorStyler: options.editorStyler
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public getTextEditorClass(context: any, inputType: 'text' | 'number' = 'text'): any {
|
||||||
|
const self = this;
|
||||||
|
class TextEditor {
|
||||||
|
private _originalValue: string;
|
||||||
|
private _input: InputBox;
|
||||||
|
private _keyCaptureList: number[];
|
||||||
|
|
||||||
|
constructor(private _args: Slick.Editors.EditorOptions<Slick.SlickData>) {
|
||||||
|
this.init();
|
||||||
|
const keycodesToCapture = [KeyCode.Home, KeyCode.End, KeyCode.UpArrow, KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow];
|
||||||
|
this._keyCaptureList = keycodesToCapture.map(keycode => getCodeForKeyCode(keycode));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The text editor should handle these key press events to avoid event bubble up
|
||||||
|
*/
|
||||||
|
public get keyCaptureList(): number[] {
|
||||||
|
return this._keyCaptureList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(): void {
|
||||||
|
this._input = new InputBox(this._args.container, self._contextViewProvider, {
|
||||||
|
type: inputType
|
||||||
|
});
|
||||||
|
self._options.editorStyler(this._input);
|
||||||
|
this._input.element.style.height = '100%';
|
||||||
|
this._input.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy(): void {
|
||||||
|
this._input.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public focus(): void {
|
||||||
|
this._input.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public loadValue(item: Slick.SlickData): void {
|
||||||
|
this._originalValue = self._options.valueGetter(item, this._args.column) ?? '';
|
||||||
|
this._input.value = this._originalValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async applyValue(item: Slick.SlickData, state: string): Promise<void> {
|
||||||
|
const activeCell = this._args.grid.getActiveCell();
|
||||||
|
await self._options.valueSetter(context, activeCell.row, item, this._args.column, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public isValueChanged(): boolean {
|
||||||
|
return this._input.value !== this._originalValue.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public serializeValue(): any {
|
||||||
|
return this._input.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public validate(): Slick.ValidateResults {
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
msg: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TextEditor;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getSelectBoxEditorClass(context: any, defaultOptions: string[]): any {
|
||||||
|
const self = this;
|
||||||
|
class TextEditor {
|
||||||
|
private _originalValue: string;
|
||||||
|
private _selectBox: SelectBox;
|
||||||
|
private _keyCaptureList: number[];
|
||||||
|
|
||||||
|
constructor(private _args: Slick.Editors.EditorOptions<Slick.SlickData>) {
|
||||||
|
this.init();
|
||||||
|
const keycodesToCapture = [KeyCode.Home, KeyCode.End, KeyCode.UpArrow, KeyCode.DownArrow, KeyCode.LeftArrow, KeyCode.RightArrow];
|
||||||
|
this._keyCaptureList = keycodesToCapture.map(keycode => getCodeForKeyCode(keycode));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The text editor should handle these key press events to avoid event bubble up
|
||||||
|
*/
|
||||||
|
public get keyCaptureList(): number[] {
|
||||||
|
return this._keyCaptureList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public init(): void {
|
||||||
|
const container = DOM.$('');
|
||||||
|
this._args.container.appendChild(container);
|
||||||
|
this._selectBox = new SelectBox([], undefined, self._contextViewProvider);
|
||||||
|
container.style.height = '100%';
|
||||||
|
container.style.width = '100%';
|
||||||
|
this._selectBox.render(container);
|
||||||
|
this._selectBox.selectElem.style.height = '100%';
|
||||||
|
self._options.editorStyler(this._selectBox);
|
||||||
|
this._selectBox.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public destroy(): void {
|
||||||
|
this._selectBox.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
|
public focus(): void {
|
||||||
|
this._selectBox.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
public loadValue(item: Slick.SlickData): void {
|
||||||
|
this._originalValue = self._options.valueGetter(item, this._args.column) ?? '';
|
||||||
|
const options = self._options.optionsGetter(item, this._args.column) ?? defaultOptions;
|
||||||
|
const idx = options?.indexOf(this._originalValue);
|
||||||
|
if (idx > -1) {
|
||||||
|
this._selectBox.setOptions(options);
|
||||||
|
this._selectBox.select(idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async applyValue(item: Slick.SlickData, state: string): Promise<void> {
|
||||||
|
const activeCell = this._args.grid.getActiveCell();
|
||||||
|
await self._options.valueSetter(context, activeCell.row, item, this._args.column, state);
|
||||||
|
}
|
||||||
|
|
||||||
|
public isValueChanged(): boolean {
|
||||||
|
return this._selectBox.value !== this._originalValue.toString();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public serializeValue(): any {
|
||||||
|
return this._selectBox.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public validate(): Slick.ValidateResults {
|
||||||
|
return {
|
||||||
|
valid: true,
|
||||||
|
msg: undefined
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TextEditor;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,11 +9,11 @@ import { RawContextKey, IContextKey, ContextKeyExpr, IContextKeyService } from '
|
|||||||
import { DisposableStore, IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
import { DisposableStore, IDisposable, combinedDisposable, toDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||||
import { createStyleSheet } from 'vs/base/browser/dom';
|
import { createStyleSheet } from 'vs/base/browser/dom';
|
||||||
import { attachHighPerfTableStyler as attachTableStyler, defaultHighPerfTableStyles } from 'sql/platform/theme/common/styler';
|
import { attachHighPerfTableStyler as attachTableStyler, defaultHighPerfTableStyles, IHighPerfTableStyleOverrides } from 'sql/platform/theme/common/styler';
|
||||||
import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys';
|
import { InputFocusedContextKey } from 'vs/platform/contextkey/common/contextkeys';
|
||||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||||
import { ITableDataSource, ITableColumn } from 'sql/base/browser/ui/table/highPerf/table';
|
import { ITableDataSource, ITableColumn } from 'sql/base/browser/ui/table/highPerf/table';
|
||||||
import { IColorMapping, computeStyles } from 'vs/platform/theme/common/styler';
|
import { computeStyles } from 'vs/platform/theme/common/styler';
|
||||||
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
|
||||||
|
|
||||||
export const ITableService = createDecorator<ITableService>('tableService');
|
export const ITableService = createDecorator<ITableService>('tableService');
|
||||||
@@ -118,7 +118,7 @@ function toWorkbenchTableOptions<T>(options: ITableOptions<T>): [ITableOptions<T
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IWorkbenchTableOptions<T> extends ITableOptions<T> {
|
export interface IWorkbenchTableOptions<T> extends ITableOptions<T> {
|
||||||
readonly overrideStyles?: IColorMapping;
|
readonly overrideStyles?: IHighPerfTableStyleOverrides;
|
||||||
}
|
}
|
||||||
|
|
||||||
export class WorkbenchTable<T> extends Table<T> {
|
export class WorkbenchTable<T> extends Table<T> {
|
||||||
|
|||||||
@@ -8,103 +8,113 @@ import * as colors from './colors';
|
|||||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||||
import * as cr from 'vs/platform/theme/common/colorRegistry';
|
import * as cr from 'vs/platform/theme/common/colorRegistry';
|
||||||
import * as sqlcr from 'sql/platform/theme/common/colorRegistry';
|
import * as sqlcr from 'sql/platform/theme/common/colorRegistry';
|
||||||
import { attachStyler, defaultListStyles, IColorMapping, IStyleOverrides } from 'vs/platform/theme/common/styler';
|
import { attachStyler, computeStyles, defaultListStyles, IColorMapping, IStyleOverrides } from 'vs/platform/theme/common/styler';
|
||||||
import { IDisposable } from 'vs/base/common/lifecycle';
|
import { IDisposable } from 'vs/base/common/lifecycle';
|
||||||
import { IThemable } from 'vs/base/common/styler';
|
import { IThemable } from 'vs/base/common/styler';
|
||||||
|
|
||||||
export function attachDropdownStyler(widget: IThemable, themeService: IThemeService, style?:
|
export interface IDropdownStyleOverrides extends IStyleOverrides {
|
||||||
{
|
foregroundColor?: cr.ColorIdentifier;
|
||||||
backgroundColor?: cr.ColorIdentifier,
|
borderColor?: cr.ColorIdentifier;
|
||||||
foregroundColor?: cr.ColorIdentifier,
|
backgroundColor?: cr.ColorIdentifier;
|
||||||
borderColor?: cr.ColorIdentifier,
|
buttonForeground?: cr.ColorIdentifier;
|
||||||
buttonForeground?: cr.ColorIdentifier,
|
buttonBackground?: cr.ColorIdentifier;
|
||||||
buttonBackground?: cr.ColorIdentifier,
|
buttonHoverBackground?: cr.ColorIdentifier;
|
||||||
buttonHoverBackground?: cr.ColorIdentifier,
|
buttonBorder?: cr.ColorIdentifier;
|
||||||
buttonFocusOutline?: cr.ColorIdentifier
|
buttonFocusOutline?: cr.ColorIdentifier;
|
||||||
}): IDisposable {
|
|
||||||
return attachStyler(themeService, {
|
|
||||||
foregroundColor: (style && style.foregroundColor) || cr.inputForeground,
|
|
||||||
borderColor: (style && style.borderColor) || cr.inputBorder,
|
|
||||||
backgroundColor: (style && style.backgroundColor) || cr.editorBackground,
|
|
||||||
buttonForeground: (style && style.buttonForeground) || cr.buttonForeground,
|
|
||||||
buttonBackground: (style && style.buttonBackground) || cr.buttonBackground,
|
|
||||||
buttonHoverBackground: (style && style.buttonHoverBackground) || cr.buttonHoverBackground,
|
|
||||||
buttonBorder: cr.contrastBorder,
|
|
||||||
buttonFocusOutline: (style && style.buttonFocusOutline) || colors.buttonFocusOutline
|
|
||||||
}, widget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function attachInputBoxStyler(widget: IThemable, themeService: IThemeService, style?:
|
export const defaultDropdownStyle: IDropdownStyleOverrides = {
|
||||||
{
|
foregroundColor: cr.inputForeground,
|
||||||
inputBackground?: cr.ColorIdentifier,
|
borderColor: cr.inputBorder,
|
||||||
inputForeground?: cr.ColorIdentifier,
|
backgroundColor: cr.editorBackground,
|
||||||
disabledInputBackground?: cr.ColorIdentifier,
|
buttonForeground: cr.buttonForeground,
|
||||||
disabledInputForeground?: cr.ColorIdentifier,
|
buttonBackground: cr.buttonBackground,
|
||||||
inputBorder?: cr.ColorIdentifier,
|
buttonHoverBackground: cr.buttonHoverBackground,
|
||||||
inputValidationInfoBorder?: cr.ColorIdentifier,
|
buttonBorder: cr.contrastBorder,
|
||||||
inputValidationInfoBackground?: cr.ColorIdentifier,
|
buttonFocusOutline: colors.buttonFocusOutline
|
||||||
inputValidationWarningBorder?: cr.ColorIdentifier,
|
};
|
||||||
inputValidationWarningBackground?: cr.ColorIdentifier,
|
|
||||||
inputValidationErrorBorder?: cr.ColorIdentifier,
|
export function attachDropdownStyler(widget: IThemable, themeService: IThemeService, style?: IDropdownStyleOverrides): IDisposable {
|
||||||
inputValidationErrorBackground?: cr.ColorIdentifier
|
return attachStyler(themeService, { ...defaultDropdownStyle, ...(style || {}) }, widget);
|
||||||
}): IDisposable {
|
|
||||||
return attachStyler(themeService, {
|
|
||||||
inputBackground: (style && style.inputBackground) || cr.inputBackground,
|
|
||||||
inputForeground: (style && style.inputForeground) || cr.inputForeground,
|
|
||||||
disabledInputBackground: (style && style.disabledInputBackground) || colors.disabledInputBackground,
|
|
||||||
disabledInputForeground: (style && style.disabledInputForeground) || colors.disabledInputForeground,
|
|
||||||
inputBorder: (style && style.inputBorder) || cr.inputBorder,
|
|
||||||
inputValidationInfoBorder: (style && style.inputValidationInfoBorder) || cr.inputValidationInfoBorder,
|
|
||||||
inputValidationInfoBackground: (style && style.inputValidationInfoBackground) || cr.inputValidationInfoBackground,
|
|
||||||
inputValidationWarningBorder: (style && style.inputValidationWarningBorder) || cr.inputValidationWarningBorder,
|
|
||||||
inputValidationWarningBackground: (style && style.inputValidationWarningBackground) || cr.inputValidationWarningBackground,
|
|
||||||
inputValidationErrorBorder: (style && style.inputValidationErrorBorder) || cr.inputValidationErrorBorder,
|
|
||||||
inputValidationErrorBackground: (style && style.inputValidationErrorBackground) || cr.inputValidationErrorBackground
|
|
||||||
}, widget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeService, style?:
|
export interface IInputBoxStyleOverrides extends IStyleOverrides {
|
||||||
{
|
inputBackground?: cr.ColorIdentifier,
|
||||||
selectBackground?: cr.ColorIdentifier,
|
inputForeground?: cr.ColorIdentifier,
|
||||||
selectListBackground?: cr.ColorIdentifier,
|
disabledInputBackground?: cr.ColorIdentifier,
|
||||||
selectForeground?: cr.ColorIdentifier,
|
disabledInputForeground?: cr.ColorIdentifier,
|
||||||
selectBorder?: cr.ColorIdentifier,
|
inputBorder?: cr.ColorIdentifier,
|
||||||
disabledSelectBackground?: cr.ColorIdentifier,
|
inputValidationInfoBorder?: cr.ColorIdentifier,
|
||||||
disabledSelectForeground?: cr.ColorIdentifier,
|
inputValidationInfoBackground?: cr.ColorIdentifier,
|
||||||
inputValidationInfoBorder?: cr.ColorIdentifier,
|
inputValidationWarningBorder?: cr.ColorIdentifier,
|
||||||
inputValidationInfoBackground?: cr.ColorIdentifier,
|
inputValidationWarningBackground?: cr.ColorIdentifier,
|
||||||
inputValidationWarningBorder?: cr.ColorIdentifier,
|
inputValidationErrorBorder?: cr.ColorIdentifier,
|
||||||
inputValidationWarningBackground?: cr.ColorIdentifier,
|
inputValidationErrorBackground?: cr.ColorIdentifier
|
||||||
inputValidationErrorBorder?: cr.ColorIdentifier,
|
}
|
||||||
inputValidationErrorBackground?: cr.ColorIdentifier,
|
|
||||||
focusBorder?: cr.ColorIdentifier,
|
export const defaultInputBoxStyleOverrides: IInputBoxStyleOverrides = {
|
||||||
listFocusBackground?: cr.ColorIdentifier,
|
inputBackground: cr.inputBackground,
|
||||||
listFocusForeground?: cr.ColorIdentifier,
|
inputForeground: cr.inputForeground,
|
||||||
listFocusOutline?: cr.ColorIdentifier,
|
disabledInputBackground: colors.disabledInputBackground,
|
||||||
listHoverBackground?: cr.ColorIdentifier,
|
disabledInputForeground: colors.disabledInputForeground,
|
||||||
listHoverForeground?: cr.ColorIdentifier
|
inputBorder: cr.inputBorder,
|
||||||
}): IDisposable {
|
inputValidationInfoBorder: cr.inputValidationInfoBorder,
|
||||||
return attachStyler(themeService, {
|
inputValidationInfoBackground: cr.inputValidationInfoBackground,
|
||||||
selectBackground: (style && style.selectBackground) || cr.selectBackground,
|
inputValidationWarningBorder: cr.inputValidationWarningBorder,
|
||||||
selectListBackground: (style && style.selectListBackground) || cr.selectListBackground,
|
inputValidationWarningBackground: cr.inputValidationWarningBackground,
|
||||||
selectForeground: (style && style.selectForeground) || cr.selectForeground,
|
inputValidationErrorBorder: cr.inputValidationErrorBorder,
|
||||||
selectBorder: (style && style.selectBorder) || cr.selectBorder,
|
inputValidationErrorBackground: cr.inputValidationErrorBackground
|
||||||
disabledSelectBackground: (style && style.disabledSelectBackground) || colors.disabledInputBackground,
|
};
|
||||||
disabledSelectForeground: (style && style.disabledSelectForeground) || colors.disabledInputForeground,
|
|
||||||
inputValidationInfoBorder: (style && style.inputValidationInfoBorder) || cr.inputValidationInfoBorder,
|
export function attachInputBoxStyler(widget: IThemable, themeService: IThemeService, style?: IInputBoxStyleOverrides): IDisposable {
|
||||||
inputValidationInfoBackground: (style && style.inputValidationInfoBackground) || cr.inputValidationInfoBackground,
|
return attachStyler(themeService, { ...defaultInputBoxStyleOverrides, ...(style || {}) }, widget);
|
||||||
inputValidationWarningBorder: (style && style.inputValidationWarningBorder) || cr.inputValidationWarningBorder,
|
}
|
||||||
inputValidationWarningBackground: (style && style.inputValidationWarningBackground) || cr.inputValidationWarningBackground,
|
|
||||||
inputValidationErrorBorder: (style && style.inputValidationErrorBorder) || cr.inputValidationErrorBorder,
|
export interface ISelectBoxStyleOverrides extends IStyleOverrides {
|
||||||
inputValidationErrorBackground: (style && style.inputValidationErrorBackground) || cr.inputValidationErrorBackground,
|
selectBackground?: cr.ColorIdentifier,
|
||||||
focusBorder: (style && style.focusBorder) || cr.focusBorder,
|
selectListBackground?: cr.ColorIdentifier,
|
||||||
listFocusBackground: (style && style.listFocusBackground) || cr.listFocusBackground,
|
selectForeground?: cr.ColorIdentifier,
|
||||||
listFocusForeground: (style && style.listFocusForeground) || cr.listFocusForeground,
|
selectBorder?: cr.ColorIdentifier,
|
||||||
listFocusOutline: (style && style.listFocusOutline) || cr.activeContrastBorder,
|
disabledSelectBackground?: cr.ColorIdentifier,
|
||||||
listHoverBackground: (style && style.listHoverBackground) || cr.listHoverBackground,
|
disabledSelectForeground?: cr.ColorIdentifier,
|
||||||
listHoverForeground: (style && style.listHoverForeground) || cr.listHoverForeground,
|
inputValidationInfoBorder?: cr.ColorIdentifier,
|
||||||
listHoverOutline: (style && style.listFocusOutline) || cr.activeContrastBorder
|
inputValidationInfoBackground?: cr.ColorIdentifier,
|
||||||
}, widget);
|
inputValidationWarningBorder?: cr.ColorIdentifier,
|
||||||
|
inputValidationWarningBackground?: cr.ColorIdentifier,
|
||||||
|
inputValidationErrorBorder?: cr.ColorIdentifier,
|
||||||
|
inputValidationErrorBackground?: cr.ColorIdentifier,
|
||||||
|
focusBorder?: cr.ColorIdentifier,
|
||||||
|
listFocusBackground?: cr.ColorIdentifier,
|
||||||
|
listFocusForeground?: cr.ColorIdentifier,
|
||||||
|
listFocusOutline?: cr.ColorIdentifier,
|
||||||
|
listHoverBackground?: cr.ColorIdentifier,
|
||||||
|
listHoverForeground?: cr.ColorIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultSelectBoxStyleOverrides: ISelectBoxStyleOverrides = {
|
||||||
|
selectBackground: cr.selectBackground,
|
||||||
|
selectListBackground: cr.selectListBackground,
|
||||||
|
selectForeground: cr.selectForeground,
|
||||||
|
selectBorder: cr.selectBorder,
|
||||||
|
disabledSelectBackground: colors.disabledInputBackground,
|
||||||
|
disabledSelectForeground: colors.disabledInputForeground,
|
||||||
|
inputValidationInfoBorder: cr.inputValidationInfoBorder,
|
||||||
|
inputValidationInfoBackground: cr.inputValidationInfoBackground,
|
||||||
|
inputValidationWarningBorder: cr.inputValidationWarningBorder,
|
||||||
|
inputValidationWarningBackground: cr.inputValidationWarningBackground,
|
||||||
|
inputValidationErrorBorder: cr.inputValidationErrorBorder,
|
||||||
|
inputValidationErrorBackground: cr.inputValidationErrorBackground,
|
||||||
|
focusBorder: cr.focusBorder,
|
||||||
|
listFocusBackground: cr.listFocusBackground,
|
||||||
|
listFocusForeground: cr.listFocusForeground,
|
||||||
|
listFocusOutline: cr.activeContrastBorder,
|
||||||
|
listHoverBackground: cr.listHoverBackground,
|
||||||
|
listHoverForeground: cr.listHoverForeground,
|
||||||
|
listHoverOutline: cr.activeContrastBorder
|
||||||
|
};
|
||||||
|
|
||||||
|
export function attachSelectBoxStyler(widget: IThemable, themeService: IThemeService, style?: ISelectBoxStyleOverrides): IDisposable {
|
||||||
|
return attachStyler(themeService, { ...defaultSelectBoxStyleOverrides, ...(style || {}) }, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function attachListBoxStyler(widget: IThemable, themeService: IThemeService, style?:
|
export function attachListBoxStyler(widget: IThemable, themeService: IThemeService, style?:
|
||||||
@@ -132,7 +142,7 @@ export function attachListBoxStyler(widget: IThemable, themeService: IThemeServi
|
|||||||
}, widget);
|
}, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function attachTableStyler(widget: IThemable, themeService: IThemeService, style?: {
|
export interface ITableStyleOverrides extends IStyleOverrides {
|
||||||
listFocusBackground?: cr.ColorIdentifier,
|
listFocusBackground?: cr.ColorIdentifier,
|
||||||
listFocusForeground?: cr.ColorIdentifier,
|
listFocusForeground?: cr.ColorIdentifier,
|
||||||
listActiveSelectionBackground?: cr.ColorIdentifier,
|
listActiveSelectionBackground?: cr.ColorIdentifier,
|
||||||
@@ -150,31 +160,35 @@ export function attachTableStyler(widget: IThemable, themeService: IThemeService
|
|||||||
listSelectionOutline?: cr.ColorIdentifier,
|
listSelectionOutline?: cr.ColorIdentifier,
|
||||||
listHoverOutline?: cr.ColorIdentifier,
|
listHoverOutline?: cr.ColorIdentifier,
|
||||||
tableHeaderBackground?: cr.ColorIdentifier,
|
tableHeaderBackground?: cr.ColorIdentifier,
|
||||||
tableHeaderForeground?: cr.ColorIdentifier
|
tableHeaderForeground?: cr.ColorIdentifier,
|
||||||
}): IDisposable {
|
|
||||||
return attachStyler(themeService, {
|
|
||||||
listFocusBackground: (style && style.listFocusBackground) || cr.listFocusBackground,
|
|
||||||
listFocusForeground: (style && style.listFocusForeground) || cr.listFocusForeground,
|
|
||||||
listActiveSelectionBackground: (style && style.listActiveSelectionBackground) || cr.listActiveSelectionBackground,
|
|
||||||
listActiveSelectionForeground: (style && style.listActiveSelectionForeground) || cr.listActiveSelectionForeground,
|
|
||||||
listFocusAndSelectionBackground: style && style.listFocusAndSelectionBackground || colors.listFocusAndSelectionBackground,
|
|
||||||
listFocusAndSelectionForeground: (style && style.listFocusAndSelectionForeground) || cr.listActiveSelectionForeground,
|
|
||||||
listInactiveFocusBackground: (style && style.listInactiveFocusBackground),
|
|
||||||
listInactiveSelectionBackground: (style && style.listInactiveSelectionBackground) || cr.listInactiveSelectionBackground,
|
|
||||||
listInactiveSelectionForeground: (style && style.listInactiveSelectionForeground) || cr.listInactiveSelectionForeground,
|
|
||||||
listHoverBackground: (style && style.listHoverBackground) || cr.listHoverBackground,
|
|
||||||
listHoverForeground: (style && style.listHoverForeground) || cr.listHoverForeground,
|
|
||||||
listDropBackground: (style && style.listDropBackground) || cr.listDropBackground,
|
|
||||||
listFocusOutline: (style && style.listFocusOutline) || cr.activeContrastBorder,
|
|
||||||
listSelectionOutline: (style && style.listSelectionOutline) || cr.activeContrastBorder,
|
|
||||||
listHoverOutline: (style && style.listHoverOutline) || cr.activeContrastBorder,
|
|
||||||
listInactiveFocusOutline: style && style.listInactiveFocusOutline,
|
|
||||||
tableHeaderBackground: (style && style.tableHeaderBackground) || colors.tableHeaderBackground,
|
|
||||||
tableHeaderForeground: (style && style.tableHeaderForeground) || colors.tableHeaderForeground
|
|
||||||
}, widget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITableStyleOverrides extends IStyleOverrides {
|
export const defaultTableStyleOverrides: ITableStyleOverrides = {
|
||||||
|
listFocusBackground: cr.listFocusBackground,
|
||||||
|
listFocusForeground: cr.listFocusForeground,
|
||||||
|
listActiveSelectionBackground: cr.listActiveSelectionBackground,
|
||||||
|
listActiveSelectionForeground: cr.listActiveSelectionForeground,
|
||||||
|
listFocusAndSelectionBackground: colors.listFocusAndSelectionBackground,
|
||||||
|
listFocusAndSelectionForeground: cr.listActiveSelectionForeground,
|
||||||
|
listInactiveFocusBackground: cr.listInactiveFocusBackground,
|
||||||
|
listInactiveSelectionBackground: cr.listInactiveSelectionBackground,
|
||||||
|
listInactiveSelectionForeground: cr.listInactiveSelectionForeground,
|
||||||
|
listHoverBackground: cr.listHoverBackground,
|
||||||
|
listHoverForeground: cr.listHoverForeground,
|
||||||
|
listDropBackground: cr.listDropBackground,
|
||||||
|
listFocusOutline: cr.activeContrastBorder,
|
||||||
|
listSelectionOutline: cr.activeContrastBorder,
|
||||||
|
listHoverOutline: cr.activeContrastBorder,
|
||||||
|
listInactiveFocusOutline: cr.listInactiveFocusOutline,
|
||||||
|
tableHeaderBackground: colors.tableHeaderBackground,
|
||||||
|
tableHeaderForeground: colors.tableHeaderForeground
|
||||||
|
};
|
||||||
|
|
||||||
|
export function attachTableStyler(widget: IThemable, themeService: IThemeService, style?: ITableStyleOverrides): IDisposable {
|
||||||
|
return attachStyler(themeService, { ...defaultTableStyleOverrides, ...(style || {}) }, widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IHighPerfTableStyleOverrides extends IStyleOverrides {
|
||||||
listFocusBackground?: cr.ColorIdentifier,
|
listFocusBackground?: cr.ColorIdentifier,
|
||||||
listFocusForeground?: cr.ColorIdentifier,
|
listFocusForeground?: cr.ColorIdentifier,
|
||||||
listActiveSelectionBackground?: cr.ColorIdentifier,
|
listActiveSelectionBackground?: cr.ColorIdentifier,
|
||||||
@@ -197,10 +211,6 @@ export interface ITableStyleOverrides extends IStyleOverrides {
|
|||||||
tableHeaderAndRowCountColor?: cr.ColorIdentifier
|
tableHeaderAndRowCountColor?: cr.ColorIdentifier
|
||||||
}
|
}
|
||||||
|
|
||||||
export function attachHighPerfTableStyler(widget: IThemable, themeService: IThemeService, overrides?: IColorMapping): IDisposable {
|
|
||||||
return attachStyler(themeService, { ...defaultHighPerfTableStyles, ...(overrides || {}) }, widget);
|
|
||||||
}
|
|
||||||
|
|
||||||
export const defaultHighPerfTableStyles: IColorMapping = {
|
export const defaultHighPerfTableStyles: IColorMapping = {
|
||||||
listFocusBackground: cr.listFocusBackground,
|
listFocusBackground: cr.listFocusBackground,
|
||||||
listFocusForeground: cr.listFocusForeground,
|
listFocusForeground: cr.listFocusForeground,
|
||||||
@@ -223,7 +233,11 @@ export const defaultHighPerfTableStyles: IColorMapping = {
|
|||||||
tableHeaderAndRowCountColor: colors.tableCellOutline
|
tableHeaderAndRowCountColor: colors.tableCellOutline
|
||||||
};
|
};
|
||||||
|
|
||||||
export function attachEditableDropdownStyler(widget: IThemable, themeService: IThemeService, style?: {
|
export function attachHighPerfTableStyler(widget: IThemable, themeService: IThemeService, overrides?: IHighPerfTableStyleOverrides): IDisposable {
|
||||||
|
return attachStyler(themeService, { ...defaultHighPerfTableStyles, ...(overrides || {}) }, widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IEditableDropdownStyleOverrides extends IStyleOverrides {
|
||||||
listFocusBackground?: cr.ColorIdentifier,
|
listFocusBackground?: cr.ColorIdentifier,
|
||||||
listFocusForeground?: cr.ColorIdentifier,
|
listFocusForeground?: cr.ColorIdentifier,
|
||||||
listActiveSelectionBackground?: cr.ColorIdentifier,
|
listActiveSelectionBackground?: cr.ColorIdentifier,
|
||||||
@@ -240,7 +254,6 @@ export function attachEditableDropdownStyler(widget: IThemable, themeService: IT
|
|||||||
listInactiveFocusOutline?: cr.ColorIdentifier,
|
listInactiveFocusOutline?: cr.ColorIdentifier,
|
||||||
listSelectionOutline?: cr.ColorIdentifier,
|
listSelectionOutline?: cr.ColorIdentifier,
|
||||||
listHoverOutline?: cr.ColorIdentifier,
|
listHoverOutline?: cr.ColorIdentifier,
|
||||||
|
|
||||||
inputBackground?: cr.ColorIdentifier,
|
inputBackground?: cr.ColorIdentifier,
|
||||||
inputForeground?: cr.ColorIdentifier,
|
inputForeground?: cr.ColorIdentifier,
|
||||||
inputBorder?: cr.ColorIdentifier,
|
inputBorder?: cr.ColorIdentifier,
|
||||||
@@ -252,43 +265,53 @@ export function attachEditableDropdownStyler(widget: IThemable, themeService: IT
|
|||||||
inputValidationErrorBackground?: cr.ColorIdentifier,
|
inputValidationErrorBackground?: cr.ColorIdentifier,
|
||||||
contextBackground?: cr.ColorIdentifier,
|
contextBackground?: cr.ColorIdentifier,
|
||||||
contextBorder?: cr.ColorIdentifier
|
contextBorder?: cr.ColorIdentifier
|
||||||
}): IDisposable {
|
|
||||||
return attachStyler(themeService, {
|
|
||||||
listFocusBackground: (style && style.listFocusBackground) || cr.listFocusBackground,
|
|
||||||
listFocusForeground: (style && style.listFocusForeground) || cr.listFocusForeground,
|
|
||||||
listActiveSelectionBackground: (style && style.listActiveSelectionBackground) || cr.lighten(cr.listActiveSelectionBackground, 0.1),
|
|
||||||
listActiveSelectionForeground: (style && style.listActiveSelectionForeground) || cr.listActiveSelectionForeground,
|
|
||||||
listFocusAndSelectionBackground: style && style.listFocusAndSelectionBackground || cr.listActiveSelectionBackground,
|
|
||||||
listFocusAndSelectionForeground: (style && style.listFocusAndSelectionForeground) || cr.listActiveSelectionForeground,
|
|
||||||
listInactiveFocusBackground: (style && style.listInactiveFocusBackground),
|
|
||||||
listInactiveSelectionBackground: (style && style.listInactiveSelectionBackground) || cr.listInactiveSelectionBackground,
|
|
||||||
listInactiveSelectionForeground: (style && style.listInactiveSelectionForeground) || cr.listInactiveSelectionForeground,
|
|
||||||
listHoverBackground: (style && style.listHoverBackground) || cr.listHoverBackground,
|
|
||||||
listHoverForeground: (style && style.listHoverForeground) || cr.listHoverForeground,
|
|
||||||
listDropBackground: (style && style.listDropBackground) || cr.listDropBackground,
|
|
||||||
listFocusOutline: (style && style.listFocusOutline) || cr.activeContrastBorder,
|
|
||||||
listSelectionOutline: (style && style.listSelectionOutline) || cr.activeContrastBorder,
|
|
||||||
listHoverOutline: (style && style.listHoverOutline) || cr.activeContrastBorder,
|
|
||||||
listInactiveFocusOutline: style && style.listInactiveFocusOutline,
|
|
||||||
inputBackground: (style && style.inputBackground) || cr.inputBackground,
|
|
||||||
inputForeground: (style && style.inputForeground) || cr.inputForeground,
|
|
||||||
inputBorder: (style && style.inputBorder) || cr.inputBorder,
|
|
||||||
inputValidationInfoBorder: (style && style.inputValidationInfoBorder) || cr.inputValidationInfoBorder,
|
|
||||||
inputValidationInfoBackground: (style && style.inputValidationInfoBackground) || cr.inputValidationInfoBackground,
|
|
||||||
inputValidationWarningBorder: (style && style.inputValidationWarningBorder) || cr.inputValidationWarningBorder,
|
|
||||||
inputValidationWarningBackground: (style && style.inputValidationWarningBackground) || cr.inputValidationWarningBackground,
|
|
||||||
inputValidationErrorBorder: (style && style.inputValidationErrorBorder) || cr.inputValidationErrorBorder,
|
|
||||||
inputValidationErrorBackground: (style && style.inputValidationErrorBackground) || cr.inputValidationErrorBackground,
|
|
||||||
contextBackground: (style && style.contextBackground) || cr.editorBackground,
|
|
||||||
contextBorder: (style && style.contextBorder) || cr.inputBorder
|
|
||||||
}, widget);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function attachCheckboxStyler(widget: IThemable, themeService: IThemeService, style?: { disabledCheckboxForeground?: cr.ColorIdentifier })
|
export const defaultEditableDropdownStyleOverrides: IEditableDropdownStyleOverrides = {
|
||||||
: IDisposable {
|
listFocusBackground: cr.listFocusBackground,
|
||||||
return attachStyler(themeService, {
|
listFocusForeground: cr.listFocusForeground,
|
||||||
disabledCheckboxForeground: (style && style.disabledCheckboxForeground) || colors.disabledCheckboxForeground
|
listActiveSelectionBackground: cr.listActiveSelectionBackground,
|
||||||
}, widget);
|
listActiveSelectionForeground: cr.listActiveSelectionForeground,
|
||||||
|
listFocusAndSelectionBackground: cr.listActiveSelectionBackground,
|
||||||
|
listFocusAndSelectionForeground: cr.listActiveSelectionForeground,
|
||||||
|
listInactiveFocusBackground: cr.listInactiveFocusBackground,
|
||||||
|
listInactiveSelectionBackground: cr.listInactiveSelectionBackground,
|
||||||
|
listInactiveSelectionForeground: cr.listInactiveSelectionForeground,
|
||||||
|
listHoverBackground: cr.listHoverBackground,
|
||||||
|
listHoverForeground: cr.listHoverForeground,
|
||||||
|
listDropBackground: cr.listDropBackground,
|
||||||
|
listFocusOutline: cr.activeContrastBorder,
|
||||||
|
listSelectionOutline: cr.activeContrastBorder,
|
||||||
|
listHoverOutline: cr.activeContrastBorder,
|
||||||
|
listInactiveFocusOutline: cr.listInactiveFocusOutline,
|
||||||
|
inputBackground: cr.inputBackground,
|
||||||
|
inputForeground: cr.inputForeground,
|
||||||
|
inputBorder: cr.inputBorder,
|
||||||
|
inputValidationInfoBorder: cr.inputValidationInfoBorder,
|
||||||
|
inputValidationInfoBackground: cr.inputValidationInfoBackground,
|
||||||
|
inputValidationWarningBorder: cr.inputValidationWarningBorder,
|
||||||
|
inputValidationWarningBackground: cr.inputValidationWarningBackground,
|
||||||
|
inputValidationErrorBorder: cr.inputValidationErrorBorder,
|
||||||
|
inputValidationErrorBackground: cr.inputValidationErrorBackground,
|
||||||
|
contextBackground: cr.editorBackground,
|
||||||
|
contextBorder: cr.inputBorder
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
export function attachEditableDropdownStyler(widget: IThemable, themeService: IThemeService, style?: IEditableDropdownStyleOverrides): IDisposable {
|
||||||
|
return attachStyler(themeService, { ...defaultEditableDropdownStyleOverrides, ...(style || {}) }, widget);
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICheckboxStyleOverrides extends IStyleOverrides {
|
||||||
|
disabledCheckboxForeground?: cr.ColorIdentifier
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultCheckboxStyleOverrides: ICheckboxStyleOverrides = {
|
||||||
|
disabledCheckboxForeground: colors.disabledCheckboxForeground
|
||||||
|
};
|
||||||
|
|
||||||
|
export function attachCheckboxStyler(widget: IThemable, themeService: IThemeService, style?: ICheckboxStyleOverrides): IDisposable {
|
||||||
|
return attachStyler(themeService, {}, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IInfoBoxStyleOverrides {
|
export interface IInfoBoxStyleOverrides {
|
||||||
@@ -329,9 +352,7 @@ export function attachInfoButtonStyler(widget: IThemable, themeService: IThemeSe
|
|||||||
|
|
||||||
export function attachTableFilterStyler(widget: IThemable, themeService: IThemeService): IDisposable {
|
export function attachTableFilterStyler(widget: IThemable, themeService: IThemeService): IDisposable {
|
||||||
return attachStyler(themeService, {
|
return attachStyler(themeService, {
|
||||||
inputBackground: cr.inputBackground,
|
...defaultInputBoxStyleOverrides,
|
||||||
inputForeground: cr.inputForeground,
|
|
||||||
inputBorder: cr.inputBorder,
|
|
||||||
buttonForeground: cr.buttonForeground,
|
buttonForeground: cr.buttonForeground,
|
||||||
buttonBackground: cr.buttonBackground,
|
buttonBackground: cr.buttonBackground,
|
||||||
buttonHoverBackground: cr.buttonHoverBackground,
|
buttonHoverBackground: cr.buttonHoverBackground,
|
||||||
@@ -349,3 +370,23 @@ export function attachTableFilterStyler(widget: IThemable, themeService: IThemeS
|
|||||||
...defaultListStyles,
|
...defaultListStyles,
|
||||||
}, widget);
|
}, widget);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function attachDesignerStyler(widget: any, themeService: IThemeService): IDisposable {
|
||||||
|
function applyStyles(): void {
|
||||||
|
const colorTheme = themeService.getColorTheme();
|
||||||
|
const inputStyles = computeStyles(colorTheme, defaultInputBoxStyleOverrides);
|
||||||
|
const selectBoxStyles = computeStyles(colorTheme, defaultSelectBoxStyleOverrides);
|
||||||
|
const tableStyles = computeStyles(colorTheme, defaultTableStyleOverrides);
|
||||||
|
const checkboxStyles = computeStyles(colorTheme, defaultCheckboxStyleOverrides);
|
||||||
|
widget.style({
|
||||||
|
inputBoxStyles: inputStyles,
|
||||||
|
selectBoxStyles: selectBoxStyles,
|
||||||
|
tableStyles: tableStyles,
|
||||||
|
checkboxStyles: checkboxStyles
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
applyStyles();
|
||||||
|
|
||||||
|
return themeService.onDidColorThemeChange(applyStyles);
|
||||||
|
}
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ import { IAssessmentService } from 'sql/workbench/services/assessment/common/int
|
|||||||
import { IDataGridProviderService } from 'sql/workbench/services/dataGridProvider/common/dataGridProviderService';
|
import { IDataGridProviderService } from 'sql/workbench/services/dataGridProvider/common/dataGridProviderService';
|
||||||
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
import { IAdsTelemetryService } from 'sql/platform/telemetry/common/telemetry';
|
||||||
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
import * as TelemetryKeys from 'sql/platform/telemetry/common/telemetryKeys';
|
||||||
|
import { ITableDesignerService } from 'sql/workbench/services/tableDesigner/common/interface';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main thread class for handling data protocol management registration.
|
* Main thread class for handling data protocol management registration.
|
||||||
@@ -59,7 +60,8 @@ export class MainThreadDataProtocol extends Disposable implements MainThreadData
|
|||||||
@IFileBrowserService private _fileBrowserService: IFileBrowserService,
|
@IFileBrowserService private _fileBrowserService: IFileBrowserService,
|
||||||
@IAssessmentService private _assessmentService: IAssessmentService,
|
@IAssessmentService private _assessmentService: IAssessmentService,
|
||||||
@IDataGridProviderService private _dataGridProviderService: IDataGridProviderService,
|
@IDataGridProviderService private _dataGridProviderService: IDataGridProviderService,
|
||||||
@IAdsTelemetryService private _telemetryService: IAdsTelemetryService
|
@IAdsTelemetryService private _telemetryService: IAdsTelemetryService,
|
||||||
|
@ITableDesignerService private _tableDesignerService: ITableDesignerService
|
||||||
) {
|
) {
|
||||||
super();
|
super();
|
||||||
if (extHostContext) {
|
if (extHostContext) {
|
||||||
@@ -507,6 +509,20 @@ export class MainThreadDataProtocol extends Disposable implements MainThreadData
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$registerTableDesignerProvider(providerId: string, handle: number): Promise<any> {
|
||||||
|
const self = this;
|
||||||
|
this._tableDesignerService.registerProvider(providerId, <azdata.designers.TableDesignerProvider>{
|
||||||
|
getTableDesignerInfo(tableInfo: azdata.designers.TableInfo): Thenable<azdata.designers.TableDesignerInfo> {
|
||||||
|
return self._proxy.$getTableDesignerInfo(handle, tableInfo);
|
||||||
|
},
|
||||||
|
processTableEdit(table, data, edit): Thenable<azdata.designers.DesignerEditResult> {
|
||||||
|
return self._proxy.$processTableDesignerEdit(handle, table, data, edit);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
public $registerSerializationProvider(providerId: string, handle: number): Promise<any> {
|
public $registerSerializationProvider(providerId: string, handle: number): Promise<any> {
|
||||||
const self = this;
|
const self = this;
|
||||||
this._serializationService.registerProvider(providerId, <azdata.SerializationProvider>{
|
this._serializationService.registerProvider(providerId, <azdata.SerializationProvider>{
|
||||||
@@ -616,6 +632,11 @@ export class MainThreadDataProtocol extends Disposable implements MainThreadData
|
|||||||
this._jobManagementService.fireOnDidChange();
|
this._jobManagementService.fireOnDidChange();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Table Designer
|
||||||
|
public $openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo): void {
|
||||||
|
this._tableDesignerService.openTableDesigner(providerId, tableInfo);
|
||||||
|
}
|
||||||
|
|
||||||
public $unregisterProvider(handle: number): Promise<any> {
|
public $unregisterProvider(handle: number): Promise<any> {
|
||||||
let capabilitiesRegistration = this._capabilitiesRegistrations[handle];
|
let capabilitiesRegistration = this._capabilitiesRegistrations[handle];
|
||||||
if (capabilitiesRegistration) {
|
if (capabilitiesRegistration) {
|
||||||
|
|||||||
@@ -194,6 +194,12 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
|
|||||||
return rt;
|
return rt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$registerTableDesignerProvider(provider: azdata.designers.TableDesignerProvider): vscode.Disposable {
|
||||||
|
let rt = this.registerProvider(provider, DataProviderType.TableDesignerProvider);
|
||||||
|
this._proxy.$registerTableDesignerProvider(provider.providerId, provider.handle);
|
||||||
|
return rt;
|
||||||
|
}
|
||||||
|
|
||||||
// Capabilities Discovery handlers
|
// Capabilities Discovery handlers
|
||||||
override $getServerCapabilities(handle: number, client: azdata.DataProtocolClientCapabilities): Thenable<azdata.DataProtocolServerCapabilities> {
|
override $getServerCapabilities(handle: number, client: azdata.DataProtocolClientCapabilities): Thenable<azdata.DataProtocolServerCapabilities> {
|
||||||
return this._resolveProvider<azdata.CapabilitiesProvider>(handle).getServerCapabilities(client);
|
return this._resolveProvider<azdata.CapabilitiesProvider>(handle).getServerCapabilities(client);
|
||||||
@@ -884,4 +890,18 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
|
|||||||
public override $getDataGridColumns(handle: number): Thenable<azdata.DataGridColumn[]> {
|
public override $getDataGridColumns(handle: number): Thenable<azdata.DataGridColumn[]> {
|
||||||
return this._resolveProvider<azdata.DataGridProvider>(handle).getDataGridColumns();
|
return this._resolveProvider<azdata.DataGridProvider>(handle).getDataGridColumns();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Table Designer
|
||||||
|
public override $getTableDesignerInfo(handle, table: azdata.designers.TableInfo): Thenable<azdata.designers.TableDesignerInfo> {
|
||||||
|
return this._resolveProvider<azdata.designers.TableDesignerProvider>(handle).getTableDesignerInfo(table);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override $processTableDesignerEdit(handle, table: azdata.designers.TableInfo, data: azdata.designers.DesignerData, edit: azdata.designers.DesignerEdit): Thenable<azdata.designers.DesignerEditResult> {
|
||||||
|
return this._resolveProvider<azdata.designers.TableDesignerProvider>(handle).processTableEdit(table, data, edit);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override $openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo): Promise<void> {
|
||||||
|
this._proxy.$openTableDesigner(providerId, tableInfo);
|
||||||
|
return Promise.resolve();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -380,6 +380,10 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp
|
|||||||
return extHostDataProvider.$registerDataGridProvider(provider);
|
return extHostDataProvider.$registerDataGridProvider(provider);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let registerTableDesignerProvider = (provider: azdata.designers.TableDesignerProvider): vscode.Disposable => {
|
||||||
|
return extHostDataProvider.$registerTableDesignerProvider(provider);
|
||||||
|
};
|
||||||
|
|
||||||
// namespace: dataprotocol
|
// namespace: dataprotocol
|
||||||
const dataprotocol: typeof azdata.dataprotocol = {
|
const dataprotocol: typeof azdata.dataprotocol = {
|
||||||
registerBackupProvider,
|
registerBackupProvider,
|
||||||
@@ -400,6 +404,7 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp
|
|||||||
registerSerializationProvider,
|
registerSerializationProvider,
|
||||||
registerSqlAssessmentServicesProvider,
|
registerSqlAssessmentServicesProvider,
|
||||||
registerDataGridProvider,
|
registerDataGridProvider,
|
||||||
|
registerTableDesignerProvider,
|
||||||
onDidChangeLanguageFlavor(listener: (e: azdata.DidChangeLanguageFlavorParams) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
|
onDidChangeLanguageFlavor(listener: (e: azdata.DidChangeLanguageFlavorParams) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
|
||||||
return extHostDataProvider.onDidChangeLanguageFlavor(listener, thisArgs, disposables);
|
return extHostDataProvider.onDidChangeLanguageFlavor(listener, thisArgs, disposables);
|
||||||
},
|
},
|
||||||
@@ -564,6 +569,15 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp
|
|||||||
SqlAssessmentTargetType: sqlExtHostTypes.SqlAssessmentTargetType
|
SqlAssessmentTargetType: sqlExtHostTypes.SqlAssessmentTargetType
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const designers: typeof azdata.designers = {
|
||||||
|
TableProperty: sqlExtHostTypes.designers.TableProperty,
|
||||||
|
TableColumnProperty: sqlExtHostTypes.designers.TableColumnProperty,
|
||||||
|
DesignerEditType: sqlExtHostTypes.designers.DesignerEditType,
|
||||||
|
openTableDesigner(providerId, tableInfo: azdata.designers.TableInfo): Promise<void> {
|
||||||
|
return extHostDataProvider.$openTableDesigner(providerId, tableInfo);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
version: initData.version,
|
version: initData.version,
|
||||||
accounts,
|
accounts,
|
||||||
@@ -614,7 +628,8 @@ export function createAdsApiFactory(accessor: ServicesAccessor): IAdsExtensionAp
|
|||||||
DatabaseEngineEdition: sqlExtHostTypes.DatabaseEngineEdition,
|
DatabaseEngineEdition: sqlExtHostTypes.DatabaseEngineEdition,
|
||||||
TabOrientation: sqlExtHostTypes.TabOrientation,
|
TabOrientation: sqlExtHostTypes.TabOrientation,
|
||||||
sqlAssessment,
|
sqlAssessment,
|
||||||
TextType: sqlExtHostTypes.TextType
|
TextType: sqlExtHostTypes.TextType,
|
||||||
|
designers: designers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -526,6 +526,21 @@ export abstract class ExtHostDataProtocolShape {
|
|||||||
* Gets the list of columns for a data grid
|
* Gets the list of columns for a data grid
|
||||||
*/
|
*/
|
||||||
$getDataGridColumns(handle: number): Thenable<azdata.DataGridColumn[]> { throw ni(); }
|
$getDataGridColumns(handle: number): Thenable<azdata.DataGridColumn[]> { throw ni(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the table designer info for the specified table
|
||||||
|
*/
|
||||||
|
$getTableDesignerInfo(handle, table: azdata.designers.TableInfo): Thenable<azdata.designers.TableDesignerInfo> { throw ni(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Process the table edit.
|
||||||
|
*/
|
||||||
|
$processTableDesignerEdit(handle, table: azdata.designers.TableInfo, data: azdata.designers.DesignerData, edit: azdata.designers.DesignerEdit): Thenable<azdata.designers.DesignerEditResult> { throw ni(); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a new instance of table designer.
|
||||||
|
*/
|
||||||
|
$openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo, designerInfo: azdata.designers.TableDesignerInfo): void { throw ni(); }
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -591,6 +606,7 @@ export interface MainThreadDataProtocolShape extends IDisposable {
|
|||||||
$registerSerializationProvider(providerId: string, handle: number): Promise<any>;
|
$registerSerializationProvider(providerId: string, handle: number): Promise<any>;
|
||||||
$registerSqlAssessmentServicesProvider(providerId: string, handle: number): Promise<any>;
|
$registerSqlAssessmentServicesProvider(providerId: string, handle: number): Promise<any>;
|
||||||
$registerDataGridProvider(providerId: string, title: string, handle: number): void;
|
$registerDataGridProvider(providerId: string, title: string, handle: number): void;
|
||||||
|
$registerTableDesignerProvider(providerId: string, handle: number): Promise<any>;
|
||||||
$unregisterProvider(handle: number): Promise<any>;
|
$unregisterProvider(handle: number): Promise<any>;
|
||||||
$onConnectionComplete(handle: number, connectionInfoSummary: azdata.ConnectionInfoSummary): void;
|
$onConnectionComplete(handle: number, connectionInfoSummary: azdata.ConnectionInfoSummary): void;
|
||||||
$onIntelliSenseCacheComplete(handle: number, connectionUri: string): void;
|
$onIntelliSenseCacheComplete(handle: number, connectionUri: string): void;
|
||||||
@@ -614,6 +630,7 @@ export interface MainThreadDataProtocolShape extends IDisposable {
|
|||||||
$onSessionStopped(handle: number, response: azdata.ProfilerSessionStoppedParams): void;
|
$onSessionStopped(handle: number, response: azdata.ProfilerSessionStoppedParams): void;
|
||||||
$onProfilerSessionCreated(handle: number, response: azdata.ProfilerSessionCreatedParams): void;
|
$onProfilerSessionCreated(handle: number, response: azdata.ProfilerSessionCreatedParams): void;
|
||||||
$onJobDataUpdated(handle: Number): void;
|
$onJobDataUpdated(handle: Number): void;
|
||||||
|
$openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo): void;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Callback when a session has completed initialization
|
* Callback when a session has completed initialization
|
||||||
|
|||||||
@@ -381,7 +381,8 @@ export enum DataProviderType {
|
|||||||
SerializationProvider = 'SerializationProvider',
|
SerializationProvider = 'SerializationProvider',
|
||||||
IconProvider = 'IconProvider',
|
IconProvider = 'IconProvider',
|
||||||
SqlAssessmentServicesProvider = 'SqlAssessmentServicesProvider',
|
SqlAssessmentServicesProvider = 'SqlAssessmentServicesProvider',
|
||||||
DataGridProvider = 'DataGridProvider'
|
DataGridProvider = 'DataGridProvider',
|
||||||
|
TableDesignerProvider = 'TableDesignerProvider'
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum DeclarativeDataType {
|
export enum DeclarativeDataType {
|
||||||
@@ -905,3 +906,27 @@ export enum TextType {
|
|||||||
UnorderedList = 'UnorderedList',
|
UnorderedList = 'UnorderedList',
|
||||||
OrderedList = 'OrderedList'
|
OrderedList = 'OrderedList'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export namespace designers {
|
||||||
|
export enum TableProperty {
|
||||||
|
Schema = 'schema',
|
||||||
|
Name = 'name',
|
||||||
|
Description = 'description',
|
||||||
|
Columns = 'columns',
|
||||||
|
Script = 'script'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum TableColumnProperty {
|
||||||
|
Name = 'name',
|
||||||
|
Type = 'type',
|
||||||
|
AllowNulls = 'allowNulls',
|
||||||
|
DefaultValue = 'defaultValue',
|
||||||
|
Length = 'length'
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum DesignerEditType {
|
||||||
|
Add = 0,
|
||||||
|
Remove = 1,
|
||||||
|
Update = 2
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
|
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
|
||||||
|
import { URI } from 'vs/workbench/workbench.web.api';
|
||||||
|
import { TableDesignerComponentInput } from 'sql/workbench/services/tableDesigner/browser/tableDesignerComponentInput';
|
||||||
|
import { TableDesignerProvider } from 'sql/workbench/services/tableDesigner/common/interface';
|
||||||
|
import * as azdata from 'azdata';
|
||||||
|
|
||||||
|
const NewTable: string = localize('tableDesigner.newTable', "New Table");
|
||||||
|
|
||||||
|
export class TableDesignerInput extends EditorInput {
|
||||||
|
public static ID: string = 'workbench.editorinputs.tableDesignerInput';
|
||||||
|
private _designerComponentInput: TableDesignerComponentInput;
|
||||||
|
constructor(provider: TableDesignerProvider,
|
||||||
|
private _tableInfo: azdata.designers.TableInfo) {
|
||||||
|
super();
|
||||||
|
this._designerComponentInput = new TableDesignerComponentInput(provider, this._tableInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
get typeId(): string {
|
||||||
|
return TableDesignerInput.ID;
|
||||||
|
}
|
||||||
|
|
||||||
|
get resource(): URI {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
public getComponentInput(): TableDesignerComponentInput {
|
||||||
|
return this._designerComponentInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
override getName(): string {
|
||||||
|
const tableName = this._tableInfo.isNewTable ? NewTable : `${this._tableInfo.schema}.${this._tableInfo.name}`;
|
||||||
|
return `${this._tableInfo.server}.${this._tableInfo.database} - ${tableName}`;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { TableDesignerInput } from 'sql/workbench/browser/editor/tableDesigner/tableDesignerInput';
|
||||||
|
import { TableDesignerEditor } from 'sql/workbench/contrib/tableDesigner/browser/tableDesignerEditor';
|
||||||
|
import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
|
||||||
|
import { Registry } from 'vs/platform/registry/common/platform';
|
||||||
|
import { EditorDescriptor, IEditorRegistry } from 'vs/workbench/browser/editor';
|
||||||
|
import { EditorExtensions } from 'vs/workbench/common/editor';
|
||||||
|
|
||||||
|
const tableDesignerDescriptor = EditorDescriptor.create(
|
||||||
|
TableDesignerEditor,
|
||||||
|
TableDesignerEditor.ID,
|
||||||
|
'TableDesignerEditor'
|
||||||
|
);
|
||||||
|
|
||||||
|
Registry.as<IEditorRegistry>(EditorExtensions.Editors)
|
||||||
|
.registerEditor(tableDesignerDescriptor, [new SyncDescriptor(TableDesignerInput)]);
|
||||||
@@ -0,0 +1,51 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { Designer } from 'sql/base/browser/ui/designer/designer';
|
||||||
|
import { attachDesignerStyler } from 'sql/platform/theme/common/styler';
|
||||||
|
import { TableDesignerInput } from 'sql/workbench/browser/editor/tableDesigner/tableDesignerInput';
|
||||||
|
import * as DOM from 'vs/base/browser/dom';
|
||||||
|
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||||
|
import { IContextViewService } from 'vs/platform/contextview/browser/contextView';
|
||||||
|
import { IEditorOptions } from 'vs/platform/editor/common/editor';
|
||||||
|
import { IStorageService } from 'vs/platform/storage/common/storage';
|
||||||
|
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
|
||||||
|
import { EditorPane } from 'vs/workbench/browser/parts/editor/editorPane';
|
||||||
|
import { IEditorOpenContext } from 'vs/workbench/common/editor';
|
||||||
|
import { IWorkbenchThemeService } from 'vs/workbench/services/themes/common/workbenchThemeService';
|
||||||
|
|
||||||
|
export class TableDesignerEditor extends EditorPane {
|
||||||
|
public static readonly ID: string = 'workbench.editor.tableDesigner';
|
||||||
|
|
||||||
|
private _designer: Designer;
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
@ITelemetryService telemetryService: ITelemetryService,
|
||||||
|
@IWorkbenchThemeService themeService: IWorkbenchThemeService,
|
||||||
|
@IStorageService storageService: IStorageService,
|
||||||
|
@IContextViewService private _contextViewService: IContextViewService
|
||||||
|
) {
|
||||||
|
super(TableDesignerEditor.ID, telemetryService, themeService, storageService);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override get input(): TableDesignerInput | undefined {
|
||||||
|
return this._input as TableDesignerInput;
|
||||||
|
}
|
||||||
|
|
||||||
|
override async setInput(input: TableDesignerInput, options: IEditorOptions | undefined, context: IEditorOpenContext, token: CancellationToken): Promise<void> {
|
||||||
|
await super.setInput(input, options, context, token);
|
||||||
|
this._designer.setInput(input.getComponentInput());
|
||||||
|
}
|
||||||
|
|
||||||
|
protected createEditor(parent: HTMLElement): void {
|
||||||
|
// The editor is only created once per editor group.
|
||||||
|
this._designer = new Designer(parent, this._contextViewService);
|
||||||
|
this._register(attachDesignerStyler(this._designer, this.themeService));
|
||||||
|
}
|
||||||
|
|
||||||
|
layout(dimension: DOM.Dimension): void {
|
||||||
|
this._designer.layout(dimension);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -13,12 +13,14 @@ export class TreeNodeContextKey implements IContextKey<TreeNode> {
|
|||||||
static Status = new RawContextKey<string>('nodeStatus', undefined);
|
static Status = new RawContextKey<string>('nodeStatus', undefined);
|
||||||
static TreeNode = new RawContextKey<TreeNode>('treeNode', undefined);
|
static TreeNode = new RawContextKey<TreeNode>('treeNode', undefined);
|
||||||
static NodeLabel = new RawContextKey<string>('nodeLabel', undefined);
|
static NodeLabel = new RawContextKey<string>('nodeLabel', undefined);
|
||||||
|
static NodePath = new RawContextKey<string>('nodePath', undefined);
|
||||||
|
|
||||||
private _nodeTypeKey: IContextKey<string>;
|
private _nodeTypeKey: IContextKey<string>;
|
||||||
private _subTypeKey: IContextKey<string>;
|
private _subTypeKey: IContextKey<string>;
|
||||||
private _statusKey: IContextKey<string>;
|
private _statusKey: IContextKey<string>;
|
||||||
private _treeNodeKey: IContextKey<TreeNode>;
|
private _treeNodeKey: IContextKey<TreeNode>;
|
||||||
private _nodeLabelKey: IContextKey<string>;
|
private _nodeLabelKey: IContextKey<string>;
|
||||||
|
private _nodePathKey: IContextKey<string>;
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@IContextKeyService contextKeyService: IContextKeyService
|
@IContextKeyService contextKeyService: IContextKeyService
|
||||||
@@ -28,6 +30,7 @@ export class TreeNodeContextKey implements IContextKey<TreeNode> {
|
|||||||
this._statusKey = TreeNodeContextKey.Status.bindTo(contextKeyService);
|
this._statusKey = TreeNodeContextKey.Status.bindTo(contextKeyService);
|
||||||
this._treeNodeKey = TreeNodeContextKey.TreeNode.bindTo(contextKeyService);
|
this._treeNodeKey = TreeNodeContextKey.TreeNode.bindTo(contextKeyService);
|
||||||
this._nodeLabelKey = TreeNodeContextKey.NodeLabel.bindTo(contextKeyService);
|
this._nodeLabelKey = TreeNodeContextKey.NodeLabel.bindTo(contextKeyService);
|
||||||
|
this._nodePathKey = TreeNodeContextKey.NodePath.bindTo(contextKeyService);
|
||||||
}
|
}
|
||||||
|
|
||||||
set(value: TreeNode) {
|
set(value: TreeNode) {
|
||||||
@@ -38,6 +41,7 @@ export class TreeNodeContextKey implements IContextKey<TreeNode> {
|
|||||||
this._statusKey.set(value && value.nodeStatus);
|
this._statusKey.set(value && value.nodeStatus);
|
||||||
}
|
}
|
||||||
this._nodeLabelKey.set(value && value.label);
|
this._nodeLabelKey.set(value && value.label);
|
||||||
|
this._nodePathKey.set(value && value.nodePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
reset(): void {
|
reset(): void {
|
||||||
@@ -46,6 +50,7 @@ export class TreeNodeContextKey implements IContextKey<TreeNode> {
|
|||||||
this._statusKey.reset();
|
this._statusKey.reset();
|
||||||
this._treeNodeKey.reset();
|
this._treeNodeKey.reset();
|
||||||
this._nodeLabelKey.reset();
|
this._nodeLabelKey.reset();
|
||||||
|
this._nodePathKey.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
public get(): TreeNode | undefined {
|
public get(): TreeNode | undefined {
|
||||||
|
|||||||
@@ -0,0 +1,177 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as azdata from 'azdata';
|
||||||
|
import { DesignerData, DesignerEdit, DesignerEditResult, DesignerComponentInput, DesignerView, DesignerTab, DesignerDataPropertyInfo, DropDownProperties, DesignerTableProperties } from 'sql/base/browser/ui/designer/interfaces';
|
||||||
|
import { TableDesignerProvider } from 'sql/workbench/services/tableDesigner/common/interface';
|
||||||
|
import { localize } from 'vs/nls';
|
||||||
|
import { designers } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||||
|
|
||||||
|
export class TableDesignerComponentInput implements DesignerComponentInput {
|
||||||
|
|
||||||
|
private _data: DesignerData;
|
||||||
|
private _view: DesignerView;
|
||||||
|
|
||||||
|
constructor(private readonly _provider: TableDesignerProvider,
|
||||||
|
private _tableInfo: azdata.designers.TableInfo) {
|
||||||
|
}
|
||||||
|
|
||||||
|
get objectTypeDisplayName(): string {
|
||||||
|
return localize('tableDesigner.tableObjectType', "Table");
|
||||||
|
}
|
||||||
|
|
||||||
|
async getView(): Promise<DesignerView> {
|
||||||
|
if (!this._view) {
|
||||||
|
await this.initialize();
|
||||||
|
}
|
||||||
|
return this._view;
|
||||||
|
}
|
||||||
|
|
||||||
|
async getData(): Promise<DesignerData> {
|
||||||
|
if (!this._data) {
|
||||||
|
await this.initialize();
|
||||||
|
}
|
||||||
|
return this._data;
|
||||||
|
}
|
||||||
|
|
||||||
|
async processEdit(edit: DesignerEdit): Promise<DesignerEditResult> {
|
||||||
|
const result = await this._provider.processTableEdit(this._tableInfo, this._data!, edit);
|
||||||
|
if (result.isValid) {
|
||||||
|
this._data = result.data;
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
isValid: result.isValid,
|
||||||
|
errors: result.errors
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private async initialize(): Promise<void> {
|
||||||
|
const designerInfo = await this._provider.getTableDesignerInfo(this._tableInfo);
|
||||||
|
|
||||||
|
this._data = designerInfo.data;
|
||||||
|
this.setDefaultData();
|
||||||
|
|
||||||
|
const advancedTabComponents: DesignerDataPropertyInfo[] = [
|
||||||
|
{
|
||||||
|
componentType: 'dropdown',
|
||||||
|
propertyName: designers.TableProperty.Schema,
|
||||||
|
componentProperties: <DropDownProperties>{
|
||||||
|
title: localize('tableDesigner.schemaTitle', "Schema"),
|
||||||
|
values: designerInfo.schemas
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
componentType: 'input',
|
||||||
|
propertyName: designers.TableProperty.Description,
|
||||||
|
componentProperties: {
|
||||||
|
title: localize('tableDesigner.descriptionTitle', "Description")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
if (designerInfo.view.additionalTableProperties) {
|
||||||
|
advancedTabComponents.push(...designerInfo.view.additionalTableProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
const advancedTab = <DesignerTab>{
|
||||||
|
title: localize('tableDesigner.advancedTab', "Advanced"),
|
||||||
|
components: advancedTabComponents
|
||||||
|
};
|
||||||
|
|
||||||
|
const columnProperties: DesignerDataPropertyInfo[] = [
|
||||||
|
{
|
||||||
|
componentType: 'input',
|
||||||
|
propertyName: designers.TableColumnProperty.Name,
|
||||||
|
componentProperties: {
|
||||||
|
title: localize('tableDesigner.columnNameTitle', "Name"),
|
||||||
|
width: 150
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
componentType: 'dropdown',
|
||||||
|
propertyName: designers.TableColumnProperty.Type,
|
||||||
|
componentProperties: {
|
||||||
|
title: localize('tableDesigner.columnTypeTitle', "Type"),
|
||||||
|
width: 100,
|
||||||
|
values: designerInfo.columnTypes
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
componentType: 'input',
|
||||||
|
propertyName: designers.TableColumnProperty.Length,
|
||||||
|
componentProperties: {
|
||||||
|
title: localize('tableDesigner.columnLengthTitle', "Length"),
|
||||||
|
width: 75
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
componentType: 'input',
|
||||||
|
propertyName: designers.TableColumnProperty.DefaultValue,
|
||||||
|
componentProperties: {
|
||||||
|
title: localize('tableDesigner.columnDefaultValueTitle', "Default Value"),
|
||||||
|
width: 150
|
||||||
|
}
|
||||||
|
}, {
|
||||||
|
componentType: 'checkbox',
|
||||||
|
propertyName: designers.TableColumnProperty.AllowNulls,
|
||||||
|
componentProperties: {
|
||||||
|
title: localize('tableDesigner.columnAllowNullTitle', "Allow Nulls"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
];
|
||||||
|
|
||||||
|
if (designerInfo.view.addtionalTableColumnProperties) {
|
||||||
|
columnProperties.push(...designerInfo.view.addtionalTableColumnProperties);
|
||||||
|
}
|
||||||
|
|
||||||
|
const columnsTab = <DesignerTab>{
|
||||||
|
title: localize('tableDesigner.columnsTabTitle', "Columns"),
|
||||||
|
components: [
|
||||||
|
{
|
||||||
|
componentType: 'table',
|
||||||
|
propertyName: designers.TableProperty.Columns,
|
||||||
|
componentProperties: <DesignerTableProperties>{
|
||||||
|
ariaLabel: localize('tableDesigner.columnsTabTitle', "Columns"),
|
||||||
|
columns: [
|
||||||
|
designers.TableColumnProperty.Name,
|
||||||
|
designers.TableColumnProperty.Type,
|
||||||
|
designers.TableColumnProperty.Length,
|
||||||
|
designers.TableColumnProperty.DefaultValue,
|
||||||
|
designers.TableColumnProperty.AllowNulls
|
||||||
|
],
|
||||||
|
itemProperties: columnProperties,
|
||||||
|
objectTypeDisplayName: localize('tableDesigner.columnTypeName', "Column")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
const tabs = [columnsTab, advancedTab];
|
||||||
|
if (designerInfo.view.addtionalTabs) {
|
||||||
|
tabs.push(...tabs);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._view = {
|
||||||
|
components: [{
|
||||||
|
componentType: 'input',
|
||||||
|
propertyName: designers.TableColumnProperty.Name,
|
||||||
|
componentProperties: {
|
||||||
|
title: localize('tableDesigner.nameTitle', "Table name"),
|
||||||
|
width: 200
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
tabs: tabs
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private setDefaultData(): void {
|
||||||
|
const properties = Object.keys(this._data);
|
||||||
|
this.setDefaultInputData(properties, designers.TableProperty.Name);
|
||||||
|
this.setDefaultInputData(properties, designers.TableProperty.Schema);
|
||||||
|
this.setDefaultInputData(properties, designers.TableProperty.Description);
|
||||||
|
}
|
||||||
|
|
||||||
|
private setDefaultInputData(allProperties: string[], property: string): void {
|
||||||
|
if (allProperties.indexOf(property) === -1) {
|
||||||
|
this._data[property] = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import { TableDesignerProvider, ITableDesignerService } from 'sql/workbench/services/tableDesigner/common/interface';
|
||||||
|
import { invalidProvider } from 'sql/base/common/errors';
|
||||||
|
import * as azdata from 'azdata';
|
||||||
|
import { ACTIVE_GROUP, IEditorService } from 'vs/workbench/services/editor/common/editorService';
|
||||||
|
import { TableDesignerInput } from 'sql/workbench/browser/editor/tableDesigner/tableDesignerInput';
|
||||||
|
|
||||||
|
export class TableDesignerService implements ITableDesignerService {
|
||||||
|
|
||||||
|
constructor(@IEditorService private _editorService: IEditorService) { }
|
||||||
|
|
||||||
|
public _serviceBrand: undefined;
|
||||||
|
private _providers = new Map<string, TableDesignerProvider>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a data grid provider
|
||||||
|
*/
|
||||||
|
public registerProvider(providerId: string, provider: TableDesignerProvider): void {
|
||||||
|
if (this._providers.has(providerId)) {
|
||||||
|
throw new Error(`A table designer provider with id "${providerId}" is already registered`);
|
||||||
|
}
|
||||||
|
this._providers.set(providerId, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
public unregisterProvider(providerId: string): void {
|
||||||
|
this._providers.delete(providerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public getProvider(providerId: string): TableDesignerProvider {
|
||||||
|
const provider = this._providers.get(providerId);
|
||||||
|
if (provider) {
|
||||||
|
return provider;
|
||||||
|
}
|
||||||
|
throw invalidProvider(providerId);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo): Promise<void> {
|
||||||
|
const provider = this.getProvider(providerId);
|
||||||
|
const tableDesignerInput = new TableDesignerInput(provider, tableInfo);
|
||||||
|
await this._editorService.openEditor(tableDesignerInput, { pinned: true }, ACTIVE_GROUP);
|
||||||
|
}
|
||||||
|
}
|
||||||
40
src/sql/workbench/services/tableDesigner/common/interface.ts
Normal file
40
src/sql/workbench/services/tableDesigner/common/interface.ts
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
/*---------------------------------------------------------------------------------------------
|
||||||
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||||
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||||
|
*--------------------------------------------------------------------------------------------*/
|
||||||
|
|
||||||
|
import * as azdata from 'azdata';
|
||||||
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||||
|
|
||||||
|
|
||||||
|
export const SERVICE_ID = 'tableDesignerService';
|
||||||
|
export const ITableDesignerService = createDecorator<ITableDesignerService>(SERVICE_ID);
|
||||||
|
|
||||||
|
export interface TableDesignerProvider extends azdata.designers.TableDesignerProvider { }
|
||||||
|
|
||||||
|
export interface ITableDesignerService {
|
||||||
|
_serviceBrand: undefined;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Register a table designer provider
|
||||||
|
*/
|
||||||
|
registerProvider(providerId: string, provider: TableDesignerProvider): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unregister a table designer provider
|
||||||
|
*/
|
||||||
|
unregisterProvider(providerId: string): void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a registered table designer provider, throwing if none are registered with the specified ID
|
||||||
|
* @param providerId The id of the registered provider
|
||||||
|
*/
|
||||||
|
getProvider(providerId: string): TableDesignerProvider;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a table designer for the given table
|
||||||
|
* @param providerId The provider id
|
||||||
|
* @param tableInfo The table information
|
||||||
|
*/
|
||||||
|
openTableDesigner(providerId: string, tableInfo: azdata.designers.TableInfo): Promise<void>;
|
||||||
|
}
|
||||||
@@ -210,6 +210,8 @@ import { IAssessmentService } from 'sql/workbench/services/assessment/common/int
|
|||||||
import { AssessmentService } from 'sql/workbench/services/assessment/common/assessmentService';
|
import { AssessmentService } from 'sql/workbench/services/assessment/common/assessmentService';
|
||||||
import { DataGridProviderService } from 'sql/workbench/services/dataGridProvider/browser/dataGridProviderService';
|
import { DataGridProviderService } from 'sql/workbench/services/dataGridProvider/browser/dataGridProviderService';
|
||||||
import { IDataGridProviderService } from 'sql/workbench/services/dataGridProvider/common/dataGridProviderService';
|
import { IDataGridProviderService } from 'sql/workbench/services/dataGridProvider/common/dataGridProviderService';
|
||||||
|
import { ITableDesignerService } from 'sql/workbench/services/tableDesigner/common/interface';
|
||||||
|
import { TableDesignerService } from 'sql/workbench/services/tableDesigner/browser/tableDesignerService';
|
||||||
|
|
||||||
registerSingleton(IDashboardService, DashboardService);
|
registerSingleton(IDashboardService, DashboardService);
|
||||||
registerSingleton(IDashboardViewService, DashboardViewService);
|
registerSingleton(IDashboardViewService, DashboardViewService);
|
||||||
@@ -249,6 +251,7 @@ registerSingleton(IObjectExplorerService, ObjectExplorerService);
|
|||||||
registerSingleton(IOEShimService, OEShimService);
|
registerSingleton(IOEShimService, OEShimService);
|
||||||
registerSingleton(IAssessmentService, AssessmentService);
|
registerSingleton(IAssessmentService, AssessmentService);
|
||||||
registerSingleton(IDataGridProviderService, DataGridProviderService);
|
registerSingleton(IDataGridProviderService, DataGridProviderService);
|
||||||
|
registerSingleton(ITableDesignerService, TableDesignerService);
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
@@ -521,4 +524,7 @@ import 'sql/workbench/contrib/azure/browser/azure.contribution';
|
|||||||
// Charts
|
// Charts
|
||||||
import 'sql/workbench/contrib/charts/browser/charts.contribution';
|
import 'sql/workbench/contrib/charts/browser/charts.contribution';
|
||||||
|
|
||||||
|
// table designer
|
||||||
|
import 'sql/workbench/contrib/tableDesigner/browser/tableDesigner.contribution';
|
||||||
|
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|||||||
Reference in New Issue
Block a user