diff --git a/src/sql/parts/dashboard/common/dashboardPanelStyles.ts b/src/sql/parts/dashboard/common/dashboardPanelStyles.ts
index c25fc78688..15fef079bf 100644
--- a/src/sql/parts/dashboard/common/dashboardPanelStyles.ts
+++ b/src/sql/parts/dashboard/common/dashboardPanelStyles.ts
@@ -71,12 +71,12 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
}
// Panel title background
- const tabBoarder = theme.getColor(TAB_BORDER);
- if (tabBoarder) {
+ const tabBorder = theme.getColor(TAB_BORDER);
+ if (tabBorder) {
collector.addRule(`
panel.dashboard-panel > .tabbedPanel > .title .tabList .tab-header {
- border-right-color: ${tabBoarder};
- border-bottom-color: ${tabBoarder};
+ border-right-color: ${tabBorder};
+ border-bottom-color: ${tabBorder};
}
`);
}
@@ -86,13 +86,13 @@ registerThemingParticipant((theme: ITheme, collector: ICssStyleCollector) => {
if (outline) {
collector.addRule(`
panel.dashboard-panel > .tabbedPanel > .title {
- border-bottom-color: ${tabBoarder};
+ border-bottom-color: ${tabBorder};
border-bottom-width: 1px;
border-bottom-style: solid;
}
panel.dashboard-panel > .tabbedPanel.vertical > .title {
- border-right-color: ${tabBoarder};
+ border-right-color: ${tabBorder};
border-right-width: 1px;
border-right-style: solid;
}
diff --git a/src/sql/parts/modelComponents/card.component.html b/src/sql/parts/modelComponents/card.component.html
new file mode 100644
index 0000000000..48e5153d95
--- /dev/null
+++ b/src/sql/parts/modelComponents/card.component.html
@@ -0,0 +1,19 @@
+
+
+
+
+
+
{{label}}
+
{{value}}
+
+
+
+
+
\ No newline at end of file
diff --git a/src/sql/parts/modelComponents/card.component.ts b/src/sql/parts/modelComponents/card.component.ts
index 823053866c..89bbfb1aff 100644
--- a/src/sql/parts/modelComponents/card.component.ts
+++ b/src/sql/parts/modelComponents/card.component.ts
@@ -9,29 +9,37 @@ import { Component, Input, Inject, ChangeDetectorRef, forwardRef, ComponentFacto
} from '@angular/core';
import * as sqlops from 'sqlops';
+import { ITheme, ICssStyleCollector } from 'vs/platform/theme/common/themeService';
+import * as colors from 'vs/platform/theme/common/colorRegistry';
import { DashboardServiceInterface } from 'sql/parts/dashboard/services/dashboardServiceInterface.service';
import { ComponentBase } from 'sql/parts/modelComponents/componentBase';
-import { IComponent, IComponentDescriptor, IModelStore } from 'sql/parts/modelComponents/interfaces';
+import { IComponent, IComponentDescriptor, IModelStore, ComponentEventType } from 'sql/parts/modelComponents/interfaces';
+import { BOOTSTRAP_SERVICE_ID, IBootstrapService } from 'sql/services/bootstrap/bootstrapService';
+import { IColorTheme } from 'vs/workbench/services/themes/common/workbenchThemeService';
+import { StatusIndicator, CardProperties, ActionDescriptor } from 'sql/workbench/api/common/sqlExtHostTypes';
@Component({
- template: `
-
-
{{label}}
-
{{value}}
-
- `
+ templateUrl: decodeURI(require.toUrl('sql/parts/modelComponents/card.component.html'))
})
export default class CardComponent extends ComponentBase implements IComponent, OnDestroy {
@Input() descriptor: IComponentDescriptor;
@Input() modelStore: IModelStore;
- constructor(@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef) {
+ private backgroundColor: string;
+
+ constructor(@Inject(forwardRef(() => ChangeDetectorRef)) changeRef: ChangeDetectorRef,
+ @Inject(forwardRef(() => ElementRef)) private _el: ElementRef,
+ @Inject(BOOTSTRAP_SERVICE_ID) private _bootstrapService: IBootstrapService
+ ) {
super(changeRef);
}
ngOnInit(): void {
this.baseInit();
+ this._register(this._bootstrapService.themeService.onDidColorThemeChange(this.updateTheme, this));
+ this.updateTheme(this._bootstrapService.themeService.getColorTheme());
+
}
ngOnDestroy(): void {
@@ -52,15 +60,45 @@ export default class CardComponent extends ComponentBase implements IComponent,
// CSS-bound properties
public get label(): string {
- return this.getPropertyOrDefault((props) => props.label, '');
+ return this.getPropertyOrDefault((props) => props.label, '');
}
public get value(): string {
- return this.getPropertyOrDefault((props) => props.value, '');
+ return this.getPropertyOrDefault((props) => props.value, '');
}
- public get actions(): sqlops.ActionDescriptor[] {
- return this.getPropertyOrDefault((props) => props.actions, []);
+ public get actions(): ActionDescriptor[] {
+ return this.getPropertyOrDefault((props) => props.actions, []);
}
+ public hasStatus(): boolean {
+ let status = this.getPropertyOrDefault((props) => props.status, StatusIndicator.None);
+ return status !== StatusIndicator.None;
+ }
+
+ public get statusColor(): string {
+ let status = this.getPropertyOrDefault((props) => props.status, StatusIndicator.None);
+ switch(status) {
+ case StatusIndicator.Ok:
+ return 'green';
+ case StatusIndicator.Warning:
+ return 'orange';
+ case StatusIndicator.Error:
+ return 'red';
+ default:
+ return this.backgroundColor;
+ }
+ }
+
+ private updateTheme(theme: IColorTheme) {
+ this.backgroundColor = theme.getColor(colors.editorBackground, true).toString();
+ }
+
+ private onDidActionClick(action: ActionDescriptor): void {
+ this._onEventEmitter.fire({
+ eventType: ComponentEventType.onDidClick,
+ args: action
+ });
+
+ }
}
diff --git a/src/sql/parts/modelComponents/card.css b/src/sql/parts/modelComponents/card.css
index 29e21d6f0f..49aecafa0f 100644
--- a/src/sql/parts/modelComponents/card.css
+++ b/src/sql/parts/modelComponents/card.css
@@ -2,12 +2,9 @@
.model-card {
position: relative;
display: inline-block;
- height: auto;
+ height: 90%;
width: auto;
margin: 15px;
- padding: 10px 45px 20px 45px;
- min-height: 30px;
- min-width: 30px;
border-width: 1px;
border-style: solid;
border-color: rgb(214, 214, 214);
@@ -16,6 +13,16 @@
box-shadow: rgba(120, 120, 120, 0.75) 0px 0px 6px;
}
+.model-card .card-content {
+ position: relative;
+ display: inline-block;
+ height: auto;
+ width: auto;
+ padding: 10px 45px 20px 45px;
+ min-height: 30px;
+ min-width: 30px;
+}
+
.model-card .card-label {
font-size: 12px;
font-weight: bold;
@@ -24,4 +31,42 @@
.model-card .card-value {
font-size: 12px;
line-height: 18px;
-}
\ No newline at end of file
+}
+
+.model-card .card-status {
+ position: absolute;
+ top: 7px;
+ left: 5px;
+ overflow: hidden;
+ width: 22px;
+ height: 22px;
+}
+
+.model-card .status-content {
+ position: absolute;
+ top: 0px;
+ right: 0px;
+ min-width: 16px;
+ height: 16px;
+ border-radius: 8px;
+ text-align: center;
+}
+
+.model-card .model-table {
+ border-spacing: 5px;
+}
+
+.model-table .table-row {
+ width: auto;
+ clear: both;
+}
+
+.model-table .table-cell {
+ vertical-align: top;
+ padding: 7px;
+}
+
+.model-table a {
+ cursor: pointer;
+ text-decoration: underline
+}
diff --git a/src/sql/services/accountManagement/accountManagementService.ts b/src/sql/services/accountManagement/accountManagementService.ts
index 8d97c240ac..017a43c02a 100644
--- a/src/sql/services/accountManagement/accountManagementService.ts
+++ b/src/sql/services/accountManagement/accountManagementService.ts
@@ -142,7 +142,7 @@ export class AccountManagementService implements IAccountManagementService {
})
.then(null, err => {
// On error, check to see if the error is because the user cancelled. If so, just ignore
- if ('userCancelledSignIn' in err) {
+ if (err && 'userCancelledSignIn' in err) {
return Promise.resolve();
}
return Promise.reject(err);
diff --git a/src/sql/sqlops.proposed.d.ts b/src/sql/sqlops.proposed.d.ts
index cb340bbc45..b315cac59f 100644
--- a/src/sql/sqlops.proposed.d.ts
+++ b/src/sql/sqlops.proposed.d.ts
@@ -188,10 +188,24 @@ declare module 'sqlops' {
*/
label: string;
/**
- * ID of the task to be called when this is clicked on.
- * These should be registered using the {tasks.registerTask} API.
+ * Name of the clickable action. If not defined then no action will be shown
*/
- taskId: string;
+ actionTitle?: string;
+ /**
+ * Data sent on callback being run.
+ */
+ callbackData?: string;
+ }
+
+ /**
+ * Defines status indicators that can be shown to the user as part of
+ * components such as the Card UI
+ */
+ export enum StatusIndicator {
+ None = 0,
+ Ok = 1,
+ Warning = 2,
+ Error = 3
}
/**
@@ -202,6 +216,7 @@ declare module 'sqlops' {
label: string;
value?: string;
actions?: ActionDescriptor[];
+ status?: StatusIndicator;
}
export interface InputBoxProperties {
@@ -230,6 +245,7 @@ declare module 'sqlops' {
label: string;
value: string;
actions?: ActionDescriptor[];
+ onDidActionClick: vscode.Event;
}
export interface InputBoxComponent extends Component, InputBoxProperties {
diff --git a/src/sql/workbench/api/common/sqlExtHostTypes.ts b/src/sql/workbench/api/common/sqlExtHostTypes.ts
index 921db2e2b7..e97fb1589c 100644
--- a/src/sql/workbench/api/common/sqlExtHostTypes.ts
+++ b/src/sql/workbench/api/common/sqlExtHostTypes.ts
@@ -118,3 +118,26 @@ export interface IModelViewButtonDetails {
enabled: boolean;
hidden: boolean;
}
+
+/// Card-related APIs that need to be here to avoid early load issues
+// with enums causing requiring of sqlops API to fail.
+export enum StatusIndicator {
+ None = 0,
+ Ok = 1,
+ Warning = 2,
+ Error = 3
+}
+
+export interface CardProperties {
+ label: string;
+ value?: string;
+ actions?: ActionDescriptor[];
+ status?: StatusIndicator;
+}
+
+export interface ActionDescriptor {
+ label: string;
+ actionTitle?: string;
+ callbackData?: string;
+}
+
diff --git a/src/sql/workbench/api/node/extHostModelView.ts b/src/sql/workbench/api/node/extHostModelView.ts
index 43519a6559..8ffae9e542 100644
--- a/src/sql/workbench/api/node/extHostModelView.ts
+++ b/src/sql/workbench/api/node/extHostModelView.ts
@@ -14,6 +14,7 @@ import * as sqlops from 'sqlops';
import { SqlMainContext, ExtHostModelViewShape, MainThreadModelViewShape } from 'sql/workbench/api/node/sqlExtHost.protocol';
import { IItemConfig, ModelComponentTypes, IComponentShape, IComponentEventArgs, ComponentEventType } from 'sql/workbench/api/common/sqlExtHostTypes';
+import { IActionDescriptor } from 'vs/editor/standalone/browser/standaloneCodeEditor';
class ModelBuilderImpl implements sqlops.ModelBuilder {
private nextComponentId: number;
@@ -306,7 +307,7 @@ class ComponentWrapper implements sqlops.Component {
} else if (eventArgs) {
let emitter = this._emitterMap.get(eventArgs.eventType);
if (emitter) {
- emitter.fire();
+ emitter.fire(eventArgs.args);
}
}
}
@@ -362,6 +363,7 @@ class CardWrapper extends ComponentWrapper implements sqlops.CardComponent {
constructor(proxy: MainThreadModelViewShape, handle: number, id: string) {
super(proxy, handle, ModelComponentTypes.Card, id);
this.properties = {};
+ this._emitterMap.set(ComponentEventType.onDidClick, new Emitter());
}
public get label(): string {
@@ -382,6 +384,11 @@ class CardWrapper extends ComponentWrapper implements sqlops.CardComponent {
public set actions(a: sqlops.ActionDescriptor[]) {
this.setProperty('actions', a);
}
+
+ public get onDidActionClick(): vscode.Event {
+ let emitter = this._emitterMap.get(ComponentEventType.onDidClick);
+ return emitter && emitter.event;
+ }
}
class InputBoxWrapper extends ComponentWrapper implements sqlops.InputBoxComponent {
diff --git a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts
index 8569b31930..f904642a9e 100644
--- a/src/sql/workbench/api/node/sqlExtHost.api.impl.ts
+++ b/src/sql/workbench/api/node/sqlExtHost.api.impl.ts
@@ -365,7 +365,8 @@ export function createApiFactory(
dashboard,
workspace,
queryeditor: queryEditor,
- ui: ui
+ ui: ui,
+ StatusIndicator: sqlExtHostTypes.StatusIndicator
};
}
};