Skip to content

Commit

Permalink
Added search bar for Data Bags list page (#5069)
Browse files Browse the repository at this point in the history
* Added UI and functionality for search bar

Signed-off-by: chaitali-mane <[email protected]>

* added cypress tests for data bag list page

Signed-off-by: chaitali-mane <[email protected]>

* removed commented line

Signed-off-by: chaitali-mane <[email protected]>
  • Loading branch information
chaitali-mane authored May 18, 2021
1 parent 60923ec commit 543faee
Show file tree
Hide file tree
Showing 5 changed files with 308 additions and 16 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ <h2 slot="title">Create Data Bag</h2>
<chef-form-field>
<label>
<span class="label">Name</span>
<input chefInput firstFocus formControlName="name" type="text" id="name-input" (keyup)="handleInput($event)" autocomplete="off"/>
<input chefInput firstFocus formControlName="name" type="text" id="name-input"
data-cy="databag-name" (keyup)="handleInput($event)" autocomplete="off"/>
</label>
<chef-error
*ngIf="createForm.get('name').hasError('required') && createForm.get('name').dirty">
Expand All @@ -23,8 +24,10 @@ <h2 slot="title">Create Data Bag</h2>
</div>

<div id="button-bar">
<chef-button tertiary id="cancel-data-bag-popup" (click)="closeCreateModal()">Cancel</chef-button>
<chef-button [disabled]="!createForm?.valid || creating || conflictError" primary id="create-button-object-modal" (click)="createDataBag()">
<chef-button tertiary id="cancel-data-bag-popup" data-cy="cancel-button"
(click)="closeCreateModal()">Cancel</chef-button>
<chef-button [disabled]="!createForm?.valid || creating || conflictError" primary
id="create-button-object-modal" data-cy="add-button" (click)="createDataBag()">
<chef-loading-spinner *ngIf="creating"></chef-loading-spinner>
<span *ngIf="!creating">Create</span>
<span *ngIf="creating">Creating Data Bag...</span>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,20 +15,21 @@
[org_Id]="orgId">
</app-create-data-bag-modal>
<app-empty-state *ngIf="authFailure" moduleTitle="data bags" (resetKeyRedirection)="resetKeyTabRedirection($event)"></app-empty-state>
<ng-container *ngIf="!dataBagsListLoading && !authFailure">
<chef-toolbar>
<app-authorized [allOf]="['/api/v0/infra/servers', 'post']">
<chef-button primary (click)="openCreateModal()">Create Data Bag</chef-button>
</app-authorized>
</chef-toolbar>
<chef-table *ngIf="dataBags.length">
<chef-thead>
<ng-container *ngIf="!dataBagsListLoading && !authFailure">
<div class="search-create-container">
<app-infra-search-bar (searchButtonClick)="searchDataBags($event)" placeHolder="data bags">
</app-infra-search-bar>
<chef-button data-cy="create-databag-button" primary (click)="openCreateModal()">Create Data Bag</chef-button>
</div>
<chef-loading-spinner class="full-screen-spinner" *ngIf="searching" size="50" fixed></chef-loading-spinner>
<chef-table *ngIf="dataBags.length" id="databags-table-container" data-cy="databags-table-container">
<chef-thead *ngIf="!searchFlag || serachArr.length">
<chef-tr class="no_border_tr">
<chef-th class="no_border_th">Name</chef-th>
<chef-th class="no_border_th" data-cy="name">Name</chef-th>
<chef-th class="no_border_th three-dot-column"></chef-th>
</chef-tr>
</chef-thead>
<chef-tbody>
<chef-tbody *ngIf="!searchFlag">
<chef-tr *ngFor="let dataBag of dataBags">
<chef-td><a [routerLink]="['/infrastructure','chef-servers', serverId, 'organizations', orgId, 'data-bags', dataBag.name]">{{ dataBag.name }}</a></chef-td>
<chef-td class="three-dot-column">
Expand All @@ -38,12 +39,23 @@
</chef-td>
</chef-tr>
</chef-tbody>
<chef-tbody *ngIf="searchFlag">
<chef-tr *ngFor="let dataBag of serachArr">
<chef-td><a [routerLink]="['/infrastructure','chef-servers', serverId, 'organizations', orgId, 'data-bags', dataBag.name]">{{ dataBag.name }}</a></chef-td>
<chef-td class="three-dot-column">
<mat-select panelClass="chef-control-menu">
<mat-option data-cy="delete" (onSelectionChange)="startDataBagDelete(dataBag)">Delete</mat-option>
</mat-select>
</chef-td>
</chef-tr>
</chef-tbody>
</chef-table>
</ng-container>
<div *ngIf="!authFailure">
<div class="empty-section" *ngIf="!dataBagsListLoading && (dataBags.length === 0)">
<div data-cy="empty-list" class="empty-section" *ngIf="!dataBagsListLoading && (dataBags.length === 0) || searchFlag && (serachArr.length === 0) ">
<img alt="No preview" src="/assets/img/no_preview.gif"/>
<p>No Data Bags available.</p>
<p *ngIf="searchValue !== ''">No results found for "{{searchValue}}".</p>
<p *ngIf="searchValue === ''">No Data Bags available.</p>
</div>
</div>
</section>
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,6 @@ chef-loading-spinner {

img {
margin-top: 130px;
margin-left: 130PX;
width: 70px;
}

Expand All @@ -25,3 +24,29 @@ chef-toolbar chef-button:first-child {
margin: 10px 0px 0px 0px;
float: right;
}

.search-create-container {
display: flex;
margin: 24px 0 18px;
flex-direction: row;

app-infra-search-bar {
flex-grow: 2;
}

chef-button {
margin: 0;
margin-left: 16px;
height: 36px;
}
}

.full-screen-spinner {
display: flex;
margin: auto;
margin-top: 238px;
background-color: $chef-white;
opacity: 0.7;
width: initial;
height: 100%;
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ export class DataBagsListComponent implements OnInit, OnDestroy {
public dataBagsListLoading = true;
public dataBagToDelete: DataBag;
public deleteModalVisible = false;
public searchValue = '';
public searchFlag = false;
public searching = false;
public serachArr: DataBag[];
public openDataBagModal = new EventEmitter<void>();
private isDestroyed = new Subject<boolean>();

Expand Down Expand Up @@ -99,4 +103,20 @@ export class DataBagsListComponent implements OnInit, OnDestroy {
public openCreateModal(): void {
this.openDataBagModal.emit();
}

public searchDataBags(searchText: string): void {
this.searching = true;
this.searchValue = searchText;
if (!this.dataBags || !searchText) {
this.searchFlag = false;
} else {
this.serachArr = this.dataBags.filter((key) => {
this.searchFlag = true;
if (key) {
return key.name.includes(searchText);
}
});
}
this.searching = false;
}
}
232 changes: 232 additions & 0 deletions e2e/cypress/integration/ui/infra-proxy/infra-databags.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
describe('infra databag', () => {
const now = Cypress.moment().format('MMDDYYhhmmss');
const cypressPrefix = 'infra';
let adminIdToken = '';
const serverID = 'chef-server-dev-test';
const serverName = 'chef server dev';
const orgID = 'chef-org-dev';
const orgName = '4thcoffee';
const serverFQDN = 'ec2-34-219-25-251.us-west-2.compute.amazonaws.com';
const serverIP = '34.219.25.251';
const adminUser = 'chefadmin';
const adminKey = Cypress.env('AUTOMATE_INFRA_ADMIN_KEY').replace(/\\n/g, '\n');
const databagName = `${cypressPrefix}-databag-${now}-1`;

before(() => {
cy.adminLogin('/').then(() => {
const admin = JSON.parse(<string>localStorage.getItem('chef-automate-user'));
adminIdToken = admin.id_token;

cy.request({
auth: { bearer: adminIdToken },
failOnStatusCode: false,
method: 'POST',
url: '/api/v0/infra/servers',
body: {
id: serverID,
name: serverName,
fqdn: serverFQDN,
ip_address: serverIP
}
}).then((resp) => {
if (resp.status === 200 && resp.body.ok === true) {
return;
} else {
cy.request({
auth: { bearer: adminIdToken },
method: 'GET',
url: `/api/v0/infra/servers/${serverID}`,
body: {
id: serverID
}
});
}
});

cy.request({
auth: { bearer: adminIdToken },
failOnStatusCode: false,
method: 'POST',
url: `/api/v0/infra/servers/${serverID}/orgs`,
body: {
id: orgID,
server_id: serverID,
name: orgName,
admin_user: adminUser,
admin_key: adminKey
}
}).then((response) => {
if (response.status === 200 && response.body.ok === true) {
return;
} else {
cy.request({
auth: { bearer: adminIdToken },
method: 'GET',
url: `/api/v0/infra/servers/${serverID}/orgs/${orgID}`,
body: {
id: orgID,
server_id: serverID
}
});
}
});
cy.visit(`/infrastructure/chef-servers/${serverID}/organizations/${orgID}`);
cy.get('app-welcome-modal').invoke('hide');
});
cy.restoreStorage();
});

beforeEach(() => {
cy.restoreStorage();
});

afterEach(() => {
cy.saveStorage();
});

function getDatabag() {
return cy.request({
auth: { bearer: adminIdToken },
failOnStatusCode: false,
method: 'GET',
url: `/api/v0/infra/servers/${serverID}/orgs/${orgID}/databags`
});
}

function checkResponse(response: any) {
if (response.body.data_bags === 0) {
cy.get('[data-cy=empty-list]').should('be.visible');
} else {
cy.get('[data-cy=create-databag-button]').contains('Create Data Bag');
cy.get('[data-cy=databags-table-container] chef-th').contains('Name');
return true;
}
}

describe('infra databags list page', () => {
it('displays org details', () => {
cy.get('.page-title').contains(orgName);
});

// databags tabs specs
it('can switch to databags tab', () => {
cy.get('.nav-tab').contains('Data Bags').click();
});

it('can check if databag has list or not', () => {
getDatabag().then((response) => {
checkResponse(response);
});
});

context('can search and change page in dataBag', () => {
it('can search a DataBag and check if empty or not', () => {
cy.get('[data-cy=search-filter]').type(databagName);
cy.get('[data-cy=search-entity]').click();
cy.get('[data-cy=databags-table-container]').then(body => {
if (body.text().includes(databagName)) {
cy.get('[data-cy=databags-table-container] [data-cy=select-run-list]')
.contains(databagName).should('exist');
}
});
cy.get('[data-cy=search-filter]').clear();
cy.get('[data-cy=search-entity]').click();
getDatabag().then((response) => {
checkResponse(response);
});
});
});

// In create databag pop-up details tab specs
context('can create databag with details tab', () => {
it('can add name and create databag', () => {
cy.get('[data-cy=create-databag-button]').contains('Create Data Bag').click();
cy.get('app-data-bags-list chef-modal').should('exist');
cy.get('[data-cy=databag-name]').type(databagName);

cy.get('[data-cy=add-button]').click();
cy.get('app-data-bags-list chef-modal').should('not.be.visible');

// verify success notification and then dismiss it
// so it doesn't get in the way of subsequent interactions
cy.get('app-notification.info').should('be.visible');
cy.get('app-notification.info chef-icon').click();
});

it('fails to create a databag with a duplicate name', () => {
cy.get('[data-cy=create-databag-button]').contains('Create Data Bag').click();
cy.get('app-data-bags-list chef-modal').should('exist');
cy.get('[data-cy=databag-name]').type(databagName);

cy.get('[data-cy=add-button]').click();
cy.get('app-data-bags-list chef-modal chef-error').contains('already exists')
.should('be.visible');

cy.get('[data-cy=cancel-button]').contains('Cancel').should('be.visible').click();
cy.get('app-data-bags-list chef-modal').should('not.be.visible');
});

it('can cancel creating a databag', () => {
cy.get('[data-cy=create-databag-button]').contains('Create Data Bag').click();
cy.get('app-data-bags-list chef-modal').should('exist');
cy.get('[data-cy=databag-name]').type(databagName);

// here we exit with the Cancel button
cy.get('[data-cy=cancel-button]').contains('Cancel').should('be.visible').click();
cy.get('app-data-bags-list chef-modal').should('not.be.visible');
});

it('can check create databag button is disabled until all inputs are filled in', () => {
cy.get('[data-cy=create-databag-button]').contains('Create Data Bag').click();
cy.get('app-data-bags-list chef-modal').should('exist');
cy.get('[data-cy=databag-name]').clear();

// check for disabled
cy.get('[data-cy=add-button]')
.invoke('attr', 'disabled')
.then(disabled => {
disabled ? cy.log('buttonIsDiabled') : cy.get('[data-cy=add-button]').click();
});

cy.get('app-data-bags-list chef-modal').should('exist');

// here we exit with the Cancel button
cy.get('[data-cy=cancel-button]').contains('Cancel').should('be.visible').click();
cy.get('app-data-bags-list chef-modal').should('not.be.visible');
});
});

// delete databag spec
context('can delete databags', () => {
it('can delete multiple databags', () => {
cy.get('[data-cy=search-filter]').type(`${cypressPrefix}-databag-${now}`);
cy.get('[data-cy=search-entity]').click();

cy.get('[data-cy=databags-table-container]').contains(databagName).should('exist');
cy.get('app-data-bags-list [data-cy=databags-table-container] chef-td a')
.contains(databagName).parent().parent().find('.mat-select-trigger').click();
// we throw in a `should` so cypress retries until introspection allows
// menu to be shown

cy.get('[data-cy=delete]').should('be.visible')
.click();
// accept dialog
cy.get('app-data-bags-list chef-button').contains('Delete').click();
// verify success notification and then dismiss it
cy.get('app-notification.info')
.contains(`Successfully deleted data bag - ${databagName}.`);
cy.get('app-notification.info chef-icon').click();

getDatabag().then((response) => {
checkResponse(response);
});

cy.get('[data-cy=search-filter]').clear();
cy.get('[data-cy=search-entity]').click();
getDatabag().then((response) => {
checkResponse(response);
});
});
});
});
});

0 comments on commit 543faee

Please sign in to comment.