Skip to content

Commit

Permalink
feat(metadata-editor): organize fields into pages and sections.
Browse files Browse the repository at this point in the history
  • Loading branch information
Romuald Caplier committed Jul 16, 2024
1 parent 55a2990 commit f100ab3
Show file tree
Hide file tree
Showing 33 changed files with 750 additions and 198 deletions.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<div class="w-full flex flex-row p-8 items-center gap-6">
<ng-container
*ngFor="let page of pages; let index = index; let isLast = last"
>
<div class="flex flex-row items-center gap-4">
<div class="flex flex-row items-center gap-4 hover:cursor-pointer">
<gn-ui-button
(buttonClick)="pageSectionClickHandler(index)"
class="flex flex-row items-center"
[type]="selectedPage === index ? 'primary' : 'default'"
extraClass="bg-transparent border-none"
>
<div
class="w-10 h-10 rounded-[8px] pt-3 text-center"
[ngClass]="
selectedPage === index ? 'bg-primary font-bold' : 'bg-gray-200'
"
>
{{ index }}
</div>
<div
class="ms-4"
[ngClass]="
selectedPage === index
? 'text-center text-black font-bold'
: 'text-gray-400'
"
translate
>
{{ page.label }}
</div>
</gn-ui-button>
</div>
<div *ngIf="!isLast" class="w-10">
<hr class="border-t-[2px]" />
</div>
</div>
</ng-container>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import { ComponentFixture, TestBed } from '@angular/core/testing'
import { TopToolbarComponent } from './top-toolbar.component'
import { Component } from '@angular/core'
import { PublishButtonComponent } from '../publish-button/publish-button.component'
import { BehaviorSubject } from 'rxjs'
import { EditorFacade } from '@geonetwork-ui/feature/editor'
import { TranslateModule } from '@ngx-translate/core'
import { BreadcrumbsComponent } from './breadcrumbs.component'

class EditorFacadeMock {
changedSinceSave$ = new BehaviorSubject(false)
alreadySavedOnce$ = new BehaviorSubject(false)
}

@Component({
selector: 'md-editor-publish-button',
template: '',
standalone: true,
})
class MockPublishButtonComponent {}

describe('BreadcrumbsComponent', () => {
let component: BreadcrumbsComponent
let fixture: ComponentFixture<BreadcrumbsComponent>
let editorFacade: EditorFacadeMock

beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [TopToolbarComponent, TranslateModule.forRoot()],
providers: [
{
provide: EditorFacade,
useClass: EditorFacadeMock,
},
],
})
.overrideComponent(TopToolbarComponent, {
add: {
imports: [MockPublishButtonComponent],
},
remove: {
imports: [PublishButtonComponent],
},
})
.compileComponents()

fixture = TestBed.createComponent(BreadcrumbsComponent)
component = fixture.componentInstance
editorFacade = TestBed.inject(EditorFacade) as any
fixture.detectChanges()
})

it('should create', () => {
expect(component).toBeTruthy()
})

describe('save status', () => {})
})
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import {
ChangeDetectionStrategy,
Component,
EventEmitter,
Input,
Output,
} from '@angular/core'
import { CommonModule } from '@angular/common'
import { PublishButtonComponent } from '../publish-button/publish-button.component'
import { ButtonComponent } from '@geonetwork-ui/ui/inputs'
import { MatIconModule } from '@angular/material/icon'
import { TranslateModule } from '@ngx-translate/core'
import { EditorFieldPage } from '@geonetwork-ui/feature/editor'

@Component({
selector: 'md-editor-breadcrumbs',
standalone: true,
imports: [
CommonModule,
PublishButtonComponent,
ButtonComponent,
MatIconModule,
TranslateModule,
],
templateUrl: './breadcrumbs.component.html',
styleUrls: ['./breadcrumbs.component.css'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
export class BreadcrumbsComponent {
@Input() selectedPage = 0
@Input() pages: EditorFieldPage[]

@Output() selectedPageChange = new EventEmitter<number>()

pageSectionClickHandler(index: number) {
this.selectedPageChange.emit(index)
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="flex flex-row items-center w-full">
<div class="flex flex-row items-center w-full border-b-[1px]">
<gn-ui-button type="light">
<mat-icon class="material-symbols-outlined">side_navigation</mat-icon>
</gn-ui-button>
Expand Down
45 changes: 36 additions & 9 deletions apps/metadata-editor/src/app/edit/edit-page.component.html
Original file line number Diff line number Diff line change
@@ -1,11 +1,38 @@
<div class="flex flex-col h-full">
<div class="w-full h-auto shrink-0">
<md-editor-top-toolbar></md-editor-top-toolbar>
</div>
<div class="grow overflow-auto relative">
<div class="absolute top-0 left-0 w-2/3 z-10 pointer-events-none">
<gn-ui-notifications-container></gn-ui-notifications-container>
<ng-container *ngIf="fields$ | async as fields">
<div class="flex flex-col h-full">
<div class="w-full h-auto shrink-0">
<md-editor-top-toolbar></md-editor-top-toolbar>
<md-editor-breadcrumbs
[pages]="fields.pages"
[selectedPage]="selectedPage"
(selectedPageChange)="selectedPageChange($event)"
></md-editor-breadcrumbs>
</div>
<div class="grow overflow-auto relative">
<div class="absolute top-0 left-0 w-2/3 z-10 pointer-events-none">
<gn-ui-notifications-container></gn-ui-notifications-container>
</div>
<gn-ui-record-form
[page]="fields.pages | find: selectedPage"
></gn-ui-record-form>
</div>
<div class="p-8 mt-auto flex flex-row justify-between">
<gn-ui-button
type="secondary"
(buttonClick)="previousPageButtonHandler()"
translate
>
{{
selectedPage === 0
? ('editor.record.form.bottomButtons.comeBackLater' | translate)
: ('editor.record.form.bottomButtons.previous' | translate)
}}
</gn-ui-button>
<gn-ui-button type="primary" (buttonClick)="nextPageButtonHandler()"
><span translate
>editor.record.form.bottomButtons.next</span
></gn-ui-button
>
</div>
<gn-ui-record-form></gn-ui-record-form>
</div>
</div>
</ng-container>
42 changes: 40 additions & 2 deletions apps/metadata-editor/src/app/edit/edit-page.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,14 @@ import {
NotificationsContainerComponent,
NotificationsService,
} from '@geonetwork-ui/feature/notifications'
import { TranslateService } from '@ngx-translate/core'
import { TranslateModule, TranslateService } from '@ngx-translate/core'
import { filter, Subscription, take } from 'rxjs'
import { FindPipe } from '../pipes/filter.pipe'
import { BreadcrumbsComponent } from './components/breadcrumbs/breadcrumbs.component'
import { marker } from '@biesbjerg/ngx-translate-extract-marker'

marker('editor.record.form.bottomButtons.comeBackLater')
marker('editor.record.form.bottomButtons.previous')

@Component({
selector: 'md-editor-edit',
Expand All @@ -29,18 +35,31 @@ import { filter, Subscription, take } from 'rxjs'
PublishButtonComponent,
TopToolbarComponent,
NotificationsContainerComponent,
FindPipe,
BreadcrumbsComponent,
TranslateModule,
],
})
export class EditPageComponent implements OnInit, OnDestroy {
subscription = new Subscription()

fields$ = this.facade.recordFields$
totalPages = 0
selectedPage = 0

constructor(
private route: ActivatedRoute,
private facade: EditorFacade,
private notificationsService: NotificationsService,
private translateService: TranslateService,
private router: Router
) {}
) {
this.subscription.add(
this.fields$.subscribe((fields) => {
this.totalPages = fields.pages.length
})
)
}

ngOnInit(): void {
const [currentRecord, currentRecordSource, currentRecordAlreadySaved] =
Expand Down Expand Up @@ -109,4 +128,23 @@ export class EditPageComponent implements OnInit, OnDestroy {
ngOnDestroy() {
this.subscription.unsubscribe()
}

previousPageButtonHandler() {
if (this.selectedPage === 0) {
this.router.navigate(['catalog', 'search'])
} else {
this.selectedPage--
}
}

nextPageButtonHandler() {
if (this.selectedPage === this.totalPages - 1) return
this.selectedPage++
}

selectedPageChange(index: number) {
this.selectedPage = index
}

protected readonly marker = marker
}
4 changes: 2 additions & 2 deletions apps/metadata-editor/src/app/pipes/filter.pipe.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { Pipe, PipeTransform } from '@angular/core'

@Pipe({
name: 'filter',
name: 'find',
standalone: true,
})
export class FilterPipe implements PipeTransform {
export class FindPipe implements PipeTransform {
transform(array: any[], index: number): any {
return array.find((item) => item.index === index)
}
Expand Down
6 changes: 1 addition & 5 deletions apps/metadata-editor/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,7 @@
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"target": "es2020",
"lib": [
"dom",
"es2020",
"dom.iterable"
],
"lib": ["dom", "es2020", "dom.iterable"],
"downlevelIteration": true
},
"angularCompilerOptions": {
Expand Down
4 changes: 2 additions & 2 deletions libs/feature/editor/src/lib/+state/editor.reducer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { Action, createReducer, on } from '@ngrx/store'
import * as EditorActions from './editor.actions'
import { CatalogRecord } from '@geonetwork-ui/common/domain/model/record'
import { SaveRecordError } from './editor.models'
import { EditorFieldsConfig } from '../models/fields.model'
import { EditorConfig } from '../models/fields.model'
import { DEFAULT_FIELDS } from '../fields.config'

export const EDITOR_FEATURE_KEY = 'editor'
Expand All @@ -22,7 +22,7 @@ export interface EditorState {
saving: boolean
saveError: SaveRecordError | null
changedSinceSave: boolean
fieldsConfig: EditorFieldsConfig
fieldsConfig: EditorConfig
}

export interface EditorPartialState {
Expand Down
18 changes: 13 additions & 5 deletions libs/feature/editor/src/lib/+state/editor.selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,9 +41,17 @@ export const selectRecordFieldsConfig = createSelector(

export const selectRecordFields = createSelector(
selectEditorState,
(state: EditorState) =>
state.fieldsConfig.map((fieldConfig) => ({
config: fieldConfig,
value: state.record?.[fieldConfig.model] ?? null,
}))
(state: EditorState) => {
const fieldsConfig = state.fieldsConfig
fieldsConfig.pages.forEach((page) => {
page.sections.forEach((section) => {
section.fields.forEach((field) => {
if (state.record) {
field.value = state.record[field.model]
}
})
})
})
return fieldsConfig
}
)
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<ng-template #withGenericWrapper>
<gn-ui-form-field-wrapper
[label]="config.labelKey | translate"
[hint]="config.hintKey | translate"
[hint]="config.hintKey! | translate"
>
<ng-container *ngTemplateOutlet="fieldContent"></ng-container>
</gn-ui-form-field-wrapper>
Expand All @@ -15,22 +15,22 @@
<ng-template #fieldContent>
<ng-container *ngIf="isTitle">
<div class="flex justify-between items-center gap-3">
<h2
<span
#titleInput
class="grow text-3xl font-normal"
class="grow font-petrona text-3xl font-normal"
[gnUiEditableLabel]="true"
(editableLabelChanged)="formControl.setValue($event)"
>
{{ formControl.value }}
</h2>
</span>
<span
class="material-symbols-outlined gn-ui-icon-small m-2 cursor-pointer"
(click)="focusTitleInput()"
>edit</span
>
<span
class="material-symbols-outlined gn-ui-icon-small m-2"
[matTooltip]="config.hintKey | translate"
[matTooltip]="config.hintKey! | translate"
matTooltipPosition="above"
>
help
Expand All @@ -42,7 +42,7 @@
class="h-[8rem]"
[control]="formControl"
[label]="config.labelKey | translate"
[hint]="config.hintKey | translate"
[hint]="config.hintKey! | translate"
></gn-ui-form-field-rich>
</ng-container>
<ng-container *ngIf="isLicenses">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ import { FormFieldObjectComponent } from './form-field-object/form-field-object.
import { FormFieldRichComponent } from './form-field-rich/form-field-rich.component'
import { FormFieldSimpleComponent } from './form-field-simple/form-field-simple.component'
import { FormFieldSpatialExtentComponent } from './form-field-spatial-extent/form-field-spatial-extent.component'
import { FormFieldConfig } from './form-field.model'
import { FormFieldUpdateFrequencyComponent } from './form-field-update-frequency/form-field-update-frequency.component'
import { CatalogRecordKeys } from '@geonetwork-ui/common/domain/model/record'
import { FormFieldKeywordsComponent } from './form-field-keywords/form-field-keywords.component'
import { FormFieldConfig } from '../../../models/fields.model'

@Component({
selector: 'gn-ui-form-field',
Expand Down Expand Up @@ -65,6 +65,7 @@ export class FormFieldComponent {
emitEvent: false,
})
}

@Output() valueChange: Observable<unknown>

@ViewChild('titleInput') titleInput: ElementRef
Expand Down
Loading

0 comments on commit f100ab3

Please sign in to comment.