aboutsummaryrefslogtreecommitdiffstats
path: root/catalog-ui/app/scripts/view-models/workspace/tabs/distribution
diff options
context:
space:
mode:
Diffstat (limited to 'catalog-ui/app/scripts/view-models/workspace/tabs/distribution')
-rw-r--r--catalog-ui/app/scripts/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal-view-model.ts67
-rw-r--r--catalog-ui/app/scripts/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal-view.html126
-rw-r--r--catalog-ui/app/scripts/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal.less33
-rw-r--r--catalog-ui/app/scripts/view-models/workspace/tabs/distribution/distribution-view-model.ts135
-rw-r--r--catalog-ui/app/scripts/view-models/workspace/tabs/distribution/distribution-view.html171
-rw-r--r--catalog-ui/app/scripts/view-models/workspace/tabs/distribution/distribution.less361
6 files changed, 893 insertions, 0 deletions
diff --git a/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal-view-model.ts b/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal-view-model.ts
new file mode 100644
index 0000000000..c0d6aba915
--- /dev/null
+++ b/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal-view-model.ts
@@ -0,0 +1,67 @@
+/*-
+ * ============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';
+
+ interface IDistributionStatusModalViewModelScope {
+ distribution:Models.Distribution;
+ status:string;
+ getStatusCount(distributionComponent:Array<Models.DistributionComponent>):any;
+ getUrlName(url:string):string;
+ modalDitributionStatus:ng.ui.bootstrap.IModalServiceInstance;
+ footerButtons: Array<any>;
+ close(): void;
+ }
+
+ export class DistributionStatusModalViewModel {
+
+ static '$inject' = ['$scope','$modalInstance', 'data'];
+
+ constructor(private $scope:IDistributionStatusModalViewModelScope,
+ private $modalInstance:ng.ui.bootstrap.IModalServiceInstance,
+ private data:any
+ ) {
+ this.initScope();
+ }
+
+ private initScope = ():void => {
+ this.$scope.distribution = this.data.distribution;
+ this.$scope.status = this.data.status;
+ this.$scope.modalDitributionStatus = this.$modalInstance;
+
+ this.$scope.getUrlName = (url:string):string =>{
+ let urlName:string = _.last(url.split('/'));
+ return urlName;
+ };
+
+ this.$scope.close = ():void => {
+ this.$modalInstance.close();
+ };
+
+ this.$scope.footerButtons = [
+ {'name': 'Close', 'css': 'blue', 'callback': this.$scope.close }
+ ];
+
+ };
+
+
+ }
+}
diff --git a/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal-view.html b/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal-view.html
new file mode 100644
index 0000000000..b3393e99e0
--- /dev/null
+++ b/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal-view.html
@@ -0,0 +1,126 @@
+<sdc-modal modal="modalDitributionStatus" type="classic" class="w-sdc-classic-top-line-modal" buttons="footerButtons" header="Distribution by Status" show-close-button="true">
+
+ <div class="w-sdc-distribution-view">
+ <div class="w-sdc-distribution-view-header">
+
+ </div>
+
+
+ <perfect-scrollbar include-padding="true" class="w-sdc-distribution-view-content">
+ <div class="w-sdc-distribution-view-content-section w-sdc-distribute-parent-block">
+ <ul>
+ <li class="w-sdc-distribute-parent-block" >
+ <div class="w-sdc-distribute-row w-sdc-distribute-row-extends extends">
+
+ <div class="w-sdc-distribute-row-content">
+ <div class="w-sdc-distribute-content">
+ <div class="title-section item-1">
+ <div class="title">Distribution ID</div>
+ <div data-ng-bind="distribution.distributionID"></div>
+ </div>
+ <div class="title-section item-2">
+ <div class="title" translate="DISTRIBUTION_VIEW_TITLE_USER_ID"></div>
+ <div data-ng-bind="distribution.userId"></div>
+ </div>
+ <div class="title-section item-3">
+ <div class="title">Time[UTC]:</div>
+ <div
+ data-ng-bind="distribution.timestamp | stringToDateFilter | date: 'MM/dd/yyyy h:mma':'UTC'"></div>
+ </div>
+ <div class="title-section item-4">
+ <span class="sprite-new status-icon" data-ng-class="distribution.deployementStatus"></span>
+ <span class="sprite-new" data-ng-bind="distribution.deployementStatus"></span>
+ </div>
+ </div>
+ <div class="w-sdc-distribute-status-block" data-ng-show="distribution.statusCount">
+ <div class="status-item-1">Status: {{status}} <span data-ng-bind="(distribution.distributionComponents | filter:status:true).length"
+ class="blue-font"></span></div>
+
+ </div>
+ </div>
+ </div>
+
+ <ul class="w-sdc-distribute-components-block disable-hover">
+ <li data-ng-repeat="(omfComponentID,omfComponentList) in distribution.distributionComponents | orderBy: '-timestamp' | filter:status:true | groupBy:'omfComponentID'"
+ class="disable-hover">
+ <div class="w-sdc-distribute-row omf-component-row w-sdc-distribute-row-extends "
+ data-ng-class="{'extends': omfComponentListExtends}">
+ <div class="w-sdc-distribution-arrow-btn" data-ng-click="omfComponentListExtends=!omfComponentListExtends"
+ ng-class="{'extends': omfComponentListExtends}"
+ data-ng-init="omfComponentListExtends=false"
+ ></div>
+ <div class="w-sdc-distribute-status-block">
+ <div class="status-item-1">{{omfComponentID}} <span class="blue-font">{{omfComponentList.length}}</span>
+ </div>
+ </div>
+ </div>
+ <div data-ng-show="omfComponentListExtends"
+ class="w-sdc-distribute-omfComponent-block disable-hover">
+ <div class="w-sdc-distribute-row-extends disable-hover">
+ <div class="disable-hover">
+ <div class="w-sdc-distribute-row omfComponent-table-head">
+ <div class="title item-1">Component ID</div>
+ <div class="title item-2">Artifact Name</div>
+ <div class="title item-3">URL</div>
+ <div class="title item-4">Time(UTC)</div>
+ <div class="title item-5">Status</div>
+ </div>
+
+ <div class="w-sdc-distribute-row omfComponent-table-row"
+ data-ng-repeat-start="(url,urlList) in omfComponentList | orderBy: '-timestamp' | groupBy:'url'"
+ data-ng-class="urlListExtends?'extends row-{{$index}}':'row-{{$index}}'" >
+ <div class="w-sdc-distribute-cell item-1">
+ <div class="w-sdc-distribution-arrow-btn" data-ng-click="urlListExtends=!urlListExtends"
+ data-ng-class="{'extends': urlListExtends}"
+ data-ng-init="urlListListExtends=false"
+ ></div>
+ {{urlList[0].omfComponentID}}
+ </div>
+ <div class="w-sdc-distribute-cell item-2" sdc-smart-tooltip>
+ {{getUrlName(urlList[0].url)}}
+ </div>
+ <div class="w-sdc-distribute-cell item-3 disable-hover">
+ <div sdc-smart-tooltip class="distribution-url">{{urlList[0].url}}</div>
+ <div sdc-smart-tooltip title="Copy url" clipboard text="urlList[0].url"
+ class="sprite-new link-btn copy-link disable-hover"></div>
+ </div>
+ <div class="w-sdc-distribute-cell item-4"><span
+ data-ng-bind="urlList[0].timestamp | date: 'MM/dd/yyyy h:mma':'UTC'"></span>
+ </div>
+ <div class="w-sdc-distribute-cell item-5">{{urlList[0].status}}</div>
+ </div>
+
+
+ <div data-ng-repeat-end data-ng-show="urlListExtends" class="disable-hover">
+ <div class="w-sdc-distribute-row extends disable-hover">
+ <ul data-ng-show="urlListExtends"
+ class="w-sdc-distribute-url-block disable-hover">
+ <li data-ng-repeat="distributionComponent in urlList | orderBy: '-timestamp'"
+ class="disable-hover">
+ <span
+ data-ng-bind="distributionComponent.timestamp | date: 'MM/dd/yyyy h:mma':'UTC'"
+ class="disable-hover"></span>
+ <span
+ class="disable-hover">{{distributionComponent.status}}</span>
+ <span
+ class="disable-hover reason" data-ng-show="distributionComponent.status == 'NOT_NOTIFIED'">Reason: Component has determined artifact is not needed.</span>
+ <span
+ class="disable-hover reason" data-ng-show="distributionComponent.errorReason">Reason: {{distributionComponent.errorReason}}</span>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+
+ </perfect-scrollbar>
+ </div>
+
+
+</sdc-modal>
diff --git a/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal.less b/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal.less
new file mode 100644
index 0000000000..02321b6e2f
--- /dev/null
+++ b/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/disribution-status-modal/disribution-status-modal.less
@@ -0,0 +1,33 @@
+.w-sdc-classic-top-line-modal {
+
+ .w-sdc-modal-head {
+ // border-bottom: none;
+ }
+ .w-sdc-distribution-view {
+
+ .w-sdc-distribution-view-content {
+ height: 500px;
+ }
+
+ .w-sdc-distribution-view-content-section {
+
+ .w-sdc-distribute-parent-block {
+ .w-sdc-distribute-components-block {
+
+ .omf-component-row {
+ .w-sdc-distribute-status-block {
+ margin-left: 0;
+ }
+
+ }
+ div {
+ padding-left: 0;
+ }
+ }
+
+ }
+
+ }
+ }
+}
+
diff --git a/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/distribution-view-model.ts b/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/distribution-view-model.ts
new file mode 100644
index 0000000000..219585fc3d
--- /dev/null
+++ b/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/distribution-view-model.ts
@@ -0,0 +1,135 @@
+/*-
+ * ============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';
+
+ interface IDistributionViewModel extends IWorkspaceViewModelScope{
+ modalDistribution:ng.ui.bootstrap.IModalServiceInstance;
+ service: Models.Components.Service;
+ distributions : Array<Models.Distribution>;
+ showComponents(distribution:Models.Distribution): void;
+ markAsDeployed(distribution:Models.Distribution): void;
+ getStatusCount(distributionComponent:Array<Models.DistributionComponent>):any;
+ initDistributions():void;
+ getUrlName(url:string):string;
+ close(): void;
+ openDisributionStatusModal:Function;
+ }
+
+ export class DistributionViewModel{
+
+ static '$inject' = [
+ '$scope',
+ 'ModalsHandler'
+
+ ];
+
+ constructor(
+ private $scope:IDistributionViewModel,
+ private ModalsHandler: Sdc.Utils.ModalsHandler
+ ){
+ this.initScope();
+ this.$scope.setValidState(true);
+ this.$scope.updateSelectedMenuItem();
+ }
+
+ private initScope = (): void => {
+ this.$scope.service = <Models.Components.Service>this.$scope.component;
+
+
+ // Open Distribution status modal
+ this.$scope.openDisributionStatusModal = (distribution: Models.Distribution,status:string):void => {
+ this.ModalsHandler.openDistributionStatusModal(distribution,status).then(()=>{
+ // OK
+ }, ()=>{
+ // ERROR
+ });
+ };
+
+
+ this.$scope.showComponents = (distribution: Models.Distribution): void => {
+ let onError = (response) => {
+ console.info('onError showComponents',response);
+ };
+ let onSuccess = (distributionComponents: Array<Models.DistributionComponent>) => {
+ distribution.distributionComponents = distributionComponents;
+ distribution.statusCount = this.$scope.getStatusCount(distribution.distributionComponents);
+ // distribution.components = this.aggregateDistributionComponent(distributionComponents);;
+ };
+ this.$scope.service.getDistributionsComponent(distribution.distributionID).then(onSuccess, onError);
+ };
+
+ this.$scope.getStatusCount = (distributionComponent:Array<Models.DistributionComponent>):any => {
+ return _.countBy(distributionComponent, 'status')
+ };
+
+ this.$scope.getUrlName = (url:string):string =>{
+ let urlName:string = _.last(url.split('/'));
+ return urlName;
+ };
+
+ this.$scope.markAsDeployed = (distribution: Models.Distribution): void => {
+ let onError = (response) => {
+ console.info('onError markAsDeployed',response);
+ };
+ let onSuccess = (result: any) => {
+ distribution.deployementStatus = 'Deployed';
+ };
+ this.$scope.service.markAsDeployed(distribution.distributionID).then(onSuccess, onError);
+
+ };
+
+ this.$scope.initDistributions = (): void => {
+ let onError = (response) => {
+ console.info('onError initDistributions',response);
+ };
+ let onSuccess = (distributions: Array<Models.Distribution>) => {
+ this.$scope.distributions = distributions;
+ };
+ this.$scope.service.getDistributionsList().then(onSuccess, onError);
+ };
+
+ this.$scope.initDistributions();
+
+ };
+
+
+ private aggregateDistributionComponent = (distributionComponents:Array<Models.DistributionComponent>):any =>{
+ let aggregateDistributions:Utils.Dictionary<string,Utils.Dictionary<string,Array<Models.DistributionComponent>>> = new Utils.Dictionary<string,Utils.Dictionary<string,Array<Models.DistributionComponent>>>();
+ let tempAggregateDistributions:any= _.groupBy(distributionComponents,'omfComponentID');
+ let aa = new Utils.Dictionary<string,Array<Models.DistributionComponent>>();
+
+ let tempAggregate:any;
+ _.forEach(tempAggregateDistributions,(distributionComponents:Array<Models.DistributionComponent>,omfComponentID:string)=>{
+
+ let urls:any = _.groupBy(distributionComponents,'url');
+ aggregateDistributions.setValue(omfComponentID,urls);
+ // aggregateDistributions[omfComponentID] = ;
+
+ });
+ console.log(aggregateDistributions);
+ return aggregateDistributions;
+ };
+
+
+ }
+}
diff --git a/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/distribution-view.html b/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/distribution-view.html
new file mode 100644
index 0000000000..1ab0f1e111
--- /dev/null
+++ b/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/distribution-view.html
@@ -0,0 +1,171 @@
+<div class="w-sdc-distribution-view">
+ <div class="w-sdc-distribution-view-header">
+ <div class="w-sdc-distribution-view-title">DISTRIBUTION <span data-ng-bind="'[' + distributions.length +']'"
+ class="blue-font"></span></div>
+ <div class="header-spacer"></div>
+ <div class="top-search">
+ <input type="text"
+ class="search-text"
+ data-tests-id="searchTextbox"
+ placeholder="Search"
+ data-ng-model="searchBind"
+ data-tests-id="main-menu-input-search"
+ ng-model-options="{ debounce: 500 }"/>
+ <span class="w-sdc-search-icon magnification"></span>
+ </div>
+ <div class="sprite-new refresh-btn" data-tests-id="refreshButton" data-ng-click="initDistributions()" sdc-smart-tooltip=""
+ title="Refresh"></div>
+ </div>
+
+
+ <perfect-scrollbar include-padding="true" class="w-sdc-distribution-view-content">
+ <div class="w-sdc-distribution-view-content-section" data-tests-id="ditributionTable">
+ <ul>
+ <li data-ng-repeat="item in distributions | orderBy: '-timestamp' | filter:searchBind"
+ data-ng-init="item.dateFormat = ( item.timestamp | stringToDateFilter | date: 'MM/dd/yyyy h:mma':'UTC' )"
+ class="w-sdc-distribute-parent-block" data-tests-id="record_{{$index}}" data-ng-class="{'extends': item.showDetails}">
+ <div class="w-sdc-distribute-row w-sdc-distribute-row-extends"
+ data-ng-class="{'extends': item.showDetails && item.distributionComponents.length}">
+ <div class="w-sdc-distribution-arrow-btn" data-tests-id="ShowRecordButton_{{$index}}" data-ng-click="showComponents(item); item.showDetails=!item.showDetails"
+ data-ng-class="{'extends': item.showDetails}"
+ ></div>
+ <div class="w-sdc-distribute-row-content">
+ <div class="w-sdc-distribute-content">
+ <div class="title-section item-1">
+ <div class="title">Distribution ID</div>
+ <div data-ng-bind="item.distributionID"></div>
+ </div>
+ <div class="title-section item-2">
+ <div class="title" translate="DISTRIBUTION_VIEW_TITLE_USER_ID"></div>
+ <div data-ng-bind="item.userId"></div>
+ </div>
+ <div class="title-section item-3">
+ <div class="title">Time[UTC]:</div>
+ <div
+ data-ng-bind="item.dateFormat"></div>
+ </div>
+ <div class="title-section item-4">
+ <span class="sprite-new status-icon" data-ng-class="item.deployementStatus"></span>
+ <span class="sprite-new" data-ng-bind="item.deployementStatus"></span>
+ </div>
+ <div>
+ <div class="sprite-new distribution-bth item-5"
+ data-ng-class="{'disable':item.deployementStatus==='Deployed'}"
+ data-ng-click="(item.deployementStatus==='Deployed') || markAsDeployed(item)"></div>
+ </div>
+ </div>
+ <div class="w-sdc-distribute-status-block" data-ng-show="item.statusCount">
+ <div class="status-item-1">Total Artifacts:<span data-ng-bind="(item.statusCount.NOT_NOTIFIED || 0) + (item.statusCount.NOTIFIED || 0) "
+ class="blue-font" data-tests-id="totalArtifacts_{{$index}}"></span></div>
+ <div class="status-item-2 " ><sapn class="link" data-ng-click="openDisributionStatusModal(item,'NOTIFIED')">Notified:</sapn><span
+ data-ng-bind="item.statusCount.NOTIFIED || 0" class="blue-font" data-tests-id="notified_{{$index}}"></span></div>
+ <div class="status-item-3 link" ><sapn class="link" data-ng-click="openDisributionStatusModal(item,'DOWNLOAD_OK')">Downloaded:</sapn><span
+ data-ng-bind="item.statusCount.DOWNLOAD_OK || 0" class="blue-font" data-tests-id="downloaded_{{$index}}"></span></div>
+ <div class="status-item-4 link"><sapn class="link" data-ng-click="openDisributionStatusModal(item,'DEPLOY_OK')">Deployed:</sapn><span
+ data-ng-bind="item.statusCount.DEPLOY_OK || 0" class="blue-font" data-tests-id="deployed_{{$index}}" ></span><span
+ data-ng-class="{'deployed':(item.statusCount.DEPLOY_OK > 0)}"></span></div>
+ <div class="status-item-5 link" ><sapn class="link" data-ng-click="openDisributionStatusModal(item,'NOT_NOTIFIED')">Not Notified:</sapn><span
+ data-ng-bind="item.statusCount.NOT_NOTIFIED || 0" class="blue-font" data-tests-id="NotNotified_{{$index}}"></span></div>
+ <div class="status-item-6"><sapn class="link" data-ng-click="openDisributionStatusModal(item,'DOWNLOAD_ERROR')" >Errors:</sapn><span
+ data-ng-bind="item.statusCount.DOWNLOAD_ERROR || 0" class="red-font "></span><span
+ data-ng-class="{'error':(item.statusCount.DOWNLOAD_ERROR > 0)}" data-tests-id="errors_{{$index}}"></span></div>
+ </div>
+ </div>
+ </div>
+
+ <ul data-ng-show="item.showDetails && item.distributionComponents.length"
+ class="w-sdc-distribute-components-block disable-hover">
+
+ <li data-ng-repeat="(omfComponentID,omfComponentList) in item.distributionComponents | orderBy: '-timestamp' | filter:searchBind | groupBy:'omfComponentID' "
+ class="disable-hover"
+ data-ng-init="statusCount = getStatusCount(omfComponentList);">
+ <div class="w-sdc-distribute-row omf-component-row w-sdc-distribute-row-extends"
+ data-ng-class="{'extends': omfComponentListExtends}">
+ <div class="w-sdc-distribution-arrow-btn" data-ng-click="omfComponentListExtends=!omfComponentListExtends"
+ ng-class="{'extends': omfComponentListExtends}"
+ data-ng-init="omfComponentListExtends=false"
+ ></div>
+ <div class="w-sdc-distribute-status-block">
+ <div class="status-item-1">{{omfComponentID}} <span class="blue-font">{{(statusCount.NOT_NOTIFIED || 0) + (statusCount.NOTIFIED || 0) }}</span>
+ </div>
+ <div class="status-item-2">Notified:<span data-ng-bind="statusCount.NOTIFIED || 0"
+ class="blue-font"></span></div>
+ <div class="status-item-3">Downloaded:<span
+ data-ng-bind="statusCount.DOWNLOAD_OK || 0" class="blue-font"></span></div>
+ <div class="status-item-4">Deployed:<span data-ng-bind="statusCount.DEPLOY_OK || 0"
+ class="blue-font"></span><span
+ data-ng-class="{'deployed':(statusCount.DEPLOY_OK > 0)}"></span></div>
+ <div class="status-item-5">Not Notified:<span
+ data-ng-bind="statusCount.NOT_NOTIFIED || 0" class="blue-font"></span></div>
+ <div class="status-item-6">Errors:<span
+ data-ng-bind="statusCount.DOWNLOAD_ERROR || 0" class="red-font"></span><span
+ data-ng-class="{'error':(statusCount.DOWNLOAD_ERROR > 0)}"></span></div>
+ </div>
+ </div>
+ <div data-ng-show="omfComponentListExtends"
+ class="w-sdc-distribute-omfComponent-block disable-hover">
+ <div class="w-sdc-distribute-row-extends disable-hover">
+ <div class="disable-hover">
+ <div class="w-sdc-distribute-row omfComponent-table-head">
+ <div class="title item-1">Component ID</div>
+ <div class="title item-2">Artifact Name</div>
+ <div class="title item-3">URL</div>
+ <div class="title item-4">Time(UTC)</div>
+ <div class="title item-5">Status</div>
+ </div>
+
+ <div class="w-sdc-distribute-row omfComponent-table-row"
+ data-ng-repeat-start="(url,urlList) in omfComponentList | orderBy: '-timestamp' | groupBy:'url'"
+ data-ng-class="urlListExtends?'extends row-{{$index}}':'row-{{$index}}'">
+ <div class="w-sdc-distribute-cell item-1">
+ <div class="w-sdc-distribution-arrow-btn" data-ng-click="urlListExtends=!urlListExtends"
+ data-ng-class="{'extends': urlListExtends}"
+ data-ng-init="urlListListExtends=false"
+ ></div>
+ {{urlList[0].omfComponentID}}
+ </div>
+ <div class="w-sdc-distribute-cell item-2" sdc-smart-tooltip>
+ {{getUrlName(urlList[0].url)}}
+ </div>
+ <div class="w-sdc-distribute-cell item-3 disable-hover">
+ <div sdc-smart-tooltip class="distribution-url">{{urlList[0].url}}</div>
+ <div sdc-smart-tooltip title="Copy url" clipboard text="urlList[0].url"
+ class="sprite-new link-btn copy-link disable-hover"></div>
+ </div>
+ <div class="w-sdc-distribute-cell item-4"><span
+ data-ng-bind="urlList[0].timestamp | date: 'MM/dd/yyyy h:mma':'UTC'"></span>
+ </div>
+ <div class="w-sdc-distribute-cell item-5">{{urlList[0].status}}</div>
+ </div>
+
+
+ <div data-ng-repeat-end data-ng-show="urlListExtends" class="disable-hover" >
+ <div class="w-sdc-distribute-row extends disable-hover">
+ <ul data-ng-show="urlListExtends"
+ class="w-sdc-distribute-url-block disable-hover">
+ <li data-ng-repeat="distributionComponent in urlList | orderBy: '-timestamp'"
+ class="disable-hover">
+ <span
+ data-ng-bind="distributionComponent.timestamp | date: 'MM/dd/yyyy h:mma':'UTC'"
+ class="disable-hover"></span>
+ <span
+ class="disable-hover">{{distributionComponent.status}}</span>
+ <span
+ class="disable-hover reason" data-ng-show="distributionComponent.status == 'NOT_NOTIFIED'">Reason: Component has determined artifact is not needed.</span>
+ <span
+ class="disable-hover reason" data-ng-show="distributionComponent.errorReason">Reason: {{distributionComponent.errorReason}}</span>
+ </li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ </div>
+ </div>
+ </li>
+ </ul>
+ </li>
+ </ul>
+ </div>
+
+ </perfect-scrollbar>
+</div>
diff --git a/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/distribution.less b/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/distribution.less
new file mode 100644
index 0000000000..8ad8c1793e
--- /dev/null
+++ b/catalog-ui/app/scripts/view-models/workspace/tabs/distribution/distribution.less
@@ -0,0 +1,361 @@
+
+.w-sdc-distribution-view {
+ text-align: left;
+
+ .g_1;
+ min-height: 500px;
+
+ .w-sdc-distribution-view-distributed-green-text {
+ .l_9;
+ .bold;
+ }
+ .w-sdc-distribution-view-distributed-error-red-text {
+ .h_9;
+ .bold;
+ }
+
+ .bg_c;
+ vertical-align: top;
+ padding: 30px 10px;
+ width: 100%;
+
+ .w-sdc-distribution-view-header {
+ display: flex;
+ -webkit-justify-content: space-between;
+ margin: 0 25px 5px 40px;
+
+ .header-spacer {
+ flex-grow: 5;
+ }
+ }
+
+ .top-search {
+ position: relative;
+ input {
+ &.search-text {
+ height: 26px;
+ line-height: 26px;
+ margin: 0 18px 4px 20px;
+ padding-right: 25px;
+ }
+
+ }
+ .magnification {
+ top: 8px;
+ right: 25px;
+ }
+ }
+
+ .w-sdc-distribution-view-content {
+ .perfect-scrollbar;
+ padding: 0 25px 0 0px;
+ margin-bottom: 25px;
+ height: 700px;
+ overflow: hidden;
+ position: relative;
+
+ }
+
+ .w-sdc-distribution-view-title {
+ .s_14_r;
+
+ line-height: 30px;
+
+ span {
+ padding-left: 5px;
+ }
+ }
+
+ .blue-font {
+ .a_14_m;
+
+ }
+
+ .red-font {
+ .q_14_m;
+ }
+
+ .w-sdc-distribution-view-block {
+ div {
+ display: inline-block;
+ }
+ }
+
+ .w-sdc-distribution-view-content-section {
+ ul {
+ list-style-type: none;
+ }
+
+ .distribution-bth {
+ .hand;
+ &.disabled {
+ cursor: none;
+ }
+ }
+
+ .copy-link {
+ padding-right: 19px;
+ margin-left: 8px;
+ cursor: pointer;
+
+ }
+
+ .w-sdc-distribute-row-extends {
+ border-Left: solid 4px transparent;
+ &.extends {
+ border-left: solid 4px @main_color_c;
+ border-bottom: 1px solid @border_color_f;
+ margin-bottom: 10px;
+ }
+ }
+ .w-sdc-distribute-parent-block {
+ border: 1px solid @main_color_o;;
+ width: 100%;
+ margin-bottom: 6px;
+
+ .status-icon {
+ vertical-align: middle;
+ margin-bottom: 4px;
+ }
+
+ &.extends {
+ background-color: @tlv_color_t;
+ }
+
+ :not(.disable-hover):hover {
+ background-color: @tlv_color_u;
+ }
+
+ .title-section {
+ display: inline-block;
+ margin-right: 10px;
+ flex-basis: 0;
+ }
+
+ .title {
+ .l_12_m;
+ font-weight: bold;
+ }
+ .w-sdc-distribute-content {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-left: 10px;
+ }
+
+ .w-sdc-distribution-arrow-btn {
+ .sprite-new;
+ .arrow-up-small;
+ margin: 0 6px;
+ }
+ .extends.w-sdc-distribution-arrow-btn {
+ -webkit-transform: rotate(180deg);
+ -ms-transform: rotate(180deg);
+ transform: rotate(180deg);
+ }
+
+ .w-sdc-distribute-row {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+
+ .w-sdc-distribute-row-content {
+ margin: 15px 31px 10px 0;
+ width: 100%;
+ .w-sdc-distribute-status-block {
+ border-top: solid 1px @main_color_o;
+ }
+ .item-1 {
+ flex-grow: 2;
+ }
+ .item-2 {
+ flex-grow: 1;
+ }
+ .item-3 {
+ flex-grow: 1;
+ }
+ .item-4 {
+ flex-grow: 1;
+ }
+ .item-5 {
+ flex-grow: 1;
+ }
+ }
+ }
+
+ .w-sdc-distribute-status-block {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin: 10px 5px 0 5px;
+ padding: 5px 5px 0 5px;;
+ width: 100%;
+ div {
+ border-left: 1px solid @main_color_o;
+ padding: 0 12px;
+ }
+
+ .link {
+ .a_14_m;
+ cursor: pointer;
+ &:hover{
+ text-decoration: underline;
+ .b_14_m;
+ }
+ }
+
+ span {
+ padding: 2px;
+ }
+
+ .deployed {
+ margin-left: 10px;
+ .sprite-new;
+ .success-circle-small;
+ }
+
+ .error {
+ .q_14_m;
+ margin-left: 10px;
+ .sprite-new;
+ .error-icon;
+ }
+
+ .status-item-1 {
+ border-left: 0;
+ }
+
+ .status-item-6 {
+ flex-grow: 1;
+ border-left: none;
+ text-align: right;
+ }
+ }
+
+ .w-sdc-distribute-components-block {
+ padding: 0;
+ padding-bottom: 5px;
+ list-style-type: none;
+
+ li {
+ margin: 5px 2px;
+ }
+
+ .omf-component-row {
+ border: 1px solid @border_color_f;
+ padding-left: 3px;
+ background-color: white;
+ margin: 0 30px;
+ &.extends {
+ padding-left: 0;
+ border-Left: solid 4px @main_color_c;
+
+ }
+
+ .w-sdc-distribute-status-block {
+ margin: 5px;
+ padding: 5px;
+ }
+
+ .blue-font {
+ .a_16_m;
+
+ }
+
+ &:hover {
+ background-color: @tlv_color_u;
+ }
+
+ }
+
+ }
+
+ .w-sdc-distribute-omfComponent-block {
+ background-color: white;
+ margin: 0 30px;
+ padding: 8px 10px;
+ border: 1px solid @border_color_f;
+
+ .omfComponent-table-head {
+ margin-bottom: 5px;
+ background-color: @tlv_color_u;
+ .title {
+ padding: 6px 10px;
+ border-left: 1px solid @border_color_f;
+ &:first-child {
+ border: none;
+ }
+ }
+ }
+
+ .omfComponent-table-row {
+ border-bottom: 1px solid @border_color_f;
+ &.row-0 {
+ border-top: 1px solid @border_color_f;
+ }
+ .w-sdc-distribute-cell {
+ padding: 10px;
+ border-left: 1px solid @border_color_f;
+ &:last-child {
+ border-right: 1px solid @border_color_f;
+ }
+ &.item-5 {
+ .m_14_m;
+ }
+ }
+ }
+
+ .distribution-url {
+
+ }
+
+ .w-sdc-distribute-row.extends {
+ border-Left: solid 4px @main_color_c;
+ .item-1 {
+ border: none;
+ }
+
+ }
+
+ .item-1 {
+ width: 20%;
+ }
+ .item-2 {
+ width: 20%;
+ }
+
+ .item-3 {
+ width: 24%;
+ display: flex;
+ }
+
+ .item-4 {
+ width: 18%;
+ }
+
+ .item-5 {
+ width: 18%;
+ }
+ }
+
+ .w-sdc-distribute-url-block {
+
+ padding: 10px 15px;
+ border: none;
+ border-right: 1px solid @border_color_f;
+ border-bottom: 1px solid @border_color_f;
+ width: 100%;
+ li {
+ border: none;
+ span {
+ padding-right: 30px;
+ .m_12_r;
+ }
+ }
+
+ }
+ }
+
+ }
+}
+