mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-03 01:25:38 -05:00
Schema Compare extension (#4974)
* extension now working * fix diff editor title disappearing and remove border from source and target name boxes * redoing a bunch of stuff that disappeared after rebasing * add images and add to extensions.ts * moving a few changes to the right place after rebase * formatting * update toolbar svgs * addressing comments * add return types * Adding PR comments * Adding light and dark theme icons * Fixing the diff editor title for dark theme
This commit is contained in:
49
src/sql/azdata.proposed.d.ts
vendored
49
src/sql/azdata.proposed.d.ts
vendored
@@ -44,6 +44,8 @@ declare module 'azdata' {
|
||||
|
||||
export function registerDacFxServicesProvider(provider: DacFxServicesProvider): vscode.Disposable;
|
||||
|
||||
export function registerSchemaCompareServicesProvider(provider: SchemaCompareServicesProvider): vscode.Disposable;
|
||||
|
||||
/**
|
||||
* An [event](#Event) which fires when the specific flavor of a language used in DMP
|
||||
* connections has changed. And example is for a SQL connection, the flavor changes
|
||||
@@ -1699,6 +1701,51 @@ declare module 'azdata' {
|
||||
generateDeployPlan(packageFilePath: string, databaseName: string, ownerUri: string, taskExecutionMode: TaskExecutionMode): Thenable<GenerateDeployPlanResult>;
|
||||
}
|
||||
|
||||
// Schema Compare interfaces -----------------------------------------------------------------------
|
||||
export interface SchemaCompareResult extends ResultStatus {
|
||||
operationId: string;
|
||||
areEqual: boolean;
|
||||
differences: DiffEntry[];
|
||||
}
|
||||
|
||||
export interface DiffEntry {
|
||||
updateAction: SchemaUpdateAction;
|
||||
differenceType: SchemaDifferenceType;
|
||||
name: string;
|
||||
sourceValue: string;
|
||||
targetValue: string;
|
||||
parent: DiffEntry;
|
||||
children: DiffEntry[];
|
||||
sourceScript: string;
|
||||
targetScript: string;
|
||||
}
|
||||
|
||||
export enum SchemaUpdateAction {
|
||||
Delete = 0,
|
||||
Change = 1,
|
||||
Add = 2
|
||||
}
|
||||
|
||||
export enum SchemaDifferenceType {
|
||||
Object = 0,
|
||||
Property = 1
|
||||
}
|
||||
export enum SchemaCompareEndpointType {
|
||||
database = 0,
|
||||
dacpac = 1
|
||||
}
|
||||
export interface SchemaCompareEndpointInfo {
|
||||
endpointType: SchemaCompareEndpointType;
|
||||
packageFilePath: string;
|
||||
databaseName: string;
|
||||
ownerUri: string;
|
||||
}
|
||||
|
||||
export interface SchemaCompareServicesProvider extends DataProvider {
|
||||
schemaCompare(sourceEndpointInfo: SchemaCompareEndpointInfo, targetEndpointInfo: SchemaCompareEndpointInfo, taskExecutionMode: TaskExecutionMode): Thenable<SchemaCompareResult>;
|
||||
schemaCompareGenerateScript(operationId: string, targetDatabaseName: string, scriptFilePath: string, taskExecutionMode: TaskExecutionMode): Thenable<ResultStatus>;
|
||||
}
|
||||
|
||||
// Security service interfaces ------------------------------------------------------------------------
|
||||
export interface CredentialInfo {
|
||||
id: number;
|
||||
@@ -2916,6 +2963,7 @@ declare module 'azdata' {
|
||||
value: string;
|
||||
width?: number;
|
||||
cssClass?: string;
|
||||
headerCssClass?: string;
|
||||
toolTip?: string;
|
||||
}
|
||||
|
||||
@@ -3764,6 +3812,7 @@ declare module 'azdata' {
|
||||
AgentServicesProvider = 'AgentServicesProvider',
|
||||
CapabilitiesProvider = 'CapabilitiesProvider',
|
||||
DacFxServicesProvider = 'DacFxServicesProvider',
|
||||
SchemaCompareServicesProvider = 'SchemaCompareServicesProvider',
|
||||
ObjectExplorerNodeProvider = 'ObjectExplorerNodeProvider',
|
||||
}
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ import { CancellationTokenSource } from 'vs/base/common/cancellation';
|
||||
@Component({
|
||||
template: `
|
||||
<div *ngIf="_title">
|
||||
<div style="width: 100%; height:100%; padding-left:3px !important; background: #F4F4F4; border: 1px solid #BFBDBD;">
|
||||
<div class="modelview-diff-editor-title" style="width: 100%; height:100%; padding-left:3px !important; border: 1px solid #BFBDBD;">
|
||||
{{_title}}
|
||||
</div>
|
||||
</div>`,
|
||||
@@ -71,6 +71,7 @@ export default class DiffEditorComponent extends ComponentBase implements ICompo
|
||||
private _createEditor(): void {
|
||||
this._instantiationService = this._instantiationService.createChild(new ServiceCollection([IProgressService, new SimpleProgressService()]));
|
||||
this._editor = this._instantiationService.createInstance(TextDiffEditor);
|
||||
this._editor.reverseColoring();
|
||||
this._editor.create(this._el.nativeElement);
|
||||
this._editor.setVisible(true);
|
||||
let uri1 = this.createUri('source');
|
||||
|
||||
@@ -13,4 +13,12 @@ modelview-diff-editor-component {
|
||||
height: 100%;
|
||||
width : 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.vs-dark modelview-diff-editor-title {
|
||||
background: #444444;
|
||||
}
|
||||
|
||||
modelview-diff-editor-title {
|
||||
background: #f4f4f4;
|
||||
}
|
||||
@@ -58,6 +58,7 @@ export default class TableComponent extends ComponentBase implements IComponent,
|
||||
field: col.value,
|
||||
width: col.width,
|
||||
cssClass: col.cssClass,
|
||||
headerCssClass: col.headerCssClass,
|
||||
toolTip: col.toolTip
|
||||
};
|
||||
} else {
|
||||
|
||||
@@ -11,4 +11,9 @@
|
||||
.align-with-header
|
||||
{
|
||||
padding-left:3px !important;
|
||||
}
|
||||
|
||||
.no-borders
|
||||
{
|
||||
border: none !important
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
'use strict';
|
||||
|
||||
import * as azdata from 'azdata';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IConnectionManagementService } from 'sql/platform/connection/common/connectionManagement';
|
||||
import { localize } from 'vs/nls';
|
||||
|
||||
export const SERVICE_ID = 'SchemaCompareService';
|
||||
export const ISchemaCompareService = createDecorator<ISchemaCompareService>(SERVICE_ID);
|
||||
|
||||
export interface ISchemaCompareService {
|
||||
_serviceBrand: any;
|
||||
|
||||
registerProvider(providerId: string, provider: azdata.SchemaCompareServicesProvider): void;
|
||||
schemaCompare(sourceEndpointInfo: azdata.SchemaCompareEndpointInfo, targetEndpointInfo: azdata.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode): void;
|
||||
schemaCompareGenerateScript(operationId: string, targetDatabaseName: string, scriptFilePath: string, taskExecutionMode: azdata.TaskExecutionMode): void;
|
||||
}
|
||||
|
||||
export class SchemaCompareService implements ISchemaCompareService {
|
||||
_serviceBrand: any;
|
||||
private _providers: { [handle: string]: azdata.SchemaCompareServicesProvider; } = Object.create(null);
|
||||
|
||||
constructor(@IConnectionManagementService private _connectionService: IConnectionManagementService) { }
|
||||
|
||||
registerProvider(providerId: string, provider: azdata.SchemaCompareServicesProvider): void {
|
||||
this._providers[providerId] = provider;
|
||||
}
|
||||
|
||||
schemaCompare(sourceEndpointInfo: azdata.SchemaCompareEndpointInfo, targetEndpointInfo: azdata.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.SchemaCompareResult> {
|
||||
return this._runAction(sourceEndpointInfo.ownerUri, (runner) => {
|
||||
return runner.schemaCompare(sourceEndpointInfo, targetEndpointInfo, taskExecutionMode);
|
||||
});
|
||||
}
|
||||
|
||||
schemaCompareGenerateScript(operationId: string, targetDatabaseName: string, scriptFilePath: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus> {
|
||||
return this._runAction('', (runner) => {
|
||||
return runner.schemaCompareGenerateScript(operationId, targetDatabaseName, scriptFilePath, taskExecutionMode);
|
||||
});
|
||||
}
|
||||
|
||||
private _runAction<T>(uri: string, action: (handler: azdata.SchemaCompareServicesProvider) => Thenable<T>): Thenable<T> {
|
||||
let providerId: string = this._connectionService.getProviderIdFromUri(uri);
|
||||
|
||||
if (!providerId) {
|
||||
return Promise.reject(new Error(localize('providerIdNotValidError', "Connection is required in order to interact with SchemaCompareService")));
|
||||
}
|
||||
let handler = this._providers[providerId];
|
||||
if (handler) {
|
||||
return action(handler);
|
||||
} else {
|
||||
return Promise.reject(new Error(localize('noHandlerRegistered', "No Handler Registered")));
|
||||
}
|
||||
}
|
||||
}
|
||||
2
src/sql/sqlops.d.ts
vendored
2
src/sql/sqlops.d.ts
vendored
@@ -39,6 +39,7 @@ declare module 'sqlops' {
|
||||
|
||||
export function registerDacFxServicesProvider(provider: DacFxServicesProvider): vscode.Disposable;
|
||||
|
||||
|
||||
/**
|
||||
* An [event](#Event) which fires when the specific flavor of a language used in DMP
|
||||
* connections has changed. And example is for a SQL connection, the flavor changes
|
||||
@@ -1324,6 +1325,7 @@ declare module 'sqlops' {
|
||||
generateDeployPlan(packageFilePath: string, databaseName: string, ownerUri: string, taskExecutionMode: TaskExecutionMode): Thenable<GenerateDeployPlanResult>;
|
||||
}
|
||||
|
||||
|
||||
// Security service interfaces ------------------------------------------------------------------------
|
||||
export interface CredentialInfo {
|
||||
id: number;
|
||||
|
||||
1
src/sql/sqlops.proposed.d.ts
vendored
1
src/sql/sqlops.proposed.d.ts
vendored
@@ -1602,6 +1602,7 @@ declare module 'sqlops' {
|
||||
AgentServicesProvider = 'AgentServicesProvider',
|
||||
CapabilitiesProvider = 'CapabilitiesProvider',
|
||||
DacFxServicesProvider = 'DacFxServicesProvider',
|
||||
SchemaCompareServicesProvider = 'SchemaCompareServicesProvider',
|
||||
ObjectExplorerNodeProvider = 'ObjectExplorerNodeProvider'
|
||||
}
|
||||
|
||||
|
||||
@@ -292,6 +292,7 @@ export enum DataProviderType {
|
||||
AgentServicesProvider = 'AgentServicesProvider',
|
||||
CapabilitiesProvider = 'CapabilitiesProvider',
|
||||
DacFxServicesProvider = 'DacFxServicesProvider',
|
||||
SchemaCompareServicesProvider = 'SchemaCompareServicesProvider',
|
||||
ObjectExplorerNodeProvider = 'ObjectExplorerNodeProvider'
|
||||
}
|
||||
|
||||
@@ -547,3 +548,19 @@ export class ConnectionProfile {
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export enum SchemaUpdateAction {
|
||||
Delete = 0,
|
||||
Change = 1,
|
||||
Add = 2
|
||||
}
|
||||
|
||||
export enum SchemaDifferenceType {
|
||||
Object = 0,
|
||||
Property = 1
|
||||
}
|
||||
|
||||
export enum SchemaCompareEndpointType {
|
||||
database = 0,
|
||||
dacpac = 1
|
||||
}
|
||||
|
||||
@@ -167,6 +167,12 @@ export class ExtHostDataProtocol extends ExtHostDataProtocolShape {
|
||||
return rt;
|
||||
}
|
||||
|
||||
$registerSchemaCompareServiceProvider(provider: azdata.SchemaCompareServicesProvider): vscode.Disposable {
|
||||
let rt = this.registerProvider(provider, DataProviderType.SchemaCompareServicesProvider);
|
||||
this._proxy.$registerSchemaCompareServicesProvider(provider.providerId, provider.handle);
|
||||
return rt;
|
||||
}
|
||||
|
||||
// Capabilities Discovery handlers
|
||||
$getServerCapabilities(handle: number, client: azdata.DataProtocolClientCapabilities): Thenable<azdata.DataProtocolServerCapabilities> {
|
||||
return this._resolveProvider<azdata.CapabilitiesProvider>(handle).getServerCapabilities(client);
|
||||
|
||||
@@ -26,6 +26,7 @@ import { ISerializationService } from 'sql/platform/serialization/common/seriali
|
||||
import { IFileBrowserService } from 'sql/platform/fileBrowser/common/interfaces';
|
||||
import { IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IDacFxService } from 'sql/platform/dacfx/common/dacFxService';
|
||||
import { ISchemaCompareService } from 'sql/platform/schemaCompare/common/schemaCompareService';
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
|
||||
/**
|
||||
@@ -57,6 +58,7 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape {
|
||||
@ISerializationService private _serializationService: ISerializationService,
|
||||
@IFileBrowserService private _fileBrowserService: IFileBrowserService,
|
||||
@IDacFxService private _dacFxService: IDacFxService,
|
||||
@ISchemaCompareService private _schemaCompareService: ISchemaCompareService,
|
||||
) {
|
||||
if (extHostContext) {
|
||||
this._proxy = extHostContext.getProxy(SqlExtHostContext.ExtHostDataProtocol);
|
||||
@@ -453,6 +455,20 @@ export class MainThreadDataProtocol implements MainThreadDataProtocolShape {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
public $registerSchemaCompareServicesProvider(providerId: string, handle: number): Promise<any> {
|
||||
const self = this;
|
||||
this._schemaCompareService.registerProvider(providerId, <azdata.SchemaCompareServicesProvider>{
|
||||
schemaCompare(sourceEndpointInfo: azdata.SchemaCompareEndpointInfo, targetEndpointInfo: azdata.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.SchemaCompareResult> {
|
||||
return self._proxy.$schemaCompare(handle, sourceEndpointInfo, targetEndpointInfo, taskExecutionMode);
|
||||
},
|
||||
schemaCompareGenerateScript(operationId: string, targetDatabaseName: string, scriptFilePath: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus> {
|
||||
return self._proxy.$schemaCompareGenerateScript(handle, operationId, targetDatabaseName, scriptFilePath, taskExecutionMode);
|
||||
}
|
||||
});
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
// Connection Management handlers
|
||||
public $onConnectionComplete(handle: number, connectionInfoSummary: azdata.ConnectionInfoSummary): void {
|
||||
this._connectionManagementService.onConnectionComplete(handle, connectionInfoSummary);
|
||||
|
||||
@@ -354,6 +354,10 @@ export function createApiFactory(
|
||||
return extHostDataProvider.$registerDacFxServiceProvider(provider);
|
||||
};
|
||||
|
||||
let registerSchemaCompareServicesProvider = (provider: azdata.SchemaCompareServicesProvider): vscode.Disposable => {
|
||||
return extHostDataProvider.$registerSchemaCompareServiceProvider(provider);
|
||||
};
|
||||
|
||||
// namespace: dataprotocol
|
||||
const dataprotocol: typeof azdata.dataprotocol = {
|
||||
registerBackupProvider,
|
||||
@@ -371,6 +375,7 @@ export function createApiFactory(
|
||||
registerAgentServicesProvider,
|
||||
registerCapabilitiesServiceProvider,
|
||||
registerDacFxServicesProvider,
|
||||
registerSchemaCompareServicesProvider,
|
||||
onDidChangeLanguageFlavor(listener: (e: azdata.DidChangeLanguageFlavorParams) => any, thisArgs?: any, disposables?: extHostTypes.Disposable[]) {
|
||||
return extHostDataProvider.onDidChangeLanguageFlavor(listener, thisArgs, disposables);
|
||||
},
|
||||
@@ -528,7 +533,10 @@ export function createApiFactory(
|
||||
nb: nb,
|
||||
AzureResource: sqlExtHostTypes.AzureResource,
|
||||
TreeItem: sqlExtHostTypes.TreeItem,
|
||||
extensions: extensions
|
||||
extensions: extensions,
|
||||
SchemaUpdateAction: sqlExtHostTypes.SchemaUpdateAction,
|
||||
SchemaDifferenceType: sqlExtHostTypes.SchemaDifferenceType,
|
||||
SchemaCompareEndpointType: sqlExtHostTypes.SchemaCompareEndpointType
|
||||
};
|
||||
},
|
||||
|
||||
@@ -754,6 +762,7 @@ export function createApiFactory(
|
||||
return extHostDataProvider.$registerDacFxServiceProvider(provider);
|
||||
};
|
||||
|
||||
|
||||
// namespace: dataprotocol
|
||||
const dataprotocol: typeof sqlops.dataprotocol = {
|
||||
registerBackupProvider,
|
||||
|
||||
@@ -455,6 +455,15 @@ export abstract class ExtHostDataProtocolShape {
|
||||
*/
|
||||
$generateDeployPlan(handle: number, packageFilePath: string, databaseName: string, ownerUri: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.GenerateDeployPlanResult> { throw ni(); }
|
||||
|
||||
/**
|
||||
* Schema compare
|
||||
*/
|
||||
$schemaCompare(handle: number, sourceEndpointInfo: azdata.SchemaCompareEndpointInfo, targetEndpointInfo: azdata.SchemaCompareEndpointInfo, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.SchemaCompareResult> { throw ni(); }
|
||||
|
||||
/**
|
||||
* Schema compare generate script
|
||||
*/
|
||||
$schemaCompareGenerateScript(handle: number, operationId: string, targetDatabaseName: string, scriptFilePath: string, taskExecutionMode: azdata.TaskExecutionMode): Thenable<azdata.ResultStatus> { throw ni(); }
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -524,6 +533,7 @@ export interface MainThreadDataProtocolShape extends IDisposable {
|
||||
$registerAdminServicesProvider(providerId: string, handle: number): Promise<any>;
|
||||
$registerAgentServicesProvider(providerId: string, handle: number): Promise<any>;
|
||||
$registerDacFxServicesProvider(providerId: string, handle: number): Promise<any>;
|
||||
$registerSchemaCompareServicesProvider(providerId: string, handle: number): Promise<any>;
|
||||
$unregisterProvider(handle: number): Promise<any>;
|
||||
$onConnectionComplete(handle: number, connectionInfoSummary: azdata.ConnectionInfoSummary): void;
|
||||
$onIntelliSenseCacheComplete(handle: number, connectionUri: string): void;
|
||||
|
||||
Reference in New Issue
Block a user