beforeEach(() => {
cy.login();
- multisite.navigateTo();
});
- describe('tabs and table tests', () => {
- it('should show two tabs', () => {
- multisite.getTabsCount().should('eq', 2);
- });
-
- it('should show Configuration tab as a first tab', () => {
- multisite.getTabText(0).should('eq', 'Configuration');
- });
-
- it('should show sync policy tab as a second tab', () => {
- multisite.getTabText(1).should('eq', 'Sync Policy');
+ describe('table tests', () => {
+ it('should show table on sync-policy page', () => {
+ multisite.navigateTo();
+ multisite.tableExist();
});
});
});
it('should edit policy status', () => {
+ multisite.navigateTo();
multisite.edit('test', 'Forbidden');
});
it('should delete policy', () => {
- multisite.getTab('Sync Policy').click();
+ multisite.navigateTo();
multisite.delete('test');
});
});
});
describe('symmetrical Flow creation started', () => {
beforeEach(() => {
- multisite.getTab('Sync Policy').click();
+ multisite.navigateTo();
multisite.getExpandCollapseElement().click();
});
describe('create, edit & delete directional sync Flow', () => {
beforeEach(() => {
- multisite.getTab('Sync Policy').click();
+ multisite.navigateTo();
multisite.getExpandCollapseElement().click();
});
describe('create, edit, delete pipe', () => {
beforeEach(() => {
- multisite.getTab('Sync Policy').click();
+ multisite.navigateTo();
multisite.getExpandCollapseElement().click();
});
const WAIT_TIMER = 1000;
const pages = {
- index: { url: '#/rgw/multisite', id: 'cd-rgw-multisite-details' },
- create: { url: '#/rgw/multisite/sync-policy/create', id: 'cd-rgw-multisite-sync-policy-form' },
- edit: { url: '#/rgw/multisite/sync-policy/edit', id: 'cd-rgw-multisite-sync-policy-form' }
+ index: { url: '#/rgw/multisite/sync-policy', id: 'cd-rgw-multisite-sync-policy' },
+ create: {
+ url: '#/rgw/multisite/sync-policy/(modal:create)',
+ id: 'cd-rgw-multisite-sync-policy-form'
+ },
+ edit: { url: '#/rgw/multisite/sync-policy/(modal:edit', id: 'cd-rgw-multisite-sync-policy-form' }
};
export class MultisitePageHelper extends PageHelper {
pages = pages;
status: 4
};
+ tableExist() {
+ cy.get('cd-rgw-multisite-sync-policy cd-table').should('exist');
+ cy.get('cd-rgw-multisite-sync-policy cd-table-actions').should('exist');
+ }
+
@PageHelper.restrictTo(pages.create.url)
create(group_id: string, status: string) {
// Enter in group_id
@PageHelper.restrictTo(pages.index.url)
edit(group_id: string, status: string) {
- cy.visit(`${pages.edit.url}/${group_id}`);
+ cy.visit(`${pages.edit.url}/${group_id})`);
// Change the status field
this.selectOption('status', status);
@PageHelper.restrictTo(pages.index.url)
createSymmetricalFlow(flow_id: string, zones: string[]) {
- cy.get('cd-rgw-multisite-sync-policy-details').should('exist');
- this.getTab('Flow').should('exist');
- this.getTab('Flow').click();
cy.request({
method: 'GET',
url: '/api/rgw/daemon',
-<nav ngbNav
- #nav="ngbNav"
- class="nav-tabs"
- [(activeId)]="activeId"
- (navChange)="onNavChange($event)">
- <ng-container ngbNavItem="configuration">
- <a ngbNavLink
- i18n>Configuration</a>
- <ng-template ngbNavContent>
- <div>
- <cd-alert-panel
- *ngIf="!rgwModuleStatus"
- type="info"
- spacingClass="mb-3"
- class="d-flex align-items-center"
- i18n
- >In order to access the import/export feature, the rgw module must be enabled
-
- <button class="btn btn-light mx-2"
- type="button"
- (click)="enableRgwModule()">
- Enable
- </button>
- </cd-alert-panel>
- <cd-alert-panel
- *ngIf="restartGatewayMessage"
- type="warning"
- spacingClass="mb-3"
- i18n>Please restart all Ceph Object Gateway instances in all zones to ensure consistent
- multisite configuration updates.
- <a class="text-decoration-underline"
- routerLink="/services"> Cluster->Services</a>
- </cd-alert-panel>
- <cd-table-actions
- class="btn-group mb-4 me-2"
- [permission]="permission"
- [selection]="selection"
- [tableActions]="createTableActions"
- >
- </cd-table-actions>
- <span *ngIf="showMigrateAction">
- <cd-table-actions
- class="btn-group mb-4 me-2 secondary"
- [permission]="permission"
- [btnColor]="'light'"
- [selection]="selection"
- [tableActions]="migrateTableAction"
- >
- </cd-table-actions>
- </span>
- <cd-table-actions
- class="btn-group mb-4 me-2"
- [permission]="permission"
- [btnColor]="'light'"
- [selection]="selection"
- [tableActions]="importAction"
- >
- </cd-table-actions>
- <cd-table-actions
- class="btn-group mb-4 me-2"
- [permission]="permission"
- [btnColor]="'light'"
- [selection]="selection"
- [tableActions]="exportAction">
- </cd-table-actions>
- </div>
- <div class="card">
- <div class="card-header"
- i18n>Topology Viewer</div>
- <div class="card-body">
- <div class="row">
- <div class="col-sm-6 col-lg-6 tree-container">
- <i *ngIf="loadingIndicator"
- [ngClass]="[icons.large, icons.spinner, icons.spin]"></i>
- <tree-root
- #tree
- [nodes]="nodes"
- [options]="treeOptions"
- (updateData)="onUpdateData()">
- <ng-template
- #treeNodeTemplate
- let-node>
- <span *ngIf="node.data.name"
- class="me-3">
- <span *ngIf="node.data.show_warning">
- <i
- class="text-danger"
- i18n-title
- [title]="node.data.warning_message"
- [ngClass]="icons.danger"
- ></i>
- </span>
- <i [ngClass]="node.data.icon"></i>
- {{ node.data.name }}
- </span>
- <span class="badge badge-success me-2"
- *ngIf="node.data.is_default">
- default
- </span>
- <span class="badge badge-warning me-2"
- *ngIf="node.data.is_master"> master </span>
- <span class="badge badge-warning me-2"
- *ngIf="node.data.secondary_zone">
- secondary-zone
- </span>
- <div class="btn-group align-inline-btns"
- *ngIf="node.isFocused"
- role="group">
- <div [title]="editTitle"
- i18n-title>
- <button
- type="button"
- class="btn btn-light dropdown-toggle-split ms-1"
- (click)="openModal(node, true)"
- [disabled]="getDisable() || node.data.secondary_zone">
- <i [ngClass]="[icons.edit]"></i>
- </button>
- </div>
- <div [title]="deleteTitle"
- i18n-title>
- <button
- type="button"
- class="btn btn-light ms-1"
- [disabled]="isDeleteDisabled(node) || node.data.secondary_zone"
- (click)="delete(node)">
- <i [ngClass]="[icons.destroy]"></i>
- </button>
- </div>
- </div>
- </ng-template>
- </tree-root>
+<cd-rgw-multisite-tabs></cd-rgw-multisite-tabs>
+<div>
+ <cd-alert-panel *ngIf="!rgwModuleStatus"
+ type="info"
+ spacingClass="mb-3"
+ class="d-flex align-items-center"
+ i18n>In order to access the import/export feature, the rgw module must be enabled
+ <button class="btn btn-light mx-2"
+ type="button"
+ (click)="enableRgwModule()">Enable</button>
+ </cd-alert-panel>
+ <cd-alert-panel *ngIf="restartGatewayMessage"
+ type="warning"
+ spacingClass="mb-3"
+ i18n>Please restart all Ceph Object Gateway instances in all zones to ensure consistent multisite configuration updates.
+ <a class="text-decoration-underline"
+ routerLink="/services">
+ Cluster->Services</a>
+ </cd-alert-panel>
+ <cd-table-actions class="btn-group mb-4 me-2"
+ [permission]="permission"
+ [selection]="selection"
+ [tableActions]="createTableActions">
+ </cd-table-actions>
+ <cd-table-actions class="btn-group mb-4 me-2 secondary"
+ [permission]="permission"
+ [btnColor]="'light'"
+ [selection]="selection"
+ [tableActions]="migrateTableAction">
+ </cd-table-actions>
+ <cd-table-actions class="btn-group mb-4 me-2"
+ [permission]="permission"
+ [btnColor]="'light'"
+ [selection]="selection"
+ [tableActions]="importAction">
+ </cd-table-actions>
+ <cd-table-actions class="btn-group mb-4 me-2"
+ [permission]="permission"
+ [btnColor]="'light'"
+ [selection]="selection"
+ [tableActions]="exportAction">
+ </cd-table-actions>
+</div>
+<div class="card">
+ <div class="card-header"
+ i18n>Topology Viewer</div>
+ <div class="row">
+ <div class="col-sm-6 col-lg-6 tree-container">
+ <i *ngIf="loadingIndicator"
+ [ngClass]="[icons.large, icons.spinner, icons.spin]"></i>
+ <tree-root #tree
+ [nodes]="nodes"
+ [options]="treeOptions"
+ (updateData)="onUpdateData()">
+ <ng-template #treeNodeTemplate
+ let-node>
+ <span *ngIf="node.data.name"
+ class="me-3">
+ <span *ngIf="(node.data.show_warning)">
+ <i class="text-danger"
+ i18n-title
+ [title]="node.data.warning_message"
+ [ngClass]="icons.danger"></i>
+ </span>
+ <i [ngClass]="node.data.icon"></i>
+ {{ node.data.name }}
+ </span>
+ <span class="badge badge-success me-2"
+ *ngIf="node.data.is_default">
+ default
+ </span>
+ <span class="badge badge-warning me-2"
+ *ngIf="node.data.is_master"> master </span>
+ <span class="badge badge-warning me-2"
+ *ngIf="node.data.secondary_zone">
+ secondary-zone
+ </span>
+ <div class="btn-group align-inline-btns"
+ *ngIf="node.isFocused"
+ role="group">
+ <div [title]="editTitle"
+ i18n-title>
+ <button type="button"
+ class="btn btn-light dropdown-toggle-split ms-1"
+ (click)="openModal(node, true)"
+ [disabled]="getDisable() || node.data.secondary_zone">
+ <i [ngClass]="[icons.edit]"></i>
+ </button>
</div>
- <div class="col-sm-6 col-lg-6 metadata"
- *ngIf="metadata">
- <legend>{{ metadataTitle }}</legend>
- <div>
- <cd-table-key-value
- cdTableDetail
- [data]="metadata"></cd-table-key-value>
- </div>
+ <div [title]="deleteTitle"
+ i18n-title>
+ <button type="button"
+ class="btn btn-light ms-1"
+ [disabled]="isDeleteDisabled(node) || node.data.secondary_zone"
+ (click)="delete(node)">
+ <i [ngClass]="[icons.destroy]"></i>
+ </button>
</div>
</div>
- </div>
+ </ng-template>
+ </tree-root>
+ </div>
+ <div class="col-sm-6 col-lg-6 metadata"
+ *ngIf="metadata">
+ <legend>{{ metadataTitle }}</legend>
+ <div>
+ <cd-table-key-value cdTableDetail
+ [data]="metadata">
+ </cd-table-key-value>
</div>
- </ng-template>
- </ng-container>
- <ng-container ngbNavItem="syncPolicy">
- <a ngbNavLink
- i18n>Sync Policy</a>
- <ng-template ngbNavContent>
- <cd-rgw-multisite-sync-policy></cd-rgw-multisite-sync-policy>
- </ng-template>
- </ng-container>
-</nav>
-
-<div [ngbNavOutlet]="nav"></div>
+ </div>
+ </div>
+</div>
import { MgrModuleService } from '~/app/shared/api/mgr-module.service';
import { BlockUI, NgBlockUI } from 'ng-block-ui';
import { Router } from '@angular/router';
+import { RgwMultisiteSyncPolicyComponent } from '../rgw-multisite-sync-policy/rgw-multisite-sync-policy.component';
@Component({
selector: 'cd-rgw-multisite-details',
private sub = new Subscription();
@ViewChild('tree') tree: TreeComponent;
+ @ViewChild(RgwMultisiteSyncPolicyComponent) syncPolicyComp: RgwMultisiteSyncPolicyComponent;
messages = {
noDefaultRealm: $localize`Please create a default realm first to enable this feature`,
private notificationService: NotificationService
) {
this.permission = this.authStorageService.getPermissions().rgw;
- const activeId = this.router.getCurrentNavigation()?.extras?.state?.activeId;
- if (activeId) {
- this.activeId = activeId;
- }
}
openModal(entity: any, edit = false) {
}
);
}
-
- onNavChange(event: any) {
- if (event.nextId == 'configuration') {
- this.metadata = null;
- /*
- It is a known issue with angular2-tree package when tree is hidden (for example inside tab or modal),
- it is not rendered when it becomes visible. Solution is to call this.tree.sizeChanged() which recalculates
- the rendered nodes according to the actual viewport size. (https://angular2-tree.readme.io/docs/common-issues)
- */
- setTimeout(() => {
- this.tree.sizeChanged();
- this.onUpdateData();
- }, 200);
- }
- }
}
<cd-modal [modalRef]="activeModal">
- <ng-container
- i18n="form title"
- class="modal-title">{{ action | titlecase }} {{ groupType | upperFirst }} Flow</ng-container>
+ <ng-container i18n="form title"
+ class="modal-title">{{ action | titlecase }} {{ groupType | upperFirst }} Flow</ng-container>
<ng-container class="modal-content">
- <form
- name="flowForm"
- #frm="ngForm"
- [formGroup]="currentFormGroupContext"
- novalidate>
+ <form name="flowForm"
+ #frm="ngForm"
+ [formGroup]="currentFormGroupContext"
+ novalidate>
<div class="modal-body">
<div class="form-group row">
- <label
- class="cd-col-form-label required"
- for="flow_id"
- i18n>Name</label>
+ <label class="cd-col-form-label required"
+ for="flow_id"
+ i18n>Name</label>
<div class="cd-col-form-input">
- <input
- class="form-control"
- type="text"
- placeholder="Flow Name..."
- id="flow_id"
- name="flow_id"
- formControlName="flow_id"
- [readonly]="editing"/>
+ <input class="form-control"
+ type="text"
+ placeholder="Flow Name..."
+ id="flow_id"
+ name="flow_id"
+ formControlName="flow_id"/>
</div>
</div>
<div class="form-group row">
for="bucket"
i18n>Bucket Name</label>
<div class="cd-col-form-input">
- <input
- id="bucket"
- name="bucket"
- class="form-control"
- type="text"
- i18n-placeholder
- placeholder="Bucket Name..."
- formControlName="bucket_name"/>
- <span
- class="invalid-feedback"
- *ngIf="currentFormGroupContext.showError('bucket_name', frm, 'bucketNameNotAllowed')"
- i18n>The bucket with chosen name does not exist.</span>
+ <input id="bucket"
+ name="bucket"
+ class="form-control"
+ type="text"
+ i18n-placeholder
+ placeholder="Bucket Name..."
+ formControlName="bucket_name"/>
+ <span class="invalid-feedback"
+ *ngIf="currentFormGroupContext.showError('bucket_name', frm, 'bucketNameNotAllowed')"
+ i18n>The bucket with chosen name does not exist.</span>
</div>
</div>
<ng-container *ngIf="groupType == flowType.symmetrical; else directionalFlow">
<div class="form-group row">
- <label
- class="cd-col-form-label required"
- for="zones">
+ <label class="cd-col-form-label required"
+ for="zones">
<ng-container i18n>Zones</ng-container>
<cd-helper>
<span i18n>Flow need to be associated with atleast one zone</span>
</ng-container>
<ng-template #directionalFlow>
<div class="form-group row">
- <label
- class="cd-col-form-label required"
- for="source_zone"
- i18n>Source Zone
+ <label class="cd-col-form-label required"
+ for="source_zone"
+ i18n>Source Zone
</label>
<div class="cd-col-form-input">
<ng-container *ngTemplateOutlet="zoneMultiSelect;context: { name: 'source_zone', zone: sourceZones }"></ng-container>
</div>
</div>
<div class="form-group row">
- <label
- class="cd-col-form-label required"
- for="destination_zone"
- i18n>Destination Zone</label>
+ <label class="cd-col-form-label required"
+ for="destination_zone"
+ i18n>Destination Zone</label>
<div class="cd-col-form-input">
<ng-container *ngTemplateOutlet="zoneMultiSelect;context: { name: 'destination_zone', zone: destinationZones }"></ng-container>
</div>
</ng-template>
</div>
<div class="modal-footer">
- <cd-form-button-panel
- (submitActionEvent)="submit()"
- [form]="currentFormGroupContext"
- [submitText]="(action | titlecase) + ' ' + (groupType | upperFirst) + ' ' + 'Flow'"></cd-form-button-panel>
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="currentFormGroupContext"
+ [submitText]="(action | titlecase) + ' ' + (groupType | upperFirst) + ' ' + 'Flow'"></cd-form-button-panel>
</div>
</form>
</ng-container>
</cd-modal>
-<ng-template
- #zoneMultiSelect
- let-name="name"
- let-zone="zone">
- <cd-select-badges
- [id]="name"
- [name]="name"
- [customBadges]="zone.customBadges"
- [customBadgeValidators]="zone.data.validators"
- [messages]="zone.data.messages"
- [data]="zone.data.selected"
- [options]="zone.data.available"
- (selection)="zoneSelection()">
+<ng-template #zoneMultiSelect
+ let-name="name"
+ let-zone="zone">
+ <cd-select-badges [id]="name"
+ [name]="name"
+ [customBadges]="zone.customBadges"
+ [customBadgeValidators]="zone.data.validators"
+ [messages]="zone.data.messages"
+ [data]="zone.data.selected"
+ [options]="zone.data.available"
+ (selection)="zoneSelection()">
</cd-select-badges>
- <i
- *ngIf="zone.data.selected.length <= 0"
- i18n-title
- title="Flow should be associated with {{name?.split('_')}}"
- class="{{ icons.warning }} icon-warning-color">
+ <i *ngIf="zone.data.selected.length <= 0"
+ i18n-title
+ title="Flow should be associated with {{name?.split('_').join(' ')}}"
+ class="{{ icons.warning }} icon-warning-color">
</i>
- <span
- class="invalid-feedback"
- *ngIf="currentFormGroupContext.showError(name, frm, 'required')"
- i18n>{{name?.split('_')}} selection is required!
+ <span class="invalid-feedback"
+ *ngIf="currentFormGroupContext.showError(name, frm, 'required')"
+ i18n>{{name?.split('_').join(' ')}} selection is required!
</span>
</ng-template>
flow_id: this.flowSelectedRow.id,
bucket_name: this.groupExpandedRow.bucket || ''
});
+ this.currentFormGroupContext.get('flow_id').disable();
}
this.rgwDaemonService.selectedDaemon$
<cd-modal [modalRef]="activeModal">
- <ng-container
- i18n="form title"
- class="modal-title">{{ action | titlecase }} Pipe</ng-container>
+ <ng-container i18n="form title"
+ class="modal-title">{{ action | titlecase }} Pipe</ng-container>
<ng-container class="modal-content">
- <form
- name="pipeForm"
- #frm="ngForm"
- [formGroup]="pipeForm"
- novalidate>
+ <form name="pipeForm"
+ #frm="ngForm"
+ [formGroup]="pipeForm"
+ novalidate>
<div class="modal-body">
<div class="form-group row">
- <label
- class="cd-col-form-label required"
- for="pipe_id"
- i18n>Name</label>
+ <label class="cd-col-form-label required"
+ for="pipe_id"
+ i18n>Name</label>
<div class="cd-col-form-input">
- <input
- class="form-control"
- type="text"
- placeholder="Pipe Name..."
- id="pipe_id"
- name="pipe_id"
- formControlName="pipe_id"
- [readonly]="editing"/>
- </div>
+ <input class="form-control"
+ type="text"
+ placeholder="Pipe Name..."
+ id="pipe_id"
+ name="pipe_id"
+ formControlName="pipe_id"
+ [readonly]="editing"/>
</div>
+ </div>
<div class="form-group row">
- <label
- class="cd-col-form-label required"
- for="source_zone"
- i18n>Source Zone </label>
+ <label class="cd-col-form-label required"
+ for="source_zone"
+ i18n>Source Zone </label>
<div class="cd-col-form-input">
<ng-container *ngTemplateOutlet="zoneMultiSelect;context: { name: 'source_zones', zone: sourceZones }"></ng-container>
</div>
</div>
<div class="form-group row">
- <label
- class="cd-col-form-label required"
- for="destination_zone"
- i18n>Destination Zone</label>
+ <label class="cd-col-form-label required"
+ for="destination_zone"
+ i18n>Destination Zone</label>
<div class="cd-col-form-input">
<ng-container *ngTemplateOutlet="zoneMultiSelect;context: { name: 'destination_zones', zone: destZones }"></ng-container>
</div>
</div>
<div class="form-group row">
- <label
- class="cd-col-form-label"
- for="bucket"
- i18n>Bucket Name</label>
+ <label class="cd-col-form-label"
+ for="bucket"
+ i18n>Bucket Name</label>
<div class="cd-col-form-input">
- <input
- id="bucket"
- name="bucket"
- class="form-control"
- type="text"
- i18n-placeholder
- placeholder="Bucket Name..."
- formControlName="bucket_name"/>
+ <input id="bucket"
+ name="bucket"
+ class="form-control"
+ type="text"
+ i18n-placeholder
+ placeholder="Bucket Name..."
+ formControlName="bucket_name"/>
</div>
</div>
<div class="form-group row">
- <label
- class="cd-col-form-label"
- for="source_bucket"
- i18n>Source Bucket</label>
+ <label class="cd-col-form-label"
+ for="source_bucket"
+ i18n>Source Bucket</label>
<div class="cd-col-form-input">
- <input
- id="source_bucket"
- name="source_bucket"
- class="form-control"
- type="text"
- i18n-placeholder
- placeholder="Source Bucket Name..."
- formControlName="source_bucket"/>
+ <input id="source_bucket"
+ name="source_bucket"
+ class="form-control"
+ type="text"
+ i18n-placeholder
+ placeholder="Source Bucket Name..."
+ formControlName="source_bucket"/>
</div>
</div>
<div class="form-group row">
- <label
- class="cd-col-form-label"
- for="dest_bucket"
- i18n>Destination Bucket</label>
+ <label class="cd-col-form-label"
+ for="dest_bucket"
+ i18n>Destination Bucket</label>
<div class="cd-col-form-input">
- <input
- id="dest_bucket"
- name="dest_bucket"
- class="form-control"
- type="text"
- i18n-placeholder
- placeholder="Destination Bucket Name..."
- formControlName="destination_bucket"/>
+ <input id="dest_bucket"
+ name="dest_bucket"
+ class="form-control"
+ type="text"
+ i18n-placeholder
+ placeholder="Destination Bucket Name..."
+ formControlName="destination_bucket"/>
</div>
</div>
</div>
<div class="modal-footer">
- <cd-form-button-panel
- (submitActionEvent)="submit()"
- [form]="pipeForm"
- [submitText]="(action | titlecase) + ' ' + 'Pipe'">
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="pipeForm"
+ [submitText]="(action | titlecase) + ' ' + 'Pipe'">
</cd-form-button-panel>
</div>
</form>
</ng-container>
</cd-modal>
-<ng-template
- #zoneMultiSelect
- let-name="name"
- let-zone="zone">
- <cd-select-badges
- id="{{ name }}"
- name="{{ name }}"
- [customBadges]="zone.customBadges"
- [customBadgeValidators]="zone.data.validators"
- [messages]="zone.data.messages"
- [data]="zone.data.selected"
- [options]="zone.data.available"
- (selection)="onZoneSelection(name)">
+<ng-template #zoneMultiSelect
+ let-name="name"
+ let-zone="zone">
+ <cd-select-badges id="{{ name }}"
+ name="{{ name }}"
+ [customBadges]="zone.customBadges"
+ [customBadgeValidators]="zone.data.validators"
+ [messages]="zone.data.messages"
+ [data]="zone.data.selected"
+ [options]="zone.data.available"
+ (selection)="onZoneSelection(name)">
</cd-select-badges>
- <i
- *ngIf="zone.data.selected.length <= 0"
- i18n-title
- title="Pipe should be associated with {{ name }}"
- class="{{ icons.warning }} icon-warning-color">
+ <i *ngIf="zone.data.selected.length <= 0"
+ i18n-title
+ title="Pipe should be associated with {{ name?.split('_').join(' ') }}"
+ class="{{ icons.warning }} icon-warning-color">
</i>
- <span
- class="invalid-feedback"
- *ngIf="pipeForm.showError(name, frm, 'required')"
- i18n>{{ name }} selection is required!
+ <span class="invalid-feedback"
+ *ngIf="pipeForm.showError(name, frm, 'required')"
+ i18n>{{ name?.split('_').join(' ') }} selection is required!
</span>
</ng-template>
});
this.sourceZones.data.available = [...zones];
if (this.editing) {
+ this.pipeForm.get('pipe_id').disable();
this.sourceZones.data.selected = this.pipeSelectedRow.source.zones;
this.destZones.data.selected = this.pipeSelectedRow.dest.zones;
this.pipeForm.patchValue({
-<div class="cd-col-form">
- <form
- name="bucketForm"
- #frm="ngForm"
- [formGroup]="syncPolicyForm"
- *cdFormLoading="loading"
- novalidate>
- <div class="card">
- <div
- i18n="form title"
- class="card-header">
- {{ action | titlecase }} {{ resource | upperFirst }}
- </div>
-
- <div class="card-body">
+<cd-modal [pageURL]="pageURL">
+ <span class="modal-title"
+ i18n>{{ action | titlecase }} {{ resource | upperFirst }}</span>
+ <ng-container class="modal-content">
+ <form
+ #frm="ngForm"
+ [formGroup]="syncPolicyForm"
+ *cdFormLoading="loading"
+ novalidate>
+ <div class="modal-body">
<!-- Group Id -->
<div class="form-group row">
<label
class="cd-col-form-label required"
for="group_id"
- i18n>Group Id</label>
+ i18n>Group Name</label>
<div class="cd-col-form-input">
<input
id="group_id"
class="form-control"
type="text"
i18n-placeholder
- placeholder="Group Id..."
+ placeholder="Group Name..."
formControlName="group_id"
[readonly]="editing"/>
<span
i18n>This field is required.</span>
</div>
</div>
-
<!-- Status -->
<div class="form-group row">
<label
i18n>This field is required.</span>
</div>
</div>
-
<!-- Bucket Name -->
<div class="form-group row">
<label
i18n-placeholder
placeholder="Bucket Name..."
formControlName="bucket_name"
- [readonly]="editing"
[ngbTypeahead]="bucketDataSource"/>
<span
class="invalid-feedback"
</div>
</div>
- <div class="card-footer">
- <cd-form-button-panel
- (submitActionEvent)="submit()"
- [form]="syncPolicyForm"
- [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"
- wrappingClass="text-right"></cd-form-button-panel>
+ <div class="modal-footer">
+ <div class="text-right">
+ <cd-form-button-panel (submitActionEvent)="submit()"
+ [form]="syncPolicyForm"
+ [submitText]="(action | titlecase) + ' ' + (resource | upperFirst)"></cd-form-button-panel>
+ </div>
</div>
- </div>
- </form>
-</div>
+ </form>
+ </ng-container>
+</cd-modal>
} from 'rxjs/operators';
import { RgwBucketService } from '~/app/shared/api/rgw-bucket.service';
import { RgwMultisiteService } from '~/app/shared/api/rgw-multisite.service';
-import { ActionLabelsI18n, URLVerbs } from '~/app/shared/constants/app.constants';
+import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
import { NotificationType } from '~/app/shared/enum/notification-type.enum';
import { CdFormBuilder } from '~/app/shared/forms/cd-form-builder';
import { CdFormGroup } from '~/app/shared/forms/cd-form-group';
action: string;
resource: string;
syncPolicyStatus = RgwMultisiteSyncPolicyStatus;
-
+ pageURL: string;
bucketDataSource = (text$: Observable<string>) => {
return text$.pipe(
debounceTime(200),
private rgwBucketService: RgwBucketService
) {
super();
- this.editing = this.router.url.startsWith(`/rgw/multisite/sync-policy/${URLVerbs.EDIT}`);
+ this.editing = this.router.url.includes('(modal:edit');
this.action = this.editing ? this.actionLabels.EDIT : this.actionLabels.CREATE;
this.resource = $localize`Sync Policy Group`;
this.createForm();
this.loadingReady();
+ this.pageURL = 'rgw/multisite/sync-policy';
}
ngOnInit(): void {
.subscribe((syncPolicy: any) => {
this.loadingReady();
if (syncPolicy) {
+ this.syncPolicyForm.get('bucket_name').disable();
this.syncPolicyForm.patchValue({
group_id: syncPolicy.id,
status: syncPolicy.status,
}
}
+ goToListView() {
+ // passing state in order to return to same tab on details page
+ this.router.navigate([this.pageURL, { outlets: { modal: null }, state: { reload: true } }]);
+ }
+
createForm() {
this.syncPolicyForm = this.fb.group({
group_id: ['', Validators.required],
});
}
- goToListView() {
- // passing state in order to return to same tab on details page
- this.router.navigate(['/rgw/multisite'], { state: { activeId: 'syncPolicy' } });
- }
-
submit() {
if (this.syncPolicyForm.pristine) {
this.goToListView();
if (!this.editing) {
// Add
- this.rgwMultisiteService.createSyncPolicyGroup(this.syncPolicyForm.value).subscribe(
+ this.rgwMultisiteService.createSyncPolicyGroup(this.syncPolicyForm.getRawValue()).subscribe(
() => {
this.notificationService.show(
NotificationType.success,
}
);
} else {
- this.rgwMultisiteService.modifySyncPolicyGroup(this.syncPolicyForm.value).subscribe(
+ this.rgwMultisiteService.modifySyncPolicyGroup(this.syncPolicyForm.getRawValue()).subscribe(
() => {
this.notificationService.show(
NotificationType.success,
+<cd-rgw-multisite-tabs></cd-rgw-multisite-tabs>
+
<legend i18n>
Multisite Sync Policy
<cd-help-text>
Are you sure you want to delete these policy groups?
</cd-alert-panel>
</ng-template>
+<router-outlet name="modal"
+ (deactivate)="getPolicyList()"></router-outlet>
import { TitleCasePipe } from '@angular/common';
import { Component, OnInit, TemplateRef, ViewChild } from '@angular/core';
+import { Router } from '@angular/router';
import { forkJoin as observableForkJoin, Observable, Subscriber } from 'rxjs';
+import { RgwDaemonService } from '~/app/shared/api/rgw-daemon.service';
import { RgwMultisiteService } from '~/app/shared/api/rgw-multisite.service';
import { ListWithDetails } from '~/app/shared/classes/list-with-details.class';
import { CriticalConfirmationModalComponent } from '~/app/shared/components/critical-confirmation-modal/critical-confirmation-modal.component';
-import { ActionLabelsI18n } from '~/app/shared/constants/app.constants';
+import { ActionLabelsI18n, URLVerbs } from '~/app/shared/constants/app.constants';
import { TableComponent } from '~/app/shared/datatable/table/table.component';
import { CellTemplate } from '~/app/shared/enum/cell-template.enum';
import { Icons } from '~/app/shared/enum/icons.enum';
private rgwMultisiteService: RgwMultisiteService,
private titleCasePipe: TitleCasePipe,
private actionLabels: ActionLabelsI18n,
- private urlBuilder: URLBuilderService,
private authStorageService: AuthStorageService,
private modalService: ModalService,
- private taskWrapper: TaskWrapperService
+ private taskWrapper: TaskWrapperService,
+ private router: Router,
+ private rgwDaemonService: RgwDaemonService
) {
super();
}
flexGrow: 1
}
];
- const getSyncGroupName = () => {
- if (this.selection.first() && this.selection.first().groupName) {
- if (this.selection.first().bucket) {
- return `${encodeURIComponent(this.selection.first().groupName)}/${encodeURIComponent(
- this.selection.first().bucket
- )}`;
- }
- return `${encodeURIComponent(this.selection.first().groupName)}`;
+ this.rgwDaemonService.list().subscribe();
+ const getEditURL = () => {
+ if (this.selection.first().groupName && this.selection.first().bucket) {
+ return `${URLVerbs.EDIT}/${this.selection.first().groupName}/${
+ this.selection.first().bucket
+ }`;
}
- return '';
+ return `${URLVerbs.EDIT}/${this.selection.first().groupName}`;
};
const addAction: CdTableAction = {
permission: 'create',
icon: Icons.add,
- routerLink: () => this.urlBuilder.getCreate(),
+ click: () => this.router.navigate([BASE_URL, { outlets: { modal: URLVerbs.CREATE } }]),
name: this.actionLabels.CREATE,
canBePrimary: (selection: CdTableSelection) => !selection.hasSelection
};
const editAction: CdTableAction = {
permission: 'update',
icon: Icons.edit,
- routerLink: () => this.urlBuilder.getEdit(getSyncGroupName()),
+ click: () => this.router.navigate([BASE_URL, { outlets: { modal: getEditURL() } }]),
name: this.actionLabels.EDIT
};
const deleteAction: CdTableAction = {
this.selection = selection;
}
- getPolicyList(context: CdTableFetchDataContext) {
+ getPolicyList(context?: CdTableFetchDataContext) {
this.rgwMultisiteService.getSyncPolicy('', '', true).subscribe(
(resp: object[]) => {
this.syncPolicyData = [];
this.transformSyncPolicyData(resp);
},
() => {
- context.error();
+ if (context) {
+ context.error();
+ }
}
);
}
--- /dev/null
+<ul class="nav nav-tabs">
+ <li class="nav-item">
+ <a class="nav-link"
+ routerLink="/rgw/multisite/configuration"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ i18n>Configuration</a>
+ </li>
+ <li class="nav-item">
+ <a class="nav-link"
+ routerLink="//rgw/multisite/sync-policy"
+ routerLinkActive="active"
+ ariaCurrentWhenActive="page"
+ i18n>Sync Policy</a>
+ </li>
+</ul>
--- /dev/null
+import { ComponentFixture, TestBed } from '@angular/core/testing';
+
+import { RgwMultisiteTabsComponent } from './rgw-multisite-tabs.component';
+
+describe('RgwMultisiteTabsComponent', () => {
+ let component: RgwMultisiteTabsComponent;
+ let fixture: ComponentFixture<RgwMultisiteTabsComponent>;
+
+ beforeEach(async () => {
+ await TestBed.configureTestingModule({
+ declarations: [RgwMultisiteTabsComponent]
+ }).compileComponents();
+
+ fixture = TestBed.createComponent(RgwMultisiteTabsComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+});
--- /dev/null
+import { Component } from '@angular/core';
+
+@Component({
+ selector: 'cd-rgw-multisite-tabs',
+ templateUrl: './rgw-multisite-tabs.component.html',
+ styleUrls: ['./rgw-multisite-tabs.component.scss']
+})
+export class RgwMultisiteTabsComponent {}
import { RgwMultisiteSyncPolicyDetailsComponent } from './rgw-multisite-sync-policy-details/rgw-multisite-sync-policy-details.component';
import { RgwMultisiteSyncFlowModalComponent } from './rgw-multisite-sync-flow-modal/rgw-multisite-sync-flow-modal.component';
import { RgwMultisiteSyncPipeModalComponent } from './rgw-multisite-sync-pipe-modal/rgw-multisite-sync-pipe-modal.component';
+import { RgwMultisiteTabsComponent } from './rgw-multisite-tabs/rgw-multisite-tabs.component';
@NgModule({
imports: [
RgwMultisiteSyncPolicyFormComponent,
RgwMultisiteSyncPolicyDetailsComponent,
RgwMultisiteSyncFlowModalComponent,
- RgwMultisiteSyncPipeModalComponent
+ RgwMultisiteSyncPipeModalComponent,
+ RgwMultisiteTabsComponent
],
providers: [TitleCasePipe]
})
path: 'multisite',
data: { breadcrumbs: 'Multi-site' },
children: [
- { path: '', component: RgwMultisiteDetailsComponent },
+ { path: '', redirectTo: 'configuration', pathMatch: 'full' },
{
- path: `sync-policy/${URLVerbs.CREATE}`,
- component: RgwMultisiteSyncPolicyFormComponent,
- data: { breadcrumbs: `${ActionLabels.CREATE} Sync Policy` }
+ path: 'configuration',
+ component: RgwMultisiteDetailsComponent
},
{
- path: `sync-policy/${URLVerbs.EDIT}/:groupName`,
- component: RgwMultisiteSyncPolicyFormComponent,
- data: { breadcrumbs: `${ActionLabels.EDIT} Sync Policy` }
- },
- {
- path: `sync-policy/${URLVerbs.EDIT}/:groupName/:bucketName`,
- component: RgwMultisiteSyncPolicyFormComponent,
- data: { breadcrumbs: `${ActionLabels.EDIT} Sync Policy` }
+ path: 'sync-policy',
+ component: RgwMultisiteSyncPolicyComponent,
+ children: [
+ {
+ path: `${URLVerbs.CREATE}`,
+ component: RgwMultisiteSyncPolicyFormComponent,
+ outlet: 'modal'
+ },
+ {
+ path: `${URLVerbs.EDIT}/:groupName`,
+ component: RgwMultisiteSyncPolicyFormComponent,
+ outlet: 'modal'
+ },
+ {
+ path: `${URLVerbs.EDIT}/:groupName/:bucketName`,
+ component: RgwMultisiteSyncPolicyFormComponent,
+ outlet: 'modal'
+ }
+ ]
}
]
},