Skip to content

Commit

Permalink
[Fiche taxon] Ajout des informations de statuts dans la fiche taxon (…
Browse files Browse the repository at this point in the history
…onglet taxonomie + badges) (#3191)

* feat: add taxonomy tab + status badges to species page

* refact: move badge to a separate component

* feat: add status-badges component in GN2CommonModule

* feat: adjust species-sheet config structure

---------

Co-authored-by: jacquesfize <jacques.fize@ecrins-parcnational.fr>
  • Loading branch information
edelclaux and jacquesfize authored Oct 30, 2024
1 parent 4372f98 commit ca05cc0
Show file tree
Hide file tree
Showing 30 changed files with 452 additions and 590 deletions.
1 change: 1 addition & 0 deletions backend/geonature/utils/config_schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ class TaxonSheet(Schema):
# --------------------------------------------------------------------
# SYNTHESE - TAXON_SHEET
ENABLE_PROFILE = fields.Boolean(load_default=True)
ENABLE_TAXONOMY = fields.Boolean(load_default=True)


class Synthese(Schema):
Expand Down
2 changes: 2 additions & 0 deletions config/default_config.toml.example
Original file line number Diff line number Diff line change
Expand Up @@ -445,6 +445,8 @@ MEDIA_CLEAN_CRONTAB = "0 1 * * *"
# Options dédiées à la fiche taxon
# Permet d'activer ou non la section "Profile"
ENABLE_PROFILE = true
# Permet d'activer ou non la section "Taxonomy"
ENABLE_TAXONOMY = true

# Gestion des demandes d'inscription
[ACCOUNT_MANAGEMENT]
Expand Down
6 changes: 6 additions & 0 deletions frontend/src/app/GN2CommonModule/GN2Common.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { AreasIntersectedComponent } from './form/areas-intersected/areas-inters
import { AutoCompleteComponent } from '@geonature_common/form/autocomplete/autocomplete.component';
import { ConfirmationDialog } from '@geonature_common/others/modal-confirmation/confirmation.dialog';
import { DatalistComponent } from '@geonature_common/form/datalist/datalist.component';
import { BadgeComponent } from '@geonature_common/others/badge/badge.component';
import { BreadcrumbsComponent } from '@geonature_common/others/breadcrumbs/breadcrumbs.component';
import { DatasetsComponent } from './form/datasets/datasets.component';
import { DateComponent } from './form/date/date.component';
Expand Down Expand Up @@ -74,6 +75,7 @@ import { ObserversTextComponent } from '@geonature_common/form/observers-text/ob
import { PeriodComponent } from '@geonature_common/form/date/period.component';
import { PlacesComponent } from './map/places/places.component';
import { PlacesListComponent } from './map/placesList/placesList.component';
import { StatusBadgesComponent } from '@geonature_common/others/status-badges/status-badges.component';
import { SyntheseSearchComponent } from '@geonature_common/form/synthese-form/synthese-form.component';
import { TaxaComponent } from '@geonature_common/form/taxa/taxa.component';
import { TaxonAdvancedModalComponent } from '@geonature_common/form/synthese-form/advanced-form/synthese-advanced-form-component';
Expand Down Expand Up @@ -141,6 +143,7 @@ import { TaxonTreeComponent } from './form/taxon-tree/taxon-tree.component';
AreasComponent,
NomenclatureComponent,
ObserversComponent,
BadgeComponent,
BreadcrumbsComponent,
DateComponent,
TaxonomyComponent,
Expand Down Expand Up @@ -185,6 +188,7 @@ import { TaxonTreeComponent } from './form/taxon-tree/taxon-tree.component';
SafeHtmlPipe,
SyntheseSearchComponent,
SafeStripHtmlPipe,
StatusBadgesComponent,
StripHtmlPipe,
TaxaComponent,
TaxonAdvancedModalComponent,
Expand All @@ -208,6 +212,7 @@ import { TaxonTreeComponent } from './form/taxon-tree/taxon-tree.component';
AcquisitionFrameworksComponent,
AreasComponent,
MunicipalitiesComponent,
BadgeComponent,
BreadcrumbsComponent,
DynamicFormComponent,
NomenclatureComponent,
Expand Down Expand Up @@ -288,6 +293,7 @@ import { TaxonTreeComponent } from './form/taxon-tree/taxon-tree.component';
ReactiveFormsModule,
ReadablePropertiePipe,
SafeHtmlPipe,
StatusBadgesComponent,
TaxaComponent,
TaxonAdvancedModalComponent,
TaxonomyComponent,
Expand Down
4 changes: 4 additions & 0 deletions frontend/src/app/GN2CommonModule/form/data-form.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,10 @@ export class DataFormService {
});
}

fetchStatusSymbology() {
return this._http.get<any>(`${this.getTaxhubAPI()}/bdc_statuts/status_symbologies`);
}

getTaxaBibList() {
return this._http.get<any>(`${this.getTaxhubAPI()}/biblistes/`).pipe(map((d) => d.data));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ export interface Taxon {
nom_vern?: string;
ordre?: string;
phylum?: string;
statuts_protection?: any[];
status?: any[];
synonymes?: any[];
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<span
class="badge badge-secondary"
[style]="symbologyAsCSS"
matTooltip="{{ tooltip }}"
>
{{ text }}
</span>
15 changes: 15 additions & 0 deletions frontend/src/app/GN2CommonModule/others/badge/badge.component.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.badge {
--bgColor: #ffffff; // Default value
--textColor: #444; // Default value

display: flex;
flex-flow: row nowrap;
white-space: nowrap;
gap: 0.25rem;
text-transform: uppercase;
font-weight: bold;

background-color: var(--bgColor);
border: 2px solid color-mix(in srgb, var(--bgColor) 80%, black);
color: var(--textColor);
}
66 changes: 66 additions & 0 deletions frontend/src/app/GN2CommonModule/others/badge/badge.component.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { Component, Input } from '@angular/core';

// ////////////////////////////////////////////////////////////////////////////
// helper method
// ////////////////////////////////////////////////////////////////////////////

function isHexadecimalColor(color: string) {
return /^#[0-9A-F]{6}$/i.test(color);
}

function computeContrastColor(backgroundColor: string) {
// Convertir la couleur en un format RGB
const r = parseInt(backgroundColor.slice(1, 3), 16);
const g = parseInt(backgroundColor.slice(3, 5), 16);
const b = parseInt(backgroundColor.slice(5, 7), 16);

// Calculer la luminosité
const luminance = 0.299 * r + 0.587 * g + 0.114 * b;

// Retourner une couleur claire ou foncée selon la luminosité
return luminance < 128 ? '#ffffff' : '#444';
}

function colorToCSS(color: string) {
return `--bgColor: ${color}; --textColor: ${computeContrastColor(color)};`;
}

// ////////////////////////////////////////////////////////////////////////////
// Badge parameters
// ////////////////////////////////////////////////////////////////////////////

export interface BadgeSymbology {
color?: string;
}

// ////////////////////////////////////////////////////////////////////////////
// helper method
// ////////////////////////////////////////////////////////////////////////////

@Component({
selector: 'gn-badge',
templateUrl: 'badge.component.html',
styleUrls: ['badge.component.scss'],
})
export class BadgeComponent {
@Input()
text: string;

@Input()
tooltip: string;

symbologyAsCSS: string;

@Input()
set symbology(symbology: BadgeSymbology | null) {
this.symbologyAsCSS = '';
if (!symbology) {
return;
}
if (!isHexadecimalColor(symbology.color)) {
console.warn(`[badge] ${symbology.color} is not a valid hexadecimal color`);
return;
}
this.symbologyAsCSS = colorToCSS(symbology.color);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<div class="StatusBadges">
<gn-badge
*ngFor="let status of status"
[tooltip]="status.tooltip"
[text]="status.badge"
[symbology]="status.symbology"
/>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.StatusBadges {
display: flex;
flex-flow: row wrap;
width: 100%;
gap: 0.5rem;
line-height: inherit;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
import { Component, Input, OnInit } from '@angular/core';
import { TaxonSheetService } from '@geonature/syntheseModule/taxon-sheet/taxon-sheet.service';
import { DataFormService } from '@geonature_common/form/data-form.service';
import { Taxon } from '@geonature_common/form/taxonomy/taxonomy.component';
import { BadgeSymbology } from '@geonature_common/others/badge/badge.component';

interface Status {
badge: string;
tooltip: string;
symbology: BadgeSymbology | null;
}
@Component({
selector: 'gn-status-badges',
templateUrl: 'status-badges.component.html',
styleUrls: ['status-badges.component.scss'],
})
export class StatusBadgesComponent implements OnInit {
_taxon: Taxon | null;
_symbology: Array<{
types: Array<string>;
values: Record<string, BadgeSymbology>;
}>;
status: Array<Status> = [];

constructor(private _ds: DataFormService) {}

ngOnInit() {
this._ds.fetchStatusSymbology().subscribe((symbology) => {
this._symbology = [];
if (!symbology || !symbology.symbologies) {
return;
}
this._symbology = symbology.symbologies;

this.computeStatus();
});
}

_getSymbologyAsBadgeSymbology(type: string, value: string): BadgeSymbology | null {
if (!this._symbology) {
return null;
}
const symbologieItem = this._symbology.find((item) => item.types.includes(type));
if (!symbologieItem) {
return null;
}
if (!('color' in symbologieItem.values[value])) {
return null;
}
return {
color: symbologieItem.values[value].color,
};
}

@Input()
set taxon(taxon: Taxon | null) {
this._taxon = taxon;
this.computeStatus();
}

computeStatus() {
this.status = [];
if (!this._taxon) {
return;
}

for (const status of Object.values(this._taxon.status)) {
for (const text of Object.values<any>(status.text)) {
for (const value of Object.values<any>(text.values)) {
const badgeValue = ['true', 'false'].includes(value.code_statut)
? `${status.cd_type_statut}`
: `${status.cd_type_statut}: ${value.code_statut}`;

this.status.push({
badge: badgeValue,
tooltip: `${status.cd_type_statut} : ${value.display} - ${text.full_citation}`,
symbology: this._getSymbologyAsBadgeSymbology(status.cd_type_statut, value.code_statut),
});
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
<div class="Taxonomy">
<h5 class="Taxonomy__subtitle">Classification</h5>
<table class="Classification font-xs table table-striped table-sm">
<tbody>
<tr>
<td class="Classification__name">Groupe taxonomique</td>
<td class="Classification__value">{{ taxon?.classe }}</td>
</tr>
<tr>
<td class="Classification__name">Ordre</td>
<td class="Classification__value">{{ taxon?.ordre }}</td>
</tr>
<tr>
<td class="Classification__name">Famille</td>
<td
class="Classification__value"
data-qa="synthese-obs-detail-taxo-familly"
>
{{ taxon?.famille }}
</td>
</tr>
</tbody>
</table>

<!-- <h5 class="underlined underlined-sm main-color">Attribut(s) Taxonomique(s) locaux</h5>
<table class="font-xs table table-striped table-sm">
<tr
class="font-xs"
*ngFor="let attr of taxon?.attributs"
>
<td>
<b>{{ attr.label_attribut }}</b>
</td>
<td>{{ attr.valeur_attribut }}</td>
</tr>
</table> -->

<h5 class="Taxonomy__subtitle">Statuts</h5>
<table
class="font-xs table table-sm"
*ngIf="taxon?.status; else noStatus"
>
<ng-container *ngFor="let status of taxon?.status | keyvalue">
<tr class="table-primary">
<th>{{ status.value.display }}</th>
</tr>
<tr *ngFor="let text of status.value.text | keyvalue">
<td>
<ul class="list-unstyled mt-2">
<li
*ngIf="text.value.full_citation"
class="d-flex w-100 justify-content-between"
>
<span class="flex-shrink-1 w-75">
<strong [innerHtml]="text.value.full_citation | safeHTML"></strong>
<br />
({{ text.value.lb_adm_tr }} - {{ text.value.cd_sig }})
</span>
<a
*ngIf="text.value.doc_url"
class="btn align-self-start"
href="{{ text.value.doc_url }}"
mat-stroked-button
color="primary"
target="_blank"
>
Voir / Télécharger
<mat-icon aria-hidden="true">launch</mat-icon>
</a>
</li>
<li>
<span *ngFor="let value of text.value.values | keyvalue">
<strong *ngIf="value.value.code != 'true'">
{{ value.value.code_statut }}
</strong>
{{ value.value.label_statut }}
{{ value.value.rq_statut }}
</span>
</li>
</ul>
</td>
</tr>
</ng-container>
</table>
<ng-template #noStatus><p>Aucun</p></ng-template>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
.Taxonomy {
display: flex;
flex-flow: column;
justify-content: flex-start;
row-gap: 0.5rem;

&__subtitle {
text-decoration: underline;
text-decoration-color: currentColor;
text-underline-offset: 0.4rem;
text-decoration-thickness: 2px;
}
.Classification {
&__name {
font-weight: bold;
white-space: nowrap;
}
&__value {
width: 100%;
padding-left: 1rem;
}
}
}
Loading

0 comments on commit ca05cc0

Please sign in to comment.