Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added search bar for Data Bags list page #5069

Merged
merged 3 commits into from
May 18, 2021
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
}
233 changes: 233 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,233 @@
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`;
const adminKey = 'Dummy--admin--key';

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);
});
});
});
});
});