Skip to content

Commit b849c63

Browse files
committed
mgr/dashboard: add smb share listing in UI
Fixes: https://tracker.ceph.com/issues/69449 Signed-off-by: Pedro Gonzalez Gomez <[email protected]>
1 parent bbcd13b commit b849c63

File tree

15 files changed

+303
-50
lines changed

15 files changed

+303
-50
lines changed

src/pybind/mgr/dashboard/controllers/smb.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ def list(self, cluster_id: str = '') -> List[Share]:
201201
'smb',
202202
'show',
203203
[f'{self._resource}.{cluster_id}' if cluster_id else self._resource])
204-
return res['resources'] if 'resources' in res else res
204+
return res['resources'] if 'resources' in res else [res]
205205

206206
@raise_on_failure
207207
@DeletePermission
Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,27 @@
11
<ng-container *ngIf="smbClusters$ | async as smbClusters">
22
<cd-table
3-
#table
43
[data]="smbClusters"
54
columnMode="flex"
65
[columns]="columns"
7-
identifier="id"
8-
forceIdentifier="true"
96
selectionType="single"
10-
[hasDetails]="false"
7+
[hasDetails]="true"
118
(setExpandedRow)="setExpandedRow($event)"
129
(fetchData)="loadSMBCluster($event)"
1310
(updateSelection)="updateSelection($event)"
1411
>
15-
<div class="table-actions">
16-
<cd-table-actions class="btn-group"
17-
[permission]="permission"
18-
[selection]="selection"
19-
[tableActions]="tableActions">
20-
</cd-table-actions>
21-
</div>
22-
</cd-table>
12+
<div class="table-actions">
13+
<cd-table-actions
14+
class="btn-group"
15+
[permission]="permission"
16+
[selection]="selection"
17+
[tableActions]="tableActions"
18+
>
19+
</cd-table-actions>
20+
</div>
21+
>
22+
<cd-smb-cluster-tabs
23+
*cdTableDetail
24+
[selection]="expandedRow">
25+
</cd-smb-cluster-tabs>
26+
</cd-table>
2327
</ng-container>
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<ng-container *ngIf="selection">
2+
<cds-tabs
3+
type="contained"
4+
followFocus="true"
5+
isNavigation="true"
6+
cacheActive="true">
7+
<cds-tab
8+
heading="Shares"
9+
i18n-heading>
10+
<cd-smb-share-list
11+
[clusterId]="selection.cluster_id"
12+
></cd-smb-share-list>
13+
</cds-tab>
14+
</cds-tabs>
15+
</ng-container>

src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-cluster-tabs/smb-cluster-tabs.component.scss

Whitespace-only changes.
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { SmbClusterTabsComponent } from './smb-cluster-tabs.component';
4+
import { RESOURCE_TYPE, SMBCluster } from '../smb.model';
5+
import { By } from '@angular/platform-browser';
6+
7+
describe('SmbClusterTabsComponent', () => {
8+
let component: SmbClusterTabsComponent;
9+
let fixture: ComponentFixture<SmbClusterTabsComponent>;
10+
11+
beforeEach(async () => {
12+
await TestBed.configureTestingModule({
13+
declarations: [SmbClusterTabsComponent]
14+
}).compileComponents();
15+
16+
fixture = TestBed.createComponent(SmbClusterTabsComponent);
17+
component = fixture.componentInstance;
18+
fixture.detectChanges();
19+
});
20+
21+
it('should create', () => {
22+
expect(component).toBeTruthy();
23+
});
24+
25+
it('should not render anything if selection is falsy', () => {
26+
component.selection = null;
27+
fixture.detectChanges();
28+
29+
const tabsElement = fixture.debugElement.query(By.css('cds-tabs'));
30+
expect(tabsElement).toBeNull();
31+
});
32+
33+
const selectedSmbCluster = (clusterId: string) => {
34+
const smbCluster: SMBCluster = {
35+
resource_type: RESOURCE_TYPE,
36+
cluster_id: clusterId,
37+
auth_mode: 'user'
38+
};
39+
return smbCluster;
40+
};
41+
42+
it('should render cds-tabs if selection is truthy', () => {
43+
component.selection = selectedSmbCluster('fooBar');
44+
fixture.detectChanges();
45+
46+
const tabsElement = fixture.debugElement.query(By.css('cds-tabs'));
47+
expect(tabsElement).toBeTruthy();
48+
});
49+
});
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import { Component, Input } from '@angular/core';
2+
import { SMBCluster } from '../smb.model';
3+
4+
@Component({
5+
selector: 'cd-smb-cluster-tabs',
6+
templateUrl: './smb-cluster-tabs.component.html',
7+
styleUrls: ['./smb-cluster-tabs.component.scss']
8+
})
9+
export class SmbClusterTabsComponent {
10+
@Input()
11+
selection: SMBCluster;
12+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<ng-container *ngIf="smbShares$ | async as smbShares">
2+
<cd-table
3+
[data]="smbShares"
4+
columnMode="flex"
5+
[columns]="columns"
6+
selectionType="single"
7+
[hasDetails]="false"
8+
(fetchData)="loadSMBShares()"
9+
>
10+
</cd-table>
11+
</ng-container>

src/pybind/mgr/dashboard/frontend/src/app/ceph/smb/smb-share-list/smb-share-list.component.scss

Whitespace-only changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
3+
import { SmbShareListComponent } from './smb-share-list.component';
4+
import { HttpClientTestingModule } from '@angular/common/http/testing';
5+
6+
describe('SmbShareListComponent', () => {
7+
let component: SmbShareListComponent;
8+
let fixture: ComponentFixture<SmbShareListComponent>;
9+
10+
beforeEach(async () => {
11+
await TestBed.configureTestingModule({
12+
imports: [HttpClientTestingModule],
13+
declarations: [SmbShareListComponent]
14+
}).compileComponents();
15+
16+
fixture = TestBed.createComponent(SmbShareListComponent);
17+
component = fixture.componentInstance;
18+
fixture.detectChanges();
19+
});
20+
21+
it('should create', () => {
22+
expect(component).toBeTruthy();
23+
});
24+
});
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { Component, Input, OnInit, ViewChild } from '@angular/core';
2+
import { Observable, BehaviorSubject, of } from 'rxjs';
3+
import { TableComponent } from '~/app/shared/datatable/table/table.component';
4+
import { CdTableColumn } from '~/app/shared/models/cd-table-column';
5+
import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
6+
import { Permission } from '~/app/shared/models/permissions';
7+
import { SMBShare } from '../smb.model';
8+
import { switchMap, catchError } from 'rxjs/operators';
9+
import { SmbService } from '~/app/shared/api/smb.service';
10+
import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
11+
import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
12+
13+
@Component({
14+
selector: 'cd-smb-share-list',
15+
templateUrl: './smb-share-list.component.html',
16+
styleUrls: ['./smb-share-list.component.scss']
17+
})
18+
export class SmbShareListComponent implements OnInit {
19+
@Input()
20+
clusterId: string;
21+
@ViewChild('table', { static: true })
22+
table: TableComponent;
23+
columns: CdTableColumn[];
24+
permission: Permission;
25+
context: CdTableFetchDataContext;
26+
27+
smbShares$: Observable<SMBShare[]>;
28+
subject$ = new BehaviorSubject<SMBShare[]>([]);
29+
30+
constructor(private authStorageService: AuthStorageService, private smbService: SmbService) {
31+
this.permission = this.authStorageService.getPermissions().smb;
32+
}
33+
34+
ngOnInit() {
35+
this.columns = [
36+
{
37+
name: $localize`ID`,
38+
prop: 'share_id',
39+
flexGrow: 2
40+
},
41+
{
42+
name: $localize`Name`,
43+
prop: 'name',
44+
flexGrow: 2
45+
},
46+
{
47+
name: $localize`File System`,
48+
prop: 'cephfs.volume',
49+
flexGrow: 2
50+
},
51+
{
52+
name: $localize`Path`,
53+
prop: 'cephfs.path',
54+
cellTransformation: CellTemplate.path,
55+
flexGrow: 2
56+
},
57+
{
58+
name: $localize`Subvolume group`,
59+
prop: 'cephfs.subvolumegroup',
60+
flexGrow: 2
61+
},
62+
{
63+
name: $localize`Subvolume`,
64+
prop: 'cephfs.subvolume',
65+
flexGrow: 2
66+
},
67+
{
68+
name: $localize`Provider`,
69+
prop: 'cephfs.provider',
70+
flexGrow: 2
71+
}
72+
];
73+
74+
this.smbShares$ = this.subject$.pipe(
75+
switchMap(() =>
76+
this.smbService.listShares(this.clusterId).pipe(
77+
catchError(() => {
78+
this.context.error();
79+
return of(null);
80+
})
81+
)
82+
)
83+
);
84+
}
85+
86+
loadSMBShares() {
87+
this.subject$.next([]);
88+
}
89+
}

0 commit comments

Comments
 (0)