Skip to content

Commit 8621ad1

Browse files
Cyrille Bourgoisjleveugle
authored andcommitted
feat(storages.blocks): update blocks storages
* add creation wizard * update list and actions (attach/detach/delete/edit/snapshot) ref: MANAGER-2291, MANAGER-2292, MANAGER-2358
1 parent 37d31be commit 8621ad1

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+1524
-352
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import controller from './add.controller';
2+
import template from './add.html';
3+
4+
export default {
5+
controller,
6+
template,
7+
bindings: {
8+
projectId: '<',
9+
goBack: '<',
10+
cancelLink: '<',
11+
},
12+
};
Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
import angular from 'angular';
2+
import get from 'lodash/get';
3+
import map from 'lodash/map';
4+
5+
import BlockStorage from '../block.class';
6+
import Region from '../region.class';
7+
8+
export default class PciBlockStorageAddController {
9+
/* @ngInject */
10+
constructor(
11+
$q,
12+
$timeout,
13+
$translate,
14+
CucCloudMessage,
15+
PciProjectStorageBlockService,
16+
) {
17+
this.$q = $q;
18+
this.$timeout = $timeout;
19+
this.$translate = $translate;
20+
this.CucCloudMessage = CucCloudMessage;
21+
this.PciProjectStorageBlockService = PciProjectStorageBlockService;
22+
}
23+
24+
$onInit() {
25+
this.typeRegionPrices = null;
26+
this.displaySelectedRegion = false;
27+
this.displaySelectedType = false;
28+
29+
this.loadings = {
30+
regions: false,
31+
types: false,
32+
size: false,
33+
save: false,
34+
};
35+
36+
this.size = {
37+
min: Region.getMinSize(),
38+
max: 0,
39+
};
40+
41+
this.storage = new BlockStorage();
42+
43+
this.loadings.regions = true;
44+
45+
this.$translate.refresh()
46+
.then(() => this.loadMessages())
47+
.then(() => this.$q.all({
48+
regions: this.PciProjectStorageBlockService.getAvailablesRegions(this.projectId),
49+
types: this.PciProjectStorageBlockService.getAvailablesTypes(),
50+
}))
51+
.then(({ regions, types }) => {
52+
this.regions = regions;
53+
this.types = types;
54+
55+
this.typesList = map(
56+
this.types,
57+
type => ({
58+
id: type,
59+
name: this.$translate.instant(`pci_projects_project_storages_blocks_add_type_${type}_description`),
60+
}),
61+
);
62+
63+
return this.PciProjectStorageBlockService.getPricesEstimations(
64+
this.projectId,
65+
this.regions,
66+
1,
67+
);
68+
})
69+
.then((typeRegionPrices) => {
70+
this.typeRegionPrices = typeRegionPrices;
71+
})
72+
.catch(err => this.CucCloudMessage.error(
73+
this.$translate.instant(
74+
'pci_projects_project_storages_blocks_add_error_query',
75+
{ message: get(err, 'data.message', '') },
76+
),
77+
))
78+
.finally(() => {
79+
this.loadings.regions = false;
80+
});
81+
}
82+
83+
loadMessages() {
84+
this.CucCloudMessage.unSubscribe('pci.projects.project.storages.blocks.add');
85+
this.messageHandler = this.CucCloudMessage.subscribe(
86+
'pci.projects.project.storages.blocks.add',
87+
{
88+
onMessage: () => this.refreshMessages(),
89+
},
90+
);
91+
}
92+
93+
refreshMessages() {
94+
this.messages = this.messageHandler.getMessages();
95+
}
96+
97+
onRegionsFocus() {
98+
this.displaySelectedRegion = false;
99+
}
100+
101+
onRegionChange() {
102+
this.displaySelectedRegion = true;
103+
}
104+
105+
onTypesFocus() {
106+
this.displaySelectedType = false;
107+
}
108+
109+
onTypeChange() {
110+
this.displaySelectedType = true;
111+
112+
this.storage.type = this.selectedType.id;
113+
114+
this.loadings.size = true;
115+
return this.estimatePrice()
116+
.then(() => {
117+
this.size.max = this.storage.region.getMaxSize();
118+
this.storage.size = Math.min(Math.max(this.storage.size, this.size.min), this.size.max);
119+
})
120+
.finally(() => {
121+
this.loadings.size = false;
122+
});
123+
}
124+
125+
onSizeChange() {
126+
// Wait the next digest because oui-numeric use the viewValue when calling on-change callback
127+
return this.$timeout(angular.noop, 0)
128+
.then(() => this.estimatePrice())
129+
// Force a digest...
130+
.then(() => this.$timeout(angular.noop, 0));
131+
}
132+
133+
estimatePrice() {
134+
return this.PciProjectStorageBlockService
135+
.getVolumePriceEstimation(this.projectId, this.storage)
136+
.then((estimatedPrice) => {
137+
this.estimatedPrice = estimatedPrice;
138+
});
139+
}
140+
141+
add() {
142+
this.loadings.save = true;
143+
144+
return this.PciProjectStorageBlockService.add(this.projectId, this.storage)
145+
.then(() => {
146+
this.CucCloudMessage.success(
147+
this.$translate.instant(
148+
'pci_projects_project_storages_blocks_add_success_message',
149+
{ volume: this.storage.name },
150+
),
151+
'pci.projects.project.storages.blocks',
152+
);
153+
154+
return this.goBack(true);
155+
})
156+
.catch((err) => {
157+
this.CucCloudMessage.error(
158+
this.$translate.instant(
159+
'pci_projects_project_storages_blocks_add_error_post',
160+
{ message: get(err, 'data.message', '') },
161+
),
162+
'pci.projects.project.storages.blocks.add',
163+
);
164+
})
165+
.finally(() => {
166+
this.loadings.save = false;
167+
});
168+
}
169+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
<div class="p-5">
2+
<oui-back-button
3+
data-on-click="$ctrl.goBack()">{{:: 'pci_projects_project_storages_blocks_add_back_label' | translate }}</oui-back-button>
4+
5+
<h1 data-translate="pci_projects_project_storages_blocks_add_title"></h1>
6+
7+
<cui-message-container data-messages="$ctrl.messages"></cui-message-container>
8+
9+
<div>
10+
<oui-stepper
11+
data-on-finish="$ctrl.add()">
12+
<oui-step-form
13+
data-header="{{:: 'pci_projects_project_storages_blocks_add_region_title' | translate }}"
14+
data-loading="$ctrl.loadings.regions"
15+
data-navigation="$ctrl.storage.region"
16+
data-submit-text="{{:: 'pci_projects_project_storages_blocks_add_submit_label' | translate }}"
17+
data-on-focus="$ctrl.onRegionsFocus()"
18+
data-on-submit="$ctrl.onRegionChange()">
19+
<pci-project-regions-list
20+
data-regions="$ctrl.regions"
21+
data-selected-region="$ctrl.storage.region"
22+
data-display-selected-region="$ctrl.displaySelectedRegion"></pci-project-regions-list>
23+
</oui-step-form>
24+
25+
<oui-step-form data-header="{{:: 'pci_projects_project_storages_blocks_add_type_title' | translate }}"
26+
data-on-focus="$ctrl.onTypesFocus()"
27+
data-on-submit="$ctrl.onTypeChange()"
28+
data-navigation="$ctrl.selectedType">
29+
<div class="container-fluid px-0"
30+
data-ng-if="$ctrl.typeRegionPrices">
31+
<div class="row">
32+
<oui-select-picker
33+
data-ng-if="!$ctrl.displaySelectedType || $ctrl.selectedType === type"
34+
data-ng-repeat="type in $ctrl.typesList track by $index"
35+
class="d-inline-block col-md-6 col-lg-4 my-3"
36+
data-name="type"
37+
data-match="name"
38+
data-model="$ctrl.selectedType"
39+
data-label="{{ 'pci_projects_project_storages_blocks_add_type_' + type.id + '_label' | translate }}"
40+
data-values="[type]"
41+
data-variant="light"
42+
data-required>
43+
<span data-translate="pci_projects_project_storages_blocks_add_type_price"
44+
data-translate-values="{ price: $ctrl.typeRegionPrices[type.id][$ctrl.storage.region.name].monthly.text }"></span>
45+
</oui-select-picker>
46+
</div>
47+
</div>
48+
</oui-step-form>
49+
50+
<oui-step-form data-header="{{:: 'pci_projects_project_storages_blocks_add_size_title' | translate }}"
51+
data-loading="$ctrl.loadings.size">
52+
<oui-field data-size="xl" data-help-text="{{:: 'pci_projects_project_storages_blocks_add_size_help' | translate }}">
53+
<div class="d-inline-block">
54+
<oui-numeric
55+
data-name="size"
56+
data-min="$ctrl.size.min"
57+
data-max="$ctrl.size.max"
58+
data-model="$ctrl.storage.size"
59+
data-on-change="$ctrl.onSizeChange(modelValue)"
60+
></oui-numeric>
61+
</div>
62+
<span class="pl-2" data-translate="pci_projects_project_storages_blocks_add_size_unit"></span>
63+
64+
<p data-translate="pci_projects_project_storages_blocks_add_submit_price_text"
65+
data-translate-values="{ price: $ctrl.estimatedPrice.monthly.text }"></p>
66+
</oui-field>
67+
68+
</oui-step-form>
69+
70+
<oui-step-form data-header="{{:: 'pci_projects_project_storages_blocks_add_name_title' | translate }}">
71+
<oui-field data-size="xl">
72+
<input class="oui-input" type="text" name="name"
73+
data-ng-model="$ctrl.storage.name"
74+
data-ng-required="true">
75+
</oui-field>
76+
</oui-step-form>
77+
78+
<oui-step-form data-header="{{:: 'pci_projects_project_storages_blocks_add_submit_title' | translate }}"
79+
data-submit-text="{{:: 'pci_projects_project_storages_blocks_add_submit_label' | translate }}"
80+
data-cancel-text="{{:: 'pci_projects_project_storages_blocks_add_submit_cancel_label' | translate }}"
81+
data-cancel-href="{{$ctrl.cancelLink}}"
82+
>
83+
<div class="mb-3"
84+
data-translate="pci_projects_project_storages_blocks_add_submit_price_text"
85+
data-translate-values="{ price: $ctrl.estimatedPrice.monthly.text }"></div>
86+
</oui-step-form>
87+
</oui-stepper>
88+
</div>
89+
90+
<div data-ng-if="$ctrl.loadings.save">
91+
<oui-spinner></oui-spinner>
92+
<p data-translate="pci_projects_project_storages_blocks_add_save_form"></p>
93+
</div>
94+
</div>
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export default /* @ngInject */ ($stateProvider) => {
2+
$stateProvider
3+
.state('pci.projects.project.storages.blocks.add', {
4+
url: '/new',
5+
component: 'pciProjectStorageBlocksAdd',
6+
resolve: {
7+
goBack: /* @ngInject */ ($rootScope, $state, projectId) => (reload = false) => {
8+
if (reload) {
9+
$rootScope.$emit('pci_storages_blocks_refresh');
10+
}
11+
return $state.go('pci.projects.project.storages.blocks', {
12+
projectId,
13+
});
14+
},
15+
cancelLink: /* @ngInject */ ($state, projectId) => $state.href('pci.projects.project.storages.blocks', {
16+
projectId,
17+
}),
18+
},
19+
});
20+
};
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import angular from 'angular';
2+
import '@ovh-ux/ng-translate-async-loader';
3+
import '@uirouter/angularjs';
4+
import 'angular-translate';
5+
import 'ovh-ui-angular';
6+
import 'ovh-api-services';
7+
8+
import component from './add.component';
9+
import routing from './add.routing';
10+
11+
import regionsList from './regions-list';
12+
13+
const moduleName = 'ovhManagerPciStoragesBlocksAdd';
14+
15+
angular
16+
.module(moduleName, [
17+
regionsList,
18+
'ui.router',
19+
'oui',
20+
'ovh-api-services',
21+
'ngTranslateAsyncLoader',
22+
'pascalprecht.translate',
23+
])
24+
.config(routing)
25+
.component('pciProjectStorageBlocksAdd', component)
26+
.run(/* @ngTranslationsInject:json ./translations */);
27+
28+
export default moduleName;
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
import angular from 'angular';
2+
import '@ovh-ux/ng-translate-async-loader';
3+
import 'angular-translate';
4+
import 'ovh-ui-angular';
5+
6+
import component from './regions-list.component';
7+
8+
const moduleName = 'ovhManagerPciRegionsList';
9+
10+
angular
11+
.module(moduleName, [
12+
'oui',
13+
'ngTranslateAsyncLoader',
14+
'pascalprecht.translate',
15+
])
16+
.component('pciProjectRegionsList', component)
17+
.run(/* @ngTranslationsInject:json ./translations */);
18+
19+
export default moduleName;
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import controller from './regions-list.controller';
2+
import template from './regions-list.html';
3+
4+
export default {
5+
controller,
6+
template,
7+
bindings: {
8+
regions: '<',
9+
selectedRegion: '=?',
10+
onChange: '&?',
11+
displaySelectedRegion: '<',
12+
},
13+
};

0 commit comments

Comments
 (0)