Skip to content
This repository has been archived by the owner on Mar 25, 2023. It is now read-only.

Commit

Permalink
feat(disk-offering): show all disk offerings when creating a data disk (
Browse files Browse the repository at this point in the history
#1405)

* feat(disk-offering): show all disk offerings when creating a data disk and show error message when chosen disk offering don't fit account resource limitations

* feat(disk-offering): fix test

* fixes after review

* fix bug

* feat(disk-offerings): add slider to selector component

* fix test

* disable creation when disk offering doesnt fit the account resources

* update after merge

* fix typings

* update

* fix conditionals for selector and slider

* fix volume resize

* fixes for style guide

* fix after review

* add selector isDiskOfferingAvailableByResources

* remove unused import

* fix bugs after testing

* remove log

* add availableStorage selector

* remove unused

* commented test

* commented test

* dispatch zone from page

* change load offering request

* load all disk offerings without restriction of size

* update

* update
  • Loading branch information
Vladimir Shakhov authored Nov 8, 2018
1 parent 0d5e805 commit 16671e6
Show file tree
Hide file tree
Showing 33 changed files with 362 additions and 159 deletions.
2 changes: 1 addition & 1 deletion src/app/home/home.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ import { State, UserTagsActions, layoutStore } from '../root-store';
import { AuthService } from '../shared/services/auth.service';
import { WithUnsubscribe } from '../utils/mixins/with-unsubscribe';
import { Route, Subroute } from '../core/nav-menu/models';
import * as authActions from '../reducers/auth/redux/auth.actions';
import { getCurrentRoute, getRoutes, getSubroutes } from '../core/nav-menu/redux/nav-menu.reducers';
import * as authActions from '../reducers/auth/redux/auth.actions';

@Component({
selector: 'cs-home',
Expand Down
7 changes: 7 additions & 0 deletions src/app/reducers/accounts/redux/accounts.reducers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,13 @@ export const selectUserAccount = createSelector(
(accountsMap, accountId) => accountsMap[accountId],
);

export const selectStorageAvailable = createSelector(selectUserAccount, account => {
if (account) {
const available = Number(account.primarystorageavailable);
return !isNaN(available) ? available : null;
}
});

export const selectFilteredAccounts = createSelector(
selectAll,
filterSelectedRoleTypes,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ describe('Disk Offering Effects', () => {

spyOn(service, 'getList').and.returnValue(of(diskOfferings));
});

it('should return a collection from LoadOfferingsResponse', () => {
const action = new actions.LoadOfferingsRequest();
const completion = new actions.LoadOfferingsResponse(diskOfferings);
Expand Down
19 changes: 18 additions & 1 deletion src/app/reducers/disk-offerings/redux/disk-offerings.reducers.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { createEntityAdapter, EntityAdapter, EntityState } from '@ngrx/entity';
import { createFeatureSelector, createSelector } from '@ngrx/store';

import { isOfferingLocal } from '../../../shared/models/offering.model';
import { isCustomized, isOfferingLocal } from '../../../shared/models/offering.model';
import { DiskOffering, ServiceOfferingAvailability, Zone } from '../../../shared/models';
import { configSelectors } from '../../../root-store';
import * as fromVolumes from '../../volumes/redux/volumes.reducers';
import * as fromZones from '../../zones/redux/zones.reducers';
import * as event from './disk-offerings.actions';
import * as fromAuth from '../../auth/redux/auth.reducers';
import * as fromVMs from '../../vm/redux/vm.reducers';
import { isTemplate } from '../../../template/shared';

export interface State extends EntityState<DiskOffering> {
loading: boolean;
Expand Down Expand Up @@ -113,3 +116,17 @@ export const getAvailableOfferings = createSelector(
return [];
},
);

export const isDiskOfferingAvailableByResources = (minSize: number) =>
createSelector(
fromAuth.getUserAccount,
fromVMs.getVmFormState,
(account, state): boolean => {
if (!isTemplate(state.template) && state.diskOffering) {
const storageAvailability = account.primarystorageavailable;
const size = isCustomized(state.diskOffering) ? minSize : state.diskOffering.disksize;
return size < Number(storageAvailability);
}
return true;
},
);
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@import '../../../style/_variables';

:host .mat-dialog-content {
overflow: hidden !important;
}
Expand All @@ -11,6 +13,6 @@ h5 {
}

.error-message {
color: #f44336;
color: $error-message-color;
font-size: 13px;
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
@import '../../../style/_variables';

.service-offering-selector {
padding-top: 10px;
display: block;
Expand All @@ -22,6 +24,6 @@
}

.error-message {
color: #f44336;
color: $error-message-color;
font-size: 13px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import { select, Store } from '@ngrx/store';
import { filter, take } from 'rxjs/operators';

import * as fromAuth from '../../../reducers/auth/redux/auth.reducers';
import * as diskOfferingActions from '../../../reducers/disk-offerings/redux/disk-offerings.actions';
import * as fromDiskOfferings from '../../../reducers/disk-offerings/redux/disk-offerings.reducers';
import * as zoneActions from '../../../reducers/zones/redux/zones.actions';
Expand All @@ -14,21 +13,24 @@ import { Account } from '../../models/account.model';
import { Volume } from '../../models/volume.model';
import { VolumeResizeData } from '../../services/volume.service';
import { VolumeType } from '../../models';
import * as fromAccounts from '../../../reducers/accounts/redux/accounts.reducers';

@Component({
selector: 'cs-volume-resize-container',
template: `
<cs-volume-resize
[maxSize]="maxSize"
[volume]="volume"
[availableStorage]="availableStorage$ | async"
[diskOfferings]="offerings$ | async"
(diskResized)="resizeDisk($event)"
>
</cs-volume-resize>`,
})
export class VolumeResizeContainerComponent implements OnInit {
readonly offerings$ = this.store.pipe(select(fromDiskOfferings.getAvailableOfferings));
readonly account$ = this.store.pipe(select(fromAuth.getUserAccount));
readonly account$ = this.store.pipe(select(fromAccounts.selectUserAccount));
readonly availableStorage$ = this.store.pipe(select(fromAccounts.selectStorageAvailable));

public volume: Volume;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,17 @@ <h3 class="mat-dialog-title">
novalidate
>
<div class="mat-dialog-content">
<div *ngIf="!volumeIsRoot && diskOfferings?.length">
<cs-disk-offering-selector
name="diskOffering"
[diskOfferings]="diskOfferings"
[ngModel]="diskOffering"
(changed)="updateDiskOffering($event)"
></cs-disk-offering-selector>
</div>
<cs-slider
*ngIf="isCustomizedForVolume(diskOffering) || volumeIsRoot"
<cs-disk-offering-selector
name="diskOffering"
[enableSelector]="!volumeIsRoot && diskOfferings?.length"
[enableSlider]="isCustomizedForVolume(diskOffering) || volumeIsRoot"
[min]="volume.size | division:2:30"
[max]="rootDiskSizeLimit"
[label]="'VM_PAGE.STORAGE_DETAILS.VOLUME_RESIZE.NEW_SIZE' | translate"
[(ngModel)]="newSize"
name="new-size"
[units]="'UNITS.GB' | translate"
></cs-slider>
[newSize]="newSize"
[availableStorage]="availableStorage"
[diskOfferings]="diskOfferings"
[diskOffering]="diskOffering"
(changed)="updateDiskOffering($event)"
></cs-disk-offering-selector>
</div>
<div class="mat-dialog-actions">
<button mat-button color="primary" matDialogClose type="button">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ export class VolumeResizeComponent implements OnInit, OnChanges {
public volume: Volume;
@Input()
public diskOfferings: DiskOffering[];
@Input()
public availableStorage: number | null;
@Output()
public diskResized = new EventEmitter<VolumeResizeData>();

Expand All @@ -43,19 +45,24 @@ export class VolumeResizeComponent implements OnInit, OnChanges {
return maxRootCapability;
}

public get volumeIsRoot(): boolean {
return isRoot(this.volume);
}

public get canResize(): boolean {
return (this.diskOfferings && this.diskOfferings.length > 0) || isRoot(this.volume);
}

constructor(
public dialogRef: MatDialogRef<VolumeResizeComponent>,
public authService: AuthService,
) {}

public isCustomizedForVolume(diskOffering: DiskOffering): boolean {
if (diskOffering) {
return isCustomized(diskOffering);
}
}

public ngOnInit(): void {
this.newSize = this.volume.size / Math.pow(2, 30);
if (!!this.availableStorage) {
this.availableStorage = this.availableStorage + this.newSize;
}
}

public ngOnChanges(changes: SimpleChanges): void {
Expand All @@ -64,16 +71,15 @@ export class VolumeResizeComponent implements OnInit, OnChanges {
}
}

public get volumeIsRoot(): boolean {
return isRoot(this.volume);
}

public get canResize(): boolean {
return (this.diskOfferings && this.diskOfferings.length > 0) || isRoot(this.volume);
public isCustomizedForVolume(diskOffering: DiskOffering): boolean {
if (diskOffering) {
return isCustomized(diskOffering);
}
}

public updateDiskOffering(value: DiskOffering): void {
this.diskOffering = value;
this.newSize = value.disksize;
}

public resizeVolume(): void {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ <h3 class="mat-dialog-title">
<ng-template #noResults>
<cs-no-results></cs-no-results>
</ng-template>

<mat-error *ngIf="resourcesLimitExceeded">
{{ "ERRORS.VOLUME.VOLUME_RESOURCES_LIMIT_EXCEEDED" | translate }}
</mat-error>
<div class="mat-dialog-actions">
<button
mat-button
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,28 @@ import { DiskOfferingDialogComponent } from './disk-offering-dialog.component';
import { MockTranslatePipe } from '../../../../../testutils/mocks/mock-translate.pipe.spec';
import { StringifyDatePipe } from '../../../pipes';
import { DateTimeFormatterService } from '../../../services/date-time-formatter.service';
import { User } from '../../../models/user.model';
import { AuthService } from '../../../services/auth.service';

class MockConfigServiceDateTimeFormatterService {
public stringifyToTime() {
return;
}
}

class MockAuthService {
// tslint:disable-next-line
_user: User;

get user() {
return this._user;
}

getCustomDiskOfferingMinSize() {
return 1;
}
}

describe('Disk Offering dialog', () => {
let fixture: ComponentFixture<DiskOfferingDialogComponent>;
let component: DiskOfferingDialogComponent;
Expand Down Expand Up @@ -72,6 +87,10 @@ describe('Disk Offering dialog', () => {
provide: DateTimeFormatterService,
useClass: MockConfigServiceDateTimeFormatterService,
},
{
provide: AuthService,
useClass: MockAuthService,
},
],
schemas: [NO_ERRORS_SCHEMA],
}).compileComponents();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { Component, Inject } from '@angular/core';
import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
import * as moment from 'moment';

import { DiskOffering } from '../../../models';
import { AuthService } from '../../../services/auth.service';
import { Utils } from '../../../services/utils/utils.service';
import { isCustomized } from '../../../models/offering.model';

@Component({
selector: 'cs-disk-offering-dialog',
Expand All @@ -13,13 +14,20 @@ import { Utils } from '../../../services/utils/utils.service';
export class DiskOfferingDialogComponent {
public diskOfferings: DiskOffering[];
public selectedDiskOffering: DiskOffering;
public storageAvailable: number | null;
public resourcesLimitExceeded = false;
public minSize: number = null;

constructor(
@Inject(MAT_DIALOG_DATA) data,
public dialogRef: MatDialogRef<DiskOfferingDialogComponent>,
public authService: AuthService,
) {
this.diskOfferings = data.diskOfferings;
this.selectedDiskOffering = data.diskOffering;
this.storageAvailable = data.storageAvailable;
this.minSize = this.authService.getCustomDiskOfferingMinSize();
this.checkResourcesLimit();
}

public offeringCreated(date: string): Date {
Expand All @@ -33,6 +41,7 @@ export class DiskOfferingDialogComponent {

public selectOffering(offering: DiskOffering) {
this.selectedDiskOffering = offering;
this.checkResourcesLimit();
}

public preventTriggerExpansionPanel(e: Event) {
Expand All @@ -46,6 +55,29 @@ export class DiskOfferingDialogComponent {
public isSubmitButtonDisabled() {
const isDiskOfferingNotSelected = !this.selectedDiskOffering;
const isNoDiskOfferings = !this.diskOfferings.length;
return isDiskOfferingNotSelected || isNoDiskOfferings;
return this.resourcesLimitExceeded || isDiskOfferingNotSelected || isNoDiskOfferings;
}

private getDiskSize() {
if (this.selectedDiskOffering) {
if (isCustomized(this.selectedDiskOffering)) {
return this.minSize;
}

return this.selectedDiskOffering.disksize;
}
}

private getResourceLimitExceeded(): boolean {
const diskSize = this.getDiskSize();
if (this.storageAvailable && diskSize) {
return Number(this.storageAvailable) < Number(diskSize);
}

return false;
}

private checkResourcesLimit() {
this.resourcesLimitExceeded = this.getResourceLimitExceeded();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<div class="top-row">
<h4 class="disk-offerings">{{ 'VM_PAGE.VM_CREATION.DISK_OFFERING' | translate }}</h4>

<button mat-button type="button" (click)="changeOffering()">
{{ 'COMMON.SELECT' | translate }}
</button>
</div>

<div class="mat-form-field-wrapper">
<span class="disk-offering-info truncate">
<ng-container *ngIf="diskOffering; then offeringName else nameStub"></ng-container>
<ng-template #offeringName>{{ diskOffering.name }}</ng-template>
<ng-template #nameStub>{{ 'VOLUME_PAGE.DETAILS.DISK_OFFERING' | translate }}</ng-template>
</span>
</div>
Loading

0 comments on commit 16671e6

Please sign in to comment.