diff --git a/libs/asset-viewer/src/lib/components/asset-picker/asset-picker.component.ts b/libs/asset-viewer/src/lib/components/asset-picker/asset-picker.component.ts index b9cfa3dc..25948717 100644 --- a/libs/asset-viewer/src/lib/components/asset-picker/asset-picker.component.ts +++ b/libs/asset-viewer/src/lib/components/asset-picker/asset-picker.component.ts @@ -3,11 +3,11 @@ import { Component, ElementRef, EventEmitter, + inject, Input, NgZone, Output, ViewChild, - inject, } from '@angular/core'; import { DragHandleOffset, getCssCustomPropertyNumberValue } from '@asset-sg/client-shared'; import { AssetEditDetail } from '@asset-sg/shared'; @@ -17,16 +17,16 @@ import { RxState } from '@rx-angular/state'; import * as O from 'fp-ts/Option'; import { WINDOW } from 'ngx-window-token'; import { - Observable, - Subject, distinctUntilChanged, filter, identity, map, merge, + Observable, pairwise, scan, startWith, + Subject, switchMap, } from 'rxjs'; @@ -162,7 +162,7 @@ export class AssetPickerComponent extends RxState { } public selectAndClose(assetId: number) { - this._store.dispatch(actions.searchForAssetDetail({ assetId })); + this._store.dispatch(actions.assetClicked({ assetId })); this.closePicker$.next(); } } diff --git a/libs/asset-viewer/src/lib/components/asset-search-results/asset-search-results.component.html b/libs/asset-viewer/src/lib/components/asset-search-results/asset-search-results.component.html index 9b3f6dc3..db34ef92 100644 --- a/libs/asset-viewer/src/lib/components/asset-search-results/asset-search-results.component.html +++ b/libs/asset-viewer/src/lib/components/asset-search-results/asset-search-results.component.html @@ -6,7 +6,7 @@ @@ -80,6 +80,7 @@ (click)="searchForAsset(row.assetId)" (mouseover)="assetMouseOver.emit(row.assetId)" (mouseleave)="assetMouseOver.emit(null)" + [ngClass]="{ selected: row.assetId === (currentAssetDetail$ | async)?.assetId }" > diff --git a/libs/asset-viewer/src/lib/components/asset-search-results/asset-search-results.component.scss b/libs/asset-viewer/src/lib/components/asset-search-results/asset-search-results.component.scss index 48fa0e13..c9155c91 100644 --- a/libs/asset-viewer/src/lib/components/asset-search-results/asset-search-results.component.scss +++ b/libs/asset-viewer/src/lib/components/asset-search-results/asset-search-results.component.scss @@ -8,8 +8,11 @@ flex-direction: column; } +::-webkit-scrollbar-corner { + background-color: variables.$grey-01; +} + @include drawerPanel.draw-panel-header; -@include drawerPanel.draw-panel-header-underline; .header { padding: 0 1rem; @@ -17,8 +20,6 @@ } .search-results { - overflow-y: scroll; - overflow-x: hidden; display: flex; flex-wrap: wrap; height: 400px; @@ -45,6 +46,7 @@ .mat-mdc-row:hover .mat-mdc-cell { background-color: variables.$grey-01; + cursor: pointer; } .table-container { @@ -53,7 +55,7 @@ overflow-x: auto; display: block; width: 100%; - padding: 0 12px; + padding-left: 22px; .mat-table { width: max-content; @@ -62,7 +64,7 @@ } .table { - margin: 12px 0; + box-shadow: none; .table-header { background-color: variables.$grey-03; @@ -71,5 +73,9 @@ .mat-column-titlePublic { word-wrap: break-word; } + + .selected { + background-color: variables.$grey-01; + } } } diff --git a/libs/asset-viewer/src/lib/components/asset-search-results/asset-search-results.component.ts b/libs/asset-viewer/src/lib/components/asset-search-results/asset-search-results.component.ts index b7c49ad0..ec9c95c4 100644 --- a/libs/asset-viewer/src/lib/components/asset-search-results/asset-search-results.component.ts +++ b/libs/asset-viewer/src/lib/components/asset-search-results/asset-search-results.component.ts @@ -8,6 +8,7 @@ import { AppStateWithAssetSearch, LoadingState } from '../../state/asset-search/ import { selectAssetEditDetailVM, selectAssetSearchPageData, + selectCurrentAssetDetail, selectIsResultsOpen, selectSearchLoadingState, } from '../../state/asset-search/asset-search.selector'; @@ -39,11 +40,12 @@ export class AssetSearchResultsComponent { public assets$ = this._store.select(selectAssetEditDetailVM); public loadingState = this._store.select(selectSearchLoadingState); public pageStats$ = this._store.select(selectAssetSearchPageData); + public currentAssetDetail$ = this._store.select(selectCurrentAssetDetail); protected readonly LoadingState = LoadingState; public searchForAsset(assetId: number) { - this._store.dispatch(actions.searchForAssetDetail({ assetId })); + this._store.dispatch(actions.assetClicked({ assetId })); } public toggleResultsOpen(isCurrentlyOpen: boolean) { diff --git a/libs/asset-viewer/src/lib/components/asset-viewer-page/asset-viewer-page.component.ts b/libs/asset-viewer/src/lib/components/asset-viewer-page/asset-viewer-page.component.ts index 4311cafc..f758f552 100644 --- a/libs/asset-viewer/src/lib/components/asset-viewer-page/asset-viewer-page.component.ts +++ b/libs/asset-viewer/src/lib/components/asset-viewer-page/asset-viewer-page.component.ts @@ -146,7 +146,7 @@ export class AssetViewerPageComponent implements AfterViewInit, OnDestroy { ); singleStudyClicked$.pipe(untilDestroyed(this)).subscribe((assetIds) => { - this._store.dispatch(actions.searchForAssetDetail({ assetId: assetIds[0] })); + this._store.dispatch(actions.assetClicked({ assetId: assetIds[0] })); }); merge( diff --git a/libs/asset-viewer/src/lib/services/asset-search.service.ts b/libs/asset-viewer/src/lib/services/asset-search.service.ts index 4674349d..5806029b 100644 --- a/libs/asset-viewer/src/lib/services/asset-search.service.ts +++ b/libs/asset-viewer/src/lib/services/asset-search.service.ts @@ -12,7 +12,7 @@ import { import { Store } from '@ngrx/store'; import { plainToInstance } from 'class-transformer'; import * as E from 'fp-ts/Either'; -import { Observable, map, tap } from 'rxjs'; +import { map, Observable, tap } from 'rxjs'; @Injectable({ providedIn: 'root' }) export class AssetSearchService { diff --git a/libs/asset-viewer/src/lib/state/asset-search/asset-search.actions.ts b/libs/asset-viewer/src/lib/state/asset-search/asset-search.actions.ts index 57b5a1eb..04a35e8a 100644 --- a/libs/asset-viewer/src/lib/state/asset-search/asset-search.actions.ts +++ b/libs/asset-viewer/src/lib/state/asset-search/asset-search.actions.ts @@ -26,8 +26,8 @@ export const resetSearch = createAction('[Asset Search] Reset Search'); export const removePolygon = createAction('[Asset Search] Remove polygon'); export const initializeSearch = createAction('[Asset Search] Initialize search'); export const setLoadingState = createAction('[Asset Search] Set loading state'); -export const searchForAssetDetail = createAction( - '[Asset Search] Search for asset detail', +export const assetClicked = createAction( + '[Asset Search] Asset clicked', props<{ assetId: number; }>() diff --git a/libs/asset-viewer/src/lib/state/asset-search/asset-search.effects.ts b/libs/asset-viewer/src/lib/state/asset-search/asset-search.effects.ts index 0fdb1490..ddc44b83 100644 --- a/libs/asset-viewer/src/lib/state/asset-search/asset-search.effects.ts +++ b/libs/asset-viewer/src/lib/state/asset-search/asset-search.effects.ts @@ -8,13 +8,13 @@ import { UntilDestroy } from '@ngneat/until-destroy'; import { Actions, concatLatestFrom, createEffect, ofType } from '@ngrx/effects'; import { Store } from '@ngrx/store'; import * as D from 'io-ts/Decoder'; -import { filter, map, merge, switchMap, tap, withLatestFrom } from 'rxjs'; +import { filter, map, merge, of, switchMap, tap, withLatestFrom } from 'rxjs'; import { AssetSearchService } from '../../services/asset-search.service'; import * as actions from './asset-search.actions'; import { AppStateWithAssetSearch, AssetSearchState } from './asset-search.reducer'; -import { selectAssetSearchQuery, selectAssetSearchState } from './asset-search.selector'; +import { selectAssetSearchQuery, selectAssetSearchState, selectCurrentAssetDetail } from './asset-search.selector'; @UntilDestroy() @Injectable() @@ -77,7 +77,7 @@ export class AssetSearchEffects { concatLatestFrom(() => this.route.queryParams), map(([_, params]) => readNumberParam(params, QUERY_PARAM_MAPPING.assetId)), filter((assetId): assetId is number => assetId !== undefined), - map((assetId) => actions.searchForAssetDetail({ assetId })) + map((assetId) => actions.assetClicked({ assetId })) ) ); @@ -150,20 +150,25 @@ export class AssetSearchEffects { public searchForAssetDetail$ = createEffect(() => { return this.actions$.pipe( - ofType(actions.searchForAssetDetail), - switchMap(({ assetId }) => { - return this.assetSearchService - .loadAssetDetailData(assetId) - .pipe(map((assetDetail) => actions.updateAssetDetail({ assetDetail }))); - }) + ofType(actions.assetClicked), + withLatestFrom(this.store.select(selectCurrentAssetDetail)), + switchMap(([{ assetId }, currentAssetDetail]) => + assetId !== currentAssetDetail?.assetId + ? this.assetSearchService + .loadAssetDetailData(assetId) + .pipe(map((assetDetail) => actions.updateAssetDetail({ assetDetail }))) + : of(actions.resetAssetDetail()) + ) ); }); public updateUrlWithAssetId = createEffect( () => { return this.actions$.pipe( - ofType(actions.searchForAssetDetail), - map(({ assetId }) => { + ofType(actions.assetClicked), + concatLatestFrom(() => this.store.select(selectCurrentAssetDetail)), + filter(([{ assetId }, currentAssetDetail]) => assetId !== currentAssetDetail?.assetId), + map(([{ assetId }]) => { const queryParams = this.route.snapshot.queryParams; this.router.navigate([], { queryParams: { ...queryParams, assetId }, queryParamsHandling: 'merge' }); }) diff --git a/libs/asset-viewer/src/lib/state/asset-search/asset-search.reducer.ts b/libs/asset-viewer/src/lib/state/asset-search/asset-search.reducer.ts index c3631d07..767add4d 100644 --- a/libs/asset-viewer/src/lib/state/asset-search/asset-search.reducer.ts +++ b/libs/asset-viewer/src/lib/state/asset-search/asset-search.reducer.ts @@ -80,7 +80,10 @@ export const assetSearchReducer = createReducer( actions.updateSearchResults, (state, { searchResults }): AssetSearchState => ({ ...state, - results: searchResults, + results: { + page: searchResults.page, + data: searchResults.data, + }, loadingState: LoadingState.Loaded, }) ), @@ -109,7 +112,7 @@ export const assetSearchReducer = createReducer( }) ), on( - actions.searchForAssetDetail, + actions.assetClicked, (state): AssetSearchState => ({ ...state, assetDetailLoadingState: LoadingState.Loading,