From c71cf3c574041797ced0f48afe54df27c0013401 Mon Sep 17 00:00:00 2001
From: HeyRoach <caloriees@gmail.com>
Date: Tue, 25 Sep 2018 10:07:52 +0700
Subject: [PATCH 01/10] feat(service-offering): show all service offerings even
 those which don't fir account resource limitation

---
 .../custom-service-offering.component.html    |  8 ++--
 .../custom-service-offering.component.ts      | 38 +++++++++++++++----
 .../service-offering-dialog.component.html    |  4 +-
 .../service-offering-dialog.component.ts      | 20 +++++++++-
 .../service-offering-list.component.html      |  5 ++-
 .../service-offering-list.component.ts        |  7 +++-
 .../selectors/service-offering.selectors.ts   | 16 +-------
 .../vm-creation-service-offering.container.ts |  3 ++
 src/i18n/en.json                              |  3 ++
 src/i18n/ru.json                              |  3 ++
 10 files changed, 76 insertions(+), 31 deletions(-)

diff --git a/src/app/service-offering/custom-service-offering/custom-service-offering.component.html b/src/app/service-offering/custom-service-offering/custom-service-offering.component.html
index a994ada989..f771f4956a 100644
--- a/src/app/service-offering/custom-service-offering/custom-service-offering.component.html
+++ b/src/app/service-offering/custom-service-offering/custom-service-offering.component.html
@@ -8,9 +8,9 @@ <h5>{{ 'SERVICE_OFFERING.CUSTOM_SERVICE_OFFERING.CPU_NUMBER' | translate }}</h5>
         type="number"
         name="cpuNumber"
         [min]="offering.customOfferingRestrictions.cpunumber.min"
-        [max]="offering.customOfferingRestrictions.cpunumber.max"
+        [max]="maxCpu"
         [csMinValue]="offering.customOfferingRestrictions.cpunumber.min"
-        [csMaxValue]="offering.customOfferingRestrictions.cpunumber.max"
+        [csMaxValue]="maxCpu"
         formControlName="cpuNumber"
         required
       >
@@ -38,9 +38,9 @@ <h5>{{ 'SERVICE_OFFERING.CUSTOM_SERVICE_OFFERING.MEMORY' | translate }}</h5>
         type="number"
         name="memory"
         [min]="offering.customOfferingRestrictions.memory.min"
-        [max]="offering.customOfferingRestrictions.memory.max"
+        [max]="maxMemory"
         [csMinValue]="offering.customOfferingRestrictions.memory.min"
-        [csMaxValue]="offering.customOfferingRestrictions.memory.max"
+        [csMaxValue]="maxMemory"
         formControlName="memory"
         required
       >
diff --git a/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts b/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
index 1a1efe1e9a..1da7dddb18 100644
--- a/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
+++ b/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
@@ -1,8 +1,19 @@
 import { Component, Inject } from '@angular/core';
-import { FormControl, FormGroup, Validators } from '@angular/forms'
+import { FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'
 import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
 
 import { ComputeOfferingViewModel } from '../../vm/view-models';
+import { Account } from '../../shared/models';
+
+function LimitValidator(cpuNumberLimit: number): ValidatorFn {
+  return function (control: FormControl) {
+    if (control.value > cpuNumberLimit) {
+      return { cpuLimitExceeded: true };
+    } else {
+      return null;
+    }
+  };
+}
 
 @Component({
   selector: 'cs-custom-service-offering',
@@ -12,13 +23,27 @@ import { ComputeOfferingViewModel } from '../../vm/view-models';
 export class CustomServiceOfferingComponent {
   public offering: ComputeOfferingViewModel;
   public hardwareForm: FormGroup;
+  public account: Account;
+  public maxCpu: number;
+  public maxMemory: number;
 
   constructor(
     @Inject(MAT_DIALOG_DATA) data,
     public dialogRef: MatDialogRef<CustomServiceOfferingComponent>,
   ) {
-    const { offering } = data;
-    this.offering = offering;
+    this.offering = data.offering;
+    this.account = data.account;
+    if (this.offering.customOfferingRestrictions.cpunumber.max > this.account.cpuavailable) {
+      this.maxCpu = this.account.cpuavailable
+    } else {
+      this.maxCpu = this.offering.customOfferingRestrictions.cpunumber.max;
+    }
+
+    if (this.offering.customOfferingRestrictions.memory.max > this.account.memoryavailable) {
+      this.maxMemory = this.account.memoryavailable;
+    } else {
+      this.maxMemory = this.offering.customOfferingRestrictions.memory.max;
+    }
 
     this.createForm();
   }
@@ -35,11 +60,10 @@ export class CustomServiceOfferingComponent {
   }
 
   private createForm() {
-    // input text=number provide all other validation for current restrictions
     this.hardwareForm = new FormGroup({
-      cpuNumber: new FormControl(this.offering.cpunumber, Validators.required),
-      cpuSpeed: new FormControl(this.offering.cpuspeed, Validators.required),
-      memory: new FormControl(this.offering.memory, Validators.required),
+      cpuNumber: new FormControl(this.offering.cpunumber, [Validators.required, LimitValidator(this.maxCpu)]),
+      cpuSpeed: new FormControl(this.offering.cpuspeed, [Validators.required]),
+      memory: new FormControl(this.offering.memory, [Validators.required, LimitValidator(this.maxMemory)]),
     });
   }
 }
diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
index 622219ed11..4f8e29eb5e 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
@@ -14,9 +14,11 @@ <h3 class="mat-dialog-title">
       [classes]="classes"
       [selectedClasses]="selectedClasses"
       [query]="query"
+      [account]="account"
       [offeringList]="serviceOfferings"
       [selectedOffering]="serviceOffering"
       [showFields]="showFields"
+      [resourcesLimitExceeded]="resourcesLimitExceeded"
       (selectedOfferingChange)="updateOffering($event)"
     ></cs-service-offering-list>
 
@@ -40,7 +42,7 @@ <h3 class="mat-dialog-title">
       <button
         mat-button
         color="primary"
-        [disabled]="isSubmitButtonDisabled()"
+        [disabled]="isSubmitButtonDisabled() || resourcesLimitExceeded"
         (click)="onChange()"
       >
         {{ (formMode ? 'COMMON.SELECT' : 'COMMON.CHANGE') | translate }}
diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
index cce2b581ff..82976492ff 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
@@ -1,6 +1,6 @@
 import { Component, EventEmitter, Input, OnChanges, OnInit, Output, SimpleChanges } from '@angular/core';
 
-import { ServiceOfferingClass, ServiceOfferingType } from '../../shared/models';
+import { Account, ServiceOfferingClass, ServiceOfferingType } from '../../shared/models';
 import { ComputeOfferingViewModel } from '../../vm/view-models';
 import { VirtualMachine } from '../../vm/shared/vm.model';
 
@@ -24,6 +24,7 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
   @Input() public virtualMachine: VirtualMachine;
   @Input() public groupings: Array<any>;
   @Input() public query: string;
+  @Input() public account: Account;
   @Input() public isVmRunning: boolean;
   @Output() public onServiceOfferingChange = new EventEmitter<ComputeOfferingViewModel>();
   @Output() public onServiceOfferingUpdate = new EventEmitter<ComputeOfferingViewModel>();
@@ -33,6 +34,7 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
   public serviceOffering: ComputeOfferingViewModel;
   public loading: boolean;
   public showFields = false;
+  public resourcesLimitExceeded = false;
 
   public ngOnInit() {
     this.serviceOffering = this.serviceOfferings.find(_ => _.id === this.serviceOfferingId);
@@ -40,6 +42,7 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
       this.viewMode === ServiceOfferingType.fixed ? this.viewModeChange.emit(ServiceOfferingType.custom) :
         this.viewModeChange.emit(ServiceOfferingType.fixed);
     }
+    this.checkLimits(this.serviceOffering);
   }
 
   public ngOnChanges(changes: SimpleChanges) {
@@ -52,6 +55,7 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
 
   public updateOffering(offering: ComputeOfferingViewModel): void {
     this.serviceOffering = offering;
+    this.checkLimits(this.serviceOffering);
     this.onServiceOfferingUpdate.emit(this.serviceOffering);
   }
 
@@ -99,4 +103,18 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
     return isDifferentOfferingId || isSameCustomOfferingWithDifferentParams;
   }
 
+  private checkLimits(offering: ComputeOfferingViewModel) {
+    let сpusExceeded;
+    let memoryExceeded;
+
+    if (offering.iscustomized) {
+      сpusExceeded = this.account.cpuavailable < this.serviceOffering['customOfferingRestrictions'].cpunumber.min;
+      memoryExceeded = this.account.memoryavailable < this.serviceOffering['customOfferingRestrictions'].memory.min;
+    } else {
+      сpusExceeded = this.account.cpuavailable < this.serviceOffering.cpunumber;
+      memoryExceeded = this.account.memoryavailable < this.serviceOffering.memory;
+    }
+    this.resourcesLimitExceeded = memoryExceeded || сpusExceeded;
+  }
+
 }
diff --git a/src/app/service-offering/service-offering-list/service-offering-list.component.html b/src/app/service-offering/service-offering-list/service-offering-list.component.html
index 23da526d7e..b0ac793fc6 100644
--- a/src/app/service-offering/service-offering-list/service-offering-list.component.html
+++ b/src/app/service-offering/service-offering-list/service-offering-list.component.html
@@ -80,10 +80,13 @@ <h5>{{ getDescription(group.soClass) | translate }}</h5>
 
       </table>
     </div>
-
   </ng-container>
 </div>
 
+<mat-error *ngIf="resourcesLimitExceeded">
+  {{ 'ERRORS.COMPUTE_OFFERING.RESOURCE_LIMIT_EXCEEDED' | translate }}
+</mat-error>
+
 <cs-no-results *ngIf="!offeringList?.length && !isLoading"></cs-no-results>
 
 
diff --git a/src/app/service-offering/service-offering-list/service-offering-list.component.ts b/src/app/service-offering/service-offering-list/service-offering-list.component.ts
index 369026e3d9..9deb311aec 100644
--- a/src/app/service-offering/service-offering-list/service-offering-list.component.ts
+++ b/src/app/service-offering/service-offering-list/service-offering-list.component.ts
@@ -5,7 +5,7 @@ import { Observable } from 'rxjs';
 import { filter } from 'rxjs/operators';
 
 import { classesFilter } from '../../reducers/service-offerings/redux/service-offerings.reducers';
-import { ServiceOffering, ServiceOfferingClass } from '../../shared/models';
+import { Account, ServiceOffering, ServiceOfferingClass } from '../../shared/models';
 import { CustomServiceOfferingComponent } from '../custom-service-offering/custom-service-offering.component';
 import { Language } from '../../shared/types';
 import { ComputeOfferingViewModel } from '../../vm/view-models';
@@ -23,6 +23,8 @@ export class ServiceOfferingListComponent implements OnChanges {
   @Input() public selectedOffering: ServiceOffering;
   @Input() public isLoading = false;
   @Input() public showFields: boolean;
+  @Input() public account: Account;
+  @Input() public resourcesLimitExceeded = false;
   @Output() public selectedOfferingChange = new EventEmitter<ComputeOfferingViewModel>();
 
   public list: Array<{ soClass: ServiceOfferingClass, items: MatTableDataSource<ComputeOfferingViewModel> }>;
@@ -61,7 +63,8 @@ export class ServiceOfferingListComponent implements OnChanges {
     return this.dialog.open(CustomServiceOfferingComponent, {
       width: '370px',
       data: {
-        offering
+        offering,
+        account: this.account
       }
     }).afterClosed();
 
diff --git a/src/app/vm/selectors/service-offering.selectors.ts b/src/app/vm/selectors/service-offering.selectors.ts
index 8a4fad9b87..2577dcd8b7 100644
--- a/src/app/vm/selectors/service-offering.selectors.ts
+++ b/src/app/vm/selectors/service-offering.selectors.ts
@@ -61,21 +61,7 @@ const getAvailableByResourcesSync = (
   zone: Zone
 ) => {
   const availableInZone = getOfferingsAvailableInZone(serviceOfferings, availability, zone);
-
-  return availableInZone.filter(offering => {
-    let enoughCpus;
-    let enoughMemory;
-
-    if (offering.iscustomized) {
-      enoughCpus = resourceUsage.available.cpus >= offering.customOfferingRestrictions.cpunumber.min;
-      enoughMemory = resourceUsage.available.memory >= offering.customOfferingRestrictions.memory.min;
-    } else {
-      enoughCpus = resourceUsage.available.cpus >= offering.cpunumber;
-      enoughMemory = resourceUsage.available.memory >= offering.memory;
-    }
-
-    return enoughCpus && enoughMemory;
-  });
+  return availableInZone;
 };
 
 export const getAvailableOfferingsForVmCreation = createSelector(
diff --git a/src/app/vm/vm-creation/service-offering/vm-creation-service-offering.container.ts b/src/app/vm/vm-creation/service-offering/vm-creation-service-offering.container.ts
index 566c2f19a6..7fd8b5373b 100644
--- a/src/app/vm/vm-creation/service-offering/vm-creation-service-offering.container.ts
+++ b/src/app/vm/vm-creation/service-offering/vm-creation-service-offering.container.ts
@@ -11,6 +11,7 @@ import * as fromServiceOfferings from '../../../reducers/service-offerings/redux
 // tslint:disable-next-line
 import { ServiceOfferingFromMode } from '../../../service-offering/service-offering-dialog/service-offering-dialog.component';
 import { UserTagsActions } from '../../../root-store';
+import * as fromAccounts from '../../../reducers/accounts/redux/accounts.reducers';
 
 @Component({
   selector: 'cs-vm-creation-service-offering-container',
@@ -23,6 +24,7 @@ import { UserTagsActions } from '../../../root-store';
       [selectedClasses]="selectedClasses$ | async"
       [viewMode]="viewMode$ | async"
       [query]="query$ | async"
+      [account]="account$ | async"
       (onServiceOfferingUpdate)="updateServiceOffering($event)"
       (onServiceOfferingChange)="changeServiceOffering($event)"
       (viewModeChange)="onViewModeChange($event)"
@@ -37,6 +39,7 @@ export class VmCreationServiceOfferingContainerComponent implements OnInit, Afte
   readonly query$ = this.store.select(fromServiceOfferings.filterQuery);
   readonly selectedClasses$ = this.store.select(fromServiceOfferings.filterSelectedClasses);
   readonly viewMode$ = this.store.select(fromServiceOfferings.filterSelectedViewMode);
+  readonly account$ = this.store.select(fromAccounts.selectUserAccount);
 
   public formMode = ServiceOfferingFromMode.SELECT;
 
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 2d42a3125e..8ff3f3df37 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -118,6 +118,9 @@
     },
     "SNAPSHOT_POLICIES": {
       "HOURLY_TURN_OFF": "Hourly schedule is turned off"
+    },
+    "COMPUTE_OFFERING": {
+      "RESOURCE_LIMIT_EXCEEDED": "The service offering cannot be selected because it doesn't fit the account resources available."
     }
   },
   "NOTIFICATIONS": {
diff --git a/src/i18n/ru.json b/src/i18n/ru.json
index 83972517e9..6671f64af9 100644
--- a/src/i18n/ru.json
+++ b/src/i18n/ru.json
@@ -118,6 +118,9 @@
     },
     "SNAPSHOT_POLICIES": {
       "HOURLY_TURN_OFF": "Почасовое расписание отключено"
+    },
+    "COMPUTE_OFFERING": {
+      "RESOURCE_LIMIT_EXCEEDED": "Вычислительное предложение не может быть выбрано, потому что больше, чем доступные для аккаунта ресурсы."
     }
   },
   "NOTIFICATIONS": {

From 4bf4a0ffaf416573e4880439affb37e8db822eb3 Mon Sep 17 00:00:00 2001
From: HeyRoach <caloriees@gmail.com>
Date: Wed, 26 Sep 2018 13:09:41 +0700
Subject: [PATCH 02/10] custom service offering refactoring

---
 .../custom-service-offering.component.ts      | 31 +++++++++----------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts b/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
index 1da7dddb18..9855b89674 100644
--- a/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
+++ b/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
@@ -1,4 +1,4 @@
-import { Component, Inject } from '@angular/core';
+import { Component, Inject, OnInit } from '@angular/core';
 import { FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'
 import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
 
@@ -7,11 +7,9 @@ import { Account } from '../../shared/models';
 
 function LimitValidator(cpuNumberLimit: number): ValidatorFn {
   return function (control: FormControl) {
-    if (control.value > cpuNumberLimit) {
-      return { cpuLimitExceeded: true };
-    } else {
-      return null;
-    }
+    return control.value > cpuNumberLimit
+      ? { cpuLimitExceeded: true }
+      : null;
   };
 }
 
@@ -20,7 +18,7 @@ function LimitValidator(cpuNumberLimit: number): ValidatorFn {
   templateUrl: 'custom-service-offering.component.html',
   styleUrls: ['custom-service-offering.component.scss']
 })
-export class CustomServiceOfferingComponent {
+export class CustomServiceOfferingComponent implements OnInit {
   public offering: ComputeOfferingViewModel;
   public hardwareForm: FormGroup;
   public account: Account;
@@ -33,17 +31,16 @@ export class CustomServiceOfferingComponent {
   ) {
     this.offering = data.offering;
     this.account = data.account;
-    if (this.offering.customOfferingRestrictions.cpunumber.max > this.account.cpuavailable) {
-      this.maxCpu = this.account.cpuavailable
-    } else {
-      this.maxCpu = this.offering.customOfferingRestrictions.cpunumber.max;
-    }
+  }
+
+  public ngOnInit() {
+    const cpuFromOffering = this.offering.customOfferingRestrictions.cpunumber.max;
+    const memoryFromOffering = this.offering.customOfferingRestrictions.memory.max;
 
-    if (this.offering.customOfferingRestrictions.memory.max > this.account.memoryavailable) {
-      this.maxMemory = this.account.memoryavailable;
-    } else {
-      this.maxMemory = this.offering.customOfferingRestrictions.memory.max;
-    }
+    this.maxCpu = cpuFromOffering > this.account.cpuavailable
+      ? this.account.cpuavailable : cpuFromOffering;
+    this.maxMemory = memoryFromOffering > this.account.memoryavailable
+      ? this.account.memoryavailable : memoryFromOffering;
 
     this.createForm();
   }

From 6c5ddd9b3d8b8bbadcdbc0b3137e5910f418ca31 Mon Sep 17 00:00:00 2001
From: HeyRoach <caloriees@gmail.com>
Date: Thu, 27 Sep 2018 08:17:58 +0700
Subject: [PATCH 03/10] updates after review

---
 .../custom-service-offering.component.ts         | 12 ++----------
 .../service-offering-dialog.component.html       |  8 ++++++--
 .../service-offering-dialog.component.ts         |  7 ++++---
 .../service-offering-list.component.html         |  4 ----
 .../service-offering-list.component.ts           |  1 -
 .../vm/selectors/service-offering.selectors.ts   | 16 ++--------------
 6 files changed, 14 insertions(+), 34 deletions(-)

diff --git a/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts b/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
index 9855b89674..c7c79a23ec 100644
--- a/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
+++ b/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
@@ -5,14 +5,6 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
 import { ComputeOfferingViewModel } from '../../vm/view-models';
 import { Account } from '../../shared/models';
 
-function LimitValidator(cpuNumberLimit: number): ValidatorFn {
-  return function (control: FormControl) {
-    return control.value > cpuNumberLimit
-      ? { cpuLimitExceeded: true }
-      : null;
-  };
-}
-
 @Component({
   selector: 'cs-custom-service-offering',
   templateUrl: 'custom-service-offering.component.html',
@@ -58,9 +50,9 @@ export class CustomServiceOfferingComponent implements OnInit {
 
   private createForm() {
     this.hardwareForm = new FormGroup({
-      cpuNumber: new FormControl(this.offering.cpunumber, [Validators.required, LimitValidator(this.maxCpu)]),
+      cpuNumber: new FormControl(this.offering.cpunumber, [Validators.required, Validators.max(this.maxCpu)]),
       cpuSpeed: new FormControl(this.offering.cpuspeed, [Validators.required]),
-      memory: new FormControl(this.offering.memory, [Validators.required, LimitValidator(this.maxMemory)]),
+      memory: new FormControl(this.offering.memory, [Validators.required, Validators.max(this.maxMemory)]),
     });
   }
 }
diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
index 4f8e29eb5e..358d0b4733 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
@@ -18,7 +18,6 @@ <h3 class="mat-dialog-title">
       [offeringList]="serviceOfferings"
       [selectedOffering]="serviceOffering"
       [showFields]="showFields"
-      [resourcesLimitExceeded]="resourcesLimitExceeded"
       (selectedOfferingChange)="updateOffering($event)"
     ></cs-service-offering-list>
 
@@ -28,6 +27,11 @@ <h3 class="mat-dialog-title">
     >{{ "SERVICE_OFFERING.VM_WILL_BE_RESTARTED" | translate }}
     </div>
   </div>
+
+  <mat-error *ngIf="resourcesLimitExceeded">
+    {{ 'ERRORS.COMPUTE_OFFERING.RESOURCE_LIMIT_EXCEEDED' | translate }}
+  </mat-error>
+
   <div class="mat-dialog-actions">
     <div>
       <button mat-button color="primary" (click)="showFields = !showFields">
@@ -42,7 +46,7 @@ <h3 class="mat-dialog-title">
       <button
         mat-button
         color="primary"
-        [disabled]="isSubmitButtonDisabled() || resourcesLimitExceeded"
+        [disabled]="isSubmitButtonDisabled()"
         (click)="onChange()"
       >
         {{ (formMode ? 'COMMON.SELECT' : 'COMMON.CHANGE') | translate }}
diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
index 82976492ff..203eecd149 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
@@ -85,7 +85,8 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
       || isNoOfferingsInCurrentViewMode
       || isSelectedOfferingFromDifferentViewMode
       || isSelectedOfferingDoNotHaveParams
-      || isSelectedOfferingDifferentFromCurrent;
+      || isSelectedOfferingDifferentFromCurrent
+      || this.resourcesLimitExceeded;
   }
 
   private isSelectedOfferingDifferent(): boolean {
@@ -108,8 +109,8 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
     let memoryExceeded;
 
     if (offering.iscustomized) {
-      сpusExceeded = this.account.cpuavailable < this.serviceOffering['customOfferingRestrictions'].cpunumber.min;
-      memoryExceeded = this.account.memoryavailable < this.serviceOffering['customOfferingRestrictions'].memory.min;
+      сpusExceeded = this.account.cpuavailable < this.serviceOffering.customOfferingRestrictions.cpunumber.min;
+      memoryExceeded = this.account.memoryavailable < this.serviceOffering.customOfferingRestrictions.memory.min;
     } else {
       сpusExceeded = this.account.cpuavailable < this.serviceOffering.cpunumber;
       memoryExceeded = this.account.memoryavailable < this.serviceOffering.memory;
diff --git a/src/app/service-offering/service-offering-list/service-offering-list.component.html b/src/app/service-offering/service-offering-list/service-offering-list.component.html
index b0ac793fc6..aca65c064d 100644
--- a/src/app/service-offering/service-offering-list/service-offering-list.component.html
+++ b/src/app/service-offering/service-offering-list/service-offering-list.component.html
@@ -83,10 +83,6 @@ <h5>{{ getDescription(group.soClass) | translate }}</h5>
   </ng-container>
 </div>
 
-<mat-error *ngIf="resourcesLimitExceeded">
-  {{ 'ERRORS.COMPUTE_OFFERING.RESOURCE_LIMIT_EXCEEDED' | translate }}
-</mat-error>
-
 <cs-no-results *ngIf="!offeringList?.length && !isLoading"></cs-no-results>
 
 
diff --git a/src/app/service-offering/service-offering-list/service-offering-list.component.ts b/src/app/service-offering/service-offering-list/service-offering-list.component.ts
index 9deb311aec..d63e28060e 100644
--- a/src/app/service-offering/service-offering-list/service-offering-list.component.ts
+++ b/src/app/service-offering/service-offering-list/service-offering-list.component.ts
@@ -24,7 +24,6 @@ export class ServiceOfferingListComponent implements OnChanges {
   @Input() public isLoading = false;
   @Input() public showFields: boolean;
   @Input() public account: Account;
-  @Input() public resourcesLimitExceeded = false;
   @Output() public selectedOfferingChange = new EventEmitter<ComputeOfferingViewModel>();
 
   public list: Array<{ soClass: ServiceOfferingClass, items: MatTableDataSource<ComputeOfferingViewModel> }>;
diff --git a/src/app/vm/selectors/service-offering.selectors.ts b/src/app/vm/selectors/service-offering.selectors.ts
index 2577dcd8b7..fe75f44b39 100644
--- a/src/app/vm/selectors/service-offering.selectors.ts
+++ b/src/app/vm/selectors/service-offering.selectors.ts
@@ -54,16 +54,6 @@ const getOfferingsAvailableInZone = (
   });
 };
 
-const getAvailableByResourcesSync = (
-  serviceOfferings: ComputeOfferingViewModel[],
-  availability: OfferingAvailability,
-  resourceUsage: ResourceStats,
-  zone: Zone
-) => {
-  const availableInZone = getOfferingsAvailableInZone(serviceOfferings, availability, zone);
-  return availableInZone;
-};
-
 export const getAvailableOfferingsForVmCreation = createSelector(
   getComputeOfferingViewModel,
   configSelectors.get('offeringAvailability'),
@@ -74,8 +64,7 @@ export const getAvailableOfferingsForVmCreation = createSelector(
       return [];
     }
 
-    const resourceUsage = ResourceStats.fromAccount([user]);
-    return getAvailableByResourcesSync(serviceOfferings, availability, resourceUsage, zone);
+    return getOfferingsAvailableInZone(serviceOfferings, availability, zone);
   }
 );
 
@@ -98,8 +87,7 @@ export const getAvailableOfferings = createSelector(
       return [];
     }
 
-    const resourceUsage = ResourceStats.fromAccount([user]);
-    const availableOfferings = getAvailableByResourcesSync(serviceOfferings, availability, resourceUsage, zone);
+    const availableOfferings = getOfferingsAvailableInZone(serviceOfferings, availability, zone);
 
     const filterByCompatibilityPolicy = VmCompatibilityPolicy.getFilter(compatibilityPolicy, currentOffering);
 

From 1597f1f0011dad73a2546249985b30be911547a1 Mon Sep 17 00:00:00 2001
From: HeyRoach <caloriees@gmail.com>
Date: Thu, 27 Sep 2018 11:25:40 +0700
Subject: [PATCH 04/10] update translations

---
 src/i18n/ru.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/i18n/ru.json b/src/i18n/ru.json
index 8736ab6300..2949d8bce6 100644
--- a/src/i18n/ru.json
+++ b/src/i18n/ru.json
@@ -120,7 +120,7 @@
       "HOURLY_TURN_OFF": "Почасовое расписание отключено"
     },
     "COMPUTE_OFFERING": {
-      "RESOURCE_LIMIT_EXCEEDED": "Вычислительное предложение не может быть выбрано, потому что больше, чем доступные для аккаунта ресурсы."
+      "RESOURCE_LIMIT_EXCEEDED": "Вычислительное предложение не может быть выбрано. Размер выбранного предложения превышает доступные ресурсы аккаунта."
     }
   },
   "NOTIFICATIONS": {

From e5eb58d9dde09077f78b98b7ff1c11693236c6df Mon Sep 17 00:00:00 2001
From: HeyRoach <caloriees@gmail.com>
Date: Tue, 2 Oct 2018 08:42:22 +0700
Subject: [PATCH 05/10] after code review

---
 src/app/app-routing.module.ts                 |   2 +-
 src/app/core/services/system-tags.service.ts  |   0
 src/app/home/home.component.ts                |   2 +-
 .../reducers/vm/redux/vm-creation.effects.ts  |  18 +-
 .../custom-service-offering.component.html    |  14 +-
 .../custom-service-offering.component.scss    |   4 +
 .../custom-service-offering.component.ts      |  20 +-
 .../service-offering-dialog.component.html    |   6 +-
 .../service-offering-dialog.component.scss    |   4 +
 .../service-offering-dialog.component.ts      |  32 ++-
 .../service-offering-list.component.ts        |   4 +-
 .../volume-actions/volume-resize.container.ts |   2 +-
 src/app/shared/models/account-user.model.ts   |   8 +-
 src/app/shared/models/account.model.ts        |  52 ++---
 src/app/shared/models/offering.model.ts       |  12 +-
 .../shared/models/service-offering.model.ts   |  16 +-
 .../template-tags/tags.component.html         |   9 -
 .../template/template-tags/tags.component.ts  |   0
 .../template-tags.component.html              |  17 +-
 .../template-tags/template-tags.component.ts  |   2 +-
 ...mpute-offering-view-model.selector.spec.ts | 188 ++++++++++++++++++
 .../compute-offering-view-model.selector.ts   | 105 +++++++++-
 .../compute-offering.view-model.ts            |   1 +
 .../service-offering-selector.component.html  |   3 +
 .../service-offering-selector.component.scss  |   4 +
 .../service-offering-selector.component.ts    |   6 +-
 .../containers/vm-creation.container.ts       |   7 +-
 .../vm/vm-creation/data/vm-creation-state.ts  |   5 +-
 .../vm-creation-service-offering.container.ts |   1 -
 .../vm/vm-creation/vm-creation.component.html |   2 +-
 .../vm/vm-creation/vm-creation.component.ts   |   9 +-
 src/app/vm/web-shell/web-shell.service.ts     |   0
 src/testutils/data/accounts.ts                |  73 +++++++
 src/testutils/data/compute-offerings.ts       |  37 ++++
 src/testutils/data/index.ts                   |   2 +
 35 files changed, 536 insertions(+), 131 deletions(-)
 delete mode 100644 src/app/core/services/system-tags.service.ts
 delete mode 100644 src/app/template/template-tags/tags.component.html
 delete mode 100644 src/app/template/template-tags/tags.component.ts
 create mode 100644 src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
 delete mode 100644 src/app/vm/web-shell/web-shell.service.ts
 create mode 100644 src/testutils/data/accounts.ts
 create mode 100644 src/testutils/data/compute-offerings.ts
 create mode 100644 src/testutils/data/index.ts

diff --git a/src/app/app-routing.module.ts b/src/app/app-routing.module.ts
index e09b69dad4..d8f0a2ca89 100644
--- a/src/app/app-routing.module.ts
+++ b/src/app/app-routing.module.ts
@@ -57,7 +57,7 @@ const routes: Routes = [
         path: '**',
         redirectTo: 'instances'
       }
-    ]
+    ],
   },
   {
     path: '**',
diff --git a/src/app/core/services/system-tags.service.ts b/src/app/core/services/system-tags.service.ts
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/src/app/home/home.component.ts b/src/app/home/home.component.ts
index 4f3ad53c3f..f8e1ed5932 100644
--- a/src/app/home/home.component.ts
+++ b/src/app/home/home.component.ts
@@ -30,7 +30,7 @@ export class HomeComponent extends WithUnsubscribe() implements OnInit {
 
     this.auth.loggedIn.pipe(
       takeUntil(this.unsubscribe$),
-      filter(isLoggedIn => !!isLoggedIn))
+      filter(isLoggedIn => isLoggedIn))
       .subscribe(() => {
         this.store.dispatch(new authActions.LoadUserAccountRequest({
           name: this.auth.user.account,
diff --git a/src/app/reducers/vm/redux/vm-creation.effects.ts b/src/app/reducers/vm/redux/vm-creation.effects.ts
index b1059227c1..126f29b8ba 100644
--- a/src/app/reducers/vm/redux/vm-creation.effects.ts
+++ b/src/app/reducers/vm/redux/vm-creation.effects.ts
@@ -46,6 +46,7 @@ import * as fromTemplates from '../../templates/redux/template.reducers';
 import * as fromVMs from './vm.reducers';
 import * as fromVMModule from '../../../vm/selectors';
 import { KeyboardLayout } from '../../../shared/types';
+import { ComputeOfferingViewModel } from '../../../vm/view-models';
 
 interface VmCreationParams {
   affinityGroupNames?: string;
@@ -160,11 +161,14 @@ export class VirtualMachineCreationEffects {
       this.store.pipe(select(fromDiskOfferings.selectAll)),
       this.store.pipe(select(configSelectors.get('defaultComputeOffering')))
     ),
-    map((
-      [action, vmCreationState, zones, templates, serviceOfferings, diskOfferings, defaultComputeOfferings]: [
-        vmActions.VmFormUpdate, VmCreationState, Zone[], BaseTemplateModel[], ServiceOffering[], DiskOffering[],
-        DefaultComputeOffering[]
-        ]) => {
+    map(([action, vmCreationState, zones, templates, serviceOfferings, diskOfferings, defaultComputeOfferings]: [
+      vmActions.VmFormUpdate,
+      VmCreationState, Zone[],
+      BaseTemplateModel[],
+      ComputeOfferingViewModel[],
+      DiskOffering[],
+      DefaultComputeOffering[]
+      ]) => {
 
       if (action.payload.zone) {
         let updates = {};
@@ -669,10 +673,10 @@ export class VirtualMachineCreationEffects {
   }
 
   private getPreselectedOffering(
-    offerings: ServiceOffering[],
+    offerings: ComputeOfferingViewModel[],
     zone: Zone,
     defaultComputeOfferingConfiguration: DefaultComputeOffering[]
-  ): ServiceOffering {
+  ): ComputeOfferingViewModel {
     const firstOffering = offerings[0];
     const configForCurrentZone = defaultComputeOfferingConfiguration.find(config => config.zoneId === zone.id);
     if (!configForCurrentZone) {
diff --git a/src/app/service-offering/custom-service-offering/custom-service-offering.component.html b/src/app/service-offering/custom-service-offering/custom-service-offering.component.html
index f771f4956a..1af5a874fb 100644
--- a/src/app/service-offering/custom-service-offering/custom-service-offering.component.html
+++ b/src/app/service-offering/custom-service-offering/custom-service-offering.component.html
@@ -8,9 +8,9 @@ <h5>{{ 'SERVICE_OFFERING.CUSTOM_SERVICE_OFFERING.CPU_NUMBER' | translate }}</h5>
         type="number"
         name="cpuNumber"
         [min]="offering.customOfferingRestrictions.cpunumber.min"
-        [max]="maxCpu"
+        [max]="offering.customOfferingRestrictions.cpunumber.max"
         [csMinValue]="offering.customOfferingRestrictions.cpunumber.min"
-        [csMaxValue]="maxCpu"
+        [csMaxValue]="offering.customOfferingRestrictions.cpunumber.max"
         formControlName="cpuNumber"
         required
       >
@@ -38,15 +38,19 @@ <h5>{{ 'SERVICE_OFFERING.CUSTOM_SERVICE_OFFERING.MEMORY' | translate }}</h5>
         type="number"
         name="memory"
         [min]="offering.customOfferingRestrictions.memory.min"
-        [max]="maxMemory"
+        [max]="offering.customOfferingRestrictions.memory.max"
         [csMinValue]="offering.customOfferingRestrictions.memory.min"
-        [csMaxValue]="maxMemory"
+        [csMaxValue]="offering.customOfferingRestrictions.memory.max"
         formControlName="memory"
         required
       >
     </mat-form-field>
   </div>
 
+  <mat-error *ngIf="!offering.isAvailableByResources">
+    {{ 'ERRORS.COMPUTE_OFFERING.RESOURCE_LIMIT_EXCEEDED' | translate }}
+  </mat-error>
+
   <div class="mat-dialog-actions">
     <button
       mat-button
@@ -60,7 +64,7 @@ <h5>{{ 'SERVICE_OFFERING.CUSTOM_SERVICE_OFFERING.MEMORY' | translate }}</h5>
       mat-button
       color="primary"
       type="submit"
-      [disabled]="!hardwareForm.valid"
+      [disabled]="!hardwareForm.valid || !offering.isAvailableByResources"
     >
       {{ 'COMMON.CONFIRM' | translate }}
     </button>
diff --git a/src/app/service-offering/custom-service-offering/custom-service-offering.component.scss b/src/app/service-offering/custom-service-offering/custom-service-offering.component.scss
index a91094ec88..ad26678bc4 100644
--- a/src/app/service-offering/custom-service-offering/custom-service-offering.component.scss
+++ b/src/app/service-offering/custom-service-offering/custom-service-offering.component.scss
@@ -9,3 +9,7 @@ h5 {
     margin-top: 0;
   }
 }
+
+mat-error {
+  font-size: 13px !important;
+}
diff --git a/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts b/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
index c7c79a23ec..504fc1c361 100644
--- a/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
+++ b/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
@@ -14,8 +14,6 @@ export class CustomServiceOfferingComponent implements OnInit {
   public offering: ComputeOfferingViewModel;
   public hardwareForm: FormGroup;
   public account: Account;
-  public maxCpu: number;
-  public maxMemory: number;
 
   constructor(
     @Inject(MAT_DIALOG_DATA) data,
@@ -26,14 +24,6 @@ export class CustomServiceOfferingComponent implements OnInit {
   }
 
   public ngOnInit() {
-    const cpuFromOffering = this.offering.customOfferingRestrictions.cpunumber.max;
-    const memoryFromOffering = this.offering.customOfferingRestrictions.memory.max;
-
-    this.maxCpu = cpuFromOffering > this.account.cpuavailable
-      ? this.account.cpuavailable : cpuFromOffering;
-    this.maxMemory = memoryFromOffering > this.account.memoryavailable
-      ? this.account.memoryavailable : memoryFromOffering;
-
     this.createForm();
   }
 
@@ -49,10 +39,14 @@ export class CustomServiceOfferingComponent implements OnInit {
   }
 
   private createForm() {
+    // input text=number provide all other validation for current restrictions
     this.hardwareForm = new FormGroup({
-      cpuNumber: new FormControl(this.offering.cpunumber, [Validators.required, Validators.max(this.maxCpu)]),
-      cpuSpeed: new FormControl(this.offering.cpuspeed, [Validators.required]),
-      memory: new FormControl(this.offering.memory, [Validators.required, Validators.max(this.maxMemory)]),
+      cpuNumber: new FormControl(
+        { value: this.offering.cpunumber, disabled: !this.offering.isAvailableByResources }, Validators.required),
+      cpuSpeed: new FormControl(
+        { value: this.offering.cpuspeed, disabled: !this.offering.isAvailableByResources }, Validators.required),
+      memory: new FormControl(
+        { value: this.offering.memory, disabled: !this.offering.isAvailableByResources }, Validators.required),
     });
   }
 }
diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
index 358d0b4733..d82fd69456 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
@@ -26,11 +26,11 @@ <h3 class="mat-dialog-title">
       *ngIf="showRebootMessage"
     >{{ "SERVICE_OFFERING.VM_WILL_BE_RESTARTED" | translate }}
     </div>
+    <mat-error *ngIf="!serviceOffering.isAvailableByResources && isSelectedOfferingViewMode()">
+      {{ 'ERRORS.COMPUTE_OFFERING.RESOURCE_LIMIT_EXCEEDED' | translate }}
+    </mat-error>
   </div>
 
-  <mat-error *ngIf="resourcesLimitExceeded">
-    {{ 'ERRORS.COMPUTE_OFFERING.RESOURCE_LIMIT_EXCEEDED' | translate }}
-  </mat-error>
 
   <div class="mat-dialog-actions">
     <div>
diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.scss b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.scss
index cde163544d..b231378709 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.scss
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.scss
@@ -20,3 +20,7 @@
   flex-direction: column;
   text-align: right;
 }
+
+mat-error {
+  font-size: 13px !important;
+}
diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
index 696919c088..d5554e6229 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
@@ -34,7 +34,6 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
   public serviceOffering: ComputeOfferingViewModel;
   public loading: boolean;
   public showFields = false;
-  public resourcesLimitExceeded = false;
 
   public ngOnInit() {
     this.serviceOffering = this.serviceOfferings.find(_ => _.id === this.serviceOfferingId);
@@ -42,7 +41,6 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
       this.viewMode === ServiceOfferingType.fixed ? this.viewModeChange.emit(ServiceOfferingType.custom) :
         this.viewModeChange.emit(ServiceOfferingType.fixed);
     }
-    this.checkLimits(this.serviceOffering);
   }
 
   public ngOnChanges(changes: SimpleChanges) {
@@ -55,7 +53,6 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
 
   public updateOffering(offering: ComputeOfferingViewModel): void {
     this.serviceOffering = offering;
-    this.checkLimits(this.serviceOffering);
     this.onServiceOfferingUpdate.emit(this.serviceOffering);
   }
 
@@ -73,6 +70,7 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
   public isSubmitButtonDisabled(): boolean {
     const isOfferingNotSelected = !this.serviceOffering;
     const isNoOfferingsInCurrentViewMode = !this.serviceOfferings.length;
+    const isNotEnoughResourcesForCurrentOffering = !this.serviceOffering.isAvailableByResources;
     const isSelectedOfferingFromDifferentViewMode = this.serviceOffering
       && this.serviceOffering.iscustomized !== (this.viewMode === ServiceOfferingType.custom);
     const isSelectedOfferingDoNotHaveParams = this.serviceOffering
@@ -86,7 +84,18 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
       || isSelectedOfferingFromDifferentViewMode
       || isSelectedOfferingDoNotHaveParams
       || isSelectedOfferingDifferentFromCurrent
-      || this.resourcesLimitExceeded;
+      || isNotEnoughResourcesForCurrentOffering;
+  }
+
+  public isSelectedOfferingViewMode(): boolean {
+    if (this.serviceOffering.iscustomized && this.viewMode === ServiceOfferingType.custom) {
+      return true;
+    }
+
+    if (!this.serviceOffering.iscustomized && this.viewMode === ServiceOfferingType.fixed) {
+      return true;
+    }
+    return false;
   }
 
   private isSelectedOfferingDifferent(): boolean {
@@ -103,19 +112,4 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
 
     return isDifferentOfferingId || isSameCustomOfferingWithDifferentParams;
   }
-
-  private checkLimits(offering: ComputeOfferingViewModel) {
-    let сpusExceeded;
-    let memoryExceeded;
-
-    if (offering.iscustomized) {
-      сpusExceeded = this.account.cpuavailable < this.serviceOffering.customOfferingRestrictions.cpunumber.min;
-      memoryExceeded = this.account.memoryavailable < this.serviceOffering.customOfferingRestrictions.memory.min;
-    } else {
-      сpusExceeded = this.account.cpuavailable < this.serviceOffering.cpunumber;
-      memoryExceeded = this.account.memoryavailable < this.serviceOffering.memory;
-    }
-    this.resourcesLimitExceeded = memoryExceeded || сpusExceeded;
-  }
-
 }
diff --git a/src/app/service-offering/service-offering-list/service-offering-list.component.ts b/src/app/service-offering/service-offering-list/service-offering-list.component.ts
index 358250c4da..18eacf1d3d 100644
--- a/src/app/service-offering/service-offering-list/service-offering-list.component.ts
+++ b/src/app/service-offering/service-offering-list/service-offering-list.component.ts
@@ -20,7 +20,7 @@ export class ServiceOfferingListComponent implements OnChanges {
   @Input() public classes: Array<ComputeOfferingClass>;
   @Input() public selectedClasses: Array<string>;
   @Input() public query: string;
-  @Input() public selectedOffering: ServiceOffering;
+  @Input() public selectedOffering: ComputeOfferingViewModel;
   @Input() public isLoading = false;
   @Input() public showFields: boolean;
   @Input() public account: Account;
@@ -102,7 +102,7 @@ export class ServiceOfferingListComponent implements OnChanges {
     }
   }
 
-  public filterOfferings(list: ServiceOffering[], soClass: ComputeOfferingClass) {
+  public filterOfferings(list: ComputeOfferingViewModel[], soClass: ComputeOfferingClass) {
     const classesMap = [soClass].reduce((m, i) => ({ ...m, [i.id]: i }), {});
     return list.filter(offering => classesFilter(offering, this.classes, classesMap));
   }
diff --git a/src/app/shared/actions/volume-actions/volume-resize.container.ts b/src/app/shared/actions/volume-actions/volume-resize.container.ts
index 122c358d90..b82616e1af 100644
--- a/src/app/shared/actions/volume-actions/volume-resize.container.ts
+++ b/src/app/shared/actions/volume-actions/volume-resize.container.ts
@@ -32,7 +32,7 @@ export class VolumeResizeContainerComponent implements OnInit {
 
   public volume: Volume;
 
-  public maxSize = 2;
+  public maxSize = '2';
 
   constructor(
     public authService: AuthService,
diff --git a/src/app/shared/models/account-user.model.ts b/src/app/shared/models/account-user.model.ts
index 7e1ba82377..7e109b3215 100644
--- a/src/app/shared/models/account-user.model.ts
+++ b/src/app/shared/models/account-user.model.ts
@@ -8,22 +8,22 @@ export interface AccountUser extends BaseModelInterface {
   firstname: string;
   lastname: string;
   email: string;
-  password?: string;
   created: string;
   state: string;
   account: string;
   accounttype: number;
-  roleid: string;
   roletype: AccountType;
   rolename: AccountType;
+  roleid: string;
   domain: string;
   domainid: string;
   timezone: string;
   accountid: string;
   iscallerchilddomain: boolean;
   isdefault: boolean;
-  secretkey: string;
-  apikey: string;
+  password?: string;
+  apikey?: string;
+  secretkey?: string;
 }
 
 export interface ApiKeys {
diff --git a/src/app/shared/models/account.model.ts b/src/app/shared/models/account.model.ts
index 919f72e2f4..7a0aff6900 100644
--- a/src/app/shared/models/account.model.ts
+++ b/src/app/shared/models/account.model.ts
@@ -41,55 +41,55 @@ export class AccountData {
 
 export interface Account extends BaseModelInterface {
   accounttype: AccountType;
-  cpuavailable: number;
-  cpulimit: number;
+  cpuavailable: string;
+  cpulimit: string;
   cputotal: number;
   domain: string;
-  fullDomain: string;
   domainid: string;
   id: string;
-  ipavailable: number;
-  iplimit: number;
+  ipavailable: string;
+  iplimit: string;
   iptotal: number;
   isdefault: false;
-  memoryavailable: number;
-  memorylimit: number;
+  memoryavailable: string;
+  memorylimit: string;
   memorytotal: number;
   name: string;
-  networkavailable: number;
-  networklimit: number;
+  networkavailable: string;
+  networklimit: string;
   networktotal: number;
-  primarystorageavailable: number;
-  primarystoragelimit: number;
+  primarystorageavailable: string;
+  primarystoragelimit: string;
   primarystoragetotal: number;
-  role: string;
   roleid: string;
   rolename: string;
   roletype: string;
-  receivedbytes: number;
-  sentbytes: number;
-  secondarystorageavailable: number;
-  secondarystoragelimit: number;
+  receivedbytes?: number;
+  sentbytes?: number;
+  secondarystorageavailable: string;
+  secondarystoragelimit: string;
   secondarystoragetotal: number;
-  snapshotavailable: number;
-  snapshotlimit: number;
+  snapshotavailable: string;
+  snapshotlimit: string;
   snapshottotal: number;
   state: string;
-  templateavailable: number;
-  templatelimit: number;
+  templateavailable: string;
+  templatelimit: string;
   templatetotal: number;
   user: Array<AccountUser>;
-  vmavailable: number;
-  vmlimit: number;
+  vmavailable: string;
+  vmlimit: string;
   vmrunning: number;
   vmstopped: number;
   vmtotal: number;
-  volumeavailable: number;
-  volumelimit: number;
+  volumeavailable: string;
+  volumelimit: string;
   volumetotal: number;
-  vpcavailable: number;
-  vpclimit: number;
+  vpcavailable: string;
+  vpclimit: string;
   vpctotal: number;
+  role?: string;
+  fullDomain?: string;
 }
 
 export const isAdmin = (account: Account) => account.accounttype !== AccountType.User;
diff --git a/src/app/shared/models/offering.model.ts b/src/app/shared/models/offering.model.ts
index bf29039ca7..e45f020385 100644
--- a/src/app/shared/models/offering.model.ts
+++ b/src/app/shared/models/offering.model.ts
@@ -9,15 +9,15 @@ export interface Offering extends BaseModelInterface {
   id: string;
   name: string;
   displaytext: string;
-  diskBytesReadRate: number;
-  diskBytesWriteRate: number;
-  diskIopsReadRate: number;
-  diskIopsWriteRate: number;
   iscustomized: boolean;
-  miniops: number;
-  maxiops: number;
   storagetype: string;
   provisioningtype: string;
+  diskBytesReadRate?: number;
+  diskBytesWriteRate?: number;
+  diskIopsReadRate?: number;
+  diskIopsWriteRate?: number;
+  miniops?: number;
+  maxiops?: number;
 }
 
 export const isOfferingLocal = (offering: Offering) => offering.storagetype === StorageTypes.local;
diff --git a/src/app/shared/models/service-offering.model.ts b/src/app/shared/models/service-offering.model.ts
index 07229c19f1..99c6b3687b 100644
--- a/src/app/shared/models/service-offering.model.ts
+++ b/src/app/shared/models/service-offering.model.ts
@@ -4,19 +4,19 @@ import { userTagKeys } from '../../tags/tag-keys';
 
 export interface ServiceOffering extends Offering {
   created: string;
-  cpunumber: number;
-  cpuspeed: number;
-  memory: number;
-  networkrate: string;
   offerha: boolean;
   limitcpuuse: boolean;
   isvolatile: boolean;
   issystem: boolean;
   defaultuse: boolean;
-  deploymentplanner: string;
-  domain: string;
-  hosttags: string;
-  tags: Array<Tag>;
+  cpunumber?: number;
+  cpuspeed?: number;
+  memory?: number;
+  tags?: Array<Tag>;
+  domain?: string;
+  hosttags?: string;
+  deploymentplanner?: string;
+  networkrate?: string;
 }
 
 export const ServiceOfferingType = {
diff --git a/src/app/template/template-tags/tags.component.html b/src/app/template/template-tags/tags.component.html
deleted file mode 100644
index 363508e192..0000000000
--- a/src/app/template/template-tags/tags.component.html
+++ /dev/null
@@ -1,9 +0,0 @@
-<div *ngIf="entity">
-  <cs-tags-view
-    [tags]="tags"
-    [hasPermissions]="hasPermissions"
-    (onTagAdd)="addTag($event)"
-    (onTagEdit)="editTag($event)"
-    (onTagDelete)="deleteTag($event)"
-  ></cs-tags-view>
-</div>
diff --git a/src/app/template/template-tags/tags.component.ts b/src/app/template/template-tags/tags.component.ts
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/src/app/template/template-tags/template-tags.component.html b/src/app/template/template-tags/template-tags.component.html
index 1baf64c5bb..363508e192 100644
--- a/src/app/template/template-tags/template-tags.component.html
+++ b/src/app/template/template-tags/template-tags.component.html
@@ -1,8 +1,9 @@
-<cs-tags-view
-  [tags]="tags$ | async"
-  [canAddTag]="!entity.isfeatured"
-  [hasPermissions]="hasPermissions"
-  (onTagAdd)="onTagAdd($event)"
-  (onTagEdit)="onTagEdit($event)"
-  (onTagDelete)="onTagDelete($event)"
-></cs-tags-view>
+<div *ngIf="entity">
+  <cs-tags-view
+    [tags]="tags"
+    [hasPermissions]="hasPermissions"
+    (onTagAdd)="addTag($event)"
+    (onTagEdit)="editTag($event)"
+    (onTagDelete)="deleteTag($event)"
+  ></cs-tags-view>
+</div>
diff --git a/src/app/template/template-tags/template-tags.component.ts b/src/app/template/template-tags/template-tags.component.ts
index 38b1cfd21c..11a752e420 100644
--- a/src/app/template/template-tags/template-tags.component.ts
+++ b/src/app/template/template-tags/template-tags.component.ts
@@ -10,7 +10,7 @@ import { KeyValuePair } from '../../tags/tags-view/tags-view.component';
 
 @Component({
   selector: 'cs-template-tags',
-  templateUrl: 'tags.component.html'
+  templateUrl: 'template-tags.component.html'
 })
 export class TemplateTagsComponent extends TagsComponent<BaseTemplateModel> {
   @Input() public entity: BaseTemplateModel;
diff --git a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
new file mode 100644
index 0000000000..cc26e5db43
--- /dev/null
+++ b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
@@ -0,0 +1,188 @@
+import { getComputeOfferingViewModel } from './compute-offering-view-model.selector';
+import { customComputeOffering, fixedComputeOffering } from '../../../../testutils/data';
+import { account } from '../../../../testutils/data/accounts';
+import { nonCustomizableProperties } from '../../../core/config/default-configuration';
+import { ComputeOfferingViewModel } from '../../view-models';
+import { Account } from '../../../shared/models';
+import { CustomComputeOfferingParameters } from '../../../shared/models/config/custom-compute-offering-parameters.interface';
+
+fdescribe('ComputeOfferingViewModelSelector', () => {
+  describe('isAvailableByResources', () => {
+    it ('should be true in fixed compute offering params which satisfy memory and cpu resources', () => {
+      const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
+        [fixedComputeOffering],
+        account,
+        [],
+        nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+        nonCustomizableProperties.customComputeOfferingHardwareValues,
+        []
+      );
+      expect(computeOfferingViewModel.isAvailableByResources).toEqual(true);
+    });
+
+    describe('should be false in fixed compute offering params which unsatisfied', () => {
+      it('memory resources', () => {
+        const limitedAccount: Account = { ...account, memoryavailable: String(fixedComputeOffering.memory - 10) };
+        const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
+          [fixedComputeOffering],
+          limitedAccount,
+          [],
+          nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+          nonCustomizableProperties.customComputeOfferingHardwareValues,
+          []
+        );
+        expect(computeOfferingViewModel.isAvailableByResources).toEqual(false);
+      });
+
+      it('cpu resources', () => {
+        const limitedAccount: Account = { ...account, cpuavailable: String(fixedComputeOffering.cpunumber - 1) };
+        const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
+          [fixedComputeOffering],
+          limitedAccount,
+          [],
+          nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+          nonCustomizableProperties.customComputeOfferingHardwareValues,
+          []
+        );
+        expect(computeOfferingViewModel.isAvailableByResources).toEqual(false);
+      });
+    });
+
+    it('should be true in custom compute offering params which satisfy memory and cpu resources', () => {
+      const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
+        [customComputeOffering],
+        account,
+        [],
+        nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+        nonCustomizableProperties.customComputeOfferingHardwareValues,
+        []
+      );
+      expect(computeOfferingViewModel.isAvailableByResources).toEqual(true);
+    });
+
+    describe('should be false in custom compute offering params which unsatisfied', () => {
+      it('memory resources', () => {
+        const memoryavailable = String(nonCustomizableProperties.customComputeOfferingHardwareValues.memory - 10);
+        const limitedAccount: Account = { ...account, memoryavailable };
+        const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
+          [customComputeOffering],
+          limitedAccount,
+          [],
+          nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+          nonCustomizableProperties.customComputeOfferingHardwareValues,
+          []
+        );
+        expect(computeOfferingViewModel.isAvailableByResources).toEqual(false);
+      });
+
+      it('cpu resources', () => {
+        const cpuavailable = String(nonCustomizableProperties.customComputeOfferingHardwareValues.cpunumber - 1);
+        const limitedAccount: Account = { ...account, cpuavailable };
+        const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
+          [customComputeOffering],
+          limitedAccount,
+          [],
+          nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+          nonCustomizableProperties.customComputeOfferingHardwareValues,
+          []
+        );
+        expect(computeOfferingViewModel.isAvailableByResources).toEqual(false);
+      });
+    });
+  });
+
+  it('must set values within restrictions and resources for custom compute offering', () => {
+    /**
+     *         Min    Value    Max    Resource
+     * cpu     2       7       8        5        => Value = MaxRestrictions = 5
+     * memory  512     4000    8192    2000      => Value = MaxRestrictions = 2000
+     */
+    const cpuavailable = '5';
+    const memoryavailable = '2000';
+    const limitedAccount: Account = { ...account, memoryavailable, cpuavailable };
+
+    const customComputeOfferingParameters: CustomComputeOfferingParameters[] = [
+      {
+        offeringId: customComputeOffering.id,
+        cpunumber: { min: 2, max: 8, value: 7 },
+        cpuspeed: { min: 1000, max: 3000, value: 1500 },
+        memory: { min: 512, max: 8192, value: 4000 }
+      }
+    ];
+
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
+      [customComputeOffering],
+      limitedAccount,
+      customComputeOfferingParameters,
+      nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+      nonCustomizableProperties.customComputeOfferingHardwareValues,
+      []
+    );
+    expect(computeOfferingViewModel.cpunumber).toBe(5);
+    expect(computeOfferingViewModel.memory).toBe(2000);
+    expect(computeOfferingViewModel.customOfferingRestrictions.cpunumber.max).toBe(5);
+    expect(computeOfferingViewModel.customOfferingRestrictions.memory.max).toBe(2000);
+  });
+
+  it('must set default values within restrictions and resources for custom compute offering', () => {
+    /**
+     *         Min    Value    Max    Resource
+     * cpu     2       7       8        5        => Value = MaxRestrictions = 5
+     * memory  512     4000    4000    8000     => Value = MaxRestrictions = 4000
+     */
+    const cpuavailable = '5';
+    const memoryavailable = '8000';
+    const limitedAccount: Account = { ...account, memoryavailable, cpuavailable };
+
+    const customComputeOfferingParameters: CustomComputeOfferingParameters[] = [
+      {
+        offeringId: customComputeOffering.id,
+        cpunumber: { min: 2, max: 8, value: 7 },
+        cpuspeed: { min: 1000, max: 3000, value: 1500 },
+        memory: { min: 512, max: 4000, value: 4000 }
+      }
+    ];
+
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
+      [customComputeOffering],
+      limitedAccount,
+      customComputeOfferingParameters,
+      nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+      nonCustomizableProperties.customComputeOfferingHardwareValues,
+      []
+    );
+    expect(computeOfferingViewModel.cpunumber).toBe(5);
+    expect(computeOfferingViewModel.memory).toBe(4000);
+    expect(computeOfferingViewModel.customOfferingRestrictions.cpunumber.max).toBe(5);
+    expect(computeOfferingViewModel.customOfferingRestrictions.memory.max).toBe(4000);
+  });
+
+
+  // it('isAvailableByResources in custom compute offering params which satisfy resource should be true', () => {
+  //   const customComputeOfferingParameters = [
+  //     {
+  //       'offeringId': '36de12ed-17f1-441f-903f-ab274832c318',
+  //       'cpunumber': {
+  //         'min': 2,
+  //         'max': 8,
+  //         'value': 4
+  //       },
+  //       'cpuspeed': {
+  //         'min': 1000,
+  //         'max': 3000,
+  //         'value': 1500
+  //       },
+  //       'memory': {
+  //         'min': 512,
+  //         'max': 8192,
+  //         'value': 512
+  //       }
+  //     }
+  //   ];
+  //
+  //   const computeOfferingViewModel = { ...fixedComputeOffering, isAvailableByResources: true };
+  //   getComputeOfferingViewModel.projector(
+  //     [fixedComputeOffering], account, customComputeOfferingParameters, null, null, []
+  //   ).toEqual([computeOfferingViewModel])
+  // })
+});
diff --git a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts
index aeb9630ae9..6f3cdadf56 100644
--- a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts
+++ b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts
@@ -10,6 +10,12 @@ import {
 import { ComputeOfferingViewModel } from '../../view-models';
 import { configSelectors, UserTagsSelectors } from '../../../root-store';
 import * as computeOffering from '../../../reducers/service-offerings/redux/service-offerings.reducers';
+import * as fromAuth from '../../../reducers/auth/redux/auth.reducers';
+
+interface Resources {
+  cpuNumber: number | string;
+  memory: number | string;
+}
 
 const getFixedAndCustomOfferingsArrays = (offerings: ServiceOffering[]) => {
   const offeringsArrays = {
@@ -71,7 +77,7 @@ const getCustomHardwareRestrictions = (
 };
 
 const getHardwareValuesFromTags = (
-  serviceOffering: ComputeOfferingViewModel,
+  serviceOffering: ServiceOffering,
   tags: Tag[]
 ): CustomComputeOfferingHardwareValues | null => {
   const getValue = (param) => {
@@ -90,24 +96,83 @@ const getHardwareValuesFromTags = (
   return null;
 };
 
+const checkAvailabilityForFixedByResources = (
+  cpuNumber: number,
+  memory: number,
+  availableResources: Resources
+): boolean => {
+  const isEnoughCpuNumber = availableResources.cpuNumber === 'Unlimited' || cpuNumber <= availableResources.cpuNumber;
+  const isEnoughMemory = availableResources.memory === 'Unlimited' || memory <= availableResources.memory;
+  return isEnoughCpuNumber && isEnoughMemory;
+};
+
+const checkAvailabilityForCustomByResources = (
+  cpuNumberRestrictions: HardwareLimits,
+  memoryRestrictions: HardwareLimits,
+  availableResources: Resources
+): boolean => {
+  const isEnoughCpuNumber = cpuNumberRestrictions.min <= availableResources.cpuNumber;
+  const isEnoughMemory = memoryRestrictions.min <= availableResources.memory;
+  return isEnoughCpuNumber && isEnoughMemory;
+};
+
 const getValueThatSatisfiesRestrictions = (defaultValue: number, restrictions: HardwareLimits) => {
   if (restrictions.min > defaultValue) {
     return restrictions.min;
-  } else if (defaultValue > restrictions.max) {
+  }
+  if (defaultValue > restrictions.max) {
     return restrictions.max;
   }
 
   return defaultValue;
 };
 
+const getValueThatSatisfiesResources = (defaultValue: number, resourceLimit: string | number): number => {
+  const limit = Number(resourceLimit);
+  if (!isNaN(limit) && limit < defaultValue) {
+    return limit;
+  }
+
+  return defaultValue;
+};
+
+const getRestrictionsThatSatisfiesResources = (
+  restrictions: CustomComputeOfferingHardwareRestrictions,
+  resources: Resources
+): CustomComputeOfferingHardwareRestrictions => {
+  const cpuResource = Number(resources.cpuNumber);
+  const memoryResource = Number(resources.memory);
+  let maxCpuNumber = restrictions.cpunumber.max;
+  if (!isNaN(cpuResource)) {
+    maxCpuNumber = restrictions.cpunumber.max > cpuResource ? cpuResource : restrictions.cpunumber.max;
+  }
+  let maxMemory = restrictions.memory.max;
+  if (!isNaN(memoryResource)) {
+    maxMemory = restrictions.memory.max > memoryResource ? memoryResource : restrictions.memory.max;
+  }
+  return <CustomComputeOfferingHardwareRestrictions>{
+    ...restrictions,
+    cpunumber: {
+      min: restrictions.cpunumber.min,
+      max: maxCpuNumber
+    },
+    memory: {
+      min: restrictions.memory.min,
+      max: maxMemory
+    }
+  };
+};
+
 export const getComputeOfferingViewModel = createSelector(
   computeOffering.selectAll,
+  fromAuth.getUserAccount,
   configSelectors.get('customComputeOfferingParameters'),
   configSelectors.get('defaultCustomComputeOfferingRestrictions'),
   configSelectors.get('customComputeOfferingHardwareValues'),
   UserTagsSelectors.getServiceOfferingParamTags,
   (
     offerings,
+    account,
     customComputeOfferingParameters,
     defaultRestrictions,
     defaultHardwareValues,
@@ -125,24 +190,52 @@ export const getComputeOfferingViewModel = createSelector(
         const prioritizedHardwareValues = hardwareValuesFromTags || customHardwareValues || defaultHardwareValues;
         const prioritizedRestrictions = customHardwareRestrictions || defaultRestrictions;
 
-        const cpunumber = getValueThatSatisfiesRestrictions(
+        const availableResources: Resources = {
+          cpuNumber: account && account.cpuavailable || 'Infinity',
+          memory: account && account.memoryavailable || 'Infinity'
+        };
+        const isAvailableByResources = checkAvailabilityForCustomByResources(
+          prioritizedRestrictions.cpunumber, prioritizedRestrictions.memory, availableResources);
+
+        let cpunumber = getValueThatSatisfiesRestrictions(
           prioritizedHardwareValues.cpunumber, prioritizedRestrictions.cpunumber);
         const cpuspeed = getValueThatSatisfiesRestrictions(
           prioritizedHardwareValues.cpuspeed, prioritizedRestrictions.cpuspeed);
-        const memory = getValueThatSatisfiesRestrictions(
+        let memory = getValueThatSatisfiesRestrictions(
           prioritizedHardwareValues.memory, prioritizedRestrictions.memory);
 
+        if (isAvailableByResources) {
+          cpunumber = getValueThatSatisfiesResources(cpunumber, availableResources.cpuNumber);
+          memory = getValueThatSatisfiesResources(memory, availableResources.memory);
+        }
+
+        const customOfferingRestrictions = getRestrictionsThatSatisfiesResources(
+          prioritizedRestrictions, availableResources);
 
         const offeringViewModel: ComputeOfferingViewModel = {
           ...offering,
           cpunumber,
           cpuspeed,
           memory,
-          customOfferingRestrictions: prioritizedRestrictions
+          customOfferingRestrictions,
+          isAvailableByResources
         };
         return offeringViewModel;
       });
 
-    return [...fixedOfferings, ...customOfferingsWithMetadata];
+    const fixedOfferingWithMeta = fixedOfferings.map(offering => {
+      const availableResources: Resources = {
+        cpuNumber: account && account.cpuavailable || 'Infinity',
+        memory: account && account.memoryavailable || 'Infinity'
+      };
+      const offeringViewModel: ComputeOfferingViewModel = {
+        ...offering,
+        isAvailableByResources: checkAvailabilityForFixedByResources(
+          offering.cpunumber, offering.memory, availableResources)
+      };
+      return offeringViewModel;
+    });
+
+    return [...fixedOfferingWithMeta, ...customOfferingsWithMetadata];
   }
 );
diff --git a/src/app/vm/view-models/compute-offering.view-model.ts b/src/app/vm/view-models/compute-offering.view-model.ts
index 329cf697bf..a9122b5eac 100644
--- a/src/app/vm/view-models/compute-offering.view-model.ts
+++ b/src/app/vm/view-models/compute-offering.view-model.ts
@@ -1,5 +1,6 @@
 import { CustomComputeOfferingHardwareRestrictions, ServiceOffering } from '../../shared/models';
 
 export interface ComputeOfferingViewModel extends ServiceOffering {
+  isAvailableByResources: boolean;
   customOfferingRestrictions?: CustomComputeOfferingHardwareRestrictions;
 }
diff --git a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.html b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.html
index 784a5c83d8..a68569e594 100644
--- a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.html
+++ b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.html
@@ -14,6 +14,9 @@ <h4 class="dialog-select-header">
     <span class="service-offering-info truncate" [matTooltip]="offeringName | async">
       {{ offeringName | async }}
     </span>
+    <mat-error *ngIf="!serviceOffering.isAvailableByResources">
+      {{ 'ERRORS.COMPUTE_OFFERING.RESOURCE_LIMIT_EXCEEDED' | translate }}
+    </mat-error>
   </ng-template>
   <ng-template #nameStub>
     {{ 'VM_PAGE.VM_CREATION.NO_OFFERINGS' | translate }}
diff --git a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.scss b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.scss
index 113be9a32a..042905a17d 100644
--- a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.scss
+++ b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.scss
@@ -18,3 +18,7 @@
   text-align: left;
   padding-top: 18px;
 }
+
+mat-error {
+  font-size: 10pt !important;
+}
diff --git a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.ts b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.ts
index cb28bbaf85..8b70d8bffa 100644
--- a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.ts
+++ b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.ts
@@ -19,7 +19,7 @@ export class ServiceOfferingSelectorComponent {
   @Input() public serviceOfferings: Array<ComputeOfferingViewModel>;
   @Output() public change: EventEmitter<ServiceOffering>;
 
-  private _serviceOffering: ServiceOffering;
+  private _serviceOffering: ComputeOfferingViewModel;
 
   constructor(
     private dialog: MatDialog,
@@ -29,11 +29,11 @@ export class ServiceOfferingSelectorComponent {
   }
 
   @Input()
-  public get serviceOffering(): ServiceOffering {
+  public get serviceOffering(): ComputeOfferingViewModel {
     return this._serviceOffering;
   }
 
-  public set serviceOffering(serviceOffering: ServiceOffering) {
+  public set serviceOffering(serviceOffering: ComputeOfferingViewModel) {
     this._serviceOffering = serviceOffering;
   }
 
diff --git a/src/app/vm/vm-creation/containers/vm-creation.container.ts b/src/app/vm/vm-creation/containers/vm-creation.container.ts
index 0cec90d411..b626e0dc08 100644
--- a/src/app/vm/vm-creation/containers/vm-creation.container.ts
+++ b/src/app/vm/vm-creation/containers/vm-creation.container.ts
@@ -2,7 +2,7 @@ import { Component, OnInit } from '@angular/core';
 import { MatDialogRef } from '@angular/material';
 import { select, Store } from '@ngrx/store';
 import { combineLatest, Observable } from 'rxjs';
-import { first, map } from 'rxjs/operators';
+import { first, filter, map } from 'rxjs/operators';
 
 import {
   AccountResourceType,
@@ -38,6 +38,7 @@ import * as fromVMs from '../../../reducers/vm/redux/vm.reducers';
 import * as zoneActions from '../../../reducers/zones/redux/zones.actions';
 import * as fromZones from '../../../reducers/zones/redux/zones.reducers';
 import { getAvailableOfferingsForVmCreation } from '../../selectors';
+import { ComputeOfferingViewModel } from '../../view-models';
 
 @Component({
   selector: 'cs-vm-creation-container',
@@ -127,14 +128,14 @@ export class VmCreationContainerComponent implements OnInit {
   }
 
   public ngOnInit() {
-    this.store.dispatch(new vmActions.VmCreationFormInit());
+    this.store.dispatch(new vmActions.VmCreationFormInit())
   }
 
   public onDisplayNameChange(displayName: string) {
     this.store.dispatch(new vmActions.VmFormUpdate({ displayName }));
   }
 
-  public onServiceOfferingChange(serviceOffering: ServiceOffering) {
+  public onServiceOfferingChange(serviceOffering: ComputeOfferingViewModel) {
     this.store.dispatch(new vmActions.VmFormUpdate({ serviceOffering }));
   }
 
diff --git a/src/app/vm/vm-creation/data/vm-creation-state.ts b/src/app/vm/vm-creation/data/vm-creation-state.ts
index aa237295dd..6869bb285f 100644
--- a/src/app/vm/vm-creation/data/vm-creation-state.ts
+++ b/src/app/vm/vm-creation/data/vm-creation-state.ts
@@ -1,6 +1,7 @@
-import { AffinityGroup, DiskOffering, InstanceGroup, ServiceOffering, SSHKeyPair, Zone } from '../../../shared/models';
+import { AffinityGroup, DiskOffering, InstanceGroup, SSHKeyPair, Zone } from '../../../shared/models';
 import { BaseTemplateModel } from '../../../template/shared';
 import { VmCreationSecurityGroupData } from '../security-group/vm-creation-security-group-data';
+import { ComputeOfferingViewModel } from '../../view-models';
 
 export interface NotSelected {
   name: string;
@@ -17,7 +18,7 @@ export interface VmCreationState {
   rootDiskSize: number;
   rootDiskMinSize: number;
   securityGroupData: VmCreationSecurityGroupData;
-  serviceOffering: ServiceOffering;
+  serviceOffering: ComputeOfferingViewModel;
   sshKeyPair: SSHKeyPair | NotSelected;
   template: BaseTemplateModel;
   zone: Zone;
diff --git a/src/app/vm/vm-creation/service-offering/vm-creation-service-offering.container.ts b/src/app/vm/vm-creation/service-offering/vm-creation-service-offering.container.ts
index 0ae0887038..87e2c2577c 100644
--- a/src/app/vm/vm-creation/service-offering/vm-creation-service-offering.container.ts
+++ b/src/app/vm/vm-creation/service-offering/vm-creation-service-offering.container.ts
@@ -10,7 +10,6 @@ import * as fromServiceOfferings from '../../../reducers/service-offerings/redux
 // tslint:disable-next-line
 import { ServiceOfferingFromMode } from '../../../service-offering/service-offering-dialog/service-offering-dialog.component';
 import * as fromAccounts from '../../../reducers/accounts/redux/accounts.reducers';
-import { UserTagsActions } from '../../../root-store';
 
 @Component({
   selector: 'cs-vm-creation-service-offering-container',
diff --git a/src/app/vm/vm-creation/vm-creation.component.html b/src/app/vm/vm-creation/vm-creation.component.html
index 2fcb8a1ac3..be4cbcb0c5 100644
--- a/src/app/vm/vm-creation/vm-creation.component.html
+++ b/src/app/vm/vm-creation/vm-creation.component.html
@@ -234,7 +234,7 @@ <h4>{{ 'VM_PAGE.VM_CREATION.SSH_KEY_PAIR' | translate }}</h4>
           mat-button
           color="primary"
           type="submit"
-          [disabled]="!vmCreateForm.valid || nameIsTaken || !vmCreationState.template"
+          [disabled]="isSubmitButtonDisabled(vmCreateForm.valid)"
         >
           {{ 'COMMON.CREATE' | translate }}
         </button>
diff --git a/src/app/vm/vm-creation/vm-creation.component.ts b/src/app/vm/vm-creation/vm-creation.component.ts
index 0f3520f52f..2da91c3b6a 100644
--- a/src/app/vm/vm-creation/vm-creation.component.ts
+++ b/src/app/vm/vm-creation/vm-creation.component.ts
@@ -95,7 +95,7 @@ export class VmCreationComponent {
       && !!this.vmCreationState.rootDiskMinSize;
   }
 
-  public get rootDiskSizeLimit(): number {
+  public get rootDiskSizeLimit(): string {
     return this.account && this.account.primarystorageavailable;
   }
 
@@ -150,4 +150,11 @@ export class VmCreationComponent {
     e.preventDefault();
     this.deploy.emit(this.vmCreationState);
   }
+
+  public isSubmitButtonDisabled(isFormValid: boolean): boolean {
+    return !isFormValid
+      || this.nameIsTaken
+      || !this.vmCreationState.template
+      || !this.vmCreationState.serviceOffering.isAvailableByResources;
+  }
 }
diff --git a/src/app/vm/web-shell/web-shell.service.ts b/src/app/vm/web-shell/web-shell.service.ts
deleted file mode 100644
index e69de29bb2..0000000000
diff --git a/src/testutils/data/accounts.ts b/src/testutils/data/accounts.ts
new file mode 100644
index 0000000000..8e20942bb3
--- /dev/null
+++ b/src/testutils/data/accounts.ts
@@ -0,0 +1,73 @@
+import { Account } from '../../app/shared/models';
+import { AccountUser } from '../../app/shared/models/account-user.model';
+import { AccountType } from '../../app/shared/models/account.model';
+
+const user: AccountUser = {
+  id: 'de80acbc-5984-48fd-90dd-061c5c3f9ba9',
+  username: 'test',
+  firstname: 'firstname',
+  lastname: 'lastname',
+  email: 'hey@bk.ru',
+  created: '2018-09-24T04:58:53+0000',
+  state: 'enabled',
+  account: 'test',
+  accounttype: 0,
+  roleid: 'ff636770-acbe-11e8-b088-0242ac110002',
+  roletype: AccountType.User,
+  rolename: AccountType.User,
+  domainid: 'ef2a7031-acbe-11e8-b088-0242ac110002',
+  domain: 'ROOT',
+  timezone: 'Etc/GMT 12',
+  accountid: '22dd3d42-37c7-42fe-bb60-cbf9ec805538',
+  iscallerchilddomain: false,
+  isdefault: false,
+};
+
+export const account: Account = {
+  id: '22dd3d42-37c7-42fe-bb60-cbf9ec805538',
+  name: 'test',
+  accounttype: AccountType.User,
+  roleid: 'ff636770-acbe-11e8-b088-0242ac110002',
+  roletype: 'User',
+  rolename: 'User',
+  domainid: 'ef2a7031-acbe-11e8-b088-0242ac110002',
+  domain: 'ROOT',
+  vmlimit: '20',
+  vmtotal: 0,
+  vmavailable: '20',
+  iplimit: '20',
+  iptotal: 0,
+  ipavailable: '0',
+  volumelimit: '20',
+  volumetotal: 0,
+  volumeavailable: '20',
+  snapshotlimit: '20',
+  snapshottotal: 0,
+  snapshotavailable: '20',
+  templatelimit: '20',
+  templatetotal: 0,
+  templateavailable: '20',
+  vmstopped: 0,
+  vmrunning: 0,
+  networklimit: '20',
+  networktotal: 0,
+  networkavailable: '20',
+  vpclimit: '20',
+  vpctotal: 0,
+  vpcavailable: '20',
+  cpulimit: '5',
+  cputotal: 0,
+  cpuavailable: 'Infinity',
+  memorylimit: '40000',
+  memorytotal: 0,
+  memoryavailable: 'Infinity',
+  primarystoragelimit: '1000',
+  primarystoragetotal: 0,
+  primarystorageavailable: '1000',
+  secondarystoragelimit: '400',
+  secondarystoragetotal: 0,
+  secondarystorageavailable: '400.0',
+  state: 'enabled',
+  user: [user],
+  isdefault: false,
+};
diff --git a/src/testutils/data/compute-offerings.ts b/src/testutils/data/compute-offerings.ts
new file mode 100644
index 0000000000..6da80a105c
--- /dev/null
+++ b/src/testutils/data/compute-offerings.ts
@@ -0,0 +1,37 @@
+import { ServiceOffering } from '../../app/shared/models';
+
+export const fixedComputeOffering: ServiceOffering = {
+  id: '36de12ed-17f1-441f-903f-ab274832c318',
+  name: 'Medium Instance',
+  displaytext: 'Medium Instance',
+  cpunumber: 1,
+  cpuspeed: 1000,
+  memory: 1024,
+  created: '2018-08-31T01:50:04+0000',
+  storagetype: 'shared',
+  provisioningtype: 'thin',
+  offerha: false,
+  limitcpuuse: false,
+  isvolatile: false,
+  issystem: false,
+  defaultuse: false,
+  iscustomized: false,
+};
+
+
+export const customComputeOffering: ServiceOffering = {
+  id: '9f55af11-99de-40b7-ab36-45c576296766',
+  name: 'custom',
+  displaytext: 'any',
+  created: '2018-08-31T01:55:05+0000',
+  storagetype: 'shared',
+  provisioningtype: 'thin',
+  offerha: false,
+  limitcpuuse: false,
+  isvolatile: false,
+  domain: 'ROOT',
+  issystem: false,
+  defaultuse: false,
+  iscustomized: true,
+};
+
diff --git a/src/testutils/data/index.ts b/src/testutils/data/index.ts
new file mode 100644
index 0000000000..3551aaccec
--- /dev/null
+++ b/src/testutils/data/index.ts
@@ -0,0 +1,2 @@
+export * from './compute-offerings';
+export * from './vitrual-machines';

From 5345a259ac4e105b2115e37efbd9fe39aefc24f1 Mon Sep 17 00:00:00 2001
From: HeyRoach <caloriees@gmail.com>
Date: Tue, 2 Oct 2018 09:09:00 +0700
Subject: [PATCH 06/10] replace mat error by span, and fix test

---
 .../custom-service-offering.component.html           |  4 ++--
 .../custom-service-offering.component.scss           |  3 ++-
 .../service-offering-dialog.component.html           |  4 ++--
 .../service-offering-dialog.component.scss           |  3 ++-
 .../compute-offering-view-model.selector.spec.ts     |  6 ++++--
 .../compute-offering-view-model.selector.ts          |  8 ++++----
 .../service-offering-selector.component.html         |  4 ++--
 .../service-offering-selector.component.scss         |  3 ++-
 .../service-offering-selector.component.ts           |  2 +-
 .../model-services/fixtures/serviceOfferings.json    | 12 ++++++++----
 10 files changed, 29 insertions(+), 20 deletions(-)

diff --git a/src/app/service-offering/custom-service-offering/custom-service-offering.component.html b/src/app/service-offering/custom-service-offering/custom-service-offering.component.html
index 1af5a874fb..5c11cfee5d 100644
--- a/src/app/service-offering/custom-service-offering/custom-service-offering.component.html
+++ b/src/app/service-offering/custom-service-offering/custom-service-offering.component.html
@@ -47,9 +47,9 @@ <h5>{{ 'SERVICE_OFFERING.CUSTOM_SERVICE_OFFERING.MEMORY' | translate }}</h5>
     </mat-form-field>
   </div>
 
-  <mat-error *ngIf="!offering.isAvailableByResources">
+  <span class="error-message" *ngIf="!offering.isAvailableByResources">
     {{ 'ERRORS.COMPUTE_OFFERING.RESOURCE_LIMIT_EXCEEDED' | translate }}
-  </mat-error>
+  </span>
 
   <div class="mat-dialog-actions">
     <button
diff --git a/src/app/service-offering/custom-service-offering/custom-service-offering.component.scss b/src/app/service-offering/custom-service-offering/custom-service-offering.component.scss
index ad26678bc4..06c02ce713 100644
--- a/src/app/service-offering/custom-service-offering/custom-service-offering.component.scss
+++ b/src/app/service-offering/custom-service-offering/custom-service-offering.component.scss
@@ -10,6 +10,7 @@ h5 {
   }
 }
 
-mat-error {
+.error-message {
+  color: red;
   font-size: 13px !important;
 }
diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
index d82fd69456..481afb2929 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
@@ -26,9 +26,9 @@ <h3 class="mat-dialog-title">
       *ngIf="showRebootMessage"
     >{{ "SERVICE_OFFERING.VM_WILL_BE_RESTARTED" | translate }}
     </div>
-    <mat-error *ngIf="!serviceOffering.isAvailableByResources && isSelectedOfferingViewMode()">
+    <span class="error-message" *ngIf="!serviceOffering.isAvailableByResources && isSelectedOfferingViewMode()">
       {{ 'ERRORS.COMPUTE_OFFERING.RESOURCE_LIMIT_EXCEEDED' | translate }}
-    </mat-error>
+    </span>
   </div>
 
 
diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.scss b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.scss
index b231378709..2f012f4ea6 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.scss
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.scss
@@ -21,6 +21,7 @@
   text-align: right;
 }
 
-mat-error {
+.error-message {
+  color: red;
   font-size: 13px !important;
 }
diff --git a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
index cc26e5db43..e39d2a6356 100644
--- a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
+++ b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
@@ -4,9 +4,11 @@ import { account } from '../../../../testutils/data/accounts';
 import { nonCustomizableProperties } from '../../../core/config/default-configuration';
 import { ComputeOfferingViewModel } from '../../view-models';
 import { Account } from '../../../shared/models';
-import { CustomComputeOfferingParameters } from '../../../shared/models/config/custom-compute-offering-parameters.interface';
+import {
+  CustomComputeOfferingParameters
+} from '../../../shared/models/config/custom-compute-offering-parameters.interface';
 
-fdescribe('ComputeOfferingViewModelSelector', () => {
+describe('ComputeOfferingViewModelSelector', () => {
   describe('isAvailableByResources', () => {
     it ('should be true in fixed compute offering params which satisfy memory and cpu resources', () => {
       const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
diff --git a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts
index 6f3cdadf56..943cd813ff 100644
--- a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts
+++ b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts
@@ -191,8 +191,8 @@ export const getComputeOfferingViewModel = createSelector(
         const prioritizedRestrictions = customHardwareRestrictions || defaultRestrictions;
 
         const availableResources: Resources = {
-          cpuNumber: account && account.cpuavailable || 'Infinity',
-          memory: account && account.memoryavailable || 'Infinity'
+          cpuNumber: account && account.cpuavailable || '0',
+          memory: account && account.memoryavailable || '0'
         };
         const isAvailableByResources = checkAvailabilityForCustomByResources(
           prioritizedRestrictions.cpunumber, prioritizedRestrictions.memory, availableResources);
@@ -225,8 +225,8 @@ export const getComputeOfferingViewModel = createSelector(
 
     const fixedOfferingWithMeta = fixedOfferings.map(offering => {
       const availableResources: Resources = {
-        cpuNumber: account && account.cpuavailable || 'Infinity',
-        memory: account && account.memoryavailable || 'Infinity'
+        cpuNumber: account && account.cpuavailable || '0',
+        memory: account && account.memoryavailable || '0'
       };
       const offeringViewModel: ComputeOfferingViewModel = {
         ...offering,
diff --git a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.html b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.html
index a68569e594..f3247023f6 100644
--- a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.html
+++ b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.html
@@ -14,9 +14,9 @@ <h4 class="dialog-select-header">
     <span class="service-offering-info truncate" [matTooltip]="offeringName | async">
       {{ offeringName | async }}
     </span>
-    <mat-error *ngIf="!serviceOffering.isAvailableByResources">
+    <span class="error-message" *ngIf="!serviceOffering.isAvailableByResources">
       {{ 'ERRORS.COMPUTE_OFFERING.RESOURCE_LIMIT_EXCEEDED' | translate }}
-    </mat-error>
+    </span>
   </ng-template>
   <ng-template #nameStub>
     {{ 'VM_PAGE.VM_CREATION.NO_OFFERINGS' | translate }}
diff --git a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.scss b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.scss
index 042905a17d..0fcba5e346 100644
--- a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.scss
+++ b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.scss
@@ -19,6 +19,7 @@
   padding-top: 18px;
 }
 
-mat-error {
+.error-message {
+  color: red;
   font-size: 10pt !important;
 }
diff --git a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.ts b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.ts
index 8b70d8bffa..cff8122f7f 100644
--- a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.ts
+++ b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.ts
@@ -13,7 +13,7 @@ import { VmCreationServiceOfferingContainerComponent } from '../../service-offer
 @Component({
   selector: 'cs-service-offering-selector',
   templateUrl: 'service-offering-selector.component.html',
-  styleUrls: ['service-offering-selector.component.scss'],
+  styleUrls: ['service-offering-selector.component.scss']
 })
 export class ServiceOfferingSelectorComponent {
   @Input() public serviceOfferings: Array<ComputeOfferingViewModel>;
diff --git a/src/testutils/mocks/model-services/fixtures/serviceOfferings.json b/src/testutils/mocks/model-services/fixtures/serviceOfferings.json
index ccd2f5cd3f..51b81d43af 100644
--- a/src/testutils/mocks/model-services/fixtures/serviceOfferings.json
+++ b/src/testutils/mocks/model-services/fixtures/serviceOfferings.json
@@ -14,7 +14,8 @@
     "isvolatile": false,
     "issystem": false,
     "defaultuse": false,
-    "iscustomized": false
+    "iscustomized": false,
+    "isAvailableByResources": true
   },
   {
     "id": "b1196c0e-0c1a-4416-bea8-f6a62309fac5",
@@ -31,7 +32,8 @@
     "isvolatile": false,
     "issystem": false,
     "defaultuse": false,
-    "iscustomized": false
+    "iscustomized": false,
+    "isAvailableByResources": true
   },
   {
     "id": "a18d52b6-268e-421c-9d0c-1c1635d3b9b9",
@@ -50,7 +52,8 @@
     "iscustomized": true,
     "cpunumber": 2,
     "cpuspeed": 500,
-    "memory": 1024
+    "memory": 1024,
+    "isAvailableByResources": true
   },
   {
     "id": "a18d52b6-268e-421c-9d0c-1c1635d3b9b9",
@@ -66,6 +69,7 @@
     "domain": "develop",
     "issystem": false,
     "defaultuse": false,
-    "iscustomized": true
+    "iscustomized": true,
+    "isAvailableByResources": true
   }
 ]

From f5fd86ae75ee806aca6b3db25ba17e63c08efaaf Mon Sep 17 00:00:00 2001
From: HeyRoach <caloriees@gmail.com>
Date: Tue, 2 Oct 2018 14:28:43 +0700
Subject: [PATCH 07/10] small fixes

---
 .../custom-service-offering.component.scss    |   4 +-
 .../custom-service-offering.component.ts      |   8 +-
 .../service-offering-dialog.component.scss    |   4 +-
 .../service-offering-dialog.component.ts      |   1 -
 ...mpute-offering-view-model.selector.spec.ts | 162 +++++++-----------
 .../service-offering-selector.component.scss  |   4 +-
 .../containers/vm-creation.container.ts       |  14 +-
 7 files changed, 75 insertions(+), 122 deletions(-)

diff --git a/src/app/service-offering/custom-service-offering/custom-service-offering.component.scss b/src/app/service-offering/custom-service-offering/custom-service-offering.component.scss
index 06c02ce713..ae72dcc5d0 100644
--- a/src/app/service-offering/custom-service-offering/custom-service-offering.component.scss
+++ b/src/app/service-offering/custom-service-offering/custom-service-offering.component.scss
@@ -11,6 +11,6 @@ h5 {
 }
 
 .error-message {
-  color: red;
-  font-size: 13px !important;
+  color: #f44336;
+  font-size: 13px;
 }
diff --git a/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts b/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
index 504fc1c361..6675b6b23d 100644
--- a/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
+++ b/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
@@ -1,5 +1,5 @@
 import { Component, Inject, OnInit } from '@angular/core';
-import { FormControl, FormGroup, ValidatorFn, Validators } from '@angular/forms'
+import { FormControl, FormGroup, Validators } from '@angular/forms'
 import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material';
 
 import { ComputeOfferingViewModel } from '../../vm/view-models';
@@ -15,10 +15,8 @@ export class CustomServiceOfferingComponent implements OnInit {
   public hardwareForm: FormGroup;
   public account: Account;
 
-  constructor(
-    @Inject(MAT_DIALOG_DATA) data,
-    public dialogRef: MatDialogRef<CustomServiceOfferingComponent>,
-  ) {
+  constructor(@Inject(MAT_DIALOG_DATA) data,
+              public dialogRef: MatDialogRef<CustomServiceOfferingComponent>,) {
     this.offering = data.offering;
     this.account = data.account;
   }
diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.scss b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.scss
index 2f012f4ea6..68a32bebc6 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.scss
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.scss
@@ -22,6 +22,6 @@
 }
 
 .error-message {
-  color: red;
-  font-size: 13px !important;
+  color: #f44336;
+  font-size: 13px;
 }
diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
index d5554e6229..a8db072062 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
@@ -91,7 +91,6 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
     if (this.serviceOffering.iscustomized && this.viewMode === ServiceOfferingType.custom) {
       return true;
     }
-
     if (!this.serviceOffering.iscustomized && this.viewMode === ServiceOfferingType.fixed) {
       return true;
     }
diff --git a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
index e39d2a6356..515157eef8 100644
--- a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
+++ b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
@@ -4,13 +4,11 @@ import { account } from '../../../../testutils/data/accounts';
 import { nonCustomizableProperties } from '../../../core/config/default-configuration';
 import { ComputeOfferingViewModel } from '../../view-models';
 import { Account } from '../../../shared/models';
-import {
-  CustomComputeOfferingParameters
-} from '../../../shared/models/config/custom-compute-offering-parameters.interface';
+import { CustomComputeOfferingParameters } from '../../../shared/models/config/custom-compute-offering-parameters.interface';
 
 describe('ComputeOfferingViewModelSelector', () => {
-  describe('isAvailableByResources', () => {
-    it ('should be true in fixed compute offering params which satisfy memory and cpu resources', () => {
+  it('isAvailableByResources should be true in fixed compute offering params which satisfy memory and cpu resources',
+    () => {
       const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
         [fixedComputeOffering],
         account,
@@ -22,75 +20,70 @@ describe('ComputeOfferingViewModelSelector', () => {
       expect(computeOfferingViewModel.isAvailableByResources).toEqual(true);
     });
 
-    describe('should be false in fixed compute offering params which unsatisfied', () => {
-      it('memory resources', () => {
-        const limitedAccount: Account = { ...account, memoryavailable: String(fixedComputeOffering.memory - 10) };
-        const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
-          [fixedComputeOffering],
-          limitedAccount,
-          [],
-          nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
-          nonCustomizableProperties.customComputeOfferingHardwareValues,
-          []
-        );
-        expect(computeOfferingViewModel.isAvailableByResources).toEqual(false);
-      });
+  it('should be false in fixed compute offering params which unsatisfied memory resources', () => {
+    const limitedAccount: Account = { ...account, memoryavailable: String(fixedComputeOffering.memory - 10) };
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
+      [fixedComputeOffering],
+      limitedAccount,
+      [],
+      nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+      nonCustomizableProperties.customComputeOfferingHardwareValues,
+      []
+    );
+    expect(computeOfferingViewModel.isAvailableByResources).toEqual(false);
+  });
 
-      it('cpu resources', () => {
-        const limitedAccount: Account = { ...account, cpuavailable: String(fixedComputeOffering.cpunumber - 1) };
-        const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
-          [fixedComputeOffering],
-          limitedAccount,
-          [],
-          nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
-          nonCustomizableProperties.customComputeOfferingHardwareValues,
-          []
-        );
-        expect(computeOfferingViewModel.isAvailableByResources).toEqual(false);
-      });
-    });
+  it('should be false in fixed compute offering params which unsatisfied cpu resources', () => {
+    const limitedAccount: Account = { ...account, cpuavailable: String(fixedComputeOffering.cpunumber - 1) };
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
+      [fixedComputeOffering],
+      limitedAccount,
+      [],
+      nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+      nonCustomizableProperties.customComputeOfferingHardwareValues,
+      []
+    );
+    expect(computeOfferingViewModel.isAvailableByResources).toEqual(false);
+  });
 
-    it('should be true in custom compute offering params which satisfy memory and cpu resources', () => {
-      const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
-        [customComputeOffering],
-        account,
-        [],
-        nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
-        nonCustomizableProperties.customComputeOfferingHardwareValues,
-        []
-      );
-      expect(computeOfferingViewModel.isAvailableByResources).toEqual(true);
-    });
+  it('should be true in custom compute offering params which satisfy memory and cpu resources', () => {
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
+      [customComputeOffering],
+      account,
+      [],
+      nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+      nonCustomizableProperties.customComputeOfferingHardwareValues,
+      []
+    );
+    expect(computeOfferingViewModel.isAvailableByResources).toEqual(true);
+  });
 
-    describe('should be false in custom compute offering params which unsatisfied', () => {
-      it('memory resources', () => {
-        const memoryavailable = String(nonCustomizableProperties.customComputeOfferingHardwareValues.memory - 10);
-        const limitedAccount: Account = { ...account, memoryavailable };
-        const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
-          [customComputeOffering],
-          limitedAccount,
-          [],
-          nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
-          nonCustomizableProperties.customComputeOfferingHardwareValues,
-          []
-        );
-        expect(computeOfferingViewModel.isAvailableByResources).toEqual(false);
-      });
+  it('should be false in custom compute offering params which unsatisfied memory resources', () => {
+    const memoryavailable = String(nonCustomizableProperties.customComputeOfferingHardwareValues.memory - 10);
+    const limitedAccount: Account = { ...account, memoryavailable };
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
+      [customComputeOffering],
+      limitedAccount,
+      [],
+      nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+      nonCustomizableProperties.customComputeOfferingHardwareValues,
+      []
+    );
+    expect(computeOfferingViewModel.isAvailableByResources).toEqual(false);
+  });
 
-      it('cpu resources', () => {
-        const cpuavailable = String(nonCustomizableProperties.customComputeOfferingHardwareValues.cpunumber - 1);
-        const limitedAccount: Account = { ...account, cpuavailable };
-        const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
-          [customComputeOffering],
-          limitedAccount,
-          [],
-          nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
-          nonCustomizableProperties.customComputeOfferingHardwareValues,
-          []
-        );
-        expect(computeOfferingViewModel.isAvailableByResources).toEqual(false);
-      });
-    });
+  it('should be false in custom compute offering params which unsatisfied cpu resources', () => {
+    const cpuavailable = String(nonCustomizableProperties.customComputeOfferingHardwareValues.cpunumber - 1);
+    const limitedAccount: Account = { ...account, cpuavailable };
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
+      [customComputeOffering],
+      limitedAccount,
+      [],
+      nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+      nonCustomizableProperties.customComputeOfferingHardwareValues,
+      []
+    );
+    expect(computeOfferingViewModel.isAvailableByResources).toEqual(false);
   });
 
   it('must set values within restrictions and resources for custom compute offering', () => {
@@ -158,33 +151,4 @@ describe('ComputeOfferingViewModelSelector', () => {
     expect(computeOfferingViewModel.customOfferingRestrictions.cpunumber.max).toBe(5);
     expect(computeOfferingViewModel.customOfferingRestrictions.memory.max).toBe(4000);
   });
-
-
-  // it('isAvailableByResources in custom compute offering params which satisfy resource should be true', () => {
-  //   const customComputeOfferingParameters = [
-  //     {
-  //       'offeringId': '36de12ed-17f1-441f-903f-ab274832c318',
-  //       'cpunumber': {
-  //         'min': 2,
-  //         'max': 8,
-  //         'value': 4
-  //       },
-  //       'cpuspeed': {
-  //         'min': 1000,
-  //         'max': 3000,
-  //         'value': 1500
-  //       },
-  //       'memory': {
-  //         'min': 512,
-  //         'max': 8192,
-  //         'value': 512
-  //       }
-  //     }
-  //   ];
-  //
-  //   const computeOfferingViewModel = { ...fixedComputeOffering, isAvailableByResources: true };
-  //   getComputeOfferingViewModel.projector(
-  //     [fixedComputeOffering], account, customComputeOfferingParameters, null, null, []
-  //   ).toEqual([computeOfferingViewModel])
-  // })
 });
diff --git a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.scss b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.scss
index 0fcba5e346..e8ed895110 100644
--- a/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.scss
+++ b/src/app/vm/vm-creation/components/service-offering-selector/service-offering-selector.component.scss
@@ -20,6 +20,6 @@
 }
 
 .error-message {
-  color: red;
-  font-size: 10pt !important;
+  color: #f44336;
+  font-size: 10pt;
 }
diff --git a/src/app/vm/vm-creation/containers/vm-creation.container.ts b/src/app/vm/vm-creation/containers/vm-creation.container.ts
index b626e0dc08..5017b111d7 100644
--- a/src/app/vm/vm-creation/containers/vm-creation.container.ts
+++ b/src/app/vm/vm-creation/containers/vm-creation.container.ts
@@ -2,17 +2,9 @@ import { Component, OnInit } from '@angular/core';
 import { MatDialogRef } from '@angular/material';
 import { select, Store } from '@ngrx/store';
 import { combineLatest, Observable } from 'rxjs';
-import { first, filter, map } from 'rxjs/operators';
-
-import {
-  AccountResourceType,
-  AffinityGroup,
-  DiskOffering,
-  InstanceGroup,
-  ServiceOffering,
-  SSHKeyPair,
-  Zone
-} from '../../../shared/models';
+import { first, map } from 'rxjs/operators';
+
+import { AccountResourceType, AffinityGroup, DiskOffering, InstanceGroup, SSHKeyPair, Zone } from '../../../shared/models';
 import { AuthService } from '../../../shared/services/auth.service';
 import { BaseTemplateModel } from '../../../template/shared';
 import { VmService } from '../../shared/vm.service';

From 65e57c21a371592ead42bbfbaea27dd7a864209a Mon Sep 17 00:00:00 2001
From: HeyRoach <caloriees@gmail.com>
Date: Tue, 2 Oct 2018 14:32:45 +0700
Subject: [PATCH 08/10] lint fixes

---
 .../custom-service-offering.component.ts                 | 6 ++++--
 .../compute-offering-view-model.selector.spec.ts         | 4 +++-
 .../vm/vm-creation/containers/vm-creation.container.ts   | 9 ++++++++-
 3 files changed, 15 insertions(+), 4 deletions(-)

diff --git a/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts b/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
index 6675b6b23d..8e652e3fb4 100644
--- a/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
+++ b/src/app/service-offering/custom-service-offering/custom-service-offering.component.ts
@@ -15,8 +15,10 @@ export class CustomServiceOfferingComponent implements OnInit {
   public hardwareForm: FormGroup;
   public account: Account;
 
-  constructor(@Inject(MAT_DIALOG_DATA) data,
-              public dialogRef: MatDialogRef<CustomServiceOfferingComponent>,) {
+  constructor(
+    @Inject(MAT_DIALOG_DATA) data,
+    public dialogRef: MatDialogRef<CustomServiceOfferingComponent>
+  ) {
     this.offering = data.offering;
     this.account = data.account;
   }
diff --git a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
index 515157eef8..9caf8f8c2b 100644
--- a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
+++ b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
@@ -4,7 +4,9 @@ import { account } from '../../../../testutils/data/accounts';
 import { nonCustomizableProperties } from '../../../core/config/default-configuration';
 import { ComputeOfferingViewModel } from '../../view-models';
 import { Account } from '../../../shared/models';
-import { CustomComputeOfferingParameters } from '../../../shared/models/config/custom-compute-offering-parameters.interface';
+import {
+  CustomComputeOfferingParameters
+} from '../../../shared/models/config/custom-compute-offering-parameters.interface';
 
 describe('ComputeOfferingViewModelSelector', () => {
   it('isAvailableByResources should be true in fixed compute offering params which satisfy memory and cpu resources',
diff --git a/src/app/vm/vm-creation/containers/vm-creation.container.ts b/src/app/vm/vm-creation/containers/vm-creation.container.ts
index 5017b111d7..eb9f6498ba 100644
--- a/src/app/vm/vm-creation/containers/vm-creation.container.ts
+++ b/src/app/vm/vm-creation/containers/vm-creation.container.ts
@@ -4,7 +4,14 @@ import { select, Store } from '@ngrx/store';
 import { combineLatest, Observable } from 'rxjs';
 import { first, map } from 'rxjs/operators';
 
-import { AccountResourceType, AffinityGroup, DiskOffering, InstanceGroup, SSHKeyPair, Zone } from '../../../shared/models';
+import {
+  AccountResourceType,
+  AffinityGroup,
+  DiskOffering,
+  InstanceGroup,
+  SSHKeyPair,
+  Zone
+} from '../../../shared/models';
 import { AuthService } from '../../../shared/services/auth.service';
 import { BaseTemplateModel } from '../../../template/shared';
 import { VmService } from '../../shared/vm.service';

From edf7a0a98b533a7bc7e66ab82c5dadc08e32ef81 Mon Sep 17 00:00:00 2001
From: HeyRoach <caloriees@gmail.com>
Date: Fri, 5 Oct 2018 09:58:09 +0700
Subject: [PATCH 09/10] add usedResources in vm editing for available resources

---
 .../service-offering-dialog.component.html    |   2 +-
 .../service-offering-dialog.component.ts      |   4 +-
 src/app/shared/models/config/index.ts         |   1 +
 .../selectors/service-offering.selectors.ts   |  10 +-
 ...mpute-offering-view-model.selector.spec.ts | 100 +++++++---
 .../compute-offering-view-model.selector.ts   | 176 ++++++++++++------
 src/app/vm/selectors/view-models/index.ts     |   2 +-
 src/testutils/data/index.ts                   |   1 +
 8 files changed, 205 insertions(+), 91 deletions(-)

diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
index 481afb2929..6555a2ff02 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.html
@@ -26,7 +26,7 @@ <h3 class="mat-dialog-title">
       *ngIf="showRebootMessage"
     >{{ "SERVICE_OFFERING.VM_WILL_BE_RESTARTED" | translate }}
     </div>
-    <span class="error-message" *ngIf="!serviceOffering.isAvailableByResources && isSelectedOfferingViewMode()">
+    <span class="error-message" *ngIf="!serviceOffering?.isAvailableByResources && isSelectedOfferingViewMode()">
       {{ 'ERRORS.COMPUTE_OFFERING.RESOURCE_LIMIT_EXCEEDED' | translate }}
     </span>
   </div>
diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
index a8db072062..ae29360939 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
@@ -70,7 +70,7 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
   public isSubmitButtonDisabled(): boolean {
     const isOfferingNotSelected = !this.serviceOffering;
     const isNoOfferingsInCurrentViewMode = !this.serviceOfferings.length;
-    const isNotEnoughResourcesForCurrentOffering = !this.serviceOffering.isAvailableByResources;
+    const isNotEnoughResourcesForCurrentOffering = this.serviceOffering && !this.serviceOffering.isAvailableByResources;
     const isSelectedOfferingFromDifferentViewMode = this.serviceOffering
       && this.serviceOffering.iscustomized !== (this.viewMode === ServiceOfferingType.custom);
     const isSelectedOfferingDoNotHaveParams = this.serviceOffering
@@ -88,7 +88,7 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
   }
 
   public isSelectedOfferingViewMode(): boolean {
-    if (this.serviceOffering.iscustomized && this.viewMode === ServiceOfferingType.custom) {
+    if (this.serviceOffering && this.serviceOffering.iscustomized && this.viewMode === ServiceOfferingType.custom) {
       return true;
     }
     if (!this.serviceOffering.iscustomized && this.viewMode === ServiceOfferingType.fixed) {
diff --git a/src/app/shared/models/config/index.ts b/src/app/shared/models/config/index.ts
index c5a2d3909a..a816dbc71d 100644
--- a/src/app/shared/models/config/index.ts
+++ b/src/app/shared/models/config/index.ts
@@ -9,3 +9,4 @@ export * from './image-group.model';
 export * from './service-offering-availability.interface';
 export * from './offering-compatibility-policy.interface';
 export * from './sidenav-config-element.interface';
+export * from './custom-compute-offering-parameters.interface';
diff --git a/src/app/vm/selectors/service-offering.selectors.ts b/src/app/vm/selectors/service-offering.selectors.ts
index 7b1aab4a92..98f36864e2 100644
--- a/src/app/vm/selectors/service-offering.selectors.ts
+++ b/src/app/vm/selectors/service-offering.selectors.ts
@@ -1,7 +1,6 @@
 import { createSelector } from '@ngrx/store';
 
 import { VmCompatibilityPolicy } from '../shared/vm-compatibility-policy';
-import { ResourceStats } from '../../shared/services/resource-usage.service';
 import { ComputeOfferingViewModel } from '../view-models';
 import { isOfferingLocal } from '../../shared/models/offering.model';
 import {
@@ -10,7 +9,6 @@ import {
   ServiceOfferingAvailability
 } from '../../shared/models/config';
 import { ServiceOffering, ServiceOfferingType, Zone } from '../../shared/models';
-import { getComputeOfferingViewModel } from './view-models';
 import { configSelectors } from '../../root-store';
 import * as fromZones from '../../reducers/zones/redux/zones.reducers';
 import * as fromAuths from '../../reducers/auth/redux/auth.reducers';
@@ -21,6 +19,10 @@ import {
   filterSelectedViewMode,
   getSelectedOffering,
 } from '../../reducers/service-offerings/redux/service-offerings.reducers';
+import {
+  getComputeOfferingForVmCreation,
+  getComputeOfferingForVmEditing
+} from './view-models/compute-offering-view-model.selector';
 
 const isComputeOfferingAvailableInZone = (
   offering: ServiceOffering,
@@ -51,7 +53,7 @@ const getOfferingsAvailableInZone = (
 };
 
 export const getAvailableOfferingsForVmCreation = createSelector(
-  getComputeOfferingViewModel,
+  getComputeOfferingForVmCreation,
   configSelectors.get('serviceOfferingAvailability'),
   fromVMs.getVMCreationZone,
   fromAuths.getUserAccount,
@@ -65,7 +67,7 @@ export const getAvailableOfferingsForVmCreation = createSelector(
 );
 
 export const getAvailableOfferings = createSelector(
-  getComputeOfferingViewModel,
+  getComputeOfferingForVmEditing,
   getSelectedOffering,
   configSelectors.get('serviceOfferingAvailability'),
   configSelectors.get('offeringCompatibilityPolicy'),
diff --git a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
index 9caf8f8c2b..433df25fc9 100644
--- a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
+++ b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.spec.ts
@@ -1,19 +1,19 @@
-import { getComputeOfferingViewModel } from './compute-offering-view-model.selector';
-import { customComputeOffering, fixedComputeOffering } from '../../../../testutils/data';
-import { account } from '../../../../testutils/data/accounts';
+import { account, customComputeOffering, fixedComputeOffering, vm } from '../../../../testutils/data';
 import { nonCustomizableProperties } from '../../../core/config/default-configuration';
 import { ComputeOfferingViewModel } from '../../view-models';
 import { Account } from '../../../shared/models';
+import { CustomComputeOfferingParameters } from '../../../shared/models/config/index';
 import {
-  CustomComputeOfferingParameters
-} from '../../../shared/models/config/custom-compute-offering-parameters.interface';
+  getComputeOfferingForVmCreation,
+  getComputeOfferingForVmEditing
+} from './compute-offering-view-model.selector';
 
-describe('ComputeOfferingViewModelSelector', () => {
+describe('GetComputeOfferingForVmCreationSelector', () => {
   it('isAvailableByResources should be true in fixed compute offering params which satisfy memory and cpu resources',
     () => {
-      const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
-        [fixedComputeOffering],
+      const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingForVmCreation.projector(
         account,
+        [fixedComputeOffering],
         [],
         nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
         nonCustomizableProperties.customComputeOfferingHardwareValues,
@@ -24,9 +24,9 @@ describe('ComputeOfferingViewModelSelector', () => {
 
   it('should be false in fixed compute offering params which unsatisfied memory resources', () => {
     const limitedAccount: Account = { ...account, memoryavailable: String(fixedComputeOffering.memory - 10) };
-    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
-      [fixedComputeOffering],
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingForVmCreation.projector(
       limitedAccount,
+      [fixedComputeOffering],
       [],
       nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
       nonCustomizableProperties.customComputeOfferingHardwareValues,
@@ -37,9 +37,9 @@ describe('ComputeOfferingViewModelSelector', () => {
 
   it('should be false in fixed compute offering params which unsatisfied cpu resources', () => {
     const limitedAccount: Account = { ...account, cpuavailable: String(fixedComputeOffering.cpunumber - 1) };
-    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
-      [fixedComputeOffering],
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingForVmCreation.projector(
       limitedAccount,
+      [fixedComputeOffering],
       [],
       nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
       nonCustomizableProperties.customComputeOfferingHardwareValues,
@@ -49,9 +49,9 @@ describe('ComputeOfferingViewModelSelector', () => {
   });
 
   it('should be true in custom compute offering params which satisfy memory and cpu resources', () => {
-    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
-      [customComputeOffering],
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingForVmCreation.projector(
       account,
+      [customComputeOffering],
       [],
       nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
       nonCustomizableProperties.customComputeOfferingHardwareValues,
@@ -63,9 +63,9 @@ describe('ComputeOfferingViewModelSelector', () => {
   it('should be false in custom compute offering params which unsatisfied memory resources', () => {
     const memoryavailable = String(nonCustomizableProperties.customComputeOfferingHardwareValues.memory - 10);
     const limitedAccount: Account = { ...account, memoryavailable };
-    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
-      [customComputeOffering],
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingForVmCreation.projector(
       limitedAccount,
+      [customComputeOffering],
       [],
       nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
       nonCustomizableProperties.customComputeOfferingHardwareValues,
@@ -77,9 +77,9 @@ describe('ComputeOfferingViewModelSelector', () => {
   it('should be false in custom compute offering params which unsatisfied cpu resources', () => {
     const cpuavailable = String(nonCustomizableProperties.customComputeOfferingHardwareValues.cpunumber - 1);
     const limitedAccount: Account = { ...account, cpuavailable };
-    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
-      [customComputeOffering],
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingForVmCreation.projector(
       limitedAccount,
+      [customComputeOffering],
       [],
       nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
       nonCustomizableProperties.customComputeOfferingHardwareValues,
@@ -107,9 +107,9 @@ describe('ComputeOfferingViewModelSelector', () => {
       }
     ];
 
-    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
-      [customComputeOffering],
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingForVmCreation.projector(
       limitedAccount,
+      [customComputeOffering],
       customComputeOfferingParameters,
       nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
       nonCustomizableProperties.customComputeOfferingHardwareValues,
@@ -140,9 +140,9 @@ describe('ComputeOfferingViewModelSelector', () => {
       }
     ];
 
-    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingViewModel.projector(
-      [customComputeOffering],
+    const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingForVmCreation.projector(
       limitedAccount,
+      [customComputeOffering],
       customComputeOfferingParameters,
       nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
       nonCustomizableProperties.customComputeOfferingHardwareValues,
@@ -154,3 +154,59 @@ describe('ComputeOfferingViewModelSelector', () => {
     expect(computeOfferingViewModel.customOfferingRestrictions.memory.max).toBe(4000);
   });
 });
+
+describe('GetComputeOfferingForVmEditingSelector', () => {
+  it('isAvailableByResources should be true in fixed compute offering params which satisfy memory and cpu resources',
+    () => {
+      const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingForVmEditing.projector(
+        account,
+        [fixedComputeOffering],
+        [],
+        nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+        nonCustomizableProperties.customComputeOfferingHardwareValues,
+        [],
+        vm
+      );
+      expect(computeOfferingViewModel.isAvailableByResources).toEqual(true);
+    });
+
+  it('isAvailableByResources should be true, cause satisfy resources plus used resources in editing vm',
+    () => {
+      const cpuavailable = '0';
+      const memoryavailable = '512';
+      const limitedAccount: Account = { ...account, memoryavailable, cpuavailable };
+      const updatedVm = { ...vm, memory: '512', cpuNumber: 1 };
+
+      const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingForVmEditing.projector(
+        limitedAccount,
+        [fixedComputeOffering],
+        [],
+        nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+        nonCustomizableProperties.customComputeOfferingHardwareValues,
+        [],
+        updatedVm
+      );
+
+      expect(computeOfferingViewModel.isAvailableByResources).toEqual(true);
+    });
+
+  it('isAvailableByResources should be false, cause unsatisfy resources plus used resources in editing vm',
+    () => {
+      const cpuavailable = '0';
+      const memoryavailable = '0';
+      const limitedAccount: Account = { ...account, memoryavailable, cpuavailable };
+      const updatedVm = { ...vm, memory: '512', cpuNumber: 1 };
+
+      const [computeOfferingViewModel]: ComputeOfferingViewModel[] = getComputeOfferingForVmEditing.projector(
+        limitedAccount,
+        [fixedComputeOffering],
+        [],
+        nonCustomizableProperties.defaultCustomComputeOfferingRestrictions,
+        nonCustomizableProperties.customComputeOfferingHardwareValues,
+        [],
+        updatedVm
+      );
+
+      expect(computeOfferingViewModel.isAvailableByResources).toEqual(false);
+    });
+});
diff --git a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts
index 943cd813ff..6d4771e0bc 100644
--- a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts
+++ b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts
@@ -11,6 +11,7 @@ import { ComputeOfferingViewModel } from '../../view-models';
 import { configSelectors, UserTagsSelectors } from '../../../root-store';
 import * as computeOffering from '../../../reducers/service-offerings/redux/service-offerings.reducers';
 import * as fromAuth from '../../../reducers/auth/redux/auth.reducers';
+import * as fromVms from '../../../reducers/vm/redux/vm.reducers';
 
 interface Resources {
   cpuNumber: number | string;
@@ -36,7 +37,7 @@ const getCustomOfferingHardwareParameters = (
   offering: ServiceOffering,
   offeringsParameters: CustomComputeOfferingParameters[]
 ): CustomComputeOfferingParameters | undefined => {
-  return offeringsParameters.find(parameters => parameters.offeringId === offering.id)
+  return offeringsParameters && offeringsParameters.find(parameters => parameters.offeringId === offering.id)
 };
 
 const getCustomHardwareValues = (
@@ -111,8 +112,10 @@ const checkAvailabilityForCustomByResources = (
   memoryRestrictions: HardwareLimits,
   availableResources: Resources
 ): boolean => {
-  const isEnoughCpuNumber = cpuNumberRestrictions.min <= availableResources.cpuNumber;
-  const isEnoughMemory = memoryRestrictions.min <= availableResources.memory;
+  const isEnoughCpuNumber = availableResources.cpuNumber === 'Unlimited'
+    || cpuNumberRestrictions.min <= availableResources.cpuNumber;
+  const isEnoughMemory = availableResources.memory === 'Unlimited'
+    || memoryRestrictions.min <= availableResources.memory;
   return isEnoughCpuNumber && isEnoughMemory;
 };
 
@@ -163,71 +166,57 @@ const getRestrictionsThatSatisfiesResources = (
   };
 };
 
-export const getComputeOfferingViewModel = createSelector(
-  computeOffering.selectAll,
-  fromAuth.getUserAccount,
-  configSelectors.get('customComputeOfferingParameters'),
-  configSelectors.get('defaultCustomComputeOfferingRestrictions'),
-  configSelectors.get('customComputeOfferingHardwareValues'),
-  UserTagsSelectors.getServiceOfferingParamTags,
-  (
+const getComputeOfferingViewModel = (
     offerings,
-    account,
     customComputeOfferingParameters,
     defaultRestrictions,
     defaultHardwareValues,
-    tags
+    tags,
+    availableResources
   ): ComputeOfferingViewModel[] => {
-    const { customOfferings, fixedOfferings } = getFixedAndCustomOfferingsArrays(offerings);
-
-    const customOfferingsWithMetadata: ComputeOfferingViewModel[] = customOfferings
-      .map((offering: ServiceOffering) => {
-        const customParameters = getCustomOfferingHardwareParameters(offering, customComputeOfferingParameters);
-        const customHardwareValues = getCustomHardwareValues(customParameters);
-        const customHardwareRestrictions = getCustomHardwareRestrictions(customParameters);
-        const hardwareValuesFromTags = getHardwareValuesFromTags(offering, tags);
-
-        const prioritizedHardwareValues = hardwareValuesFromTags || customHardwareValues || defaultHardwareValues;
-        const prioritizedRestrictions = customHardwareRestrictions || defaultRestrictions;
-
-        const availableResources: Resources = {
-          cpuNumber: account && account.cpuavailable || '0',
-          memory: account && account.memoryavailable || '0'
-        };
-        const isAvailableByResources = checkAvailabilityForCustomByResources(
-          prioritizedRestrictions.cpunumber, prioritizedRestrictions.memory, availableResources);
-
-        let cpunumber = getValueThatSatisfiesRestrictions(
-          prioritizedHardwareValues.cpunumber, prioritizedRestrictions.cpunumber);
-        const cpuspeed = getValueThatSatisfiesRestrictions(
-          prioritizedHardwareValues.cpuspeed, prioritizedRestrictions.cpuspeed);
-        let memory = getValueThatSatisfiesRestrictions(
-          prioritizedHardwareValues.memory, prioritizedRestrictions.memory);
-
-        if (isAvailableByResources) {
-          cpunumber = getValueThatSatisfiesResources(cpunumber, availableResources.cpuNumber);
-          memory = getValueThatSatisfiesResources(memory, availableResources.memory);
-        }
-
-        const customOfferingRestrictions = getRestrictionsThatSatisfiesResources(
-          prioritizedRestrictions, availableResources);
-
-        const offeringViewModel: ComputeOfferingViewModel = {
-          ...offering,
-          cpunumber,
-          cpuspeed,
-          memory,
-          customOfferingRestrictions,
-          isAvailableByResources
-        };
-        return offeringViewModel;
-      });
+  const { customOfferings, fixedOfferings } = getFixedAndCustomOfferingsArrays(offerings);
 
-    const fixedOfferingWithMeta = fixedOfferings.map(offering => {
-      const availableResources: Resources = {
-        cpuNumber: account && account.cpuavailable || '0',
-        memory: account && account.memoryavailable || '0'
+  const customOfferingsWithMetadata: ComputeOfferingViewModel[] = customOfferings
+    .map((offering: ServiceOffering) => {
+      const customParameters = getCustomOfferingHardwareParameters(offering, customComputeOfferingParameters);
+      const customHardwareValues = getCustomHardwareValues(customParameters);
+      const customHardwareRestrictions = getCustomHardwareRestrictions(customParameters);
+      const hardwareValuesFromTags = getHardwareValuesFromTags(offering, tags);
+
+      const prioritizedHardwareValues = hardwareValuesFromTags || customHardwareValues || defaultHardwareValues;
+      const prioritizedRestrictions = customHardwareRestrictions || defaultRestrictions;
+
+
+      const isAvailableByResources = checkAvailabilityForCustomByResources(
+        prioritizedRestrictions.cpunumber, prioritizedRestrictions.memory, availableResources);
+
+      let cpunumber = getValueThatSatisfiesRestrictions(
+        prioritizedHardwareValues.cpunumber, prioritizedRestrictions.cpunumber);
+      const cpuspeed = getValueThatSatisfiesRestrictions(
+        prioritizedHardwareValues.cpuspeed, prioritizedRestrictions.cpuspeed);
+      let memory = getValueThatSatisfiesRestrictions(
+        prioritizedHardwareValues.memory, prioritizedRestrictions.memory);
+
+      if (isAvailableByResources) {
+        cpunumber = getValueThatSatisfiesResources(cpunumber, availableResources.cpuNumber);
+        memory = getValueThatSatisfiesResources(memory, availableResources.memory);
+      }
+
+      const customOfferingRestrictions = getRestrictionsThatSatisfiesResources(
+        prioritizedRestrictions, availableResources);
+
+      const offeringViewModel: ComputeOfferingViewModel = {
+        ...offering,
+        cpunumber,
+        cpuspeed,
+        memory,
+        customOfferingRestrictions,
+        isAvailableByResources
       };
+      return offeringViewModel;
+    });
+
+    const fixedOfferingWithMeta = fixedOfferings.map(offering => {
       const offeringViewModel: ComputeOfferingViewModel = {
         ...offering,
         isAvailableByResources: checkAvailabilityForFixedByResources(
@@ -237,5 +226,70 @@ export const getComputeOfferingViewModel = createSelector(
     });
 
     return [...fixedOfferingWithMeta, ...customOfferingsWithMetadata];
+  };
+
+export const getComputeOfferingForVmEditing = createSelector(
+  fromAuth.getUserAccount,
+  computeOffering.selectAll,
+  configSelectors.get('customComputeOfferingParameters'),
+  configSelectors.get('defaultCustomComputeOfferingRestrictions'),
+  configSelectors.get('customComputeOfferingHardwareValues'),
+  UserTagsSelectors.getServiceOfferingParamTags,
+  fromVms.getSelectedVM,
+  (account,
+   offerings,
+   customComputeOfferingParameters,
+   defaultRestrictions,
+   defaultHardwareValues,
+   tags, vm): ComputeOfferingViewModel[] => {
+    const memoryUsed = vm.memory;
+    const cpuNumberUsed = vm.cpuNumber;
+
+    const cpuNumber = account && account.cpuavailable === 'Unlimited'
+      ? account.cpuavailable
+      : Number(account.cpuavailable) + cpuNumberUsed;
+    const memory = account && account.memoryavailable === 'Unlimited'
+      ? account.memoryavailable
+      : Number(account.memoryavailable) + memoryUsed;
+
+    const availableResources: Resources = {
+      cpuNumber: cpuNumber || cpuNumberUsed,
+      memory: memory || memoryUsed
+    };
+
+    return getComputeOfferingViewModel(
+      offerings,
+      customComputeOfferingParameters,
+      defaultRestrictions,
+      defaultHardwareValues,
+      tags,
+      availableResources);
+  }
+);
+
+export const getComputeOfferingForVmCreation = createSelector(
+  fromAuth.getUserAccount,
+  computeOffering.selectAll,
+  configSelectors.get('customComputeOfferingParameters'),
+  configSelectors.get('defaultCustomComputeOfferingRestrictions'),
+  configSelectors.get('customComputeOfferingHardwareValues'),
+  UserTagsSelectors.getServiceOfferingParamTags,
+  (account,
+   offerings,
+   customComputeOfferingParameters,
+   defaultRestrictions,
+   defaultHardwareValues,
+   tags): ComputeOfferingViewModel[] => {
+    const availableResources: Resources = {
+      cpuNumber: account && account.cpuavailable || '0',
+      memory: account && account.memoryavailable || '0'
+    };
+    return getComputeOfferingViewModel(
+      offerings,
+      customComputeOfferingParameters,
+      defaultRestrictions,
+      defaultHardwareValues,
+      tags,
+      availableResources);
   }
 );
diff --git a/src/app/vm/selectors/view-models/index.ts b/src/app/vm/selectors/view-models/index.ts
index 65a8ed8a70..c7881ca31d 100644
--- a/src/app/vm/selectors/view-models/index.ts
+++ b/src/app/vm/selectors/view-models/index.ts
@@ -1 +1 @@
-export { getComputeOfferingViewModel } from './compute-offering-view-model.selector';
+export { getComputeOfferingForVmCreation } from './compute-offering-view-model.selector';
diff --git a/src/testutils/data/index.ts b/src/testutils/data/index.ts
index 3551aaccec..2d7277d5dd 100644
--- a/src/testutils/data/index.ts
+++ b/src/testutils/data/index.ts
@@ -1,2 +1,3 @@
 export * from './compute-offerings';
 export * from './vitrual-machines';
+export * from './accounts';

From 07788b9822e2399c96e6b1bb41dc9f4b02fa0f8b Mon Sep 17 00:00:00 2001
From: HeyRoach <caloriees@gmail.com>
Date: Fri, 5 Oct 2018 15:07:41 +0700
Subject: [PATCH 10/10] small updates after review

---
 .../service-offering-dialog.component.ts            |  2 +-
 .../volume-actions/volume-resize.container.ts       |  2 +-
 .../compute-offering-view-model.selector.ts         | 13 ++++++++-----
 src/app/vm/selectors/view-models/index.ts           |  5 ++++-
 4 files changed, 14 insertions(+), 8 deletions(-)

diff --git a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
index ae29360939..a06ecf7c16 100644
--- a/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
+++ b/src/app/service-offering/service-offering-dialog/service-offering-dialog.component.ts
@@ -91,7 +91,7 @@ export class ServiceOfferingDialogComponent implements OnInit, OnChanges {
     if (this.serviceOffering && this.serviceOffering.iscustomized && this.viewMode === ServiceOfferingType.custom) {
       return true;
     }
-    if (!this.serviceOffering.iscustomized && this.viewMode === ServiceOfferingType.fixed) {
+    if (this.serviceOffering && !this.serviceOffering.iscustomized && this.viewMode === ServiceOfferingType.fixed) {
       return true;
     }
     return false;
diff --git a/src/app/shared/actions/volume-actions/volume-resize.container.ts b/src/app/shared/actions/volume-actions/volume-resize.container.ts
index 5a7042f465..b82616e1af 100644
--- a/src/app/shared/actions/volume-actions/volume-resize.container.ts
+++ b/src/app/shared/actions/volume-actions/volume-resize.container.ts
@@ -51,7 +51,7 @@ export class VolumeResizeContainerComponent implements OnInit {
       take(1),
       filter(account => !!account))
       .subscribe((account: Account) => {
-        this.maxSize = Number(account.primarystorageavailable);
+        this.maxSize = account.primarystorageavailable;
       });
   }
 
diff --git a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts
index 6d4771e0bc..19b655dee2 100644
--- a/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts
+++ b/src/app/vm/selectors/view-models/compute-offering-view-model.selector.ts
@@ -241,7 +241,8 @@ export const getComputeOfferingForVmEditing = createSelector(
    customComputeOfferingParameters,
    defaultRestrictions,
    defaultHardwareValues,
-   tags, vm): ComputeOfferingViewModel[] => {
+   tags,
+   vm): ComputeOfferingViewModel[] => {
     const memoryUsed = vm.memory;
     const cpuNumberUsed = vm.cpuNumber;
 
@@ -252,10 +253,7 @@ export const getComputeOfferingForVmEditing = createSelector(
       ? account.memoryavailable
       : Number(account.memoryavailable) + memoryUsed;
 
-    const availableResources: Resources = {
-      cpuNumber: cpuNumber || cpuNumberUsed,
-      memory: memory || memoryUsed
-    };
+    const availableResources: Resources = { cpuNumber, memory };
 
     return getComputeOfferingViewModel(
       offerings,
@@ -280,6 +278,11 @@ export const getComputeOfferingForVmCreation = createSelector(
    defaultRestrictions,
    defaultHardwareValues,
    tags): ComputeOfferingViewModel[] => {
+
+    /**
+     * '0' used to prevent an error when account is not loaded yet
+     * it happened when you go to vm creation dialog by url
+     */
     const availableResources: Resources = {
       cpuNumber: account && account.cpuavailable || '0',
       memory: account && account.memoryavailable || '0'
diff --git a/src/app/vm/selectors/view-models/index.ts b/src/app/vm/selectors/view-models/index.ts
index c7881ca31d..470eaeb895 100644
--- a/src/app/vm/selectors/view-models/index.ts
+++ b/src/app/vm/selectors/view-models/index.ts
@@ -1 +1,4 @@
-export { getComputeOfferingForVmCreation } from './compute-offering-view-model.selector';
+export {
+  getComputeOfferingForVmCreation,
+  getComputeOfferingForVmEditing
+} from './compute-offering-view-model.selector';