Skip to content

Commit

Permalink
Merge branch 'develop' into ME/records-published-by-my-org
Browse files Browse the repository at this point in the history
  • Loading branch information
cmoinier authored Oct 13, 2023
2 parents c4b5817 + 5926a9c commit c55b56f
Show file tree
Hide file tree
Showing 27 changed files with 427 additions and 93 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/artifacts.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:
push:
branches:
- main
- develop
release:
types: [published]
issue_comment:
Expand All @@ -20,7 +21,7 @@ concurrency:
env:
NODE_VERSION: 18.16.1
# a list of apps to build and publish on releases
APP_NAMES: datafeeder,datahub
APP_NAMES: datafeeder,datahub,metadata-editor

jobs:
checks:
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cleanup.yml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ run-name: 🧹 Cleanup operations for 🌱 ${{github.event.ref}}

env:
# a list of apps to build and publish on releases
APP_NAMES: datafeeder,datahub
APP_NAMES: datafeeder,datahub,metadata-editor

on:
delete:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ <h2 class="text-xl mr-4 font-title" translate>
></gn-ui-filter-dropdown>
<div
class="spatial-filter-toggle sm:col-span-2"
*ngIf="isOpen && searchFacade.hasSpatialFilter$ | async"
*ngIf="isOpen && (searchFacade.hasSpatialFilter$ | async)"
>
<gn-ui-check-toggle
[title]="'search.filters.useSpatialFilterHelp' | translate"
Expand All @@ -63,6 +63,30 @@ <h2 class="text-xl mr-4 font-title" translate>
(toggled)="toggleSpatialFilter($event)"
></gn-ui-check-toggle>
</div>
<div class="sm:col-span-2" *ngIf="userId && isOpen">
<gn-ui-check-toggle
[title]="'search.filters.myRecordsHelp' | translate"
[label]="'search.filters.myRecords' | translate"
[color]="'secondary'"
[value]="myRecordsFilterEnabled$ | async"
(toggled)="toggleMyRecordsFilter($event)"
></gn-ui-check-toggle>
</div>
<div
class="sm:col-span-2"
*ngIf="!userId && (myRecordsFilterEnabled$ | async) && isOpen"
>
<gn-ui-button
type="light"
extraClass="text-sm align-middle"
(buttonClick)="toggleMyRecordsFilter(false)"
>
<span>{{ 'search.filters.otherRecords' | translate }}</span>
<mat-icon class="material-symbols-outlined ml-3 opacity-40"
>close</mat-icon
>
</gn-ui-button>
</div>
</div>
<div
class="col-span-2 flex flex-col justify-between"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@ import { SearchFiltersComponent } from './search-filters.component'
import { TranslateModule } from '@ngx-translate/core'
import { By } from '@angular/platform-browser'
import { FormsModule } from '@angular/forms'
import {
AggregationsTypes,
FieldFilters,
} from '@geonetwork-ui/common/domain/search'
import { FieldFilters } from '@geonetwork-ui/common/domain/search'
import { USER_FIXTURE } from '@geonetwork-ui/common/fixtures'
import { AuthService } from '@geonetwork-ui/api/repository/gn4'

jest.mock('@geonetwork-ui/util/app-config', () => ({
getOptionalSearchConfig: () => ({
Expand Down Expand Up @@ -67,6 +66,7 @@ export class MockFilterDropdownComponent {
@Input() title: string
}
const state = { OrgForResource: { mel: true } } as FieldFilters
const user = USER_FIXTURE()
class SearchFacadeMock {
searchFilters$ = new BehaviorSubject(state)
hasSpatialFilter$ = new BehaviorSubject(false)
Expand Down Expand Up @@ -103,6 +103,12 @@ class FieldsServiceMock {
}
}

class AuthServiceMock {
user$ = new BehaviorSubject(user)
authReady = jest.fn(() => this._authSubject$)
_authSubject$ = new BehaviorSubject({})
}

describe('SearchFiltersComponent', () => {
let component: SearchFiltersComponent
let fixture: ComponentFixture<SearchFiltersComponent>
Expand Down Expand Up @@ -131,6 +137,10 @@ describe('SearchFiltersComponent', () => {
provide: FieldsService,
useClass: FieldsServiceMock,
},
{
provide: AuthService,
useClass: AuthServiceMock,
},
],
})
.overrideComponent(SearchFiltersComponent, {
Expand All @@ -155,7 +165,9 @@ describe('SearchFiltersComponent', () => {

describe('spatial filter button', () => {
function getCheckToggleDebugElement() {
return fixture.debugElement.query(By.directive(MockCheckToggleComponent))
return fixture.debugElement.queryAll(
By.directive(MockCheckToggleComponent)
)
}

describe('when panel is closed', () => {
Expand All @@ -164,7 +176,7 @@ describe('SearchFiltersComponent', () => {
fixture.detectChanges()
})
it('does not show up', () => {
expect(getCheckToggleDebugElement()).toBeFalsy()
expect(getCheckToggleDebugElement().length).toBeFalsy()
})
})
describe('when panel is opened & a spatial filter is unavailable', () => {
Expand All @@ -174,7 +186,7 @@ describe('SearchFiltersComponent', () => {
fixture.detectChanges()
})
it('does not show up', () => {
expect(getCheckToggleDebugElement()).toBeFalsy()
expect(getCheckToggleDebugElement().length).toBe(1)
})
})
describe('when panel is opened & a spatial filter is available', () => {
Expand All @@ -185,11 +197,11 @@ describe('SearchFiltersComponent', () => {
fixture.detectChanges()
})
it('does show up', () => {
expect(getCheckToggleDebugElement()).toBeTruthy()
expect(getCheckToggleDebugElement().length).toBe(2)
})
it('has the value set in the state', () => {
expect(
getCheckToggleDebugElement().componentInstance.value
getCheckToggleDebugElement()[0].componentInstance.value
).toBeTruthy()
})
})
Expand All @@ -201,7 +213,7 @@ describe('SearchFiltersComponent', () => {
})
it('emits a SetSpatialFilterEnabled action', () => {
const checkToggleComponent =
getCheckToggleDebugElement().componentInstance
getCheckToggleDebugElement()[0].componentInstance
checkToggleComponent.toggled.emit(false)
expect(searchFacade.setSpatialFilterEnabled).toHaveBeenCalledWith(false)
})
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import {
QueryList,
ViewChildren,
} from '@angular/core'
import { AuthService } from '@geonetwork-ui/api/repository/gn4'
import {
FieldsService,
FilterDropdownComponent,
SearchFacade,
SearchService,
} from '@geonetwork-ui/feature/search'
import { getOptionalSearchConfig } from '@geonetwork-ui/util/app-config'
import { Observable, switchMap } from 'rxjs'
import { map } from 'rxjs/operators'

@Component({
selector: 'datahub-search-filters',
Expand All @@ -24,14 +27,28 @@ export class SearchFiltersComponent implements OnInit {
filters: QueryList<FilterDropdownComponent>
searchConfig: { fieldName: string; title: string }[]
isOpen = false
userId: string
myRecordsFilterEnabled$: Observable<boolean> =
this.searchFacade.searchFilters$.pipe(
switchMap((filters) => {
return this.fieldsService.readFieldValuesFromFilters(filters)
}),
map((fieldValues) =>
fieldValues['owner'] && Array.isArray(fieldValues['owner'])
? fieldValues['owner'].length > 0
: !!fieldValues['owner']
)
)

constructor(
public searchFacade: SearchFacade,
private searchService: SearchService,
private fieldsService: FieldsService
private fieldsService: FieldsService,
private authService: AuthService
) {}

ngOnInit(): void {
this.authService.user$.subscribe((user) => (this.userId = user?.id))
this.searchConfig = (
getOptionalSearchConfig().ADVANCED_FILTERS || [
'publisher',
Expand Down Expand Up @@ -70,6 +87,12 @@ export class SearchFiltersComponent implements OnInit {
this.searchFacade.setSpatialFilterEnabled(enabled)
}

toggleMyRecordsFilter(enabled: boolean) {
this.fieldsService
.buildFiltersFromFieldValues({ owner: enabled ? this.userId : [] })
.subscribe((filters) => this.searchService.updateFilters(filters))
}

clearFilters() {
const fieldNames = this.filters.map((component) => component.fieldName)
const fieldValues = fieldNames.reduce(
Expand Down
10 changes: 10 additions & 0 deletions apps/metadata-editor/project.json
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,16 @@
"jestConfig": "apps/metadata-editor/jest.config.ts",
"passWithNoTests": true
}
},
"docker-build": {
"executor": "nx:run-commands",
"options": {
"commands": [
"nx build metadata-editor --base-href='/metadata-editor/'",
"docker build --build-arg APP_NAME=metadata-editor -f ./tools/docker/Dockerfile.apps . -t $(tools/print-docker-tag.sh metadata-editor)"
],
"parallel": false
}
}
},
"tags": ["type:app"]
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
<md-editor-records-list [title]="'dashboard.records.myRecords' | translate">
<md-editor-records-list
[title]="'dashboard.records.myRecords' | translate"
[linkToDatahub]="getDatahubUrl()"
>
</md-editor-records-list>
Original file line number Diff line number Diff line change
@@ -1,20 +1,41 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { MyRecordsComponent } from './my-records.component'
import { SearchFacade } from '@geonetwork-ui/feature/search'
import { Component, importProvidersFrom } from '@angular/core'
import { FieldsService, SearchFacade } from '@geonetwork-ui/feature/search'
import { Component, importProvidersFrom, Input } from '@angular/core'
import { TranslateModule } from '@ngx-translate/core'
import { RecordsListComponent } from '../records-list.component'
import { BehaviorSubject, of } from 'rxjs'
import { USER_FIXTURE } from '@geonetwork-ui/common/fixtures'
import { AuthService } from '@geonetwork-ui/api/repository/gn4'
import { EditorRouterService } from '../../router.service'

@Component({
// eslint-disable-next-line
selector: 'md-editor-records-list',
template: '',
standalone: true,
})
export class MockRecordsListComponent {}
export class MockRecordsListComponent {
@Input() linkToDatahub: string
}
const user = USER_FIXTURE()

class SearchFacadeMock {
resetSearch = jest.fn()
updateFilters = jest.fn()
}
class EditorRouterServiceMock {
getDatahubSearchRoute = jest.fn(() => `/datahub/`)
}

class AuthServiceMock {
user$ = new BehaviorSubject(user)
authReady = jest.fn(() => this._authSubject$)
_authSubject$ = new BehaviorSubject({})
}

class FieldsServiceMock {
buildFiltersFromFieldValues = jest.fn((val) => of(val))
}

describe('MyRecordsComponent', () => {
Expand All @@ -26,10 +47,22 @@ describe('MyRecordsComponent', () => {
TestBed.configureTestingModule({
providers: [
importProvidersFrom(TranslateModule.forRoot()),
{
provide: FieldsService,
useClass: FieldsServiceMock,
},
{
provide: SearchFacade,
useClass: SearchFacadeMock,
},
{
provide: AuthService,
useClass: AuthServiceMock,
},
{
provide: EditorRouterService,
useClass: EditorRouterServiceMock,
},
],
}).overrideComponent(MyRecordsComponent, {
remove: {
Expand All @@ -53,5 +86,18 @@ describe('MyRecordsComponent', () => {
it('clears filters on init', () => {
expect(searchFacade.resetSearch).toHaveBeenCalled()
})
it('Update filters on init', () => {
expect(searchFacade.updateFilters).toHaveBeenCalledWith({
owner: user.id,
})
})
})

describe('datahub url', () => {
it('get correct url', () => {
expect(component.getDatahubUrl()).toEqual(
'http://localhost/datahub/?owner=46798'
)
})
})
})
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import { Component } from '@angular/core'
import { Component, OnDestroy, OnInit } from '@angular/core'
import { CommonModule } from '@angular/common'
import { TranslateModule } from '@ngx-translate/core'
import { RecordsListComponent } from '../records-list.component'
import { SearchFacade } from '@geonetwork-ui/feature/search'
import { FieldsService, SearchFacade } from '@geonetwork-ui/feature/search'
import { AuthService } from '@geonetwork-ui/api/repository/gn4'
import { EditorRouterService } from '../../router.service'
import { Subscription } from 'rxjs'

@Component({
selector: 'md-editor-my-records',
Expand All @@ -11,8 +14,41 @@ import { SearchFacade } from '@geonetwork-ui/feature/search'
standalone: true,
imports: [CommonModule, TranslateModule, RecordsListComponent],
})
export class MyRecordsComponent {
constructor(public searchFacade: SearchFacade) {
export class MyRecordsComponent implements OnInit, OnDestroy {
private sub: Subscription
private ownerId: string

constructor(
public fieldsService: FieldsService,
public searchFacade: SearchFacade,
private authService: AuthService,
private router: EditorRouterService
) {}

ngOnInit() {
this.searchFacade.resetSearch()
this.sub = this.authService.user$.subscribe((user) => {
this.ownerId = user.id
this.fieldsService
.buildFiltersFromFieldValues({ owner: user.id })
.subscribe((filters) => {
this.searchFacade.updateFilters(filters)
})
})
}

getDatahubUrl(): string {
const url = new URL(
`${this.router.getDatahubSearchRoute()}`,
this.router.getDatahubSearchRoute().startsWith('http')
? this.router.getDatahubSearchRoute()
: window.location.toString()
)
url.searchParams.append('owner', this.ownerId)
return url.toString()
}

ngOnDestroy(): void {
this.sub.unsubscribe()
}
}
Loading

0 comments on commit c55b56f

Please sign in to comment.