Commit 72dfdd55 authored by Deng, Qian's avatar Deng, Qian
Browse files

Add ldap serach

1. Add group management
2. Add rewrite import user to member ui
3. Add import group to member
4. Add new items in configuration page
parent e705224b
......@@ -79,7 +79,7 @@ script:
- sudo mkdir -p /harbor
- sudo mv ./VERSION /harbor/UIVERSION
- sudo service postgresql stop
- sudo make run_clarity_ut CLARITYIMAGE=vmware/harbor-clarity-ui-builder:1.4.1
- sudo make run_clarity_ut CLARITYIMAGE=vmware/harbor-clarity-ui-builder:1.4.0
- cat ./src/ui_ng/npm-ut-test-results
- sudo ./tests/testprepare.sh
- sudo make -f make/photon/Makefile _build_db _build_registry -e VERSIONTAG=dev -e CLAIRDBVERSION=dev -e REGISTRYVERSION=v2.6.2
......@@ -105,7 +105,7 @@ script:
- sudo rm -rf /data/config/*
- sudo rm -rf /data/database/*
- ls /data/cert
- sudo make install GOBUILDIMAGE=golang:1.9.2 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:1.4.1 NOTARYFLAG=true CLAIRFLAG=true
- sudo make install GOBUILDIMAGE=golang:1.9.2 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:1.4.0 NOTARYFLAG=true CLAIRFLAG=true
- sleep 10
- docker ps
- ./tests/validatecontainers.sh
......
......@@ -50,19 +50,19 @@ You can compile the code by one of the three approaches:
* Build, install and bring up Harbor without Notary:
```sh
$ make install GOBUILDIMAGE=golang:1.9.2 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:1.4.1
$ make install GOBUILDIMAGE=golang:1.9.2 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:1.4.0
```
* Build, install and bring up Harbor with Notary:
```sh
$ make install GOBUILDIMAGE=golang:1.9.2 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:1.4.1 NOTARYFLAG=true
$ make install GOBUILDIMAGE=golang:1.9.2 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:1.4.0 NOTARYFLAG=true
```
* Build, install and bring up Harbor with Clair:
```sh
$ make install GOBUILDIMAGE=golang:1.9.2 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:1.4.1 CLAIRFLAG=true
$ make install GOBUILDIMAGE=golang:1.9.2 COMPILETAG=compile_golangimage CLARITYIMAGE=vmware/harbor-clarity-ui-builder:1.4.0 CLAIRFLAG=true
```
#### II. Compile code with your own Golang environment, then build Harbor
......
......@@ -34,7 +34,7 @@ sed -i 's/* as//g' src/app/shared/gauge/gauge.component.js
cp ./dist/build.min.js ../ui/static/
cp -r ./src/i18n/ ../ui/static/
cp ./src/styles.scss ../ui/static/
cp ./src/styles.css ../ui/static/
cp -r ./src/images/ ../ui/static/
cp ./src/setting.json ../ui/static/
......
......@@ -20,7 +20,7 @@
"styles": [
"../node_modules/clarity-icons/clarity-icons.min.css",
"../node_modules/clarity-ui/clarity-ui.min.css",
"styles.scss"
"styles.css"
],
"scripts": [
"../node_modules/core-js/client/shim.min.js",
......
......@@ -65,6 +65,10 @@ export class Configuration {
ldap_uid: StringValueItem;
ldap_url: StringValueItem;
ldap_verify_cert: BoolValueItem;
ldap_group_base_dn: StringValueItem;
ldap_group_search_filter: StringValueItem;
ldap_group_attribute_name: StringValueItem;
ldap_group_search_scope: NumberValueItem;
uaa_client_id: StringValueItem;
uaa_client_secret?: StringValueItem;
uaa_endpoint: StringValueItem;
......@@ -96,6 +100,10 @@ export class Configuration {
this.ldap_uid = new StringValueItem("", true);
this.ldap_url = new StringValueItem("", true);
this.ldap_verify_cert = new BoolValueItem(true, true);
this.ldap_group_base_dn = new StringValueItem("", true);
this.ldap_group_search_filter = new StringValueItem("", true);
this.ldap_group_attribute_name = new StringValueItem("", true);
this.ldap_group_search_scope = new NumberValueItem(0, true);
this.uaa_client_id = new StringValueItem("", true);
this.uaa_client_secret = new StringValueItem("", true);
this.uaa_endpoint = new StringValueItem("", true);
......
......@@ -4,6 +4,7 @@
*/
export class BatchInfo {
id?: number;
name: string;
status: string;
loading: boolean;
......@@ -17,11 +18,17 @@ export class BatchInfo {
}
}
export function BathInfoChanges(list: BatchInfo, status: string, loading = false, errStatus = false, errorInfo = '') {
list.status = status;
list.loading = loading;
list.errorState = errStatus;
list.errorInfo = errorInfo;
return list;
export function BathInfoChanges(batchInfo: BatchInfo, status: string, loading = false, errStatus = false, errorInfo = '') {
batchInfo.status = status;
batchInfo.loading = loading;
batchInfo.errorState = errStatus;
batchInfo.errorInfo = errorInfo;
return batchInfo;
}
export enum BatchOperations {
Idle,
Delete,
ChangeRole
}
......@@ -48,7 +48,9 @@ export function getCurrentLanguage(translateService: TranslateService) {
BaseModule,
AccountModule,
HarborRoutingModule,
ConfigurationModule,
ConfigurationModule
],
exports: [
],
providers: [
AppConfigService,
......
......@@ -19,6 +19,7 @@ import { ProjectModule } from '../project/project.module';
import { UserModule } from '../user/user.module';
import { AccountModule } from '../account/account.module';
import { RepositoryModule } from '../repository/repository.module';
import { GroupModule } from '../group/group.module';
import { NavigatorComponent } from './navigator/navigator.component';
import { GlobalSearchComponent } from './global-search/global-search.component';
......@@ -36,7 +37,8 @@ import { SearchTriggerService } from './global-search/search-trigger.service';
UserModule,
AccountModule,
RouterModule,
RepositoryModule
RepositoryModule,
GroupModule
],
declarations: [
NavigatorComponent,
......
......@@ -28,6 +28,13 @@
<clr-icon shape="users" clrVerticalNavIcon></clr-icon>
{{'SIDE_NAV.SYSTEM_MGMT.USER' | translate}}
</a>
<a *ngIf='isLdapMode'
clrVerticalNavLink
routerLink="/harbor/groups"
routerLinkActive="active">
<clr-icon shape="users" clrVerticalNavIcon></clr-icon>
{{'SIDE_NAV.SYSTEM_MGMT.GROUP' | translate}}
</a>
<a clrVerticalNavLink
routerLink="/harbor/registries"
routerLinkActive="active">
......
......@@ -13,6 +13,8 @@
// limitations under the License.
import { Component, OnInit, ViewChild, OnDestroy } from '@angular/core';
import { Router, ActivatedRoute } from '@angular/router';
import { Subscription } from 'rxjs/Subscription';
import { AppConfigService } from '../..//app-config.service';
import { ModalEvent } from '../modal-event';
import { modalEvents } from '../modal-events.const';
......@@ -23,11 +25,7 @@ import { NavigatorComponent } from '../navigator/navigator.component';
import { SessionService } from '../../shared/session.service';
import { AboutDialogComponent } from '../../shared/about-dialog/about-dialog.component';
import { SearchTriggerService } from '../global-search/search-trigger.service';
import { Subscription } from 'rxjs/Subscription';
import { CommonRoutes } from '../../shared/shared.const';
@Component({
......@@ -61,7 +59,8 @@ export class HarborShellComponent implements OnInit, OnDestroy {
private route: ActivatedRoute,
private router: Router,
private session: SessionService,
private searchTrigger: SearchTriggerService) { }
private searchTrigger: SearchTriggerService,
private appConfigService: AppConfigService) { }
ngOnInit() {
this.searchSub = this.searchTrigger.searchTriggerChan$.subscribe(searchEvt => {
......@@ -98,6 +97,11 @@ export class HarborShellComponent implements OnInit, OnDestroy {
return account != null && account.has_admin_role;
}
public get isLdapMode(): boolean {
let appConfig = this.appConfigService.getConfig();
return appConfig.auth_mode === 'ldap_auth';
}
public get isUserExisting(): boolean {
let account = this.session.getCurrentUser();
return account != null;
......
......@@ -19,50 +19,44 @@
<section class="form-block" *ngIf="showUAA">
<div class="form-group">
<label for="uaa-endpoint" class="required">{{'CONFIG.UAA.ENDPOINT' | translate}}</label>
<input type="text" id="uaa-endpoint" name="uaa-endpoint" size="35"
[(ngModel)]="currentConfig.uaa_endpoint.value" [disabled]="!currentConfig.uaa_verify_cert.editable">
<input type="text" id="uaa-endpoint" name="uaa-endpoint" size="35" [(ngModel)]="currentConfig.uaa_endpoint.value" [disabled]="!currentConfig.uaa_verify_cert.editable">
</div>
<div class="form-group">
<label for="uaa-id" class="required">{{'CONFIG.UAA.CLIENT_ID' | translate}}</label>
<input type="text" id="uaa-cid" name="uaa-client-id" size="35"
[(ngModel)]="currentConfig.uaa_client_id.value" [disabled]="!currentConfig.uaa_verify_cert.editable">
<input type="text" id="uaa-cid" name="uaa-client-id" size="35" [(ngModel)]="currentConfig.uaa_client_id.value" [disabled]="!currentConfig.uaa_verify_cert.editable">
</div>
<div class="form-group">
<label for="uaa-id" class="required">{{'CONFIG.UAA.CLIENT_SECRET' | translate}}</label>
<input type="text" id="uaa-secret" name="uaa-client-secret" type="password" size="35"
[(ngModel)]="currentConfig.uaa_client_secret.value" [disabled]="!currentConfig.uaa_verify_cert.editable">
<input type="text" id="uaa-secret" name="uaa-client-secret" type="password" size="35" [(ngModel)]="currentConfig.uaa_client_secret.value"
[disabled]="!currentConfig.uaa_verify_cert.editable">
</div>
<div class="form-group">
<label for="uaa-cert" class="required">{{'CONFIG.UAA.VERIFY_CERT' | translate}}</label>
<clr-checkbox id="uaa-cert" name="uaa-cert" [(clrChecked)]="currentConfig.uaa_verify_cert.value"
[clrDisabled]="!currentConfig.uaa_verify_cert.editable"></clr-checkbox>
<clr-checkbox id="uaa-cert" name="uaa-cert" [(clrChecked)]="currentConfig.uaa_verify_cert.value" [clrDisabled]="!currentConfig.uaa_verify_cert.editable"></clr-checkbox>
</div>
</section>
<section class="form-block" *ngIf="showLdap">
<div class="form-group">
<label for="ldapUrl" class="required">{{'CONFIG.LDAP.URL' | translate}}</label>
<label for="ldapUrl" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-lg tooltip-top-right" [class.invalid]="ldapUrlInput.invalid && (ldapUrlInput.dirty || ldapUrlInput.touched)">
<input name="ldapUrl" type="text" #ldapUrlInput="ngModel" [(ngModel)]="currentConfig.ldap_url.value"
required
id="ldapUrl"
size="40"
[disabled]="disabled(currentConfig.ldap_url)">
<span class="tooltip-content">
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
</span>
</label>
<label for="ldapUrl" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-lg tooltip-top-right"
[class.invalid]="ldapUrlInput.invalid && (ldapUrlInput.dirty || ldapUrlInput.touched)">
<input name="ldapUrl" type="text" #ldapUrlInput="ngModel" [(ngModel)]="currentConfig.ldap_url.value" required id="ldapUrl"
size="40" [disabled]="disabled(currentConfig.ldap_url)">
<span class="tooltip-content">
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
</span>
</label>
</div>
<div class="form-group">
<label for="ldapSearchDN">{{'CONFIG.LDAP.SEARCH_DN' | translate}}</label>
<label for="ldapSearchDN" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-lg tooltip-top-right">
<input name="ldapSearchDN" type="text" #ldapSearchDNInput="ngModel" [(ngModel)]="currentConfig.ldap_search_dn.value"
id="ldapSearchDN"
size="40" [disabled]="disabled(currentConfig.ldap_search_dn)">
<span class="tooltip-content">
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
</span>
</label>
<input name="ldapSearchDN" type="text" #ldapSearchDNInput="ngModel" [(ngModel)]="currentConfig.ldap_search_dn.value" id="ldapSearchDN"
size="40" [disabled]="disabled(currentConfig.ldap_search_dn)">
<span class="tooltip-content">
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
</span>
</label>
<a href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-lg tooltip-top-right" style="top:-1px;">
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
<span class="tooltip-content">{{'CONFIG.TOOLTIP.LDAP_SEARCH_DN' | translate}}</span>
......@@ -71,25 +65,23 @@
<div class="form-group">
<label for="ldapSearchPwd">{{'CONFIG.LDAP.SEARCH_PWD' | translate}}</label>
<label for="ldapSearchPwd" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-lg tooltip-top-right">
<input name="ldapSearchPwd" type="password" #ldapSearchPwdInput="ngModel" [(ngModel)]="currentConfig.ldap_search_password.value"
id="ldapSearchPwd"
size="40" [disabled]="disabled(currentConfig.ldap_search_password)">
<span class="tooltip-content">
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
</span>
</label>
<input name="ldapSearchPwd" type="password" #ldapSearchPwdInput="ngModel" [(ngModel)]="currentConfig.ldap_search_password.value"
id="ldapSearchPwd" size="40" [disabled]="disabled(currentConfig.ldap_search_password)">
<span class="tooltip-content">
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
</span>
</label>
</div>
<div class="form-group">
<label for="ldapBaseDN" class="required">{{'CONFIG.LDAP.BASE_DN' | translate}}</label>
<label for="ldapBaseDN" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-lg tooltip-top-right" [class.invalid]="ldapBaseDNInput.invalid && (ldapBaseDNInput.dirty || ldapBaseDNInput.touched)">
<input name="ldapBaseDN" type="text" #ldapBaseDNInput="ngModel" [(ngModel)]="currentConfig.ldap_base_dn.value"
required
id="ldapBaseDN"
size="40" [disabled]="disabled(currentConfig.ldap_base_dn)">
<span class="tooltip-content">
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
</span>
</label>
<label for="ldapBaseDN" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-lg tooltip-top-right"
[class.invalid]="ldapBaseDNInput.invalid && (ldapBaseDNInput.dirty || ldapBaseDNInput.touched)">
<input name="ldapBaseDN" type="text" #ldapBaseDNInput="ngModel" [(ngModel)]="currentConfig.ldap_base_dn.value" required id="ldapBaseDN"
size="40" [disabled]="disabled(currentConfig.ldap_base_dn)">
<span class="tooltip-content">
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
</span>
</label>
<a href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-top-right" style="top: -1px;">
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
<span class="tooltip-content">{{'CONFIG.TOOLTIP.LDAP_BASE_DN' | translate}}</span>
......@@ -98,25 +90,23 @@
<div class="form-group">
<label for="ldapFilter">{{'CONFIG.LDAP.FILTER' | translate}}</label>
<label for="ldapFilter" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-lg tooltip-top-right">
<input name="ldapFilter" type="text" #ldapFilterInput="ngModel" [(ngModel)]="currentConfig.ldap_filter.value"
id="ldapFilter"
size="40" [disabled]="disabled(currentConfig.ldap_filter)">
<span class="tooltip-content">
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
</span>
</label>
<input name="ldapFilter" type="text" #ldapFilterInput="ngModel" [(ngModel)]="currentConfig.ldap_filter.value" id="ldapFilter"
size="40" [disabled]="disabled(currentConfig.ldap_filter)">
<span class="tooltip-content">
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
</span>
</label>
</div>
<div class="form-group">
<label for="ldapUid" class="required">{{'CONFIG.LDAP.UID' | translate}}</label>
<label for="ldapUid" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-lg tooltip-top-right" [class.invalid]="ldapUidInput.invalid && (ldapUidInput.dirty || ldapUidInput.touched)">
<input name="ldapUid" type="text" #ldapUidInput="ngModel" [(ngModel)]="currentConfig.ldap_uid.value"
required
id="ldapUid"
size="40" [disabled]="disabled(currentConfig.ldap_uid)">
<span class="tooltip-content">
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
</span>
</label>
<label for="ldapUid" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-lg tooltip-top-right"
[class.invalid]="ldapUidInput.invalid && (ldapUidInput.dirty || ldapUidInput.touched)">
<input name="ldapUid" type="text" #ldapUidInput="ngModel" [(ngModel)]="currentConfig.ldap_uid.value" required id="ldapUid"
size="40" [disabled]="disabled(currentConfig.ldap_uid)">
<span class="tooltip-content">
{{'TOOLTIP.ITEM_REQUIRED' | translate}}
</span>
</label>
<a href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-lg tooltip-top-right" style="top: -1px;">
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
<span class="tooltip-content">{{'CONFIG.TOOLTIP.LDAP_UID' | translate}}</span>
......@@ -138,13 +128,72 @@
</div>
<div class="form-group">
<label for="ldapVerifyCert">{{'CONFIG.LDAP.VERIFY_CERT' | translate}}</label>
<clr-checkbox name="ldapVerifyCert" id="ldapVerifyCert" [clrChecked]="currentConfig.ldap_verify_cert.value" [clrDisabled]="disabled(currentConfig.ldap_scope)" (clrCheckedChange)="setVerifyCertValue($event)">
<clr-checkbox name="ldapVerifyCert" id="ldapVerifyCert" [clrChecked]="currentConfig.ldap_verify_cert.value" [clrDisabled]="disabled(currentConfig.ldap_scope)"
(clrCheckedChange)="setVerifyCertValue($event)">
<a href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-top-right" style="top:-7px;">
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
<span class="tooltip-content">{{'CONFIG.TOOLTIP.VERIFY_CERT' | translate}}</span>
</a>
</clr-checkbox>
</div>
<div class="form-group">
<label for="ldapGroupBaseDN" class="required">{{'CONFIG.LDAP.LDAP_GROUP_BASE_DN' | translate}}</label>
<label for="ldapGroupBaseDN" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-lg tooltip-top-right">
<input name="ldapGroupBaseDN" type="text" #ldapGroupDNInput="ngModel" [(ngModel)]="currentConfig.ldap_group_base_dn.value"
id="ldapGroupBaseDN" size="40" [disabled]="disabled(currentConfig.ldap_group_base_dn)">
<span class="tooltip-content"> {{'TOOLTIP.ITEM_REQUIRED' | translate}} </span>
</label>
<clr-tooltip>
<clr-icon clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
<clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>
<span>{{'CONFIG.LDAP.LDAP_GROUP_BASE_DN_INFO' | translate}}</span>
</clr-tooltip-content>
</clr-tooltip>
</div>
<div class="form-group">
<label for="ldapGroupFilter" class="required">{{'CONFIG.LDAP.LDAP_GROUP_FILTER' | translate}}</label>
<label for="ldapGroupFilter" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-lg tooltip-top-right">
<input name="ldapGroupFilter" type="text" #ldapGroupFilterInput="ngModel" [(ngModel)]="currentConfig.ldap_group_search_filter.value"
id="ldapGroupFilter" size="40" [disabled]="disabled(currentConfig.ldap_group_search_filter)">
<span class="tooltip-content"> {{'TOOLTIP.ITEM_REQUIRED' | translate}} </span>
</label>
<clr-tooltip>
<clr-icon clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
<clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>
<span>{{'CONFIG.LDAP.LDAP_GROUP_FILTER_INFO' | translate}}</span>
</clr-tooltip-content>
</clr-tooltip>
</div>
<div class="form-group">
<label for="ldapGroupGID" class="required">{{'CONFIG.LDAP.LDAP_GROUP_GID' | translate}}</label>
<label for="ldapGroupGID" aria-haspopup="true" role="tooltip" class="tooltip tooltip-validation tooltip-lg tooltip-top-right">
<input name="ldapGroupGID" type="text" #ldapGroupDNInput="ngModel" [(ngModel)]="currentConfig.ldap_group_attribute_name.value"
id="ldapGroupGID" size="40" [disabled]="disabled(currentConfig.ldap_group_attribute_name)">
<span class="tooltip-content"> {{'TOOLTIP.ITEM_REQUIRED' | translate}} </span>
</label>
<clr-tooltip>
<clr-icon clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
<clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>
<span>{{'CONFIG.LDAP.LDAP_GROUP_GID_INFO' | translate}}</span>
</clr-tooltip-content>
</clr-tooltip>
</div>
<div class="form-group">
<label for="ldapGroupScope">{{'CONFIG.LDAP.GROUP_SCOPE' | translate}}</label>
<div class="select">
<select id="ldapGroupScope" name="ldapGroupScope" [(ngModel)]="currentConfig.ldap_group_search_scope.value" [disabled]="disabled(currentConfig.ldap_group_search_scope)">
<option value="0">{{'CONFIG.SCOPE_BASE' | translate }}</option>
<option value="1">{{'CONFIG.SCOPE_ONE_LEVEL' | translate }}</option>
<option value="2">{{'CONFIG.SCOPE_SUBTREE' | translate }}</option>
</select>
</div>
<clr-tooltip>
<clr-icon clrTooltipTrigger shape="info-circle" size="24"></clr-icon>
<clr-tooltip-content clrPosition="top-right" clrSize="lg" *clrIfOpen>
<span>{{'CONFIG.LDAP.GROUP_SCOPE_INFO' | translate}}</span>
</clr-tooltip-content>
</clr-tooltip>
</div>
</section>
<section class="form-block">
<div class="form-group">
......@@ -165,8 +214,10 @@
<clr-checkbox name="selfReg" id="selfReg" [(ngModel)]="currentConfig.self_registration.value" [disabled]="disabled(currentConfig.self_registration)">
<a href="javascript:void(0)" role="tooltip" aria-haspopup="true" class="tooltip tooltip-top-right" style="top:-7px;">
<clr-icon shape="info-circle" class="info-tips-icon" size="24"></clr-icon>
<span *ngIf="checkable; else elseBlock" class="tooltip-content">{{'CONFIG.TOOLTIP.SELF_REGISTRATION_ENABLE' | translate}}</span>
<ng-template #elseBlock><span class="tooltip-content">{{'CONFIG.TOOLTIP.SELF_REGISTRATION_DISABLE' | translate}}</span></ng-template>
<span *ngIf="checkable; else elseBlock" class="tooltip-content">{{'CONFIG.TOOLTIP.SELF_REGISTRATION_ENABLE' | translate}}</span>
<ng-template #elseBlock>
<span class="tooltip-content">{{'CONFIG.TOOLTIP.SELF_REGISTRATION_DISABLE' | translate}}</span>
</ng-template>
</a>
</clr-checkbox>
</div>
......
clr-tooltip {
top: -1px;
}
\ No newline at end of file
......@@ -371,7 +371,7 @@ export class ConfigurationComponent implements OnInit, OnDestroy {
.catch(error => {
this.testingLDAPOnGoing = false;
let err = error._body;
if (!err) {
if (!err || !err.trim()) {
err = 'UNKNOWN';
}
this.msgHandler.showError('CONFIG.TEST_LDAP_FAILED', { 'param': err });
......
<clr-modal [(clrModalOpen)]="opened" [clrModalStaticBackdrop]="true" [clrModalClosable]="false">
<h3 class="modal-title" *ngIf="mode === 'create'">{{'GROUP.IMPORT_LDAP_GROUP' | translate}}</h3>
<h3 class="modal-title" *ngIf="mode !== 'create'">{{'GROUP.EDIT' | translate}}</h3>
<div class="modal-body">
<form class="form" #groupForm="ngForm">
<section class="form-block">
<div class="form-group">
<label for="ldap_group_dn" class="required">{{ 'GROUP.GROUP_DN' | translate}}</label>
<label for="ldap_group_dn"
aria-haspopup="true"
role="tooltip"
class="tooltip tooltip-validation tooltip-sm tooltip-right"
[class.invalid]="isDNInvalid">
<input type="text" id="ldap_group_dn" name="ldap_group_dn"
required
[(ngModel)]="group.ldap_group_dn"
#groupDN="ngModel">
<span class="tooltip-content">
{{dnTooltip | translate}}
</span>
</label>
</div>
<div class="form-group">
<label for="type">{{'GROUP.TYPE' | translate}}</label>
<label id="type">LDAP</label>
</div>
<div class="form-group">
<label for="group_name">{{'GROUP.NAME' | translate}}</label>
<label for="group_name">
<input type="text" id="group_name" name="group_name"
[(ngModel)]="group.group_name"
#groupDN="ngModel">
</label>
</div>
</section>
</form>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-outline" (click)="close()">{{'BUTTON.CANCEL' | translate | translate}}</button>
<button type="button" class="btn btn-primary" [disabled]="!isFormValid" (click)="save()">{{'BUTTON.SAVE' | translate | translate}}</button>
</div>
</clr-modal>
\ No newline at end of file
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { AddGroupModalComponent } from './add-group-modal.component';
describe('AddGroupModalComponent', () => {
let component: AddGroupModalComponent;
let fixture: ComponentFixture<AddGroupModalComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ AddGroupModalComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(AddGroupModalComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Subscription } from 'rxjs/Subscription';
import { Component, OnInit, EventEmitter, Output, ChangeDetectorRef, OnDestroy, ViewChild } from "@angular/core";
import { NgForm } from "@angular/forms";
import "rxjs/add/operator/finally";
import { GroupService } from "../group.service";
import { MessageHandlerService } from "./../../shared/message-handler/message-handler.service";
import { SessionService } from "./../../shared/session.service";
import { UserGroup } from "./../group";
@Component({
selector: "hbr-add-group-modal",
templateUrl: "./add-group-modal.component.html",
styleUrls: ["./add-group-modal.component.scss"]
})
export class AddGroupModalComponent implements OnInit, OnDestroy {
opened = false;
mode = "create";
dnTooltip = 'TOOLTIP.ITEM_REQUIRED';
group: UserGroup = new UserGroup();
formChangeSubscription: Subscription;
@ViewChild('groupForm')
groupForm: NgForm;
submitted = false;
@Output() dataChange = new EventEmitter();
constructor(
private session: SessionService,
private msgHandler: MessageHandlerService,
private groupService: GroupService,
private cdr: ChangeDetectorRef
) {}
ngOnInit() { }
ngOnDestroy() { }
public get isDNInvalid(): boolean {
let dnControl = this.groupForm.controls['ldap_group_dn'];
return dnControl && dnControl.invalid && (dnControl.dirty || dnControl.touched);
}
public get isFormValid(): boolean {
return this.groupForm.valid;
}