Skip to content

Commit

Permalink
fix: improve detail layout, use observable on search
Browse files Browse the repository at this point in the history
  • Loading branch information
HenryT-CG committed Oct 26, 2024
1 parent 626c3cb commit 0fcaa9c
Show file tree
Hide file tree
Showing 6 changed files with 102 additions and 83 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@
</label>
</div>

<div class="w-full flex flex-column sm:flex-row row-gap-3 sm:row-gap-1 sm:justify-content-evenly align-items-end">
<div class="w-full flex flex-column row-gap-2 sm:flex-row sm:justify-content-evenly sm:align-items-end">
<div class="p-0 md:text-right flex flex-column md:justify-content-end">
<label class="float-label mb-1 text-sm font-medium" for="am_announcement_detail_form_priority"
>{{ 'ANNOUNCEMENT.PRIORITY' | translate }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,18 @@
[workspaces]="(usedWorkspaces$ | async) ?? []"
[products]="(usedProducts$ | async) ?? []"
(criteriaEmitter)="search($event)"
(resetSearchEmitter)="onReset()"
(resetSearchEmitter)="onCriteriaReset()"
></app-announcement-criteria>

<ocx-page-content styleClass="px-3">
<ocx-page-content *ngIf="announcements$ | async as announcements" styleClass="px-3">
<p-message
*ngIf="searchInProgress"
severity="info"
styleClass="my-3 p-2"
[text]="'ACTIONS.SEARCH.IN_PROGRESS' | translate"
></p-message>
<p-table
*ngIf="!searchInProgress"
#announcementTable
id="am_announcement_search_table"
[value]="announcements"
Expand All @@ -35,7 +42,6 @@
[enableFiltering]="true"
[enableSorting]="false"
[columnDefinitions]="columns"
[columnTemplates]="[]"
(columnsChange)="onColumnsChange($event)"
(filterChange)="onFilterChange($event)"
[filterColumns]="['ANNOUNCEMENT.TITLE' | translate, 'ANNOUNCEMENT.WORKSPACE' | translate]"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import {
PortalMessageService,
UserService
} from '@onecx/portal-integration-angular'
import { Announcement, AnnouncementAssignments, AnnouncementInternalAPIService } from 'src/app/shared/generated'
import { AnnouncementAssignments, AnnouncementInternalAPIService } from 'src/app/shared/generated'
import { AnnouncementSearchComponent } from './announcement-search.component'

const announcementData: any = [
Expand Down Expand Up @@ -71,7 +71,6 @@ describe('AnnouncementSearchComponent', () => {
}
const translateServiceSpy = jasmine.createSpyObj('TranslateService', ['get'])

const newAnnArray: Announcement[] = [{ id: 'id', title: 'new' }]
const mockUserService = {
lang$: {
getValue: jasmine.createSpy('getValue')
Expand Down Expand Up @@ -132,27 +131,41 @@ describe('AnnouncementSearchComponent', () => {
})

describe('search', () => {
it('should search announcements without search criteria', () => {
it('should search announcements without search criteria', (done) => {
apiServiceSpy.searchAnnouncements.and.returnValue(of({ stream: announcementData }))
component.announcements = []

component.search({ announcementSearchCriteria: {} })

expect(component.announcements).toEqual(announcementData)
component.announcements$!.subscribe({
next: (data) => {
expect(data.length).toBe(3)
expect(data[0]).toEqual(announcementData[0])
expect(data[1]).toEqual(announcementData[1])
expect(data[2]).toEqual(announcementData[2])
done()
},
error: done.fail
})
})

it('should search anncmts assigned to one workspace', () => {
it('should search anncmts assigned to one workspace', (done) => {
apiServiceSpy.searchAnnouncements.and.returnValue(of({ stream: [announcementData[1]] }))
component.announcements = []
component.criteria = { workspaceName: 'ADMIN' }
const reuseCriteria = false

component.search({ announcementSearchCriteria: component.criteria }, reuseCriteria)

expect(component.announcements[0]).toEqual(announcementData[1])
component.announcements$!.subscribe({
next: (data) => {
expect(data.length).toBe(1)
expect(data[0]).toEqual(announcementData[1])
done()
},
error: done.fail
})
})

it('should search anncmts in all workspaces and products', () => {
it('should search anncmts in all workspaces and products', (done) => {
apiServiceSpy.searchAnnouncements.and.returnValue(of({ stream: announcementData }))
component.criteria = { workspaceName: 'all', productName: 'all' }
const resultCriteria = {
Expand All @@ -163,43 +176,59 @@ describe('AnnouncementSearchComponent', () => {

component.search({ announcementSearchCriteria: component.criteria }, reuseCriteria)
expect(component.criteria).toEqual(resultCriteria)
expect(component.announcements).toEqual(announcementData)
})

it('should display an info message if there are no announcements', () => {
apiServiceSpy.searchAnnouncements.and.returnValue(of([]))
component.announcements = []

component.search({ announcementSearchCriteria: {} })

expect(component.announcements.length).toEqual(0)
expect(msgServiceSpy.info).toHaveBeenCalledOnceWith({ summaryKey: 'ACTIONS.SEARCH.NO_RESULTS' })
component.announcements$!.subscribe({
next: (data) => {
expect(data.length).toBe(3)
expect(data[0]).toEqual(announcementData[0])
expect(data[1]).toEqual(announcementData[1])
expect(data[2]).toEqual(announcementData[2])
done()
},
error: done.fail
})
})

it('should reset search criteria and empty announcements for the next search', () => {
it('should reset search criteria and empty announcements for the next search', (done) => {
apiServiceSpy.searchAnnouncements.and.returnValue(of({ stream: [announcementData[1]] }))
component.announcements = []
component.criteria = { workspaceName: 'ADMIN' }
const reuseCriteria = false

component.search({ announcementSearchCriteria: component.criteria }, reuseCriteria)
expect(component.announcements[0]).toEqual(announcementData[1])

component.onReset()
component.announcements$!.subscribe({
next: (data) => {
expect(data.length).toBe(1)
expect(data[0]).toEqual(announcementData[1])
done()
},
error: done.fail
})

component.onCriteriaReset()

expect(component.criteria).toEqual({})
expect(component.announcements).toEqual([])
})

it('should display an error message if the search call fails', () => {
it('should display an error message if the search call fails', (done) => {
const err = { status: '400' }
apiServiceSpy.searchAnnouncements.and.returnValue(throwError(() => err))

component.search({ announcementSearchCriteria: {} })

expect(msgServiceSpy.error).toHaveBeenCalledWith({
summaryKey: 'ACTIONS.SEARCH.SEARCH_FAILED',
detailKey: 'EXCEPTIONS.HTTP_STATUS_' + err.status + '.ANNOUNCEMENTS'
component.announcements$!.subscribe({
next: (data) => {
expect(data.length).toBe(0)
done()
},
error: () => {
expect(component.exceptionKey).toEqual('EXCEPTIONS.HTTP_STATUS_400.HELP_ITEM')
expect(msgServiceSpy.error).toHaveBeenCalledWith({
summaryKey: 'ACTIONS.SEARCH.SEARCH_FAILED',
detailKey: 'EXCEPTIONS.HTTP_STATUS_' + err.status + '.ANNOUNCEMENTS'
})
done.fail
}
})
})

Expand All @@ -214,14 +243,20 @@ describe('AnnouncementSearchComponent', () => {
expect(component.criteria).toEqual(newCriteria)
})

it('should search with wildcard * in title', () => {
it('should search with wildcard * in title', (done) => {
apiServiceSpy.searchAnnouncements.and.returnValue(of({ stream: announcementData }))
component.criteria = { title: 'A*' }
const reuseCriteria = false

component.search({ announcementSearchCriteria: component.criteria }, reuseCriteria)

expect(component.announcements).toEqual(announcementData)
component.announcements$!.subscribe({
next: (data) => {
expect(data).toEqual(announcementData)
done()
},
error: done.fail
})
})
})

Expand Down Expand Up @@ -279,34 +314,25 @@ describe('AnnouncementSearchComponent', () => {
it('should delete an announcement item with and without workspace assignment', () => {
const ev: MouseEvent = new MouseEvent('type')
apiServiceSpy.deleteAnnouncementById.and.returnValue(of({}))
// component.usedWorkspaces = [{ label: 'workspace', value: 'workspace' }]
component.announcements = [
const announcements = [
{ id: 'a1', title: 'a1' },
{ id: 'a2', title: 'a2', workspaceName: 'workspace' }
]
component.onDelete(ev, component.announcements[0])
component.onDelete(ev, announcements[0])
component.onDeleteConfirmation()

expect(component.announcements.length).toBe(1)
expect(msgServiceSpy.success).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.DELETE.MESSAGE.OK' })

component.onDelete(ev, component.announcements[0])
component.onDeleteConfirmation()
expect(component.announcements.length).toBe(0)
})

it('should display error if deleting an announcement fails', () => {
apiServiceSpy.deleteAnnouncementById.and.returnValue(throwError(() => new Error()))
component.announcement = {
id: 'definedHere'
}
component.announcements = newAnnArray

component.onDeleteConfirmation()

expect(msgServiceSpy.error).toHaveBeenCalledWith({
summaryKey: 'ACTIONS.DELETE.MESSAGE.NOK'
})
expect(msgServiceSpy.error).toHaveBeenCalledWith({ summaryKey: 'ACTIONS.DELETE.MESSAGE.NOK' })
})

it('should set correct values when detail dialog is closed', () => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,13 @@ import { SelectItem } from 'primeng/api'
import { Action, Column, PortalMessageService, UserService } from '@onecx/portal-integration-angular'
import {
Announcement,
AnnouncementAssignments,
AnnouncementPageResult,
AnnouncementInternalAPIService,
SearchAnnouncementsRequestParams,
AnnouncementSearchCriteria,
SearchAnnouncementsRequestParams,
WorkspaceAbstract,
ProductsPageResult,
AnnouncementAssignments
ProductsPageResult
} from 'src/app/shared/generated'
import { limitText, dropDownSortItemsByLabel } from 'src/app/shared/utils'

Expand All @@ -38,12 +39,12 @@ export class AnnouncementSearchComponent implements OnInit {
public actions$: Observable<Action[]> | undefined
public criteria: AnnouncementSearchCriteria = {}
public announcement: Announcement | undefined
public announcements: Announcement[] = []
public announcements$: Observable<Announcement[]> | undefined
public displayDeleteDialog = false
public displayDetailDialog = false
public appsChanged = false
public searching = false
public loading = false
public searchInProgress = false
public exceptionKey: string | undefined = undefined
public dateFormat: string
public usedWorkspaces$: Observable<SelectItem[]> | undefined
public allWorkspaces: SelectItem[] = []
Expand Down Expand Up @@ -166,9 +167,8 @@ export class AnnouncementSearchComponent implements OnInit {
}
}

public onReset(): void {
public onCriteriaReset(): void {
this.criteria = {}
this.announcements = []
}

/****************************************************************************
Expand All @@ -188,28 +188,17 @@ export class AnnouncementSearchComponent implements OnInit {
criteria.announcementSearchCriteria.productName = undefined
this.criteria = criteria.announcementSearchCriteria
}
this.searching = true
this.announcementApi
.searchAnnouncements(criteria)
.pipe(
finalize(() => {
this.searching = false
this.loading = false
})
)
.subscribe({
next: (data) => {
this.announcements = data.stream || []
if (this.announcements.length === 0) {
this.msgService.info({ summaryKey: 'ACTIONS.SEARCH.NO_RESULTS' })
}
},
error: (err) =>
this.msgService.error({
summaryKey: 'ACTIONS.SEARCH.SEARCH_FAILED',
detailKey: 'EXCEPTIONS.HTTP_STATUS_' + err.status + '.ANNOUNCEMENTS'
})
})
this.searchInProgress = true
this.announcements$ = this.announcementApi.searchAnnouncements(criteria).pipe(
catchError((err) => {
this.exceptionKey = 'EXCEPTIONS.HTTP_STATUS_' + err.status + '.HELP_ITEM'
console.error('searchHelps():', err)
this.msgService.error({ summaryKey: 'ACTIONS.SEARCH.MSG_SEARCH_FAILED' })
return of({ stream: [] } as AnnouncementPageResult)
}),
map((data: AnnouncementPageResult) => data.stream ?? []),
finalize(() => (this.searchInProgress = false))
)
}

onColumnsChange(activeIds: string[]) {
Expand Down Expand Up @@ -255,8 +244,7 @@ export class AnnouncementSearchComponent implements OnInit {
this.announcementApi.deleteAnnouncementById({ id: this.announcement?.id }).subscribe({
next: () => {
this.displayDeleteDialog = false
this.announcements = this.announcements.filter((a) => a.id !== this.announcement?.id)
this.announcement = undefined
//this.announcements = this.announcements.filter((a) => a.id !== this.announcement?.id)
this.appsChanged = true
this.msgService.success({ summaryKey: 'ACTIONS.DELETE.MESSAGE.OK' })
if (workspaceUsed) this.getUsedWorkspacesAndProducts()
Expand Down Expand Up @@ -364,7 +352,7 @@ export class AnnouncementSearchComponent implements OnInit {
* used to display readable names in drop down lists and result set
*/

// declare searching for ALL workspaces
// declare search for ALL products
private searchProducts(): Observable<SelectItem[]> {
this.allProducts$ = this.announcementApi.getAllProductNames({ productsSearchCriteria: {} }).pipe(
catchError((err) => {
Expand All @@ -386,7 +374,7 @@ export class AnnouncementSearchComponent implements OnInit {
)
}

// declare searching for ALL workspaces
// declare search for ALL workspaces
private searchWorkspaces(): Observable<SelectItem[]> {
this.allWorkspaces$ = this.announcementApi.getAllWorkspaceNames().pipe(
catchError((err) => {
Expand All @@ -408,7 +396,6 @@ export class AnnouncementSearchComponent implements OnInit {

// Loading everything - triggered from HTML
private loadAllData(): void {
this.loading = true
this.allMetaData$ = combineLatest([this.searchWorkspaces(), this.searchProducts()]).pipe(
map(([w, p]: [SelectItem[], SelectItem[]]) => {
this.allWorkspaces = w
Expand Down
2 changes: 1 addition & 1 deletion src/assets/i18n/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@
"RESET_TOOLTIP": "Suchkriterien löschen",
"NO_DATA": "Keine Ergebnisse",
"NO_RESULTS": "Die Suche ergab keine Ergebnisse",
"IN_PROGRESS": "Suche...",
"SEARCH_FAILED": "Die Suche ist fehlgeschlagen",
"NOT_FOUND": "Keine Daten gefunden",
"OF": "von"
},
"CANCEL": "Abbrechen",
"CHOOSE": "Auswählen",
"CONFIRM": "Bestätigen",
"LOADING": "...wird geladen",
"RELOAD": "Neuladen",
"SAVE": "Speichern",
"SAVE_AS": "Speichern als ...",
Expand Down
2 changes: 1 addition & 1 deletion src/assets/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,14 @@
"RESET_TOOLTIP": "Clear given criteria",
"NO_DATA": "No data",
"NO_RESULTS": "Search returned no results",
"IN_PROGRESS": "Searching...",
"SEARCH_FAILED": "Search failed",
"NOT_FOUND": "No data found",
"OF": "of"
},
"CANCEL": "Cancel",
"CHOOSE": "Choose",
"CONFIRM": "Confirm",
"LOADING": "...is loading",
"RELOAD": "Reload",
"SAVE": "Save",
"SAVE_AS": "Save as ...",
Expand Down

0 comments on commit 0fcaa9c

Please sign in to comment.