summaryrefslogtreecommitdiffstats
path: root/catalog-ui/app/scripts/view-models/dashboard
diff options
context:
space:
mode:
Diffstat (limited to 'catalog-ui/app/scripts/view-models/dashboard')
-rw-r--r--catalog-ui/app/scripts/view-models/dashboard/cover/dashboard-cover-view-model.ts91
-rw-r--r--catalog-ui/app/scripts/view-models/dashboard/cover/dashboard-cover-view.html1
-rw-r--r--catalog-ui/app/scripts/view-models/dashboard/dashboard-view-model-tests.ts276
-rw-r--r--catalog-ui/app/scripts/view-models/dashboard/dashboard-view-model.ts415
-rw-r--r--catalog-ui/app/scripts/view-models/dashboard/dashboard-view.html106
-rw-r--r--catalog-ui/app/scripts/view-models/dashboard/dashboard.less420
6 files changed, 1309 insertions, 0 deletions
diff --git a/catalog-ui/app/scripts/view-models/dashboard/cover/dashboard-cover-view-model.ts b/catalog-ui/app/scripts/view-models/dashboard/cover/dashboard-cover-view-model.ts
new file mode 100644
index 0000000000..9979b6451b
--- /dev/null
+++ b/catalog-ui/app/scripts/view-models/dashboard/cover/dashboard-cover-view-model.ts
@@ -0,0 +1,91 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+/// <reference path="../../../references"/>
+module Sdc.ViewModels {
+
+ 'use strict';
+
+ export interface IDashboardCoverViewModelScope extends ng.IScope {
+ showTutorial:boolean;
+ version:string;
+ modalInstance:ng.ui.bootstrap.IModalServiceInstance;
+ }
+
+ export class DashboardCoverViewModel {
+ static '$inject' = [
+ '$scope',
+ '$stateParams',
+ 'Sdc.Services.CacheService',
+ '$templateCache',
+ '$state',
+ '$modal',
+ 'sdcConfig'
+ ];
+
+ constructor(private $scope:IDashboardCoverViewModelScope,
+ private $stateParams:any,
+ private cacheService:Services.CacheService,
+ private $templateCache:ng.ITemplateCacheService,
+ private $state:any,
+ private $modal:ng.ui.bootstrap.IModalService,
+ private sdcConfig:Models.IAppConfigurtaion) {
+
+ // Show the tutorial if needed when the dashboard page is opened.<script src="bower_components/angular-filter/dist/angular-filter.min.js"></script>
+ // This is called from the welcome page.
+ if (this.$stateParams.show === 'tutorial') {
+ this.$scope.showTutorial = true;
+ } else if (this.$stateParams.show === 'whatsnew') {
+ this.$scope.version = this.cacheService.get('version');
+ this.openWhatsNewModal(this.$scope);
+ }
+
+ this.initScope();
+ }
+
+ private initScope = ():void => {
+
+ };
+
+ private openWhatsNewModal = (scope:IDashboardCoverViewModelScope):void => {
+
+ let onOk = ():void => {};
+
+ let onCancel = ():void => {
+ this.$state.go('dashboard.welcome', {show: ''});
+ };
+
+ let modalOptions:ng.ui.bootstrap.IModalSettings = {
+ template: this.$templateCache.get('/app/scripts/view-models/whats-new/whats-new-view.html'),
+ controller: 'Sdc.ViewModels.WhatsNewViewModel',
+ size: 'sdc-l',
+ backdrop: 'static',
+ scope: scope,
+ resolve: {
+ 'version': scope.version
+ }
+ };
+
+ scope.modalInstance = this.$modal.open(modalOptions);
+ scope.modalInstance.result.then(onOk, onCancel);
+ };
+
+ }
+
+}
diff --git a/catalog-ui/app/scripts/view-models/dashboard/cover/dashboard-cover-view.html b/catalog-ui/app/scripts/view-models/dashboard/cover/dashboard-cover-view.html
new file mode 100644
index 0000000000..c8657cba23
--- /dev/null
+++ b/catalog-ui/app/scripts/view-models/dashboard/cover/dashboard-cover-view.html
@@ -0,0 +1 @@
+<div class="sdc-welcome-page"></div>
diff --git a/catalog-ui/app/scripts/view-models/dashboard/dashboard-view-model-tests.ts b/catalog-ui/app/scripts/view-models/dashboard/dashboard-view-model-tests.ts
new file mode 100644
index 0000000000..d97d9bb5ec
--- /dev/null
+++ b/catalog-ui/app/scripts/view-models/dashboard/dashboard-view-model-tests.ts
@@ -0,0 +1,276 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+/// <reference path="../../references"/>
+
+describe("dashboard View Model ", () => {
+
+ let $controllerMock:ng.IControllerService;
+ let $qMock:ng.IQService;
+ let $httpBackendMock:ng.IHttpBackendService;
+ let $scopeMock:Sdc.ViewModels.IDashboardViewModelScope;
+ let $stateMock:ng.ui.IStateService;
+ let $stateParams:any;
+ let entityServiceMock;
+
+
+ let getAllEntitiesResponseMock = [
+ {
+ "uniqueId": "855acdc7-7976-4913-9fa6-25220bd5a069",
+ "uuid": "8bc54f94-082c-42fa-9049-84767df3ff05",
+ "contactId": "qa1234",
+ "category": "VoIP Call Control",
+ "creationDate": 1447234712398,
+ "description": "ddddd",
+ "highestVersion": true,
+ "icon": "mobility",
+ "lastUpdateDate": 1447234712398,
+ "lastUpdaterUserId": "cs0008",
+ "lastUpdaterFullName": "Carlos Santana",
+ "lifecycleState": "NOT_CERTIFIED_CHECKOUT",
+ "distributionStatus": "DISTRIBUTION_NOT_APPROVED",
+ "projectCode": "233233",
+ "name": "mas mas mas mas mas mas mas mas mas mas mas mas ma",
+ "version": "0.1",
+ "type": 0,
+ "tags": [
+ "mas mas mas mas mas mas mas mas mas mas mas mas ma"
+ ],
+ "systemName": "MasMasMasMasMasMasMasMasMasMasMasMasMa",
+ "vnf": true,
+ "$$hashKey": "object:30"
+ },
+ {
+ "uniqueId": "4bb577ce-cb2c-4cb7-bb39-58644b5e73cb",
+ "uuid": "e27f4723-c9ec-4160-89da-dbf84d19a7e3",
+ "contactId": "qa1111",
+ "category": "Mobility",
+ "creationDate": 1447238503181,
+ "description": "aqa",
+ "highestVersion": true,
+ "icon": "call_controll",
+ "lastUpdateDate": 1447248991388,
+ "lastUpdaterUserId": "jm0007",
+ "lastUpdaterFullName": "Joni Mitchell",
+ "lifecycleState": "CERTIFIED",
+ "distributionStatus": "DISTRIBUTION_REJECTED",
+ "projectCode": "111111",
+ "name": "martin18",
+ "version": "1.0",
+ "type": 0,
+ "tags": [
+ "martin18"
+ ],
+ "systemName": "Martin18",
+ "vnf": true
+ },
+ {
+ "uniqueId": "f192f4a6-7fbf-42e4-a546-37509df28dc1",
+ "uuid": "0b77dc0d-222e-4d10-85cd-e420c9481417",
+ "contactId": "fd1212",
+ "category": "Application Layer 4+/Web Server",
+ "creationDate": 1447233679778,
+ "description": "geefw",
+ "highestVersion": true,
+ "icon": "database",
+ "lastUpdateDate": 1447233681582,
+ "lastUpdaterUserId": "cs0008",
+ "lastUpdaterFullName": "Carlos Santana",
+ "lifecycleState": "NOT_CERTIFIED_CHECKOUT",
+ "name": "ger",
+ "version": "0.1",
+ "type": 1,
+ "tags": [
+ "ger"
+ ],
+ "vendorName": "fewwfe",
+ "vendorRelease": "fewew",
+ "systemName": "Ger",
+ "$$hashKey": "object:31"
+ },
+ {
+ "uniqueId": "78392d08-1859-47c2-b1f2-1a35b7f8c30e",
+ "uuid": "8cdd63b2-6a62-4376-9012-624f424f71d4",
+ "contactId": "qw1234",
+ "category": "Application Layer 4+/Application Servers",
+ "creationDate": 1447234046114,
+ "description": "test",
+ "highestVersion": true,
+ "icon": "router",
+ "lastUpdateDate": 1447234050545,
+ "lastUpdaterUserId": "cs0008",
+ "lastUpdaterFullName": "Carlos Santana",
+ "lifecycleState": "NOT_CERTIFIED_CHECKOUT",
+ "name": "test",
+ "version": "0.1",
+ "type": 1,
+ "tags": [
+ "test"
+ ],
+ "vendorName": "test",
+ "vendorRelease": "test",
+ "systemName": "Test",
+ "$$hashKey": "object:32"
+ },
+ {
+ "uniqueId": "939e153d-2236-410f-b4a9-3b4bf8c79c9e",
+ "uuid": "84862547-4f56-4058-b78e-40df5f374d7e",
+ "contactId": "qw1234",
+ "category": "Application Layer 4+/Application Servers",
+ "creationDate": 1447235242560,
+ "description": "jlk",
+ "highestVersion": true,
+ "icon": "database",
+ "lastUpdateDate": 1447235328062,
+ "lastUpdaterUserId": "cs0008",
+ "lastUpdaterFullName": "Carlos Santana",
+ "lifecycleState": "NOT_CERTIFIED_CHECKIN",
+ "name": "new",
+ "version": "0.1",
+ "type": 1,
+ "tags": [
+ "new"
+ ],
+ "vendorName": "e",
+ "vendorRelease": "e",
+ "systemName": "New",
+ "$$hashKey": "object:33"
+ },
+ {
+ "uniqueId": "ece818e0-fd59-477a-baf6-e27461a7ce23",
+ "uuid": "8db823c2-6a9c-4636-8676-f5e713270dd7",
+ "contactId": "uf2345",
+ "category": "Network Layer 2-3/Router",
+ "creationDate": 1447235352429,
+ "description": "u",
+ "highestVersion": true,
+ "icon": "network",
+ "lastUpdateDate": 1447235370064,
+ "lastUpdaterUserId": "cs0008",
+ "lastUpdaterFullName": "Carlos Santana",
+ "lifecycleState": "NOT_CERTIFIED_CHECKOUT",
+ "name": "u",
+ "version": "0.1",
+ "type": 1,
+ "tags": [
+ "u"
+ ],
+ "vendorName": "u",
+ "vendorRelease": "u",
+ "systemName": "U",
+ "$$hashKey": "object:34"
+ }
+ ];
+ let getAllEntitiesDefered:ng.IDeferred<any> = null;
+
+ beforeEach(angular.mock.module('sdcApp'));
+
+ beforeEach(angular.mock.inject((_$controller_:ng.IControllerService,
+ _$httpBackend_:ng.IHttpBackendService,
+ _$rootScope_,
+ _$q_:ng.IQService,
+ _$state_:ng.ui.IStateService,
+ _$stateParams_:any) => {
+
+ $controllerMock = _$controller_;
+ $httpBackendMock = _$httpBackend_
+ $scopeMock = _$rootScope_.$new();
+ $qMock = _$q_;
+ $stateMock = _$state_;
+ $stateParams = _$stateParams_;
+
+
+ //handle all http request thet not relevant to the tests
+ $httpBackendMock.expectGET(/.*languages\/en_US.json.*/).respond(200, JSON.stringify({}));
+ // $httpBackendMock.expectGET(/.*resources\/certified\/abstract.*/).respond(200, JSON.stringify({}));
+ $httpBackendMock.expectGET(/.*rest\/version.*/).respond(200, JSON.stringify({}));
+ $httpBackendMock.expectGET(/.*configuration\/ui.*/).respond(200, JSON.stringify({}));
+ $httpBackendMock.expectGET(/.*user\/authorize.*/).respond(200, JSON.stringify({}));
+ $httpBackendMock.expectGET(/.*categories\/services.*/).respond(200, JSON.stringify({}));
+ $httpBackendMock.expectGET(/.*categories\/resources.*/).respond(200, JSON.stringify({}));
+ $httpBackendMock.expectGET(/.*categories\/products.*/).respond(200, JSON.stringify({}));
+ $httpBackendMock.expectGET('http://feHost:8181/sdc1/feProxy/rest/version').respond(200, JSON.stringify({}));
+
+ /**
+ * Mock the service
+ * @type {any}
+ */
+ getAllEntitiesDefered = $qMock.defer();
+ getAllEntitiesDefered.resolve(getAllEntitiesResponseMock);
+ entityServiceMock = jasmine.createSpyObj('entityServiceMock', ['getAllComponents']);
+ entityServiceMock.getAllComponents.and.returnValue(getAllEntitiesDefered.promise);
+
+ // $stateParams['show'] = '';
+
+ /**
+ * Need to inject into the controller only the objects that we want to MOCK
+ * those that we need to change theirs behaviors
+ */
+ $controllerMock(Sdc.ViewModels.DashboardViewModel, {
+ '$scope': $scopeMock,
+ '$stateParams': $stateParams,
+ 'Sdc.Services.EntityService': entityServiceMock,
+ });
+
+ }));
+
+
+ describe("when Controller 'DashboardViewModel' created", () => {
+
+ it('should generate all entities', () => {
+ $scopeMock.$apply();
+ expect($scopeMock.components.length).toBe(getAllEntitiesResponseMock.length);
+ });
+
+
+ it('should show tutorial page ', () => {
+ $stateParams.show = 'tutorial';
+
+ $controllerMock(Sdc.ViewModels.DashboardViewModel, {
+ '$scope': $scopeMock,
+ '$stateParams': $stateParams,
+ 'Sdc.Services.EntityService': entityServiceMock,
+ //to complete injects
+ });
+
+ $scopeMock.$apply();
+ expect($scopeMock.isFirstTime).toBeTruthy();
+ expect($scopeMock.showTutorial).toBeTruthy();
+ });
+
+ });
+
+
+ describe("when function 'entitiesCount' invoked", () => {
+
+ beforeEach(() => {
+ $controllerMock(Sdc.ViewModels.DashboardViewModel, {
+ '$scope': $scopeMock,
+ 'Sdc.Services.EntityService': entityServiceMock,
+ });
+ $scopeMock.$apply();
+ });
+
+ it('should return entities count per folder', () => {
+
+ });
+
+
+ });
+});
diff --git a/catalog-ui/app/scripts/view-models/dashboard/dashboard-view-model.ts b/catalog-ui/app/scripts/view-models/dashboard/dashboard-view-model.ts
new file mode 100644
index 0000000000..8325a3f133
--- /dev/null
+++ b/catalog-ui/app/scripts/view-models/dashboard/dashboard-view-model.ts
@@ -0,0 +1,415 @@
+/*-
+ * ============LICENSE_START=======================================================
+ * SDC
+ * ================================================================================
+ * Copyright (C) 2017 AT&T Intellectual Property. All rights reserved.
+ * ================================================================================
+ * 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.
+ * ============LICENSE_END=========================================================
+ */
+/// <reference path="../../references"/>
+module Sdc.ViewModels {
+
+ 'use strict';
+ import ResourceType = Sdc.Utils.Constants.ResourceType;
+
+ export interface IDashboardViewModelScope extends ng.IScope {
+
+ isLoading: boolean;
+ components: Array<Models.Components.Component>;
+ folders: FoldersMenu;
+ roles: Models.IConfigRoles;
+ user: Models.IUserProperties;
+ sdcConfig:Models.IAppConfigurtaion;
+ sdcMenu:Models.IAppMenu;
+ sharingService:Sdc.Services.SharingService;
+ showTutorial:boolean;
+ isFirstTime:boolean;
+ version:string;
+ checkboxesFilter:CheckboxesFilter;
+
+ onImportVfc(file:any):void;
+ onImportVf(file:any):void;
+ openCreateModal(componentType: Utils.Constants.ComponentType, importedFile:any): void;
+ openWhatsNewModal(version:string):void;
+ openDesignerModal(isResource:boolean, uniqueId:string): void;
+ openViewerModal(entity:any) : void;
+ setSelectedFolder(folderItem: FoldersItemsMenu): void;
+ entitiesCount(folderItem: FoldersItemsMenu): number;
+ getCurrentFolderDistributed(): Array<Models.Components.Component>;
+ changeLifecycleState(entity:any, data:any): void;
+ goToComponent(component:Models.Components.Component):void;
+ wizardDebugEdit:Function;
+ notificationIconCallback:Function;
+ }
+
+ interface CheckboxesFilter {
+ // Statuses
+ selectedStatuses:Array<string>;
+ // distributed
+ distributed:Array<string>;
+ }
+
+ export interface IItemMenu {
+
+ }
+
+ export interface IMenuItemProperties {
+ text: string;
+ group: string;
+ state: string;
+ dist: string;
+ groupname: string;
+ states: Array<any>;
+ }
+
+ export class FoldersMenu {
+
+ private _folders: Array<FoldersItemsMenu> = [];
+
+ constructor(folders: Array<IMenuItemProperties>) {
+ let self = this;
+ folders.forEach(function(folder: IMenuItemProperties) {
+ if (folder.groupname){
+ self._folders.push(new FoldersItemsMenuGroup(folder));
+ } else {
+ self._folders.push(new FoldersItemsMenu(folder));
+ }
+ });
+ self._folders[0].setSelected(true);
+ }
+
+ public getFolders = (): Array<FoldersItemsMenu> => {
+ return this._folders;
+ };
+
+ public getCurrentFolder = (): FoldersItemsMenu => {
+ let menuItem: FoldersItemsMenu = undefined;
+ this.getFolders().forEach(function(tmpFolder: FoldersItemsMenu) {
+ if (tmpFolder.isSelected()){
+ menuItem = tmpFolder;
+ }
+ });
+ return menuItem;
+ };
+
+ public setSelected = (folder: FoldersItemsMenu):void => {
+ this.getFolders().forEach(function(tmpFolder: FoldersItemsMenu) {
+ tmpFolder.setSelected(false);
+ });
+ folder.setSelected(true);
+ }
+
+ }
+
+ export class FoldersItemsMenu implements IItemMenu {
+
+ public text:string;
+ public group: string;
+ public state: string;
+ public dist: string;
+ public states: Array<any>;
+
+ private selected: boolean = false;
+
+ constructor(menuProperties: IMenuItemProperties) {
+ this.text = menuProperties.text;
+ this.group = menuProperties.group;
+ this.state = menuProperties.state;
+ this.states = menuProperties.states;
+ this.dist = menuProperties.dist;
+ }
+
+ public isSelected = ():boolean => {
+ return this.selected;
+ };
+
+ public setSelected = (value: boolean):void => {
+ this.selected = value;
+ };
+
+ public isGroup = ():boolean => {
+ return false;
+ }
+
+ }
+
+ export class FoldersItemsMenuGroup extends FoldersItemsMenu {
+
+ public groupname:string;
+
+ constructor(menuProperties: IMenuItemProperties) {
+ super(menuProperties);
+ this.groupname = menuProperties.groupname;
+ }
+
+ public isGroup = ():boolean => {
+ return true;
+ }
+
+ }
+
+ export class DashboardViewModel {
+ static '$inject' = [
+ '$scope',
+ '$filter',
+ 'Sdc.Services.EntityService',
+ '$http',
+ 'sdcConfig',
+ 'sdcMenu',
+ '$modal',
+ '$templateCache',
+ '$state',
+ '$stateParams',
+ 'Sdc.Services.UserResourceService',
+ 'Sdc.Services.SharingService',
+ 'Sdc.Services.CacheService',
+ '$q',
+ 'ComponentFactory',
+ 'ChangeLifecycleStateHandler',
+ 'ModalsHandler',
+ 'MenuHandler'
+ ];
+
+ private components: Array<Models.Components.Component>;
+
+ constructor(private $scope:IDashboardViewModelScope,
+ private $filter:ng.IFilterService,
+ private entityService:Services.EntityService,
+ private $http:ng.IHttpService,
+ private sdcConfig:Models.IAppConfigurtaion,
+ private sdcMenu:Models.IAppMenu,
+ private $modal:ng.ui.bootstrap.IModalService,
+ private $templateCache:ng.ITemplateCacheService,
+ private $state:any,
+ private $stateParams:any,
+ private userResourceService:Sdc.Services.IUserResourceClass,
+ private sharingService:Services.SharingService,
+ private cacheService:Services.CacheService,
+ private $q:ng.IQService,
+ private ComponentFactory: Sdc.Utils.ComponentFactory,
+ private ChangeLifecycleStateHandler: Sdc.Utils.ChangeLifecycleStateHandler,
+ private ModalsHandler: Sdc.Utils.ModalsHandler,
+ private MenuHandler: Utils.MenuHandler
+ ) {
+ this.initScope();
+ this.initFolders();
+ this.initEntities(true);
+
+ if (this.$stateParams){
+
+ if (this.$state.params.folder){
+ let self = this;
+ let folderName = this.$state.params.folder.replaceAll("_"," ");
+
+ this.$scope.folders.getFolders().forEach(function(tmpFolder: FoldersItemsMenu) {
+ if (tmpFolder.text === folderName){
+ self.$scope.setSelectedFolder(tmpFolder);
+ }
+ });
+ }
+
+ // Show the tutorial if needed when the dashboard page is opened.<script src="bower_components/angular-filter/dist/angular-filter.min.js"></script>
+ // This is called from the welcome page.
+ else if (this.$stateParams.show==='tutorial'){
+ this.$scope.showTutorial = true;
+ this.$scope.isFirstTime = true;
+ }
+ }
+ }
+
+ private initFolders = ():void => {
+ if (this.$scope.user) {
+ this.$scope.folders = new FoldersMenu(this.$scope.roles[this.$scope.user.role].folder);
+ }
+ };
+
+ private initScope = ():void => {
+ let self = this;
+
+ this.$scope.version = this.cacheService.get('version');
+ this.$scope.sharingService = this.sharingService;
+ this.$scope.isLoading = false;
+ this.$scope.sdcConfig = this.sdcConfig;
+ this.$scope.sdcMenu = this.sdcMenu;
+ this.$scope.user = this.userResourceService.getLoggedinUser();
+ this.$scope.roles = this.sdcMenu.roles;
+ this.$scope.showTutorial = false;
+ this.$scope.isFirstTime = false;
+
+ // Open onboarding modal
+ this.$scope.notificationIconCallback = ():void => {
+ this.ModalsHandler.openOnboadrdingModal('Import').then(()=>{
+ // OK
+ }, ()=>{
+ // ERROR
+ });
+ };
+
+ // Checkboxes filter init
+ this.$scope.checkboxesFilter = <CheckboxesFilter>{};
+ this.$scope.checkboxesFilter.selectedStatuses = [];
+ this.$scope.checkboxesFilter.distributed = [];
+
+ let appendTemplateAndControllerForProduct:Function = (modalOptions:ng.ui.bootstrap.IModalSettings, isViewer:boolean):void => {
+ let viewModelsHtmlBasePath:string = '/app/scripts/view-models/';
+
+ if (isViewer) {
+ modalOptions.template = this.$templateCache.get(viewModelsHtmlBasePath + 'entity-viewer/product-viewer-view.html');
+ modalOptions.controller = 'Sdc.ViewModels.ResourceViewerViewModel';
+ } else {
+ modalOptions.template = this.$templateCache.get(viewModelsHtmlBasePath + 'entity-handler/product-form/product-form-view.html');
+ modalOptions.controller = 'Sdc.ViewModels.ProductFormViewModel';
+ }
+
+ };
+
+ this.$scope.onImportVf = (file:any):void => {
+ if(file && file.filename) {
+ // Check that the file has valid extension.
+ let fileExtension:string = file.filename.split(".").pop();
+ if (this.sdcConfig.csarFileExtension.indexOf(fileExtension.toLowerCase()) !== -1){
+ this.$state.go('workspace.general', {type:Utils.Constants.ComponentType.RESOURCE.toLowerCase(), importedFile: file, resourceType: ResourceType.VF});
+ }else {
+ let data:Sdc.ViewModels.IClientMessageModalModel = {
+ title: self.$filter('translate')("NEW_SERVICE_RESOURCE_ERROR_VALID_CSAR_EXTENSIONS_TITLE"),
+ message: self.$filter('translate')("NEW_SERVICE_RESOURCE_ERROR_VALID_CSAR_EXTENSIONS", "{'extensions': '" + this.sdcConfig.csarFileExtension + "'}"),
+ severity: Utils.Constants.SEVERITY.ERROR
+ };
+ this.ModalsHandler.openClientMessageModal(data);
+ }
+ }
+ };
+
+ this.$scope.onImportVfc = (file:any):void => {
+ if(file && file.filename) {
+ // Check that the file has valid extension.
+ let fileExtension:string = file.filename.split(".").pop();
+ if (this.sdcConfig.toscaFileExtension.indexOf(fileExtension.toLowerCase()) !== -1){
+ this.$state.go('workspace.general', {type:Utils.Constants.ComponentType.RESOURCE.toLowerCase(), importedFile: file, resourceType: ResourceType.VFC});
+ }else {
+ let data:Sdc.ViewModels.IClientMessageModalModel = {
+ title: self.$filter('translate')("NEW_SERVICE_RESOURCE_ERROR_VALID_TOSCA_EXTENSIONS_TITLE"),
+ message: self.$filter('translate')("NEW_SERVICE_RESOURCE_ERROR_VALID_TOSCA_EXTENSIONS", "{'extensions': '" + this.sdcConfig.toscaFileExtension + "'}"),
+ severity: Utils.Constants.SEVERITY.ERROR
+ };
+ this.ModalsHandler.openClientMessageModal(data);
+ }
+ }
+ };
+
+ this.$scope.openCreateModal = (componentType: string, importedFile:any):void => {
+ if (importedFile){
+ this.initEntities(true); // Return from import
+ } else {
+ this.$state.go('workspace.general', {type:componentType.toLowerCase()});
+ }
+
+ };
+
+ this.$scope.entitiesCount = (folderItem: FoldersItemsMenu): any => {
+ let self = this;
+ let total: number = 0;
+ if (folderItem.isGroup()){
+ this.$scope.folders.getFolders().forEach(function(tmpFolder: FoldersItemsMenu){
+ if (tmpFolder.group && tmpFolder.group===(<FoldersItemsMenuGroup>folderItem).groupname){
+ total = total + self._getTotalCounts(tmpFolder, self);
+ }
+ });
+ } else {
+ total = total + self._getTotalCounts(folderItem, self);
+ }
+ return total;
+ };
+
+ this.$scope.getCurrentFolderDistributed = (): Array<any> => {
+ let self = this;
+ let states = [];
+ if (this.$scope.folders) {
+ let folderItem:FoldersItemsMenu = this.$scope.folders.getCurrentFolder();
+ if (folderItem.isGroup()) {
+ this.$scope.folders.getFolders().forEach(function (tmpFolder:FoldersItemsMenu) {
+ if (tmpFolder.group && tmpFolder.group === (<FoldersItemsMenuGroup>folderItem).groupname) {
+ self._setStates(tmpFolder, states);
+ }
+ });
+ } else {
+ self._setStates(folderItem, states);
+ }
+ }
+ return states;
+ };
+
+ this.$scope.setSelectedFolder = (folderItem: FoldersItemsMenu):void => {
+ this.$scope.folders.setSelected(folderItem);
+ };
+
+ this.$scope.goToComponent = (component:Models.Components.Component):void => {
+ this.$scope.isLoading=true;
+ this.$state.go('workspace.general', {id: component.uniqueId, type:component.componentType.toLowerCase() });
+ };
+
+ };
+
+ private _getTotalCounts(tmpFolder, self): number {
+ let total: number = 0;
+ if (tmpFolder.dist !== undefined) {
+ let distributions = tmpFolder.dist.split(',');
+ distributions.forEach((item:any) => {
+ total = total + self.getEntitiesByStateDist(tmpFolder.state, item).length;
+ });
+ }
+ else {
+ total = total + self.getEntitiesByStateDist(tmpFolder.state, tmpFolder.dist).length;
+ }
+ return total;
+ }
+
+ private _setStates(tmpFolder, states) {
+ if (tmpFolder.states !== undefined) {
+ tmpFolder.states.forEach(function (item:any) {
+ states.push({"state": item.state, "dist": item.dist});
+ });
+ } else {
+ states.push({"state": tmpFolder.state, "dist": tmpFolder.dist});
+ }
+ }
+
+ private initEntities = (reload:boolean):void => {
+ this.$scope.isLoading = reload;
+ this.entityService.getAllComponents().then(
+ (components: Array<Models.Components.Component>) => {
+ this.components = components;
+ this.$scope.components = components;
+ this.$scope.isLoading = false;
+ });
+ };
+
+ private getEntitiesByStateDist = (state: string, dist: string) : Array<Models.Components.Component> => {
+ let gObj:Array<Models.Components.Component>;
+ if (this.components && (state || dist)) {
+ gObj = this.components.filter(function (obj:Models.Components.Component) {
+ if (dist !== undefined && obj.distributionStatus === dist && obj.lifecycleState === state){
+ return true;
+ } else if (dist === undefined && obj.lifecycleState === state) {
+ return true;
+ }
+ return false;
+ });
+ } else {
+ gObj = [];
+ }
+ return gObj;
+ }
+ }
+}
diff --git a/catalog-ui/app/scripts/view-models/dashboard/dashboard-view.html b/catalog-ui/app/scripts/view-models/dashboard/dashboard-view.html
new file mode 100644
index 0000000000..0aef4e19c6
--- /dev/null
+++ b/catalog-ui/app/scripts/view-models/dashboard/dashboard-view.html
@@ -0,0 +1,106 @@
+<div class="sdc-catalog-container">
+ <loader data-display="isLoading"></loader>
+
+ <!-- HEADER -->
+<!--
+ <ecomp-header menu-data="menuItems" version="{{version}}"></ecomp-header>
+-->
+
+ <div class="w-sdc-main-container">
+
+ <perfect-scrollbar include-padding="true" class="w-sdc-main-right-container">
+
+ <!-- ADD Component -->
+ <div ng-if="user.role === 'DESIGNER' || user.role === 'PRODUCT_MANAGER'" class="w-sdc-dashboard-card-new"
+ data-ng-mouseleave="displayActions = false"
+ data-ng-mouseover="displayActions = true"
+ data-ng-init="displayActions = false">
+ <div class="w-sdc-dashboard-card-new-content" data-tests-id="AddButtonsArea">
+ <div class="w-sdc-dashboard-card-new-content-plus" data-ng-show="!displayActions"></div>
+ <div class="sdc-dashboard-create-element-container" data-ng-show="displayActions">
+ <button data-ng-if="roles[user.role].dashboard.showCreateNewProduct" class="tlv-btn outline blue" data-ng-click="openCreateModal('PRODUCT')">Create Product</button>
+ <button data-ng-if="roles[user.role].dashboard.showCreateNew" data-tests-id="createResourceButton" class="tlv-btn outline blue" data-ng-click="openCreateModal('RESOURCE')">Add VF</button>
+ <button data-ng-if="roles[user.role].dashboard.showCreateNew" data-tests-id="createServiceButton" class="tlv-btn outline blue" data-ng-click="openCreateModal('SERVICE')">Add Service</button>
+ </div>
+ </div>
+ </div>
+
+ <!-- Import Component -->
+ <div ng-if="user.role === 'DESIGNER'" class="w-sdc-dashboard-card-new"
+ data-ng-mouseleave="displayActions = false"
+ data-ng-mouseover="displayActions = true"
+ data-ng-init="displayActions = false">
+ <div class="w-sdc-dashboard-card-new-content" data-tests-id="importButtonsArea" >
+ <div class="w-sdc-dashboard-card-import-content-plus" data-ng-show="!displayActions"></div>
+ <div class="sdc-dashboard-import-element-container" data-ng-show="displayActions">
+ <div data-ng-if="roles[user.role].dashboard.showCreateNew" class="tlv-btn outline blue">Import VFC
+ <file-opener on-file-upload="onImportVfc(file)" data-tests-id="importVFCbutton" extensions="{{sdcConfig.toscaFileExtension}}" data-ng-click="displayActions=false"></file-opener>
+ </div>
+ <div data-ng-if="roles[user.role].dashboard.showCreateNew" class="tlv-btn outline blue" data-ng-click="notificationIconCallback()">Import VSP</div>
+ <div data-ng-if="roles[user.role].dashboard.showCreateNew" class="tlv-btn outline blue import-dcae">Import DCAE asset
+ <file-opener on-file-upload="onImportVf(file)" data-tests-id="importVFbutton" extensions="{{sdcConfig.csarFileExtension}}" data-ng-click="displayActions=false"></file-opener>
+ </div>
+ </div>
+ </div>
+ </div>
+
+ <div
+ data-ng-class="{'sdc-hide-popover': hidePopover,'resource' : component.isResource(),'service' : component.isService()}"
+ class="w-sdc-dashboard-card"
+ data-ng-repeat="component in components | entityFilter:checkboxesFilter | filter:search"
+ >
+ <div class="w-sdc-dashboard-card-body" data-tests-id="dashboard-Elements" data-ng-click="goToComponent(component)">
+ <!--<div class="w-sdc-dashboard-card-description">{{entity.description}}</div>-->
+ <div class="w-sdc-dashboard-card-avatar"><span data-tests-id="asset-type" class="{{component.getComponentSubType()}}"></span></div>
+ <!--<div class="w-sdc-dashboard-card-edit" data-ng-class="component.lifecycleState" data-tests-id="{{component.lifecycleState}}"></div>-->
+ <div class="w-sdc-dashboard-card-schema-image {{component.iconSprite}} {{component.icon}}"
+ data-ng-class="{'sprite-resource-icons': component.isResource(), 'sprite-services-icons': component.isService()}"
+ data-tests-id="{{component.name}}"></div>
+ <div class="w-sdc-dashboard-card-info-name-container">
+ <span class="w-sdc-dashboard-card-info-name" tooltips
+ tooltip-content="{{component.name | resourceName}}"> {{component.name | resourceName}}</span>
+ </div>
+ </div>
+ <div class="w-sdc-dashboard-card-footer">
+
+ <div class="w-sdc-dashboard-card-info">
+ <div class="w-sdc-dashboard-card-info-lifecycleState">
+ <span class="w-sdc-dashboard-card-info-lifecycleState" tooltips
+ tooltip-content="{{component.getStatus(sdcMenu)}}"> {{component.getStatus(sdcMenu)}}</span>
+ </div>
+ <div class="w-sdc-dashboard-card-info-user"data-tests-id="{{component.name}}Version">V {{component.version}}</div>
+ </div>
+ <!--<div class="w-sdc-dashboard-card-info-lifecycleState-icon sprite-new {{sdcMenu.LifeCycleStatuses[component.lifecycleState].icon}}"></div>-->
+ </div>
+ </div>
+
+ </perfect-scrollbar>
+
+ <div class="w-sdc-left-sidebar">
+ <div class="i-sdc-left-sidebar-item "
+ data-ng-repeat="folder in folders.getFolders()"
+ data-ng-class="{'category-title': folder.isGroup(), 'selectedLink': folder.isSelected()}"
+ >
+ <span data-ng-if="folder.isGroup()">{{folder.text}}</span>
+
+ <sdc-checkbox data-ng-if="!folder.isGroup() && !folder.dist"
+ elem-id="checkbox-{{folder.text | lowercase | clearWhiteSpaces}}"
+ sdc-checklist-model="checkboxesFilter.selectedStatuses"
+ sdc-checklist-value="folder.state"
+ text="{{folder.text}}"></sdc-checkbox>
+
+ <sdc-checkbox data-ng-if="!folder.isGroup() && folder.dist"
+ elem-id="checkbox-{{folder.text | lowercase | clearWhiteSpaces}}"
+ sdc-checklist-model="checkboxesFilter.distributed"
+ sdc-checklist-value="folder.dist"
+ text="{{folder.text}}"></sdc-checkbox>
+ <span class="i-sdc-left-sidebar-item-state-count">{{entitiesCount(folder)}}</span>
+ </div>
+ </div>
+
+ </div>
+
+ <top-nav top-lvl-selected-index="0" version="{{version}}" search-bind="search.filterTerm" notification-icon-callback="notificationIconCallback" version="{{version}}"></top-nav>
+
+</div>
+<div data-ui-view=""></div>
diff --git a/catalog-ui/app/scripts/view-models/dashboard/dashboard.less b/catalog-ui/app/scripts/view-models/dashboard/dashboard.less
new file mode 100644
index 0000000000..7b2522113b
--- /dev/null
+++ b/catalog-ui/app/scripts/view-models/dashboard/dashboard.less
@@ -0,0 +1,420 @@
+.sdc-dashboard-container {
+ .tlv-loader {
+ top: -110px;
+ left: 80px;
+ }
+ .sdc-hide-popover {
+ .popover {
+ display: none !important;
+ }
+ }
+}
+
+.w-sdc-left-sidebar-nav {
+ margin-top: 46px;
+}
+
+.w-sdc-main-right-container-element {
+ float: left;
+ height: 217px;
+ width: 217px;
+ margin: 10px;
+ position: relative;
+}
+
+.w-sdc-main-right-container-element-details-container {
+ position: absolute;
+ top: 165px;
+ left: 50px;
+}
+
+.w-sdc-main-right-container-element-name {
+ font-weight: bold;
+}
+
+.w-sdc-main-right-container-element-owner {
+
+}
+
+//////////////////////////////Cards////////////////////
+.w-sdc-dashboard-card-new {
+ border: 2px dashed @color_m;
+ .border-radius(2px);
+ cursor: pointer;
+ display: inline-block;
+ height: 200px;
+ margin: 9px;
+ position: relative;
+ vertical-align: middle;
+ width: 204px;
+}
+
+.w-sdc-dashboard-card-new-content {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ flex-direction: column;
+ height: 100%;
+}
+
+.w-sdc-dashboard-card-new-content-plus {
+ .sprite-new;
+ .add-icon;
+ position: relative;
+ margin-bottom: 20px;
+
+ &:after {
+ .n_14_m;
+ content: 'ADD';
+ position: absolute;
+ top: 25px;
+ left: -3px;
+ vertical-align: -50%;
+ }
+}
+
+.w-sdc-dashboard-card-import-content-plus {
+ .sprite-new;
+ .import-icon;
+ position: relative;
+ margin-bottom: 20px;
+
+ &:after {
+ .n_14_m;
+ content: 'IMPORT';
+ position: absolute;
+ top: 25px;
+ left: -16px;
+ vertical-align: -50%;
+ }
+}
+
+.sdc-dashboard-create-element-container,
+.sdc-dashboard-import-element-container {
+
+ width: 140px;
+
+ .tlv-btn.import-dcae {
+ padding: 0;
+ }
+
+ .tlv-btn {
+ position: relative;
+ width: 100%;
+ margin-bottom: 10px;
+
+ &:last-child {
+ margin-bottom: 0;
+ }
+ }
+
+ input[type="file"] {
+ cursor: inherit;
+ filter: alpha(opacity=0);
+ opacity: 0;
+ position: absolute;
+ top: 0;
+ left: 0;
+ width: 138px;
+ height: 30px;
+ }
+}
+
+.w-sdc-dashboard-card {
+ width: 204px;
+ height: 200px;
+ background-color: @main_color_p;
+ .border-radius(2px);
+ .box-shadow(0px 2px 2px 0px rgba(24, 24, 25, 0.05));
+ display: inline-block;
+ margin: 10px;
+ position: relative;
+ vertical-align: middle;
+ border: solid 1px @main_color_p;
+
+ &:hover {
+ border: solid 1px @main_color_o;
+ .box-shadow(3px 3px 2px 0px rgba(24, 24, 25, 0.05));
+ }
+
+ &:active {
+ border: solid 1px @main_color_c;
+ .box-shadow(3px 3px 2px 0px rgba(24, 24, 25, 0.05));
+ }
+}
+
+.w-sdc-dashboard-card-body {
+ .hand;
+ border-bottom: 1px solid @color_j;
+ height: 155px;
+ position: relative;
+ text-align: center;
+}
+
+.w-sdc-dashboard-card-description {
+ .c_3;
+ .hand;
+ background-color: rgba(57, 73, 84, 0.9);
+ border-radius: 4px 4px 0 0;
+ bottom: 0;
+ left: 0;
+ opacity: 0;
+ padding: 10px;
+ position: absolute;
+ right: 0;
+ text-align: left;
+ top: 0;
+ word-wrap: break-word;
+ z-index: 4;
+ min-height: 100px;
+ overflow: hidden;
+}
+
+
+.w-sdc-dashboard-card-schema {
+ margin-top: 30px;
+}
+
+.w-sdc-dashboard-card-edit {
+ .hand;
+ position: absolute;
+ right: 13px;
+ top: 15px;
+ z-index: 2;
+}
+
+.w-sdc-dashboard-card-footer {
+ padding: 3px 12px 10px 12px;
+ position: relative;
+}
+
+.w-sdc-dashboard-card-avatar {
+ .uppercase;
+ border-radius: 50%;
+ display: inline-block;
+ position: absolute;
+ left: -6px;
+ text-align: center;
+ top: -6px;
+
+ span {
+
+ background-color: @main_color_p;
+ .border-radius(15px);
+ color: @color_c;
+ content: '';
+ height: 30px;
+ text-align: center;
+ display: block;
+ border: solid 2px #ECEFF3;
+ padding: 3px 10px 2px 10px;
+
+ &.VF {
+ .j_14_m;
+ &::before {
+ content: 'VF';
+ }
+ }
+
+ &.VFC {
+ .j_14_m;
+ &::before {
+ content: 'VFC';
+ }
+ }
+
+ &.CP {
+ .j_14_m;
+ &::before {
+ content: 'CP';
+ }
+ }
+
+ &.VL {
+ .j_14_m;
+ &::before {
+ content: 'VL';
+ }
+ }
+
+ &.SERVICE {
+ .c_14_m;
+ &::before {
+ content: 'S';
+ }
+ }
+
+ &.PRODUCT {
+ .b_14_m;
+ &::before {
+ content: 'P';
+ }
+ }
+
+ &.green {
+ .d_12;
+ &::before {
+ content: 'R';
+ }
+ }
+ &.red {
+ .r_12;
+ &::before {
+ content: 'S';
+ }
+ }
+ &.dblack {
+ .s_12;
+ &::before {
+ content: 'P';
+ }
+ }
+ }
+}
+
+.w-sdc-dashboard-card-info {
+ display: inline-block;
+ vertical-align: middle;
+ max-width: 165px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.w-sdc-dashboard-card-info-name-container{
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ margin: 0 0 2px 10px;
+}
+.w-sdc-dashboard-card-info-name {
+ .m_14_m;
+ display: inline-block;
+ vertical-align: middle;
+ max-width: 165px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.w-sdc-dashboard-card-info-lifecycleState {
+ .m_13_m;
+ display: inline-block;
+ vertical-align: middle;
+ max-width: 165px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+}
+
+.w-sdc-dashboard-card-info-user {
+ .n_13_r;
+ line-height: 18px;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ white-space: nowrap;
+ width: 100%;
+}
+
+.w-sdc-dashboard-card-menu-button {
+ display: inline-block;
+ padding: 12px 0 0 10px;
+ position: absolute;
+ right: 12px;
+ top: 8px;
+ border-left: solid 1px @color_k;
+ height: 42px;
+
+ &:hover {
+ .w-sdc-dashboard-card-menu {
+ display: block;
+ }
+ }
+}
+
+.w-sdc-dashboard-card-menu {
+ .bg_c;
+ border-radius: 0 0 4px 4px;
+ border-top: 3px solid @color_a;
+ box-shadow: 0 2px 2px 0px rgba(0, 0, 0, 0.2);
+ color: @color_s;
+ display: none;
+ min-height: 30px;
+ padding: 9px 0;
+ position: absolute;
+ right: -27px;
+ width: 208px;
+ z-index: 9;
+ max-height: 164px;
+
+ &::before {
+ //TODO: Missing image for small blue triangle.
+ background-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAFCAYAAAB4ka1VAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAyZpVFh0WE1MOmNvbS5hZG9iZS54bXAAAAAAADw/eHBhY2tldCBiZWdpbj0i77u/IiBpZD0iVzVNME1wQ2VoaUh6cmVTek5UY3prYzlkIj8+IDx4OnhtcG1ldGEgeG1sbnM6eD0iYWRvYmU6bnM6bWV0YS8iIHg6eG1wdGs9IkFkb2JlIFhNUCBDb3JlIDUuNi1jMDE0IDc5LjE1Njc5NywgMjAxNC8wOC8yMC0wOTo1MzowMiAgICAgICAgIj4gPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4gPHJkZjpEZXNjcmlwdGlvbiByZGY6YWJvdXQ9IiIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bWxuczp4bXBNTT0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL21tLyIgeG1sbnM6c3RSZWY9Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9zVHlwZS9SZXNvdXJjZVJlZiMiIHhtcDpDcmVhdG9yVG9vbD0iQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgKFdpbmRvd3MpIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOkE1OTIzNDI1MENFQjExRTU4ODRERTI1MDM2REZCOUYzIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOkE1OTIzNDI2MENFQjExRTU4ODRERTI1MDM2REZCOUYzIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9InhtcC5paWQ6QTU5MjM0MjMwQ0VCMTFFNTg4NERFMjUwMzZERkI5RjMiIHN0UmVmOmRvY3VtZW50SUQ9InhtcC5kaWQ6QTU5MjM0MjQwQ0VCMTFFNTg4NERFMjUwMzZERkI5RjMiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz4gBXTlAAAAOElEQVR42mK0rp7NgASMgZgFiE/CBJjQJPcA8U4gNkdXAJMUAGJ+ZEVMaJIwAFfEhEUSRRFAgAEAVtgJyiLAPWAAAAAASUVORK5CYII=');
+ content: '';
+ display: block;
+ height: 21px;
+ position: absolute;
+ right: 24px;
+ top: -24px;
+ width: 184px;
+ background-repeat: no-repeat;
+ background-position: 175px 16px;
+ }
+}
+
+.i-sdc-dashboard-card-menu-item {
+ .hand;
+ line-height: 24px;
+ padding: 0 10px;
+ &:hover { .a_7; }
+}
+
+.w-sdc-dashboard-card-info-lifecycleState-icon{
+ position:absolute;
+ bottom:18px;
+ right:10px;
+}
+
+// Same for dashboard and catalog view.
+.w-sdc-dashboard-card-schema-image {
+ position: absolute;
+ top: 41%;
+
+ //TODO: Israel - remove this after getting the services sprite.
+ height: 45px;
+ width: 53px;
+ background-repeat: no-repeat;
+
+ // Center the icon vertical and horizontal.
+ margin: auto;
+ left: 0;
+ right: 0;
+ top: -10px;
+ bottom: 0;
+}
+
+/* dashboard card main icons */
+.w-sdc-dashboard-card-schema-image.service { .s-sdc-service }
+.w-sdc-dashboard-card-schema-image.resource { .s-sdc-resource }
+
+/* dashboard card statuses icons */
+.w-sdc-dashboard-card-edit.NOT_CERTIFIED_CHECKIN { .sprite; .s-sdc-state.NOT_CERTIFIED_CHECKIN; }
+.w-sdc-dashboard-card-edit.NOT_CERTIFIED_CHECKOUT { .sprite; .s-sdc-state.NOT_CERTIFIED_CHECKOUT; }
+.w-sdc-dashboard-card-edit.CERTIFIED { .sprite; .s-sdc-state.CERTIFIED; }
+.w-sdc-dashboard-card-edit.READY_FOR_CERTIFICATION { .sprite; .s-sdc-state.READY_FOR_CERTIFICATION; }
+.w-sdc-dashboard-card-edit.CERTIFICATION_IN_PROGRESS { .sprite; .s-sdc-state.CERTIFICATION_IN_PROGRESS; }
+.w-sdc-dashboard-card-edit.DISTRIBUTED { .sprite; .s-sdc-state.DISTRIBUTED; }
+
+.w-sdc-dashboard-card-avatar.green + .w-sdc-dashboard-card-edit.NOT_CERTIFIED_CHECKIN { .sprite; .s-sdc-state.NOT_CERTIFIED_CHECKIN.green; }
+.w-sdc-dashboard-card-avatar.green + .w-sdc-dashboard-card-edit.NOT_CERTIFIED_CHECKOUT { .sprite; .s-sdc-state.NOT_CERTIFIED_CHECKOUT.green; }
+.w-sdc-dashboard-card-avatar.green + .w-sdc-dashboard-card-edit.CERTIFIED { .sprite; .s-sdc-state.CERTIFIED.green; }
+.w-sdc-dashboard-card-avatar.green + .w-sdc-dashboard-card-edit.READY_FOR_CERTIFICATION { .sprite; .s-sdc-state.READY_FOR_CERTIFICATION.green; }
+.w-sdc-dashboard-card-avatar.green + .w-sdc-dashboard-card-edit.CERTIFICATION_IN_PROGRESS { .sprite; .s-sdc-state.CERTIFICATION_IN_PROGRESS.green; }
+.w-sdc-dashboard-card-avatar.green + .w-sdc-dashboard-card-edit.DISTRIBUTED { .sprite; .s-sdc-state.DISTRIBUTED.green; }
+
+.w-sdc-dashboard-card-avatar.red + .w-sdc-dashboard-card-edit.NOT_CERTIFIED_CHECKIN { .sprite; .s-sdc-state.NOT_CERTIFIED_CHECKIN.red; }
+.w-sdc-dashboard-card-avatar.red + .w-sdc-dashboard-card-edit.NOT_CERTIFIED_CHECKOUT { .sprite; .s-sdc-state.NOT_CERTIFIED_CHECKOUT.red; }
+.w-sdc-dashboard-card-avatar.red + .w-sdc-dashboard-card-edit.CERTIFIED { .sprite; .s-sdc-state.CERTIFIED.red; }
+.w-sdc-dashboard-card-avatar.red + .w-sdc-dashboard-card-edit.READY_FOR_CERTIFICATION { .sprite; .s-sdc-state.READY_FOR_CERTIFICATION.red; }
+.w-sdc-dashboard-card-avatar.red + .w-sdc-dashboard-card-edit.CERTIFICATION_IN_PROGRESS { .sprite; .s-sdc-state.CERTIFICATION_IN_PROGRESS.red; }
+.w-sdc-dashboard-card-avatar.red + .w-sdc-dashboard-card-edit.DISTRIBUTED { .sprite; .s-sdc-state.DISTRIBUTED.red; }