Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Support Multiple WebUI #147

Draft
wants to merge 11 commits into
base: feature/v2_carbonfay_round1
Choose a base branch
from
Next Next commit
Feature: Support Multiple WebUI
olddeda committed Aug 29, 2019
commit 0fcc4a5be93359df875a3b6533e6d4040926d541
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
WEBUI_MULTIPLE=true
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
WEBUI_MULTIPLE=false
1 change: 1 addition & 0 deletions app/index.ejs
Original file line number Diff line number Diff line change
@@ -40,6 +40,7 @@
</span>
<span class="connected-status" ng-class="(isConnected()) ? 'label label-success' : 'label label-danger'"
ng-bind="isConnected() ? 'Connected' : 'Disconnected'"></span>
<web-ui-select></web-ui-select>
</p>
</div>

6 changes: 5 additions & 1 deletion app/scripts/app.js
Original file line number Diff line number Diff line change
@@ -84,6 +84,7 @@ import routingModule from './app.routes';

// Internal components
import LoginFormModule from './components/loginForm/index';
import WebUIModule from './components/webUI/index';

//-----------------------------------------------------------------------------
/**
@@ -114,11 +115,13 @@ const module = angular
metaTypeFilterModule,
dumbTemplateModule,
LoginFormModule,
WebUIModule,

///'toggle-switch',
'plotly',
'ui-rangeSlider',
'ngToast'
'ngToast',
'ngBootbox',
])
.value('historyMaxPoints', 1000)
.value('webuiConfigPath', '/etc/wb-webui.conf')
@@ -297,6 +300,7 @@ const realApp = angular.module('realHomeuiApp', [module.name, mqttServiceModule,
urlTemplate: '/scripts/i18n/{part}/{lang}.json'
});
$translateProvider.preferredLanguage('ru');
$translateProvider.usePostCompiling(true);
}])
.run(($rootScope, $window, mqttClient, ConfigEditorProxy, webuiConfigPath, errors, whenMqttReady,
uiConfig, $timeout, configSaveDebounceMs, ngToast, $sce) => {
17 changes: 17 additions & 0 deletions app/scripts/components/webUI/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
'use strict';

import webUIManageComponent from './manage/webUIManage.component';
import webUISelectComponent from './select/webUISelect.component';
import webUIService from './services/webUI.service';

import './webUI.scss';

export default angular
.module('HomeuiApp.webUI', [])
.config(['$translatePartialLoaderProvider', ($translatePartialLoaderProvider) => {
$translatePartialLoaderProvider.addPart('webUI');
}])
.component('webUiManage', webUIManageComponent)
.component('webUiSelect', webUISelectComponent)
.factory('webUIService', webUIService)
.name;
12 changes: 12 additions & 0 deletions app/scripts/components/webUI/manage/webUIManage.component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict';

import template from './webUIManage.html';
import controller from './webUIManage.controller';

export default {
restrict: 'E',
bindings: {
},
template,
controller
};
68 changes: 68 additions & 0 deletions app/scripts/components/webUI/manage/webUIManage.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
'use strict';

class WebUIManageController {

constructor ($scope, $window, $translate, $ngBootbox, rolesFactory, webUIService) {
'ngInject';

this.$scope = $scope;
this.$window = $window;
this.$translate = $translate;
this.$ngBootbox = $ngBootbox;
this.rolesFactory = rolesFactory;
this.service = webUIService;

this.accounts = webUIService.accounts;
this.current = webUIService.current;
this.editable = null;

this.isMultiple = process.env.WEBUI_MULTIPLE;
if (!this.isMultiple) {
this.editable = this.current;
}

$scope.$watch('$ctrl.service.getCurrent()', (newValue, oldValue) => {
if (newValue !== oldValue) {
this.current = newValue;
}
});
}

create() {
this.editable = this.service.create();
}

update(account) {
this.editable = account;
}

remove(account) {
this.$translate('webUI.manager.prompt.remove', { name: account.name }).then((translation) => {
this.$ngBootbox.confirm(translation).then(() => {
this.service.remove(account);
});
});
}

save() {
this.service.save(this.editable);

if (this.editable === this.current) {
this.login(this.current);
}

if (this.isMultiple) {
this.editable = false;
}
}

cancel() {
this.editable = null;
}

login(account) {
this.service.login(account);
}
}

export default WebUIManageController;
91 changes: 91 additions & 0 deletions app/scripts/components/webUI/manage/webUIManage.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
<div class="web-ui-manage">
<div class="list" ng-show="!$ctrl.editable">
<div class="table-responsive">
<table class="table table-hover">
<thead>
<tr>
<th>{{'webUI.manager.table.header.name' | translate}}</th>
<th>{{'webUI.manager.table.header.host' | translate}}</th>
<th>{{'webUI.manager.table.header.port' | translate}}</th>
<th>{{'webUI.manager.table.header.user' | translate}}</th>
<th>{{'webUI.manager.table.header.prefix' | translate}}</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="account in $ctrl.accounts track by $index">
<td>{{ account.name }}</td>
<td>{{ account.host }}</td>
<td>{{ account.port }}</td>
<td>{{ account.user }}</td>
<td width="100"><i class="fa fa-check" ng-show="account.prefix"></i></td>
<td width="200" class="text-center">
<button class="btn btn-sm btn-primary" ng-click="$ctrl.update(account)">{{'webUI.manager.button.edit' | translate}}</button>
<button class="btn btn-sm btn-success"
ng-click="$ctrl.login(account)"
ng-disabled="account === $ctrl.current">{{'webUI.manager.button.login' | translate}}</button>
<button
class="btn btn-sm btn-danger"
ng-click="$ctrl.remove(account)"
>{{'webUI.manager.button.remove' | translate}}</button>
</td>
</tr>
</tbody>
</table>
</div>

<div>
<button class="btn btn-primary" ng-click="$ctrl.create()">{{'webUI.manager.button.add' | translate}}</button>
</div>
</div>
<div class="edit" ng-if="$ctrl.editable">
<form name="account" novalidate autocomplete="off">
<div class="form-group">
<div class="form-group required" ng-class="{'has-error': account.name.$invalid, 'has-success': !account.name.$invalid && account.name.$touched}">
<label for="host" class="control-label">{{'webUI.manager.field.name' | translate}}</label>
<input type="text" class="form-control" id="name" name="name" ng-model="$ctrl.editable.name" ng-required="account.name.$touched" />
<div class="help-block with-errors" ng-show="account.name.$error.required">{{'webUI.manager.error.name.empty' | translate}}</div>
</div>
<div class="form-group required" ng-class="{'has-error': account.host.$invalid, 'has-success': !account.host.$invalid && account.host.$touched}">
<label for="host" class="control-label">{{'webUI.manager.field.host' | translate}}</label>
<input type="text" class="form-control" id="host" name="host" ng-model="$ctrl.editable.host" ng-required="account.host.$touched" />
<div class="help-block with-errors" ng-show="account.host.$error.required">{{'webUI.manager.error.host.empty' | translate}}</div>
</div>
<div class="form-group required" ng-class="{'has-error': account.port.$invalid, 'has-success': !account.port.$invalid && account.port.$touched}">
<label for="port" class="control-label">{{'webUI.manager.field.port' | translate}}</label>
<input type="number" maxlength="5" class="form-control" id="port" name="port" ng-model="$ctrl.editable.port" ng-required="account.port.$touched" />
<div class="help-block with-errors" ng-show="account.port.$error.required">{{'webUI.manager.error.port.empty' | translate}}</div>
<div class="help-block with-errors" ng-show="account.port.$error.number">{{'webUI.manager.error.port.invalid' | translate}}</div>
</div>
<div class="form-group">
<label for="credentials" class="control-label">
<input type="checkbox" id="credentials" name="credentials" ng-model="$ctrl.editable.credentials" />
{{'webUI.manager.field.credentials' | translate}}
</label>
</div>
<div ng-show="$ctrl.editable.credentials">
<div class="form-group" ng-class="{'required': $ctrl.editable.credentials, 'has-error': account.user.$invalid, 'has-success': !account.user.$invalid && account.user.$touched}">
<label for="host" class="control-label">{{'webUI.manager.field.user' | translate}}</label>
<input type="text" class="form-control" id="user" name="user" autocomplete="off" ng-model="$ctrl.editable.user" ng-required="$ctrl.editable.credentials && account.user.$touched" />
<div class="help-block with-errors" ng-show="account.user.$error.required">{{'webUI.manager.error.user.empty' | translate}}</div>
</div>
<div class="form-group" ng-class="{'required': $ctrl.editable.credentials, 'has-error': account.password.$invalid, 'has-success': !account.password.$invalid && account.password.$touched}">
<label for="password" class="control-label">{{'webUI.manager.field.password' | translate}}</label>
<input type="password" class="form-control" id="password" name="password" autocomplete="new-password" ng-model="$ctrl.editable.password" ng-required="$ctrl.editable.credentials && account.password.$touched" />
<div class="help-block with-errors" ng-show="account.password.$error.required">{{'webUI.manager.error.password.empty' | translate}}</div>
</div>
</div>
<div class="form-group">
<label for="prefix" class="control-label">
<input type="checkbox" id="prefix" name="prefix" ng-model="$ctrl.editable.prefix" />
{{'webUI.manager.field.prefix' | translate}}
</label>
</div>
</div>
</form>
<div class="form-group">
<button class="btn btn-primary" ng-click="$ctrl.save()">{{'webUI.manager.button.save' | translate}}</button>
<button class="btn btn-default" ng-click="$ctrl.cancel()" ng-if="$ctrl.isMultiple">{{'webUI.manager.button.cancel' | translate}}</button>
</div>
</div>
</div>
12 changes: 12 additions & 0 deletions app/scripts/components/webUI/select/webUISelect.component.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
'use strict';

import template from './webUISelect.html';
import controller from './webUISelect.controller';

export default {
restrict: 'E',
bindings: {
},
template,
controller
};
28 changes: 28 additions & 0 deletions app/scripts/components/webUI/select/webUISelect.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use strict';

class AccountSelectController {

constructor ($scope, $element, rolesFactory, webUIService) {
'ngInject';

this.$scope = $scope;
this.$element = $element;
this.rolesFactory = rolesFactory;
this.service = webUIService;

this.accounts = webUIService.accounts;
this.current = webUIService.current;

$scope.$watch('$ctrl.current', (newValue, oldValue) => {
if (newValue !== oldValue) {
this.login(newValue);
}
});
}

login(account) {
this.service.login(account);
}
}

export default AccountSelectController;
8 changes: 8 additions & 0 deletions app/scripts/components/webUI/select/webUISelect.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="web-ui-select">
<ui-select ng-model="$ctrl.current" theme="bootstrap" title="Choose a control" append-to-body="false" search-enabled="false">
<ui-select-match placeholder="">{{ $select.selected.name }}</ui-select-match>
<ui-select-choices repeat="account in $ctrl.accounts | filter: { name: $select.search }">
<div ng-bind-html="account.name | hilite: $select.search"></div>
</ui-select-choices>
</ui-select>
</div>
22 changes: 22 additions & 0 deletions app/scripts/components/webUI/services/webUI.account.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
'use strict';

class Account {

constructor(name, host, port, user, password, prefix, role, current = false) {
this.name = name;
this.host = host;
this.port = port ? parseInt(port) : null;
this.user = user;
this.password = password;
this.prefix = (typeof prefix === 'string') ? (prefix === 'true') : prefix;
this.role = role;
this.current = current;
this.credentials = this.useCredentials;
}

get useCredentials() {
return (!!this.user || (!!this.user && !!this.password));
}
}

export default Account;
Loading