(updateBucketDetails)="updateBucketDetails(extractLifecycleDetails.bind(this))"></cd-rgw-bucket-lifecycle-list>
</ng-template>
</ng-container>
+ <ng-container ngbNavItem="notification">
+ <a ngbNavLink
+ i18n>Notification</a>
+ <ng-template ngbNavContent>
+ <cd-rgw-bucket-notification-list [bucket]="selection"></cd-rgw-bucket-notification-list>
+ </ng-template>
+ </ng-container>
</nav>
<div [ngbNavOutlet]="nav"></div>
--- /dev/null
+ <fieldset>
+ <legend i18n
+ class="cd-header">
+ Notification Configuration
+ <cd-help-text>
+ Configure bucket notification to trigger alerts for specific events, such as object creation or transitions, based on prefixes or tags.
+ </cd-help-text>
+ </legend>
+ </fieldset>
+ <ng-container *ngIf="notification$ | async as notification">
+ <cd-table #table
+ [data]="notification"
+ [columns]="columns"
+ columnMode="flex"
+ selectionType="single"
+ identifier="Id"
+ (fetchData)="fetchData()">
+ </cd-table>
+ </ng-container>
+ <ng-template #filterTpl
+ let-config="data.value">
+ <ng-container *ngIf="config">
+ <ng-container *ngFor="let item of config | keyvalue">
+ <ng-container *ngIf="item.value?.FilterRule?.length">
+ <div class="cds--label">
+ {{ item.key }}:
+ </div>
+ <div [cdsStack]="'horizontal'"
+ *ngFor="let rule of item.value.FilterRule">
+ <cds-tag size="sm"
+ class="badge-background-gray">{{ rule.Name }}: {{ rule.Value }}</cds-tag>
+ </div>
+ <br>
+ </ng-container>
+ </ng-container>
+ </ng-container>
+ </ng-template>
+ <ng-template #eventTpl
+ let-event="data.value">
+ <ng-container *ngIf="event">
+ <cds-tag size="sm"
+ class="badge-background-primary">
+ {{ event }}
+ </cds-tag>
+ </ng-container>
+ </ng-template>
--- /dev/null
+@use '@carbon/layout';
+
+::ng-deep.cds--type-mono {
+ margin-right: layout.$spacing-02;
+}
--- /dev/null
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+import { HttpClientTestingModule } from '@angular/common/http/testing';
+import { RgwBucketNotificationListComponent } from './rgw-bucket-notification-list.component';
+import { configureTestBed } from '~/testing/unit-test-helper';
+import { ComponentsModule } from '~/app/shared/components/components.module';
+import { RgwBucketService } from '~/app/shared/api/rgw-bucket.service';
+import { of } from 'rxjs';
+
+class MockRgwBucketService {
+ listNotification = jest.fn((bucket: string) => of([{ bucket, notifications: [] }]));
+}
+describe('RgwBucketNotificationListComponent', () => {
+ let component: RgwBucketNotificationListComponent;
+ let fixture: ComponentFixture<RgwBucketNotificationListComponent>;
+ let rgwtbucketService: RgwBucketService;
+ let rgwnotificationListSpy: jasmine.Spy;
+
+ configureTestBed({
+ declarations: [RgwBucketNotificationListComponent],
+ imports: [ComponentsModule, HttpClientTestingModule],
+ providers: [
+ { provide: 'bucket', useValue: { bucket: 'bucket1', owner: 'dashboard' } },
+ { provide: RgwBucketService, useClass: MockRgwBucketService }
+ ]
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(RgwBucketNotificationListComponent);
+ component = fixture.componentInstance;
+ rgwtbucketService = TestBed.inject(RgwBucketService);
+ rgwnotificationListSpy = spyOn(rgwtbucketService, 'listNotification').and.callThrough();
+
+ fixture = TestBed.createComponent(RgwBucketNotificationListComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+ it('should call list', () => {
+ rgwtbucketService.listNotification('testbucket').subscribe((response) => {
+ expect(response).toEqual([{ bucket: 'testbucket', notifications: [] }]);
+ });
+ expect(rgwnotificationListSpy).toHaveBeenCalledWith('testbucket');
+ });
+});
--- /dev/null
+import { Component, Input, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { BehaviorSubject, Observable, of } from 'rxjs';
+import { RgwBucketService } from '~/app/shared/api/rgw-bucket.service';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
+import { TableComponent } from '~/app/shared/datatable/table/table.component';
+import { CdTableAction } from '~/app/shared/models/cd-table-action';
+import { CdTableColumn } from '~/app/shared/models/cd-table-column';
+import { CdTableSelection } from '~/app/shared/models/cd-table-selection';
+import { Permission } from '~/app/shared/models/permissions';
+import { AuthStorageService } from '~/app/shared/services/auth-storage.service';
+import { URLBuilderService } from '~/app/shared/services/url-builder.service';
+import { Bucket } from '../models/rgw-bucket';
+import { CdTableFetchDataContext } from '~/app/shared/models/cd-table-fetch-data-context';
+import { catchError, switchMap } from 'rxjs/operators';
+import { TopicConfiguration } from '~/app/shared/models/notification-configuration.model';
+import { ListWithDetails } from '~/app/shared/classes/list-with-details.class';
+import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
+
+const BASE_URL = 'rgw/bucket';
+@Component({
+ selector: 'cd-rgw-bucket-notification-list',
+ templateUrl: './rgw-bucket-notification-list.component.html',
+ styleUrl: './rgw-bucket-notification-list.component.scss',
+ providers: [{ provide: URLBuilderService, useValue: new URLBuilderService(BASE_URL) }]
+})
+export class RgwBucketNotificationListComponent extends ListWithDetails implements OnInit {
+ @Input() bucket: Bucket;
+ table: TableComponent;
+ permission: Permission;
+ tableActions: CdTableAction[];
+ columns: CdTableColumn[] = [];
+ selection: CdTableSelection = new CdTableSelection();
+ notification$: Observable<TopicConfiguration[]>;
+ subject = new BehaviorSubject<TopicConfiguration[]>([]);
+ context: CdTableFetchDataContext;
+ @ViewChild('filterTpl', { static: true })
+ filterTpl: TemplateRef<any>;
+ @ViewChild('eventTpl', { static: true })
+ eventTpl: TemplateRef<any>;
+
+ constructor(
+ private rgwBucketService: RgwBucketService,
+ private authStorageService: AuthStorageService,
+ public actionLabels: ActionLabelsI18n
+ ) {
+ super();
+ }
+
+ ngOnInit() {
+ this.permission = this.authStorageService.getPermissions().rgw;
+ this.columns = [
+ {
+ name: $localize`Name`,
+ prop: 'Id',
+ flexGrow: 2
+ },
+ {
+ name: $localize`Topic`,
+ prop: 'Topic',
+ flexGrow: 1,
+ cellTransformation: CellTemplate.copy
+ },
+ {
+ name: $localize`Event`,
+ prop: 'Event',
+ flexGrow: 1,
+ cellTemplate: this.eventTpl
+ },
+ {
+ name: $localize`Filter`,
+ prop: 'Filter',
+ flexGrow: 1,
+ cellTemplate: this.filterTpl
+ }
+ ];
+
+ this.notification$ = this.subject.pipe(
+ switchMap(() =>
+ this.rgwBucketService.listNotification(this.bucket.bucket).pipe(
+ catchError((error) => {
+ this.context.error(error);
+ return of(null);
+ })
+ )
+ )
+ );
+ }
+
+ fetchData() {
+ this.subject.next([]);
+ }
+}
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RgwTopicListComponent } from './rgw-topic-list.component';
-import { RgwTopicService } from '~/app/shared/api/rgw-topic.service';
import { SharedModule } from '~/app/shared/shared.module';
import { configureTestBed, PermissionHelper } from '~/testing/unit-test-helper';
import { RgwTopicDetailsComponent } from '../rgw-topic-details/rgw-topic-details.component';
import { HttpClientTestingModule } from '@angular/common/http/testing';
import { ToastrModule } from 'ngx-toastr';
import { of } from 'rxjs';
+import { RgwTopicService } from '~/app/shared/api/rgw-topic.service';
describe('RgwTopicListComponent', () => {
let component: RgwTopicListComponent;
TagModule,
TooltipModule,
ComboBoxModule,
- ToggletipModule
+ ToggletipModule,
+ LayoutModule
} from 'carbon-components-angular';
import { CephSharedModule } from '../shared/ceph-shared.module';
import { RgwUserAccountsComponent } from './rgw-user-accounts/rgw-user-accounts.component';
import { RgwTopicListComponent } from './rgw-topic-list/rgw-topic-list.component';
import { RgwTopicDetailsComponent } from './rgw-topic-details/rgw-topic-details.component';
import { RgwTopicFormComponent } from './rgw-topic-form/rgw-topic-form.component';
+import { RgwBucketNotificationListComponent } from './rgw-bucket-notification-list/rgw-bucket-notification-list.component';
@NgModule({
imports: [
ComboBoxModule,
ToggletipModule,
RadioModule,
- SelectModule
+ SelectModule,
+ LayoutModule
],
exports: [
RgwDaemonDetailsComponent,
RgwRateLimitDetailsComponent,
RgwTopicListComponent,
RgwTopicDetailsComponent,
- RgwTopicFormComponent
+ RgwTopicFormComponent,
+ RgwBucketNotificationListComponent
],
providers: [TitleCasePipe]
})
getGlobalBucketRateLimit() {
return this.http.get(`${this.url}/ratelimit`);
}
+
+ listNotification(bucket_name: string) {
+ return this.rgwDaemonService.request((params: HttpParams) => {
+ params = params.appendAll({
+ bucket_name: bucket_name
+ });
+ return this.http.get(`${this.url}/notification`, { params: params });
+ });
+ }
+
+ setNotification(bucket_name: string, notification: string, owner: string) {
+ return this.rgwDaemonService.request((params: HttpParams) => {
+ params = params.appendAll({
+ bucket_name: bucket_name,
+ notification: notification,
+ owner: owner
+ });
+ return this.http.put(`${this.url}/notification`, null, { params: params });
+ });
+ }
}
super();
}
- listTopic(): Observable<Topic[]> {
- return this.http.get<Topic[]>(this.baseURL);
+ listTopic(): Observable<Topic> {
+ return this.http.get<Topic>(this.baseURL);
}
getTopic(key: string) {
--- /dev/null
+export interface NotificationConfiguration {
+ TopicConfiguration: TopicConfiguration[];
+}
+
+export interface TopicConfiguration {
+ Id: string;
+ Topic: string;
+ Event: string[];
+ Filter?: Filter;
+}
+
+export interface Filter {
+ Key: Key;
+ Metadata: Metadata;
+ Tags: Tags;
+}
+
+export interface Key {
+ FilterRules: FilterRules[];
+}
+export interface Metadata {
+ FilterRules: FilterRules[];
+}
+export interface Tags {
+ FilterRules: FilterRules[];
+}
+export interface FilterRules {
+ Name: string;
+ Value: string;
+}
if topic_filter:
normalize_filter_rules(topic_filter)
- return notification_configuration
+ return topic_configuration
@RestClient.api_delete('/{bucket_name}?notification={notification_id}')
def delete_notification(self, bucket_name, notification_id, request=None):