Skip to content

Commit

Permalink
feat(editor): delete a record and its draft
Browse files Browse the repository at this point in the history
  • Loading branch information
LHBruneton-C2C committed Jul 29, 2024
1 parent 767ab89 commit de2f098
Show file tree
Hide file tree
Showing 18 changed files with 267 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { MatIconModule } from '@angular/material/icon'
import { RouterModule } from '@angular/router'
import { TranslateModule } from '@ngx-translate/core'
import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface'
import { map } from 'rxjs/operators'
import { map, startWith, switchMap } from 'rxjs/operators'
import { BadgeComponent } from '@geonetwork-ui/ui/inputs'

@Component({
Expand All @@ -22,9 +22,11 @@ import { BadgeComponent } from '@geonetwork-ui/ui/inputs'
],
})
export class DashboardMenuComponent {
draftsCount$ = this.recordsRepository
.getAllDrafts()
.pipe(map((drafts) => drafts.length))
draftsCount$ = this.recordsRepository.draftsChanged$.pipe(
startWith(void 0),
switchMap(() => this.recordsRepository.getAllDrafts()),
map((drafts) => drafts.length)
)

constructor(private recordsRepository: RecordsRepositoryInterface) {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ <h1 class="text-[16px] text-main font-title font-bold" translate>
<gn-ui-results-table
[records]="records$ | async"
[recordHasDraft]="hasDraft"
[recordIsDraft]="isDraft"
(recordClick)="editRecord($event)"
></gn-ui-results-table>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ import { startWith } from 'rxjs'
export class MyDraftComponent {
records$ = this.recordsRepository.getAllDrafts().pipe(startWith([]))
hasDraft = () => true
isDraft = () => true

constructor(
private router: Router,
Expand Down
15 changes: 13 additions & 2 deletions libs/api/repository/src/lib/gn4/gn4-repository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
from,
Observable,
of,
Subject,
switchMap,
throwError,
} from 'rxjs'
Expand All @@ -34,6 +35,9 @@ import { HttpErrorResponse } from '@angular/common/http'

@Injectable()
export class Gn4Repository implements RecordsRepositoryInterface {
_draftsChanged = new Subject<void>()
draftsChanged$ = this._draftsChanged.asObservable()

constructor(
private gn4SearchApi: SearchApiService,
private gn4SearchHelper: ElasticsearchService,
Expand Down Expand Up @@ -244,6 +248,7 @@ export class Gn4Repository implements RecordsRepositoryInterface {
this.getLocalStorageKeyForRecord(record.uniqueIdentifier),
xml
)
this._draftsChanged.next()
return [record, xml, false] as [CatalogRecord, string, false]
})
)
Expand Down Expand Up @@ -294,24 +299,30 @@ export class Gn4Repository implements RecordsRepositoryInterface {
)
}

deleteRecord(uniqueIdentifier: string): Observable<void> {
return this.gn4RecordsApi.deleteRecord(uniqueIdentifier)
}

saveRecordAsDraft(
record: CatalogRecord,
referenceRecordSource?: string
): Observable<string> {
return this.serializeRecordToXml(record, referenceRecordSource).pipe(
tap((recordXml) =>
tap((recordXml) => {
window.localStorage.setItem(
this.getLocalStorageKeyForRecord(record.uniqueIdentifier),
recordXml
)
)
this._draftsChanged.next()
})
)
}

clearRecordDraft(uniqueIdentifier: string): void {
window.localStorage.removeItem(
this.getLocalStorageKeyForRecord(uniqueIdentifier)
)
this._draftsChanged.next()
}

recordHasDraft(uniqueIdentifier: string): boolean {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,12 @@ export abstract class RecordsRepositoryInterface {
referenceRecordSource?: string
): Observable<string>

/**
* @param uniqueIdentifier
* @returns Observable<void> Returns when record is deleted
*/
abstract deleteRecord(uniqueIdentifier: string): Observable<void>

/**
* @param record
* @param referenceRecordSource
Expand All @@ -67,4 +73,5 @@ export abstract class RecordsRepositoryInterface {

/** will return all pending drafts, both published and not published */
abstract getAllDrafts(): Observable<CatalogRecord[]>
abstract draftsChanged$: Observable<void>
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
[sortOrder]="sortBy$ | async"
(recordClick)="handleRecordClick($event)"
(duplicateRecord)="handleDuplicateRecord($event)"
(deleteRecord)="handleDeleteRecord($event)"
(recordsSelectedChange)="handleRecordsSelectedChange($event[0], $event[1])"
(sortByChange)="handleSortByChange($event[0], $event[1])"
></gn-ui-results-table>
Original file line number Diff line number Diff line change
@@ -1,11 +1,14 @@
import { Component, EventEmitter, Output } from '@angular/core'
import { Component, EventEmitter, OnDestroy, Output } from '@angular/core'
import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record'
import { SearchFacade } from '../state/search.facade'
import { SelectionService } from '@geonetwork-ui/api/repository'
import { SearchService } from '../utils/service/search.service'
import { RecordsRepositoryInterface } from '@geonetwork-ui/common/domain/repository/records-repository.interface'
import { ResultsTableComponent } from '@geonetwork-ui/ui/search'
import { CommonModule } from '@angular/common'
import { Subscription } from 'rxjs'
import { NotificationsService } from '@geonetwork-ui/feature/notifications'
import { TranslateService } from '@ngx-translate/core'

@Component({
selector: 'gn-ui-results-table-container',
Expand All @@ -14,10 +17,12 @@ import { CommonModule } from '@angular/common'
standalone: true,
imports: [CommonModule, ResultsTableComponent],
})
export class ResultsTableContainerComponent {
export class ResultsTableContainerComponent implements OnDestroy {
@Output() recordClick = new EventEmitter<CatalogRecord>()
@Output() duplicateRecord = new EventEmitter<CatalogRecord>()

subscription = new Subscription()

records$ = this.searchFacade.results$
selectedRecords$ = this.selectionService.selectedRecordsIdentifiers$
sortBy$ = this.searchFacade.sortBy$
Expand All @@ -29,7 +34,9 @@ export class ResultsTableContainerComponent {
private searchFacade: SearchFacade,
private searchService: SearchService,
private selectionService: SelectionService,
private recordsRepository: RecordsRepositoryInterface
private recordsRepository: RecordsRepositoryInterface,
private notificationsService: NotificationsService,
private translateService: TranslateService
) {}

handleRecordClick(item: unknown) {
Expand All @@ -40,6 +47,32 @@ export class ResultsTableContainerComponent {
this.duplicateRecord.emit(item as CatalogRecord)
}

async handleDeleteRecord(item: unknown) {
const uniqueIdentifier = (item as CatalogRecord).uniqueIdentifier
this.subscription.add(
this.recordsRepository.deleteRecord(uniqueIdentifier).subscribe({
next: () => {
this.recordsRepository.clearRecordDraft(uniqueIdentifier)
this.searchFacade.requestNewResults()
},
error: (error) => {
this.notificationsService.showNotification({
type: 'error',
title: this.translateService.instant(
'editor.record.deleteError.title'
),
text: `${this.translateService.instant(
'editor.record.deleteError.body'
)} ${error}`,
closeMessage: this.translateService.instant(
'editor.record.deleteError.closeMessage'
),
})
},
})
)
}

handleSortByChange(col: string, order: 'asc' | 'desc') {
this.searchService.setSortBy([order, col])
}
Expand All @@ -51,4 +84,8 @@ export class ResultsTableContainerComponent {
this.selectionService.selectRecords(records)
}
}

ngOnDestroy() {
this.subscription.unsubscribe()
}
}
6 changes: 6 additions & 0 deletions libs/feature/search/src/lib/state/search.facade.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
Paginate,
RequestMoreOnAggregation,
RequestMoreResults,
RequestNewResults,
SetConfigAggregations,
SetConfigFilters,
SetConfigRequestFields,
Expand Down Expand Up @@ -151,6 +152,11 @@ export class SearchFacade {
return this
}

requestNewResults(): SearchFacade {
this.store.dispatch(new RequestNewResults(this.searchId))
return this
}

requestMoreOnAggregation(key: string, increment: number): SearchFacade {
this.store.dispatch(
new RequestMoreOnAggregation(key, increment, this.searchId)
Expand Down
1 change: 1 addition & 0 deletions libs/ui/elements/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export * from './lib/api-card/api-card.component'
export * from './lib/avatar/avatar.component'
export * from './lib/confirmation-dialog/confirmation-dialog.component'
export * from './lib/content-ghost/content-ghost.component'
export * from './lib/download-item/download-item.component'
export * from './lib/downloads-list/downloads-list.component'
Expand Down
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<h1 mat-dialog-title>{{ data.title }}</h1>
<div mat-dialog-content>{{ data.message }}</div>
<div mat-dialog-actions>
<gn-ui-button (buttonClick)="onCancel()">{{ data.cancelText }}</gn-ui-button>
<gn-ui-button (buttonClick)="onConfirm()" cdkFocusInitial class="ml-2">{{
data.confirmText
}}</gn-ui-button>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { ConfirmationDialogComponent } from './confirmation-dialog.component'

describe('ConfirmationDialogComponent', () => {
let component: ConfirmationDialogComponent
let fixture: ComponentFixture<ConfirmationDialogComponent>

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [ConfirmationDialogComponent],
}).compileComponents()
})

beforeEach(() => {
fixture = TestBed.createComponent(ConfirmationDialogComponent)
component = fixture.componentInstance
fixture.detectChanges()
})

it('should create', () => {
fixture.detectChanges()
expect(component).toBeTruthy()
})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import { Component, Input } from '@angular/core'
import { MatDialog } from '@angular/material/dialog'
import { ButtonComponent } from '@geonetwork-ui/ui/inputs'
import { Meta, moduleMetadata, StoryObj } from '@storybook/angular'
import { ConfirmationDialogComponent } from './confirmation-dialog.component'

@Component({
selector: 'gn-ui-launcher',
template: ` <gn-ui-button (buttonClick)="launch()">Open</gn-ui-button> `,
})
class LaunchDialogComponent {
@Input() title = ''
@Input() message = ''
@Input() confirmText = ''
@Input() cancelText = ''
constructor(private _dialog: MatDialog) {}

launch(): void {
this._dialog.open(ConfirmationDialogComponent, {
data: {
title: this.title,
message: this.message,
confirmText: this.confirmText,
cancelText: this.cancelText,
},
})
}
}

export default {
title: 'Elements/ConfirmationDialogComponent',
component: LaunchDialogComponent,
decorators: [
moduleMetadata({
imports: [ButtonComponent, ConfirmationDialogComponent],
}),
],
} as Meta

export const Primary: StoryObj<LaunchDialogComponent> = {
args: {
title: 'Some title',
message: 'Some message to confirm',
confirmText: 'OK',
cancelText: 'KO',
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import { ChangeDetectionStrategy, Component, Inject } from '@angular/core'
import {
MAT_DIALOG_DATA,
MatDialogModule,
MatDialogRef,
} from '@angular/material/dialog'
import { ButtonComponent } from '@geonetwork-ui/ui/inputs'

export interface ConfirmationDialogData {
title: string
message: string
confirmText: string
cancelText: string
}

@Component({
selector: 'gn-ui-confirmation-dialog',
templateUrl: './confirmation-dialog.component.html',
styleUrls: ['./confirmation-dialog.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: true,
imports: [MatDialogModule, ButtonComponent],
})
export class ConfirmationDialogComponent {
constructor(
public dialogRef: MatDialogRef<ConfirmationDialogComponent>,
@Inject(MAT_DIALOG_DATA) public data: ConfirmationDialogData
) {}

onConfirm() {
this.dialogRef.close(true)
}

onCancel() {
this.dialogRef.close(false)
}
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<gn-ui-button
type="outline"
type="light"
[matMenuTriggerFor]="menu"
(buttonClick)="openMenu()"
data-test="record-menu-button"
Expand All @@ -9,9 +9,18 @@
<mat-menu #menu="matMenu">
<button
mat-menu-item
[disabled]="isDraft"
(click)="duplicate.emit()"
data-test="record-menu-duplicate-button"
>
<span translate>record.action.duplicate</span>
</button>
<button
mat-menu-item
[disabled]="isDraft"
(click)="openDeleteConfirmationDialog()"
data-test="record-menu-delete-button"
>
<span translate>record.action.delete</span>
</button>
</mat-menu>
Loading

0 comments on commit de2f098

Please sign in to comment.