Skip to content

Commit

Permalink
feat: added app search
Browse files Browse the repository at this point in the history
  • Loading branch information
HenryT-CG committed Jan 27, 2024
1 parent df55a88 commit af80ecb
Show file tree
Hide file tree
Showing 8 changed files with 359 additions and 22 deletions.
111 changes: 111 additions & 0 deletions src/app/product-store/app-search/app-search.component.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
<ocx-portal-page permission="MICROFRONTEND#SEARCH" helpArticleId="PAGE_MICROFRONTEND_SEARCH">
<ocx-search-criteria
[header]="'DIALOG.SEARCH.APPS.HEADER' | translate"
[subheader]="'DIALOG.SEARCH.APPS.SUBHEADER' | translate"
[actions]="actions"
[disableAdvancedToggle]="true"
[disableAdvancedToggle]="true"
(search)="onSearch()"
(reset)="onSearchReset()"
>
<div simpleCriteria>
<div [formGroup]="appSearchCriteriaGroup" class="flex flex-wrap gap-4 row-gap-3 px-2">
<span class="p-float-label">
<input
id="app_search_app_id"
pInputText
type="text"
formControlName="appId"
class="w-18rem"
[clear]="true"
[title]="'MICROFRONTEND.APP_ID' | translate"
/>
<label for="app_search_app_id">{{ 'MICROFRONTEND.APP_ID' | translate }}</label>
</span>
<span class="p-float-label">
<input
id="app_search_app_name"
pInputText
type="text"
formControlName="appName"
class="w-18rem"
[clear]="true"
[title]="'MICROFRONTEND.APP_NAME' | translate"
/>
<label for="app_search_app_name">{{ 'MICROFRONTEND.APP_NAME' | translate }}</label>
</span>
<span class="p-float-label">
<input
id="app_search_product_name"
pInputText
type="text"
formControlName="productName"
class="w-18rem"
[clear]="true"
[title]="'MICROFRONTEND.PRODUCT_NAME' | translate"
/>
<label for="app_search_product_name">{{ 'MICROFRONTEND.PRODUCT_NAME' | translate }}</label>
</span>
</div>
</div>
</ocx-search-criteria>

<ocx-page-content>
<div *ngIf="!apps$" class="card px-3 align-items-center">
<p-message severity="error" styleClass="p-2" [text]="'ACTIONS.SEARCH.PRODUCT.NOT_EXISTS' | translate"></p-message>
</div>
<ng-container *ngIf="apps$ | async as apps">
<p-dataView
id="product_search_dataview"
[value]="apps.stream ? apps.stream : []"
[paginator]="true"
[alwaysShowPaginator]="false"
[rowsPerPageOptions]="[10, 20, 50]"
[rows]="viewMode === 'grid' ? 24 : 10"
[layout]="viewMode"
[emptyMessage]="'ACTIONS.SEARCH.NOT_FOUND' | translate"
filterBy="appId,appName,productName"
[sortField]="sortField"
[sortOrder]="sortOrder"
>
<ng-template pTemplate="header">
<ocx-data-view-controls
[enableFiltering]="true"
[enableSorting]="true"
[supportedViews]="['grid']"
[initialViewMode]="viewMode"
[sortingOptions]="[
{ label: 'MICROFRONTEND.APP_ID' | translate, value: 'appId' },
{ label: 'MICROFRONTEND.APP_NAME' | translate, value: 'appName' },
{ label: 'MICROFRONTEND.PRODUCT_NAME' | translate, value: 'productName' }
]"
[defaultSortOption]="sortField"
[defaultSortDirection]="sortOrder === 1"
(dataViewChange)="onLayoutChange($event)"
(filterChange)="onFilterChange($event)"
[filterColumns]="[
'MICROFRONTEND.APP_ID' | translate,
'MICROFRONTEND.APP_NAME' | translate,
'MICROFRONTEND.PRODUCT_NAME' | translate
]"
(sortChange)="onSortChange($event)"
(sortDirectionChange)="onSortDirChange($event)"
[translations]="dataViewControlsTranslations"
>
</ocx-data-view-controls
></ng-template>
<ng-template let-app pTemplate="gridItem">
<div class="col-12 sm:col-6 md:col-4 lg:col-4 xl:col-3 p-3" [routerLink]="['../', app.productName]">
<div class="card p-1 flex flex-column justify-content-center hover:bg-gray-200 cursor-pointer">
<div class="flex flex-column justify-content-between gap-1 text-center">
<div class="font-bold" [title]="app.appId">{{ limitText(app.appId, 25) }}</div>
<div class="text-sm" [title]="app.appName">{{ limitText(app.appName, 30) }}</div>
<div [title]="app.productName">{{ limitText(app.productName, 25) }}</div>
</div>
</div>
</div>
</ng-template>
</p-dataView>
</ng-container>
</ocx-page-content>
</ocx-portal-page>
13 changes: 13 additions & 0 deletions src/app/product-store/app-search/app-search.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
:host ::ng-deep {
.p-dataview-content .p-grid > div {
min-height: 60px;
&.listview-row {
&:nth-child(odd) {
background-color: #f8f9fa;
}
}
}
.h-05rem {
height: 0.5rem;
}
}
143 changes: 143 additions & 0 deletions src/app/product-store/app-search/app-search.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
import { Component, OnInit, ViewChild } from '@angular/core'
import { ActivatedRoute, Router } from '@angular/router'
import { Observable, finalize } from 'rxjs'
import { DataView } from 'primeng/dataview'
import { TranslateService } from '@ngx-translate/core'
import { Action, DataViewControlTranslations } from '@onecx/portal-integration-angular'
import { MicrofrontendPageResult, MicrofrontendsAPIService } from '../../generated'
import { limitText } from '../../shared/utils'
import { FormControl, FormGroup } from '@angular/forms'

export interface MicrofrontendSearchCriteria {
appId: FormControl<string | null>
appName: FormControl<string | null>
productName: FormControl<string | null>
}

@Component({
templateUrl: './app-search.component.html',
styleUrls: ['./app-search.component.scss']
})
export class AppSearchComponent implements OnInit {
public apps$!: Observable<MicrofrontendPageResult>
public appSearchCriteriaGroup!: FormGroup<MicrofrontendSearchCriteria>
public actions: Action[] = []
public viewMode = 'grid'
public filter: string | undefined
public sortField = 'appName'
public sortOrder = 1
public searchInProgress = false
public limitText = limitText

public dataViewControlsTranslations: DataViewControlTranslations = {}
@ViewChild(DataView) dv: DataView | undefined

constructor(
private route: ActivatedRoute,
private router: Router,
private appApi: MicrofrontendsAPIService,
private translate: TranslateService
) {
this.appSearchCriteriaGroup = new FormGroup<MicrofrontendSearchCriteria>({
appId: new FormControl<string | null>(null),
appName: new FormControl<string | null>(null),
productName: new FormControl<string | null>(null)
})
}

ngOnInit(): void {
this.prepareTranslations()
this.loadProducts()
}

public loadProducts(): void {
this.searchInProgress = true
this.apps$ = this.appApi
.searchMicrofrontends({
microfrontendSearchCriteria: {
appId: this.appSearchCriteriaGroup.controls['appId'].value,
appName: this.appSearchCriteriaGroup.controls['appName'].value,
productName: this.appSearchCriteriaGroup.controls['productName'].value,
pageSize: 1000
}
})
.pipe(finalize(() => (this.searchInProgress = false)))
}

private prepareTranslations(): void {
this.translate
.get([
'MICROFRONTEND.APP_ID',
'MICROFRONTEND.APP_NAME',
'MICROFRONTEND.PRODUCT_NAME',
'ACTIONS.NAVIGATION.BACK',
'ACTIONS.NAVIGATION.BACK.TOOLTIP',
'ACTIONS.CREATE.LABEL',
'ACTIONS.CREATE.PRODUCT.TOOLTIP',
'ACTIONS.DATAVIEW.VIEW_MODE_LIST',
'ACTIONS.DATAVIEW.VIEW_MODE_TABLE',
'ACTIONS.DATAVIEW.SORT_BY',
'ACTIONS.DATAVIEW.FILTER',
'ACTIONS.DATAVIEW.FILTER_OF',
'ACTIONS.DATAVIEW.SORT_DIRECTION_ASC',
'ACTIONS.DATAVIEW.SORT_DIRECTION_DESC'
])
.subscribe((data) => {
this.dataViewControlsTranslations = {
sortDropdownPlaceholder: data['ACTIONS.DATAVIEW.SORT_BY'],
filterInputPlaceholder: data['ACTIONS.DATAVIEW.FILTER'],
filterInputTooltip:
data['ACTIONS.DATAVIEW.FILTER_OF'] +
data['MICROFRONTEND.APP_ID'] +
', ' +
data['MICROFRONTEND.APP_NAME'] +
', ' +
data['MICROFRONTEND.PRODUCT_NAME'],
viewModeToggleTooltips: {
grid: data['ACTIONS.DATAVIEW.VIEW_MODE_GRID'],
table: data['ACTIONS.DATAVIEW.VIEW_MODE_TABLE']
},
sortOrderTooltips: {
ascending: data['ACTIONS.DATAVIEW.SORT_DIRECTION_ASC'],
descending: data['ACTIONS.DATAVIEW.SORT_DIRECTION_DESC']
},
sortDropdownTooltip: data['ACTIONS.DATAVIEW.SORT_BY']
}
this.prepareActionButtons(data)
})
}

private prepareActionButtons(data: any): void {
this.actions = [] // provoke change event
this.actions.push({
label: data['ACTIONS.NAVIGATION.BACK'],
title: data['ACTIONS.NAVIGATION.BACK.TOOLTIP'],
actionCallback: () => this.onBack(),
icon: 'pi pi-arrow-left',
show: 'always'
})
}

public onLayoutChange(viewMode: string): void {
this.viewMode = viewMode
}
public onFilterChange(filter: string): void {
this.filter = filter
this.dv?.filter(filter, 'contains')
}
public onSortChange(field: string): void {
this.sortField = field
}
public onSortDirChange(asc: boolean): void {
this.sortOrder = asc ? -1 : 1
}
public onSearch() {
this.loadProducts()
}
public onSearchReset() {
this.appSearchCriteriaGroup.reset()
}
public onBack() {
this.router.navigate(['../'], { relativeTo: this.route })
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
</ocx-search-criteria>

<ocx-page-content>
<div *ngIf="!product$" class="card px-3 align-items-center">
<div *ngIf="!products$" class="card px-3 align-items-center">
<p-message severity="error" styleClass="p-2" [text]="'ACTIONS.SEARCH.PRODUCT.NOT_EXISTS' | translate"></p-message>
</div>
<ng-container *ngIf="product$ | async as products">
<ng-container *ngIf="products$ | async as products">
<p-dataView
id="product_search_dataview"
[value]="products.stream ? products.stream : []"
Expand Down
36 changes: 25 additions & 11 deletions src/app/product-store/product-search/product-search.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export interface ProductSearchCriteria {
styleUrls: ['./product-search.component.scss']
})
export class ProductSearchComponent implements OnInit {
public product$!: Observable<ProductPageResult>
public products$!: Observable<ProductPageResult>
public productSearchCriteriaGroup!: FormGroup<ProductSearchCriteria>
public actions: Action[] = []
public viewMode = 'grid'
Expand Down Expand Up @@ -48,7 +48,7 @@ export class ProductSearchComponent implements OnInit {

public loadProducts(): void {
this.searchInProgress = true
this.product$ = this.productApi
this.products$ = this.productApi
.searchProducts({
productSearchCriteria: { name: this.productSearchCriteriaGroup.controls['productName'].value, pageSize: 1000 }
})
Expand All @@ -60,6 +60,8 @@ export class ProductSearchComponent implements OnInit {
.get([
'PRODUCT.NAME',
'PRODUCT.DISPLAY_NAME',
'DIALOG.SEARCH.APPS.LABEL',
'DIALOG.SEARCH.APPS.TOOLTIP',
'ACTIONS.CREATE.LABEL',
'ACTIONS.CREATE.PRODUCT.TOOLTIP',
'ACTIONS.DATAVIEW.VIEW_MODE_GRID',
Expand All @@ -80,7 +82,6 @@ export class ProductSearchComponent implements OnInit {
viewModeToggleTooltips: {
grid: data['ACTIONS.DATAVIEW.VIEW_MODE_GRID'],
list: data['ACTIONS.DATAVIEW.VIEW_MODE_LIST']
// table: data['ACTIONS.DATAVIEW.VIEW_MODE_TABLE'],
},
sortOrderTooltips: {
ascending: data['ACTIONS.DATAVIEW.SORT_DIRECTION_ASC'],
Expand All @@ -94,14 +95,24 @@ export class ProductSearchComponent implements OnInit {

private prepareActionButtons(data: any): void {
this.actions = [] // provoke change event
this.actions.push({
label: data['ACTIONS.CREATE.LABEL'],
title: data['ACTIONS.CREATE.PRODUCT.TOOLTIP'],
actionCallback: () => this.onNewProduct(),
permission: 'PRODUCT#EDIT',
icon: 'pi pi-plus',
show: 'always'
})
this.actions.push(
{
label: data['DIALOG.SEARCH.APPS.LABEL'],
title: data['DIALOG.SEARCH.APPS.TOOLTIP'],
actionCallback: () => this.onAppSearch(),
permission: 'MICROFRONTEND#SEARCH',
icon: 'pi pi-cog',
show: 'always'
},
{
label: data['ACTIONS.CREATE.LABEL'],
title: data['ACTIONS.CREATE.PRODUCT.TOOLTIP'],
actionCallback: () => this.onNewProduct(),
permission: 'PRODUCT#CREATE',
icon: 'pi pi-plus',
show: 'always'
}
)
}

public onLayoutChange(viewMode: string): void {
Expand All @@ -126,4 +137,7 @@ export class ProductSearchComponent implements OnInit {
public onNewProduct() {
this.router.navigate(['./new'], { relativeTo: this.route })
}
public onAppSearch() {
this.router.navigate(['./apps'], { relativeTo: this.route })
}
}
14 changes: 14 additions & 0 deletions src/app/product-store/product-store.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { MFE_INFO, PortalCoreModule, MyMissingTranslationHandler } from '@onecx/
import { CanActivateGuard } from '../shared/can-active-guard.service'
import { LabelResolver } from '../shared/label.resolver'
import { HttpLoaderFactory, SharedModule } from '../shared/shared.module'
import { AppSearchComponent } from './app-search/app-search.component'
import { ProductSearchComponent } from './product-search/product-search.component'
import { ProductDetailComponent } from './product-detail/product-detail.component'
import { ProductPropertyComponent } from './product-detail/product-props/product-props.component'
Expand All @@ -24,6 +25,18 @@ const routes: Routes = [
canActivate: [CanActivateGuard],
pathMatch: 'full'
},
{
path: 'apps',
component: AppSearchComponent,
canActivate: [CanActivateGuard],
data: {
breadcrumb: 'BREADCRUMBS.APPS',
breadcrumbFn: (data: any) => `${data.labeli18n}`
},
resolve: {
labeli18n: LabelResolver
}
},
{
path: 'new',
canActivate: [CanActivateGuard],
Expand Down Expand Up @@ -51,6 +64,7 @@ const routes: Routes = [
]
@NgModule({
declarations: [
AppSearchComponent,
ProductSearchComponent,
ProductDetailComponent,
ProductPropertyComponent,
Expand Down
Loading

0 comments on commit af80ecb

Please sign in to comment.