import {
PerformanceCounterComponent
} from './ceph/performance-counter/performance-counter/performance-counter.component';
+import { RgwBucketListComponent } from './ceph/rgw/rgw-bucket-list/rgw-bucket-list.component';
import { RgwDaemonListComponent } from './ceph/rgw/rgw-daemon-list/rgw-daemon-list.component';
+import { RgwUserListComponent } from './ceph/rgw/rgw-user-list/rgw-user-list.component';
import { LoginComponent } from './core/auth/login/login.component';
import { NotFoundComponent } from './core/not-found/not-found.component';
import { AuthGuardService } from './shared/services/auth-guard.service';
{ path: 'login', component: LoginComponent },
{ path: 'hosts', component: HostsComponent, canActivate: [AuthGuardService] },
{
- path: 'rgw',
+ path: 'rgw/daemon',
component: RgwDaemonListComponent,
canActivate: [AuthGuardService]
},
+ {
+ path: 'rgw/user',
+ component: RgwUserListComponent,
+ canActivate: [AuthGuardService]
+ },
+ {
+ path: 'rgw/bucket',
+ component: RgwBucketListComponent,
+ canActivate: [AuthGuardService]
+ },
{ path: 'block/iscsi', component: IscsiComponent, canActivate: [AuthGuardService] },
{ path: 'block/rbd', component: RbdListComponent, canActivate: [AuthGuardService] },
{ path: 'rbd/add', component: RbdFormComponent, canActivate: [AuthGuardService] },
--- /dev/null
+<tabset *ngIf="selection.hasSingleSelection">
+ <tab i18n-heading heading="Details">
+ <div *ngIf="bucket">
+ <table class="table table-striped table-bordered">
+ <tbody>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Name</td>
+ <td class="col-sm-3">{{ bucket.bucket }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">ID</td>
+ <td>{{ bucket.id }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Owner</td>
+ <td>{{ bucket.owner }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Index type</td>
+ <td>{{ bucket.index_type }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Placement rule</td>
+ <td>{{ bucket.placement_rule }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Marker</td>
+ <td>{{ bucket.marker }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Maximum marker</td>
+ <td>{{ bucket.max_marker }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Version</td>
+ <td>{{ bucket.ver }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Master version</td>
+ <td>{{ bucket.master_ver }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Modification time</td>
+ <td>{{ bucket.mtime }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Zonegroup</td>
+ <td>{{ bucket.zonegroup }}</td>
+ </tr>
+ </tbody>
+ </table>
+
+ <!-- Bucket quota -->
+ <div *ngIf="bucket.bucket_quota">
+ <legend i18n>Bucket quota</legend>
+ <table class="table table-striped table-bordered">
+ <tbody>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Enabled</td>
+ <td class="col-sm-3">{{ bucket.bucket_quota.enabled ? "Yes" : "No" }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Maximum size</td>
+ <td *ngIf="bucket.bucket_quota.max_size <= -1"
+ i18n
+ class="col-sm-3">Unlimited</td>
+ <td *ngIf="bucket.bucket_quota.max_size > -1"
+ class="col-sm-3">
+ {{ bucket.bucket_quota.max_size | dimless }}
+ </td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Maximum objects</td>
+ <td *ngIf="bucket.bucket_quota.max_objects <= -1"
+ i18n
+ class="col-sm-3">Unlimited</td>
+ <td *ngIf="bucket.bucket_quota.max_objects > -1"
+ class="col-sm-3">
+ {{ bucket.bucket_quota.max_objects }}
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </tab>
+</tabset>
--- /dev/null
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TabsModule } from 'ngx-bootstrap/tabs';
+
+import { CdTableSelection } from '../../../shared/models/cd-table-selection';
+import { SharedModule } from '../../../shared/shared.module';
+import { RgwBucketDetailsComponent } from './rgw-bucket-details.component';
+
+describe('RgwBucketDetailsComponent', () => {
+ let component: RgwBucketDetailsComponent;
+ let fixture: ComponentFixture<RgwBucketDetailsComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ RgwBucketDetailsComponent ],
+ imports: [
+ SharedModule,
+ TabsModule.forRoot()
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RgwBucketDetailsComponent);
+ component = fixture.componentInstance;
+ component.selection = new CdTableSelection();
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
--- /dev/null
+import { Component, Input, OnChanges } from '@angular/core';
+
+import { CdTableSelection } from '../../../shared/models/cd-table-selection';
+
+@Component({
+ selector: 'cd-rgw-bucket-details',
+ templateUrl: './rgw-bucket-details.component.html',
+ styleUrls: ['./rgw-bucket-details.component.scss']
+})
+export class RgwBucketDetailsComponent implements OnChanges {
+ bucket: any;
+
+ @Input() selection: CdTableSelection;
+
+ constructor() {}
+
+ ngOnChanges() {
+ if (this.selection.hasSelection) {
+ this.bucket = this.selection.first();
+ }
+ }
+}
--- /dev/null
+<nav aria-label="breadcrumb">
+ <ol class="breadcrumb">
+ <li i18n
+ class="breadcrumb-item">Object Gateway</li>
+ <li i18n
+ class="breadcrumb-item active"
+ aria-current="page">Buckets</li>
+ </ol>
+</nav>
+<cd-table [data]="buckets"
+ [columns]="columns"
+ columnMode="flex"
+ selectionType="single"
+ (updateSelection)="updateSelection($event)"
+ identifier="bucket"
+ (fetchData)="getBucketList()"
+ #table>
+ <cd-rgw-bucket-details cdTableDetail
+ [selection]="selection">
+ </cd-rgw-bucket-details>
+</cd-table>
--- /dev/null
+import { HttpClientModule } from '@angular/common/http';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { RouterTestingModule } from '@angular/router/testing';
+
+import { BsDropdownModule } from 'ngx-bootstrap';
+import { TabsModule } from 'ngx-bootstrap/tabs';
+
+import { RgwBucketService } from '../../../shared/api/rgw-bucket.service';
+import { DataTableModule } from '../../../shared/datatable/datatable.module';
+import { SharedModule } from '../../../shared/shared.module';
+import { RgwBucketDetailsComponent } from '../rgw-bucket-details/rgw-bucket-details.component';
+import { RgwBucketListComponent } from './rgw-bucket-list.component';
+
+describe('RgwBucketListComponent', () => {
+ let component: RgwBucketListComponent;
+ let fixture: ComponentFixture<RgwBucketListComponent>;
+
+ const fakeService = {
+ list: () => {
+ return new Promise(function(resolve, reject) {
+ return [];
+ });
+ }
+ };
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ RgwBucketListComponent,
+ RgwBucketDetailsComponent
+ ],
+ imports: [
+ HttpClientModule,
+ RouterTestingModule,
+ BsDropdownModule.forRoot(),
+ TabsModule.forRoot(),
+ DataTableModule,
+ SharedModule
+ ],
+ providers: [{ provide: RgwBucketService, useValue: fakeService }]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RgwBucketListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
--- /dev/null
+import { Component, ViewChild } from '@angular/core';
+
+import { RgwBucketService } from '../../../shared/api/rgw-bucket.service';
+import { TableComponent } from '../../../shared/datatable/table/table.component';
+import { CdTableColumn } from '../../../shared/models/cd-table-column';
+import { CdTableSelection } from '../../../shared/models/cd-table-selection';
+
+@Component({
+ selector: 'cd-rgw-bucket-list',
+ templateUrl: './rgw-bucket-list.component.html',
+ styleUrls: ['./rgw-bucket-list.component.scss']
+})
+export class RgwBucketListComponent {
+ @ViewChild('table') table: TableComponent;
+
+ columns: CdTableColumn[] = [];
+ buckets: object[] = [];
+ selection: CdTableSelection = new CdTableSelection();
+
+ constructor(private rgwBucketService: RgwBucketService) {
+ this.columns = [
+ {
+ name: 'Name',
+ prop: 'bucket',
+ flexGrow: 1
+ },
+ {
+ name: 'Owner',
+ prop: 'owner',
+ flexGrow: 1
+ }
+ ];
+ }
+
+ getBucketList() {
+ this.rgwBucketService.list()
+ .subscribe((resp: object[]) => {
+ this.buckets = resp;
+ });
+ }
+
+ updateSelection(selection: CdTableSelection) {
+ this.selection = selection;
+ }
+}
beforeEach(() => {
fixture = TestBed.createComponent(RgwDaemonDetailsComponent);
component = fixture.componentInstance;
-
component.selection = new CdTableSelection();
-
fixture.detectChanges();
});
if (_.isEmpty(this.serviceId)) {
return;
}
- this.rgwDaemonService.get(this.serviceId).then(resp => {
- this.metadata = resp['rgw_metadata'];
- });
+ this.rgwDaemonService.get(this.serviceId)
+ .subscribe((resp) => {
+ this.metadata = resp['rgw_metadata'];
+ });
}
}
<nav aria-label="breadcrumb">
<ol class="breadcrumb">
+ <li i18n
+ class="breadcrumb-item">Object Gateway</li>
<li i18n
class="breadcrumb-item active"
- aria-current="page">Object Gateway</li>
+ aria-current="page">Daemons</li>
</ol>
</nav>
import { HttpClientModule } from '@angular/common/http';
-import { HttpClientTestingModule } from '@angular/common/http/testing';
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { TabsModule } from 'ngx-bootstrap/tabs';
-import { DataTableModule } from '../../../shared/datatable/datatable.module';
import { SharedModule } from '../../../shared/shared.module';
import { PerformanceCounterModule } from '../../performance-counter/performance-counter.module';
import { RgwDaemonDetailsComponent } from '../rgw-daemon-details/rgw-daemon-details.component';
beforeEach(async(() => {
TestBed.configureTestingModule({
- declarations: [ RgwDaemonListComponent, RgwDaemonDetailsComponent ],
+ declarations: [
+ RgwDaemonListComponent,
+ RgwDaemonDetailsComponent
+ ],
imports: [
- DataTableModule,
- HttpClientTestingModule,
HttpClientModule,
TabsModule.forRoot(),
PerformanceCounterModule,
})
export class RgwDaemonListComponent {
- columns: Array<CdTableColumn> = [];
- daemons: Array<object> = [];
- selection = new CdTableSelection();
+ columns: CdTableColumn[] = [];
+ daemons: object[] = [];
+ selection: CdTableSelection = new CdTableSelection();
constructor(private rgwDaemonService: RgwDaemonService,
cephShortVersionPipe: CephShortVersionPipe) {
getDaemonList() {
this.rgwDaemonService.list()
- .then((resp) => {
+ .subscribe((resp: object[]) => {
this.daemons = resp;
});
}
--- /dev/null
+<tabset *ngIf="selection.hasSingleSelection">
+ <tab i18n-heading heading="Details">
+ <div *ngIf="user">
+ <table class="table table-striped table-bordered">
+ <tbody>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Username</td>
+ <td class="col-sm-3">{{ user.user_id }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Full name</td>
+ <td class="col-sm-3">{{ user.display_name }}</td>
+ </tr>
+ <tr *ngIf="user.email.length">
+ <td i18n
+ class="bold col-sm-1">Email address</td>
+ <td class="col-sm-3">{{ user.email }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Suspended</td>
+ <td class="col-sm-3">{{ user.suspended ? "Yes" : "No" }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Maximum buckets</td>
+ <td class="col-sm-3">{{ user.max_buckets }}</td>
+ </tr>
+ <tr *ngIf="user.subusers && user.subusers.length">
+ <td i18n
+ class="bold col-sm-1">Subusers</td>
+ <td class="col-sm-3">
+ <div *ngFor="let subuser of user.subusers">
+ {{ subuser.id }} ({{ subuser.permissions }})
+ </div>
+ </td>
+ </tr>
+ <tr *ngIf="user.caps && user.caps.length">
+ <td i18n
+ class="bold col-sm-1">Capabilities</td>
+ <td class="col-sm-3">
+ <div *ngFor="let cap of user.caps">
+ {{ cap.type }} ({{ cap.perm }})
+ </div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+
+ <!-- User quota -->
+ <div *ngIf="user.user_quota">
+ <legend i18n>User quota</legend>
+ <table class="table table-striped table-bordered">
+ <tbody>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Enabled</td>
+ <td class="col-sm-3">{{ user.user_quota.enabled ? "Yes" : "No" }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Maximum size</td>
+ <td *ngIf="user.user_quota.max_size <= -1"
+ i18n
+ class="col-sm-3">Unlimited</td>
+ <td *ngIf="user.user_quota.max_size > -1"
+ class="col-sm-3">
+ {{ user.user_quota.max_size | dimlessBinary }}
+ </td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Maximum objects</td>
+ <td *ngIf="user.user_quota.max_objects <= -1"
+ i18n
+ class="col-sm-3">Unlimited</td>
+ <td *ngIf="user.user_quota.max_objects > -1"
+ class="col-sm-3">
+ {{ user.user_quota.max_objects }}
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+
+ <!-- Bucket quota -->
+ <div *ngIf="user.bucket_quota">
+ <legend i18n>Bucket quota</legend>
+ <table class="table table-striped table-bordered">
+ <tbody>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Enabled</td>
+ <td class="col-sm-3">{{ user.bucket_quota.enabled ? "Yes" : "No" }}</td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Maximum size</td>
+ <td *ngIf="user.bucket_quota.max_size <= -1"
+ i18n
+ class="col-sm-3">Unlimited</td>
+ <td *ngIf="user.bucket_quota.max_size > -1"
+ class="col-sm-3">
+ {{ user.bucket_quota.max_size | dimlessBinary }}
+ </td>
+ </tr>
+ <tr>
+ <td i18n
+ class="bold col-sm-1">Maximum objects</td>
+ <td *ngIf="user.bucket_quota.max_objects <= -1"
+ i18n
+ class="col-sm-3">Unlimited</td>
+ <td *ngIf="user.bucket_quota.max_objects > -1"
+ class="col-sm-3">
+ {{ user.bucket_quota.max_objects }}
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ </tab>
+</tabset>
--- /dev/null
+import { HttpClientModule } from '@angular/common/http';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { TabsModule } from 'ngx-bootstrap/tabs';
+
+import { CdTableSelection } from '../../../shared/models/cd-table-selection';
+import { SharedModule } from '../../../shared/shared.module';
+import { RgwUserDetailsComponent } from './rgw-user-details.component';
+
+describe('RgwUserDetailsComponent', () => {
+ let component: RgwUserDetailsComponent;
+ let fixture: ComponentFixture<RgwUserDetailsComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [ RgwUserDetailsComponent ],
+ imports: [
+ HttpClientTestingModule,
+ HttpClientModule,
+ SharedModule,
+ TabsModule.forRoot()
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RgwUserDetailsComponent);
+ component = fixture.componentInstance;
+ component.selection = new CdTableSelection();
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
--- /dev/null
+import { Component, Input, OnChanges } from '@angular/core';
+
+import * as _ from 'lodash';
+
+import { RgwUserService } from '../../../shared/api/rgw-user.service';
+import { CdTableSelection } from '../../../shared/models/cd-table-selection';
+
+@Component({
+ selector: 'cd-rgw-user-details',
+ templateUrl: './rgw-user-details.component.html',
+ styleUrls: ['./rgw-user-details.component.scss']
+})
+export class RgwUserDetailsComponent implements OnChanges {
+ user: any;
+
+ @Input() selection: CdTableSelection;
+
+ constructor(private rgwUserService: RgwUserService) {}
+
+ ngOnChanges() {
+ if (this.selection.hasSelection) {
+ this.user = this.selection.first();
+
+ // Sort subusers and capabilities.
+ this.user.subusers = _.sortBy(this.user.subusers, 'id');
+ this.user.caps = _.sortBy(this.user.caps, 'type');
+
+ // Load the user/bucket quota of the selected user.
+ if (this.user.tenant === '') {
+ this.rgwUserService.getQuota(this.user.user_id)
+ .subscribe((resp: object) => {
+ _.extend(this.user, resp);
+ });
+ }
+ }
+ }
+}
--- /dev/null
+<nav aria-label="breadcrumb">
+ <ol class="breadcrumb">
+ <li i18n
+ class="breadcrumb-item">Object Gateway</li>
+ <li i18n
+ class="breadcrumb-item active"
+ aria-current="page">Users</li>
+ </ol>
+</nav>
+<cd-table [data]="users"
+ [columns]="columns"
+ columnMode="flex"
+ selectionType="single"
+ (updateSelection)="updateSelection($event)"
+ identifier="user_id"
+ (fetchData)="getUserList()">
+ <cd-rgw-user-details cdTableDetail
+ [selection]="selection">
+ </cd-rgw-user-details>
+</cd-table>
--- /dev/null
+import { HttpClientModule } from '@angular/common/http';
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { BsDropdownModule } from 'ngx-bootstrap';
+import { TabsModule } from 'ngx-bootstrap/tabs';
+
+import { SharedModule } from '../../../shared/shared.module';
+import { RgwUserDetailsComponent } from '../rgw-user-details/rgw-user-details.component';
+import { RgwUserListComponent } from './rgw-user-list.component';
+
+describe('RgwUserListComponent', () => {
+ let component: RgwUserListComponent;
+ let fixture: ComponentFixture<RgwUserListComponent>;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [
+ RgwUserListComponent,
+ RgwUserDetailsComponent
+ ],
+ imports: [
+ HttpClientModule,
+ BsDropdownModule.forRoot(),
+ TabsModule.forRoot(),
+ SharedModule
+ ]
+ })
+ .compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RgwUserListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
--- /dev/null
+import { Component } from '@angular/core';
+
+import { RgwUserService } from '../../../shared/api/rgw-user.service';
+import { CellTemplate } from '../../../shared/enum/cell-template.enum';
+import { CdTableColumn } from '../../../shared/models/cd-table-column';
+import { CdTableSelection } from '../../../shared/models/cd-table-selection';
+
+@Component({
+ selector: 'cd-rgw-user-list',
+ templateUrl: './rgw-user-list.component.html',
+ styleUrls: ['./rgw-user-list.component.scss']
+})
+export class RgwUserListComponent {
+
+ columns: CdTableColumn[] = [];
+ users: object[] = [];
+ selection: CdTableSelection = new CdTableSelection();
+
+ constructor(private rgwUserService: RgwUserService) {
+ this.columns = [
+ {
+ name: 'Username',
+ prop: 'user_id',
+ flexGrow: 1
+ },
+ {
+ name: 'Full name',
+ prop: 'display_name',
+ flexGrow: 1
+ },
+ {
+ name: 'Email address',
+ prop: 'email',
+ flexGrow: 1
+ },
+ {
+ name: 'Suspended',
+ prop: 'suspended',
+ flexGrow: 1,
+ cellTransformation: CellTemplate.checkIcon
+ },
+ {
+ name: 'Max. buckets',
+ prop: 'max_buckets',
+ flexGrow: 1
+ }
+ ];
+ }
+
+ getUserList() {
+ this.rgwUserService.list()
+ .subscribe((resp: object[]) => {
+ this.users = resp;
+ });
+ }
+
+ updateSelection(selection: CdTableSelection) {
+ this.selection = selection;
+ }
+}
import { SharedModule } from '../../shared/shared.module';
import { PerformanceCounterModule } from '../performance-counter/performance-counter.module';
+import { RgwBucketDetailsComponent } from './rgw-bucket-details/rgw-bucket-details.component';
+import { RgwBucketListComponent } from './rgw-bucket-list/rgw-bucket-list.component';
import { RgwDaemonDetailsComponent } from './rgw-daemon-details/rgw-daemon-details.component';
import { RgwDaemonListComponent } from './rgw-daemon-list/rgw-daemon-list.component';
+import { RgwUserDetailsComponent } from './rgw-user-details/rgw-user-details.component';
+import { RgwUserListComponent } from './rgw-user-list/rgw-user-list.component';
@NgModule({
entryComponents: [
- RgwDaemonDetailsComponent
+ RgwDaemonDetailsComponent,
+ RgwBucketDetailsComponent,
+ RgwUserDetailsComponent
],
imports: [
CommonModule,
],
exports: [
RgwDaemonListComponent,
- RgwDaemonDetailsComponent
+ RgwDaemonDetailsComponent,
+ RgwBucketListComponent,
+ RgwBucketDetailsComponent,
+ RgwUserListComponent,
+ RgwUserDetailsComponent
],
declarations: [
RgwDaemonListComponent,
- RgwDaemonDetailsComponent
+ RgwDaemonDetailsComponent,
+ RgwBucketListComponent,
+ RgwBucketDetailsComponent,
+ RgwUserListComponent,
+ RgwUserDetailsComponent
]
})
export class RgwModule { }
-->
<!-- Object Gateway -->
- <li routerLinkActive="active"
- class="tc_menuitem tc_menuitem_rgw">
- <a i18n
- routerLink="/rgw">Object Gateway
- </a>
- </li>
-
- <!--<li class="dropdown tc_menuitem tc_menuitem_ceph_rgw">
- <a href=""
+ <li dropdown
+ routerLinkActive="active"
+ class="dropdown tc_menuitem tc_menuitem_rgw">
+ <a dropdownToggle
class="dropdown-toggle"
data-toggle="dropdown">
<ng-container i18n>Object Gateway</ng-container>
</a>
<ul *dropdownMenu
class="dropdown-menu">
+ <li routerLinkActive="active"
+ class="tc_submenuitem tc_submenuitem_rgw_daemons">
+ <a i18n
+ class="dropdown-item"
+ routerLink="/rgw/daemon">Daemons
+ </a>
+ </li>
<li routerLinkActive="active"
class="tc_submenuitem tc_submenuitem_rgw_users">
<a i18n
class="dropdown-item"
- routerLink="/rgw-users">Users
+ routerLink="/rgw/user">Users
</a>
</li>
<li routerLinkActive="active"
class="tc_submenuitem tc_submenuitem_rgw_buckets">
<a i18n
class="dropdown-item"
- routerLink="/rgw-buckets">Buckets
+ routerLink="/rgw/bucket">Buckets
</a>
</li>
</ul>
</li>
+
+ <!--
<li routerLinkActive="active"
class="tc_menuitem tc_submenuitem_settings">
<a i18n
routerLink="/settings">Settings
</a>
- </li> -->
+ </li>
+ -->
</ul>
<!-- /.navbar-primary -->
import { PoolService } from './pool.service';
import { RbdMirroringService } from './rbd-mirroring.service';
import { RbdService } from './rbd.service';
+import { RgwBucketService } from './rgw-bucket.service';
import { RgwDaemonService } from './rgw-daemon.service';
+import { RgwUserService } from './rgw-user.service';
import { TablePerformanceCounterService } from './table-performance-counter.service';
import { TcmuIscsiService } from './tcmu-iscsi.service';
PoolService,
RbdService,
RbdMirroringService,
+ RgwBucketService,
RgwDaemonService,
+ RgwUserService,
TablePerformanceCounterService,
TcmuIscsiService
]
--- /dev/null
+import { HttpClientModule } from '@angular/common/http';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { inject, TestBed } from '@angular/core/testing';
+
+import { RgwBucketService } from './rgw-bucket.service';
+
+describe('RgwBucketService', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [RgwBucketService],
+ imports: [HttpClientTestingModule, HttpClientModule]
+ });
+ });
+
+ it(
+ 'should be created',
+ inject([RgwBucketService], (service: RgwBucketService) => {
+ expect(service).toBeTruthy();
+ })
+ );
+});
--- /dev/null
+import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import 'rxjs/add/observable/forkJoin';
+import 'rxjs/add/observable/of';
+import { Observable } from 'rxjs/Observable';
+
+import * as _ from 'lodash';
+
+@Injectable()
+export class RgwBucketService {
+
+ private url = '/api/rgw/proxy/bucket';
+
+ constructor(private http: HttpClient) { }
+
+ list() {
+ return this.http.get(this.url)
+ .flatMap((buckets: string[]) => {
+ if (buckets.length > 0) {
+ return Observable.forkJoin(
+ buckets.map((bucket: string) => {
+ return this.get(bucket);
+ })
+ );
+ }
+ return Observable.of([]);
+ });
+ }
+
+ get(bucket: string) {
+ let params = new HttpParams();
+ params = params.append('bucket', bucket);
+ return this.http.get(this.url, { params: params });
+ }
+
+ create(bucket: string, uid: string) {
+ const body = JSON.stringify({
+ 'bucket': bucket,
+ 'uid': uid
+ });
+ return this.http.post(`/api/rgw/bucket`, body);
+ }
+
+ update(bucketId: string, bucket: string, uid: string) {
+ let params = new HttpParams();
+ params = params.append('bucket', bucket);
+ params = params.append('bucket-id', bucketId as string);
+ params = params.append('uid', uid);
+ return this.http.put(this.url, null, { params: params });
+ }
+
+ delete(bucket: string, purgeObjects = true) {
+ let params = new HttpParams();
+ params = params.append('bucket', bucket);
+ params = params.append('purge-objects', purgeObjects ? 'true' : 'false');
+ return this.http.delete(this.url, { params: params });
+ }
+
+ find(bucket: string) {
+ let params = new HttpParams();
+ params = params.append('bucket', bucket);
+ return this.http.get(this.url, { params: params })
+ .flatMap((resp: object | null) => {
+ // Make sure we have received valid data.
+ if ((null === resp) || (!_.isObjectLike(resp))) {
+ return Observable.of([]);
+ }
+ // Return an array to be able to support wildcard searching someday.
+ return Observable.of([resp]);
+ });
+ }
+}
constructor(private http: HttpClient) { }
list() {
- return this.http.get(this.url)
- .toPromise()
- .then((resp: any) => {
- return resp;
- });
+ return this.http.get(this.url);
}
get(id: string) {
- return this.http.get(`${this.url}/${id}`)
- .toPromise()
- .then((resp: any) => {
- return resp;
- });
+ return this.http.get(`${this.url}/${id}`);
}
}
--- /dev/null
+import { HttpClientModule } from '@angular/common/http';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { inject, TestBed } from '@angular/core/testing';
+
+import { RgwUserService } from './rgw-user.service';
+
+describe('RgwUserService', () => {
+ beforeEach(() => {
+ TestBed.configureTestingModule({
+ providers: [RgwUserService],
+ imports: [HttpClientTestingModule, HttpClientModule]
+ });
+ });
+
+ it(
+ 'should be created',
+ inject([RgwUserService], (service: RgwUserService) => {
+ expect(service).toBeTruthy();
+ })
+ );
+});
--- /dev/null
+import { HttpClient, HttpParams } from '@angular/common/http';
+import { Injectable } from '@angular/core';
+import 'rxjs/add/observable/forkJoin';
+import 'rxjs/add/observable/of';
+import { Observable } from 'rxjs/Observable';
+
+@Injectable()
+export class RgwUserService {
+
+ private url = '/api/rgw/proxy/user';
+
+ constructor(private http: HttpClient) { }
+
+ list() {
+ return this.enumerate()
+ .flatMap((uids: string[]) => {
+ if (uids.length > 0) {
+ return Observable.forkJoin(
+ uids.map((uid: string) => {
+ return this.get(uid);
+ })
+ );
+ }
+ return Observable.of([]);
+ });
+ }
+
+ enumerate() {
+ return this.http.get('/api/rgw/proxy/metadata/user');
+ }
+
+ get(uid: string) {
+ let params = new HttpParams();
+ params = params.append('uid', uid);
+ return this.http.get(this.url, { params: params });
+ }
+
+ getQuota(uid: string) {
+ let params = new HttpParams();
+ params = params.append('uid', uid);
+ return this.http.get(`${this.url}?quota`, {params: params});
+ }
+}
<a [routerLink]="[row.cdLink]">{{ value }}</a>
</ng-template>
+<ng-template #checkIconTpl
+ let-value="value">
+ <i class="fa fa-check fa-fw"
+ [hidden]="!value"></i>
+</ng-template>
+
+
<ng-template #perSecondTpl
let-row="row"
let-value="value">
@ViewChild('tableCellBoldTpl') tableCellBoldTpl: TemplateRef<any>;
@ViewChild('sparklineTpl') sparklineTpl: TemplateRef<any>;
@ViewChild('routerLinkTpl') routerLinkTpl: TemplateRef<any>;
+ @ViewChild('checkIconTpl') checkIconTpl: TemplateRef<any>;
@ViewChild('perSecondTpl') perSecondTpl: TemplateRef<any>;
@ViewChild('executingTpl') executingTpl: TemplateRef<any>;
_addTemplates() {
this.cellTemplates.bold = this.tableCellBoldTpl;
+ this.cellTemplates.checkIcon = this.checkIconTpl;
this.cellTemplates.sparkline = this.sparklineTpl;
this.cellTemplates.routerLink = this.routerLinkTpl;
this.cellTemplates.perSecond = this.perSecondTpl;
bold = 'bold',
sparkline = 'sparkline',
perSecond = 'perSecond',
+ checkIcon = 'checkIcon',
routerLink = 'routerLink',
executing = 'executing'
}