From 5d8135908313390cb020a5ef1c5368a5190292bd Mon Sep 17 00:00:00 2001 From: ksendart Date: Fri, 27 Oct 2017 10:53:28 +0700 Subject: [PATCH] feat(select account) - use ngrx for selected account (#607) #597 --- .../account-details.container.ts | 107 +++++++++++++++++ .../account-sidebar.container.ts | 38 ++++++ .../account-container/account.container.ts | 57 +++++---- .../account-details.component.html | 4 - .../account-details.component.ts | 37 +----- .../account-limits.component.html | 55 +++++---- .../account-limits.component.ts | 11 +- .../account-configuration.component.ts | 23 +++- .../edit-account-configuration.component.html | 1 - .../account-settings.component.html | 2 +- .../account-settings.component.ts | 42 ++----- .../account-sidebar.component.html | 6 +- .../account-sidebar.component.scss | 9 +- .../account-sidebar.component.ts | 26 ++--- .../account-statistics.component.html | 2 +- .../account-statistics.component.ts | 22 +--- .../account/account/account-item.component.ts | 12 +- src/app/account/accounts.module.ts | 39 +++++-- src/app/account/accounts.routing.ts | 8 +- src/app/domains/redux/domains.effects.ts | 34 ------ .../events/containers/event-list.container.ts | 6 +- src/app/events/redux/events.reducers.ts | 11 +- .../accounts}/redux/accounts.actions.ts | 11 +- .../accounts}/redux/accounts.effects.ts | 7 +- .../accounts}/redux/accounts.reducers.ts | 27 +++-- .../redux/configurations.actions.ts | 44 +++++++ .../redux/configurations.effects.ts | 65 +++++++++++ .../redux/configurations.reducers.ts | 107 +++++++++++++++++ .../domains/redux/domains.actions.ts | 3 +- .../reducers/domains/redux/domains.effects.ts | 30 +++++ .../domains/redux/domains.reducers.ts | 7 +- .../redux/resource-counts.actions.ts | 22 ++++ .../redux/resource-counts.effects.ts | 30 +++++ .../redux/resource-counts.reducers.ts | 108 ++++++++++++++++++ .../redux/resource-limits.actions.ts | 43 +++++++ .../redux/resource-limits.effects.ts | 65 +++++++++++ .../redux/resource-limits.reducers.ts | 106 +++++++++++++++++ .../roles/redux/roles.actions.ts | 0 .../roles/redux/roles.effects.ts | 18 +-- .../roles/redux/roles.reducers.ts | 9 +- .../account-actions.component.html | 2 +- .../account-actions.component.ts | 18 +-- src/app/shared/models/resource-count.model.ts | 7 +- src/app/shared/models/resource-limit.model.ts | 6 +- src/app/shared/services/account.service.ts | 10 +- .../shared/services/configuration.service.ts | 9 +- .../shared/services/resource-count.service.ts | 8 +- .../shared/services/resource-limit.service.ts | 4 +- .../containers/ssh-key-list.container.ts | 8 +- src/app/ssh-keys/redux/ssh-key.reducers.ts | 12 +- .../ssh-key-list-item.component.ts | 12 +- src/app/tags/tag/tag.component.scss | 6 +- .../template/template/template.component.ts | 4 +- src/app/vm/vm-list/vm-list-item.component.ts | 4 +- .../volume-item/volume-item.component.ts | 20 +++- 55 files changed, 1071 insertions(+), 313 deletions(-) create mode 100644 src/app/account/account-container/account-details.container.ts create mode 100644 src/app/account/account-container/account-sidebar.container.ts delete mode 100644 src/app/domains/redux/domains.effects.ts rename src/app/{account => reducers/accounts}/redux/accounts.actions.ts (74%) rename src/app/{account => reducers/accounts}/redux/accounts.effects.ts (88%) rename src/app/{account => reducers/accounts}/redux/accounts.reducers.ts (89%) create mode 100644 src/app/reducers/configuration/redux/configurations.actions.ts create mode 100644 src/app/reducers/configuration/redux/configurations.effects.ts create mode 100644 src/app/reducers/configuration/redux/configurations.reducers.ts rename src/app/{ => reducers}/domains/redux/domains.actions.ts (92%) create mode 100644 src/app/reducers/domains/redux/domains.effects.ts rename src/app/{ => reducers}/domains/redux/domains.reducers.ts (94%) create mode 100644 src/app/reducers/resource-count/redux/resource-counts.actions.ts create mode 100644 src/app/reducers/resource-count/redux/resource-counts.effects.ts create mode 100644 src/app/reducers/resource-count/redux/resource-counts.reducers.ts create mode 100644 src/app/reducers/resource-limit/redux/resource-limits.actions.ts create mode 100644 src/app/reducers/resource-limit/redux/resource-limits.effects.ts create mode 100644 src/app/reducers/resource-limit/redux/resource-limits.reducers.ts rename src/app/{ => reducers}/roles/redux/roles.actions.ts (100%) rename src/app/{ => reducers}/roles/redux/roles.effects.ts (56%) rename src/app/{ => reducers}/roles/redux/roles.reducers.ts (95%) diff --git a/src/app/account/account-container/account-details.container.ts b/src/app/account/account-container/account-details.container.ts new file mode 100644 index 0000000000..e6de8b3bb8 --- /dev/null +++ b/src/app/account/account-container/account-details.container.ts @@ -0,0 +1,107 @@ +import { + Component, + OnInit +} from '@angular/core'; +import { State } from '../../reducers/index'; +import { Store } from '@ngrx/store'; +import * as configurationAction from '../../reducers/configuration/redux/configurations.actions'; +import * as resourceLimitAction from '../../reducers/resource-limit/redux/resource-limits.actions'; +import * as resourceCountAction from '../../reducers/resource-count/redux/resource-counts.actions'; +import * as fromAccounts from '../../reducers/accounts/redux/accounts.reducers'; +import * as fromConfigurations from '../../reducers/configuration/redux/configurations.reducers'; +import * as fromResourceLimits from '../../reducers/resource-limit/redux/resource-limits.reducers'; +import * as fromResourceCounts from '../../reducers/resource-count/redux/resource-counts.reducers'; +import { WithUnsubscribe } from '../../utils/mixins/with-unsubscribe'; +import { AuthService } from '../../shared/services/auth.service'; +import { Account } from '../../shared/models/account.model'; + +@Component({ + selector: 'cs-account-page-container', + template: ` + + + + + ` +}) +export class AccountDetailsContainerComponent extends WithUnsubscribe() implements OnInit { + + readonly account$ = this.store.select(fromAccounts.getSelectedAccount); + readonly configurations$ = this.store.select(fromConfigurations.selectAll); + readonly limits$ = this.store.select(fromResourceLimits.selectAll); + readonly stats$ = this.store.select(fromResourceCounts.selectAll); + + public account: Account; + + + constructor( + private store: Store, + private authService: AuthService + ) { + super(); + } + + public onConfigurationEdit(configuration) { + this.store.dispatch(new configurationAction.UpdateConfigurationRequest({ + configuration, + account: this.account + })); + } + + public onLimitsEdit(limits) { + this.store.dispatch(new resourceLimitAction.UpdateResourceLimitsRequest({ + limits, + account: this.account + })); + } + + public onStatsUpdate(stats) { + this.store.dispatch(new resourceCountAction.LoadResourceCountsRequest({ + account: this.account.name, + domainid: this.account.domainid + })); + } + + public ngOnInit() { + this.account$ + .takeUntil(this.unsubscribe$) + .subscribe(account => { + if (account) { + this.account = account; + this.store.dispatch(new resourceLimitAction.LoadResourceLimitsRequest({ + account: account.name, + domainid: account.domainid + })); + + if (this.isAdmin()) { + this.store.dispatch(new configurationAction.LoadConfigurationsRequest({ accountid: account.id })); + this.store.dispatch(new resourceCountAction.LoadResourceCountsRequest({ + account: account.name, + domainid: account.domainid + })); + } + } + }); + } + + + public isAdmin() { + return this.authService.isAdmin(); + } + +} diff --git a/src/app/account/account-container/account-sidebar.container.ts b/src/app/account/account-container/account-sidebar.container.ts new file mode 100644 index 0000000000..4b9004b3f1 --- /dev/null +++ b/src/app/account/account-container/account-sidebar.container.ts @@ -0,0 +1,38 @@ +import { + Component, + OnInit +} from '@angular/core'; +import { State } from '../../reducers/index'; +import { Store } from '@ngrx/store'; +import * as accountEvent from '../../reducers/accounts/redux/accounts.actions'; +import { ActivatedRoute } from '@angular/router'; +import * as fromAccounts from '../../reducers/accounts/redux/accounts.reducers'; + +@Component({ + selector: 'cs-account-page-container', + template: ` + ` +}) +export class AccountSidebarContainerComponent implements OnInit { + + readonly account$ = this.store.select(fromAccounts.getSelectedAccount); + + + constructor( + private store: Store, + private activatedRoute: ActivatedRoute + ) { } + + public onAccountChange(id) { + this.store.dispatch(new accountEvent.LoadAccountsRequest()); + } + + public ngOnInit() { + const params = this.activatedRoute.snapshot.params; + this.store.dispatch(new accountEvent.LoadSelectedAccount(params['id'])); + } + +} diff --git a/src/app/account/account-container/account.container.ts b/src/app/account/account-container/account.container.ts index 462b7ad790..bfcde49814 100644 --- a/src/app/account/account-container/account.container.ts +++ b/src/app/account/account-container/account.container.ts @@ -4,20 +4,24 @@ import { } from '@angular/core'; import { State } from '../../reducers/index'; import { Store } from '@ngrx/store'; -import * as accountActions from '../redux/accounts.actions'; -import * as domainActions from '../../domains/redux/domains.actions'; -import * as roleActions from '../../roles/redux/roles.actions'; +import * as accountActions from '../../reducers/accounts/redux/accounts.actions'; +import * as domainActions from '../../reducers/domains/redux/domains.actions'; +import * as roleActions from '../../reducers/roles/redux/roles.actions'; import { FilterService } from '../../shared/services/filter.service'; import { ActivatedRoute, Router } from '@angular/router'; import { SessionStorageService } from '../../shared/services/session-storage.service'; -import * as fromAccounts from '../redux/accounts.reducers'; -import * as fromDomains from '../../domains/redux/domains.reducers'; -import * as fromRoles from '../../roles/redux/roles.reducers'; +import * as fromAccounts from '../../reducers/accounts/redux/accounts.reducers'; +import * as fromDomains from '../../reducers/domains/redux/domains.reducers'; +import * as fromRoles from '../../reducers/roles/redux/roles.reducers'; import { WithUnsubscribe } from '../../utils/mixins/with-unsubscribe'; -import { Account, AccountState } from '../../shared/models/account.model'; +import { + Account, + AccountState +} from '../../shared/models/account.model'; +import { AuthService } from '../../shared/services/auth.service'; export const stateTranslations = { [AccountState.disabled]: 'ACCOUNT_STATE.DISABLED', @@ -54,8 +58,8 @@ export class AccountPageContainerComponent extends WithUnsubscribe() implements readonly accounts$ = this.store.select(fromAccounts.selectFilteredAccounts); readonly loading$ = this.store.select(fromAccounts.isLoading); readonly filters$ = this.store.select(fromAccounts.filters); - readonly domains$ = this.store.select(fromDomains.domains); - readonly roles$ = this.store.select(fromRoles.roles); + readonly domains$ = this.store.select(fromDomains.selectAll); + readonly roles$ = this.store.select(fromRoles.selectAll); readonly roleTypes$ = this.store.select(fromRoles.roleTypes); readonly selectedDomainIds$ = this.store.select(fromAccounts.filterSelectedDomainIds); @@ -109,6 +113,7 @@ export class AccountPageContainerComponent extends WithUnsubscribe() implements constructor( private store: Store, + private authService: AuthService, private sessionStorage: SessionStorageService, private activatedRoute: ActivatedRoute, private router: Router @@ -140,21 +145,29 @@ export class AccountPageContainerComponent extends WithUnsubscribe() implements this.store.dispatch(new accountActions.AccountFilterUpdate({})); } + public isAdmin() { + return this.authService.isAdmin(); + } + public ngOnInit() { - this.store.dispatch(new domainActions.LoadDomainsRequest()); - this.store.dispatch(new roleActions.LoadRolesRequest()); - this.initFilters(); - this.filters$ - .takeUntil(this.unsubscribe$) - .subscribe(filters => { - this.filterService.update({ - 'domains': filters.selectedDomainIds, - 'roles': filters.selectedRoleNames, - 'roleTypes': filters.selectedRoleTypes, - 'states': filters.selectedStates, - 'groupings': filters.selectedGroupingNames + if (this.isAdmin()) { + this.store.dispatch(new domainActions.LoadDomainsRequest()); + this.store.dispatch(new roleActions.LoadRolesRequest()); + this.initFilters(); + this.filters$ + .takeUntil(this.unsubscribe$) + .subscribe(filters => { + this.filterService.update({ + 'domains': filters.selectedDomainIds, + 'roles': filters.selectedRoleNames, + 'roleTypes': filters.selectedRoleTypes, + 'states': filters.selectedStates, + 'groupings': filters.selectedGroupingNames + }); }); - }); + } else { + this.store.dispatch(new accountActions.LoadAccountsRequest()); + } } public update(selectedGroupings) { diff --git a/src/app/account/account-sidebar/account-details/account-details.component.html b/src/app/account/account-sidebar/account-details/account-details.component.html index 0f19f8c6ee..c2266d4766 100644 --- a/src/app/account/account-sidebar/account-details/account-details.component.html +++ b/src/app/account/account-sidebar/account-details/account-details.component.html @@ -147,7 +147,3 @@

{{ 'ACCOUNT_PAGE.DETAILS.TITLE' | translate }} - - - - diff --git a/src/app/account/account-sidebar/account-details/account-details.component.ts b/src/app/account/account-sidebar/account-details/account-details.component.ts index e5e62ce0bd..3d8a384a07 100644 --- a/src/app/account/account-sidebar/account-details/account-details.component.ts +++ b/src/app/account/account-sidebar/account-details/account-details.component.ts @@ -1,10 +1,8 @@ -import { Component } from '@angular/core'; +import { + Component, + Input +} from '@angular/core'; import { Account } from '../../../shared/models/account.model'; -import { ActivatedRoute } from '@angular/router'; -import { AccountService } from '../../../shared/services/account.service'; -import { ResourceLimit } from '../../../shared/models/resource-limit.model'; -import { ResourceLimitService } from '../../../shared/services/resource-limit.service'; -import { Observable } from 'rxjs/Observable'; import { AuthService } from '../../../shared/services/auth.service'; @Component({ @@ -12,34 +10,11 @@ import { AuthService } from '../../../shared/services/auth.service'; templateUrl: 'account-details.component.html' }) export class AccountDetailsComponent { - public account: Account; - public limits: Array; + @Input() public account: Account; constructor( - private accountService: AccountService, - private activatedRoute: ActivatedRoute, - private resourceLimitService: ResourceLimitService, private authService: AuthService - ) { - const params = this.activatedRoute.snapshot.parent.params; - - this.accountService.get(params.id) - .switchMap(account => { - this.account = account; - return this.resourceLimitService.getList({ - account: this.account.name, - domainid: this.account.domainid - }); - }).subscribe(limits => { - this.limits = limits; - }); - - } - - public updateLimits(limits: Array) { - const observes = limits.map(limit => this.resourceLimitService.updateResourceLimit(limit, this.account)); - Observable.forkJoin(...observes).subscribe(); - } + ) { } public isAdmin() { return this.authService.isAdmin(); diff --git a/src/app/account/account-sidebar/account-limits/account-limits.component.html b/src/app/account/account-sidebar/account-limits/account-limits.component.html index 36afa3b3cf..a9938ca744 100644 --- a/src/app/account/account-sidebar/account-limits/account-limits.component.html +++ b/src/app/account/account-sidebar/account-limits/account-limits.component.html @@ -8,31 +8,46 @@

-
-
-
+ +
+
+
+
+
+
-
-
- +
+
+ +
+
+
+
+
+ + +
+
@@ -40,7 +55,7 @@

mat-icon-button [matTooltip]="'COMMON.EDIT' | translate" matTooltipPosition="above" - (click)="isEdit=!isEdit" + (click)="editLimits()" > edit diff --git a/src/app/account/account-sidebar/account-limits/account-limits.component.ts b/src/app/account/account-sidebar/account-limits/account-limits.component.ts index dd0c37b124..aa748a518a 100644 --- a/src/app/account/account-sidebar/account-limits/account-limits.component.ts +++ b/src/app/account/account-sidebar/account-limits/account-limits.component.ts @@ -1,4 +1,5 @@ import { + ChangeDetectionStrategy, Component, EventEmitter, Input, @@ -13,6 +14,7 @@ import { @Component({ selector: 'cs-account-limits', templateUrl: 'account-limits.component.html', + changeDetection: ChangeDetectionStrategy.OnPush, styleUrls: ['account-limits.component.scss'] }) export class AccountLimitsComponent { @@ -21,6 +23,8 @@ export class AccountLimitsComponent { @Output() public onLimitsEdit: EventEmitter>; public isEdit: boolean = false; + public localLimits = []; + public limitLabels = { [ResourceType.Instance]: 'ACCOUNT_PAGE.CONFIGURATION.VM_LIMIT', [ResourceType.IP]: 'ACCOUNT_PAGE.CONFIGURATION.IP_LIMIT', @@ -41,8 +45,13 @@ export class AccountLimitsComponent { } public onSave(): void { - this.onLimitsEdit.emit(this.limits); + this.onLimitsEdit.emit(this.localLimits); this.isEdit = false; } + public editLimits() { + this.localLimits = this.limits.map(limit => ({resourcetype: limit.resourcetype, max: limit.max})); + this.isEdit = !this.isEdit; + } + } diff --git a/src/app/account/account-sidebar/account-settings/account-configuration/account-configuration.component.ts b/src/app/account/account-sidebar/account-settings/account-configuration/account-configuration.component.ts index 401e4a026c..ca21d530a0 100644 --- a/src/app/account/account-sidebar/account-settings/account-configuration/account-configuration.component.ts +++ b/src/app/account/account-sidebar/account-settings/account-configuration/account-configuration.component.ts @@ -1,5 +1,12 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { + Component, + EventEmitter, + Input, + Output +} from '@angular/core'; import { Configuration } from '../../../../shared/models/configuration.model'; +import { EditAccountConfigurationComponent } from './edit-account-configuration.component'; +import { MatDialog } from '@angular/material'; @Component({ selector: 'cs-account-configuration', @@ -9,12 +16,22 @@ export class AccountConfigurationComponent { @Input() public configuration: Configuration; @Output() public onConfigurationEdit: EventEmitter; - constructor() { + constructor( + private dialog: MatDialog + ) { this.onConfigurationEdit = new EventEmitter(); } public edit(): void { - this.onConfigurationEdit.emit(this.configuration); + this.dialog.open(EditAccountConfigurationComponent, { + width: '375px', + data: { + title: 'ACCOUNT_PAGE.CONFIGURATION.EDIT', + configuration: this.configuration + } + }) + .afterClosed() + .subscribe(configurationPair => this.onConfigurationEdit.emit(configurationPair)); } } diff --git a/src/app/account/account-sidebar/account-settings/account-configuration/edit-account-configuration.component.html b/src/app/account/account-sidebar/account-settings/account-configuration/edit-account-configuration.component.html index 0bea4536c1..d20f8ae782 100644 --- a/src/app/account/account-sidebar/account-settings/account-configuration/edit-account-configuration.component.html +++ b/src/app/account/account-sidebar/account-settings/account-configuration/edit-account-configuration.component.html @@ -28,7 +28,6 @@

mat-button color="primary" (click)="close()" - type="button" > {{ 'COMMON.CANCEL' | translate }} diff --git a/src/app/account/account-sidebar/account-settings/account-settings.component.html b/src/app/account/account-sidebar/account-settings/account-settings.component.html index 1a7348532e..35fd96fe5b 100644 --- a/src/app/account/account-sidebar/account-settings/account-settings.component.html +++ b/src/app/account/account-sidebar/account-settings/account-settings.component.html @@ -11,7 +11,7 @@

diff --git a/src/app/account/account-sidebar/account-settings/account-settings.component.ts b/src/app/account/account-sidebar/account-settings/account-settings.component.ts index 49877d1959..667701a091 100644 --- a/src/app/account/account-sidebar/account-settings/account-settings.component.ts +++ b/src/app/account/account-sidebar/account-settings/account-settings.component.ts @@ -1,44 +1,22 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { EditAccountConfigurationComponent } from './account-configuration/edit-account-configuration.component'; +import { + Component, + EventEmitter, + Input, + Output +} from '@angular/core'; import { Configuration } from '../../../shared/models/configuration.model'; -import { MatDialog } from '@angular/material'; -import { ConfigurationService } from '../../../shared/services/configuration.service'; import { Account } from '../../../shared/models/account.model'; @Component({ selector: 'cs-account-settings', templateUrl: 'account-settings.component.html' }) -export class AccountSettingsComponent implements OnInit { +export class AccountSettingsComponent { @Input() public account: Account; - public configurations: Array; + @Input() public configurations: Array; - constructor( - private dialog: MatDialog, - private configurationService: ConfigurationService - ) { } - - ngOnInit() { - this.getConfiguration(); - } - - public getConfiguration() { - this.configurationService.getList({ accountid: this.account.id }) - .subscribe(configurations => this.configurations = configurations); - } - - public editConfiguration(configuration: Configuration): void { - this.dialog.open(EditAccountConfigurationComponent, { - width: '375px', - data: { - title: 'ACCOUNT_PAGE.CONFIGURATION.EDIT', - configuration - } - }) - .afterClosed() - .switchMap(configurationPair => this.configurationService.updateConfiguration(configurationPair, this.account)) - .subscribe(() => this.getConfiguration()); - } + @Output() public onConfigurationEdit = new EventEmitter(); + constructor( ) { } } diff --git a/src/app/account/account-sidebar/account-sidebar.component.html b/src/app/account/account-sidebar/account-sidebar.component.html index 4f1ab0aa65..699c39ec57 100644 --- a/src/app/account/account-sidebar/account-sidebar.component.html +++ b/src/app/account/account-sidebar/account-sidebar.component.html @@ -12,11 +12,9 @@

{{ entity.name }}

- + - - - + diff --git a/src/app/account/account-sidebar/account-sidebar.component.scss b/src/app/account/account-sidebar/account-sidebar.component.scss index 5712066378..b1cfd47e18 100644 --- a/src/app/account/account-sidebar/account-sidebar.component.scss +++ b/src/app/account/account-sidebar/account-sidebar.component.scss @@ -1,5 +1,4 @@ :host ::ng-deep .name { - font-weight: bold; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; @@ -10,7 +9,6 @@ overflow: hidden; text-overflow: ellipsis; cursor: default; - max-width: 34% !important; text-align: right; white-space: nowrap; } @@ -22,11 +20,7 @@ } :host ::ng-deep .left { - max-width: 66% !important; - min-width: 66% !important; margin-right: 15px; - - span { width: 100%; } @@ -34,7 +28,6 @@ :host ::ng-deep .buttons { display: none; - min-width: 68px; margin-left: 10px; } @@ -49,5 +42,5 @@ } :host ::ng-deep .container:hover .buttons { - display: inline-block; + display: flex; } diff --git a/src/app/account/account-sidebar/account-sidebar.component.ts b/src/app/account/account-sidebar/account-sidebar.component.ts index 8db1ad89a0..8ee8acac76 100644 --- a/src/app/account/account-sidebar/account-sidebar.component.ts +++ b/src/app/account/account-sidebar/account-sidebar.component.ts @@ -1,11 +1,8 @@ -import { Component } from '@angular/core'; -import { SidebarComponent } from '../../shared/components/sidebar/sidebar.component'; +import { Component, EventEmitter, Input, Output } from '@angular/core'; import { Account } from '../../shared/models/account.model'; import { AccountService } from '../../shared/services/account.service'; import { NotificationService } from '../../shared/services/notification.service'; import { ActivatedRoute, Router } from '@angular/router'; -import { Observable } from 'rxjs/Observable'; -import { EntityDoesNotExistError } from '../../shared/components/sidebar/entity-does-not-exist-error'; import { AuthService } from '../../shared/services/auth.service'; @Component({ @@ -13,7 +10,11 @@ import { AuthService } from '../../shared/services/auth.service'; templateUrl: 'account-sidebar.component.html', styleUrls: ['account-sidebar.component.scss'] }) -export class AccountSidebarComponent extends SidebarComponent{ +export class AccountSidebarComponent { + + @Input() public entity: any; + @Output() public onAccountChanged = new EventEmitter(); + constructor( protected accountService: AccountService, protected notificationService: NotificationService, @@ -21,18 +22,13 @@ export class AccountSidebarComponent extends SidebarComponent{ protected router: Router, protected authService: AuthService ) { - super(accountService, notificationService, route, router); + } - protected loadEntity(id: string): Observable { - return this.accountService.get(id) - .switchMap(account => { - if (account) { - return Observable.of(account); - } else { - return Observable.throw(new EntityDoesNotExistError()); - } - }); + public tabIsActive(tabId: string) { + const path = this.route.snapshot; + const pathLastChild = path.firstChild.routeConfig.path; + return (tabId === pathLastChild) } public isAdmin() { diff --git a/src/app/account/account-sidebar/account-statistic/account-statistics.component.html b/src/app/account/account-sidebar/account-statistic/account-statistics.component.html index 1a18b427b0..08f3f73765 100644 --- a/src/app/account/account-sidebar/account-statistic/account-statistics.component.html +++ b/src/app/account/account-sidebar/account-statistic/account-statistics.component.html @@ -23,7 +23,7 @@

; +export class AccountStatisticsComponent { + @Input() public stats: Array; + @Output() public onStatsUpdate = new EventEmitter(); public resourceLabels = { [ResourceType.Instance]: 'ACCOUNT_PAGE.CONFIGURATION.VM_COUNT', @@ -33,18 +32,9 @@ export class AccountStatisticsComponent implements OnInit { }; constructor( - private resourceCountService: ResourceCountService, private dialogService: DialogService ) { } - ngOnInit() { - this.updateStats(); - } - - public updateStats(){ - this.resourceCountService.updateResourceCount(this.account) - .subscribe(stats => this.stats = stats); - } public confirmUpdateStats() { this.dialogService.confirm({ @@ -52,6 +42,6 @@ export class AccountStatisticsComponent implements OnInit { }) .onErrorResumeNext() .filter(res => Boolean(res)) - .subscribe(res => this.updateStats()); + .subscribe(res => this.onStatsUpdate.emit(res)); } } diff --git a/src/app/account/account/account-item.component.ts b/src/app/account/account/account-item.component.ts index 8f029a02db..2ef9ea32b8 100644 --- a/src/app/account/account/account-item.component.ts +++ b/src/app/account/account/account-item.component.ts @@ -1,4 +1,10 @@ -import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; +import { + Component, + EventEmitter, + Input, + Output, + ViewChild +} from '@angular/core'; import { MatMenuTrigger } from '@angular/material'; import { AuthService } from '../../shared/services/auth.service'; import { Account } from '../../shared/models/account.model'; @@ -14,7 +20,7 @@ export class AccountItemComponent { @Input() public isSelected: (account) => boolean; @Output() public onClick = new EventEmitter(); @Output() public onAccountChanged = new EventEmitter(); - @ViewChild(MatMenuTrigger) public mdMenuTrigger: MatMenuTrigger; + @ViewChild(MatMenuTrigger) public matMenuTrigger: MatMenuTrigger; readonly stateTranslations = stateTranslations; @@ -23,7 +29,7 @@ export class AccountItemComponent { public handleClick(e: MouseEvent): void { e.stopPropagation(); - if (!this.mdMenuTrigger || !this.mdMenuTrigger.menuOpen) { + if (!this.matMenuTrigger || !this.matMenuTrigger.menuOpen) { this.onClick.emit(this.item); } } diff --git a/src/app/account/accounts.module.ts b/src/app/account/accounts.module.ts index c82de8b6cb..26fa8e333d 100644 --- a/src/app/account/accounts.module.ts +++ b/src/app/account/accounts.module.ts @@ -12,7 +12,8 @@ import { MatMenuModule, MatSelectModule, MatTabsModule, - MatTooltipModule + MatTooltipModule, + MatInputModule } from '@angular/material'; import { AccountItemComponent } from './account/account-item.component'; import { DynamicModule } from 'ng-dynamic-component'; @@ -25,16 +26,23 @@ import { AccountDetailsComponent } from './account-sidebar/account-details/accou import { AccountConfigurationComponent } from './account-sidebar/account-settings/account-configuration/account-configuration.component'; import { EditAccountConfigurationComponent } from './account-sidebar/account-settings/account-configuration/edit-account-configuration.component'; import { AccountPageContainerComponent } from './account-container/account.container'; -import { AccountsEffects } from './redux/accounts.effects'; -import { DomainsEffects } from '../domains/redux/domains.effects'; -import { RolesEffects } from '../roles/redux/roles.effects'; +import { AccountsEffects } from '../reducers/accounts/redux/accounts.effects'; +import { DomainsEffects } from '../reducers/domains/redux/domains.effects'; +import { RolesEffects } from '../reducers/roles/redux/roles.effects'; import { StoreModule } from '@ngrx/store'; import { EffectsModule } from '@ngrx/effects'; -import { accountReducers } from './redux/accounts.reducers'; -import { domainReducers } from '../domains/redux/domains.reducers' -import { roleReducers } from '../roles/redux/roles.reducers'; +import { accountReducers } from '../reducers/accounts/redux/accounts.reducers'; +import { domainReducers } from '../reducers/domains/redux/domains.reducers' +import { roleReducers } from '../reducers/roles/redux/roles.reducers'; import { DraggableSelectModule } from '../shared/components/draggable-select/draggable-select.module'; - +import { AccountSidebarContainerComponent } from './account-container/account-sidebar.container'; +import { AccountDetailsContainerComponent } from './account-container/account-details.container'; +import { configurationReducers } from '../reducers/configuration/redux/configurations.reducers'; +import { ConfigurationEffects } from '../reducers/configuration/redux/configurations.effects'; +import { resourceLimitsReducers } from '../reducers/resource-limit/redux/resource-limits.reducers'; +import { ResourceLimitsEffects } from '../reducers/resource-limit/redux/resource-limits.effects'; +import { ResourceCountsEffects } from '../reducers/resource-count/redux/resource-counts.effects'; +import { resourceCountsReducers } from '../reducers/resource-count/redux/resource-counts.reducers'; @NgModule({ imports: [ @@ -47,14 +55,25 @@ import { DraggableSelectModule } from '../shared/components/draggable-select/dra MatButtonModule, MatSelectModule, MatIconModule, + MatInputModule, RouterModule, SharedModule, TranslateModule, DraggableSelectModule, + StoreModule.forFeature('configurations', configurationReducers), + StoreModule.forFeature('resourceLimits', resourceLimitsReducers), + StoreModule.forFeature('resourceCounts', resourceCountsReducers), StoreModule.forFeature('accounts', accountReducers), StoreModule.forFeature('domains', domainReducers), StoreModule.forFeature('roles', roleReducers), - EffectsModule.forFeature([AccountsEffects, DomainsEffects, RolesEffects]), + EffectsModule.forFeature([ + AccountsEffects, + DomainsEffects, + RolesEffects, + ConfigurationEffects, + ResourceLimitsEffects, + ResourceCountsEffects + ]), ], declarations: [ AccountPageComponent, @@ -68,6 +87,8 @@ import { DraggableSelectModule } from '../shared/components/draggable-select/dra AccountDetailsComponent, AccountConfigurationComponent, AccountPageContainerComponent, + AccountSidebarContainerComponent, + AccountDetailsContainerComponent, EditAccountConfigurationComponent, ], entryComponents: [ diff --git a/src/app/account/accounts.routing.ts b/src/app/account/accounts.routing.ts index bc77e201a0..6a5bd507ab 100644 --- a/src/app/account/accounts.routing.ts +++ b/src/app/account/accounts.routing.ts @@ -1,8 +1,8 @@ import { Routes } from '@angular/router'; import { AuthGuard } from '../shared/services/auth-guard.service'; -import { AccountSidebarComponent } from './account-sidebar/account-sidebar.component'; -import { AccountDetailsComponent } from './account-sidebar/account-details/account-details.component'; import { AccountPageContainerComponent } from './account-container/account.container'; +import { AccountSidebarContainerComponent } from './account-container/account-sidebar.container'; +import { AccountDetailsContainerComponent } from './account-container/account-details.container'; export const accountsRoutes: Routes = [ { @@ -15,7 +15,7 @@ export const accountsRoutes: Routes = [ component: AccountCreationDialogComponent },*/ { path: ':id', - component: AccountSidebarComponent, + component: AccountSidebarContainerComponent, canActivate: [AuthGuard], children: [ { @@ -25,7 +25,7 @@ export const accountsRoutes: Routes = [ }, { path: 'account', - component: AccountDetailsComponent + component: AccountDetailsContainerComponent }, ] } diff --git a/src/app/domains/redux/domains.effects.ts b/src/app/domains/redux/domains.effects.ts deleted file mode 100644 index 69b0049b67..0000000000 --- a/src/app/domains/redux/domains.effects.ts +++ /dev/null @@ -1,34 +0,0 @@ -import { Injectable } from '@angular/core'; -import { Actions, Effect } from '@ngrx/effects'; -import { Observable } from 'rxjs/Observable'; -import { Action } from '@ngrx/store'; -import { DomainService } from '../../shared/services/domain.service'; -import { Domain } from '../../shared/models/domain.model'; -import { AuthService } from '../../shared/services/auth.service'; - -import * as domainActions from './domains.actions'; - - -@Injectable() -export class DomainsEffects { - - @Effect() - loadDomains$: Observable = this.actions$ - .ofType(domainActions.LOAD_DOMAINS_REQUEST) - .switchMap((action: domainActions.LoadDomainsRequest) => { - return this.authService.isAdmin() - ? this.domainService.getList(action.payload) - .map((domains: Domain[]) => { - return new domainActions.LoadDomainsResponse(domains); - }) - .catch(() => Observable.of(new domainActions.LoadDomainsResponse([]))) - : Observable.of(new domainActions.LoadDomainsResponse([])); - }); - - constructor( - private actions$: Actions, - private domainService: DomainService, - private authService: AuthService - ) { - } -} diff --git a/src/app/events/containers/event-list.container.ts b/src/app/events/containers/event-list.container.ts index 053ef3e4f7..e3d55ebd2b 100644 --- a/src/app/events/containers/event-list.container.ts +++ b/src/app/events/containers/event-list.container.ts @@ -5,7 +5,7 @@ import { import { State } from '../../reducers/index'; import { Store } from '@ngrx/store'; import * as eventAction from '../redux/events.actions'; -import * as accountAction from '../../account/redux/accounts.actions'; +import * as accountAction from '../../reducers/accounts/redux/accounts.actions'; import * as debounce from 'lodash/debounce'; import { FilterService } from '../../shared/services/filter.service'; import { @@ -14,7 +14,7 @@ import { } from '@angular/router'; import { SessionStorageService } from '../../shared/services/session-storage.service'; import * as fromEvents from '../redux/events.reducers'; -import * as fromAccounts from '../../account/redux/accounts.reducers'; +import * as fromAccounts from '../../reducers/accounts/redux/accounts.reducers'; import { LanguageService } from '../../shared/services/language.service'; import { WithUnsubscribe } from '../../utils/mixins/with-unsubscribe'; import { AuthService } from '../../shared/services/auth.service'; @@ -46,7 +46,7 @@ export class EventListContainerComponent extends WithUnsubscribe() implements On readonly firstDayOfWeek$ = this.languageService.getFirstDayOfWeek(); readonly events$ = this.store.select(fromEvents.selectFilteredEvents); - readonly accounts$ = this.store.select(fromAccounts.accounts); + readonly accounts$ = this.store.select(fromAccounts.selectAll); readonly query$ = this.store.select(fromEvents.filterQuery); readonly loading$ = this.store.select(fromEvents.isLoading); readonly filters$ = this.store.select(fromEvents.filters); diff --git a/src/app/events/redux/events.reducers.ts b/src/app/events/redux/events.reducers.ts index acd70e800a..01bf1d11e7 100644 --- a/src/app/events/redux/events.reducers.ts +++ b/src/app/events/redux/events.reducers.ts @@ -9,7 +9,7 @@ import { } from '@ngrx/entity'; import * as event from './events.actions'; import { Event } from '../event.model'; -import { accounts } from '../../account/redux/accounts.reducers'; +import * as fromAccounts from '../../reducers/accounts/redux/accounts.reducers'; import moment = require('moment'); /** @@ -179,7 +179,7 @@ export const selectFilteredEvents = createSelector( filterSelectedTypes, filterSelectedLevels, filterSelectedAccountIds, - accounts, + fromAccounts.selectAll, (events, query, selectedTypes, selectedLevels, selectedAccountIds, accounts) => { const queryLower = query && query.toLowerCase(); const typeMap = selectedTypes.reduce((m, i) => ({ ...m, [i]: i }), {}); @@ -198,9 +198,10 @@ export const selectFilteredEvents = createSelector( !!levelsMap[event.level]; }; - const selectedAccounts = accounts.filter(account => selectedAccountIds.find(id => id === account.id)); - const accountsMap = selectedAccounts.reduce((m, i) => ({...m, [i.name]: i }), {}); - const domainsMap = selectedAccounts.reduce((m, i) => ({...m, [i.domainid]: i }), {}); + const selectedAccounts = accounts.filter( + account => selectedAccountIds.find(id => id === account.id)); + const accountsMap = selectedAccounts.reduce((m, i) => ({ ...m, [i.name]: i }), {}); + const domainsMap = selectedAccounts.reduce((m, i) => ({ ...m, [i.domainid]: i }), {}); const selectedAccountIdsFilter = event => !selectedAccountIds.length || (accountsMap[event.account] && domainsMap[event.domainId]); diff --git a/src/app/account/redux/accounts.actions.ts b/src/app/reducers/accounts/redux/accounts.actions.ts similarity index 74% rename from src/app/account/redux/accounts.actions.ts rename to src/app/reducers/accounts/redux/accounts.actions.ts index 67f53690e2..4b8fbb12f9 100644 --- a/src/app/account/redux/accounts.actions.ts +++ b/src/app/reducers/accounts/redux/accounts.actions.ts @@ -3,6 +3,7 @@ import { Action } from '@ngrx/store'; export const LOAD_ACCOUNTS_REQUEST = '[ACCOUNTS] LOAD_ACCOUNTS_REQUEST'; export const LOAD_ACCOUNTS_RESPONSE = '[ACCOUNTS] LOAD_ACCOUNTS_RESPONSE'; export const ACCOUNT_FILTER_UPDATE = '[ACCOUNTS] ACCOUNT_FILTER_UPDATE'; +export const LOAD_SELECTED_ACCOUNT = '[ACCOUNTS] LOAD_SELECTED_ACCOUNT'; export class LoadAccountsRequest implements Action { type = LOAD_ACCOUNTS_REQUEST; @@ -20,6 +21,14 @@ export class LoadAccountsResponse implements Action { } +export class LoadSelectedAccount implements Action { + type = LOAD_SELECTED_ACCOUNT; + + constructor(public payload: string) { + } + +} + export class AccountFilterUpdate implements Action { type = ACCOUNT_FILTER_UPDATE; @@ -29,4 +38,4 @@ export class AccountFilterUpdate implements Action { } -export type Actions = LoadAccountsRequest | LoadAccountsResponse | AccountFilterUpdate; +export type Actions = LoadAccountsRequest | LoadAccountsResponse | AccountFilterUpdate | LoadSelectedAccount; diff --git a/src/app/account/redux/accounts.effects.ts b/src/app/reducers/accounts/redux/accounts.effects.ts similarity index 88% rename from src/app/account/redux/accounts.effects.ts rename to src/app/reducers/accounts/redux/accounts.effects.ts index a12cd9b18e..8d63d64619 100644 --- a/src/app/account/redux/accounts.effects.ts +++ b/src/app/reducers/accounts/redux/accounts.effects.ts @@ -1,9 +1,12 @@ import { Injectable } from '@angular/core'; -import { Actions, Effect } from '@ngrx/effects'; +import { + Actions, + Effect +} from '@ngrx/effects'; import { Observable } from 'rxjs/Observable'; import * as accountActions from './accounts.actions'; import { Action } from '@ngrx/store'; -import { AccountService } from '../../shared/services/account.service'; +import { AccountService } from '../../../shared/services/account.service'; @Injectable() export class AccountsEffects { diff --git a/src/app/account/redux/accounts.reducers.ts b/src/app/reducers/accounts/redux/accounts.reducers.ts similarity index 89% rename from src/app/account/redux/accounts.reducers.ts rename to src/app/reducers/accounts/redux/accounts.reducers.ts index cfd0d16bca..d6fdcb2aec 100644 --- a/src/app/account/redux/accounts.reducers.ts +++ b/src/app/reducers/accounts/redux/accounts.reducers.ts @@ -8,7 +8,7 @@ import { EntityState } from '@ngrx/entity'; import * as event from './accounts.actions'; -import { Account } from '../../shared/models/account.model'; +import { Account } from '../../../shared/models/account.model'; /** * @ngrx/entity provides a predefined interface for handling @@ -19,6 +19,7 @@ import { Account } from '../../shared/models/account.model'; */ export interface State extends EntityState { loading: boolean, + selectedAccountId: string | null; filters: { selectedDomainIds: string[], selectedRoleNames: string[], @@ -55,8 +56,9 @@ export const adapter: EntityAdapter = createEntityAdapter({ */ export const initialState: State = adapter.getInitialState({ loading: false, + selectedAccountId: null, filters: { - selectedDomainIds:[], + selectedDomainIds: [], selectedRoleTypes: [], selectedRoleNames: [], selectedStates: [], @@ -101,6 +103,13 @@ export function reducer( }; } + case event.LOAD_SELECTED_ACCOUNT: { + return { + ...state, + selectedAccountId: action.payload + }; + } + default: { return state; @@ -128,7 +137,16 @@ export const isLoading = createSelector( state => state.loading ); +export const getSelectedId = createSelector( + getAccountsEntitiesState, + state => state.selectedAccountId +); +export const getSelectedAccount = createSelector( + getAccountsState, + getSelectedId, + (state, selectedId) => state.list.entities[selectedId] +); export const filters = createSelector( getAccountsEntitiesState, @@ -156,11 +174,6 @@ export const filterSelectedStates = createSelector( state => state.selectedStates ); -export const accounts = createSelector( - selectAll, - (accounts) => accounts -); - export const selectFilteredAccounts = createSelector( selectAll, filterSelectedRoleTypes, diff --git a/src/app/reducers/configuration/redux/configurations.actions.ts b/src/app/reducers/configuration/redux/configurations.actions.ts new file mode 100644 index 0000000000..c63ba0559a --- /dev/null +++ b/src/app/reducers/configuration/redux/configurations.actions.ts @@ -0,0 +1,44 @@ +import { Action } from '@ngrx/store'; + +export const LOAD_CONFIGURATIONS_REQUEST = '[CONFIGURATIONS] LOAD_CONFIGURATIONS_REQUEST'; +export const LOAD_CONFIGURATIONS_RESPONSE = '[CONFIGURATIONS] LOAD_CONFIGURATIONS_RESPONSE'; +export const UPDATE_CONFIGURATIONS_REQUEST = '[CONFIGURATIONS] UPDATE_CONFIGURATIONS_REQUEST'; +export const UPDATE_CONFIGURATIONS_ERROR = '[CONFIGURATIONS] UPDATE_CONFIGURATIONS_ERROR'; + +export class LoadConfigurationsRequest implements Action { + type = LOAD_CONFIGURATIONS_REQUEST; + + constructor(public payload?: any) { + } + +} + +export class LoadConfigurationsResponse implements Action { + type = LOAD_CONFIGURATIONS_RESPONSE; + + constructor(public payload: any ) { + } + +} + +export class UpdateConfigurationRequest implements Action { + type = UPDATE_CONFIGURATIONS_REQUEST; + + constructor(public payload: any ) { + } + +} + +export class UpdateConfigurationError implements Action { + readonly type = UPDATE_CONFIGURATIONS_ERROR; + + constructor(public payload: Error) { + } + +} + + +export type Actions = LoadConfigurationsRequest + | LoadConfigurationsResponse + | UpdateConfigurationRequest + | UpdateConfigurationError; diff --git a/src/app/reducers/configuration/redux/configurations.effects.ts b/src/app/reducers/configuration/redux/configurations.effects.ts new file mode 100644 index 0000000000..b0c44bda96 --- /dev/null +++ b/src/app/reducers/configuration/redux/configurations.effects.ts @@ -0,0 +1,65 @@ +import { Injectable } from '@angular/core'; +import { + Actions, + Effect +} from '@ngrx/effects'; +import { Observable } from 'rxjs/Observable'; +import * as configurationActions from './configurations.actions'; +import { Action } from '@ngrx/store'; +import { ConfigurationService } from '../../../shared/services/configuration.service'; +import { Configuration } from '../../../shared/models/configuration.model'; +import { DialogService } from '../../../dialog/dialog-service/dialog.service'; + +@Injectable() +export class ConfigurationEffects { + + @Effect() + loadConfigurations$: Observable = this.actions$ + .ofType(configurationActions.LOAD_CONFIGURATIONS_REQUEST) + .switchMap((action: configurationActions.LoadConfigurationsRequest) => { + return this.configurationService.getList(action.payload) + .map((configurations: Configuration[]) => { + return new configurationActions.LoadConfigurationsResponse(configurations); + }) + .catch(() => Observable.of(new configurationActions.LoadConfigurationsResponse([]))); + }); + + @Effect() + updateConfiguration$: Observable = this.actions$ + .ofType(configurationActions.UPDATE_CONFIGURATIONS_REQUEST) + .switchMap((action: configurationActions.UpdateConfigurationRequest) => { + return this.configurationService.updateConfiguration( + action.payload.configuration, + action.payload.account) + .map(() => { + return new configurationActions.LoadConfigurationsRequest({ + accountid: action.payload.account.id + }) + }) + .catch((error) => Observable.of(new configurationActions.UpdateConfigurationError(error))); + }); + + @Effect({ dispatch: false }) + updateConfigurationError$: Observable = this.actions$ + .ofType(configurationActions.UPDATE_CONFIGURATIONS_ERROR) + .do((action: configurationActions.UpdateConfigurationError) => { + this.handleError(action.payload); + }); + + + constructor( + private actions$: Actions, + private configurationService: ConfigurationService, + private dialogService: DialogService + ) { + } + + private handleError(error): void { + this.dialogService.alert({ + message: { + translationToken: error.message, + interpolateParams: error.params + } + }); + } +} diff --git a/src/app/reducers/configuration/redux/configurations.reducers.ts b/src/app/reducers/configuration/redux/configurations.reducers.ts new file mode 100644 index 0000000000..486a97efb4 --- /dev/null +++ b/src/app/reducers/configuration/redux/configurations.reducers.ts @@ -0,0 +1,107 @@ +import { + createFeatureSelector, + createSelector +} from '@ngrx/store'; +import { + createEntityAdapter, + EntityAdapter, + EntityState +} from '@ngrx/entity'; +import * as event from './configurations.actions'; +import { Configuration } from '../../../shared/models/configuration.model'; + +/** + * @ngrx/entity provides a predefined interface for handling + * a structured dictionary of records. This interface + * includes an array of ids, and a dictionary of the provided + * model type by id. This interface is extended to include + * any additional interface properties. + */ +export interface State extends EntityState { + loading: boolean +} + +export interface ConfigurationsState { + list: State; +} + +export const configurationReducers = { + list: reducer, +}; + +/** + * createEntityAdapter creates many an object of helper + * functions for single or multiple operations + * against the dictionary of records. The configuration + * object takes a record id selector function and + * a sortComparer option which is set to a compare + * function if the records are to be sorted. + */ +export const adapter: EntityAdapter = createEntityAdapter({ + selectId: (item: Configuration) => item.name, + sortComparer: false +}); + +/** getInitialState returns the default initial state + * for the generated entity state. Initial state + * additional properties can also be defined. + */ +export const initialState: State = adapter.getInitialState({ + loading: false +}); + +export function reducer( + state = initialState, + action: event.Actions +): State { + switch (action.type) { + case event.LOAD_CONFIGURATIONS_REQUEST: { + return { + ...state, + loading: true + }; + } + + case event.LOAD_CONFIGURATIONS_RESPONSE: { + + const configurations = action.payload; + + return { + /** + * The addMany function provided by the created adapter + * adds many records to the entity dictionary + * and returns a new state including those records. If + * the collection is to be sorted, the adapter will + * sort each record upon entry into the sorted array. + */ + ...adapter.addAll(configurations, state), + loading: false + }; + } + default: { + return state; + } + } +} + + +export const getConfigurationsState = createFeatureSelector('configurations'); + +export const getConfigurationsEntitiesState = createSelector( + getConfigurationsState, + state => state.list +); + +export const { + selectIds, + selectEntities, + selectAll, + selectTotal, +} = adapter.getSelectors(getConfigurationsEntitiesState); + +export const isLoading = createSelector( + getConfigurationsEntitiesState, + state => state.loading +); + + diff --git a/src/app/domains/redux/domains.actions.ts b/src/app/reducers/domains/redux/domains.actions.ts similarity index 92% rename from src/app/domains/redux/domains.actions.ts rename to src/app/reducers/domains/redux/domains.actions.ts index 243fb5b146..fd1aac0d08 100644 --- a/src/app/domains/redux/domains.actions.ts +++ b/src/app/reducers/domains/redux/domains.actions.ts @@ -14,8 +14,9 @@ export class LoadDomainsRequest implements Action { export class LoadDomainsResponse implements Action { type = LOAD_DOMAINS_RESPONSE; - constructor(public payload: any) { + constructor(public payload: any ) { } + } export type Actions = LoadDomainsResponse | LoadDomainsRequest; diff --git a/src/app/reducers/domains/redux/domains.effects.ts b/src/app/reducers/domains/redux/domains.effects.ts new file mode 100644 index 0000000000..accc4eeb72 --- /dev/null +++ b/src/app/reducers/domains/redux/domains.effects.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { + Actions, + Effect +} from '@ngrx/effects'; +import { Observable } from 'rxjs/Observable'; +import * as domainActions from './domains.actions'; +import { Action } from '@ngrx/store'; +import { DomainService } from '../../../shared/services/domain.service'; +import { Domain } from '../../../shared/models/domain.model'; + +@Injectable() +export class DomainsEffects { + + @Effect() + loadDomains$: Observable = this.actions$ + .ofType(domainActions.LOAD_DOMAINS_REQUEST) + .switchMap((action: domainActions.LoadDomainsRequest) => { + return this.domainService.getList(action.payload) + .map((domains: Domain[]) => { + return new domainActions.LoadDomainsResponse(domains); + }) + .catch(() => Observable.of(new domainActions.LoadDomainsResponse([]))); + }); + + constructor( + private actions$: Actions, + private domainService: DomainService + ) { } +} diff --git a/src/app/domains/redux/domains.reducers.ts b/src/app/reducers/domains/redux/domains.reducers.ts similarity index 94% rename from src/app/domains/redux/domains.reducers.ts rename to src/app/reducers/domains/redux/domains.reducers.ts index 26f1f96b68..4d4a248690 100644 --- a/src/app/domains/redux/domains.reducers.ts +++ b/src/app/reducers/domains/redux/domains.reducers.ts @@ -7,7 +7,7 @@ import { EntityAdapter, EntityState } from '@ngrx/entity'; -import { Domain } from '../../shared/models/domain.model'; +import { Domain } from '../../../shared/models/domain.model'; import * as event from './domains.actions'; @@ -103,8 +103,3 @@ export const isLoading = createSelector( getDomainsEntitiesState, state => state.loading ); - -export const domains = createSelector( - selectAll, - (domainsList) => domainsList -); diff --git a/src/app/reducers/resource-count/redux/resource-counts.actions.ts b/src/app/reducers/resource-count/redux/resource-counts.actions.ts new file mode 100644 index 0000000000..16ac5890ca --- /dev/null +++ b/src/app/reducers/resource-count/redux/resource-counts.actions.ts @@ -0,0 +1,22 @@ +import { Action } from '@ngrx/store'; + +export const LOAD_RESOURCE_COUNTS_REQUEST = '[RESOURCE_COUNTS] LOAD_RESOURCE_COUNTS_REQUEST'; +export const LOAD_RESOURCE_COUNTS_RESPONSE = '[RESOURCE_COUNTS] LOAD_RESOURCE_COUNTS_RESPONSE'; + +export class LoadResourceCountsRequest implements Action { + type = LOAD_RESOURCE_COUNTS_REQUEST; + + constructor(public payload?: any) { + } + +} + +export class LoadResourceCountsResponse implements Action { + type = LOAD_RESOURCE_COUNTS_RESPONSE; + + constructor(public payload: any ) { + } + +} + +export type Actions = LoadResourceCountsResponse | LoadResourceCountsRequest; diff --git a/src/app/reducers/resource-count/redux/resource-counts.effects.ts b/src/app/reducers/resource-count/redux/resource-counts.effects.ts new file mode 100644 index 0000000000..45b2aac981 --- /dev/null +++ b/src/app/reducers/resource-count/redux/resource-counts.effects.ts @@ -0,0 +1,30 @@ +import { Injectable } from '@angular/core'; +import { + Actions, + Effect +} from '@ngrx/effects'; +import { Observable } from 'rxjs/Observable'; +import * as resourceCountActions from './resource-counts.actions'; +import { Action } from '@ngrx/store'; +import { ResourceCountService } from '../../../shared/services/resource-count.service'; +import { ResourceCount } from '../../../shared/models/resource-count.model'; + +@Injectable() +export class ResourceCountsEffects { + + @Effect() + loadResourceLimits$: Observable = this.actions$ + .ofType(resourceCountActions.LOAD_RESOURCE_COUNTS_REQUEST) + .switchMap((action: resourceCountActions.LoadResourceCountsRequest) => { + return this.resourceCountService.updateResourceCount(action.payload) + .map((stats: ResourceCount[]) => { + return new resourceCountActions.LoadResourceCountsResponse(stats); + }) + .catch(() => Observable.of(new resourceCountActions.LoadResourceCountsResponse([]))); + }); + + constructor( + private actions$: Actions, + private resourceCountService: ResourceCountService + ) { } +} diff --git a/src/app/reducers/resource-count/redux/resource-counts.reducers.ts b/src/app/reducers/resource-count/redux/resource-counts.reducers.ts new file mode 100644 index 0000000000..e354108860 --- /dev/null +++ b/src/app/reducers/resource-count/redux/resource-counts.reducers.ts @@ -0,0 +1,108 @@ +import { + createFeatureSelector, + createSelector +} from '@ngrx/store'; +import { + createEntityAdapter, + EntityAdapter, + EntityState +} from '@ngrx/entity'; +import * as event from './resource-counts.actions'; +import { ResourceCount } from '../../../shared/models/resource-count.model'; + +/** + * @ngrx/entity provides a predefined interface for handling + * a structured dictionary of records. This interface + * includes an array of ids, and a dictionary of the provided + * model type by id. This interface is extended to include + * any additional interface properties. + */ +export interface State extends EntityState { + loading: boolean +} + +export interface ResourceCountsState { + list: State; +} + +export const resourceCountsReducers = { + list: reducer, +}; + +/** + * createEntityAdapter creates many an object of helper + * functions for single or multiple operations + * against the dictionary of records. The configuration + * object takes a record id selector function and + * a sortComparer option which is set to a compare + * function if the records are to be sorted. + */ +export const adapter: EntityAdapter = createEntityAdapter({ + selectId: (item: ResourceCount) => item.resourcetype.toString(), + sortComparer: false +}); + +/** getInitialState returns the default initial state + * for the generated entity state. Initial state + * additional properties can also be defined. + */ +export const initialState: State = adapter.getInitialState({ + loading: false +}); + +export function reducer( + state = initialState, + action: event.Actions +): State { + switch (action.type) { + case event.LOAD_RESOURCE_COUNTS_REQUEST: { + return { + ...state, + loading: true + }; + } + case event.LOAD_RESOURCE_COUNTS_RESPONSE: { + + const resourceCounts = action.payload; + + return { + /** + * The addMany function provided by the created adapter + * adds many records to the entity dictionary + * and returns a new state including those records. If + * the collection is to be sorted, the adapter will + * sort each record upon entry into the sorted array. + */ + ...adapter.addAll(resourceCounts, state), + loading: false + }; + } + + + default: { + return state; + } + } +} + + +export const getResourceCountsState = createFeatureSelector('resourceCounts'); + +export const getResourceCountsEntitiesState = createSelector( + getResourceCountsState, + state => state.list +); + +export const { + selectIds, + selectEntities, + selectAll, + selectTotal, +} = adapter.getSelectors(getResourceCountsEntitiesState); + +export const isLoading = createSelector( + getResourceCountsEntitiesState, + state => state.loading +); + + diff --git a/src/app/reducers/resource-limit/redux/resource-limits.actions.ts b/src/app/reducers/resource-limit/redux/resource-limits.actions.ts new file mode 100644 index 0000000000..7eb8b6bd36 --- /dev/null +++ b/src/app/reducers/resource-limit/redux/resource-limits.actions.ts @@ -0,0 +1,43 @@ +import { Action } from '@ngrx/store'; + +export const LOAD_RESOURCE_LIMITS_REQUEST = '[RESOURCE_LIMITS] LOAD_RESOURCE_LIMITS_REQUEST'; +export const LOAD_RESOURCE_LIMITS_RESPONSE = '[RESOURCE_LIMITS] LOAD_RESOURCE_LIMITS_RESPONSE'; +export const UPDATE_RESOURCE_LIMITS_REQUEST = '[RESOURCE_LIMITS] UPDATE_RESOURCE_LIMITS_REQUEST'; +export const UPDATE_RESOURCE_LIMITS_ERROR = '[RESOURCE_LIMITS] UPDATE_RESOURCE_LIMITS_ERROR'; + +export class LoadResourceLimitsRequest implements Action { + type = LOAD_RESOURCE_LIMITS_REQUEST; + + constructor(public payload?: any) { + } + +} + +export class LoadResourceLimitsResponse implements Action { + type = LOAD_RESOURCE_LIMITS_RESPONSE; + + constructor(public payload: any ) { + } + +} + +export class UpdateResourceLimitsRequest implements Action { + type = UPDATE_RESOURCE_LIMITS_REQUEST; + + constructor(public payload: { limits: any[], account: any } ) { + } + +} + +export class UpdateResourceLimitsError implements Action { + readonly type = UPDATE_RESOURCE_LIMITS_ERROR; + + constructor(public payload: Error) { + } + +} + +export type Actions = LoadResourceLimitsResponse + | LoadResourceLimitsRequest + | UpdateResourceLimitsRequest + | UpdateResourceLimitsError; diff --git a/src/app/reducers/resource-limit/redux/resource-limits.effects.ts b/src/app/reducers/resource-limit/redux/resource-limits.effects.ts new file mode 100644 index 0000000000..564088c5c6 --- /dev/null +++ b/src/app/reducers/resource-limit/redux/resource-limits.effects.ts @@ -0,0 +1,65 @@ +import { Injectable } from '@angular/core'; +import { + Actions, + Effect +} from '@ngrx/effects'; +import { Observable } from 'rxjs/Observable'; +import * as resourceLimitActions from './resource-limits.actions'; +import { Action } from '@ngrx/store'; +import { ResourceLimitService } from '../../../shared/services/resource-limit.service'; +import { ResourceLimit } from '../../../shared/models/resource-limit.model'; +import { DialogService } from '../../../dialog/dialog-service/dialog.service'; + +@Injectable() +export class ResourceLimitsEffects { + + @Effect() + loadResourseLimits$: Observable = this.actions$ + .ofType(resourceLimitActions.LOAD_RESOURCE_LIMITS_REQUEST) + .switchMap((action: resourceLimitActions.LoadResourceLimitsRequest) => { + return this.resourceLimitService.getList(action.payload) + .map((limits: ResourceLimit[]) => { + return new resourceLimitActions.LoadResourceLimitsResponse(limits); + }) + .catch(() => Observable.of(new resourceLimitActions.LoadResourceLimitsResponse([]))); + }); + + @Effect() + updateResourceLimits$: Observable = this.actions$ + .ofType(resourceLimitActions.UPDATE_RESOURCE_LIMITS_REQUEST) + .switchMap((action: resourceLimitActions.UpdateResourceLimitsRequest) => { + const observes = action.payload.limits.map(limit => + this.resourceLimitService.updateResourceLimit(limit, action.payload.account)); + return Observable.forkJoin(observes) + .map(() => { + return new resourceLimitActions.LoadResourceLimitsRequest({ + domainid: action.payload.account.domainid, + account: action.payload.account.name + }); + }) + .catch((error) => Observable.of(new resourceLimitActions.UpdateResourceLimitsError(error))); + }); + + @Effect({ dispatch: false }) + updateResourceLimitsError$: Observable = this.actions$ + .ofType(resourceLimitActions.UPDATE_RESOURCE_LIMITS_ERROR) + .do((action: resourceLimitActions.UpdateResourceLimitsError) => { + this.handleError(action.payload); + }); + + constructor( + private actions$: Actions, + private resourceLimitService: ResourceLimitService, + private dialogService: DialogService + ) { } + + private handleError(error): void { + this.dialogService.alert({ + message: { + translationToken: error.message, + interpolateParams: error.params + } + }); + } + +} diff --git a/src/app/reducers/resource-limit/redux/resource-limits.reducers.ts b/src/app/reducers/resource-limit/redux/resource-limits.reducers.ts new file mode 100644 index 0000000000..00f8b1d035 --- /dev/null +++ b/src/app/reducers/resource-limit/redux/resource-limits.reducers.ts @@ -0,0 +1,106 @@ +import { + createFeatureSelector, + createSelector +} from '@ngrx/store'; +import { + createEntityAdapter, + EntityAdapter, + EntityState +} from '@ngrx/entity'; +import * as event from './resource-limits.actions'; +import { ResourceLimit } from '../../../shared/models/resource-limit.model'; + +/** + * @ngrx/entity provides a predefined interface for handling + * a structured dictionary of records. This interface + * includes an array of ids, and a dictionary of the provided + * model type by id. This interface is extended to include + * any additional interface properties. + */ +export interface State extends EntityState { + loading: boolean +} + +export interface ResourceLimitsState { + list: State; +} + +export const resourceLimitsReducers = { + list: reducer, +}; + +/** + * createEntityAdapter creates many an object of helper + * functions for single or multiple operations + * against the dictionary of records. The configuration + * object takes a record id selector function and + * a sortComparer option which is set to a compare + * function if the records are to be sorted. + */ +export const adapter: EntityAdapter = createEntityAdapter({ + selectId: (item: ResourceLimit) => item.resourcetype.toString(), + sortComparer: false +}); + +/** getInitialState returns the default initial state + * for the generated entity state. Initial state + * additional properties can also be defined. + */ +export const initialState: State = adapter.getInitialState({ + loading: false +}); + +export function reducer( + state = initialState, + action: event.Actions +): State { + switch (action.type) { + case event.LOAD_RESOURCE_LIMITS_REQUEST: { + return { + ...state, + loading: true + }; + } + case event.LOAD_RESOURCE_LIMITS_RESPONSE: { + + const resourceLimits = action.payload; + + return { + /** + * The addMany function provided by the created adapter + * adds many records to the entity dictionary + * and returns a new state including those records. If + * the collection is to be sorted, the adapter will + * sort each record upon entry into the sorted array. + */ + ...adapter.addAll(resourceLimits, state), + loading: false + }; + } + + + default: { + return state; + } + } +} + + +export const getResourceLimitsState = createFeatureSelector('resourceLimits'); + +export const getResourceLimitsEntitiesState = createSelector( + getResourceLimitsState, + state => state.list +); + +export const { + selectIds, + selectEntities, + selectAll, + selectTotal, +} = adapter.getSelectors(getResourceLimitsEntitiesState); + +export const isLoading = createSelector( + getResourceLimitsEntitiesState, + state => state.loading +); diff --git a/src/app/roles/redux/roles.actions.ts b/src/app/reducers/roles/redux/roles.actions.ts similarity index 100% rename from src/app/roles/redux/roles.actions.ts rename to src/app/reducers/roles/redux/roles.actions.ts diff --git a/src/app/roles/redux/roles.effects.ts b/src/app/reducers/roles/redux/roles.effects.ts similarity index 56% rename from src/app/roles/redux/roles.effects.ts rename to src/app/reducers/roles/redux/roles.effects.ts index 622cd9989b..cfb385cca8 100644 --- a/src/app/roles/redux/roles.effects.ts +++ b/src/app/reducers/roles/redux/roles.effects.ts @@ -1,11 +1,13 @@ import { Injectable } from '@angular/core'; -import { Actions, Effect } from '@ngrx/effects'; +import { + Actions, + Effect +} from '@ngrx/effects'; import { Observable } from 'rxjs/Observable'; import * as roleActions from './roles.actions'; import { Action } from '@ngrx/store'; -import { RoleService } from '../../shared/services/role.service'; -import { Role } from '../../shared/models/role.model'; -import { AuthService } from '../../shared/services/auth.service'; +import { RoleService } from '../../../shared/services/role.service'; +import { Role } from '../../../shared/models/role.model'; @Injectable() export class RolesEffects { @@ -14,17 +16,15 @@ export class RolesEffects { loadRoless$: Observable = this.actions$ .ofType(roleActions.LOAD_ROLES_REQUEST) .switchMap((action: roleActions.LoadRolesRequest) => { - return this.authService.isAdmin() ? this.roleService.getList(action.payload) + return this.roleService.getList(action.payload) .map((roles: Role[]) => { return new roleActions.LoadRolesResponse(roles); }) - .catch(() => Observable.of(new roleActions.LoadRolesResponse([]))): - Observable.of(new roleActions.LoadRolesResponse([])); + .catch(() => Observable.of(new roleActions.LoadRolesResponse([]))); }); constructor( private actions$: Actions, - private roleService: RoleService, - private authService: AuthService + private roleService: RoleService ) { } } diff --git a/src/app/roles/redux/roles.reducers.ts b/src/app/reducers/roles/redux/roles.reducers.ts similarity index 95% rename from src/app/roles/redux/roles.reducers.ts rename to src/app/reducers/roles/redux/roles.reducers.ts index 7f0a4106ea..d5321ddb5e 100644 --- a/src/app/roles/redux/roles.reducers.ts +++ b/src/app/reducers/roles/redux/roles.reducers.ts @@ -8,7 +8,7 @@ import { EntityState } from '@ngrx/entity'; import * as event from './roles.actions'; -import { Role } from '../../shared/models/role.model'; +import { Role } from '../../../shared/models/role.model'; /** * @ngrx/entity provides a predefined interface for handling @@ -105,13 +105,8 @@ export const isLoading = createSelector( state => state.loading ); -export const roles = createSelector( - selectAll, - (roles) => roles -); - export const roleTypes = createSelector( - roles, + selectAll, roles => Array.from(new Set(roles.map(role => role.type))) ); diff --git a/src/app/shared/actions/account-actions/account-actions.component.html b/src/app/shared/actions/account-actions/account-actions.component.html index 45886f21af..a81b12eb72 100644 --- a/src/app/shared/actions/account-actions/account-actions.component.html +++ b/src/app/shared/actions/account-actions/account-actions.component.html @@ -1,6 +1,6 @@ diff --git a/src/app/shared/actions/account-actions/account-actions.component.ts b/src/app/shared/actions/account-actions/account-actions.component.ts index bf28f10bbd..5c8e72c2c3 100644 --- a/src/app/shared/actions/account-actions/account-actions.component.ts +++ b/src/app/shared/actions/account-actions/account-actions.component.ts @@ -1,7 +1,11 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { + Component, + EventEmitter, + Input, + Output +} from '@angular/core'; import { BaseAccountAction } from './actions/base-account-action'; import { AccountActionsService } from './account-actions.service'; -import { AccountService } from '../../services/account.service'; import { Account } from '../../models/account.model'; @Component({ @@ -15,14 +19,14 @@ export class AccountActionsComponent { public actions: Array; constructor( - private accountActionService: AccountActionsService, - private accountService: AccountService + private accountActionService: AccountActionsService ) { this.actions = this.accountActionService.actions; this.onAccountChanged = new EventEmitter(); - this.accountService.onAccountUpdated.subscribe( - (account) => this.onAccountChanged.emit(account) - ); + } + + public activateAction(action: BaseAccountAction, account: Account) { + action.activate(account).subscribe(() => this.onAccountChanged.emit(account)); } } diff --git a/src/app/shared/models/resource-count.model.ts b/src/app/shared/models/resource-count.model.ts index 5a289abeba..972de20ae0 100644 --- a/src/app/shared/models/resource-count.model.ts +++ b/src/app/shared/models/resource-count.model.ts @@ -1,7 +1,6 @@ import { BaseModel } from './base.model'; -import { FieldMapper } from '../decorators/field-mapper.decorator'; -export const enum ResourceType { +/*export const enum ResourceType { Instance, // Number of instances a user can create IP, // Number of public IP addresses an account can own Volume, // Number of disk volumes an account can own @@ -18,12 +17,12 @@ export const enum ResourceType { @FieldMapper({ resourcetype: 'resourceType' -}) +})*/ export class ResourceCount extends BaseModel { public account: string; public domain: string; public domainid: string; public resourcecount: number; - public resourcetype: ResourceType; + public resourcetype: number; } diff --git a/src/app/shared/models/resource-limit.model.ts b/src/app/shared/models/resource-limit.model.ts index b9ec602d5d..00603e9f3c 100644 --- a/src/app/shared/models/resource-limit.model.ts +++ b/src/app/shared/models/resource-limit.model.ts @@ -1,5 +1,4 @@ import { BaseModel } from './base.model'; -import { FieldMapper } from '../decorators/field-mapper.decorator'; export const enum ResourceType { Instance, // Number of instances a user can create @@ -16,11 +15,8 @@ export const enum ResourceType { SecondaryStorage // Total secondary storage space (in GiB) a user can use } -@FieldMapper({ - resourcetype: 'resourceType' -}) export class ResourceLimit extends BaseModel { public id: string; public max: number; - public resourceType: ResourceType; + public resourcetype: number; } diff --git a/src/app/shared/services/account.service.ts b/src/app/shared/services/account.service.ts index b49f397235..d96fbda050 100644 --- a/src/app/shared/services/account.service.ts +++ b/src/app/shared/services/account.service.ts @@ -4,7 +4,6 @@ import { Account } from '../models/account.model'; import { BaseBackendService } from './base-backend.service'; import { HttpClient } from '@angular/common/http'; import { Observable } from 'rxjs/Observable'; -import { Subject } from 'rxjs/Subject'; @Injectable() @BackendResource({ @@ -12,7 +11,6 @@ import { Subject } from 'rxjs/Subject'; entityModel: Account }) export class AccountService extends BaseBackendService { - public onAccountUpdated = new Subject(); constructor(protected http: HttpClient) { super(http); @@ -29,7 +27,7 @@ export class AccountService extends BaseBackendService { public removeAccount(account: Account): Observable { return this.sendCommand('delete', { id: account.id, - }).map(() => this.onAccountUpdated.next(account)); + }); } public disableAccount(account: Account): Observable { @@ -37,7 +35,7 @@ export class AccountService extends BaseBackendService { account: account.name, lock: false, domainid: account.domainid - }).map(() => this.onAccountUpdated.next(account)); + }); } public lockAccount(account: Account): Observable { @@ -45,13 +43,13 @@ export class AccountService extends BaseBackendService { account: account.name, lock: true, domainid: account.domainid - }).map(() => this.onAccountUpdated.next(account)); + }); } public enableAccount(account: Account): Observable { return this.sendCommand('enable', { account: account.name, domainid: account.domainid - }).map(() => this.onAccountUpdated.next(account)); + }); } } diff --git a/src/app/shared/services/configuration.service.ts b/src/app/shared/services/configuration.service.ts index 09aadb274a..7ffdf68f83 100644 --- a/src/app/shared/services/configuration.service.ts +++ b/src/app/shared/services/configuration.service.ts @@ -5,7 +5,6 @@ import { BaseBackendService } from './base-backend.service'; import { Configuration } from '../models/configuration.model'; import { Observable } from 'rxjs/Observable'; import { Account } from '../models/account.model'; -import { AsyncJobService } from './async-job.service'; @Injectable() @BackendResource({ @@ -13,17 +12,13 @@ import { AsyncJobService } from './async-job.service'; entityModel: Configuration }) export class ConfigurationService extends BaseBackendService { - constructor(protected http: HttpClient, private asyncJob: AsyncJobService) { + constructor(protected http: HttpClient) { super(http); } - /*public update(accountid: string, name: string, value: any): Observable { - return this.postRequest('update', { accountid, name, value }); - }*/ - public updateConfiguration( configuration: Configuration, - account?: Account + account: Account ): Observable { return this.sendCommand('update', { accountid: account.id, diff --git a/src/app/shared/services/resource-count.service.ts b/src/app/shared/services/resource-count.service.ts index b007d0ef40..82c87bdc3d 100644 --- a/src/app/shared/services/resource-count.service.ts +++ b/src/app/shared/services/resource-count.service.ts @@ -3,7 +3,6 @@ import { BaseBackendCachedService } from './base-backend-cached.service'; import { BackendResource } from '../decorators/backend-resource.decorator'; import { Observable } from 'rxjs/Observable'; import { HttpClient } from '@angular/common/http'; -import { Account } from '../models/account.model'; import { ResourceCount } from '../models/resource-count.model'; @@ -18,11 +17,8 @@ export class ResourceCountService extends BaseBackendCachedService> { - return this.sendCommand('update', { - domainid: account.domainid, - account: account.name - }).map(response => this.formatGetListResponse(response).list); + return this.sendCommand('update', params).map(response => this.formatGetListResponse(response).list); } } diff --git a/src/app/shared/services/resource-limit.service.ts b/src/app/shared/services/resource-limit.service.ts index e682741cd4..f0eb0b8397 100644 --- a/src/app/shared/services/resource-limit.service.ts +++ b/src/app/shared/services/resource-limit.service.ts @@ -19,7 +19,7 @@ export class ResourceLimitService extends BaseBackendCachedService> { return super.getList(params) - .map(result => result.sort((a, b) => a.resourceType - b.resourceType)); + .map(result => result.sort((a, b) => a.resourcetype - b.resourcetype)); } public updateResourceLimit( @@ -27,7 +27,7 @@ export class ResourceLimitService extends BaseBackendCachedService { return this.sendCommand('update', { - resourceType: resourceLimit.resourceType, + resourceType: resourceLimit.resourcetype, max: resourceLimit.max, domainid: account.domainid, account: account.name diff --git a/src/app/ssh-keys/containers/ssh-key-list.container.ts b/src/app/ssh-keys/containers/ssh-key-list.container.ts index 1b9307308f..a8adc96a69 100644 --- a/src/app/ssh-keys/containers/ssh-key-list.container.ts +++ b/src/app/ssh-keys/containers/ssh-key-list.container.ts @@ -14,9 +14,9 @@ import { FilterService } from '../../shared/services/filter.service'; import { SSHKeyPair } from '../../shared/models/ssh-keypair.model'; import * as fromSshKeys from '../redux/ssh-key.reducers'; +import * as fromAccounts from '../../reducers/accounts/redux/accounts.reducers'; import * as sshKeyActions from '../redux/ssh-key.actions'; -import * as accountAction from '../../account/redux/accounts.actions'; -import * as fromAccounts from '../../account/redux/accounts.reducers'; +import * as accountActions from '../../reducers/accounts/redux/accounts.actions'; export const sshKeyListFilters = 'sshKeyListFilters'; @@ -27,7 +27,7 @@ export const sshKeyListFilters = 'sshKeyListFilters'; export class SshKeyListContainerComponent extends WithUnsubscribe() implements OnInit { readonly sshKeyList$ = this.store.select(fromSshKeys.selectFilteredSshKeys); readonly filters$ = this.store.select(fromSshKeys.filters); - readonly accounts$ = this.store.select(fromAccounts.accounts); + readonly accounts$ = this.store.select(fromAccounts.selectAll); readonly selectedGroupings$ = this.store.select(fromSshKeys.filterSelectedGroupings); readonly selectedAccountIds$ = this.store.select(fromSshKeys.filterSelectedAccountIds); @@ -62,7 +62,7 @@ export class SshKeyListContainerComponent extends WithUnsubscribe() implements O } public ngOnInit(): void { - this.store.dispatch(new accountAction.LoadAccountsRequest()); + this.store.dispatch(new accountActions.LoadAccountsRequest()); this.initFilters(); this.filters$ .takeUntil(this.unsubscribe$) diff --git a/src/app/ssh-keys/redux/ssh-key.reducers.ts b/src/app/ssh-keys/redux/ssh-key.reducers.ts index ec39f0c444..67072dc7ec 100644 --- a/src/app/ssh-keys/redux/ssh-key.reducers.ts +++ b/src/app/ssh-keys/redux/ssh-key.reducers.ts @@ -8,7 +8,8 @@ import { createFeatureSelector, createSelector } from '@ngrx/store'; -import { accounts } from '../../account/redux/accounts.reducers'; + +import * as fromAccounts from '../../reducers/accounts/redux/accounts.reducers'; import * as sshKey from './ssh-key.actions'; @@ -193,12 +194,13 @@ export const filterSelectedAccountIds = createSelector( export const selectFilteredSshKeys = createSelector( selectAll, filterSelectedAccountIds, - accounts, + fromAccounts.selectAll, (sshKeys, selectedAccountIds, accounts) => { - const selectedAccounts = accounts.filter(account => selectedAccountIds.find(id => id === account.id)); - const accountsMap = selectedAccounts.reduce((m, i) => ({...m, [i.name]: i }), {}); - const domainsMap = selectedAccounts.reduce((m, i) => ({...m, [i.domainid]: i }), {}); + const selectedAccounts = accounts.filter( + account => selectedAccountIds.find(id => id === account.id)); + const accountsMap = selectedAccounts.reduce((m, i) => ({ ...m, [i.name]: i }), {}); + const domainsMap = selectedAccounts.reduce((m, i) => ({ ...m, [i.domainid]: i }), {}); const selectedAccountIdsFilter = sshKey => !selectedAccountIds.length || (accountsMap[sshKey.account] && domainsMap[sshKey.domainid]); diff --git a/src/app/ssh-keys/ssh-key-list-item/ssh-key-list-item.component.ts b/src/app/ssh-keys/ssh-key-list-item/ssh-key-list-item.component.ts index 1a8db24c06..b1146faae7 100644 --- a/src/app/ssh-keys/ssh-key-list-item/ssh-key-list-item.component.ts +++ b/src/app/ssh-keys/ssh-key-list-item/ssh-key-list-item.component.ts @@ -1,4 +1,10 @@ -import { Component, EventEmitter, Input, Output, ViewChild } from '@angular/core'; +import { + Component, + EventEmitter, + Input, + Output, + ViewChild +} from '@angular/core'; import { MatMenuTrigger } from '@angular/material'; import { SSHKeyPair } from '../../shared/models/ssh-keypair.model'; @@ -12,12 +18,12 @@ export class SshKeyListItemComponent { @Input() public item: SSHKeyPair; @Output() public onClick = new EventEmitter(); @Output() public onRemove = new EventEmitter(); - @ViewChild(MatMenuTrigger) public mdMenuTrigger: MatMenuTrigger; + @ViewChild(MatMenuTrigger) public matMenuTrigger: MatMenuTrigger; public onClicked(e: MouseEvent): void { e.stopPropagation(); - if (!this.mdMenuTrigger || !this.mdMenuTrigger.menuOpen) { + if (!this.matMenuTrigger || !this.matMenuTrigger.menuOpen) { this.onClick.emit(this.item); } } diff --git a/src/app/tags/tag/tag.component.scss b/src/app/tags/tag/tag.component.scss index 3c5538cbd8..a2afef7419 100644 --- a/src/app/tags/tag/tag.component.scss +++ b/src/app/tags/tag/tag.component.scss @@ -9,7 +9,6 @@ overflow: hidden; text-overflow: ellipsis; cursor: pointer; - max-width: 34% !important; text-align: right; white-space: nowrap; } @@ -21,14 +20,11 @@ } .left { - max-width: 66% !important; - min-width: 66% !important; margin-right: 15px; } .buttons { display: none; - min-width: 68px; margin-left: 10px; } @@ -43,5 +39,5 @@ } .container:hover .buttons { - display: inline-block; + display: flex; } diff --git a/src/app/template/template/template.component.ts b/src/app/template/template/template.component.ts index 7d247e8087..d6e72fdb8d 100644 --- a/src/app/template/template/template.component.ts +++ b/src/app/template/template/template.component.ts @@ -25,7 +25,7 @@ export class TemplateComponent implements OnChanges { @Input() public searchQuery: () => string; @Output() public deleteTemplate = new EventEmitter(); @Output() public onClick = new EventEmitter(); - @ViewChild(MatMenuTrigger) public mdMenuTrigger: MatMenuTrigger; + @ViewChild(MatMenuTrigger) public matMenuTrigger: MatMenuTrigger; public query: string; @@ -40,7 +40,7 @@ export class TemplateComponent implements OnChanges { public handleClick(e: MouseEvent): void { e.stopPropagation(); - if (!this.mdMenuTrigger || !this.mdMenuTrigger.menuOpen) { + if (!this.matMenuTrigger || !this.matMenuTrigger.menuOpen) { this.onClick.emit(this.item); } } diff --git a/src/app/vm/vm-list/vm-list-item.component.ts b/src/app/vm/vm-list/vm-list-item.component.ts index 541db9c57a..baad849b89 100644 --- a/src/app/vm/vm-list/vm-list-item.component.ts +++ b/src/app/vm/vm-list/vm-list-item.component.ts @@ -46,7 +46,7 @@ export class VmListItemComponent implements OnInit, OnChanges { @Input() public item: VirtualMachine; @Input() public isSelected: (vm: VirtualMachine) => boolean; @Output() public onClick = new EventEmitter(); - @ViewChild(MatMenuTrigger) public mdMenuTrigger: MatMenuTrigger; + @ViewChild(MatMenuTrigger) public matMenuTrigger: MatMenuTrigger; public color: Color; public gigabyte = Math.pow(2, 10); // to compare with RAM which is in megabytes @@ -103,7 +103,7 @@ export class VmListItemComponent implements OnInit, OnChanges { public handleClick(e: MouseEvent): void { e.stopPropagation(); - if (!this.mdMenuTrigger.menuOpen) { + if (!this.matMenuTrigger.menuOpen) { this.onClick.emit(this.item); } } diff --git a/src/app/volume/volume-item/volume-item.component.ts b/src/app/volume/volume-item/volume-item.component.ts index 381e0a7d6a..003b7190a4 100644 --- a/src/app/volume/volume-item/volume-item.component.ts +++ b/src/app/volume/volume-item/volume-item.component.ts @@ -1,7 +1,19 @@ -import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges, ViewChild } from '@angular/core'; +import { + Component, + EventEmitter, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges, + ViewChild +} from '@angular/core'; import { MatMenuTrigger } from '@angular/material'; import { VolumeActionsService } from '../../shared/actions/volume-actions/volume-actions.service'; -import { DiskOffering, Volume } from '../../shared/models'; +import { + DiskOffering, + Volume +} from '../../shared/models'; import { VolumeType } from '../../shared/models/volume.model'; import { DiskOfferingService } from '../../shared/services/disk-offering.service'; import { ZoneService } from '../../shared/services/zone.service'; @@ -18,7 +30,7 @@ export class VolumeItemComponent extends VolumeItem implements OnInit, OnChanges @Input() public searchQuery: () => string; @Input() public item: Volume; @Output() public onClick = new EventEmitter(); - @ViewChild(MatMenuTrigger) public mdMenuTrigger: MatMenuTrigger; + @ViewChild(MatMenuTrigger) public matMenuTrigger: MatMenuTrigger; public diskOfferings: Array; public query: string; @@ -61,7 +73,7 @@ export class VolumeItemComponent extends VolumeItem implements OnInit, OnChanges public handleClick(e: MouseEvent): void { e.stopPropagation(); - if (!this.mdMenuTrigger.menuOpen) { + if (!this.matMenuTrigger.menuOpen) { this.onClick.emit(this.item); } }