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/11/04 17:14:05 UTC

[brooklyn-ui] branch master updated (c230bc36 -> ea0d991f)

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

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


    from c230bc36 fix display of output for current step (if error handler running)
     new b8077034 fix line-up of blurred secrets
     new 03c9fa3c fix replay api call for recent server contract change, and tidy-up
     new e898e660 use suppressSecret for tasks and workflow output api; add workflow yaml with re-run ability
     new ea0d991f show workflow for ui-based scripts, to be able to re-run it

The 4 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 .../config-sensor-table.style.less                 |  3 +-
 .../components/providers/activity-api.provider.js  |  8 +--
 .../components/providers/entity-api.provider.js    | 28 +++++------
 .../workflow/workflow-steps.directive.js           |  2 +-
 ui-modules/app-inspector/app/index.js              |  3 +-
 .../inspect/activities/activities.controller.js    |  2 +-
 .../inspect/activities/detail/detail.controller.js | 57 ++++++++++++++++++++--
 .../main/inspect/activities/detail/detail.less     |  1 +
 .../inspect/activities/detail/detail.template.html | 17 ++++++-
 .../app/views/main/inspect/inspect.controller.js   | 21 ++++++--
 .../main/inspect/run-workflow-modal.template.html  |  2 +-
 .../utils/user-management/user-management.js       |  1 -
 ui-modules/utils/yaml-editor/yaml-editor.js        |  6 ++-
 13 files changed, 118 insertions(+), 33 deletions(-)


[brooklyn-ui] 04/04: show workflow for ui-based scripts, to be able to re-run it

Posted by he...@apache.org.
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 ea0d991f0d903fd0f6ad0a02b29c95e6ed33e400
Author: Alex Heneveld <al...@cloudsoft.io>
AuthorDate: Wed Nov 2 21:06:43 2022 +0000

    show workflow for ui-based scripts, to be able to re-run it
---
 .../workflow/workflow-steps.directive.js           |  2 +-
 ui-modules/app-inspector/app/index.js              |  3 ++-
 .../inspect/activities/activities.controller.js    |  2 +-
 .../inspect/activities/detail/detail.controller.js | 26 ++++++++++++++++++----
 .../inspect/activities/detail/detail.template.html |  4 ++++
 .../app/views/main/inspect/inspect.controller.js   | 21 ++++++++++++++---
 .../main/inspect/run-workflow-modal.template.html  |  2 +-
 .../utils/user-management/user-management.js       |  1 -
 ui-modules/utils/yaml-editor/yaml-editor.js        |  6 ++++-
 9 files changed, 54 insertions(+), 13 deletions(-)

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 ab49d345..35021841 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
@@ -163,7 +163,7 @@ function makeArrows(workflow, steps) {
 
         function stepY(n) {
             if (n==-1) return 'start/end';
-            if (!steps || n<0 || n>=steps.length) {
+            if (!steps || n<0 || n>=steps.length || _.isNil(n)) {
                 console.log("workflow arrow bounds error", steps, n);
                 return null;
             }
diff --git a/ui-modules/app-inspector/app/index.js b/ui-modules/app-inspector/app/index.js
index d8c00ebf..9dbfd95f 100755
--- a/ui-modules/app-inspector/app/index.js
+++ b/ui-modules/app-inspector/app/index.js
@@ -36,6 +36,7 @@ import brYamlEditor from "brooklyn-ui-utils/yaml-editor/yaml-editor";
 import brWebNotifications from 'brooklyn-ui-utils/web-notifications/web-notifications';
 import brExpandablePanel from 'brooklyn-ui-utils/expandable-panel/expandable-panel';
 import brLogbook from 'brooklyn-ui-utils/logbook/logbook';
+import serverApi from 'brooklyn-ui-utils/api/brooklyn/server';
 
 import "angular-xeditable";
 import apiProvider from "components/providers/api.provider";
@@ -71,7 +72,7 @@ const IS_PRODUCTION = process.env.NODE_ENV === 'production' || false;
 angular.module('brooklynAppInspector', [ngResource, ngCookies, ngSanitize, uiRouter, brCore, brUtilsGeneral,
     dropdownNested,
     brServerStatus, brIconGenerator, brInterstitialSpinner, brooklynModuleLinks, brSensitiveField, brooklynUserManagement,
-    brYamlEditor, brWebNotifications, brExpandablePanel, 'xeditable', brLogbook, apiProvider, entityTree, loadingState,
+    brYamlEditor, brWebNotifications, brExpandablePanel, 'xeditable', brLogbook, apiProvider, entityTree, loadingState, serverApi,
     configSensorTable, entityEffector, entityPolicy, breadcrumbNavigation, taskList, taskSunburst, stream, adjunctsList,
     workflowSteps, workflowStep,
     managementDetail, brandAngularJs])
diff --git a/ui-modules/app-inspector/app/views/main/inspect/activities/activities.controller.js b/ui-modules/app-inspector/app/views/main/inspect/activities/activities.controller.js
index 449504e6..eb00c68b 100644
--- a/ui-modules/app-inspector/app/views/main/inspect/activities/activities.controller.js
+++ b/ui-modules/app-inspector/app/views/main/inspect/activities/activities.controller.js
@@ -195,7 +195,7 @@ function ActivitiesController($scope, $state, $stateParams, $log, $timeout, enti
 export function makeTaskStubFromWorkflowRecord(wf, wft) {
     const result = {
         id: wft.taskId,
-        displayName: wf.name + (wft.reasonForReplay && wft.reasonForReplay!="initial run" ? " ("+wft.reasonForReplay+")" : ""),
+        displayName: wf.name + (wft.reasonForReplay && wft.reasonForReplay!="Initial run" ? " ("+wft.reasonForReplay+")" : ""),
         entityId: (wf.entity || {}).id,
         isError: wft.isError===false ? false : true,
         currentStatus: _.isNil(wft.isError) ? "Unavailable" : wft.status,
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 6589760f..86fa0e6f 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
@@ -142,7 +142,10 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod
                         });
                     }
 
-                    $scope.actions.workflowReplays = [];
+                    let osi = vm.model.workflow.data.oldStepInfo;
+                    vm.model.workflow.finishedWithNoSteps = ((osi["-2"] || {}).previous || [])[0] == -1;
+
+                        $scope.actions.workflowReplays = [];
                     if (vm.model.workflow.data.status !== 'RUNNING') {
 
                         $scope.actions.workflowReplays = [];
@@ -170,8 +173,8 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod
                         if (replayableFromStart) {
                             let w1 = 'Restart', w2 = '(not resumable)';
                             if (stepIndex<0 || (_.isNil(stepIndex) && vm.model.workflow.data.replayableLastStep==-2)) { w1 = 'Run'; w2 = 'again'; }
-                            else if (_.isNil(stepIndex)) { w2 = '(did not start)'; }
                             else if (replayableContinuing) w2 = '';
+                            else if (_.isNil(stepIndex)) { w2 = '(did not start)'; }
 
                             $scope.actions.workflowReplays.push({targetId: 'start', reason: 'Restart workflow from UI',
                                 label: w1+' '+(stepIndex>=0 ? 'workflow ' : '')+w2});
@@ -212,6 +215,21 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod
                 if (vm.model.workflow.data.status === 'RUNNING') wResponse.interval(1000);
                 observers.push(wResponse.subscribe(processWorkflowData));
 
+                function initFromWorkflowFirstReplayTask(task) {
+                    if (task) {
+                        const workflowYaml = (task.tags || []).find(t => t.workflow_yaml);
+                        if (workflowYaml) {
+                            $scope.workflow_yaml = workflowYaml.workflow_yaml;
+                        }
+                    }
+                }
+
+                if ($scope.workflowId === activityId) initFromWorkflowFirstReplayTask(vm.model.activity);
+                else activityApi.activity($scope.workflowId).then((response)=> {
+                    initFromWorkflowFirstReplayTask(response.data);
+                });
+
+
             }).catch(error => {
                 if (optimistic) {
                     vm.model.workflow.loading = null;
@@ -318,13 +336,13 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod
     }
 
     vm.isNonEmpty = Utils.isNonEmpty;
-    vm.yaml = jsyaml.dump;
+    vm.yaml = (o) => typeof o === 'string' ? o : jsyaml.dump(o);
 
     vm.openInRunModel = function (workflowYaml) {
         $uibModal.open({
             animation: true,
             template: runWorkflowModalTemplate,
-            controller: ['$scope', '$http', '$uibModalInstance', 'applicationId', 'entityId', 'workflowYaml', runWorkflowController],
+            controller: ['$scope', '$http', '$uibModalInstance', 'serverApi', 'applicationId', 'entityId', 'workflowYaml', runWorkflowController],
             size: 'lg',
             resolve: {
                 applicationId: ()=>(applicationId),
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 04a68636..1fe8b110 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
@@ -255,6 +255,10 @@
                                     ></a></b>.
                                 </div>
 
+                                <div ng-if="vm.model.workflow.finishedWithNoSteps" class="workflow-preface-para">
+                                    The workflow did not run any steps; if this is unexpected, check the conditions on the steps.
+                                </div>
+
                                 <div ng-if="vm.model.workflow.data.errorHandlerTaskId" class="workflow-preface-para">
                                     <span ng-if="vm.model.activityId==vm.model.workflow.data.errorHandlerTaskId">
                                         This is the page for the error handler for this workflow.
diff --git a/ui-modules/app-inspector/app/views/main/inspect/inspect.controller.js b/ui-modules/app-inspector/app/views/main/inspect/inspect.controller.js
index 61dd014f..896374e3 100644
--- a/ui-modules/app-inspector/app/views/main/inspect/inspect.controller.js
+++ b/ui-modules/app-inspector/app/views/main/inspect/inspect.controller.js
@@ -80,7 +80,7 @@ export function inspectController($scope, $state, $stateParams, $uibModal, brSna
         $uibModal.open({
             animation: true,
             template: runWorkflowModalTemplate,
-            controller: ['$scope', '$http', '$uibModalInstance', 'applicationId', 'entityId', runWorkflowController],
+            controller: ['$scope', '$http', '$uibModalInstance', 'serverApi', 'applicationId', 'entityId', runWorkflowController],
             size: 'lg',
             resolve: {
                 applicationId: ()=>(applicationId),
@@ -144,12 +144,27 @@ export function addChildController($scope, $http, $uibModalInstance, application
     }
 }
 
-export function runWorkflowController($scope, $http, $uibModalInstance, applicationId, entityId, workflowYaml) {
-    $scope.workflowYaml = workflowYaml || 'steps:\n  - ';
+export function runWorkflowController($scope, $http, $uibModalInstance, serverApi, applicationId, entityId, workflowYaml) {
+    $scope.workflowYaml = workflowYaml;
     $scope.errorMessage = null;
     $scope.running = false;
     $scope.runWorkflow = runWorkflow;
 
+    if (!$scope.workflowYaml) {
+        function initWorkflowYaml() {
+            if (!$scope.workflowYaml) {
+                $scope.workflowYaml = 'name: Workflow via UI' + ($scope.user ? ' ' + $scope.user : '') + '\n' + 'steps:\n  - ';
+            }
+        }
+        serverApi.getUser().then((response) => {
+            $scope.user = response.data;
+            initWorkflowYaml();
+        }).catch((response) => {
+            $scope.user = null;
+            initWorkflowYaml();
+        });
+    }
+
     function runWorkflow() {
         $scope.running = true;
         $scope.errorMessage = null;
diff --git a/ui-modules/app-inspector/app/views/main/inspect/run-workflow-modal.template.html b/ui-modules/app-inspector/app/views/main/inspect/run-workflow-modal.template.html
index 9bb3e654..83860e0a 100644
--- a/ui-modules/app-inspector/app/views/main/inspect/run-workflow-modal.template.html
+++ b/ui-modules/app-inspector/app/views/main/inspect/run-workflow-modal.template.html
@@ -25,7 +25,7 @@
     <div ng-if="errorMessage" class="alert alert-danger" role="alert">
         <strong>Error</strong> {{errorMessage}}
     </div>
-    <br-yaml-editor value="workflowYaml" enable-auto-complete></br-yaml-editor>
+    <br-yaml-editor value="workflowYaml" enable-auto-complete reset-to-end-on-external-value-set="true"></br-yaml-editor>
 </div>
 
 <div class="modal-footer">
diff --git a/ui-modules/utils/user-management/user-management.js b/ui-modules/utils/user-management/user-management.js
index 5383461b..54fd2bd6 100644
--- a/ui-modules/utils/user-management/user-management.js
+++ b/ui-modules/utils/user-management/user-management.js
@@ -42,7 +42,6 @@ export function userMenuDirective($compile, serverApi) {
             .addClass('dropdown')
             .removeAttr('br-user-menu') //remove the attribute to avoid indefinite loop
             .removeAttr('data-br-user-menu'); //also remove the same attribute with data- prefix in case users specify data-common-things in the html
-
         serverApi.getUser().then((response) => {
             scope.user = response.data;
         }).catch((response) => {
diff --git a/ui-modules/utils/yaml-editor/yaml-editor.js b/ui-modules/utils/yaml-editor/yaml-editor.js
index 4cfa160b..38952be2 100644
--- a/ui-modules/utils/yaml-editor/yaml-editor.js
+++ b/ui-modules/utils/yaml-editor/yaml-editor.js
@@ -45,7 +45,8 @@ export function yamlEditorDirective($rootScope, brSnackbar) {
         scope: {
             type: '@',
             value: '=',
-            onChange: '&'
+            onChange: '&',
+            resetToEndOnExternalValueSet: '=?',
         },
         link: link
     };
@@ -180,6 +181,9 @@ export function yamlEditorDirective($rootScope, brSnackbar) {
             $scope.cm.focus();
             if ($scope.cm.getValue() !== newVal && angular.isDefined(newVal)) {
                 $scope.cm.setValue(newVal);
+                if ($scope.resetToEndOnExternalValueSet) {
+                    $scope.cm.setCursor($scope.cm.lineCount(), 0);
+                }
             }
             setTimeout(()=> {
                 $scope.cm.focus();


[brooklyn-ui] 02/04: fix replay api call for recent server contract change, and tidy-up

Posted by he...@apache.org.
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 03c9fa3cf6a895445c1a0e5dedc9694522ff8331
Author: Alex Heneveld <al...@cloudsoft.io>
AuthorDate: Wed Nov 2 00:19:09 2022 +0000

    fix replay api call for recent server contract change, and tidy-up
---
 .../components/providers/entity-api.provider.js    | 22 +++++++++++-----------
 .../inspect/activities/detail/detail.controller.js |  7 +++++--
 2 files changed, 16 insertions(+), 13 deletions(-)

diff --git a/ui-modules/app-inspector/app/components/providers/entity-api.provider.js b/ui-modules/app-inspector/app/components/providers/entity-api.provider.js
index 39c28fe0..6c0f1613 100644
--- a/ui-modules/app-inspector/app/components/providers/entity-api.provider.js
+++ b/ui-modules/app-inspector/app/components/providers/entity-api.provider.js
@@ -141,7 +141,7 @@ function EntityApi($http, $q) {
         return $http.get('/v1/applications/' + applicationId + '/entities/' + entityId + '/activities', {observable: true, ignoreLoadingBar: true});
     }
     function getEntityActivitiesDeep(applicationId, entityId) {
-        return $http.get('/v1/applications/' + applicationId + '/entities/' + entityId + '/activities?recurse=true', {observable: true, ignoreLoadingBar: true});
+        return $http.get('/v1/applications/' + applicationId + '/entities/' + entityId + '/activities', {observable: true, ignoreLoadingBar: true, params: { recurse: true }});
     }
 
     function getEntityLocations(applicationId, entityId) {
@@ -166,18 +166,18 @@ function EntityApi($http, $q) {
         ]);
     }
     function expungeEntity(applicationId, entityId, release) {
-        return $http.post('/v1/applications/' + applicationId + '/entities/' + entityId + '/expunge?release=' + release + '&timeout=0');
+        return $http.post('/v1/applications/' + applicationId + '/entities/' + entityId + '/expunge', null, { params: { release, timeout: 0 } });
     }
-    function invokeEntityEffector(applicationId, entityId, effectorId, params) {
-        return $http.post('/v1/applications/' + applicationId + '/entities/' + entityId + '/effectors/' + effectorId + '?timeout=0', params);
+    function invokeEntityEffector(applicationId, entityId, effectorId, body) {
+        return $http.post('/v1/applications/' + applicationId + '/entities/' + entityId + '/effectors/' + effectorId, body, { params: { timeout: 0 } });
     }
     
-    function addEntityPolicy(applicationId, entityId, policyType, params) {
-        return $http.post('/v1/applications/'+ applicationId +'/entities/' + entityId + '/policies/?type=' + policyType, params);
+    function addEntityPolicy(applicationId, entityId, policyType, body) {
+        return $http.post('/v1/applications/'+ applicationId +'/entities/' + entityId + '/policies', body, { params: { type: policyType } });
     }
 
-    function addEntityAdjunct(applicationId, entityId, adjunctType, params) {
-        return $http.post('/v1/applications/'+ applicationId +'/entities/' + entityId + '/adjuncts/?type=' + adjunctType, params);
+    function addEntityAdjunct(applicationId, entityId, adjunctType, body) {
+        return $http.post('/v1/applications/'+ applicationId +'/entities/' + entityId + '/adjuncts', body, { params: { type: adjunctType } });
     }
     function startEntityAdjunct(applicationId, entityId, adjunctId) {
         return $http.post('/v1/applications/'+ applicationId +'/entities/' + entityId + '/adjuncts/' + adjunctId + '/start');
@@ -188,8 +188,8 @@ function EntityApi($http, $q) {
     function destroyEntityAdjunct(applicationId, entityId, adjunctId) {
         return $http.delete('/v1/applications/'+ applicationId +'/entities/' + entityId + '/adjuncts/' + adjunctId);
     }
-    function updateEntityAdjunctConfig(applicationId, entityId, adjunctId, configId, data) {
-        return $http.post('/v1/applications/'+ applicationId +'/entities/' + entityId + '/adjuncts/' + adjunctId + '/config/' + configId, data);
+    function updateEntityAdjunctConfig(applicationId, entityId, adjunctId, configId, body) {
+        return $http.post('/v1/applications/'+ applicationId +'/entities/' + entityId + '/adjuncts/' + adjunctId + '/config/' + configId, body);
     }
     function getWorkflows(applicationId, entityId) {
         return $http.get('/v1/applications/'+ applicationId +'/entities/' + entityId + '/workflows/', {observable: true, ignoreLoadingBar: true});
@@ -199,6 +199,6 @@ function EntityApi($http, $q) {
     }
     function replayWorkflow(applicationId, entityId, workflowId, step, options) {
         return $http.post('/v1/applications/'+ applicationId +'/entities/' + entityId + '/workflows/' + workflowId
-            + '/replay/from/' + step, {params: options});
+            + '/replay/from/' + step, null, {params: options});
     }
 }
\ No newline at end of file
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 7475be5a..f09de2bf 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
@@ -166,7 +166,7 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod
 
                         if (replayableFromStart) {
                             let w1 = 'Restart', w2 = '(not resumable)';
-                            if (stepIndex<0) { w1 = 'Run'; w2 = 'again'; }
+                            if (stepIndex<0 || (_.isNil(stepIndex) && vm.model.workflow.data.replayableLastStep==-2)) { w1 = 'Run'; w2 = 'again'; }
                             else if (_.isNil(stepIndex)) { w2 = '(did not start)'; }
                             else if (replayableContinuing) w2 = '';
 
@@ -187,11 +187,14 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod
                                 if (r.force) opts.force = true;
                                 entityApi.replayWorkflow(applicationId, entityId, $scope.workflowId, r.targetId, opts)
                                     .then(response => {
+                                        console.log("Replay requested", response);
                                         $state.go('main.inspect.activities.detail', {
                                             applicationId: applicationId,
                                             entityId: entityId,
-                                            activityId: response.data,
+                                            activityId: response.data.id,
                                         });
+                                    }).catch(error => {
+                                        console.log("Replay failed", error);
                                     });
                             };
                         });


[brooklyn-ui] 01/04: fix line-up of blurred secrets

Posted by he...@apache.org.
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 b807703465563959c5f353feac3dbcdd67a9ab4f
Author: Alex Heneveld <al...@cloudsoft.io>
AuthorDate: Wed Nov 2 00:18:40 2022 +0000

    fix line-up of blurred secrets
---
 .../app/components/config-sensor-table/config-sensor-table.style.less  | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/ui-modules/app-inspector/app/components/config-sensor-table/config-sensor-table.style.less b/ui-modules/app-inspector/app/components/config-sensor-table/config-sensor-table.style.less
index 78d5ba26..be66ebb5 100644
--- a/ui-modules/app-inspector/app/components/config-sensor-table/config-sensor-table.style.less
+++ b/ui-modules/app-inspector/app/components/config-sensor-table/config-sensor-table.style.less
@@ -145,7 +145,8 @@
   > .content {
     transition: none;
     text-shadow: rgba(0, 0, 0, 0.95) 10px 0px 10px;
-
+    position: relative;
+    left: -10px;
   }
   &.sensitive-field-show {
     > .content {


[brooklyn-ui] 03/04: use suppressSecret for tasks and workflow output api; add workflow yaml with re-run ability

Posted by he...@apache.org.
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 e898e660599f9e105d6a3a3016ef2d37d3732f10
Author: Alex Heneveld <al...@cloudsoft.io>
AuthorDate: Wed Nov 2 09:08:52 2022 +0000

    use suppressSecret for tasks and workflow output api; add workflow yaml with re-run ability
---
 .../components/providers/activity-api.provider.js  |  8 +++----
 .../components/providers/entity-api.provider.js    |  8 +++----
 .../inspect/activities/detail/detail.controller.js | 28 ++++++++++++++++++++++
 .../main/inspect/activities/detail/detail.less     |  1 +
 .../inspect/activities/detail/detail.template.html | 13 +++++++++-
 .../app/views/main/inspect/inspect.controller.js   |  4 ++--
 6 files changed, 51 insertions(+), 11 deletions(-)

diff --git a/ui-modules/app-inspector/app/components/providers/activity-api.provider.js b/ui-modules/app-inspector/app/components/providers/activity-api.provider.js
index 27deb5cc..4c6169ee 100644
--- a/ui-modules/app-inspector/app/components/providers/activity-api.provider.js
+++ b/ui-modules/app-inspector/app/components/providers/activity-api.provider.js
@@ -44,17 +44,17 @@ function ActivityApi($http) {
     };
 
     function getActivities() {
-        return $http.get('/v1/activities', {observable: true, ignoreLoadingBar: true});
+        return $http.get('/v1/activities', {observable: true, ignoreLoadingBar: true, params: { suppressSecrets: true }});
     }
     function getActivity(activityId) {
-        return $http.get('/v1/activities/' + activityId, {observable: true, ignoreLoadingBar: true});
+        return $http.get('/v1/activities/' + activityId, {observable: true, ignoreLoadingBar: true, params: { suppressSecrets: true }});
     }
     function getActivityChildren(activityId) {
-        return $http.get('/v1/activities/' + activityId + '/children?includeBackground=true', {observable: true, ignoreLoadingBar: true});
+        return $http.get('/v1/activities/' + activityId + '/children', {observable: true, ignoreLoadingBar: true, params: { suppressSecrets: true, includeBackground: true }});
     }
     function getActivityDescendants(activityId, maxDepth) {
         return $http.get('/v1/activities/' + activityId + '/children/recurse'+
-            (maxDepth ? '?maxDepth='+maxDepth : ''), {observable: true, ignoreLoadingBar: true});
+            (maxDepth ? '?maxDepth='+maxDepth : ''), {observable: true, ignoreLoadingBar: true, params: { suppressSecrets: true }});
     }
     function getActivityStream(activityId, streamType) {
         return $http.get('/v1/activities/' + activityId + '/stream/' + encodeURIComponent(streamType), {observable: true, ignoreLoadingBar: true, transformResponse: (data)=> {
diff --git a/ui-modules/app-inspector/app/components/providers/entity-api.provider.js b/ui-modules/app-inspector/app/components/providers/entity-api.provider.js
index 6c0f1613..fea4517b 100644
--- a/ui-modules/app-inspector/app/components/providers/entity-api.provider.js
+++ b/ui-modules/app-inspector/app/components/providers/entity-api.provider.js
@@ -138,10 +138,10 @@ function EntityApi($http, $q) {
     }
     
     function getEntityActivities(applicationId, entityId) {
-        return $http.get('/v1/applications/' + applicationId + '/entities/' + entityId + '/activities', {observable: true, ignoreLoadingBar: true});
+        return $http.get('/v1/applications/' + applicationId + '/entities/' + entityId + '/activities', {observable: true, ignoreLoadingBar: true, params: { suppressSecrets: true }});
     }
     function getEntityActivitiesDeep(applicationId, entityId) {
-        return $http.get('/v1/applications/' + applicationId + '/entities/' + entityId + '/activities', {observable: true, ignoreLoadingBar: true, params: { recurse: true }});
+        return $http.get('/v1/applications/' + applicationId + '/entities/' + entityId + '/activities', {observable: true, ignoreLoadingBar: true, params: { recurse: true, suppressSecrets: true }});
     }
 
     function getEntityLocations(applicationId, entityId) {
@@ -192,10 +192,10 @@ function EntityApi($http, $q) {
         return $http.post('/v1/applications/'+ applicationId +'/entities/' + entityId + '/adjuncts/' + adjunctId + '/config/' + configId, body);
     }
     function getWorkflows(applicationId, entityId) {
-        return $http.get('/v1/applications/'+ applicationId +'/entities/' + entityId + '/workflows/', {observable: true, ignoreLoadingBar: true});
+        return $http.get('/v1/applications/'+ applicationId +'/entities/' + entityId + '/workflows/', {observable: true, ignoreLoadingBar: true, params: { suppressSecrets: true }});
     }
     function getWorkflow(applicationId, entityId, workflowId) {
-        return $http.get('/v1/applications/'+ applicationId +'/entities/' + entityId + '/workflows/' + workflowId, {observable: true, ignoreLoadingBar: true});
+        return $http.get('/v1/applications/'+ applicationId +'/entities/' + entityId + '/workflows/' + workflowId, {observable: true, ignoreLoadingBar: true, params: { suppressSecrets: true }});
     }
     function replayWorkflow(applicationId, entityId, workflowId, step, options) {
         return $http.post('/v1/applications/'+ applicationId +'/entities/' + entityId + '/workflows/' + workflowId
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 f09de2bf..6589760f 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
@@ -20,6 +20,9 @@ import {HIDE_INTERSTITIAL_SPINNER_EVENT} from 'brooklyn-ui-utils/interstitial-sp
 import template from "./detail.template.html";
 import modalTemplate from './kilt.modal.template.html';
 import {makeTaskStubFromWorkflowRecord} from "../activities.controller";
+import jsyaml from 'js-yaml';
+import runWorkflowModalTemplate from "../../run-workflow-modal.template.html";
+import {runWorkflowController} from "../../inspect.controller";
 
 export const detailState = {
     name: 'main.inspect.activities.detail',
@@ -243,6 +246,10 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod
                     vm.model.workflow.tag = workflowTag;
                     loadWorkflow(workflowTag);
                 }
+                const workflowYaml = vm.model.activity.tags.find(t => t.workflow_yaml);
+                if (workflowYaml) {
+                    $scope.workflow_yaml = workflowYaml.workflow_yaml;
+                }
             }
 
             function saveActivity(response) {
@@ -311,6 +318,27 @@ function DetailController($scope, $state, $stateParams, $location, $log, $uibMod
     }
 
     vm.isNonEmpty = Utils.isNonEmpty;
+    vm.yaml = jsyaml.dump;
+
+    vm.openInRunModel = function (workflowYaml) {
+        $uibModal.open({
+            animation: true,
+            template: runWorkflowModalTemplate,
+            controller: ['$scope', '$http', '$uibModalInstance', 'applicationId', 'entityId', 'workflowYaml', runWorkflowController],
+            size: 'lg',
+            resolve: {
+                applicationId: ()=>(applicationId),
+                entityId: ()=>(entityId),
+                workflowYaml: ()=>(workflowYaml),
+            }
+        }).result.then((closeData)=> {
+            $state.go('main.inspect.activities.detail', {
+                applicationId: applicationId,
+                entityId: closeData.entityId,
+                activityId: closeData.id
+            });
+        });
+    }
 
     vm.getStreamIdsInOrder = function () {
         // sort with known streams first, in preferred order
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 2011eda9..9ad5dd5b 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
@@ -171,6 +171,7 @@
     .result-parent.big-result {
         border: 1px solid @gray-lighter;
         .result-body {
+            white-space: pre;
             padding: 4px;
         }
     }
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 b8c245c6..04a68636 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
@@ -95,7 +95,7 @@
                                 </div>
                                 <div class="col-md-6 summary-item" ng-if="vm.model.activity.result!=undefined">
                                     <div class="summary-item-label">Result</div>
-                                    <div class="summary-item-value result-parent" ng-class="{ 'big-result': (''+vm.model.activity.result).length > 10 }"><div class="result-body">{{::vm.model.activity.result}}</div></div>
+                                    <div class="summary-item-value result-parent" ng-class="{ 'big-result': (''+vm.model.activity.result).length > 10 }"><div class="result-body">{{::vm.yaml(vm.model.activity.result)}}</div></div>
                                 </div>
                             </div>
                         </div>
@@ -338,6 +338,17 @@
                         <pre>{{vm.model.activity.detailedStatus}}</pre>
                     </br-collapsible>
 
+                    <br-collapsible ng-if="workflow_yaml" state="vm.model.accordion.workflowYamlOpen">
+                        <heading> Workflow Definition</heading>
+                        <div class="blueprint-copy-holder">
+                            <a class="text-muted blueprint-button" ng-click="vm.openInRunModel(workflow_yaml)"
+                               title="Open in Run Workflow">
+                                <i class="fa fa-arrow-circle-o-right"></i>
+                            </a>
+                        </div>
+                        <pre>{{workflow_yaml}}</pre>
+                    </br-collapsible>
+
                     <br-collapsible ng-if="vm.model.activity.id || vm.model.workflow.data" state="vm.model.accordion.jsonOpen">
                         <heading> JSON</heading>
                         <b>Activity</b>
diff --git a/ui-modules/app-inspector/app/views/main/inspect/inspect.controller.js b/ui-modules/app-inspector/app/views/main/inspect/inspect.controller.js
index e3ab4fe2..61dd014f 100644
--- a/ui-modules/app-inspector/app/views/main/inspect/inspect.controller.js
+++ b/ui-modules/app-inspector/app/views/main/inspect/inspect.controller.js
@@ -144,8 +144,8 @@ export function addChildController($scope, $http, $uibModalInstance, application
     }
 }
 
-export function runWorkflowController($scope, $http, $uibModalInstance, applicationId, entityId) {
-    $scope.workflowYaml = 'steps:\n  - ';
+export function runWorkflowController($scope, $http, $uibModalInstance, applicationId, entityId, workflowYaml) {
+    $scope.workflowYaml = workflowYaml || 'steps:\n  - ';
     $scope.errorMessage = null;
     $scope.running = false;
     $scope.runWorkflow = runWorkflow;