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
1 change: 1 addition & 0 deletions .env
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
WEBUI_MULTIPLE=false
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
WEBUI_MULTIPLE=false
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,21 @@ Run `grunt` for building and `grunt serve` for preview.
## Testing

Running `grunt test` will run the unit tests with karma.

# Documentation

## Multipe WebUI

Change value in .env file

**Multiple account disabled:**

```
WEBUI_MULTIPLE=false
```

**Multipe account enabled:**

```
WEBUI_MULTIPLE=true
```
4 changes: 4 additions & 0 deletions app/index.ejs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
</span>
<span class="connected-status" ng-class="(isConnected()) ? 'label label-success' : 'label label-danger'"
ng-bind="isConnected() ? 'Connected' : 'Disconnected'"></span>
<web-ui-select class="hidden-xs"></web-ui-select>
</p>
</div>

Expand All @@ -56,6 +57,9 @@
<!-- Sidebar Menu Items - These collapse to the responsive navigation menu on small screens -->
<div class="collapse navbar-collapse navbar-ex1-collapse">
<ul class="nav navbar-nav side-nav">
<li class="visible-xs">
<web-ui-select></web-ui-select>
</li>
<li ui-sref-active="active">
<a data-toggle="collapse" data-target=".navbar-ex1-collapse" ui-sref="home"><i class="glyphicon glyphicon-cog"></i> Home</a>
</li>
Expand Down
3 changes: 3 additions & 0 deletions app/scripts/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ import routingModule from './app.routes';

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

//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -117,6 +118,7 @@ const module = angular
metaTypeFilterModule,
dumbTemplateModule,
LoginFormModule,
WebUIModule,
SvgEditorModule,

///'toggle-switch',
Expand Down Expand Up @@ -302,6 +304,7 @@ const realApp = angular.module('realHomeuiApp', [module.name, mqttServiceModule,
urlTemplate: '/scripts/i18n/{part}/{lang}.json'
});
$translateProvider.preferredLanguage('ru');
$translateProvider.usePostCompiling(true);
}])
.config(['$compileProvider', function ($compileProvider) {
$compileProvider.aHrefSanitizationWhitelist(/^\s*(https?|ftp|mailto|tel|file|blob):/);
Expand Down
7 changes: 7 additions & 0 deletions app/scripts/app.routes.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use strict';

import uiRouter from 'angular-ui-router';

import homeTemplateUrl from 'ngtemplate-loader?relativeTo=/app!../views/home.html';
Expand Down Expand Up @@ -45,6 +47,11 @@ function routing($stateProvider, $locationProvider, $urlRouterProvider) {
templateUrl: webUITemplateUrl,
controller: 'WebUICtrl as $ctrl'
})
.state('webUIAdd', {
url: '/web-ui/add',
templateUrl: webUITemplateUrl,
controller: 'WebUICtrl as $ctrl'
})
.state('system', {
url: '/system',
templateUrl: systemTemplateUrl,
Expand Down
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

Check failure on line 9 in app/scripts/components/webUI/index.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app/scripts/components/webUI/index.js#L9

'angular' is not defined.
.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
};
76 changes: 76 additions & 0 deletions app/scripts/components/webUI/manage/webUIManage.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'use strict';

class WebUIManageController {

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

this.$scope = $scope;
this.$window = $window;
this.$state = $state;
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 === 'true';
if (!this.isMultiple) {
this.editable = this.current;
}
else if ($state.current.name === 'webUIAdd') {
this.create();
}

$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.cancel();
}
}

cancel() {
this.editable = null;

if (this.$state.current.name === 'webUIAdd') {
this.$state.go('webUI');
}
}

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

export default WebUIManageController;
100 changes: 100 additions & 0 deletions app/scripts/components/webUI/manage/webUIManage.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
<div class="web-ui-manage">
<div class="list" ng-show="!$ctrl.editable">
<div class="table-responsive">
<table class="table table-hover">
<thead class="hidden-xs">
<tr>
<th>{{'webUI.manager.table.header.name' | translate}}</th>
<th class="hidden-xs">{{'webUI.manager.table.header.host' | translate}}</th>
<th class="hidden-xs">{{'webUI.manager.table.header.port' | translate}}</th>
<th class="hidden-xs">{{'webUI.manager.table.header.user' | translate}}</th>
<th class="hidden-xs">{{'webUI.manager.table.header.prefix' | translate}}</th>
<th></th>
</tr>
</thead>
<tbody>
<tr ng-repeat="account in $ctrl.accounts track by $index">
<td class="visible-xs tap" ng-click="$ctrl.update(account)">{{ account.name }}</td>
<td class="hidden-xs">{{ account.name }}</td>
<td class="hidden-xs">{{ account.host }}</td>
<td class="hidden-xs">{{ account.port }}</td>
<td class="hidden-xs">{{ account.user }}</td>
<td class="hidden-xs" width="100"><i class="fa fa-check" ng-show="account.prefix"></i></td>
<td class="hidden-xs" width="200" class="text-right">
<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>
<td class="visible-xs text-right"><i class="fa fa-check" ng-show="account === $ctrl.current"></i></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" ng-class="{'has-error': account.name.$invalid, 'has-success': !account.name.$invalid && account.name.$touched}" ng-show="$ctrl.isMultiple">
<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" />
<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">
<div class="pull-left">
<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 class="pull-right">
<button class="btn btn-success" ng-click="$ctrl.login($ctrl.editable)" ng-if="$ctrl.isMultiple" ng-disabled="$ctrl.editable === $ctrl.current">{{'webUI.manager.button.login' | translate}}</button>
<button class="btn btn-danger" ng-click="$ctrl.remove($ctrl.editable)" ng-if="$ctrl.isMultiple">{{'webUI.manager.button.remove' | translate}}</button>
</div>
</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
};
57 changes: 57 additions & 0 deletions app/scripts/components/webUI/select/webUISelect.controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
'use strict';

class AccountSelectController {

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

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

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

this.accountAdd = {
'name': 'Add service'
};

this.isMultiple = process.env.WEBUI_MULTIPLE === 'true';

$scope.$watch('$ctrl.current', (newValue, oldValue) => {
if (newValue !== oldValue) {
if (oldValue === this.accountAdd) {
return;
}
else if (newValue === this.accountAdd) {
this.current = webUIService.current;
$state.go('webUIAdd');
}
else {
this.login(newValue);
}
}
});

this.$translate('webUI.select.button.add').then((translation) => {
this.accountAdd.name = translation;
});
}

items() {
return this.accounts.concat(this.accountAdd);
}

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

tagHelper(tag) {

Check failure on line 52 in app/scripts/components/webUI/select/webUISelect.controller.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app/scripts/components/webUI/select/webUISelect.controller.js#L52

'tag' is defined but never used.

Check failure on line 52 in app/scripts/components/webUI/select/webUISelect.controller.js

View check run for this annotation

Codacy Production / Codacy Static Code Analysis

app/scripts/components/webUI/select/webUISelect.controller.js#L52

'tag' is defined but never used.
return null;
}
}

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 ng-if="$ctrl.isMultiple" class="web-ui-select">
<ui-select ng-model="$ctrl.current" tagging="$ctrl.tagHandler" theme="bootstrap" title="{{'webUI.select.tip.account' | translate}}" append-to-body="false" search-enabled="false">
<ui-select-match placeholder="">{{ $select.selected.name }}</ui-select-match>
<ui-select-choices repeat="account in $ctrl.items() | filter: { name: $select.search }">
<div ng-bind-html="account.name"></div>
</ui-select-choices>
</ui-select>
</div>
Loading