diff --git a/ngapp/src/app/dataservices/dataservices.module.ts b/ngapp/src/app/dataservices/dataservices.module.ts
index ffde9b36..875abbaf 100644
--- a/ngapp/src/app/dataservices/dataservices.module.ts
+++ b/ngapp/src/app/dataservices/dataservices.module.ts
@@ -77,6 +77,7 @@ import { CreateViewsDialogComponent } from './create-views-dialog/create-views-d
import { SetDescriptionDialogComponent } from "@dataservices/set-description-dialog/set-description-dialog.component";
import { PropertyEditorComponent } from './virtualization/view-editor/view-property-editors/property-editor/property-editor.component';
import { ProjectedColumnsEditorComponent } from './virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component';
+import { ViewsListComponent} from './virtualization/view-editor/views-list/views-list.component';
@NgModule({
imports: [
@@ -133,7 +134,8 @@ import { ProjectedColumnsEditorComponent } from './virtualization/view-editor/vi
CreateViewsDialogComponent,
SetDescriptionDialogComponent,
PropertyEditorComponent,
- ProjectedColumnsEditorComponent
+ ProjectedColumnsEditorComponent,
+ ViewsListComponent
],
providers: [
{
diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts
index b13c550f..ef0addca 100644
--- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts
+++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/canvas.service.ts
@@ -171,6 +171,8 @@ export class CanvasService {
}
public clear(): void {
+ if (this.canvasGraph == null)
+ return;
this.canvasGraph.clear();
}
diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css
index 50bca7a7..b521ac0d 100644
--- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css
+++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.css
@@ -4,8 +4,8 @@
#view-editor-canvas-editor {
display: grid;
grid-template-areas:
- "canvas-editor properties-editor";
- grid-template-columns: 50fr 50fr;
+ "views-list-panel canvas-editor properties-editor";
+ grid-template-columns: 20fr 50fr 30fr;
height: 100%;
}
@@ -17,6 +17,13 @@
grid-area: canvas-editor;
}
+/*
+ * Views List Panel
+ */
+#views-list-container {
+ grid-area: views-list-panel;
+}
+
/*
* Configures the alert when view has no sources.
*/
diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html
index e7d6709b..555f09bf 100644
--- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html
+++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.html
@@ -1,5 +1,10 @@
+
+
diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts
index 7ab84fb1..ebb1dee8 100644
--- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts
+++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/view-canvas.component.spec.ts
@@ -21,12 +21,15 @@ import { VdbService } from "@dataservices/shared/vdb.service";
import { MockVdbService } from "@dataservices/shared/mock-vdb.service";
import { NotifierService } from "@dataservices/shared/notifier.service";
import { ViewPropertyEditorsComponent } from "@dataservices/virtualization/view-editor/view-property-editors/view-property-editors.component";
-import { TabsModule } from "ngx-bootstrap";
+import { TabsModule} from "ngx-bootstrap";
import { GraphVisualComponent, LinkVisualComponent, NodeVisualComponent } from "@dataservices/virtualization/view-editor/view-canvas/visuals";
import { CanvasService } from "@dataservices/virtualization/view-editor/view-canvas/canvas.service";
import { SelectionService } from "@core/selection.service";
import { PropertyEditorComponent } from "@dataservices/virtualization/view-editor/view-property-editors/property-editor/property-editor.component";
import { ProjectedColumnsEditorComponent } from "@dataservices/virtualization/view-editor/view-property-editors/projected-columns-editor/projected-columns-editor.component";
+import { ViewsListComponent } from "@dataservices/virtualization/view-editor/views-list/views-list.component";
+import { BsModalService } from "ngx-bootstrap";
+import { Dataservice } from "@dataservices/shared/dataservice.model";
describe('ViewCanvasComponent', () => {
let component: ViewCanvasComponent;
@@ -54,9 +57,11 @@ describe('ViewCanvasComponent', () => {
ProjectedColumnsEditorComponent,
PropertyEditorComponent,
ViewCanvasComponent,
- ViewPropertyEditorsComponent
+ ViewPropertyEditorsComponent,
+ ViewsListComponent
],
providers: [
+ BsModalService,
{ provide: AppSettingsService, useClass: MockAppSettingsService },
{ provide: DataserviceService, useClass: MockDataserviceService },
CanvasService,
@@ -75,6 +80,14 @@ describe('ViewCanvasComponent', () => {
beforeEach(() => {
fixture = TestBed.createComponent(ViewCanvasComponent);
component = fixture.componentInstance;
+
+ const selService = TestBed.get( SelectionService );
+ const ds: Dataservice = new Dataservice();
+ ds.setId("testDs");
+ ds.setServiceVdbName("testDsVdb");
+ // noinspection JSUnusedAssignment
+ selService.setSelectedVirtualization( ds );
+
fixture.detectChanges();
});
diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts
index 667d8495..68a7cb7f 100644
--- a/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts
+++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-canvas/visuals/node/node-visual.component.ts
@@ -77,7 +77,7 @@ export class NodeVisualComponent {
public get icon(): string {
if (this.node.type === CanvasConstants.SOURCE_TYPE)
- return "/assets/graphicsfuel/database-64.png";
+ return "/assets/table.png";
else if (this.node.type === CanvasConstants.COMPOSITION_TYPE)
return "/assets/composition.png";
diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css
index 828d08cd..9b87ebfc 100644
--- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css
+++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.css
@@ -1,60 +1,3 @@
-/*
- * The view description textarea.
- */
-#view-editor-header-description-input {
- max-width: max-content;
- min-height: 20px;
- min-width: 400px;
- vertical-align: top;
-}
-
-.list-pf-container {
- -ms-flex-align: start;
- align-items: flex-start;
- display: -ms-flexbox;
- display: flex;
- padding: 0;
-}
-
-.view-table-div {
- padding-left: 0;
- padding-right: 0;
- margin-bottom: 5px;
- min-height: 70px;
- max-height: 70px;
- border: 1px inset grey;
- overflow-y: auto;
-}
-
-.view-editor-header-name-input {
- padding-left: 0;
- padding-right: 5px;
-}
-
-.view-editor-header-create-button {
- margin-left: 0;
- padding-left: 0;
- padding-top: 8px;
-}
-
-.view-editor-header-delete-button {
- padding-left: 0;
- padding-top: 8px;
-}
-
-.view-editor-header-description-area {
- padding-left: 0;
- margin-left: 0;
-}
-
-/*
- * A div containing an input field in the header.
- */
-.view-editor-header-input-div {
- margin: 1px;
- padding: 1px;
-}
-
/*
* A type for the header title
*/
@@ -62,49 +5,3 @@
margin-left: 10px;
}
-/*
- * A type for vertically aligned labels in the header.
- */
-.view-editor-header-label {
- margin: 2px;
- padding: 2px;
-}
-
-/*
- * The checkbox that shows/hides the virtualization description.
- */
-#view-editor-header-show-description {
- margin-right: 4px;
-}
-
-/*
- * The label for the checkbox that shows/hides the view description.
- */
-#view-editor-header-show-description-label {
- margin-top: 2px;
- text-align: left;
-}
-
-/*
- * The label where the virtualization name is the content.
- */
-#view-editor-header-virtualization-name {
- text-align: left;
-}
-
-/*
- * Style the empty state component so that it is centered and extends the entire width.
- */
-#view-editor-header-table .blank-slate-pf {
- background-color: inherit;
- min-width: 200px;
- border: none;
- padding: 0;
-}
-
-/*
- * Style text in blank slate for table
- */
-#view-editor-header-table h1, .h1 {
- font-size: 14px;
-}
diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html
index bd386954..6167371c 100644
--- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html
+++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.html
@@ -4,57 +4,7 @@
-
-
-
-
-
diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts
index 0a733e60..bb46a189 100644
--- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts
+++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor-header/view-editor-header.component.ts
@@ -16,25 +16,7 @@
*/
import { Component, OnDestroy, OnInit, ViewEncapsulation } from "@angular/core";
-import { LoggerService } from "@core/logger.service";
-import { ViewEditorPart } from "@dataservices/virtualization/view-editor/view-editor-part.enum";
import { ViewEditorService } from "@dataservices/virtualization/view-editor/view-editor.service";
-import { ViewEditorEvent } from "@dataservices/virtualization/view-editor/event/view-editor-event";
-import { ViewEditorI18n } from "@dataservices/virtualization/view-editor/view-editor-i18n";
-import { CommandFactory } from "@dataservices/virtualization/view-editor/command/command-factory";
-import { Subscription } from "rxjs/Subscription";
-import { Command } from "@dataservices/virtualization/view-editor/command/command";
-import { EmptyStateConfig, NgxDataTableConfig, TableConfig } from "patternfly-ng";
-import { ViewDefinition } from "@dataservices/shared/view-definition.model";
-import { BsModalService } from "ngx-bootstrap";
-import { CreateViewDialogComponent } from "@dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component";
-import { DataserviceService } from "@dataservices/shared/dataservice.service";
-import { LoadingState } from "@shared/loading-state.enum";
-import { ConfirmDialogComponent } from "@shared/confirm-dialog/confirm-dialog.component";
-import { SelectionService } from "@core/selection.service";
-import { ViewEditorState } from "@dataservices/shared/view-editor-state.model";
-import { Dataservice } from "@dataservices/shared/dataservice.model";
-import { ViewEditorProgressChangeId } from "@dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum";
@Component({
encapsulation: ViewEncapsulation.None,
@@ -44,151 +26,23 @@ import { ViewEditorProgressChangeId } from "@dataservices/virtualization/view-ed
})
export class ViewEditorHeaderComponent implements OnInit, OnDestroy {
- // used by html
- public readonly viewDescriptionLabel = ViewEditorI18n.viewDescriptionLabel;
- public readonly viewDescriptionPlaceholder = ViewEditorI18n.viewDescriptionPlaceholder;
-
- public ngxTableConfig: NgxDataTableConfig;
- public tableConfig: TableConfig;
- public tableColumns: any[] = [];
- public tableRows: ViewDefinition[] = [];
- private emptyStateConfig: EmptyStateConfig;
-
- private readonly logger: LoggerService;
private readonly editorService: ViewEditorService;
- private subscription: Subscription;
- private modalService: BsModalService;
- private dataserviceService: DataserviceService;
- private selectionService: SelectionService;
- private viewsLoadingState: LoadingState = LoadingState.LOADING;
- private selectedVirtualization: Dataservice;
- private viewSavedUponCompletion: ViewDefinition;
- constructor( editorService: ViewEditorService,
- dataserviceService: DataserviceService,
- selectionService: SelectionService,
- logger: LoggerService,
- modalService: BsModalService) {
+ constructor( editorService: ViewEditorService) {
this.editorService = editorService;
- this.dataserviceService = dataserviceService;
- this.selectionService = selectionService;
- this.logger = logger;
- this.modalService = modalService;
- }
-
- /**
- * @param {ViewEditorEvent} event the event being processed
- */
- public handleEditorEvent( event: ViewEditorEvent ): void {
- this.logger.debug( "ViewEditorHeaderComponent received event: " + event.toString() );
-
- if ( event.typeIsEditorViewSaveProgressChanged() ) {
- if ( event.args.length !== 0 ) {
- // Detect changes in view editor save progress
- if ( event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_SUCCESS ||
- event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_FAILED ) {
- if (this.viewSavedUponCompletion && this.viewSavedUponCompletion !== null) {
- this.createNewView(this.viewSavedUponCompletion);
- }
- }
- }
- }
}
/**
* Cleanup code when destroying the view editor header.
*/
public ngOnDestroy(): void {
- this.subscription.unsubscribe();
+
}
/**
* Initialization code run after construction.
*/
public ngOnInit(): void {
- this.subscription = this.editorService.editorEvent.subscribe( ( event ) => this.handleEditorEvent( event ) );
-
- // ----------------------------------
- // View Table configurations
- // ----------------------------------
- this.tableColumns = [
- {
- draggable: false,
- name: "Views",
- prop: "viewName",
- resizeable: true,
- sortable: false,
- width: "100"
- }
- ];
-
- this.ngxTableConfig = {
- headerHeight: 0,
- rowHeight: 20,
- reorderable: false,
- selectionType: "'single'"
- } as NgxDataTableConfig;
-
- this.emptyStateConfig = {
- title: ViewEditorI18n.noViewsDefined
- } as EmptyStateConfig;
-
- this.tableConfig = {
- emptyStateConfig: this.emptyStateConfig
- } as TableConfig;
-
- // init the available views
- this.initViews();
- }
-
- /*
- * Initialize the views for the current dataservice. Makes a rest call to get the ViewEditorStates for the serviceVdb
- */
- private initViews( ): void {
- this.viewsLoadingState = LoadingState.LOADING;
- this.selectedVirtualization = this.selectionService.getSelectedVirtualization();
- if ( !this.selectedVirtualization || this.selectedVirtualization === null ) {
- this.tableRows = [];
- }
-
- const selectedView = this.selectionService.getSelectedViewDefinition();
-
- const vdbName = this.selectedVirtualization.getServiceVdbName();
- const editorStatesPattern = vdbName.toLowerCase() + "*";
-
- const self = this;
- this.dataserviceService
- .getViewEditorStates(editorStatesPattern)
- .subscribe(
- (viewEditorStates) => {
- const viewDefns: ViewDefinition[] = [];
- for ( const viewState of viewEditorStates ) {
- const viewDefn = viewState.getViewDefinition();
- if ( viewDefn ) {
- viewDefns.push( viewDefn );
- }
- }
- self.tableRows = viewDefns.sort( (left, right): number => {
- if (left.getName() < right.getName()) return -1;
- if (left.getName() > right.getName()) return 1;
- return 0;
- });
-
- let initialView: ViewDefinition = null;
- if (!selectedView || selectedView === null) {
- initialView = (self.tableRows && self.tableRows.length > 0) ? self.tableRows[0] : null;
- } else {
- initialView = self.tableRows.find((x) => x.getName() === selectedView.getName());
- }
- self.viewsLoadingState = LoadingState.LOADED_VALID;
- self.selectView(initialView);
- },
- (error) => {
- self.logger.error("[VirtualizationComponent] Error updating the views for the virtualization: %o", error);
- self.viewsLoadingState = LoadingState.LOADED_INVALID;
- self.tableRows = [];
- }
- );
}
/**
@@ -198,55 +52,6 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy {
return !this.editorService.getEditorView() || this.editorService.isReadOnly();
}
- /**
- * @returns {boolean} `true` if views are being loaded
- */
- public get viewsLoading(): boolean {
- return this.viewsLoadingState === LoadingState.LOADING;
- }
-
- /**
- * @returns {string} the view description
- */
- public get viewDescription(): string {
- if ( this.editorService.getEditorView() ) {
- return this.editorService.getEditorView().getDescription();
- }
-
- return "";
- }
-
- /**
- * @param {string} newDescription the new description
- */
- public set viewDescription( newDescription: string ) {
- if ( this.editorService.getEditorView() ) {
- if ( newDescription !== this.editorService.getEditorView().getDescription() ) {
- const oldDescription = this.editorService.getEditorView().getDescription();
- const temp = CommandFactory.createUpdateViewDescriptionCommand( newDescription, oldDescription );
-
- if ( temp instanceof Command ) {
- this.editorService.fireViewStateHasChanged( ViewEditorPart.HEADER, temp as Command );
- } else {
- const error = temp as Error;
- this.logger.error( error.message );
- }
- }
- } else {
- // shouldn't get here as description text input should be disabled if no view being edited
- this.logger.error( "Trying to set description but there is no view being edited" );
- }
- }
-
- /**
- * Called when text in the view description textarea changes.
- *
- * @param {string} newDescription the new description of the view
- */
- public viewDescriptionChanged( newDescription: string ): void {
- this.viewDescription = newDescription;
- }
-
/**
* @returns {string} the name of the dataservice of the view being edited
*/
@@ -260,233 +65,4 @@ export class ViewEditorHeaderComponent implements OnInit, OnDestroy {
// should always have a virtualization name so shouldn't get here
return "< error >";
}
-
- /**
- * @returns {string} the description of the dataservice of the view being edited
- */
- public get virtualizationDescription(): string {
- const virtualization = this.editorService.getEditorVirtualization();
-
- if ( virtualization ) {
- return virtualization.getDescription();
- }
-
- // should always have a virtualization description so shouldn't get here
- return "< error >";
- }
-
- public get deleteViewButtonEnabled(): boolean {
- return ( this.getSelectedView() !== null );
- }
-
- /**
- * Handles view selection from table
- * @param $event
- */
- public viewSelectionChanged( $event ): void {
- const selectedViews: ViewDefinition[] = $event.selected;
- // If the current view has pending changes, auto save it
- if ( this.editorService.hasChanges() ) {
- this.editorService.saveEditorState();
- }
- this.selectView(selectedViews[0]);
- }
-
- /**
- * Handle creation of a new View. Displays the createView dialog,
- * then saves the viewDefinition and adds it to the list
- */
- public onCreateView(): void {
- // Open New View dialog
- const initialState = {
- title: ViewEditorI18n.createViewDialogTitle,
- cancelButtonText: ViewEditorI18n.cancelButtonText,
- okButtonText: ViewEditorI18n.okButtonText
- };
-
- // Show Dialog, act upon confirmation click
- const modalRef = this.modalService.show(CreateViewDialogComponent, {initialState});
- modalRef.content.okAction.take(1).subscribe((viewDefn) => {
- // If the current view has pending changes, save them first
- if ( this.editorService.hasChanges() ) {
- this.viewSavedUponCompletion = viewDefn;
- this.editorService.saveEditorState();
- } else {
- this.createNewView(viewDefn);
- }
- // addition of a view undeploys active serviceVdb
- this.editorService.undeploySelectedVirtualization();
- });
- }
-
- private createNewView(viewDefn: ViewDefinition): void {
- const selectedDs = this.selectionService.getSelectedVirtualization();
- const editorId = this.getEditorStateId(selectedDs, viewDefn);
-
- // Create new editor state to save
- const editorState = new ViewEditorState();
- editorState.setId(editorId);
- editorState.setViewDefinition(viewDefn);
-
- const editorStates: ViewEditorState[] = [];
- editorStates.push(editorState);
-
- this.viewsLoadingState = LoadingState.LOADING;
-
- const self = this;
- this.dataserviceService
- .saveViewEditorStatesRefreshViews(editorStates, selectedDs.getId())
- .subscribe(
- (wasSuccess) => {
- // Add the new ViewDefinition to the table
- self.addViewDefinitionToList(viewDefn);
- self.viewSavedUponCompletion = null;
- self.viewsLoadingState = LoadingState.LOADED_VALID;
- },
- (error) => {
- self.logger.error("[VirtualizationComponent] Error saving the editor state: %o", error);
- self.viewSavedUponCompletion = null;
- self.viewsLoadingState = LoadingState.LOADED_INVALID;
- }
- );
- }
-
- /**
- * Construct id for the editor state
- * @param {Dataservice} dataservice the dataservice
- * @param {ViewDefinition} viewDefn the view definition
- * @returns {string} the ID used to persist the editor state
- */
- private getEditorStateId(dataservice: Dataservice, viewDefn: ViewDefinition): string {
- return dataservice.getServiceVdbName().toLowerCase() + "." + viewDefn.getName();
- }
-
- /**
- * Handle Delete of the selected View
- * @param {string} viewName
- */
- public onDeleteView( ): void {
- const viewName = this.getSelectedView().getName();
-
- // Dialog Content
- const message = "Do you really want to delete View '" + viewName + "'?";
- const initialState = {
- title: "Confirm Delete",
- bodyContent: message,
- cancelButtonText: "Cancel",
- confirmButtonText: "Delete"
- };
-
- // Show Dialog, act upon confirmation click
- const modalRef = this.modalService.show(ConfirmDialogComponent, {initialState});
- modalRef.content.confirmAction.take(1).subscribe((value) => {
- this.doDeleteView(viewName);
- });
- }
-
- /**
- * Deletes the specified ViewEditorState from the userProfile, and removes ViewDefinition from the current list.
- * @param {string} viewDefnName the name of the view
- */
- private doDeleteView(viewDefnName: string): void {
- const selectedViewDefn = this.tableRows.find((x) => x.getName() === viewDefnName);
- const selectedDs = this.selectionService.getSelectedVirtualization();
- const vdbName = selectedDs.getServiceVdbName();
- const editorStateId = vdbName.toLowerCase() + "." + viewDefnName;
- const dataserviceName = selectedDs.getId();
-
- this.viewsLoadingState = LoadingState.LOADING;
- // Note: we can only doDelete selected items that we can see in the UI.
- this.logger.debug("[VirtualizationComponent] Deleting selected Virtualization View.");
- const self = this;
- this.dataserviceService
- .deleteViewEditorStateRefreshViews(editorStateId, dataserviceName)
- .subscribe(
- (wasSuccess) => {
- self.removeViewDefinitionFromList(selectedViewDefn);
- // deletion of a view undeploys active serviceVdb
- self.editorService.undeploySelectedVirtualization();
- this.viewsLoadingState = LoadingState.LOADED_VALID;
- },
- (error) => {
- self.logger.error("[VirtualizationComponent] Error deleting the editor state: %o", error);
- this.viewsLoadingState = LoadingState.LOADED_INVALID;
- }
- );
- }
-
- /*
- * Add the specified ViewDefinition to the view definitions table
- * @param {ViewDefinition} viewDefn the view definition to add
- */
- private addViewDefinitionToList(viewDefn: ViewDefinition): void {
- const newRows: ViewDefinition[] = [];
- newRows.push(viewDefn);
- for ( const row of this.tableRows ) {
- if ( row.getName() !== viewDefn.getName() ) {
- newRows.push( row );
- }
- }
- this.tableRows = newRows.sort( (left, right): number => {
- if (left.getName() < right.getName()) return -1;
- if (left.getName() > right.getName()) return 1;
- return 0;
- });
- this.selectView(viewDefn);
- }
-
- /*
- * Remove the specified ViewDefinition from the view definitions table
- * @param {ViewDefinition} viewDefn the view definition to remove
- */
- private removeViewDefinitionFromList(viewDefn: ViewDefinition): void {
- const origIndex = this.tableRows.findIndex( ( defn ) => defn.getName() === viewDefn.getName() );
-
- const newRows: ViewDefinition[] = [];
- for ( const row of this.tableRows ) {
- if ( row.getName() !== viewDefn.getName() ) {
- newRows.push( row );
- }
- }
- this.tableRows = newRows;
-
- // auto select another row
- if ( this.tableRows.length > origIndex ) {
- this.selectView( this.tableRows[origIndex] );
- } else if ( this.tableRows.length > 0 ) {
- this.selectView( this.tableRows[origIndex - 1] );
- } else if ( this.tableRows.length === 0 ) {
- this.selectView( null );
- }
- }
-
- private selectView( selView: ViewDefinition ): void {
- // Updates table selection display
- let viewSelection = null;
- if ( selView && selView !== null ) {
- for (const view of this.tableRows) {
- if (view.getName() === selView.getName()) {
- view.setSelected(true);
- viewSelection = view;
- } else {
- view.setSelected(false);
- }
- }
- }
- // Update selection service, then fire event
- this.selectionService.setSelectedViewDefinition(this.selectedVirtualization, viewSelection);
- this.editorService.setEditorView(viewSelection, ViewEditorPart.HEADER);
- }
-
- private getSelectedView( ): ViewDefinition {
- let selectedView: ViewDefinition = null;
- for (const view of this.tableRows) {
- if (view.selected) {
- selectedView = view;
- break;
- }
- }
- return selectedView;
- }
-
}
diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css
index 8cae6216..9a69e1f9 100644
--- a/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css
+++ b/ngapp/src/app/dataservices/virtualization/view-editor/view-editor.component.css
@@ -90,6 +90,8 @@
*/
#view-editor-toolbar .form-group {
margin: 2px;
+ padding-left: 5px;
+ padding-right: 5px;
}
/*
@@ -99,7 +101,7 @@
background-color: inherit;
border: none;
box-shadow: none;
- padding: 0;
+ padding: 0px;
}
/*
diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.css b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.css
new file mode 100644
index 00000000..c0ccdd80
--- /dev/null
+++ b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.css
@@ -0,0 +1,79 @@
+.list-pf-container {
+ -ms-flex-align: start;
+ align-items: flex-start;
+ display: -ms-flexbox;
+ display: flex;
+ padding: 0;
+}
+
+.views-list-title {
+ padding-left: 10px;
+ text-align: left;
+}
+
+.create-delete-buttons {
+ horiz-align: left;
+ padding-top: 5px;
+ padding-bottom: 5px;
+ grid-row-gap: 1px;
+ vertical-align: middle;
+}
+
+.views-list-create-button {
+ margin-left: 0px;
+ padding-left: 0;
+ padding-top: 8px;
+ padding-bottom: 8px;
+ background-color: aquamarine;
+}
+
+.views-list-delete-button {
+ padding-left: 0px;
+ padding-top: 8px;
+ padding-bottom: 8px;
+}
+
+.views-list-description-area {
+ padding-left: 0;
+ margin-left: 0;
+}
+
+.views-list-div {
+ padding-left: 1px;
+ padding-right: 1px;
+ margin-bottom: 5px;
+ min-height: 400px;
+ max-height: 400px;
+ height: 100%;
+ width: 100%;
+ border: 1px inset grey;
+ overflow-y: auto;
+}
+
+/*
+ * Style the empty state component so that it is centered and extends the entire width.
+ */
+#views-list-table .blank-slate-pf {
+ background-color: inherit;
+ min-width: 200px;
+ border: none;
+ padding: 0;
+ min-height: 400px;
+ max-height: 400px;
+}
+
+/*
+ * Style text in blank slate for table
+ */
+#views-list-table h1, .h1 {
+ font-size: 14px;
+}
+
+/*
+ * The view description text area.
+ */
+#views-list-description-input {
+ min-height: 20px;
+ min-width: 300px;
+ vertical-align: top;
+}
diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.html b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.html
new file mode 100644
index 00000000..18ccdd3b
--- /dev/null
+++ b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.html
@@ -0,0 +1,37 @@
+
diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.spec.ts b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.spec.ts
new file mode 100644
index 00000000..50ea4c2c
--- /dev/null
+++ b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.spec.ts
@@ -0,0 +1,66 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { ViewsListComponent } from './views-list.component';
+import {SelectionService} from "@core/selection.service";
+import {Dataservice} from "@dataservices/shared/dataservice.model";
+import {ViewEditorService} from "@dataservices/virtualization/view-editor/view-editor.service";
+import {MockAppSettingsService} from "@core/mock-app-settings.service";
+import {LoggerService} from "@core/logger.service";
+import {AppSettingsService} from "@core/app-settings.service";
+import {DataserviceService} from "@dataservices/shared/dataservice.service";
+import {MockVdbService} from "@dataservices/shared/mock-vdb.service";
+import {BsModalService, ComponentLoaderFactory} from "ngx-bootstrap";
+import {MockDataserviceService} from "@dataservices/shared/mock-dataservice.service";
+import {NotifierService} from "@dataservices/shared/notifier.service";
+import {VdbService} from "@dataservices/shared/vdb.service";
+import {HttpModule} from "@angular/http";
+import {FormsModule} from "@angular/forms";
+import {TableModule} from "patternfly-ng";
+import {RouterTestingModule} from "@angular/router/testing";
+
+describe('ViewsListComponent', () => {
+ let component: ViewsListComponent;
+ let fixture: ComponentFixture
;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [
+ FormsModule,
+ HttpModule,
+ RouterTestingModule,
+ TableModule
+ ],
+ declarations: [ ViewsListComponent ],
+ providers: [
+ BsModalService,
+ { provide: AppSettingsService, useClass: MockAppSettingsService },
+ { provide: DataserviceService, useClass: MockDataserviceService },
+ LoggerService,
+ NotifierService,
+ SelectionService,
+ { provide: VdbService, useClass: MockVdbService },
+ ComponentLoaderFactory,
+ ViewEditorService
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(ViewsListComponent);
+ component = fixture.componentInstance;
+
+ const selService = TestBed.get( SelectionService );
+ const ds: Dataservice = new Dataservice();
+ ds.setId("testDs");
+ ds.setServiceVdbName("testDsVdb");
+ // noinspection JSUnusedAssignment
+ selService.setSelectedVirtualization( ds );
+
+ fixture.detectChanges();
+ });
+
+ it('should be created', () => {
+ expect(component).toBeTruthy();
+ });
+});
diff --git a/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts
new file mode 100644
index 00000000..4ab1a34a
--- /dev/null
+++ b/ngapp/src/app/dataservices/virtualization/view-editor/views-list/views-list.component.ts
@@ -0,0 +1,468 @@
+/**
+ * @license
+ * Copyright 2017 JBoss Inc
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import {AfterViewInit, Component, OnDestroy, OnInit, ViewEncapsulation} from '@angular/core';
+import {LoadingState} from "@shared/loading-state.enum";
+import {ViewDefinition} from "@dataservices/shared/view-definition.model";
+import {ViewEditorPart} from "@dataservices/virtualization/view-editor/view-editor-part.enum";
+import {EmptyStateConfig, NgxDataTableConfig, TableConfig} from "patternfly-ng";
+import {ViewEditorI18n} from "@dataservices/virtualization/view-editor/view-editor-i18n";
+import {ViewEditorProgressChangeId} from "@dataservices/virtualization/view-editor/event/view-editor-save-progress-change-id.enum";
+import {ViewEditorState} from "@dataservices/shared/view-editor-state.model";
+import {ViewEditorService} from "@dataservices/virtualization/view-editor/view-editor.service";
+import {Dataservice} from "@dataservices/shared/dataservice.model";
+import {LoggerService} from "@core/logger.service";
+import {ViewEditorEvent} from "@dataservices/virtualization/view-editor/event/view-editor-event";
+import {Subscription} from "rxjs/Subscription";
+import {BsModalService} from "ngx-bootstrap";
+import {DataserviceService} from "@dataservices/shared/dataservice.service";
+import {SelectionService} from "@core/selection.service";
+import {ConfirmDialogComponent} from "@shared/confirm-dialog/confirm-dialog.component";
+import {CommandFactory} from "@dataservices/virtualization/view-editor/command/command-factory";
+import {Command} from "@dataservices/virtualization/view-editor/command/command";
+import {CreateViewDialogComponent} from "@dataservices/virtualization/view-editor/create-view-dialog/create-view-dialog.component";
+
+@Component({
+ encapsulation: ViewEncapsulation.None,
+ selector: 'app-views-list',
+ templateUrl: './views-list.component.html',
+ styleUrls: ['./views-list.component.css']
+})
+export class ViewsListComponent implements OnInit, OnDestroy, AfterViewInit {
+
+ // used by html
+ public readonly viewDescriptionLabel = ViewEditorI18n.viewDescriptionLabel;
+ public readonly viewDescriptionPlaceholder = ViewEditorI18n.viewDescriptionPlaceholder;
+
+ public ngxTableConfig: NgxDataTableConfig;
+ public tableConfig: TableConfig;
+ public tableColumns: any[] = [];
+ public tableRows: ViewDefinition[] = [];
+ private emptyStateConfig: EmptyStateConfig;
+
+ private readonly logger: LoggerService;
+ private readonly editorService: ViewEditorService;
+ private subscription: Subscription;
+ private modalService: BsModalService;
+ private dataserviceService: DataserviceService;
+ private selectionService: SelectionService;
+ private viewsLoadingState: LoadingState = LoadingState.LOADING;
+ private selectedVirtualization: Dataservice;
+ private viewSavedUponCompletion: ViewDefinition;
+
+ constructor( editorService: ViewEditorService,
+ dataserviceService: DataserviceService,
+ selectionService: SelectionService,
+ logger: LoggerService,
+ modalService: BsModalService) {
+ this.editorService = editorService;
+ this.dataserviceService = dataserviceService;
+ this.selectionService = selectionService;
+ this.logger = logger;
+ this.modalService = modalService;
+ }
+
+ /**
+ * @param {ViewEditorEvent} event the event being processed
+ */
+ public handleEditorEvent( event: ViewEditorEvent ): void {
+ this.logger.debug( "ViewsListComponent received event: " + event.toString() );
+
+ if ( event.typeIsEditorViewSaveProgressChanged() ) {
+ if ( event.args.length !== 0 ) {
+ // Detect changes in view editor save progress
+ if ( event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_SUCCESS ||
+ event.args[ 0 ] === ViewEditorProgressChangeId.COMPLETED_FAILED ) {
+ if (this.viewSavedUponCompletion && this.viewSavedUponCompletion !== null) {
+ this.createNewView(this.viewSavedUponCompletion);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Cleanup code when destroying the view editor header.
+ */
+ public ngOnDestroy(): void {
+ this.subscription.unsubscribe();
+ }
+
+ /**
+ * Initialization code run after construction.
+ */
+ public ngOnInit(): void {
+ this.subscription = this.editorService.editorEvent.subscribe( ( event ) => this.handleEditorEvent( event ) );
+
+ // ----------------------------------
+ // View Table configurations
+ // ----------------------------------
+ this.tableColumns = [
+ {
+ draggable: false,
+ name: "Views",
+ prop: "viewName",
+ resizeable: true,
+ sortable: false,
+ width: "100"
+ }
+ ];
+
+ this.ngxTableConfig = {
+ headerHeight: 0,
+ rowHeight: 20,
+ reorderable: false,
+ selectionType: "'single'"
+ } as NgxDataTableConfig;
+
+ this.emptyStateConfig = {
+ title: ViewEditorI18n.noViewsDefined
+ } as EmptyStateConfig;
+
+ this.tableConfig = {
+ emptyStateConfig: this.emptyStateConfig
+ } as TableConfig;
+
+
+ }
+
+ public ngAfterViewInit(): void {
+ // init the available views
+ this.initViews();
+ }
+
+ /*
+ * Initialize the views for the current dataservice. Makes a rest call to get the ViewEditorStates for the serviceVdb
+ */
+ private initViews( ): void {
+ this.viewsLoadingState = LoadingState.LOADING;
+ this.selectedVirtualization = this.selectionService.getSelectedVirtualization();
+ if ( !this.selectedVirtualization || this.selectedVirtualization === null ) {
+ this.tableRows = [];
+ }
+
+ const selectedView = this.selectionService.getSelectedViewDefinition();
+
+ const vdbName = this.selectedVirtualization.getServiceVdbName();
+ const editorStatesPattern = vdbName.toLowerCase() + "*";
+
+ const self = this;
+ this.dataserviceService
+ .getViewEditorStates(editorStatesPattern)
+ .subscribe(
+ (viewEditorStates) => {
+ const viewDefns: ViewDefinition[] = [];
+ for ( const viewState of viewEditorStates ) {
+ const viewDefn = viewState.getViewDefinition();
+ if ( viewDefn ) {
+ viewDefns.push( viewDefn );
+ }
+ }
+ self.tableRows = viewDefns.sort( (left, right): number => {
+ if (left.getName() < right.getName()) return -1;
+ if (left.getName() > right.getName()) return 1;
+ return 0;
+ });
+
+ let initialView: ViewDefinition = null;
+ if (!selectedView || selectedView === null) {
+ initialView = (self.tableRows && self.tableRows.length > 0) ? self.tableRows[0] : null;
+ } else {
+ initialView = self.tableRows.find((x) => x.getName() === selectedView.getName());
+ }
+ self.viewsLoadingState = LoadingState.LOADED_VALID;
+ if( initialView !== null) {
+ self.selectView(initialView);
+ }
+ },
+ (error) => {
+ self.logger.error("[VirtualizationComponent] Error updating the views for the virtualization: %o", error);
+ self.viewsLoadingState = LoadingState.LOADED_INVALID;
+ self.tableRows = [];
+ }
+ );
+ }
+
+ /**
+ * @returns {boolean} `true` if view being edited is readonly
+ */
+ public get readOnly(): boolean {
+ return !this.editorService.getEditorView() || this.editorService.isReadOnly();
+ }
+
+ /**
+ * @returns {boolean} `true` if views are being loaded
+ */
+ public get viewsLoading(): boolean {
+ return this.viewsLoadingState === LoadingState.LOADING;
+ }
+
+ /**
+ * Handles view selection from table
+ * @param $event
+ */
+ public viewSelectionChanged( $event ): void {
+ const selectedViews: ViewDefinition[] = $event.selected;
+ // If the current view has pending changes, auto save it
+ if ( this.editorService.hasChanges() ) {
+ this.editorService.saveEditorState();
+ }
+ this.selectView(selectedViews[0]);
+ }
+
+ public get deleteViewButtonEnabled(): boolean {
+ return ( this.getSelectedView() !== null );
+ }
+
+ private createNewView(viewDefn: ViewDefinition): void {
+ const selectedDs = this.selectionService.getSelectedVirtualization();
+ const editorId = this.getEditorStateId(selectedDs, viewDefn);
+
+ // Create new editor state to save
+ const editorState = new ViewEditorState();
+ editorState.setId(editorId);
+ editorState.setViewDefinition(viewDefn);
+
+ const editorStates: ViewEditorState[] = [];
+ editorStates.push(editorState);
+
+ this.viewsLoadingState = LoadingState.LOADING;
+
+ const self = this;
+ this.dataserviceService
+ .saveViewEditorStatesRefreshViews(editorStates, selectedDs.getId())
+ .subscribe(
+ (wasSuccess) => {
+ // Add the new ViewDefinition to the table
+ self.addViewDefinitionToList(viewDefn);
+ self.viewSavedUponCompletion = null;
+ self.viewsLoadingState = LoadingState.LOADED_VALID;
+ },
+ (error) => {
+ self.logger.error("[VirtualizationComponent] Error saving the editor state: %o", error);
+ self.viewSavedUponCompletion = null;
+ self.viewsLoadingState = LoadingState.LOADED_INVALID;
+ }
+ );
+ }
+
+ /**
+ * Handle creation of a new View. Displays the createView dialog,
+ * then saves the viewDefinition and adds it to the list
+ */
+ public onCreateView(): void {
+ // Open New View dialog
+ const initialState = {
+ title: ViewEditorI18n.createViewDialogTitle,
+ cancelButtonText: ViewEditorI18n.cancelButtonText,
+ okButtonText: ViewEditorI18n.okButtonText
+ };
+
+ // Show Dialog, act upon confirmation click
+ const modalRef = this.modalService.show(CreateViewDialogComponent, {initialState});
+ modalRef.content.okAction.take(1).subscribe((viewDefn) => {
+ // If the current view has pending changes, save them first
+ if ( this.editorService.hasChanges() ) {
+ this.viewSavedUponCompletion = viewDefn;
+ this.editorService.saveEditorState();
+ } else {
+ this.createNewView(viewDefn);
+ }
+ // addition of a view undeploys active serviceVdb
+ this.editorService.undeploySelectedVirtualization();
+ });
+ }
+
+ /**
+ * Construct id for the editor state
+ * @param {Dataservice} dataservice the dataservice
+ * @param {ViewDefinition} viewDefn the view definition
+ * @returns {string} the ID used to persist the editor state
+ */
+ private getEditorStateId(dataservice: Dataservice, viewDefn: ViewDefinition): string {
+ return dataservice.getServiceVdbName().toLowerCase() + "." + viewDefn.getName();
+ }
+
+ /**
+ * Handle Delete of the selected View
+ * @param {string} viewName
+ */
+ public onDeleteView( ): void {
+ const viewName = this.getSelectedView().getName();
+
+ // Dialog Content
+ const message = "Do you really want to delete View '" + viewName + "'?";
+ const initialState = {
+ title: "Confirm Delete",
+ bodyContent: message,
+ cancelButtonText: "Cancel",
+ confirmButtonText: "Delete"
+ };
+
+ // Show Dialog, act upon confirmation click
+ const modalRef = this.modalService.show(ConfirmDialogComponent, {initialState});
+ modalRef.content.confirmAction.take(1).subscribe((value) => {
+ this.doDeleteView(viewName);
+ });
+ }
+
+ /**
+ * Deletes the specified ViewEditorState from the userProfile, and removes ViewDefinition from the current list.
+ * @param {string} viewDefnName the name of the view
+ */
+ private doDeleteView(viewDefnName: string): void {
+ const selectedViewDefn = this.tableRows.find((x) => x.getName() === viewDefnName);
+ const selectedDs = this.selectionService.getSelectedVirtualization();
+ const vdbName = selectedDs.getServiceVdbName();
+ const editorStateId = vdbName.toLowerCase() + "." + viewDefnName;
+ const dataserviceName = selectedDs.getId();
+
+ this.viewsLoadingState = LoadingState.LOADING;
+ // Note: we can only doDelete selected items that we can see in the UI.
+ this.logger.debug("[VirtualizationComponent] Deleting selected Virtualization View.");
+ const self = this;
+ this.dataserviceService
+ .deleteViewEditorStateRefreshViews(editorStateId, dataserviceName)
+ .subscribe(
+ (wasSuccess) => {
+ self.removeViewDefinitionFromList(selectedViewDefn);
+ // deletion of a view undeploys active serviceVdb
+ self.editorService.undeploySelectedVirtualization();
+ this.viewsLoadingState = LoadingState.LOADED_VALID;
+ },
+ (error) => {
+ self.logger.error("[VirtualizationComponent] Error deleting the editor state: %o", error);
+ this.viewsLoadingState = LoadingState.LOADED_INVALID;
+ }
+ );
+ }
+
+ /*
+ * Add the specified ViewDefinition to the view definitions table
+ * @param {ViewDefinition} viewDefn the view definition to add
+ */
+ private addViewDefinitionToList(viewDefn: ViewDefinition): void {
+ const newRows: ViewDefinition[] = [];
+ newRows.push(viewDefn);
+ for ( const row of this.tableRows ) {
+ if ( row.getName() !== viewDefn.getName() ) {
+ newRows.push( row );
+ }
+ }
+ this.tableRows = newRows.sort( (left, right): number => {
+ if (left.getName() < right.getName()) return -1;
+ if (left.getName() > right.getName()) return 1;
+ return 0;
+ });
+ this.selectView(viewDefn);
+ }
+
+ /*
+ * Remove the specified ViewDefinition from the view definitions table
+ * @param {ViewDefinition} viewDefn the view definition to remove
+ */
+ private removeViewDefinitionFromList(viewDefn: ViewDefinition): void {
+ const origIndex = this.tableRows.findIndex( ( defn ) => defn.getName() === viewDefn.getName() );
+
+ const newRows: ViewDefinition[] = [];
+ for ( const row of this.tableRows ) {
+ if ( row.getName() !== viewDefn.getName() ) {
+ newRows.push( row );
+ }
+ }
+ this.tableRows = newRows;
+
+ // auto select another row
+ if ( this.tableRows.length > origIndex ) {
+ this.selectView( this.tableRows[origIndex] );
+ } else if ( this.tableRows.length > 0 ) {
+ this.selectView( this.tableRows[origIndex - 1] );
+ } else if ( this.tableRows.length === 0 ) {
+ this.selectView( null );
+ }
+ }
+
+ private selectView( selView: ViewDefinition ): void {
+ // Updates table selection display
+ let viewSelection = null;
+ if ( selView && selView !== null ) {
+ for (const view of this.tableRows) {
+ if (view.getName() === selView.getName()) {
+ view.setSelected(true);
+ viewSelection = view;
+ } else {
+ view.setSelected(false);
+ }
+ }
+ }
+ // Update selection service, then fire event
+ this.selectionService.setSelectedViewDefinition(this.selectedVirtualization, viewSelection);
+ this.editorService.setEditorView(viewSelection, ViewEditorPart.HEADER);
+ }
+
+ private getSelectedView( ): ViewDefinition {
+ let selectedView: ViewDefinition = null;
+ for (const view of this.tableRows) {
+ if (view.selected) {
+ selectedView = view;
+ break;
+ }
+ }
+ return selectedView;
+ }
+
+ /**
+ * @returns {string} the view description
+ */
+ public get viewDescription(): string {
+ if ( this.editorService.getEditorView() ) {
+ return this.editorService.getEditorView().getDescription();
+ }
+
+ return "";
+ }
+
+ /**
+ * @param {string} newDescription the new description
+ */
+ public set viewDescription( newDescription: string ) {
+ if ( this.editorService.getEditorView() ) {
+ if ( newDescription !== this.editorService.getEditorView().getDescription() ) {
+ const oldDescription = this.editorService.getEditorView().getDescription();
+ const temp = CommandFactory.createUpdateViewDescriptionCommand( newDescription, oldDescription );
+
+ if ( temp instanceof Command ) {
+ this.editorService.fireViewStateHasChanged( ViewEditorPart.HEADER, temp as Command );
+ } else {
+ const error = temp as Error;
+ this.logger.error( error.message );
+ }
+ }
+ } else {
+ // shouldn't get here as description text input should be disabled if no view being edited
+ this.logger.error( "Trying to set description but there is no view being edited" );
+ }
+ }
+
+ /**
+ * Called when text in the view description textarea changes.
+ *
+ * @param {string} newDescription the new description of the view
+ */
+ public viewDescriptionChanged( newDescription: string ): void {
+ this.viewDescription = newDescription;
+ }
+}
diff --git a/ngapp/src/assets/table.png b/ngapp/src/assets/table.png
new file mode 100644
index 00000000..99a133d4
Binary files /dev/null and b/ngapp/src/assets/table.png differ