LayoutModule,
ContainedListModule,
LayerModule,
- ThemeModule,
- LayoutModule
+ ThemeModule
} from 'carbon-components-angular';
// Icons
<div
class="cds--type-label-01"
i18n>
- Nodes to run NVMe-oF target pods/services
+ Nodes to run NVMe-oF target service
</div>
</div>
import { TableComponent } from '~/app/shared/datatable/table/table.component';
import { HostStatus } from '~/app/shared/enum/host-status.enum';
import { Icons } from '~/app/shared/enum/icons.enum';
+import { NvmeofGatewayNodeMode } from '~/app/shared/enum/nvmeof.enum';
import { CdTableAction } from '~/app/shared/models/cd-table-action';
import { CdTableColumn } from '~/app/shared/models/cd-table-column';
import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
@Output() hostsLoaded = new EventEmitter<number>();
@Input() groupName: string | undefined;
- @Input() mode: 'selector' | 'details' = 'selector';
+ @Input() mode: 'selector' | 'details' = NvmeofGatewayNodeMode.SELECTOR;
usedHostnames: Set<string> = new Set();
serviceSpec: CephServiceSpec | undefined;
this.mode = routeData['mode'];
}
- this.selectionType = this.mode === 'selector' ? 'multiClick' : 'single';
+ this.selectionType = this.mode === NvmeofGatewayNodeMode.SELECTOR ? 'multiClick' : 'single';
- if (this.mode === 'details') {
+ if (this.mode === NvmeofGatewayNodeMode.DETAILS) {
this.route.parent?.params.subscribe((params: any) => {
this.groupName = params.group;
});
}
const fetchData$: Observable<any> =
- this.mode === 'details'
+ this.mode === NvmeofGatewayNodeMode.DETAILS
? this.nvmeofService.fetchHostsAndGroups()
: this.nvmeofService.getAvailableHosts(this.tableContext?.toParams());
)
.subscribe({
next: (result: any) => {
- if (this.mode === 'details') {
+ if (this.mode === NvmeofGatewayNodeMode.DETAILS) {
this.processDetailsData(result.groups, result.hosts);
} else {
this.hosts = result;
import {
NvmeofSubsystem,
NvmeofSubsystemData,
- NvmeofSubsystemInitiator
+ NvmeofSubsystemInitiator,
+ getSubsystemAuthStatus
} from '~/app/shared/models/nvmeof';
import { CdTableColumn } from '~/app/shared/models/cd-table-column';
import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
count = initiators.hosts.length;
}
- let authStatus = NvmeofSubsystemAuthType.NO_AUTH;
- if (sub.psk) {
- authStatus = NvmeofSubsystemAuthType.BIDIRECTIONAL;
- } else if (
- initiators &&
- 'hosts' in initiators &&
- Array.isArray(initiators.hosts)
- ) {
- const hasDhchapKey = initiators.hosts.some(
- (host: NvmeofSubsystemInitiator) => !!host.dhchap_key
- );
- if (hasDhchapKey) {
- authStatus = NvmeofSubsystemAuthType.UNIDIRECTIONAL;
- }
- } else if (Array.isArray(initiators)) {
- // Fallback for unexpected structure, though getInitiators usually returns {hosts: []}
- const hasDhchapKey = (initiators as NvmeofSubsystemInitiator[]).some(
- (host: NvmeofSubsystemInitiator) => !!host.dhchap_key
- );
- if (hasDhchapKey) {
- authStatus = NvmeofSubsystemAuthType.UNIDIRECTIONAL;
- }
- }
-
return {
...sub,
- auth: authStatus,
+ auth: getSubsystemAuthStatus(sub, initiators),
hosts: count
};
}
let-row="data.row">
<div [cdsStack]="'horizontal'"
gap="4">
- @if (row.enable_ha === false) {
+ @if (row.auth === authType.NO_AUTH) {
<cd-icon type="warning"></cd-icon>
- <span class="cds-ml-3"
- i18n>No authentication</span>
- } @else if (row.allow_any_host) {
- <cd-icon type="success"></cd-icon>
- <span class="cds-ml-3"
- i18n>Unidirectional</span>
} @else {
<cd-icon type="success"></cd-icon>
- <span class="cds-ml-3"
- i18n>Bidirectional</span>
}
+ <span class="cds-ml-3">{{ row.auth }}</span>
</div>
</ng-template>
const expected = mockSubsystems.map((s) => ({
...s,
gw_group: component.group,
+ auth: 'No authentication',
initiator_count: 0
}));
expect(component.subsystems).toEqual(expected);
import { ActivatedRoute, Router } from '@angular/router';
import { ActionLabelsI18n, URLVerbs } from '~/app/shared/constants/app.constants';
import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
-import { NvmeofSubsystem, NvmeofSubsystemInitiator } from '~/app/shared/models/nvmeof';
+import {
+ NvmeofSubsystem,
+ NvmeofSubsystemInitiator,
+ getSubsystemAuthStatus
+} from '~/app/shared/models/nvmeof';
import { Permissions } from '~/app/shared/models/permissions';
import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
import { ListWithDetails } from '~/app/shared/classes/list-with-details.class';
import { CdTableAction } from '~/app/shared/models/cd-table-action';
import { Icons } from '~/app/shared/enum/icons.enum';
+import { NvmeofSubsystemAuthType } from '~/app/shared/enum/nvmeof.enum';
import { DeleteConfirmationModalComponent } from '~/app/shared/components/delete-confirmation-modal/delete-confirmation-modal.component';
import { FinishedTask } from '~/app/shared/models/finished-task';
import { TaskWrapperService } from '~/app/shared/services/task-wrapper.service';
group: string = null;
gwGroupsEmpty: boolean = false;
gwGroupPlaceholder: string = DEFAULT_PLACEHOLDER;
+ authType = NvmeofSubsystemAuthType;
private destroy$ = new Subject<void>();
return {
...sub,
gw_group: this.group,
- initiator_count: count
- } as NvmeofSubsystem & { initiator_count?: number };
+ initiator_count: count,
+ auth: getSubsystemAuthStatus(sub, initiators)
+ } as NvmeofSubsystem & { initiator_count?: number; auth?: string };
})
);
}
}
<div class="sidebar-layout-container">
<div class="sidebar-layout-shell">
- <cds-sidenav [expanded]="true">
+ <cds-sidenav
+ [expanded]="true"
+ class="sidebar-layout-nav">
@for (item of items; track item.label) {
<cds-sidenav-item
[route]="item.route"
.sidebar-layout-container {
min-height: calc(100vh - (vv.$navbar-height + layout.rem(55px)));
- background-color: var(--cds-background);
padding-right: var(--cds-spacing-07);
+ background-color: var(--cds-background);
}
.sidebar-layout-shell {
transform: translate(0);
position: relative;
+ height: 100vh;
+}
+
+.sidebar-layout-nav {
+ background-color: var(--cds-layer-03);
}
.sidebar-layout-main {
margin-left: layout.rem(272px);
+
+ .cds--table-toolbar {
+ background-color: var(--cds-layer-03);
+ }
+
+ .cds--data-table tbody {
+ background-color: var(--cds-layer-03);
+ }
+
+ .cds--pagination {
+ background-color: var(--cds-layer-03);
+ }
}
.sidebar-header {
ALL: 'all',
SPECIFIC: 'specific'
};
+
+/**
+ * Determines the authentication status of a subsystem based on PSK and initiators.
+ * Can be reused across subsystem pages.
+ */
+export function getSubsystemAuthStatus(
+ subsystem: NvmeofSubsystem,
+ _initiators: NvmeofSubsystemInitiator[] | { hosts?: NvmeofSubsystemInitiator[] }
+): string {
+ // Import enum value strings to avoid circular dependency
+ const NO_AUTH = 'No authentication';
+ const UNIDIRECTIONAL = 'Unidirectional';
+ const BIDIRECTIONAL = 'Bi-directional';
+
+ if (subsystem.psk) {
+ return BIDIRECTIONAL;
+ }
+
+ let hostsList: NvmeofSubsystemInitiator[] = [];
+ if (_initiators && 'hosts' in _initiators && Array.isArray(_initiators.hosts)) {
+ hostsList = _initiators.hosts;
+ } else if (Array.isArray(_initiators)) {
+ hostsList = _initiators as NvmeofSubsystemInitiator[];
+ }
+
+ const hasDhchapKey = hostsList.some((host) => !!host.dhchap_key);
+ if (hasDhchapKey) {
+ return UNIDIRECTIONAL;
+ }
+
+ return NO_AUTH;
+}