You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@brooklyn.apache.org by he...@apache.org on 2022/10/21 13:58:11 UTC

[brooklyn-ui] 02/24: workflow UI polish, subworkflows, bug-fixes

This is an automated email from the ASF dual-hosted git repository.

heneveld pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/brooklyn-ui.git

commit 0714fb85b637c070e5daac8b869f82d2c9d4ee8a
Author: Alex Heneveld <al...@cloudsoft.io>
AuthorDate: Tue Oct 4 23:03:40 2022 +0100

    workflow UI polish, subworkflows, bug-fixes
---
 .../components/workflow/workflow-step.directive.js |  1 +
 .../workflow/workflow-step.template.html           | 34 ++++++---
 .../workflow/workflow-steps.directive.js           |  2 +-
 .../app/components/workflow/workflow-steps.less    |  7 ++
 .../inspect/activities/detail/detail.controller.js | 70 ++++++++++++++-----
 .../main/inspect/activities/detail/detail.less     | 31 +++++++--
 .../inspect/activities/detail/detail.template.html | 81 ++++++++++++++++------
 7 files changed, 174 insertions(+), 52 deletions(-)

diff --git a/ui-modules/app-inspector/app/components/workflow/workflow-step.directive.js b/ui-modules/app-inspector/app/components/workflow/workflow-step.directive.js
index 9a322297..e22cf1e2 100644
--- a/ui-modules/app-inspector/app/components/workflow/workflow-step.directive.js
+++ b/ui-modules/app-inspector/app/components/workflow/workflow-step.directive.js
@@ -61,6 +61,7 @@ export function workflowStepDirective() {
             vm.yaml = (data) => jsyaml.dump(data);
             vm.yamlOrPrimitive = (data) => typeof data === "string" ? data : vm.yaml(data);
             vm.nonEmpty = (data) => data && (data.length || Object.keys(data).length);
+            vm.isNullish = _.isNil;
 
             $scope.json = null;
             $scope.jsonMode = null;
diff --git a/ui-modules/app-inspector/app/components/workflow/workflow-step.template.html b/ui-modules/app-inspector/app/components/workflow/workflow-step.template.html
index b3ac63c9..a9d4848b 100644
--- a/ui-modules/app-inspector/app/components/workflow/workflow-step.template.html
+++ b/ui-modules/app-inspector/app/components/workflow/workflow-step.template.html
@@ -97,15 +97,15 @@
                     </span>
 
                     <span ng-if="isFocusTask">
-                        in this task ({{ stepContext.taskId }}).
+                        as the activity currently being viewed (<span class="monospace">{{ stepContext.taskId }}</span>).
                     </span>
                     <span ng-if="!isFocusTask">
-                        in <a ui-sref="main.inspect.activities.detail({applicationId: workflow.applicationId, entityId: workflow.entityId, activityId: stepContext.taskId })">Task {{ stepContext.taskId }}</a>.
+                        in <a ui-sref="main.inspect.activities.detail({applicationId: workflow.applicationId, entityId: workflow.entityId, activityId: stepContext.taskId })">task <span class="monospace">{{ stepContext.taskId }}</span></a>.
                     </span>
                 </div>
 
                 <div ng-if="isFocusStep && !isFocusTask" class="space-above">
-                    <b>The currently selected task ({{ task.id }}) is for a previous invocation of this step.</b>
+                    <b>The activity currently being viewed (<span class="monospace">{{ task.id }}</span>) is for a previous run of this step.</b>
                 </div>
 
                 <div  class="more-space-above">
@@ -126,10 +126,11 @@
                         <div class="A"><span ng-if="isCurrent">CURRENT</span><span ng-if="!isCurrent">LAST</span> EXECUTION</div>
                         <div class="B">
                                     <span ng-if="isFocusTask">
-                                        Task {{ stepContext.taskId }}
+                                        task <span class="monospace">{{ stepContext.taskId }}</span>
                                     </span>
                             <span ng-if="!isFocusTask">
-                                         <a ui-sref="main.inspect.activities.detail({applicationId: workflow.applicationId, entityId: workflow.entityId, activityId: stepContext.taskId })">Task {{ stepContext.taskId }}</a>
+                                         <a ui-sref="main.inspect.activities.detail({applicationId: workflow.applicationId, entityId: workflow.entityId, activityId: stepContext.taskId })"
+                                            >task <span class="monospace">{{ stepContext.taskId }}</span></a>
                                     </span>
                         </div>
                     </div>
@@ -138,19 +139,34 @@
                             <span ng-if="osi.previousTaskId">
                                 Step {{ osi.previous[0]+1 }}
                                 (<a ui-sref="main.inspect.activities.detail({applicationId: workflow.applicationId, entityId: workflow.entityId, activityId: osi.previousTaskId })"
-                                    >Task {{ osi.previousTaskId }}</a>)
+                                    >task <span class="monospace">{{ osi.previousTaskId }}</span></a>)
                             </span>
                             <span ng-if="!osi.previousTaskId">(workflow start)</span>
                         </div></div>
+
                         <div class="data-row nested" ng-if="!isCurrent"><div class="A">Followed by</div> <div class="B">
                             <span ng-if="osi.nextTaskId">
                                 Step {{ osi.next[0]+1 }}
                                 (<a ui-sref="main.inspect.activities.detail({applicationId: workflow.applicationId, entityId: workflow.entityId, activityId: osi.nextTaskId })"
-                                    >Task {{ osi.nextTaskId }}</a>)
+                                    >task <span class="monospace">{{ osi.nextTaskId }}</span></a>)
                             </span>
                             <span ng-if="!osi.nextTaskId">(workflow end)</span>
                         </div></div>
 
+                        <div class="data-row nested with-buttons" ng-if="stepContext.subWorkflows && stepContext.subWorkflows.length"><div class="A" style="margin-top: 2px;">Sub-workflows</div> <div class="B">
+                            <div class="btn-group" uib-dropdown>
+                                <button id="workflow-button" type="button" class="btn btn-select-dropdown workflow-button-small" uib-dropdown-toggle>
+                                    {{ stepContext.subWorkflows.length }} nested workflow{{ stepContext.subWorkflows.length>1 ? 's' : '' }} <span class="caret"></span>
+                                </button>
+                                <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="workflow-button">
+                                    <li role="menuitem" ng-repeat="sub in stepContext.subWorkflows" id="sub-workflow-{{ sub.workflowId }}">
+                                        <a href="" ui-sref="main.inspect.activities.detail({applicationId: sub.applicationId, entityId: sub.entityId, activityId: sub.workflowId})">
+                                            <i class="fa fa-check check"></i>
+                                            <span class="monospace">{{ sub.workflowId }}</span></a> </li>
+                                </ul>
+                            </div>
+                        </div></div>
+
                         <div class="data-row nested" ng-if="osi.workflowScratch"><div class="A">Workflow Vars</div> <div class="B multiline-code">{{ vm.yaml(osi.workflowScratch) }}</div></div>
                         <div class="data-row nested" ng-if="stepContext.input"><div class="A">Input</div> <div class="B multiline-code">{{ vm.yaml(stepContext.input) }}</div></div>
                         <div class="data-row nested" ng-if="!isCurrent && stepContext.output"><div class="A">Output</div> <div class="B multiline-code">{{ vm.yaml(stepContext.output) }}</div></div>
@@ -165,10 +181,10 @@
             <div class="more-space-above" ng-if="vm.nonEmpty(stepContext) || vm.nonEmpty(step) || vm.nonEmpty(osi)">
 
                 <div class="btn-group right" uib-dropdown>
-                    <button id="single-button" type="button" class="btn btn-select-dropdown pull-right" uib-dropdown-toggle>
+                    <button id="extra-data-button" type="button" class="btn btn-select-dropdown pull-right" uib-dropdown-toggle>
                         View data <span class="caret"></span>
                     </button>
-                    <ul class="dropdown-menu pull-right" uib-dropdown-menu role="menu" aria-labelledby="single-button">
+                    <ul class="dropdown-menu pull-right" uib-dropdown-menu role="menu" aria-labelledby="extra-data-button">
                         <li role="menuitem" > <a href="" ng-click="vm.showJson('stepContext', stepContext)" ng-class="{'selected' : jsonMode === 'stepContext'}">
                             <i class="fa fa-check check"></i>
                             Last Execution Context</a> </li>
diff --git a/ui-modules/app-inspector/app/components/workflow/workflow-steps.directive.js b/ui-modules/app-inspector/app/components/workflow/workflow-steps.directive.js
index 1d509ada..8eb950d0 100644
--- a/ui-modules/app-inspector/app/components/workflow/workflow-steps.directive.js
+++ b/ui-modules/app-inspector/app/components/workflow/workflow-steps.directive.js
@@ -54,7 +54,7 @@ export function workflowStepsDirective() {
         }
 
         $scope.expandStates = {};
-        if ($scope.workflow.tag && $scope.workflow.tag.stepIndex) {
+        if ($scope.workflow.tag && !_.isNil($scope.workflow.tag.stepIndex)) {
             $scope.expandStates[$scope.workflow.tag.stepIndex] = true;
         }
 
diff --git a/ui-modules/app-inspector/app/components/workflow/workflow-steps.less b/ui-modules/app-inspector/app/components/workflow/workflow-steps.less
index 0a9bd803..2c067037 100644
--- a/ui-modules/app-inspector/app/components/workflow/workflow-steps.less
+++ b/ui-modules/app-inspector/app/components/workflow/workflow-steps.less
@@ -122,6 +122,7 @@
         display: flex;
         margin-top: 3px;
         margin-bottom: 3px;
+        align-items: baseline;
         .A {
           flex: 0 0 auto;
           width: 30%;
@@ -134,6 +135,9 @@
         }
         .B {
           flex: 1 1 auto;
+          &.multiline-code {
+            margin-top: 3px;
+          }
         }
 
         &.nested {
@@ -171,6 +175,9 @@
         }
       }
     }
+    .workflow-button-small {
+      padding: 1px 5px;
+    }
   }
 
   .workflow-step-status-indicators {
diff --git a/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.controller.js b/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.controller.js
index 02388f97..7ef65aba 100644
--- a/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.controller.js
+++ b/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.controller.js
@@ -43,6 +43,7 @@ function DetailController($scope, $state, $stateParams, $log, $uibModal, $timeou
         activityId: activityId,
         childFilter: {'EFFECTOR': true, 'SUB-TASK': false},
         accordion: {summaryOpen: true, subTaskOpen: true, streamsOpen: true, workflowOpen: true},
+        activity: {},
         workflow: {},
     };
 
@@ -52,7 +53,39 @@ function DetailController($scope, $state, $stateParams, $log, $uibModal, $timeou
     let observers = [];
 
     if ($state.current.name === detailState.name) {
-        
+
+        function loadWorkflow(workflowTag, optimistic) {
+            if (!workflowTag) {
+                workflowTag = {}
+                optimistic = true;
+            }
+            vm.model.workflow.loading = 'loading';
+
+            return entityApi.getWorkflow(workflowTag.applicationId || applicationId, workflowTag.entityId || entityId, workflowTag.workflowId || activityId).then(wResponse => {
+                workflowTag = {applicationId, entityId, workflowId: activityId, ...workflowTag};
+                if (optimistic) {
+                    vm.model.workflow.tag = workflowTag;
+                }
+                vm.model.workflow.data = wResponse.data;
+                vm.model.workflow.loading = 'loaded';
+                vm.model.workflow.applicationId = workflowTag.applicationId;
+                vm.model.workflow.entityId = workflowTag.entityId;
+
+                observers.push(wResponse.subscribe((wResponse2)=> {
+                    // change the workflow object so widgets get refreshed
+                    vm.model.workflow = { ...vm.model.workflow, data: wResponse2.data };
+                }));
+            }).catch(error => {
+                if (optimistic) {
+                    vm.model.workflow.loading = null;
+                    throw error;
+                }
+
+                console.log("ERROR loading workflow " + workflowTag.workflowId, error);
+                vm.model.workflow.loading = 'error';
+            });
+        };
+
         activityApi.activity(activityId).then((response)=> {
             vm.model.activity = response.data;
 
@@ -72,21 +105,7 @@ function DetailController($scope, $state, $stateParams, $log, $uibModal, $timeou
                 const workflowTag = findWorkflowTag(vm.model.activity);
                 if (workflowTag) {
                     vm.model.workflow.tag = workflowTag;
-                    vm.model.workflow.loading = 'loading';
-                    entityApi.getWorkflow(applicationId, entityId, workflowTag.workflowId).then(wResponse => {
-                        vm.model.workflow.data = wResponse.data;
-                        vm.model.workflow.loading = 'loaded';
-                        vm.model.workflow.applicationId = applicationId;
-                        vm.model.workflow.entityId = entityId;
-
-                        observers.push(wResponse.subscribe((wResponse2)=> {
-                           // change the workflow object so widgets get refreshed
-                           vm.model.workflow = { ...vm.model.workflow, data: wResponse2.data };
-                        }));
-                    }).catch(error => {
-                        console.log("ERROR loading workflow " + workflowTag.workflowId, error);
-                        vm.model.workflow.loading = 'error';
-                    });
+                    loadWorkflow(workflowTag);
                 }
             }
 
@@ -96,12 +115,24 @@ function DetailController($scope, $state, $stateParams, $log, $uibModal, $timeou
                 vm.error = undefined;
                 vm.errorBasic = false;
             }));
+
         }).catch((error)=> {
             $log.warn('Error loading activity for '+activityId, error);
             // prefer this simpler error message over the specific ones below
             vm.errorBasic = true;
             vm.error = $sce.trustAsHtml('Cannot load activity with ID: <b>' + _.escape(activityId) + '</b> <br/><br/>' +
                 'Task may have completed and been cleared from memory, or may not have been run. Details may be available in logs.');
+
+            // in case it corresponds to a workflow and not a task, try loading as a workflow
+
+            loadWorkflow(null).then(()=> {
+                // give a better error
+                vm.error = $sce.trustAsHtml('Information on workflow <b>' + _.escape(activityId) + '</b> is available but with limitations.<br/><br/>' +
+                    'The initial task is no longer available, possibly because this workflow has been resumed after a restart.');
+
+            }).catch(error2 => {
+                $log.debug("ID "+activityId+" does not correspond to workflow either", error2);
+            });
         });
 
         activityApi.activityChildren(activityId).then((response)=> {
@@ -173,7 +204,6 @@ function DetailController($scope, $state, $stateParams, $log, $uibModal, $timeou
         $timeout(function() { $scope.$broadcast('resize') }, 100);
     };
 
-    vm.stringifyActivity = () => JSON.stringify(vm.model.activity, null, 2);
     vm.stringify = (data) => JSON.stringify(data, null, 2);
 
     vm.invokeEffector = (effectorName, effectorParams) => {
@@ -206,6 +236,12 @@ function DetailController($scope, $state, $stateParams, $log, $uibModal, $timeou
         // so transient tasks etc less relevant
     }
 
+    vm.showReplayHelp = () => {
+        $scope.showReplayHelp = !$scope.showReplayHelp;
+    }
+
+    vm.isNullish = _.isNil;
+
 }
 
 function findWorkflowTag(task) {
diff --git a/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.less b/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.less
index b6eb05e5..2dc74ee4 100644
--- a/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.less
+++ b/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.less
@@ -106,10 +106,6 @@
             .monospace();
         }
 
-        .monospace {
-            .monospace();
-        }
-        
         .table-responsive,
         .table {
             margin-bottom: 0;
@@ -161,7 +157,7 @@
             }
         }
     }
-    .result-parent {
+    .monospace, .result-parent {
         .monospace();
     }
     .result-parent.big-result {
@@ -190,4 +186,29 @@
         margin-top: -12px;
     }
 
+    .workflow-body {
+        .btn-group {
+            > .dropdown-menu {
+                li a {
+                    padding-left: 2em;
+                }
+            }
+
+            .selected {
+                .check {
+                    margin-left: -1.5em;
+                    display: block;
+                    width: 0;
+                    height: 0;
+                    overflow: visible;
+                    margin-top: 3px;
+                    margin-bottom: -3px;
+                }
+            }
+            .check {
+                display: none;
+            }
+        }
+    }
+
 }
diff --git a/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.template.html b/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.template.html
index 25eada16..09e45831 100644
--- a/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.template.html
+++ b/ui-modules/app-inspector/app/views/main/inspect/activities/detail/detail.template.html
@@ -18,9 +18,9 @@
 -->
 <ui-view class="activity-any">
     <div>
-        <loading-state error="vm.error" trust-error="true" ng-if="!vm.model.activity || !vm.model.activityChildren"></loading-state>
+        <loading-state error="vm.error" trust-error="true" ng-if="!vm.model.activity.id || !vm.model.activityChildren"></loading-state>
 
-        <div ng-if="vm.model.activity && vm.model.activityChildren">
+        <div ng-if="vm.model.activity.id && vm.model.activityChildren">
             <ol class="breadcrumb" ng-show="showParents">
                 <li breadcrumb-navigation parent-id="{{vm.model.activity.submittedByTask.metadata.id}}"
                     entity-id="{{vm.model.entityId}}"></li>
@@ -34,22 +34,24 @@
                 </li>
                 <li class="breadcrumb-item active">{{vm.model.activity.displayName}}</li>
             </ol>
+        </div>
 
-            <div ng-if="vm.model.activity" class="activity-detail">
+        <div>
+            <div class="activity-detail">
                 <div class="alert alert-info" ng-if="vm.model.activity.blockingTask">
                     <strong>Blocked on:</strong>
                     <span ng-if="vm.model.activity.blockingDetails">{{vm.model.activity.blockingDetails}}:</span>
                     <code><a ui-sref="main.inspect.activities.detail({entityId: vm.model.activity.blockingTask.metadata.entityId, activityId: vm.model.activity.blockingTask.metadata.id})">{{vm.model.activity.blockingTask.metadata.taskName}}</a></code> for <strong><a ui-sref="main.inspect.summary({entityId: vm.model.activity.blockingTask.metadata.entityId})">{{vm.model.activity.blockingTask.metadata.entityDisplayName}} entity</a></strong>
                 </div>
 
-                <div class="activity-header">
+                <div class="activity-header" ng-if="vm.model.activity.id">
                     <div class="activity-title">{{vm.model.activity.displayName}}</div>
                     <div class="activity-entity">{{vm.model.activity.entityDisplayName}}</div>
                     <div class="activity-description" ng-if="vm.model.activity.description">{{vm.model.activity.description}}</div>
                 </div>
 
                 <div class="activity-body">
-                    <div class="summary-body">
+                    <div class="summary-body" ng-if="vm.model.activity.id">
                         <div class="summary-block">
                             <div class="row">
                                 <div class="col-md-3 summary-item">
@@ -158,21 +160,56 @@
                     </br-collapsible>
 
                     <br-collapsible state="vm.model.accordion.workflowOpen"
-                                    ng-if="vm.model.workflow">
+                                    ng-if="vm.model.workflow.data">
                         <heading> Workflow</heading>
 
                         <div class="workflow-body">
                             <div ng-if="vm.model.workflow.loading == 'loaded'">
-                                <p style="margin-top: 12px; margin-bottom: 24px;">
+                                <div ng-if="vm.model.workflow.data.taskIds.length > 1">
+                                    <div style="float: right; margin-top: -9px;" class="btn-group" uib-dropdown>
+                                        <button id="replay-button" type="button" class="btn btn-select-dropdown" uib-dropdown-toggle>
+                                            Select replay <span class="caret"></span>
+                                        </button>
+                                        <ul class="dropdown-menu" uib-dropdown-menu role="menu" aria-labelledby="replay-button">
+                                            <li role="menuitem" ng-repeat="id in vm.model.workflow.data.taskIds" id="workflow-replay-{{ id }}">
+                                                <a href="" ui-sref="main.inspect.activities.detail({activityId: id})" ng-class="{'selected' : vm.model.activityId === id}">
+                                                    <i class="fa fa-check check"></i>
+                                                    <span class="monospace">{{ id }}</span></a> </li>
+                                            <li role="menuitem">
+                                                <a href="" ng-click="vm.showReplayHelp()" ng-class="{'selected' : showReplayHelp}"><i>More information</i></a>
+                                            </li>
+                                        </ul>
+                                    </div>
+                                </div>
+                                <div style="margin-top: 12px; margin-bottom: 24px;">
                                     This task is for
-                                    <span ng-if="vm.model.workflow.tag.stepIndex">step <b>{{ vm.model.workflow.tag.stepIndex+1 }}</b>
-                                        in workflow
+                                    <span ng-if="!vm.isNullish(vm.model.workflow.tag.stepIndex)">step <b>{{ vm.model.workflow.tag.stepIndex+1 }}</b>
+                                        in
                                         <a ui-sref="main.inspect.activities.detail({entityId: vm.model.entityId, activityId: vm.model.workflow.data.taskId})">
-                                            <b>{{vm.model.workflow.data.name}}</b>.
-                                        </a>
+                                            workflow <span class="monospace">{{vm.model.workflow.data.workflowId}}</span>:
+                                            <b>{{vm.model.workflow.data.name}}</b></a>.
+                                    </span>
+                                    <span ng-if="vm.isNullish(vm.model.workflow.tag.stepIndex)">
+                                        <span ng-if="vm.model.workflow.data.taskIds.length>1">
+                                            <span ng-if="vm.model.workflow.data.taskIds[vm.model.workflow.data.taskIds.length-1] === vm.model.activityId">
+                                                the most recent </span>
+                                            <span ng-if="vm.model.workflow.data.taskIds[vm.model.workflow.data.taskIds.length-1] !== vm.model.activityId">
+                                                run {{vm.model.workflow.data.taskIds.indexOf(vm.model.activityId)+1}} </span>
+                                            of {{ vm.model.workflow.data.taskIds.length }} of
+                                        </span>
+                                        workflow <span class="monospace">{{vm.model.workflow.data.workflowId}}</span>:
+                                        <b>{{vm.model.workflow.data.name}}</b>.
                                     </span>
-                                    <span ng-if="!vm.model.workflow.tag.stepIndex"> workflow <b>{{vm.model.workflow.data.name}}</b>.</span>
-                                </p>
+                                </div>
+                                <div ng-if="showReplayHelp" style="margin-top: 12px; margin-bottom: 24px;">
+                                    Workflows can be replayed in certain situations, such as if they fail or the server is restarted.
+                                    This workflow invocation instance has been replayed, with a total of {{ vm.model.workflow.data.taskIds.length }} runs.
+                                    Individual replays can be viewed by selecting a task ID from the dropdown.
+                                    The workflow step data below shows the most recent run of each step in any replay.
+                                    The arrows between steps show all step transitions in any replay of this workflow instance.
+                                    Sub-task and log views further below can be useful to disambiguate multiple replays if required.
+                                </div>
+
                                 <workflow-steps workflow="vm.model.workflow" task="vm.model.activity"></workflow-steps>
                             </div>
                             <div ng-if="vm.model.workflow.loading != 'loaded'">
@@ -211,19 +248,23 @@
 
                     <br-collapsible ng-if="vm.model.activity.detailedStatus" state="vm.model.accordion.jsonOpen">
                         <heading> JSON</heading>
-                        <pre>{{vm.stringifyActivity()}}</pre>
+                        <b>Activity</b>
+                        <pre>{{vm.stringify(vm.model.activity)}}</pre>
+                        <b>Workflow</b>
+                        <pre>{{vm.stringify(vm.model.workflow)}}</pre>
                     </br-collapsible>
 
+                    <div>
+                        <br-collapsible state="vm.model.accordion.logbookOpen">
+                            <heading> Logbook (activity)</heading>
+                            <br-logbook task-id="{{vm.model.activityId}}"></br-logbook>
+                        </br-collapsible>
+                    </div>
+
                 </div>
             </div>
         </div>
 
-        <div>
-            <br-collapsible state="vm.model.accordion.logbookOpen">
-                <heading> Logbook (activity)</heading>
-                <br-logbook task-id="{{vm.model.activityId}}"></br-logbook>
-            </br-collapsible>
-        </div>
 
     </div>
 </ui-view>