Skip to content

Commit

Permalink
admin: uniformize fields display in detailed views
Browse files Browse the repository at this point in the history
* Removes useless detailed views.
* Redirects to the search view after record edition.
* Uses short editor when it is possible.
* Uses a generic component to display fields in detailed views.
* Removes useless test files.

Co-Authored-by: Johnny Mariéthoz <[email protected]>
  • Loading branch information
jma committed Jul 24, 2024
1 parent 1978bb7 commit f41d920
Show file tree
Hide file tree
Showing 20 changed files with 576 additions and 956 deletions.
1 change: 0 additions & 1 deletion angular.json
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@
"extractLicenses": true,
"vendorChunk": false,
"buildOptimizer": true,
"optimization": true,
"budgets": [
{
"type": "initial",
Expand Down
31 changes: 11 additions & 20 deletions projects/sonar/src/app/app-routing.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,8 +41,6 @@ import { OrganisationComponent } from './record/organisation/organisation.compon
import { BriefViewComponent as ProjectBriefViewComponent } from './record/project/brief-view/brief-view.component';
import { DetailComponent as ProjectDetailComponent } from './record/project/detail/detail.component';
import { BriefViewComponent as SubdivisionBriefViewComponent } from './record/subdivision/brief-view/brief-view.component';
import { DetailComponent as SubdivisionDetailComponent } from './record/subdivision/detail/detail.component';
import { DetailComponent as UserDetailComponent } from './record/user/detail/detail.component';
import { UserComponent } from './record/user/user.component';
import { UserService } from './user.service';

Expand Down Expand Up @@ -298,11 +296,8 @@ export class AppRoutingModule {
{
type: 'users',
briefView: UserComponent,
detailView: UserDetailComponent,
aggregationsOrder: ['subdivision'],
editorSettings: {
longMode: true,
},
redirectUrl: (record: any) => of(`/records/users?q=pid:${record.metadata.pid}`),
sortOptions: [
{
label: _('Relevance'),
Expand Down Expand Up @@ -362,12 +357,12 @@ export class AppRoutingModule {
label: 'Research projects',
briefView: ProjectBriefViewComponent,
detailView: projectDetail$,
editorSettings: {
longMode: true,
},
recordResource: true,
aggregationsExpand: ['organisation', 'user'],
aggregationsOrder: ['organisation', 'user', 'status'],
editorSettings: {
longMode: true,
},
exportFormats: [
{
label: 'CSV',
Expand Down Expand Up @@ -401,9 +396,6 @@ export class AppRoutingModule {
briefView: CollectionBriefViewComponent,
detailView: CollectionDetailComponent,
files: fileConfig,
editorSettings: {
longMode: true,
},
sortOptions: [
{
label: _('Relevance'),
Expand All @@ -421,10 +413,7 @@ export class AppRoutingModule {
type: 'subdivisions',
label: 'Subdivisions',
briefView: SubdivisionBriefViewComponent,
detailView: SubdivisionDetailComponent,
editorSettings: {
longMode: true,
},
redirectUrl: (record: any) => of(`/records/subdivisions?q=pid:${record.metadata.pid}`),
sortOptions: [
{
label: _('Relevance'),
Expand All @@ -449,12 +438,11 @@ export class AppRoutingModule {
}

recordsRoutesConfiguration.forEach((config: any) => {
const route = {
const route: any = {
matcher: (url: any) => this._routeMatcher(url, config.type),
canActivate: mapToCanActivate([RoleGuard]),
children: [
{ path: '', component: RecordSearchPageComponent },
{ path: 'detail/:pid', component: DetailComponent },
{ path: 'edit/:pid', component: EditorComponent },
{ path: 'new', component: EditorComponent, canActivate: mapToCanActivate([CanAddGuard]) }
],
Expand All @@ -466,7 +454,8 @@ export class AppRoutingModule {
key: config.type,
label: config.label || config.type.charAt(0).toUpperCase() + config.type.slice(1),
component: config.briefView || null,
editorSettings: config.editorSettings || false,
editorSettings: config.editorSettings || {},
redirectUrl: config.redirectUrl || null,
detailComponent: config.detailView || null,
aggregations: config.aggregations || null,
aggregationsExpand: config.aggregationsExpand || [],
Expand All @@ -485,7 +474,9 @@ export class AppRoutingModule {
]
}
};

if (config.detailView) {
route.children.push({ path: 'detail/:pid', component: DetailComponent });
}
this._router.config[0].children.push(route);
});
}
Expand Down
16 changes: 7 additions & 9 deletions projects/sonar/src/app/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ import { TabsModule } from 'ngx-bootstrap/tabs';
import { TooltipModule } from 'ngx-bootstrap/tooltip';
import { NgxDropzoneModule } from 'ngx-dropzone';
import { ToastrModule } from 'ngx-toastr';
import { DividerModule } from 'primeng/divider';
import { CarouselModule } from 'primeng/carousel';
import { DividerModule } from 'primeng/divider';
import { DropdownModule } from 'primeng/dropdown';
import { FileUploadModule } from 'primeng/fileupload';
import { InputTextModule } from 'primeng/inputtext';
Expand All @@ -44,6 +44,7 @@ import { AppInitializerService } from './app-initializer.service';
import { AppRoutingModule } from './app-routing.module';
import { AppTranslateLoader } from './app-translate-loader';
import { AppComponent } from './app.component';
import { FieldDescriptionComponent } from './core/field-description/field-description.component';
import { FileLinkPipe } from './core/file-link.pipe';
import { FileSizePipe } from './core/filesize.pipe';
import { HighlightJsonPipe } from './core/highlight-json.pipe';
Expand All @@ -57,6 +58,7 @@ import { ReviewComponent } from './deposit/review/review.component';
import { UploadComponent } from './deposit/upload/upload.component';
import { HttpInterceptor } from './interceptor/http.interceptor';
import { ContributorsPipe } from './pipe/contributors.pipe';
import { FaIconClassPipe } from './pipe/fa-icon-class.pipe';
import { LanguageValuePipe } from './pipe/language-value.pipe';
import { BriefViewComponent as CollectionBriefViewComponent } from './record/collection/brief-view/brief-view.component';
import { DetailComponent as CollectionDetailComponent } from './record/collection/detail/detail.component';
Expand All @@ -67,6 +69,8 @@ import { DocumentComponent } from './record/document/document.component';
import { FileComponent } from './record/document/file/file.component';
import { PublicationPipe } from './record/document/publication.pipe';
import { FileItemComponent } from './record/files/file-item/file-item.component';
import { OtherFilesComponent } from './record/files/other-files/other-files.component';
import { StatsFilesComponent } from './record/files/stats-files/stats-files.component';
import { UploadFilesComponent } from './record/files/upload-files/upload-files.component';
import { DetailComponent as HepvsProjectDetailComponent } from './record/hepvs/project/detail/detail.component';
import { IdentifierComponent } from './record/identifier/identifier.component';
Expand All @@ -75,14 +79,9 @@ import { OrganisationComponent } from './record/organisation/organisation.compon
import { BriefViewComponent as ProjectBriefViewComponent } from './record/project/brief-view/brief-view.component';
import { DetailComponent as ProjectDetailComponent } from './record/project/detail/detail.component';
import { BriefViewComponent as SubdivisionBriefViewComponent } from './record/subdivision/brief-view/brief-view.component';
import { DetailComponent as SubdivisionDetailComponent } from './record/subdivision/detail/detail.component';
import { DetailComponent as UserDetailComponent } from './record/user/detail/detail.component';
import { UserComponent } from './record/user/user.component';
import { ValidationComponent } from './record/validation/validation.component';
import { UserService } from './user.service';
import { OtherFilesComponent } from './record/files/other-files/other-files.component';
import { FaIconClassPipe } from './pipe/fa-icon-class.pipe';
import { StatsFilesComponent } from './record/files/stats-files/stats-files.component';

export function appInitializerFactory(appInitializerService: AppInitializerService): () => Promise<any> {
return () => appInitializerService.initialize().toPromise();
Expand All @@ -100,7 +99,6 @@ export function minElementError(err: any, field: FormlyFieldConfig) {
UserComponent,
DocumentDetailComponent,
OrganisationDetailComponent,
UserDetailComponent,
JoinPipe,
LanguageValuePipe,
DashboardComponent,
Expand All @@ -124,15 +122,15 @@ export function minElementError(err: any, field: FormlyFieldConfig) {
CollectionBriefViewComponent,
CollectionDetailComponent,
SubdivisionBriefViewComponent,
SubdivisionDetailComponent,
ContributorsPipe,
ContributionsComponent,
ContributionComponent,
UploadFilesComponent,
FileItemComponent,
OtherFilesComponent,
FaIconClassPipe,
StatsFilesComponent
StatsFilesComponent,
FieldDescriptionComponent
],
imports: [
BrowserModule,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@

@if (field()) {
<div class="grid">
<dt class="col-4">{{ label() }}</dt>
<dd class="col mb-0">
@if(type() == 'array') {

Check failure on line 6 in projects/sonar/src/app/core/field-description/field-description.component.html

View workflow job for this annotation

GitHub Actions / build (18.x)

Expected `===` but received `==`

Check failure on line 6 in projects/sonar/src/app/core/field-description/field-description.component.html

View workflow job for this annotation

GitHub Actions / build (20.x)

Expected `===` but received `==`
<ul class="list-none p-0 mb-0">
@for (value of field(); track value; let last=$last; let index=$index) {
<li>
@if (template) {
<ng-container
*ngTemplateOutlet="template; context: { $implicit: value, last, index }"/>
} @else {
{{ value }}
}
</li>
}
</ul>
}
@else {
@if (template) {
<ng-container
*ngTemplateOutlet="template; context: { $implicit: field() }"/>
} @else {
{{ field() }}
}
}
</dd>
</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import { AfterContentInit, Component, ContentChildren, QueryList, TemplateRef, computed, input } from '@angular/core';
import { PrimeTemplate } from 'primeng/api';
import { Nullable } from 'primeng/ts-helpers';

@Component({
selector: 'sonar-field-description',
templateUrl: './field-description.component.html'
})
export class FieldDescriptionComponent implements AfterContentInit {
label = input<string>();
field = input<any>();
type = computed(() => this.getType());
template: Nullable<TemplateRef<any>>;

@ContentChildren(PrimeTemplate) templates: QueryList<PrimeTemplate> | null;

ngAfterContentInit() {
(this.templates as QueryList<PrimeTemplate>).forEach((item) => {
switch (item.getType()) {
case 'template':
this.template = item.template;
break;
}
});
}
getType() {
const field = this.field();
if (Array.isArray(field)) {
return 'array';
}
return typeof field;
}
}
77 changes: 0 additions & 77 deletions projects/sonar/src/app/deposit/upload/upload.component.spec.ts

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
<!--
SONAR User Interface
Copyright (C) 2021 RERO

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.

You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
SONAR User Interface
Copyright (C) 2021 RERO
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, version 3 of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<ng-container *ngIf="record$ | async as record">
<h1 class="mb-4">{{ record.metadata.name | languageValue | async }}</h1>
<dl class="row mt-4">
<ng-container *ngIf="record.metadata.description">
<dt class="col-sm-3" translate>Description</dt>
<dd class="col-sm-9" [innerHtml]="record.metadata.description | languageValue | async | markdown"></dd>
</ng-container>
</dl>
@if(record.metadata.description) {
<h4 translate>Description</h4>
<p [innerHtml]="record.metadata.description | languageValue | async | markdown"></p>
}
</ng-container>
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
<ng-container *ngVar="contributions|contributors:meeting as contributors">
<ng-container *ngIf="contributors.length > 0">
<div class="my-2" *ngIf="!additionalInfosFields; else additionalInfoField">
<ul class="list-unstyled m-0">
<ul class="list-none p-0 mb-0">
<ng-container *ngFor="let contributor of contributors|slice:0:contributorsLength">
<li>
<sonar-contribution [contributor]="contributor" viewType="detail"></sonar-contribution>
Expand All @@ -29,11 +29,11 @@
</a>
</div>
<ng-template #additionalInfoField>
<dl class="row mb-0">
<dt class="col-lg-4" translate>Conference</dt>
<dd class="col-lg-8">
<ul class="list-unstyled mb-0">
<li class="p-0" *ngFor="let contributor of contributors|slice:0:contributorsLength">
<dl class="grid mb-0">
<dt class="col-4" translate>Conference</dt>
<dd class="col mb-0">
<ul class="list-none p-0 mb-0">
<li *ngFor="let contributor of contributors|slice:0:contributorsLength">
<sonar-contribution [contributor]="contributor" viewType="detail"></sonar-contribution>
</li>
</ul>
Expand Down
Loading

0 comments on commit f41d920

Please sign in to comment.