path: 'hosts',
component: NvmeofInitiatorsListComponent
},
+
{
path: 'namespaces',
component: NvmeofSubsystemNamespacesListComponent
path: `${URLVerbs.ADD}/listener`,
component: NvmeofListenersFormComponent,
outlet: 'modal'
+ },
+ {
+ path: `${URLVerbs.EDIT}/:subsystem_nqn/namespace/:nsid`,
+ component: NvmeofNamespaceExpandModalComponent,
+ outlet: 'modal'
}
]
}
[title]="subsystemNQN"
[items]="sidebarItems"
></cd-sidebar-layout>
-
<router-outlet name="modal"></router-outlet>
<cds-tab
heading="Gateways"
[tabContent]="gateways_content"
+
i18n-heading
[active]="activeTab === Tabs.gateways"
(selected)="onSelected(Tabs.gateways)">
<cds-tab
heading="Subsystem"
[tabContent]="subsystem_content"
+
i18n-heading
[active]="activeTab === Tabs.subsystem"
(selected)="onSelected(Tabs.subsystem)">
<cds-tab
heading="Namespace"
[tabContent]="namespace_content"
+
i18n-heading
[active]="activeTab === Tabs.namespace"
(selected)="onSelected(Tabs.namespace)">
[columnNumbers]="{sm: 4, md: 8}">
<div cdsRow
class="form-heading form-item">
- <h3>{{ action | titlecase }} {{ resource | titlecase }}</h3>
+ <h3>{{ title }}</h3>
<cd-help-text>
- <span i18n>
- Namespaces define the storage volumes that subsystems present to hosts.
+ <span>
+ {{ description }}
</span>
</cd-help-text>
</div>
import { Component, OnInit } from '@angular/core';
import { UntypedFormControl, Validators } from '@angular/forms';
-import { ActivatedRoute, Router } from '@angular/router';
+import { ActivatedRoute, Params, Router } from '@angular/router';
import {
NamespaceCreateRequest,
NamespaceInitiatorRequest,
resource: string;
pageURL: string;
+ title: string = '';
+ description: string = '';
+
nsForm: CdFormGroup;
subsystemNQN: string;
- subsystems: NvmeofSubsystem[];
+ subsystems: NvmeofSubsystem[] = [];
rbdPools: Array<Pool> = null;
rbdImages: any[] = [];
initiatorCandidates: { content: string; selected: boolean }[] = [];
}
init() {
- this.route.queryParams.subscribe((params) => {
- this.group = params?.['group'];
- });
this.createForm();
this.action = this.actionLabels.CREATE;
- this.route.params.subscribe((params: { subsystem_nqn: string; nsid: string }) => {
- this.subsystemNQN = params.subsystem_nqn;
- this.nsid = params?.nsid;
+ this.title = this.action + ' ' + this.resource;
+ this.description = $localize`Namespaces define the storage volumes that subsystems present to hosts.`;
+
+ this.route.params.subscribe((params: Params) => {
+ this.subsystemNQN = params['subsystem_nqn'];
+ this.nsid = params['nsid'];
+ if (params['group']) {
+ this.group = params['group'];
+ }
+ if (this.subsystemNQN && this.group) {
+ this.pageURL = `block/nvmeof/subsystems/${this.subsystemNQN}/${this.group}`;
+ this.action = this.actionLabels.ADD;
+ this.title = this.action + ' ' + this.resource;
+ this.description = $localize`Create a new namespace associated with this subsystem.`;
+ }
});
- this.route.queryParams.subscribe((params) => {
- if (params?.['subsystem_nqn']) {
- this.subsystemNQN = params?.['subsystem_nqn'];
+ this.route.queryParams.subscribe((params: Params) => {
+ if (params['group']) {
+ this.group = params['group'];
+ }
+ if (params['subsystem_nqn']) {
+ this.subsystemNQN = params['subsystem_nqn'];
+ }
+ if (this.subsystemNQN && this.group) {
+ this.pageURL = `block/nvmeof/subsystems/${this.subsystemNQN}/namespaces`;
+ this.action = this.actionLabels.ADD;
+ this.title = this.action + ' ' + this.resource;
+ this.description = $localize`Create a new namespace associated with this subsystem.`;
}
});
}
},
complete: () => {
this.router.navigate([this.pageURL], {
- queryParams: { group: this.group, tab: 'namespace' }
+ queryParams: { group: this.group }
});
}
});
<cd-table [data]="namespaces"
columnMode="flex"
(fetchData)="fetchData()"
- [autoReload]="false"
[columns]="namespacesColumns"
selectionType="single"
(updateSelection)="updateSelection($event)"
emptyStateMessage="Namespaces are storage volumes mapped to subsystems for host access. Create a namespace to start provisioning storage within a subsystem."
i18n-emptyStateMessage>
- <div class="table-actions">
- <cd-table-actions [permission]="permission"
- [selection]="selection"
- class="btn-group"
- [tableActions]="tableActions">
- </cd-table-actions>
- </div>
- </cd-table>
+ <div class="table-actions">
+ <cd-table-actions [permission]="permission"
+ [selection]="selection"
+ class="btn-group"
+ [tableActions]="tableActions">
+ </cd-table-actions>
+ </div>
+</cd-table>
</ng-container>
import { HttpClientModule } from '@angular/common/http';
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
import { of } from 'rxjs';
+import { take } from 'rxjs/operators';
import { RouterTestingModule } from '@angular/router/testing';
import { SharedModule } from '~/app/shared/shared.module';
it('should retrieve namespaces', (done) => {
component.group = 'g1';
- component.namespaces$.subscribe((namespaces) => {
+ component.namespaces$.pipe(take(1)).subscribe((namespaces) => {
expect(namespaces).toEqual(mockNamespaces);
done();
});
name: $localize`Expand`,
permission: 'update',
icon: Icons.edit,
- click: () =>
+ click: (row: NvmeofSubsystemNamespace) => {
+ const namespace = row || this.selection.first();
this.router.navigate(
[
{
outlets: {
- modal: [
- URLVerbs.EDIT,
- this.selection.first().ns_subsystem_nqn,
- 'namespace',
- this.selection.first().nsid
- ]
+ modal: [URLVerbs.EDIT, namespace.ns_subsystem_nqn, 'namespace', namespace.nsid]
}
}
],
queryParams: { group: this.group },
queryParamsHandling: 'merge'
}
- )
+ );
+ }
},
{
name: this.actionLabels.DELETE,
import { combineLatest, Subject } from 'rxjs';
import { takeUntil } from 'rxjs/operators';
-const BASE_URL = 'block/nvmeof/subsystems';
-
@Component({
selector: 'cd-nvmeof-subsystem-namespaces-list',
templateUrl: './nvmeof-subsystem-namespaces-list.component.html',
setupTableActions() {
this.tableActions = [
{
- name: this.actionLabels.CREATE,
+ name: this.actionLabels.ADD,
permission: 'create',
icon: Icons.add,
click: () =>
- this.router.navigate(
- [BASE_URL, { outlets: { modal: [URLVerbs.CREATE, this.subsystemNQN, 'namespace'] } }],
- { queryParams: { group: this.group } }
- ),
+ this.router.navigate(['block/nvmeof/namespaces/create'], {
+ queryParams: {
+ group: this.group,
+ subsystem_nqn: this.subsystemNQN
+ }
+ }),
+
canBePrimary: (selection: CdTableSelection) => !selection.hasSelection
},
{
- name: this.actionLabels.EDIT,
+ name: $localize`Expand`,
permission: 'update',
icon: Icons.edit,
- click: () =>
+ click: (row: NvmeofSubsystemNamespace) => {
+ const namespace = row || this.selection.first();
this.router.navigate(
[
- BASE_URL,
{
outlets: {
- modal: [
- URLVerbs.EDIT,
- this.subsystemNQN,
- 'namespace',
- this.selection.first().nsid
- ]
+ modal: [URLVerbs.EDIT, this.subsystemNQN, 'namespace', namespace.nsid]
}
}
],
- { queryParams: { group: this.group } }
- )
+ {
+ relativeTo: this.route.parent,
+ queryParams: { group: this.group },
+ queryParamsHandling: 'merge'
+ }
+ );
+ }
},
{
name: this.actionLabels.DELETE,
updateGroupSelectionState() {
if (this.gwGroups.length) {
+ this.gwGroupsEmpty = false;
+ this.gwGroupPlaceholder = DEFAULT_PLACEHOLDER;
if (!this.group) {
this.onGroupSelection(this.gwGroups[0]);
} else {
selected: g.content === this.group
}));
}
- this.gwGroupsEmpty = false;
- this.gwGroupPlaceholder = DEFAULT_PLACEHOLDER;
} else {
this.gwGroupsEmpty = true;
this.gwGroupPlaceholder = $localize`No groups available`;