Skip to content

Commit

Permalink
Data bag details UI improvements changes with search box (#4675)
Browse files Browse the repository at this point in the history
* added UI changes for the accordion

Signed-off-by: Vinay Sharma <[email protected]>

* added search bar for the data bag items

Signed-off-by: Vinay Sharma <[email protected]>

* changes for the API integrations

Signed-off-by: Vinay Sharma <[email protected]>

* added changes for the spinner

Signed-off-by: Vinay Sharma <[email protected]>

* fixed build issue

Signed-off-by: Vinay Sharma <[email protected]>

* added some minor changes

Signed-off-by: Vinay Sharma <[email protected]>

* added changes for the new preview available

Signed-off-by: Vinay Sharma <[email protected]>

* added changes for the build issue

Signed-off-by: Vinay Sharma <[email protected]>

* change the less no preview gif

Signed-off-by: Vinay Sharma <[email protected]>

* fix the size of no preview image

Signed-off-by: Vinay Sharma <[email protected]>

* added some changes for the API request

Signed-off-by: Vinay Sharma <[email protected]>

* added some changes for the load search result

Signed-off-by: Vinay Sharma <[email protected]>

* added changes for empty list without search

Signed-off-by: Vinay Sharma <[email protected]>

* added some minor changes

Signed-off-by: Vinay Sharma <[email protected]>

* added changes for the entities

Signed-off-by: Vinay Sharma <[email protected]>

* added chanegs for the data bag items pagination

Signed-off-by: Vinay Sharma <[email protected]>

* added chanegs for the loading spinner

Signed-off-by: Vinay Sharma <[email protected]>

* added some minor changes

Signed-off-by: Vinay Sharma <[email protected]>

* added some changes for lint

Signed-off-by: Vinay Sharma <[email protected]>
  • Loading branch information
vinay033 authored Feb 17, 2021
1 parent 8648d2b commit 3d2587b
Show file tree
Hide file tree
Showing 19 changed files with 518 additions and 172 deletions.
Original file line number Diff line number Diff line change
@@ -1,33 +1,43 @@
import { HttpErrorResponse } from '@angular/common/http';
import { Action } from '@ngrx/store';
import { DataBags } from './data-bags.model';
import { DataBagItems } from './data-bags.model';

export enum DataBagDetailsActionTypes {
GET_ALL = 'DATA_BAG_DETAILS::GET_ALL',
GET_ALL_SUCCESS = 'DATA_BAG_DETAILS::GET_ALL::SUCCESS',
GET_ALL_FAILURE = 'DATA_BAG_DETAILS::GET_ALL::FAILURE'
export enum DataBagItemsActionTypes {
GET_ALL = 'DATA_BAG_ITEMS::GET_ALL',
GET_ALL_SUCCESS = 'DATA_BAG_ITEMS::GET_ALL::SUCCESS',
GET_ALL_FAILURE = 'DATA_BAG_ITEMS::GET_ALL::FAILURE'
}

export interface DataBagDetailsSuccessPayload {
data_bags: DataBags[];
export interface DataBagItemsSuccessPayload {
items: DataBagItems[];
total: number;
}

export class GetDataBagDetails implements Action {
readonly type = DataBagDetailsActionTypes.GET_ALL;
constructor(public payload: { server_id: string, org_id: string, name: string }) { }
export interface DataBagItemPayload {
databagName: string;
server_id: string;
org_id: string;
name: string;
page: number;
per_page: number;
}

export class GetDataBagDetailsSuccess implements Action {
readonly type = DataBagDetailsActionTypes.GET_ALL_SUCCESS;
constructor(public payload: DataBagDetailsSuccessPayload) { }
export class GetDataBagItems implements Action {
readonly type = DataBagItemsActionTypes.GET_ALL;
constructor(public payload: DataBagItemPayload) { }
}

export class GetDataBagDetailsFailure implements Action {
readonly type = DataBagDetailsActionTypes.GET_ALL_FAILURE;
export class GetDataBagItemsSuccess implements Action {
readonly type = DataBagItemsActionTypes.GET_ALL_SUCCESS;
constructor(public payload: DataBagItemsSuccessPayload) { }
}

export class GetDataBagItemsFailure implements Action {
readonly type = DataBagItemsActionTypes.GET_ALL_FAILURE;
constructor(public payload: HttpErrorResponse) { }
}

export type DataBagDetailsActions =
| GetDataBagDetails
| GetDataBagDetailsSuccess
| GetDataBagDetailsFailure;
export type DataBagItemsActions =
| GetDataBagItems
| GetDataBagItemsSuccess
| GetDataBagItemsFailure;
Original file line number Diff line number Diff line change
Expand Up @@ -7,40 +7,40 @@ import { CreateNotification } from 'app/entities/notifications/notification.acti
import { Type } from 'app/entities/notifications/notification.model';

import {
GetDataBagDetails,
GetDataBagDetailsSuccess,
GetDataBagDetailsFailure,
DataBagDetailsSuccessPayload,
DataBagDetailsActionTypes
GetDataBagItems,
GetDataBagItemsSuccess,
GetDataBagItemsFailure,
DataBagItemsActionTypes,
DataBagItemsSuccessPayload
} from './data-bag-details.actions';

import { DataBagsRequests } from './data-bags.requests';

@Injectable()
export class DataBagDetailsEffects {
export class DataBagItemsEffects {
constructor(
private actions$: Actions,
private requests: DataBagsRequests
) { }

@Effect()
getDataBagDetails$ = this.actions$.pipe(
ofType(DataBagDetailsActionTypes.GET_ALL),
mergeMap(({ payload: { server_id, org_id, name } }: GetDataBagDetails) =>
this.requests.getDataBagDetails(server_id, org_id, name).pipe(
map((resp: DataBagDetailsSuccessPayload) => new GetDataBagDetailsSuccess(resp)),
catchError((error: HttpErrorResponse) =>
observableOf(new GetDataBagDetailsFailure(error))))));
getDataBagItems$ = this.actions$.pipe(
ofType(DataBagItemsActionTypes.GET_ALL),
mergeMap(( action: GetDataBagItems) =>
this.requests.getDataBagItems(action.payload).pipe(
map((resp: DataBagItemsSuccessPayload) => new GetDataBagItemsSuccess(resp)),
catchError((error: HttpErrorResponse) =>
observableOf(new GetDataBagItemsFailure(error))))));

@Effect()
getDataBagDetailsFailure$ = this.actions$.pipe(
ofType(DataBagDetailsActionTypes.GET_ALL_FAILURE),
map(({ payload }: GetDataBagDetailsFailure) => {
const msg = payload.error.error;
return new CreateNotification({
type: Type.error,
message: `Could not get infra data bag details: ${msg || payload.error}`
});
}));
getDataBagItemsFailure$ = this.actions$.pipe(
ofType(DataBagItemsActionTypes.GET_ALL_FAILURE),
map(({ payload }: GetDataBagItemsFailure) => {
const msg = payload.error.error;
return new CreateNotification({
type: Type.error,
message: `Could not get infra data bag items: ${msg || payload.error}`
});
}));

}
Original file line number Diff line number Diff line change
@@ -1,40 +1,46 @@
import { EntityState, EntityAdapter, createEntityAdapter } from '@ngrx/entity';
import { set, pipe } from 'lodash/fp';
import { EntityStatus } from 'app/entities/entities';
import { DataBagDetailsActionTypes, DataBagDetailsActions } from './data-bag-details.actions';
import { DataBags } from './data-bags.model';
import { DataBagItemsActionTypes, DataBagItemsActions } from './data-bag-details.actions';
import { DataBagItems } from './data-bags.model';

export interface DataBagDetailsEntityState extends EntityState<DataBags> {
export interface DataBagItemsEntityState extends EntityState<DataBagItems> {
getAllStatus: EntityStatus;
dataBagItems: {
items: DataBagItems[],
total: number;
};
}

const GET_ALL_STATUS = 'getAllStatus';

export const dataBagDetailsEntityAdapter: EntityAdapter<DataBags> = createEntityAdapter<DataBags>({
selectId: (dataBags: DataBags) => dataBags.name
export const dataBagItemsEntityAdapter: EntityAdapter<DataBagItems> =
createEntityAdapter<DataBagItems>({
selectId: (dataBagItems: DataBagItems) => dataBagItems.name
});

export const DataBagDetailsEntityInitialState: DataBagDetailsEntityState =
dataBagDetailsEntityAdapter.getInitialState(<DataBagDetailsEntityState>{
export const DataBagItemsEntityInitialState: DataBagItemsEntityState =
dataBagItemsEntityAdapter.getInitialState(<DataBagItemsEntityState>{
getAllStatus: EntityStatus.notLoaded
});

export function dataBagDetailsEntityReducer(
state: DataBagDetailsEntityState = DataBagDetailsEntityInitialState,
action: DataBagDetailsActions): DataBagDetailsEntityState {
export function dataBagItemsEntityReducer(
state: DataBagItemsEntityState = DataBagItemsEntityInitialState,
action: DataBagItemsActions): DataBagItemsEntityState {

switch (action.type) {
case DataBagDetailsActionTypes.GET_ALL:
return set(GET_ALL_STATUS, EntityStatus.loading, dataBagDetailsEntityAdapter
case DataBagItemsActionTypes.GET_ALL:
return set(GET_ALL_STATUS, EntityStatus.loading, dataBagItemsEntityAdapter
.removeAll(state));

case DataBagDetailsActionTypes.GET_ALL_SUCCESS:
case DataBagItemsActionTypes.GET_ALL_SUCCESS:
return pipe(
set(GET_ALL_STATUS, EntityStatus.loadingSuccess))
(dataBagDetailsEntityAdapter
.setAll(action.payload.data_bags, state)) as DataBagDetailsEntityState;
set(GET_ALL_STATUS, EntityStatus.loadingSuccess),
set('dataBagItems.items', action.payload.items || []),
set('dataBagItems.total', action.payload.total || 0)
)(state) as DataBagItemsEntityState;

case DataBagDetailsActionTypes.GET_ALL_FAILURE:
case DataBagItemsActionTypes.GET_ALL_FAILURE:
return set(GET_ALL_STATUS, EntityStatus.loadingFailure, state);

default:
Expand All @@ -43,4 +49,4 @@ export function dataBagDetailsEntityReducer(
}

export const getEntityById = (id: string) =>
(state: DataBagDetailsEntityState) => state.entities[id];
(state: DataBagItemsEntityState) => state.entities[id];
Original file line number Diff line number Diff line change
@@ -1,27 +1,29 @@
import { createSelector, createFeatureSelector } from '@ngrx/store';

import { routeParams } from 'app/route.selectors';
import { find } from 'lodash/fp';

import { DataBagDetailsEntityState, dataBagDetailsEntityAdapter } from './data-bag-details.reducer';
import { DataBagItemsEntityState, dataBagItemsEntityAdapter } from './data-bag-details.reducer';


export const dataBagDetailsState =
createFeatureSelector<DataBagDetailsEntityState>
('dataBagDetails');
export const dataBagItemsState =
createFeatureSelector<DataBagItemsEntityState>('dataBagItems');

export const {
selectAll: allDataBagDetails,
selectEntities: dataBagDetailsEntities
} = dataBagDetailsEntityAdapter.getSelectors(dataBagDetailsState);
selectAll: allDataBagItems,
selectEntities: dataBagItemsEntities
} = dataBagItemsEntityAdapter.getSelectors(dataBagItemsState);

export const getAllStatus = createSelector(
dataBagDetailsState,
dataBagItemsState,
(state) => state.getAllStatus
);

export const dataBagDetailsFromRoute = createSelector(
dataBagDetailsEntities,
export const dataBagItemsFromRoute = createSelector(
dataBagItemsEntities,
routeParams,
(state, { name }) => find({ name }, state)
);

export const dataBagItemList = createSelector(
dataBagItemsState,
(state) => state.dataBagItems
);
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,11 @@ export interface DataBags {
name: string;
}

export interface DataBagItems {
name: string;
active?: boolean;
}

export interface DataBagsItemDetails {
name: string;
id: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,17 @@ import { HttpClient, HttpHeaders } from '@angular/common/http';
import { Observable } from 'rxjs';
import { environment as env } from 'environments/environment';
import { DataBagsSuccessPayload } from './data-bags.actions';
import { DataBagDetailsSuccessPayload } from './data-bag-details.actions';
import { DataBagsItemDetails } from './data-bags.model';
import { DataBagItemPayload } from './data-bag-details.actions';
import { DataBags, DataBagsItemDetails } from './data-bags.model';
import { InterceptorSkipHeader } from 'app/services/http/http-client-auth.interceptor';

const headers = new HttpHeaders().set(InterceptorSkipHeader, '');

export interface DataBagSearchResponse {
items: DataBags[];
total: number;
}

@Injectable()
export class DataBagsRequests {

Expand All @@ -19,12 +24,18 @@ export class DataBagsRequests {
`${env.infra_proxy_url}/servers/${server_id}/orgs/${org_id}/data_bags`, {headers});
}

public getDataBagDetails(server_id: string, org_id: string, name: string)
: Observable<DataBagDetailsSuccessPayload> {
return this.http.get<DataBagDetailsSuccessPayload>(
`${env.infra_proxy_url}/servers/${server_id}/orgs/${org_id}/data_bags?name=${name}`,
{headers}
);
public getDataBagItems(payload: DataBagItemPayload)
: Observable<DataBagSearchResponse> {

const wildCardSearch = '*';
const target = payload.databagName !== '' ?
'id:' + wildCardSearch + payload.databagName : wildCardSearch + ':';
const nameTarget = target + wildCardSearch;
const currentPage = payload.page - 1;
const params = `search_query.q=${nameTarget}&search_query.page=${currentPage}&search_query.per_page=${payload.per_page}`;
const url = `${env.infra_proxy_url}/servers/${payload.server_id}/orgs/${payload.org_id}/data_bags/${payload.name}?${params}`;

return this.http.get<DataBagSearchResponse>(url, {headers});
}

public getDataBagItemDetails(server_id: string, org_id: string, name: string, item_name: string)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,36 +27,55 @@
</chef-tab-selector>
</chef-page-header>
<section class="page-body" *ngIf="tabValue === 'details'">
<div class="section-container" *ngIf="dataBagDetails">
<div class="empty-section" *ngIf="!dataBagDetails.length">No data available</div>
<div class="details-row" *ngIf="dataBagDetails.length">
<div class="item-column">
<ul>
<li *ngFor="let item of dataBagDetails" [class.selected]="item.name === selectedItem"
(click)="handleItemSelected(item.name)">
{{item.name}}
<chef-icon class="arrow">play_arrow</chef-icon>
</li>
</ul>
</div>
<div class="item-details-column">
<chef-loading-spinner *ngIf="dataBagsItemDetailsLoading" size="50" fixed></chef-loading-spinner>
<div *ngIf="!dataBagsItemDetailsLoading && selectedItemDetails">
<div class="expand-collapse">
<span class="action" (click)="tree.expand()">
<chef-icon>add_circle</chef-icon>
<span>Expand All</span>
</span>
<span class="separator">|</span>
<span class="action" (click)="tree.collapse()">
<chef-icon>remove_circle</chef-icon>
<span>Collapse All</span>
</span>
<div class="search-items">
<app-infra-search-bar (searchButtonClick)="searchDataBagItems($event)" placeHolder="data bag items"></app-infra-search-bar>
</div>
<div class="section-container" *ngIf="dataBagItems">
<chef-loading-spinner *ngIf="searching" size="50" fixed></chef-loading-spinner>
<div class="empty-section" *ngIf="!searching && !dataBagItems.length">
<img alt="No preview" src="/assets/img/no_preview.gif" />
<p *ngIf="searchValue === ''">No data bag items available</p>
<p *ngIf="searchValue != ''">No results found for "{{searchValue}}".</p>
</div>
<div *ngIf="dataBagItems.length">
<ul id="accordion" class="accordion" >
<li *ngFor="let item of dataBagItems; let i = index" [class.active]="item.active" class="items">
<div class="menu" (click)="handleItemSelected(item.name, i)">
<div class="data-bag-name">
{{ item.name }}
</div>
<!-- <i class="fa fa-chevron-down"></i> -->
<chef-icon class="arrows">keyboard_arrow_down</chef-icon>
</div>
<div class="submenu" [ngClass]="item.active ? activeClassName : ''">
<div class="item-details">
<chef-loading-spinner *ngIf="item.active && dataBagsItemDetailsLoading" size="50" fixed></chef-loading-spinner>
<div *ngIf="!dataBagsItemDetailsLoading && selectedItemDetails">
<div class="expand-collapse">
<span class="action" (click)="tree.expand()">
<chef-icon>add_circle</chef-icon>
<span>Expand All</span>
</span>
<span class="separator">|</span>
<span class="action" (click)="tree.collapse()">
<chef-icon>remove_circle</chef-icon>
<span>Collapse All</span>
</span>
</div>
<app-json-tree-table class="json-tree-container" #tree [json]="selectedItemDetails"></app-json-tree-table>
</div>
</div>
</div>
<app-json-tree-table class="json-tree-container" #tree [json]="selectedItemDetails"></app-json-tree-table>
</div>
</div>
</li>
</ul>
</div>
<app-page-picker
class="data-bag-items-list-paging"
[total]="total"
[perPage]="per_page"
[page]="page"
(pageChanged)="onPageChange($event)">
</app-page-picker>
</div>
</section>
</main>
Expand Down
Loading

0 comments on commit 3d2587b

Please sign in to comment.