mirror of
https://github.com/bitwarden/browser.git
synced 2025-01-22 21:21:35 +01:00
collection and group listing from org admin
This commit is contained in:
parent
d830499c76
commit
93582da044
2
jslib
2
jslib
@ -1 +1 @@
|
||||
Subproject commit a600c4a5398f8893d4cfea298fcfb66f90c3d975
|
||||
Subproject commit 2a526940fd4eefd2758ea654b0c7994e0ee12c4e
|
@ -109,6 +109,7 @@ import { TrueFalseValueDirective } from 'jslib/angular/directives/true-false-val
|
||||
|
||||
import { I18nPipe } from 'jslib/angular/pipes/i18n.pipe';
|
||||
import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
|
||||
import { SearchPipe } from 'jslib/angular/pipes/search.pipe';
|
||||
|
||||
@NgModule({
|
||||
imports: [
|
||||
@ -189,6 +190,7 @@ import { SearchCiphersPipe } from 'jslib/angular/pipes/search-ciphers.pipe';
|
||||
PurgeVaultComponent,
|
||||
RegisterComponent,
|
||||
SearchCiphersPipe,
|
||||
SearchPipe,
|
||||
SettingsComponent,
|
||||
ShareComponent,
|
||||
StopClickDirective,
|
||||
|
@ -1,3 +1,43 @@
|
||||
<div class="page-header">
|
||||
<div class="page-header d-flex">
|
||||
<h1>{{'collections' | i18n}}</h1>
|
||||
<div class="ml-auto d-flex">
|
||||
<div class="form-inline">
|
||||
<label class="sr-only" for="search">{{'search' | i18n}}</label>
|
||||
<input type="search" class="form-control form-control-sm" id="search" placeholder="{{'search' | i18n}}" [(ngModel)]="searchText">
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary ml-3" (click)="add()">
|
||||
<i class="fa fa-plus fa-fw"></i>
|
||||
{{'newCollection' | i18n}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<i class="fa fa-spinner fa-spin text-muted" *ngIf="loading"></i>
|
||||
<ng-container *ngIf="!loading && (collections | search:searchText:'name') as searchedCollections">
|
||||
<p *ngIf="!searchedCollections.length">{{'noItemsInList' | i18n}}</p>
|
||||
<table class="table table-hover table-list" *ngIf="searchedCollections.length">
|
||||
<tbody>
|
||||
<tr *ngFor="let c of searchedCollections">
|
||||
<td class="normal-lh">
|
||||
<a href="#" appStopClick (click)="edit(c)">{{c.name}}</a>
|
||||
</td>
|
||||
<td class="table-list-options">
|
||||
<div class="dropdown" appListDropdown>
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fa fa-cog fa-lg"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<a class="dropdown-item" href="#" appStopClick (click)="users(c)">
|
||||
<i class="fa fa-fw fa-users"></i>
|
||||
{{'users' | i18n}}
|
||||
</a>
|
||||
<a class="dropdown-item text-danger" href="#" appStopClick (click)="delete(c)">
|
||||
<i class="fa fa-fw fa-trash-o"></i>
|
||||
{{'delete' | i18n}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</ng-container>
|
||||
|
@ -1,7 +1,40 @@
|
||||
import { Component } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
import { CollectionService } from 'jslib/abstractions/collection.service';
|
||||
|
||||
import { CollectionData } from 'jslib/models/data/collectionData';
|
||||
import { Collection } from 'jslib/models/domain/collection';
|
||||
import { CollectionView } from 'jslib/models/view/collectionView';
|
||||
|
||||
@Component({
|
||||
selector: 'app-org-manage-collections',
|
||||
templateUrl: 'collections.component.html',
|
||||
})
|
||||
export class CollectionsComponent { }
|
||||
export class CollectionsComponent implements OnInit {
|
||||
loading = true;
|
||||
organizationId: string;
|
||||
collections: CollectionView[];
|
||||
searchText: string;
|
||||
|
||||
constructor(private apiService: ApiService, private route: ActivatedRoute,
|
||||
private collectionService: CollectionService) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.route.parent.parent.params.subscribe(async (params) => {
|
||||
this.organizationId = params.organizationId;
|
||||
});
|
||||
await this.load();
|
||||
}
|
||||
|
||||
async load() {
|
||||
const response = await this.apiService.getCollections(this.organizationId);
|
||||
const collections = response.data.map((r) => new Collection(new CollectionData(r)));
|
||||
this.collections = await this.collectionService.decryptMany(collections);
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,43 @@
|
||||
<div class="page-header">
|
||||
<div class="page-header d-flex">
|
||||
<h1>{{'groups' | i18n}}</h1>
|
||||
<div class="ml-auto d-flex">
|
||||
<div class="form-inline">
|
||||
<label class="sr-only" for="search">{{'search' | i18n}}</label>
|
||||
<input type="search" class="form-control form-control-sm" id="search" placeholder="{{'search' | i18n}}" [(ngModel)]="searchText">
|
||||
</div>
|
||||
<button type="button" class="btn btn-sm btn-outline-primary ml-3" (click)="add()">
|
||||
<i class="fa fa-plus fa-fw"></i>
|
||||
{{'newGroup' | i18n}}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<i class="fa fa-spinner fa-spin text-muted" *ngIf="loading"></i>
|
||||
<ng-container *ngIf="!loading && (groups | search:searchText:'name') as searchedGroups">
|
||||
<p *ngIf="!searchedGroups.length">{{'noItemsInList' | i18n}}</p>
|
||||
<table class="table table-hover table-list" *ngIf="searchedGroups.length">
|
||||
<tbody>
|
||||
<tr *ngFor="let g of searchedGroups">
|
||||
<td class="normal-lh">
|
||||
<a href="#" appStopClick (click)="edit(g)">{{g.name}}</a>
|
||||
</td>
|
||||
<td class="table-list-options">
|
||||
<div class="dropdown" appListDropdown>
|
||||
<button class="btn btn-outline-secondary dropdown-toggle" type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="fa fa-cog fa-lg"></i>
|
||||
</button>
|
||||
<div class="dropdown-menu dropdown-menu-right">
|
||||
<a class="dropdown-item" href="#" appStopClick (click)="users(g)">
|
||||
<i class="fa fa-fw fa-users"></i>
|
||||
{{'users' | i18n}}
|
||||
</a>
|
||||
<a class="dropdown-item text-danger" href="#" appStopClick (click)="delete(g)">
|
||||
<i class="fa fa-fw fa-trash-o"></i>
|
||||
{{'delete' | i18n}}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</ng-container>
|
||||
|
@ -1,7 +1,39 @@
|
||||
import { Component } from '@angular/core';
|
||||
import {
|
||||
Component,
|
||||
OnInit,
|
||||
} from '@angular/core';
|
||||
import { ActivatedRoute } from '@angular/router';
|
||||
|
||||
import { ApiService } from 'jslib/abstractions/api.service';
|
||||
|
||||
import { GroupResponse } from 'jslib/models/response/groupUserResponse';
|
||||
|
||||
@Component({
|
||||
selector: 'app-org-groups',
|
||||
templateUrl: 'groups.component.html',
|
||||
})
|
||||
export class GroupsComponent { }
|
||||
export class GroupsComponent implements OnInit {
|
||||
loading = true;
|
||||
organizationId: string;
|
||||
groups: GroupResponse[];
|
||||
searchText: string;
|
||||
|
||||
constructor(private apiService: ApiService, private route: ActivatedRoute) { }
|
||||
|
||||
async ngOnInit() {
|
||||
this.route.parent.parent.params.subscribe(async (params) => {
|
||||
this.organizationId = params.organizationId;
|
||||
});
|
||||
await this.load();
|
||||
}
|
||||
|
||||
async load() {
|
||||
const response = await this.apiService.getGroups(this.organizationId);
|
||||
if (response.data != null && response.data.length > 0) {
|
||||
this.groups = response.data;
|
||||
} else {
|
||||
this.groups = [];
|
||||
}
|
||||
this.loading = false;
|
||||
}
|
||||
}
|
||||
|
@ -31,16 +31,8 @@ export class GroupingsComponent extends BaseGroupingsComponent {
|
||||
}
|
||||
const collections = await this.apiService.getCollections(this.organization.id);
|
||||
if (collections != null && collections.data != null && collections.data.length) {
|
||||
const decCollections: CollectionView[] = [];
|
||||
const promises: any[] = [];
|
||||
collections.data.forEach((r) => {
|
||||
const data = new CollectionData(r);
|
||||
const collection = new Collection(data);
|
||||
promises.push(collection.decrypt().then((c) => decCollections.push(c)));
|
||||
});
|
||||
await Promise.all(promises);
|
||||
decCollections.sort(this.collectionService.getLocaleSortingFunction());
|
||||
this.collections = decCollections;
|
||||
const collectionDomains = collections.data.map((r) => new Collection(new CollectionData(r)));
|
||||
this.collections = await this.collectionService.decryptMany(collectionDomains);
|
||||
} else {
|
||||
this.collections = [];
|
||||
}
|
||||
|
@ -1699,5 +1699,17 @@
|
||||
},
|
||||
"groups": {
|
||||
"message": "Groups"
|
||||
},
|
||||
"newGroup": {
|
||||
"message": "New Group"
|
||||
},
|
||||
"newCollection": {
|
||||
"message": "New Collection"
|
||||
},
|
||||
"inviteUser": {
|
||||
"message": "Invite User"
|
||||
},
|
||||
"search": {
|
||||
"message": "Search"
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user