You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@brooklyn.apache.org by GitBox <gi...@apache.org> on 2021/06/18 21:09:42 UTC

[GitHub] [brooklyn-ui] zan-mateusz opened a new pull request #228: Feature/node management UI

zan-mateusz opened a new pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228


   Front end side of Node Management enhancements
   
   REQUIREMENTS
   * UI to support setting state and priority for management servers (currently exposed via REST API only), eg to trigger a new master to run
   * UI to show date of last seen for terminated servers (thought we had that but I didn't see it in screen shot) [only if this is easy to add!]
   * invocation of code to remove files for terminated servers via explicit REST operation with UI button (TBC)
   
   
   IMPLEMENTATION
   
   1. Extra information (last active, priority) added to the table for each management node, status column renamed to ‘Information’. 
        * ‘Last active’ is based on remoteTimestamp, now passed in HA Summary.
        * Timestamp parsed into a ‘x ago’ with help of a custom filter using moment’s fromNow() function.
   
   2. ‘Remove terminated nodes’ button and ‘remove’ button for a particular management node on row hover.
        * Remove button present for each node whose status is “TERMINATED”, when the row is hovered on with the mouse (can’t see in the screenshot as pointer is hidden).
        * For removing all terminated nodes, API call to “ha/states/clear” is made which clear all nodes apart from master and then repopulates the active nodes (essentially removing just the terminated ones).
        * Because of the above, in the refresh logic I introduced a concept of expectedNodeCounter, which ensures that we repopulate the active nodes before the table is refreshed (otherwise the operation would wipe all nodes apart from master and page would need to be refreshed to refresh the table correctly).
        * For removing a single node, I introduced another API “ha/states/clear/node” which takes a parameter - nodeId, ID of the node to be removed. In such case only 1 node is removed.
   
   
   3. ‘Manage’ button available on hover over for the current management node (node can only manage itself).
        * Button click opens the modal that allows to modify the node (see below)
   4. Modal view for node management once ‘manage’ button is clicked. 
        * List of parameters of class list-group-items and labels of class badge used for the node data (to be uniform with other sections in about page).
        * Edit button that allows to make changes and Cancel button to dismiss the modal and not apply any changes.
        * Clicking edit changes the labels into editable components for Status and Priority. Status is a drop down  select a new status from list ["MASTER", "STANDBY", "HOT_STANDBY", "HOT_BACKUP"], priority is a number-type input
        * Apply button disabled if no changes are made.
        * Once a change to either property gets introduced, the colour of the label changes to indicate that. Also ‘Apply’ button will then be enabled, which sends the API calls to make the changes in persistence.
        * When switching from non-MASTER to MASTER (or vice-versa), appropriate message is displayed with a warning message
        * Changing state to and from MASTER results in change of MASTER in the management context (note: this might take around a minute to load)
        * All changes are automatically reflected in the HA Status table with no need to refresh page.
   5. For operations that take a little bit longer (removal of all nodes, changing status to MASTER), a spinner is introduced under the HA Status part of about page to indicate that data is loading. It is present on all operations.
   6. All operations carried out update the persistence, so removing nodes, changing the properties is correctly saved back to persistence files
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r668929416



##########
File path: ui-modules/home/app/views/about/node-management/node-management.template.html
##########
@@ -0,0 +1,88 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you 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.
+-->
+
+<h3 class="node-management-title">Node Management Panel</h3>
+<div>
+    <div></div>
+    <ul class="list-group">
+        <li class="list-group-item">
+            <span class="badge node-management-badge">{{vm.node.nodeId}}</span>
+            <h4 class="list-group-item-heading">Node ID</h4>
+        </li>
+
+        <li class="list-group-item">
+            <span class="badge node-management-badge">{{vm.node.remoteTimestamp | timeAgoFilter}}</span>
+            <h4 class="list-group-item-heading">Last active</h4>
+        </li>
+
+        <li class="list-group-item">
+            <span class="badge node-management-badge"
+                  ng-style="(vm.newStatus !== vm.node.status) && {'background-color' : '#f0ad4e'} || {'background-color' : 'gray'}">
+                <div ng-if="vm.showEditOptions===false">{{vm.newStatus}}</div>

Review comment:
       Change to `ng-if="!vm.showEditOptions"`




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r655134791



##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -67,4 +72,139 @@ export function aboutStateController($scope, brBrandInfo, version, states) {
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    this.container = $element[0];
+    this.now = Date.now();
+    this.expectedNodeCounter = Object.keys(this.states.nodes).length;
+    this.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    this.openDialog = function (states, nodeId, serverApi, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', 'serverApi', nodeManagementController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[nodeId];
+                    },
+                    serverApi: function () {
+                        return serverApi;
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    this.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    this.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementController($scope, $uibModalInstance, node, serverApi) {
+
+        this.node = node;

Review comment:
       Applies to all functions defined below.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r668936776



##########
File path: ui-modules/utils/api/brooklyn/server.js
##########
@@ -60,4 +65,50 @@ function ServerApi($http, $q, cache) {
     function getUpExtended(config) {
         return $http.get('/v1/server/up/extended', angular.extend({cache: cache}, config));
     }
+
+    function setHaStatus(state, config) {
+        return $http({
+            method: 'POST',
+            url: '/v1/server/ha/state',
+            data: 'mode=' + state,
+            headers: {
+                'Content-Type': 'application/x-www-form-urlencoded',
+                'Accept': 'application/json',
+                'Brooklyn-Allow-Non-Master-Access': 'true',
+            }
+
+        });
+    }
+
+    function setHaPriority(priority, config) {

Review comment:
       `config` is not used




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r668927924



##########
File path: ui-modules/home/app/views/about/node-management/node-management.template.html
##########
@@ -0,0 +1,88 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you 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.
+-->
+
+<h3 class="node-management-title">Node Management Panel</h3>
+<div>
+    <div></div>
+    <ul class="list-group">
+        <li class="list-group-item">
+            <span class="badge node-management-badge">{{vm.node.nodeId}}</span>
+            <h4 class="list-group-item-heading">Node ID</h4>
+        </li>
+
+        <li class="list-group-item">
+            <span class="badge node-management-badge">{{vm.node.remoteTimestamp | timeAgoFilter}}</span>
+            <h4 class="list-group-item-heading">Last active</h4>
+        </li>
+
+        <li class="list-group-item">
+            <span class="badge node-management-badge"
+                  ng-style="(vm.newStatus !== vm.node.status) && {'background-color' : '#f0ad4e'} || {'background-color' : 'gray'}">
+                <div ng-if="vm.showEditOptions===false">{{vm.newStatus}}</div>
+                <div ng-if="vm.showEditOptions">
+                    <select class="form-control property-change-box"
+                            ng-style="(vm.newStatus !== vm.node.status) && {'background-color' : '#f0ad4e'} || {'background-color' : 'gray'}"
+                            ng-options="status for status in vm.statuses" ng-init="vm.newStatus"
+                            ng-model="vm.newStatus">
+                    </select>
+                    <label style="font-size:small">Update status... (current: {{vm.node.status}})
+                    </label>
+                </div>
+
+            </span>
+            <h4 class="list-group-item-heading">Status</h4>
+            <br ng-if="vm.showEditOptions">
+            <br ng-if="vm.showEditOptions">
+            <p class="master-change-warning" ng-show="vm.node.status === 'MASTER' && vm.newStatus !== 'MASTER'">Warning!
+                Applying changes will de-mote this node from being Master and a new Master will be elected from other
+                management nodes.</p>
+            <p class="master-change-warning" ng-show="vm.node.status !== 'MASTER' && vm.newStatus === 'MASTER'">Warning!
+                Applying changes will de-mote the current Master and this node will be forcibly made the new Master.</p>
+        </li>
+
+        <li class="list-group-item" ng-style="vm.showEditOptions && {'min-height': '80px'}">
+
+            <span class="badge node-management-badge"
+                  ng-style="(vm.newPriority !== vm.node.priority) && {'background-color' : '#f0ad4e'} || {'background-color' : 'gray'}">
+                <div ng-if="vm.showEditOptions===false">{{vm.newPriority}}</div>
+                <div ng-if="vm.showEditOptions">
+                    <input class="form-control property-change-box" type="number" ng-model="vm.newPriority"
+                           ng-style="(vm.newPriority !== vm.node.priority) && {'background-color' : '#f0ad4e'} || {'background-color' : 'gray'}">
+                        <label style="font-size:small">Update priority... (current: {{vm.node.priority}})
+                        </label>
+                    </input>
+                </div>
+            </span>
+            <h4 class="list-group-item-heading">Priority</h4>
+
+        </li>
+    </ul>
+    <div class="node-management-actions">
+        <button class="btn btn-lg btn-danger btn-default pull-right" style="margin-left: 1em; margin-right: 1em"
+                ng-click="vm.cancelAndQuit()">Cancel</button>
+        <button class="btn btn-lg btn-default pull-right" style="margin-left: 1em;"
+                ng-if="!vm.showEditOptions"
+                ng-click="vm.setShowEditOptions(true)">Edit</button>

Review comment:
       Function is not required, can be:
   ```
   ng-click="vm.showEditOptions = !vm.showEditOptions"
   ```




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r668928273



##########
File path: ui-modules/home/app/views/about/node-management/node-management.template.html
##########
@@ -0,0 +1,88 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you 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.
+-->
+
+<h3 class="node-management-title">Node Management Panel</h3>
+<div>
+    <div></div>
+    <ul class="list-group">
+        <li class="list-group-item">
+            <span class="badge node-management-badge">{{vm.node.nodeId}}</span>
+            <h4 class="list-group-item-heading">Node ID</h4>
+        </li>
+
+        <li class="list-group-item">
+            <span class="badge node-management-badge">{{vm.node.remoteTimestamp | timeAgoFilter}}</span>
+            <h4 class="list-group-item-heading">Last active</h4>
+        </li>
+
+        <li class="list-group-item">
+            <span class="badge node-management-badge"
+                  ng-style="(vm.newStatus !== vm.node.status) && {'background-color' : '#f0ad4e'} || {'background-color' : 'gray'}">
+                <div ng-if="vm.showEditOptions===false">{{vm.newStatus}}</div>
+                <div ng-if="vm.showEditOptions">
+                    <select class="form-control property-change-box"
+                            ng-style="(vm.newStatus !== vm.node.status) && {'background-color' : '#f0ad4e'} || {'background-color' : 'gray'}"
+                            ng-options="status for status in vm.statuses" ng-init="vm.newStatus"
+                            ng-model="vm.newStatus">
+                    </select>
+                    <label style="font-size:small">Update status... (current: {{vm.node.status}})
+                    </label>
+                </div>
+
+            </span>
+            <h4 class="list-group-item-heading">Status</h4>
+            <br ng-if="vm.showEditOptions">
+            <br ng-if="vm.showEditOptions">
+            <p class="master-change-warning" ng-show="vm.node.status === 'MASTER' && vm.newStatus !== 'MASTER'">Warning!
+                Applying changes will de-mote this node from being Master and a new Master will be elected from other
+                management nodes.</p>
+            <p class="master-change-warning" ng-show="vm.node.status !== 'MASTER' && vm.newStatus === 'MASTER'">Warning!
+                Applying changes will de-mote the current Master and this node will be forcibly made the new Master.</p>
+        </li>
+
+        <li class="list-group-item" ng-style="vm.showEditOptions && {'min-height': '80px'}">
+
+            <span class="badge node-management-badge"
+                  ng-style="(vm.newPriority !== vm.node.priority) && {'background-color' : '#f0ad4e'} || {'background-color' : 'gray'}">
+                <div ng-if="vm.showEditOptions===false">{{vm.newPriority}}</div>

Review comment:
       Change to 'ng-if="!vm.showEditOptions"'

##########
File path: ui-modules/home/app/views/about/node-management/node-management.template.html
##########
@@ -0,0 +1,88 @@
+<!--
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you 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.
+-->
+
+<h3 class="node-management-title">Node Management Panel</h3>
+<div>
+    <div></div>
+    <ul class="list-group">
+        <li class="list-group-item">
+            <span class="badge node-management-badge">{{vm.node.nodeId}}</span>
+            <h4 class="list-group-item-heading">Node ID</h4>
+        </li>
+
+        <li class="list-group-item">
+            <span class="badge node-management-badge">{{vm.node.remoteTimestamp | timeAgoFilter}}</span>
+            <h4 class="list-group-item-heading">Last active</h4>
+        </li>
+
+        <li class="list-group-item">
+            <span class="badge node-management-badge"
+                  ng-style="(vm.newStatus !== vm.node.status) && {'background-color' : '#f0ad4e'} || {'background-color' : 'gray'}">
+                <div ng-if="vm.showEditOptions===false">{{vm.newStatus}}</div>
+                <div ng-if="vm.showEditOptions">
+                    <select class="form-control property-change-box"
+                            ng-style="(vm.newStatus !== vm.node.status) && {'background-color' : '#f0ad4e'} || {'background-color' : 'gray'}"
+                            ng-options="status for status in vm.statuses" ng-init="vm.newStatus"
+                            ng-model="vm.newStatus">
+                    </select>
+                    <label style="font-size:small">Update status... (current: {{vm.node.status}})
+                    </label>
+                </div>
+
+            </span>
+            <h4 class="list-group-item-heading">Status</h4>
+            <br ng-if="vm.showEditOptions">
+            <br ng-if="vm.showEditOptions">
+            <p class="master-change-warning" ng-show="vm.node.status === 'MASTER' && vm.newStatus !== 'MASTER'">Warning!
+                Applying changes will de-mote this node from being Master and a new Master will be elected from other
+                management nodes.</p>
+            <p class="master-change-warning" ng-show="vm.node.status !== 'MASTER' && vm.newStatus === 'MASTER'">Warning!
+                Applying changes will de-mote the current Master and this node will be forcibly made the new Master.</p>
+        </li>
+
+        <li class="list-group-item" ng-style="vm.showEditOptions && {'min-height': '80px'}">
+
+            <span class="badge node-management-badge"
+                  ng-style="(vm.newPriority !== vm.node.priority) && {'background-color' : '#f0ad4e'} || {'background-color' : 'gray'}">
+                <div ng-if="vm.showEditOptions===false">{{vm.newPriority}}</div>

Review comment:
       Change to `ng-if="!vm.showEditOptions"`




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] asfgit closed pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
asfgit closed pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228


   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] ahgittin commented on pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
ahgittin commented on pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#issuecomment-880589897


   LGTM - nice comments @jathanasiou 


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] jathanasiou commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
jathanasiou commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r669842563



##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -55,17 +61,141 @@ export function aboutStateConfig($stateProvider) {
     $stateProvider.state(aboutState);
 }
 
-export function aboutStateController($scope, brBrandInfo, version, states) {
+export function aboutStateController($scope, $element, $q, $uibModal, brBrandInfo, version, states, serverApi) {
     $scope.$emit(HIDE_INTERSTITIAL_SPINNER_EVENT);
     $scope.getBrandedText = brBrandInfo.getBrandedText;
-
     $scope.serverVersion = version.data;
-    this.states = states.data;
-    this.buildInfo = {
+    $scope.states = states.data;
+    $scope.buildInfo = {
         buildVersion: BUILD_VERSION,
         buildName: BUILD_NAME,
         buildBranch: BUILD_BRANCH,
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    $scope.container = $element[0];
+    $scope.now = Date.now();
+    $scope.expectedNodeCounter = Object.keys($scope.states.nodes).length;
+    $scope.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    $scope.openDialog = function (states, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', nodeManagementModalController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[states.ownId];
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    $scope.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    $scope.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementModalController($scope, $uibModalInstance, node) {
+
+        // newStatus and newPriority are required to belong to the instance of the modal
+        let vm = this;
+        vm.newPriority = node.priority;
+        vm.newStatus = node.status;
+        
+        $scope.node = node;
+        $scope.statuses = ["MASTER", "STANDBY", "HOT_STANDBY", "HOT_BACKUP"];
+        $scope.now = Date.now();
+        $scope.showEditOptions = false;
+
+        $scope.applyChangesAndQuit = function () {
+            let promiseList = [];
+            if ($scope.node.priority !== vm.newPriority) {
+                let result = serverApi.setHaPriority(vm.newPriority);
+                promiseList.push(result);
+            }
+            if ($scope.node.status !== vm.newStatus) {
+                let result = serverApi.setHaStatus(vm.newStatus);
+                promiseList.push(result);
+            }
+            $uibModalInstance.close(promiseList);
+
+        }
+
+        $scope.cancelAndQuit = function () {
+            vm.newPriority = $scope.node.priority;
+            vm.newStatus = $scope.node.status;
+            $uibModalInstance.dismiss();
+        }
+
+        $scope.doShowEditOptions = function () {
+            $scope.showEditOptions = true;
+        }
+
+    }
+
+    $scope.removeNode = function (nodeId) {
+        $scope.template = 'spinnerTemplate';
+        let removeNode = serverApi.removeHaTerminatedNode(nodeId);
+        removeNode.then(data => {
+            $scope.expectedNodeCounter--;
+            let event = new CustomEvent('update-states', {});
+            $scope.container.dispatchEvent(event);
+        });
+    }
+
+    $scope.removeAllTerminatedNodes = function () {
+        $scope.template = 'spinnerTemplate';
+        let removeNodes = serverApi.removeHaTerminatedNodes();
+        removeNodes.then(data => {
+            for (const node in $scope.states.nodes) {
+                if ($scope.states.nodes[node].status === "TERMINATED" || $scope.states.nodes[node].status === "FAILED") $scope.expectedNodeCounter--;
+            }
+            let event = new CustomEvent('update-states', {});
+            $scope.container.dispatchEvent(event);
+        });
+    }
+
+    $element.bind('update-states', (event) => {
+        let updateStates = serverApi.getHaStates();
+        updateStates.then(data => {
+            if (Object.keys(data.data.nodes).length === $scope.expectedNodeCounter) {
+                $scope.states = data.data;
+                $scope.now = Date.now();
+                $scope.template = 'haStatusTemplate';
+            } else {
+                let event = new CustomEvent('update-states', {});
+                $scope.container.dispatchEvent(event);
+            }
+        })
+    })
+
 }
+
+export function timeAgoFilter() {

Review comment:
       Equivalanent and shorter:
   ```
   export const timeAgoFilter = () => (input) => input ? moment(input).fromNow() : null;
   ```




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r668937060



##########
File path: ui-modules/utils/api/brooklyn/server.js
##########
@@ -60,4 +65,50 @@ function ServerApi($http, $q, cache) {
     function getUpExtended(config) {
         return $http.get('/v1/server/up/extended', angular.extend({cache: cache}, config));
     }
+
+    function setHaStatus(state, config) {

Review comment:
       `config` is not used




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] zan-mateusz commented on pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
zan-mateusz commented on pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#issuecomment-865700388


   > can you merge master and resolve the conflicts? (should be simple -- it's just around the recent logbook additions)
   
   Thanks Alex, I think that should be now resolved


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r668939793



##########
File path: ui-modules/home/app/views/about/about.template.html
##########
@@ -54,29 +54,71 @@ <h4 class="list-group-item-heading">Brooklyn Server</h4>
                 </li>
             </ul>
 
-            <h2>HA status</h2>
-            <table class="table table-responsive table-bordered">
-                <thead>
-                <tr>
-                    <th class="server-status-node-id">Node ID</th>
-                    <th>Status</th>
-                </tr>
-                </thead>
-                <tbody>
-                <tr ng-repeat="node in vm.states.nodes track by node.nodeId"
-                    ng-class="{success: node.state === 'online', danger: node.state === 'offline'}">
-                    <td>
-                        {{node.nodeId}}
-                        <span ng-if="node.nodeId === vm.states.ownId" class="label label-info">current</span>
-                        <span ng-if="node.status === 'MASTER'" class="label label-success">master</span>
-                    </td>
-                    <td>
-                        <span class="text-left">{{node.status | lowercase}}</span>
-                        <a ng-if="node.state === 'online'" class="btn btn-xs btn-success pull-right" class="text-right" ng-class="{disabled: node.nodeUri === null}">Open</a>
-                    </td>
-                </tr>
-                </tbody>
-            </table>
+            <h2>
+                HA status
+                <button ng-if="vm.states.nodes[vm.states.ownId].status === 'MASTER'"
+                        ng-click="vm.removeAllTerminatedNodes()" class="btn btn-sm btn-default"
+                        style="float: right;">Remove terminated nodes</button>
+            </h2>
+
+            <ng-include src="vm.template"></ng-include>
+
+            <script type="text/ng-template" id="haStatusTemplate">
+
+                <table class="table table-responsive table-bordered table-hover">
+                    <thead>
+                    <tr>
+                        <th class="server-status-node-id">Node ID</th>
+                        <th>Information</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <tr ng-repeat="node in vm.states.nodes track by node.nodeId"
+                        ng-class="{success: node.state === 'online', danger: node.state === 'offline'}"
+                        ng-mouseover="row = $index" ng-mouseleave="row = -1">
+                        <td>
+                            {{node.nodeId}}
+                            <button class="btn btn-sm btn-default" style="float: right;"
+                                    ng-if="node.nodeId === vm.states.ownId"
+                                    ng-click="vm.openDialog(vm.states, vm.states.ownId, vm.serverApi, vm.container)"
+                                    ng-show="row == $index">Manage</button>
+                            <button class="btn btn-sm btn-default" style="float: right;"
+                                    ng-if="(node.status === 'TERMINATED') && (vm.states.nodes[vm.states.ownId].status === 'MASTER')"
+                                    ng-click="vm.removeNode(node.nodeId)" ng-show="row == $index">Remove</button>
+                            <span ng-if="node.nodeId === vm.states.ownId" class="label label-info">current</span>
+                            <span ng-if="node.status === 'MASTER'" class="label label-success">master</span><br>
+                        </td>
+                        <td>
+                            <span class="text-left">Status: {{node.status | lowercase}}</span><br>
+                            <span class="text-left">Last active: {{node.remoteTimestamp | timeAgoFilter}}</span><br>
+                            <span class="text-left">Priority: {{node.priority}}</span><br>
+                            <a ng-if="node.state === 'online'" class="btn btn-xs btn-success pull-right"
+                               class="text-right" ng-class="{disabled: node.nodeUri === null}">Open</a>
+                        </td>
+                    </tr>
+                    </tbody>
+                </table>
+            </script>
+
+            <script type="text/ng-template" id="spinnerTemplate">
+                <br-interstitial-spinner event-count="1" remove-after="0" max-wait="120000">
+                    <style>
+                        ${require('brooklyn-shared/partials/interstitial.less')}
+                    </style>
+
+                    <div class="spinner-area" style="height: 100px">
+                        <div class="spinner">
+                            <div class="svg-container">
+                                <svg viewBox="20 20 60 60">
+                                    <circle r="25" cx="50" cy="50" class="background"/>
+                                    <circle r="25" cx="50" cy="50" class="foreground"/>
+                                </svg>
+                            </div>
+                        </div>
+                    </div>
+                </br-interstitial-spinner>
+            </script>
+  
             <h2>Logbook</h2>
             <a class="btn btn-sm btn-default" href="#!/logbook"><i class="fa fa-eye"></i> Logbook</a>

Review comment:
       This file looks like merged in, however, git does not show it?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r668932269



##########
File path: ui-modules/home/app/views/about/about.template.html
##########
@@ -54,29 +54,71 @@ <h4 class="list-group-item-heading">Brooklyn Server</h4>
                 </li>
             </ul>
 
-            <h2>HA status</h2>
-            <table class="table table-responsive table-bordered">
-                <thead>
-                <tr>
-                    <th class="server-status-node-id">Node ID</th>
-                    <th>Status</th>
-                </tr>
-                </thead>
-                <tbody>
-                <tr ng-repeat="node in vm.states.nodes track by node.nodeId"
-                    ng-class="{success: node.state === 'online', danger: node.state === 'offline'}">
-                    <td>
-                        {{node.nodeId}}
-                        <span ng-if="node.nodeId === vm.states.ownId" class="label label-info">current</span>
-                        <span ng-if="node.status === 'MASTER'" class="label label-success">master</span>
-                    </td>
-                    <td>
-                        <span class="text-left">{{node.status | lowercase}}</span>
-                        <a ng-if="node.state === 'online'" class="btn btn-xs btn-success pull-right" class="text-right" ng-class="{disabled: node.nodeUri === null}">Open</a>
-                    </td>
-                </tr>
-                </tbody>
-            </table>
+            <h2>
+                HA status
+                <button ng-if="vm.states.nodes[vm.states.ownId].status === 'MASTER'"
+                        ng-click="vm.removeAllTerminatedNodes()" class="btn btn-sm btn-default"
+                        style="float: right;">Remove terminated nodes</button>
+            </h2>
+
+            <ng-include src="vm.template"></ng-include>
+
+            <script type="text/ng-template" id="haStatusTemplate">
+
+                <table class="table table-responsive table-bordered table-hover">
+                    <thead>
+                    <tr>
+                        <th class="server-status-node-id">Node ID</th>
+                        <th>Information</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <tr ng-repeat="node in vm.states.nodes track by node.nodeId"
+                        ng-class="{success: node.state === 'online', danger: node.state === 'offline'}"
+                        ng-mouseover="row = $index" ng-mouseleave="row = -1">
+                        <td>
+                            {{node.nodeId}}
+                            <button class="btn btn-sm btn-default" style="float: right;"
+                                    ng-if="node.nodeId === vm.states.ownId"
+                                    ng-click="vm.openDialog(vm.states, vm.states.ownId, vm.serverApi, vm.container)"
+                                    ng-show="row == $index">Manage</button>
+                            <button class="btn btn-sm btn-default" style="float: right;"
+                                    ng-if="(node.status === 'TERMINATED') && (vm.states.nodes[vm.states.ownId].status === 'MASTER')"
+                                    ng-click="vm.removeNode(node.nodeId)" ng-show="row == $index">Remove</button>
+                            <span ng-if="node.nodeId === vm.states.ownId" class="label label-info">current</span>
+                            <span ng-if="node.status === 'MASTER'" class="label label-success">master</span><br>
+                        </td>
+                        <td>
+                            <span class="text-left">Status: {{node.status | lowercase}}</span><br>
+                            <span class="text-left">Last active: {{node.remoteTimestamp | timeAgoFilter}}</span><br>
+                            <span class="text-left">Priority: {{node.priority}}</span><br>
+                            <a ng-if="node.state === 'online'" class="btn btn-xs btn-success pull-right"
+                               class="text-right" ng-class="{disabled: node.nodeUri === null}">Open</a>
+                        </td>
+                    </tr>
+                    </tbody>
+                </table>
+            </script>
+
+            <script type="text/ng-template" id="spinnerTemplate">
+                <br-interstitial-spinner event-count="1" remove-after="0" max-wait="120000">
+                    <style>
+                        ${require('brooklyn-shared/partials/interstitial.less')}
+                    </style>
+
+                    <div class="spinner-area" style="height: 100px">
+                        <div class="spinner">
+                            <div class="svg-container">
+                                <svg viewBox="20 20 60 60">
+                                    <circle r="25" cx="50" cy="50" class="background"/>
+                                    <circle r="25" cx="50" cy="50" class="foreground"/>
+                                </svg>
+                            </div>
+                        </div>
+                    </div>
+                </br-interstitial-spinner>
+            </script>
+  
             <h2>Logbook</h2>
             <a class="btn btn-sm btn-default" href="#!/logbook"><i class="fa fa-eye"></i> Logbook</a>

Review comment:
       Merge in logbook changes, should  be `<br-logbook></br-logbook>` now.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] jathanasiou commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
jathanasiou commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r669833866



##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -55,17 +61,141 @@ export function aboutStateConfig($stateProvider) {
     $stateProvider.state(aboutState);
 }
 
-export function aboutStateController($scope, brBrandInfo, version, states) {
+export function aboutStateController($scope, $element, $q, $uibModal, brBrandInfo, version, states, serverApi) {
     $scope.$emit(HIDE_INTERSTITIAL_SPINNER_EVENT);
     $scope.getBrandedText = brBrandInfo.getBrandedText;
-
     $scope.serverVersion = version.data;
-    this.states = states.data;
-    this.buildInfo = {
+    $scope.states = states.data;
+    $scope.buildInfo = {
         buildVersion: BUILD_VERSION,
         buildName: BUILD_NAME,
         buildBranch: BUILD_BRANCH,
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    $scope.container = $element[0];
+    $scope.now = Date.now();
+    $scope.expectedNodeCounter = Object.keys($scope.states.nodes).length;
+    $scope.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    $scope.openDialog = function (states, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', nodeManagementModalController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[states.ownId];
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    $scope.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});

Review comment:
       variable declarations aren't great for memory. If they don't add valuable clarity it might be better to be concise like
   ```
   container.dispatchEvent(new CustomEvent('update-states', {}));
   ```




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] ahgittin commented on pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
ahgittin commented on pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#issuecomment-865234874


   can you merge master and resolve the conflicts?  (should be simple -- it's just around the recent logbook additions)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#issuecomment-879246640


   @zan-mateusz, I left couple of tidy-up comments. I see that latest logbook changes are merged, however, GitHub does not seem to show them, or there is something else that is not resolved.


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r655135942



##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -67,4 +72,139 @@ export function aboutStateController($scope, brBrandInfo, version, states) {
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    this.container = $element[0];
+    this.now = Date.now();
+    this.expectedNodeCounter = Object.keys(this.states.nodes).length;
+    this.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    this.openDialog = function (states, nodeId, serverApi, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', 'serverApi', nodeManagementController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[nodeId];
+                    },
+                    serverApi: function () {
+                        return serverApi;
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    this.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    this.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementController($scope, $uibModalInstance, node, serverApi) {
+
+        this.node = node;

Review comment:
       Controller instance could be named asa `vm`, the same as `controllerAs: 'vm',`, instead of `mgmtController`.
   See examples in blueprint-composer, e.g. spec-editor.

##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -67,4 +72,139 @@ export function aboutStateController($scope, brBrandInfo, version, states) {
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    this.container = $element[0];
+    this.now = Date.now();
+    this.expectedNodeCounter = Object.keys(this.states.nodes).length;
+    this.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    this.openDialog = function (states, nodeId, serverApi, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', 'serverApi', nodeManagementController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[nodeId];
+                    },
+                    serverApi: function () {
+                        return serverApi;
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    this.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    this.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementController($scope, $uibModalInstance, node, serverApi) {
+
+        this.node = node;

Review comment:
       Controller instance could be named as `vm`, the same as `controllerAs: 'vm',`, instead of `mgmtController`.
   See examples in blueprint-composer, e.g. spec-editor.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] jathanasiou commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
jathanasiou commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r669837685



##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -55,17 +61,141 @@ export function aboutStateConfig($stateProvider) {
     $stateProvider.state(aboutState);
 }
 
-export function aboutStateController($scope, brBrandInfo, version, states) {
+export function aboutStateController($scope, $element, $q, $uibModal, brBrandInfo, version, states, serverApi) {
     $scope.$emit(HIDE_INTERSTITIAL_SPINNER_EVENT);
     $scope.getBrandedText = brBrandInfo.getBrandedText;
-
     $scope.serverVersion = version.data;
-    this.states = states.data;
-    this.buildInfo = {
+    $scope.states = states.data;
+    $scope.buildInfo = {
         buildVersion: BUILD_VERSION,
         buildName: BUILD_NAME,
         buildBranch: BUILD_BRANCH,
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    $scope.container = $element[0];
+    $scope.now = Date.now();
+    $scope.expectedNodeCounter = Object.keys($scope.states.nodes).length;
+    $scope.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    $scope.openDialog = function (states, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', nodeManagementModalController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[states.ownId];
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    $scope.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    $scope.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementModalController($scope, $uibModalInstance, node) {
+
+        // newStatus and newPriority are required to belong to the instance of the modal
+        let vm = this;
+        vm.newPriority = node.priority;
+        vm.newStatus = node.status;
+        
+        $scope.node = node;
+        $scope.statuses = ["MASTER", "STANDBY", "HOT_STANDBY", "HOT_BACKUP"];
+        $scope.now = Date.now();
+        $scope.showEditOptions = false;
+
+        $scope.applyChangesAndQuit = function () {
+            let promiseList = [];
+            if ($scope.node.priority !== vm.newPriority) {
+                let result = serverApi.setHaPriority(vm.newPriority);
+                promiseList.push(result);
+            }
+            if ($scope.node.status !== vm.newStatus) {
+                let result = serverApi.setHaStatus(vm.newStatus);
+                promiseList.push(result);
+            }
+            $uibModalInstance.close(promiseList);
+
+        }
+
+        $scope.cancelAndQuit = function () {
+            vm.newPriority = $scope.node.priority;
+            vm.newStatus = $scope.node.status;
+            $uibModalInstance.dismiss();
+        }
+
+        $scope.doShowEditOptions = function () {
+            $scope.showEditOptions = true;
+        }
+
+    }
+
+    $scope.removeNode = function (nodeId) {
+        $scope.template = 'spinnerTemplate';
+        let removeNode = serverApi.removeHaTerminatedNode(nodeId);
+        removeNode.then(data => {
+            $scope.expectedNodeCounter--;
+            let event = new CustomEvent('update-states', {});
+            $scope.container.dispatchEvent(event);
+        });
+    }
+
+    $scope.removeAllTerminatedNodes = function () {
+        $scope.template = 'spinnerTemplate';
+        let removeNodes = serverApi.removeHaTerminatedNodes();
+        removeNodes.then(data => {
+            for (const node in $scope.states.nodes) {
+                if ($scope.states.nodes[node].status === "TERMINATED" || $scope.states.nodes[node].status === "FAILED") $scope.expectedNodeCounter--;
+            }
+            let event = new CustomEvent('update-states', {});
+            $scope.container.dispatchEvent(event);
+        });
+    }
+
+    $element.bind('update-states', (event) => {
+        let updateStates = serverApi.getHaStates();
+        updateStates.then(data => {

Review comment:
       `updateStates.then(({ data }) =>`
   Deconstruction would lead to much more natural syntax.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r668939793



##########
File path: ui-modules/home/app/views/about/about.template.html
##########
@@ -54,29 +54,71 @@ <h4 class="list-group-item-heading">Brooklyn Server</h4>
                 </li>
             </ul>
 
-            <h2>HA status</h2>
-            <table class="table table-responsive table-bordered">
-                <thead>
-                <tr>
-                    <th class="server-status-node-id">Node ID</th>
-                    <th>Status</th>
-                </tr>
-                </thead>
-                <tbody>
-                <tr ng-repeat="node in vm.states.nodes track by node.nodeId"
-                    ng-class="{success: node.state === 'online', danger: node.state === 'offline'}">
-                    <td>
-                        {{node.nodeId}}
-                        <span ng-if="node.nodeId === vm.states.ownId" class="label label-info">current</span>
-                        <span ng-if="node.status === 'MASTER'" class="label label-success">master</span>
-                    </td>
-                    <td>
-                        <span class="text-left">{{node.status | lowercase}}</span>
-                        <a ng-if="node.state === 'online'" class="btn btn-xs btn-success pull-right" class="text-right" ng-class="{disabled: node.nodeUri === null}">Open</a>
-                    </td>
-                </tr>
-                </tbody>
-            </table>
+            <h2>
+                HA status
+                <button ng-if="vm.states.nodes[vm.states.ownId].status === 'MASTER'"
+                        ng-click="vm.removeAllTerminatedNodes()" class="btn btn-sm btn-default"
+                        style="float: right;">Remove terminated nodes</button>
+            </h2>
+
+            <ng-include src="vm.template"></ng-include>
+
+            <script type="text/ng-template" id="haStatusTemplate">
+
+                <table class="table table-responsive table-bordered table-hover">
+                    <thead>
+                    <tr>
+                        <th class="server-status-node-id">Node ID</th>
+                        <th>Information</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <tr ng-repeat="node in vm.states.nodes track by node.nodeId"
+                        ng-class="{success: node.state === 'online', danger: node.state === 'offline'}"
+                        ng-mouseover="row = $index" ng-mouseleave="row = -1">
+                        <td>
+                            {{node.nodeId}}
+                            <button class="btn btn-sm btn-default" style="float: right;"
+                                    ng-if="node.nodeId === vm.states.ownId"
+                                    ng-click="vm.openDialog(vm.states, vm.states.ownId, vm.serverApi, vm.container)"
+                                    ng-show="row == $index">Manage</button>
+                            <button class="btn btn-sm btn-default" style="float: right;"
+                                    ng-if="(node.status === 'TERMINATED') && (vm.states.nodes[vm.states.ownId].status === 'MASTER')"
+                                    ng-click="vm.removeNode(node.nodeId)" ng-show="row == $index">Remove</button>
+                            <span ng-if="node.nodeId === vm.states.ownId" class="label label-info">current</span>
+                            <span ng-if="node.status === 'MASTER'" class="label label-success">master</span><br>
+                        </td>
+                        <td>
+                            <span class="text-left">Status: {{node.status | lowercase}}</span><br>
+                            <span class="text-left">Last active: {{node.remoteTimestamp | timeAgoFilter}}</span><br>
+                            <span class="text-left">Priority: {{node.priority}}</span><br>
+                            <a ng-if="node.state === 'online'" class="btn btn-xs btn-success pull-right"
+                               class="text-right" ng-class="{disabled: node.nodeUri === null}">Open</a>
+                        </td>
+                    </tr>
+                    </tbody>
+                </table>
+            </script>
+
+            <script type="text/ng-template" id="spinnerTemplate">
+                <br-interstitial-spinner event-count="1" remove-after="0" max-wait="120000">
+                    <style>
+                        ${require('brooklyn-shared/partials/interstitial.less')}
+                    </style>
+
+                    <div class="spinner-area" style="height: 100px">
+                        <div class="spinner">
+                            <div class="svg-container">
+                                <svg viewBox="20 20 60 60">
+                                    <circle r="25" cx="50" cy="50" class="background"/>
+                                    <circle r="25" cx="50" cy="50" class="foreground"/>
+                                </svg>
+                            </div>
+                        </div>
+                    </div>
+                </br-interstitial-spinner>
+            </script>
+  
             <h2>Logbook</h2>
             <a class="btn btn-sm btn-default" href="#!/logbook"><i class="fa fa-eye"></i> Logbook</a>

Review comment:
       This file looks like merged with latest master, however, GitHub does not show it?




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] jathanasiou commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
jathanasiou commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r669831667



##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -55,17 +61,141 @@ export function aboutStateConfig($stateProvider) {
     $stateProvider.state(aboutState);
 }
 
-export function aboutStateController($scope, brBrandInfo, version, states) {
+export function aboutStateController($scope, $element, $q, $uibModal, brBrandInfo, version, states, serverApi) {
     $scope.$emit(HIDE_INTERSTITIAL_SPINNER_EVENT);
     $scope.getBrandedText = brBrandInfo.getBrandedText;
-
     $scope.serverVersion = version.data;
-    this.states = states.data;
-    this.buildInfo = {
+    $scope.states = states.data;
+    $scope.buildInfo = {
         buildVersion: BUILD_VERSION,
         buildName: BUILD_NAME,
         buildBranch: BUILD_BRANCH,
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    $scope.container = $element[0];
+    $scope.now = Date.now();
+    $scope.expectedNodeCounter = Object.keys($scope.states.nodes).length;
+    $scope.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    $scope.openDialog = function (states, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', nodeManagementModalController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[states.ownId];
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    $scope.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    $scope.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementModalController($scope, $uibModalInstance, node) {
+
+        // newStatus and newPriority are required to belong to the instance of the modal
+        let vm = this;
+        vm.newPriority = node.priority;
+        vm.newStatus = node.status;
+        
+        $scope.node = node;
+        $scope.statuses = ["MASTER", "STANDBY", "HOT_STANDBY", "HOT_BACKUP"];
+        $scope.now = Date.now();
+        $scope.showEditOptions = false;
+
+        $scope.applyChangesAndQuit = function () {
+            let promiseList = [];
+            if ($scope.node.priority !== vm.newPriority) {
+                let result = serverApi.setHaPriority(vm.newPriority);
+                promiseList.push(result);
+            }
+            if ($scope.node.status !== vm.newStatus) {
+                let result = serverApi.setHaStatus(vm.newStatus);
+                promiseList.push(result);
+            }
+            $uibModalInstance.close(promiseList);
+
+        }
+
+        $scope.cancelAndQuit = function () {
+            vm.newPriority = $scope.node.priority;
+            vm.newStatus = $scope.node.status;
+            $uibModalInstance.dismiss();
+        }
+
+        $scope.doShowEditOptions = function () {
+            $scope.showEditOptions = true;
+        }
+
+    }
+
+    $scope.removeNode = function (nodeId) {
+        $scope.template = 'spinnerTemplate';
+        let removeNode = serverApi.removeHaTerminatedNode(nodeId);
+        removeNode.then(data => {
+            $scope.expectedNodeCounter--;
+            let event = new CustomEvent('update-states', {});
+            $scope.container.dispatchEvent(event);
+        });
+    }
+
+    $scope.removeAllTerminatedNodes = function () {
+        $scope.template = 'spinnerTemplate';
+        let removeNodes = serverApi.removeHaTerminatedNodes();
+        removeNodes.then(data => {
+            for (const node in $scope.states.nodes) {

Review comment:
       consider using `$scope.states.nodes.forEach(node => { logic here )` instead for a better syntax




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r655132274



##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -67,4 +72,139 @@ export function aboutStateController($scope, brBrandInfo, version, states) {
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    this.container = $element[0];
+    this.now = Date.now();
+    this.expectedNodeCounter = Object.keys(this.states.nodes).length;
+    this.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    this.openDialog = function (states, nodeId, serverApi, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', 'serverApi', nodeManagementController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[nodeId];
+                    },
+                    serverApi: function () {
+                        return serverApi;
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    this.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    this.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementController($scope, $uibModalInstance, node, serverApi) {
+
+        this.node = node;

Review comment:
       I suggest to create reference variable for `this` to reference the instance of the controller.
   ```
   let mgmtController = this;
   mgmtController.node = node;
   // etc.
   ```
   
   So that it is clear what instance does `this` reference to:
   ```
   mgmtController.setHaStatus = function () {
       let result = serverApi.setHaStatus(this.newStatus);
       this.node.status = this.newStatus; // this is likely to be a reference to function() instance, not the controller.
       // or ?
       mgmtController.setHaStatus.node.status; // explicit reference to the controller instance.
   }
   ```

##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -67,4 +72,139 @@ export function aboutStateController($scope, brBrandInfo, version, states) {
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    this.container = $element[0];
+    this.now = Date.now();
+    this.expectedNodeCounter = Object.keys(this.states.nodes).length;
+    this.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    this.openDialog = function (states, nodeId, serverApi, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', 'serverApi', nodeManagementController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[nodeId];
+                    },
+                    serverApi: function () {
+                        return serverApi;
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    this.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    this.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementController($scope, $uibModalInstance, node, serverApi) {
+
+        this.node = node;

Review comment:
       I suggest to create reference variable for `this` to reference the instance of the controller.
   ```
   let mgmtController = this;
   mgmtController.node = node;
   // etc.
   ```
   
   So that it is clear what instance does `this` reference to:
   ```
   mgmtController.setHaStatus = function () {
       let result = serverApi.setHaStatus(this.newStatus);
       this.node.status = this.newStatus; // this is likely to be a reference to function() instance, not the controller.
       // or ?
       mgmtController.node.status; // explicit reference to the controller instance.
   }
   ```

##########
File path: ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
##########
@@ -230,7 +230,7 @@ function BlueprintService($log, $q, $sce, paletteApi, iconGenerator, dslService,
     }
 
     function lookup(entity, id, any = false) {
-        if (entity._id === id) {
+        if ((entity._id === id) || (entity.id === id)) {

Review comment:
       Do we still need this? I thought we agreed to not engage public ID of the Entity (which is optional, can be null, and not unique) into lookup.

##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -67,4 +72,139 @@ export function aboutStateController($scope, brBrandInfo, version, states) {
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    this.container = $element[0];
+    this.now = Date.now();
+    this.expectedNodeCounter = Object.keys(this.states.nodes).length;
+    this.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    this.openDialog = function (states, nodeId, serverApi, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', 'serverApi', nodeManagementController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[nodeId];
+                    },
+                    serverApi: function () {
+                        return serverApi;
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    this.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    this.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementController($scope, $uibModalInstance, node, serverApi) {
+
+        this.node = node;

Review comment:
       Applies to all functions defined below.

##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -67,4 +72,139 @@ export function aboutStateController($scope, brBrandInfo, version, states) {
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    this.container = $element[0];
+    this.now = Date.now();
+    this.expectedNodeCounter = Object.keys(this.states.nodes).length;
+    this.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    this.openDialog = function (states, nodeId, serverApi, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', 'serverApi', nodeManagementController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[nodeId];
+                    },
+                    serverApi: function () {
+                        return serverApi;
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    this.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    this.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementController($scope, $uibModalInstance, node, serverApi) {
+
+        this.node = node;

Review comment:
       Controller instance could be named asa `vm`, the same as `controllerAs: 'vm',`, instead of `mgmtController`.
   See examples in blueprint-composer, e.g. spec-editor.

##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -67,4 +72,139 @@ export function aboutStateController($scope, brBrandInfo, version, states) {
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    this.container = $element[0];
+    this.now = Date.now();
+    this.expectedNodeCounter = Object.keys(this.states.nodes).length;
+    this.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    this.openDialog = function (states, nodeId, serverApi, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', 'serverApi', nodeManagementController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[nodeId];
+                    },
+                    serverApi: function () {
+                        return serverApi;
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    this.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    this.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementController($scope, $uibModalInstance, node, serverApi) {
+
+        this.node = node;

Review comment:
       Controller instance could be named as `vm`, the same as `controllerAs: 'vm',`, instead of `mgmtController`.
   See examples in blueprint-composer, e.g. spec-editor.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r669411582



##########
File path: ui-modules/home/app/views/about/about.template.html
##########
@@ -54,29 +54,71 @@ <h4 class="list-group-item-heading">Brooklyn Server</h4>
                 </li>
             </ul>
 
-            <h2>HA status</h2>
-            <table class="table table-responsive table-bordered">
-                <thead>
-                <tr>
-                    <th class="server-status-node-id">Node ID</th>
-                    <th>Status</th>
-                </tr>
-                </thead>
-                <tbody>
-                <tr ng-repeat="node in vm.states.nodes track by node.nodeId"
-                    ng-class="{success: node.state === 'online', danger: node.state === 'offline'}">
-                    <td>
-                        {{node.nodeId}}
-                        <span ng-if="node.nodeId === vm.states.ownId" class="label label-info">current</span>
-                        <span ng-if="node.status === 'MASTER'" class="label label-success">master</span>
-                    </td>
-                    <td>
-                        <span class="text-left">{{node.status | lowercase}}</span>
-                        <a ng-if="node.state === 'online'" class="btn btn-xs btn-success pull-right" class="text-right" ng-class="{disabled: node.nodeUri === null}">Open</a>
-                    </td>
-                </tr>
-                </tbody>
-            </table>
+            <h2>
+                HA status
+                <button ng-if="vm.states.nodes[vm.states.ownId].status === 'MASTER'"
+                        ng-click="vm.removeAllTerminatedNodes()" class="btn btn-sm btn-default"
+                        style="float: right;">Remove terminated nodes</button>
+            </h2>
+
+            <ng-include src="vm.template"></ng-include>
+
+            <script type="text/ng-template" id="haStatusTemplate">
+
+                <table class="table table-responsive table-bordered table-hover">
+                    <thead>
+                    <tr>
+                        <th class="server-status-node-id">Node ID</th>
+                        <th>Information</th>
+                    </tr>
+                    </thead>
+                    <tbody>
+                    <tr ng-repeat="node in vm.states.nodes track by node.nodeId"
+                        ng-class="{success: node.state === 'online', danger: node.state === 'offline'}"
+                        ng-mouseover="row = $index" ng-mouseleave="row = -1">
+                        <td>
+                            {{node.nodeId}}
+                            <button class="btn btn-sm btn-default" style="float: right;"
+                                    ng-if="node.nodeId === vm.states.ownId"
+                                    ng-click="vm.openDialog(vm.states, vm.states.ownId, vm.serverApi, vm.container)"
+                                    ng-show="row == $index">Manage</button>
+                            <button class="btn btn-sm btn-default" style="float: right;"
+                                    ng-if="(node.status === 'TERMINATED') && (vm.states.nodes[vm.states.ownId].status === 'MASTER')"
+                                    ng-click="vm.removeNode(node.nodeId)" ng-show="row == $index">Remove</button>
+                            <span ng-if="node.nodeId === vm.states.ownId" class="label label-info">current</span>
+                            <span ng-if="node.status === 'MASTER'" class="label label-success">master</span><br>
+                        </td>
+                        <td>
+                            <span class="text-left">Status: {{node.status | lowercase}}</span><br>
+                            <span class="text-left">Last active: {{node.remoteTimestamp | timeAgoFilter}}</span><br>
+                            <span class="text-left">Priority: {{node.priority}}</span><br>
+                            <a ng-if="node.state === 'online'" class="btn btn-xs btn-success pull-right"
+                               class="text-right" ng-class="{disabled: node.nodeUri === null}">Open</a>
+                        </td>
+                    </tr>
+                    </tbody>
+                </table>
+            </script>
+
+            <script type="text/ng-template" id="spinnerTemplate">
+                <br-interstitial-spinner event-count="1" remove-after="0" max-wait="120000">
+                    <style>
+                        ${require('brooklyn-shared/partials/interstitial.less')}
+                    </style>
+
+                    <div class="spinner-area" style="height: 100px">
+                        <div class="spinner">
+                            <div class="svg-container">
+                                <svg viewBox="20 20 60 60">
+                                    <circle r="25" cx="50" cy="50" class="background"/>
+                                    <circle r="25" cx="50" cy="50" class="foreground"/>
+                                </svg>
+                            </div>
+                        </div>
+                    </div>
+                </br-interstitial-spinner>
+            </script>
+  
             <h2>Logbook</h2>
             <a class="btn btn-sm btn-default" href="#!/logbook"><i class="fa fa-eye"></i> Logbook</a>

Review comment:
       Please remove this old button and header. Logbook directive is at the bottom now.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r655133732



##########
File path: ui-modules/blueprint-composer/app/components/providers/blueprint-service.provider.js
##########
@@ -230,7 +230,7 @@ function BlueprintService($log, $q, $sce, paletteApi, iconGenerator, dslService,
     }
 
     function lookup(entity, id, any = false) {
-        if (entity._id === id) {
+        if ((entity._id === id) || (entity.id === id)) {

Review comment:
       Do we still need this? I thought we agreed to not engage public ID of the Entity (which is optional, can be null, and not unique) into lookup.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] jathanasiou commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
jathanasiou commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r669831667



##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -55,17 +61,141 @@ export function aboutStateConfig($stateProvider) {
     $stateProvider.state(aboutState);
 }
 
-export function aboutStateController($scope, brBrandInfo, version, states) {
+export function aboutStateController($scope, $element, $q, $uibModal, brBrandInfo, version, states, serverApi) {
     $scope.$emit(HIDE_INTERSTITIAL_SPINNER_EVENT);
     $scope.getBrandedText = brBrandInfo.getBrandedText;
-
     $scope.serverVersion = version.data;
-    this.states = states.data;
-    this.buildInfo = {
+    $scope.states = states.data;
+    $scope.buildInfo = {
         buildVersion: BUILD_VERSION,
         buildName: BUILD_NAME,
         buildBranch: BUILD_BRANCH,
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    $scope.container = $element[0];
+    $scope.now = Date.now();
+    $scope.expectedNodeCounter = Object.keys($scope.states.nodes).length;
+    $scope.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    $scope.openDialog = function (states, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', nodeManagementModalController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[states.ownId];
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    $scope.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    $scope.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementModalController($scope, $uibModalInstance, node) {
+
+        // newStatus and newPriority are required to belong to the instance of the modal
+        let vm = this;
+        vm.newPriority = node.priority;
+        vm.newStatus = node.status;
+        
+        $scope.node = node;
+        $scope.statuses = ["MASTER", "STANDBY", "HOT_STANDBY", "HOT_BACKUP"];
+        $scope.now = Date.now();
+        $scope.showEditOptions = false;
+
+        $scope.applyChangesAndQuit = function () {
+            let promiseList = [];
+            if ($scope.node.priority !== vm.newPriority) {
+                let result = serverApi.setHaPriority(vm.newPriority);
+                promiseList.push(result);
+            }
+            if ($scope.node.status !== vm.newStatus) {
+                let result = serverApi.setHaStatus(vm.newStatus);
+                promiseList.push(result);
+            }
+            $uibModalInstance.close(promiseList);
+
+        }
+
+        $scope.cancelAndQuit = function () {
+            vm.newPriority = $scope.node.priority;
+            vm.newStatus = $scope.node.status;
+            $uibModalInstance.dismiss();
+        }
+
+        $scope.doShowEditOptions = function () {
+            $scope.showEditOptions = true;
+        }
+
+    }
+
+    $scope.removeNode = function (nodeId) {
+        $scope.template = 'spinnerTemplate';
+        let removeNode = serverApi.removeHaTerminatedNode(nodeId);
+        removeNode.then(data => {
+            $scope.expectedNodeCounter--;
+            let event = new CustomEvent('update-states', {});
+            $scope.container.dispatchEvent(event);
+        });
+    }
+
+    $scope.removeAllTerminatedNodes = function () {
+        $scope.template = 'spinnerTemplate';
+        let removeNodes = serverApi.removeHaTerminatedNodes();
+        removeNodes.then(data => {
+            for (const node in $scope.states.nodes) {

Review comment:
       consider using `$scope.states.nodes.forEach(node => { logic here )` instead for a better syntax, if nodes are an array.




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r655132274



##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -67,4 +72,139 @@ export function aboutStateController($scope, brBrandInfo, version, states) {
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    this.container = $element[0];
+    this.now = Date.now();
+    this.expectedNodeCounter = Object.keys(this.states.nodes).length;
+    this.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    this.openDialog = function (states, nodeId, serverApi, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', 'serverApi', nodeManagementController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[nodeId];
+                    },
+                    serverApi: function () {
+                        return serverApi;
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    this.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    this.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementController($scope, $uibModalInstance, node, serverApi) {
+
+        this.node = node;

Review comment:
       I suggest to create reference variable for `this` to reference the instance of the controller.
   ```
   let mgmtController = this;
   mgmtController.node = node;
   // etc.
   ```
   
   So that it is clear what instance does `this` reference to:
   ```
   mgmtController.setHaStatus = function () {
       let result = serverApi.setHaStatus(this.newStatus);
       this.node.status = this.newStatus; // this is likely to be a reference to function() instance, not the controller.
       // or ?
       mgmtController.setHaStatus.node.status; // explicit reference to the controller instance.
   }
   ```




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r655132274



##########
File path: ui-modules/home/app/views/about/about.controller.js
##########
@@ -67,4 +72,139 @@ export function aboutStateController($scope, brBrandInfo, version, states) {
         buildCommitId: BUILD_COMMIT_ID,
         brooklynVersion: BROOKLYN_VERSION,
     };
+
+    this.container = $element[0];
+    this.now = Date.now();
+    this.expectedNodeCounter = Object.keys(this.states.nodes).length;
+    this.template = 'haStatusTemplate';
+
+    let modalInstance = null;
+
+    this.openDialog = function (states, nodeId, serverApi, container) {
+        if (!modalInstance) {
+            modalInstance = $uibModal.open({
+                template: nodeManagementTemplate,
+                controller: ['$scope', '$uibModalInstance', 'node', 'serverApi', nodeManagementController],
+                controllerAs: 'vm',
+                backdrop: 'static',
+                windowClass: 'quick-launch-modal',
+                size: 'md',
+                resolve: {
+                    node: function () {
+                        return states.nodes[nodeId];
+                    },
+                    serverApi: function () {
+                        return serverApi;
+                    }
+                }
+            });
+            modalInstance.result.then(
+                (promiseList) => {
+                    this.template = 'spinnerTemplate';
+                    Promise.allSettled(promiseList).then((values) => {
+                        let event = new CustomEvent('update-states', {});
+                        container.dispatchEvent(event);
+                    });
+                    modalInstance = null;
+                },
+                () => {
+                    this.template = 'spinnerTemplate';
+                    let event = new CustomEvent('update-states', {});
+                    container.dispatchEvent(event);
+                    modalInstance = null;
+                }
+            );
+        }
+
+    };
+
+    function nodeManagementController($scope, $uibModalInstance, node, serverApi) {
+
+        this.node = node;

Review comment:
       I suggest to create reference variable for `this` to reference the instance of the controller.
   ```
   let mgmtController = this;
   mgmtController.node = node;
   // etc.
   ```
   
   So that it is clear what instance does `this` reference to:
   ```
   mgmtController.setHaStatus = function () {
       let result = serverApi.setHaStatus(this.newStatus);
       this.node.status = this.newStatus; // this is likely to be a reference to function() instance, not the controller.
       // or ?
       mgmtController.node.status; // explicit reference to the controller instance.
   }
   ```




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] ahgittin commented on pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
ahgittin commented on pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#issuecomment-865234874


   can you merge master and resolve the conflicts?  (should be simple -- it's just around the recent logbook additions)


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

For queries about this service, please contact Infrastructure at:
users@infra.apache.org



[GitHub] [brooklyn-ui] algairim commented on a change in pull request #228: Feature/node management UI

Posted by GitBox <gi...@apache.org>.
algairim commented on a change in pull request #228:
URL: https://github.com/apache/brooklyn-ui/pull/228#discussion_r668936502



##########
File path: ui-modules/utils/api/brooklyn/server.js
##########
@@ -60,4 +65,50 @@ function ServerApi($http, $q, cache) {
     function getUpExtended(config) {
         return $http.get('/v1/server/up/extended', angular.extend({cache: cache}, config));
     }
+
+    function setHaStatus(state, config) {
+        return $http({
+            method: 'POST',
+            url: '/v1/server/ha/state',
+            data: 'mode=' + state,
+            headers: {
+                'Content-Type': 'application/x-www-form-urlencoded',
+                'Accept': 'application/json',
+                'Brooklyn-Allow-Non-Master-Access': 'true',
+            }
+
+        });
+    }
+
+    function setHaPriority(priority, config) {
+        return $http({
+            method: 'POST',
+            url: '/v1/server/ha/priority',
+            data: 'priority=' + priority,
+            headers: {
+                'Content-Type': 'application/x-www-form-urlencoded',
+                'Accept': 'application/json',
+                'Brooklyn-Allow-Non-Master-Access': 'true',
+            }
+
+        });
+    }
+
+    function removeHaTerminatedNodes(config){
+        return $http.post('/v1/server/ha/states/clear', angular.extend({cache: cache}, config));
+    }
+
+    function removeHaTerminatedNode(nodeId, config){

Review comment:
       `config` is not used




-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: dev-unsubscribe@brooklyn.apache.org

For queries about this service, please contact Infrastructure at:
users@infra.apache.org