10 [columnNumbers]="{sm: 4, md: 8}">
12 class="form-heading form-item">
13 <h3>{{ action | titlecase }} {{ resource | titlecase }}</h3>
14 <cd-help-text [formAllFieldsRequired]="true">
16 Namespaces define the storage volumes that subsystems present to hosts.
21 <!-- Namespace Count (Create only) -->
27 formControlName="nsCount"
29 #nsCountRef="cdValidate"
30 label="Number of namespaces"
31 helperText="No. of namespaces to generate. Value must be between 1 and 5."
32 [min]="MIN_NAMESPACE_CREATE"
33 [max]="MAX_NAMESPACE_CREATE"
34 [invalid]="nsCountRef.isInvalid"
35 [invalidText]="nsCountError"
39 <ng-template #nsCountError>
40 <ng-container *ngTemplateOutlet="validationErrors; context: { control: nsForm.get('nsCount') }"></ng-container>
46 <!-- Namespace Size (sent as block_size) -->
52 formControlName="namespace_size"
53 cdOptionalField="Namespace size (GiB)"
54 label="Namespace size (GiB)"
55 helperText="Specify the size to expose to hosts. Leave blank for full device/file."
56 placeholder="e.g. 100"
58 [invalid]="nsForm.controls['namespace_size'].invalid && (nsForm.controls['namespace_size'].dirty || nsForm.controls['namespace_size'].touched)"
59 invalidText="Value must be greater than or equal to 0."
68 <!-- Host Access (drives no_auto_visible in create request) -->
74 class="cds--type-label-01"
75 i18n>Host access (Initiators)</legend>
76 <div class="form-item">
78 formControlName="host_access"
79 orientation="horizontal">
85 class="cds--type-body-compact-01"
86 i18n>All hosts on the subsystem</span>
88 class="cds--type-helper-text-01 cds-ml-1 d-block"
89 i18n>Allow all hosts associated with the selected subsystem to access the namespace.</span>
92 <cds-radio value="specific">
95 class="cds--type-body-compact-01"
96 i18n>Select specific hosts</span>
98 class="cds--type-helper-text-01 cds-ml-1 d-block"
99 i18n>Only the selected hosts will be able to access this namespace.</span>
108 <!-- Host Selection (Visible only when 'specific' is selected) -->
109 @if (!edit && nsForm.getValue('host_access') === 'specific') {
113 <div class="form-item">
116 selectionFeedback="top-after-reopen"
119 placeholder="Select one or more hosts"
120 [appendInline]="true"
121 [items]="initiatorCandidates"
122 (selected)="onInitiatorSelection($event)"
123 [invalid]="nsForm.controls['initiators'].invalid && (nsForm.controls['initiators'].dirty || nsForm.controls['initiators'].touched)"
124 invalidText="This field is required."
127 <cds-dropdown-list></cds-dropdown-list>
144 [value]="nsForm.get('subsystem').value" />
148 formControlName="subsystem"
150 #subsystemRef="cdValidate"
151 label="Select subsystem"
152 [invalid]="subsystemRef.isInvalid"
153 invalidText="This field is required."
156 @if (subsystems === undefined) {
159 disabled>Loading...</option>
161 @if (subsystems && subsystems.length === 0) {
164 disabled>-- No subsystems available --</option>
166 @if (subsystems && subsystems.length > 0) {
169 selected>Select a subsystem</option>
171 @for (subsystem of subsystems; track subsystem.nqn) {
173 [value]="subsystem.nqn">{{ subsystem.nqn }}</option>
186 label="RBD image pool"
190 [value]="nsForm.get('pool').value" />
194 formControlName="pool"
196 #poolRef="cdValidate"
197 label="RBD image pool"
198 [invalid]="poolRef.isInvalid"
199 invalidText="This field is required."
200 helperText="Pool where the backing Ceph block device resides."
204 @if (rbdPools === null) {
207 disabled>Loading...</option>
209 @if (rbdPools && rbdPools.length === 0) {
212 disabled>-- No block pools available --</option>
214 @if (rbdPools && rbdPools.length > 0) {
217 selected>Select a RBD image pool</option>
219 @for (pool of rbdPools; track pool.pool_name) {
221 [value]="pool.pool_name">{{ pool.pool_name }}</option>
228 <!-- RBD image creation (drives create_image flag in request) -->
234 class="cds--type-label-01"
235 i18n>RBD image creation</legend>
237 formControlName="rbd_image_creation"
238 orientation="vertical">
240 value="gateway_provisioned"
241 i18n>Gateway-provisioned image</cds-radio>
243 value="externally_managed"
244 [disabled]="nsForm.getValue('nsCount') > 1"
245 [title]="nsForm.getValue('nsCount') > 1 ? 'Unavailable during bulk creation. RBD images are created automatically.' : ''"
246 i18n>Externally managed image</cds-radio>
252 <!-- Image Name (Visible when 'gateway_provisioned' and nsCount > 1) -->
253 @if (!edit && nsForm.getValue('rbd_image_creation') === 'gateway_provisioned' && nsForm.getValue('nsCount') > 1) {
259 [dismissible]="false"
261 <strong i18n>For bulk namespace creation, RBD images are provisioned automatically.</strong>
264 <div class="form-item"
265 cdOptionalField="Image name">
267 class="cds--type-label-01 cds--label"
268 i18n>Image name</label>
270 helperText="Provide a name for the images. For bulk creation, this will be used as the base prefix with numeric suffixes (e.g., img-1, img-2). Leave blank to auto-generate."
271 [invalid]="rbdImageNameRef.isInvalid"
272 [invalidText]="rbdImageNameError"
275 placeholder="Enter a name"
276 formControlName="rbd_image_name"
278 #rbdImageNameRef="cdValidate"
279 [invalid]="rbdImageNameRef.isInvalid" />
281 <ng-template #rbdImageNameError>
282 <ng-container *ngTemplateOutlet="validationErrors; context: { control: nsForm.get('rbd_image_name') }"></ng-container>
289 <!-- Image Selection (Visible only when 'externally_managed' is selected) -->
290 @if (!edit && nsForm.getValue('rbd_image_creation') === 'externally_managed') {
295 formControlName="rbd_image_name"
297 #rbdImageSelectRef="cdValidate"
299 [invalid]="rbdImageSelectRef.isInvalid"
300 invalidText="This field is required."
301 helperText="Select an existing RBD image from the pool to expose as a namespace."
308 selected>Select an image</option>
309 @for (img of rbdImages; track img.name) {
311 [value]="img.name">{{ img.name }} ({{ img.size | dimlessBinary }})</option>
319 @if (!edit && nsForm.getValue('rbd_image_creation') !== 'externally_managed') {
324 [columnNumbers]="{md: 4}">
326 helperText="The size of the namespace image."
327 [invalid]="imageSizeRef.isInvalid"
328 [invalidText]="sizeError"
333 placeholder="e.g. 100 GiB"
335 formControlName="image_size"
337 #imageSizeRef="cdValidate"
338 [invalid]="imageSizeRef.isInvalid"
343 <ng-template #sizeError>
344 <ng-container *ngTemplateOutlet="validationErrors; context: { control: nsForm.get('image_size') }"></ng-container>
351 <cd-form-button-panel
352 (submitActionEvent)="onSubmit()"
354 [submitText]="(action | titlecase) + ' ' + (resource | titlecase)"
355 wrappingClass="text-right form-button">
356 </cd-form-button-panel>
363 <ng-template #validationErrors
364 let-control="control">
365 @if (control.errors) {
366 @for (err of control.errors | keyvalue; track err.key) {
367 <span class="invalid-feedback">{{ INVALID_TEXTS[err.key] }}</span>