Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Fiche taxon] Ajout des informations de statuts dans la fiche taxon (onglet taxonomie + badges) #3191

Merged
merged 5 commits into from
Oct 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading