]>
Commit | Line | Data |
---|---|---|
f67539c2 TL |
1 | <div class="cd-col-form" |
2 | *cdFormLoading="loading"> | |
11fdf7f2 | 3 | <form name="form" |
11fdf7f2 TL |
4 | #formDir="ngForm" |
5 | [formGroup]="form" | |
6 | novalidate> | |
9f95a23c TL |
7 | <div class="card"> |
8 | <div i18n="form title|Example: Create Pool@@formTitle" | |
9 | class="card-header">{{ action | titlecase }} {{ resource | upperFirst }}</div> | |
11fdf7f2 | 10 | |
9f95a23c | 11 | <div class="card-body"> |
11fdf7f2 | 12 | <!-- Name --> |
9f95a23c TL |
13 | <div class="form-group row"> |
14 | <label class="cd-col-form-label required" | |
15 | for="name" | |
16 | i18n>Name</label> | |
17 | <div class="cd-col-form-input"> | |
11fdf7f2 TL |
18 | <input id="name" |
19 | name="name" | |
20 | type="text" | |
21 | class="form-control" | |
22 | placeholder="Name..." | |
23 | i18n-placeholder | |
24 | formControlName="name" | |
25 | autofocus> | |
9f95a23c | 26 | <span class="invalid-feedback" |
11fdf7f2 TL |
27 | *ngIf="form.showError('name', formDir, 'required')" |
28 | i18n>This field is required!</span> | |
9f95a23c | 29 | <span class="invalid-feedback" |
11fdf7f2 TL |
30 | *ngIf="form.showError('name', formDir, 'uniqueName')" |
31 | i18n>The chosen Ceph pool name is already in use.</span> | |
9f95a23c TL |
32 | <span *ngIf="form.showError('name', formDir, 'rbdPool')" |
33 | class="invalid-feedback" | |
34 | i18n>It's not possible to create an RBD pool with '/' in the name. | |
35 | Please change the name or remove 'rbd' from the applications list.</span> | |
36 | <span *ngIf="form.showError('name', formDir, 'pattern')" | |
37 | class="invalid-feedback" | |
38 | i18n>Pool name can only contain letters, numbers, '.', '-', '_' or '/'.</span> | |
11fdf7f2 TL |
39 | </div> |
40 | </div> | |
41 | ||
42 | <!-- Pool type selection --> | |
9f95a23c TL |
43 | <div class="form-group row"> |
44 | <label class="cd-col-form-label required" | |
45 | for="poolType" | |
46 | i18n>Pool type</label> | |
47 | <div class="cd-col-form-input"> | |
33c7a0ef | 48 | <select class="form-control" |
11fdf7f2 TL |
49 | id="poolType" |
50 | formControlName="poolType" | |
51 | name="poolType"> | |
52 | <option ngValue="" | |
53 | i18n>-- Select a pool type --</option> | |
54 | <option *ngFor="let poolType of data.poolTypes" | |
55 | [value]="poolType"> | |
56 | {{ poolType }} | |
57 | </option> | |
58 | </select> | |
9f95a23c | 59 | <span class="invalid-feedback" |
11fdf7f2 TL |
60 | *ngIf="form.showError('poolType', formDir, 'required')" |
61 | i18n>This field is required!</span> | |
62 | </div> | |
63 | </div> | |
64 | ||
9f95a23c TL |
65 | <div *ngIf="isReplicated || isErasure"> |
66 | <!-- PG Autoscale Mode --> | |
67 | <div class="form-group row"> | |
68 | <label i18n | |
69 | class="cd-col-form-label" | |
70 | for="pgAutoscaleMode">PG Autoscale</label> | |
71 | <div class="cd-col-form-input"> | |
33c7a0ef | 72 | <select class="form-control" |
9f95a23c TL |
73 | id="pgAutoscaleMode" |
74 | name="pgAutoscaleMode" | |
75 | formControlName="pgAutoscaleMode"> | |
76 | <option *ngFor="let mode of pgAutoscaleModes" | |
77 | [value]="mode"> | |
78 | {{ mode }} | |
79 | </option> | |
80 | </select> | |
81 | </div> | |
82 | </div> | |
83 | ||
11fdf7f2 | 84 | <!-- Pg number --> |
9f95a23c TL |
85 | <div class="form-group row" |
86 | *ngIf="form.getValue('pgAutoscaleMode') !== 'on'"> | |
87 | <label class="cd-col-form-label required" | |
88 | for="pgNum" | |
89 | i18n>Placement groups</label> | |
90 | <div class="cd-col-form-input"> | |
11fdf7f2 TL |
91 | <input class="form-control" |
92 | id="pgNum" | |
93 | name="pgNum" | |
94 | formControlName="pgNum" | |
95 | min="1" | |
96 | type="number" | |
97 | (focus)="externalPgChange = false" | |
98 | (blur)="alignPgs()" | |
99 | required> | |
9f95a23c | 100 | <span class="invalid-feedback" |
11fdf7f2 TL |
101 | *ngIf="form.showError('pgNum', formDir, 'required')" |
102 | i18n>This field is required!</span> | |
9f95a23c | 103 | <span class="invalid-feedback" |
11fdf7f2 TL |
104 | *ngIf="form.showError('pgNum', formDir, 'min')" |
105 | i18n>At least one placement group is needed!</span> | |
9f95a23c | 106 | <span class="invalid-feedback" |
11fdf7f2 TL |
107 | *ngIf="form.showError('pgNum', formDir, '34')" |
108 | i18n>Your cluster can't handle this many PGs. Please recalculate the PG amount needed.</span> | |
9f95a23c | 109 | <span class="form-text text-muted"> |
f6b5b4d7 TL |
110 | <cd-doc section="pgs" |
111 | docText="Calculation help" | |
112 | i18n-docText></cd-doc> | |
11fdf7f2 | 113 | </span> |
9f95a23c | 114 | <span class="form-text text-muted" |
11fdf7f2 TL |
115 | *ngIf="externalPgChange" |
116 | i18n>The current PGs settings were calculated for you, you | |
9f95a23c | 117 | should make sure the values suit your needs before submit.</span> |
11fdf7f2 TL |
118 | </div> |
119 | </div> | |
120 | ||
121 | <!-- Replica Size --> | |
9f95a23c TL |
122 | <div class="form-group row" |
123 | *ngIf="isReplicated"> | |
124 | <label class="cd-col-form-label required" | |
125 | for="size" | |
126 | i18n>Replicated size</label> | |
127 | <div class="cd-col-form-input"> | |
11fdf7f2 TL |
128 | <input class="form-control" |
129 | id="size" | |
130 | [max]="getMaxSize()" | |
131 | [min]="getMinSize()" | |
132 | name="size" | |
133 | type="number" | |
134 | formControlName="size"> | |
9f95a23c | 135 | <span class="invalid-feedback" |
11fdf7f2 TL |
136 | *ngIf="form.showError('size', formDir)"> |
137 | <ul class="list-inline"> | |
138 | <li i18n>Minimum: {{ getMinSize() }}</li> | |
139 | <li i18n>Maximum: {{ getMaxSize() }}</li> | |
140 | </ul> | |
141 | </span> | |
9f95a23c | 142 | <span class="invalid-feedback" |
11fdf7f2 TL |
143 | *ngIf="form.showError('size', formDir)" |
144 | i18n>The size specified is out of range. A value from | |
f6b5b4d7 | 145 | {{ getMinSize() }} to {{ getMaxSize() }} is usable.</span> |
f91f0fd5 TL |
146 | <span class="text-warning-dark" |
147 | *ngIf="form.getValue('size') === 1" | |
148 | i18n>A size of 1 will not create a replication of the | |
149 | object. The 'Replicated size' includes the object itself.</span> | |
11fdf7f2 TL |
150 | </div> |
151 | </div> | |
152 | ||
9f95a23c TL |
153 | <!-- Flags --> |
154 | <div class="form-group row" | |
155 | *ngIf="info.is_all_bluestore && isErasure"> | |
156 | <label i18n | |
157 | class="cd-col-form-label">Flags</label> | |
158 | <div class="cd-col-form-input"> | |
159 | <div class="custom-control custom-checkbox"> | |
160 | <input type="checkbox" | |
161 | class="custom-control-input" | |
162 | id="ec-overwrites" | |
163 | formControlName="ecOverwrites"> | |
164 | <label class="custom-control-label" | |
165 | for="ec-overwrites" | |
166 | i18n>EC Overwrites</label> | |
167 | </div> | |
168 | </div> | |
169 | </div> | |
170 | ||
171 | </div> | |
172 | <!-- Applications --> | |
173 | <div class="form-group row"> | |
174 | <label i18n | |
175 | class="cd-col-form-label" | |
176 | for="applications">Applications</label> | |
177 | <div class="cd-col-form-input"> | |
178 | <cd-select-badges id="applications" | |
179 | [customBadges]="true" | |
180 | [customBadgeValidators]="data.applications.validators" | |
181 | [messages]="data.applications.messages" | |
182 | [data]="data.applications.selected" | |
183 | [options]="data.applications.available" | |
184 | [selectionLimit]="4" | |
185 | (selection)="appSelection()"> | |
186 | </cd-select-badges> | |
20effc67 TL |
187 | <i *ngIf="data.applications.selected <= 0" |
188 | i18n-title | |
189 | title="Pools should be associated with an application tag" | |
190 | class="{{icons.warning}} icon-warning-color"> | |
191 | </i> | |
9f95a23c TL |
192 | </div> |
193 | </div> | |
9f95a23c TL |
194 | <!-- CRUSH --> |
195 | <div *ngIf="isErasure || isReplicated"> | |
196 | ||
197 | <legend i18n>CRUSH</legend> | |
198 | ||
11fdf7f2 | 199 | <!-- Erasure Profile select --> |
9f95a23c TL |
200 | <div class="form-group row" |
201 | *ngIf="isErasure"> | |
11fdf7f2 | 202 | <label i18n |
9f95a23c | 203 | class="cd-col-form-label" |
11fdf7f2 | 204 | for="erasureProfile">Erasure code profile</label> |
9f95a23c | 205 | <div class="cd-col-form-input"> |
11fdf7f2 | 206 | <div class="input-group"> |
33c7a0ef | 207 | <select class="form-control" |
11fdf7f2 TL |
208 | id="erasureProfile" |
209 | name="erasureProfile" | |
210 | formControlName="erasureProfile"> | |
211 | <option *ngIf="!ecProfiles" | |
212 | ngValue="" | |
213 | i18n>Loading...</option> | |
214 | <option *ngIf="ecProfiles && ecProfiles.length === 0" | |
215 | [ngValue]="null" | |
216 | i18n>-- No erasure code profile available --</option> | |
217 | <option *ngIf="ecProfiles && ecProfiles.length > 0" | |
218 | [ngValue]="null" | |
219 | i18n>-- Select an erasure code profile --</option> | |
220 | <option *ngFor="let ecp of ecProfiles" | |
221 | [ngValue]="ecp"> | |
222 | {{ ecp.name }} | |
223 | </option> | |
224 | </select> | |
9f95a23c TL |
225 | <span class="input-group-append"> |
226 | <button class="btn btn-light" | |
11fdf7f2 TL |
227 | [ngClass]="{'active': data.erasureInfo}" |
228 | id="ecp-info-button" | |
229 | type="button" | |
230 | (click)="data.erasureInfo = !data.erasureInfo"> | |
9f95a23c | 231 | <i [ngClass]="[icons.questionCircle]" |
11fdf7f2 TL |
232 | aria-hidden="true"></i> |
233 | </button> | |
9f95a23c | 234 | <button class="btn btn-light" |
11fdf7f2 | 235 | type="button" |
9f95a23c | 236 | *ngIf="!editing" |
11fdf7f2 | 237 | (click)="addErasureCodeProfile()"> |
9f95a23c | 238 | <i [ngClass]="[icons.add]" |
11fdf7f2 TL |
239 | aria-hidden="true"></i> |
240 | </button> | |
9f95a23c | 241 | <button class="btn btn-light" |
11fdf7f2 | 242 | type="button" |
9f95a23c | 243 | *ngIf="!editing" |
f67539c2 TL |
244 | ngbTooltip="This profile can't be deleted as it is in use." |
245 | i18n-ngbTooltip | |
246 | triggers="manual" | |
247 | #ecpDeletionBtn="ngbTooltip" | |
9f95a23c TL |
248 | (click)="deleteErasureCodeProfile()"> |
249 | <i [ngClass]="[icons.trash]" | |
11fdf7f2 TL |
250 | aria-hidden="true"></i> |
251 | </button> | |
252 | </span> | |
253 | </div> | |
9f95a23c | 254 | <span class="form-text text-muted" |
11fdf7f2 TL |
255 | id="ecp-info-block" |
256 | *ngIf="data.erasureInfo && form.getValue('erasureProfile')"> | |
f67539c2 TL |
257 | <ul ngbNav |
258 | #ecpInfoTabs="ngbNav" | |
259 | class="nav-tabs"> | |
260 | <li ngbNavItem="ecp-info"> | |
261 | <a ngbNavLink | |
262 | i18n>Profile</a> | |
263 | <ng-template ngbNavContent> | |
264 | <cd-table-key-value [renderObjects]="true" | |
265 | [hideKeys]="['name']" | |
266 | [data]="form.getValue('erasureProfile')" | |
267 | [autoReload]="false"> | |
268 | </cd-table-key-value> | |
269 | </ng-template> | |
270 | </li> | |
271 | <li ngbNavItem="used-by-pools"> | |
272 | <a ngbNavLink | |
273 | i18n>Used by pools</a> | |
274 | <ng-template ngbNavContent> | |
275 | <ng-template #ecpIsNotUsed> | |
276 | <span i18n>Profile is not in use.</span> | |
277 | </ng-template> | |
278 | <ul *ngIf="ecpUsage; else ecpIsNotUsed"> | |
279 | <li *ngFor="let pool of ecpUsage"> | |
280 | {{ pool }} | |
281 | </li> | |
282 | </ul> | |
e306af50 | 283 | </ng-template> |
f67539c2 TL |
284 | </li> |
285 | </ul> | |
286 | ||
287 | <div [ngbNavOutlet]="ecpInfoTabs"></div> | |
11fdf7f2 TL |
288 | </span> |
289 | </div> | |
290 | </div> | |
291 | ||
9f95a23c TL |
292 | <!-- Crush ruleset selection --> |
293 | <div class="form-group row" | |
294 | *ngIf="isErasure && !editing"> | |
295 | <label class="cd-col-form-label" | |
296 | for="crushRule" | |
297 | i18n>Crush ruleset</label> | |
298 | <div class="cd-col-form-input"> | |
299 | <span class="form-text text-muted" | |
300 | i18n>A new crush ruleset will be implicitly created.</span> | |
301 | </div> | |
302 | </div> | |
303 | <div class="form-group row" | |
304 | *ngIf="isReplicated || editing"> | |
305 | <label class="cd-col-form-label" | |
306 | for="crushRule" | |
307 | i18n>Crush ruleset</label> | |
308 | <div class="cd-col-form-input"> | |
309 | <ng-template #noRules> | |
310 | <span class="form-text text-muted"> | |
311 | <span i18n>There are no rules.</span> | |
312 | </span> | |
313 | </ng-template> | |
314 | <div *ngIf="current.rules.length > 0; else noRules"> | |
315 | <div class="input-group"> | |
33c7a0ef | 316 | <select class="form-control" |
9f95a23c TL |
317 | id="crushRule" |
318 | formControlName="crushRule" | |
319 | name="crushSet"> | |
320 | <option [ngValue]="null" | |
321 | i18n>-- Select a crush rule --</option> | |
322 | <option *ngFor="let rule of current.rules" | |
323 | [ngValue]="rule"> | |
324 | {{ rule.rule_name }} | |
325 | </option> | |
326 | </select> | |
327 | <span class="input-group-append"> | |
328 | <button class="btn btn-light" | |
329 | [ngClass]="{'active': data.crushInfo}" | |
330 | id="crush-info-button" | |
331 | type="button" | |
f67539c2 TL |
332 | ngbTooltip="Placement and |
333 | replication strategies or distribution policies that allow to | |
334 | specify how CRUSH places data replicas." | |
335 | i18n-ngbTooltip | |
9f95a23c TL |
336 | (click)="data.crushInfo = !data.crushInfo"> |
337 | <i [ngClass]="[icons.questionCircle]" | |
338 | aria-hidden="true"></i> | |
339 | </button> | |
340 | <button class="btn btn-light" | |
341 | type="button" | |
342 | *ngIf="isReplicated && !editing" | |
343 | (click)="addCrushRule()"> | |
344 | <i [ngClass]="[icons.add]" | |
345 | aria-hidden="true"></i> | |
346 | </button> | |
347 | <button class="btn btn-light" | |
348 | *ngIf="isReplicated && !editing" | |
349 | type="button" | |
f67539c2 TL |
350 | ngbTooltip="This rule can't be deleted as it is in use." |
351 | i18n-ngbTooltip | |
352 | triggers="manual" | |
353 | #crushDeletionBtn="ngbTooltip" | |
9f95a23c TL |
354 | (click)="deleteCrushRule()"> |
355 | <i [ngClass]="[icons.trash]" | |
356 | aria-hidden="true"></i> | |
357 | </button> | |
358 | </span> | |
11fdf7f2 | 359 | </div> |
f67539c2 TL |
360 | |
361 | <div class="form-text text-muted" | |
362 | id="crush-info-block" | |
363 | *ngIf="data.crushInfo && form.getValue('crushRule')"> | |
364 | <ul ngbNav | |
365 | #crushInfoTabs="ngbNav" | |
366 | class="nav-tabs"> | |
367 | <li ngbNavItem="crush-rule-info"> | |
368 | <a ngbNavLink | |
369 | i18n>Crush rule</a> | |
370 | <ng-template ngbNavContent> | |
371 | <cd-table-key-value [renderObjects]="false" | |
20effc67 | 372 | [hideKeys]="['steps', 'type', 'rule_name']" |
f67539c2 TL |
373 | [data]="form.getValue('crushRule')" |
374 | [autoReload]="false"> | |
375 | </cd-table-key-value> | |
9f95a23c | 376 | </ng-template> |
f67539c2 TL |
377 | </li> |
378 | <li ngbNavItem="crush-rule-steps"> | |
379 | <a ngbNavLink | |
380 | i18n>Crush steps</a> | |
381 | <ng-template ngbNavContent> | |
382 | <ol> | |
383 | <li *ngFor="let step of form.get('crushRule').value.steps"> | |
384 | {{ describeCrushStep(step) }} | |
385 | </li> | |
386 | </ol> | |
387 | </ng-template> | |
388 | </li> | |
389 | <li ngbNavItem="used-by-pools"> | |
390 | <a ngbNavLink | |
391 | i18n>Used by pools</a> | |
392 | <ng-template ngbNavContent> | |
393 | ||
394 | <ng-template #ruleIsNotUsed> | |
395 | <span i18n>Rule is not in use.</span> | |
396 | </ng-template> | |
397 | <ul *ngIf="crushUsage; else ruleIsNotUsed"> | |
398 | <li *ngFor="let pool of crushUsage"> | |
399 | {{ pool }} | |
400 | </li> | |
401 | </ul> | |
402 | </ng-template> | |
403 | </li> | |
404 | </ul> | |
405 | ||
406 | <div [ngbNavOutlet]="crushInfoTabs"></div> | |
407 | </div> | |
9f95a23c TL |
408 | <span class="invalid-feedback" |
409 | *ngIf="form.showError('crushRule', formDir, 'required')" | |
410 | i18n>This field is required!</span> | |
411 | <span class="invalid-feedback" | |
412 | *ngIf="form.showError('crushRule', formDir, 'tooFewOsds')" | |
413 | i18n>The rule can't be used in the current cluster as it has | |
414 | too few OSDs to meet the minimum required OSD by this rule.</span> | |
11fdf7f2 TL |
415 | </div> |
416 | </div> | |
417 | </div> | |
418 | ||
11fdf7f2 TL |
419 | </div> |
420 | ||
9f95a23c TL |
421 | <!-- Compression --> |
422 | <div *ngIf="info.is_all_bluestore" | |
423 | formGroupName="compression"> | |
424 | <legend i18n>Compression</legend> | |
11fdf7f2 | 425 | |
9f95a23c TL |
426 | <!-- Compression Mode --> |
427 | <div class="form-group row"> | |
428 | <label i18n | |
429 | class="cd-col-form-label" | |
430 | for="mode">Mode</label> | |
431 | <div class="cd-col-form-input"> | |
33c7a0ef | 432 | <select class="form-control" |
9f95a23c TL |
433 | id="mode" |
434 | name="mode" | |
435 | formControlName="mode"> | |
436 | <option *ngFor="let mode of info.compression_modes" | |
437 | [value]="mode"> | |
438 | {{ mode }} | |
439 | </option> | |
440 | </select> | |
441 | </div> | |
442 | </div> | |
443 | <div *ngIf="hasCompressionEnabled()"> | |
444 | <!-- Compression algorithm selection --> | |
445 | <div class="form-group row"> | |
11fdf7f2 | 446 | <label i18n |
9f95a23c TL |
447 | class="cd-col-form-label" |
448 | for="algorithm">Algorithm</label> | |
449 | <div class="cd-col-form-input"> | |
33c7a0ef | 450 | <select class="form-control" |
9f95a23c TL |
451 | id="algorithm" |
452 | name="algorithm" | |
453 | formControlName="algorithm"> | |
454 | <option *ngIf="!info.compression_algorithms" | |
455 | ngValue="" | |
456 | i18n>Loading...</option> | |
457 | <option *ngIf="info.compression_algorithms && info.compression_algorithms.length === 0" | |
458 | i18n | |
459 | ngValue="">-- No erasure compression algorithm available --</option> | |
460 | <option *ngFor="let algorithm of info.compression_algorithms" | |
461 | [value]="algorithm"> | |
462 | {{ algorithm }} | |
11fdf7f2 TL |
463 | </option> |
464 | </select> | |
465 | </div> | |
466 | </div> | |
11fdf7f2 | 467 | |
9f95a23c TL |
468 | <!-- Compression min blob size --> |
469 | <div class="form-group row"> | |
470 | <label i18n | |
471 | class="cd-col-form-label" | |
472 | for="minBlobSize">Minimum blob size</label> | |
473 | <div class="cd-col-form-input"> | |
474 | <input id="minBlobSize" | |
475 | name="minBlobSize" | |
476 | formControlName="minBlobSize" | |
477 | type="text" | |
478 | min="0" | |
479 | class="form-control" | |
480 | i18n-placeholder | |
481 | placeholder="e.g., 128KiB" | |
482 | defaultUnit="KiB" | |
483 | cdDimlessBinary> | |
484 | <span class="invalid-feedback" | |
485 | *ngIf="form.showError('minBlobSize', formDir, 'min')" | |
486 | i18n>Value should be greater than 0</span> | |
487 | <span class="invalid-feedback" | |
488 | *ngIf="form.showError('minBlobSize', formDir, 'maximum')" | |
489 | i18n>Value should be less than the maximum blob size</span> | |
11fdf7f2 | 490 | </div> |
9f95a23c | 491 | </div> |
11fdf7f2 | 492 | |
9f95a23c TL |
493 | <!-- Compression max blob size --> |
494 | <div class="form-group row"> | |
495 | <label i18n | |
496 | class="cd-col-form-label" | |
497 | for="maxBlobSize">Maximum blob size</label> | |
498 | <div class="cd-col-form-input"> | |
499 | <input id="maxBlobSize" | |
500 | type="text" | |
501 | min="0" | |
502 | formControlName="maxBlobSize" | |
503 | class="form-control" | |
504 | i18n-placeholder | |
505 | placeholder="e.g., 512KiB" | |
506 | defaultUnit="KiB" | |
507 | cdDimlessBinary> | |
508 | <span class="invalid-feedback" | |
509 | *ngIf="form.showError('maxBlobSize', formDir, 'min')" | |
510 | i18n>Value should be greater than 0</span> | |
511 | <span class="invalid-feedback" | |
512 | *ngIf="form.showError('maxBlobSize', formDir, 'minimum')" | |
513 | i18n>Value should be greater than the minimum blob size</span> | |
11fdf7f2 | 514 | </div> |
9f95a23c | 515 | </div> |
11fdf7f2 | 516 | |
9f95a23c TL |
517 | <!-- Compression ratio --> |
518 | <div class="form-group row"> | |
519 | <label i18n | |
520 | class="cd-col-form-label" | |
521 | for="ratio">Ratio</label> | |
522 | <div class="cd-col-form-input"> | |
523 | <input id="ratio" | |
524 | name="ratio" | |
525 | formControlName="ratio" | |
526 | type="number" | |
527 | min="0" | |
528 | max="1" | |
529 | step="0.1" | |
530 | class="form-control" | |
531 | i18n-placeholder | |
532 | placeholder="Compression ratio"> | |
533 | <span class="invalid-feedback" | |
534 | *ngIf="form.showError('ratio', formDir, 'min') || form.showError('ratio', formDir, 'max')" | |
535 | i18n>Value should be between 0.0 and 1.0</span> | |
11fdf7f2 | 536 | </div> |
9f95a23c TL |
537 | </div> |
538 | ||
539 | </div> | |
540 | </div> | |
541 | ||
542 | <!-- Quotas --> | |
543 | <div> | |
544 | <legend i18n>Quotas</legend> | |
545 | ||
546 | <!-- Max Bytes --> | |
547 | <div class="form-group row"> | |
548 | <label class="cd-col-form-label" | |
549 | for="max_bytes"> | |
550 | <ng-container i18n>Max bytes</ng-container> | |
551 | <cd-helper> | |
552 | <span i18n>Leave it blank or specify 0 to disable this quota.</span> | |
553 | <br> | |
554 | <span i18n>A valid quota should be greater than 0.</span> | |
555 | </cd-helper> | |
556 | </label> | |
557 | <div class="cd-col-form-input"> | |
558 | <input class="form-control" | |
559 | id="max_bytes" | |
560 | name="max_bytes" | |
561 | type="text" | |
562 | formControlName="max_bytes" | |
563 | i18n-placeholder | |
564 | placeholder="e.g., 10GiB" | |
565 | defaultUnit="GiB" | |
566 | cdDimlessBinary> | |
567 | </div> | |
568 | </div> | |
11fdf7f2 | 569 | |
9f95a23c TL |
570 | <!-- Max Objects --> |
571 | <div class="form-group row"> | |
572 | <label class="cd-col-form-label" | |
573 | for="max_objects"> | |
574 | <ng-container i18n>Max objects</ng-container> | |
575 | <cd-helper> | |
576 | <span i18n>Leave it blank or specify 0 to disable this quota.</span> | |
577 | <br> | |
578 | <span i18n>A valid quota should be greater than 0.</span> | |
579 | </cd-helper> | |
580 | </label> | |
581 | <div class="cd-col-form-input"> | |
582 | <input class="form-control" | |
583 | id="max_objects" | |
584 | min="0" | |
585 | name="max_objects" | |
586 | type="number" | |
587 | formControlName="max_objects"> | |
588 | <span class="invalid-feedback" | |
589 | *ngIf="form.showError('max_objects', formDir, 'min')" | |
590 | i18n>The value should be greater or equal to 0</span> | |
11fdf7f2 TL |
591 | </div> |
592 | </div> | |
9f95a23c | 593 | </div> |
11fdf7f2 TL |
594 | |
595 | <!-- Pool configuration --> | |
9f95a23c | 596 | <div [hidden]="isErasure || data.applications.selected.indexOf('rbd') === -1"> |
11fdf7f2 TL |
597 | <cd-rbd-configuration-form [form]="form" |
598 | [initializeData]="initializeConfigData" | |
599 | (changes)="currentConfigurationValues = $event()"> | |
600 | </cd-rbd-configuration-form> | |
601 | </div> | |
11fdf7f2 | 602 | </div> |
9f95a23c | 603 | <div class="card-footer"> |
f67539c2 TL |
604 | <cd-form-button-panel (submitActionEvent)="submit()" |
605 | [form]="form" | |
606 | [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)" | |
607 | wrappingClass="text-right"></cd-form-button-panel> | |
11fdf7f2 TL |
608 | </div> |
609 | ||
610 | </div> | |
611 | ||
612 | </form> | |
613 | </div> |