some minor changes

parent fb3d6220
......@@ -71,18 +71,25 @@
"tsConfig": "tsconfig.app.json",
"assets": [
"src/favicon.ico",
"src/assets"
"src/assets",
{
"glob": "**/*",
"input": "./node_modules/ngx-extended-pdf-viewer/assets/",
"output": "/assets/"
}
],
"styles": [
"src/styles.css",
"./src/theme.css",
"./node_modules/primeicons/primeicons.css",
"./node_modules/primeng/resources/themes/mdc-light-indigo/theme.css",
"./node_modules/primeng/resources/primeng.css",
"./node_modules/primeflex/primeflex.css",
"./node_modules/quill/dist/quill.core.css",
"./node_modules/quill/dist/quill.snow.css"
],
"scripts": []
"scripts": [
"./node_modules/quill/dist/quill.js"
]
},
"configurations": {
"production": {
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -10,42 +10,46 @@
},
"private": true,
"dependencies": {
"@angular/animations": "~13.2.6",
"@angular/common": "~13.2.6",
"@angular/compiler": "~13.2.6",
"@angular/core": "~13.2.6",
"@angular/forms": "~13.2.6",
"@angular/platform-browser": "~13.2.6",
"@angular/platform-browser-dynamic": "~13.2.6",
"@angular/router": "~13.2.6",
"@ngxs/storage-plugin": "^3.5.0",
"@ngxs/store": "^3.5.0",
"@angular/animations": "~17.3.6",
"@angular/common": "~17.3.6",
"@angular/compiler": "~17.3.6",
"@angular/core": "~17.3.6",
"@angular/forms": "~17.3.6",
"@angular/platform-browser": "~17.3.6",
"@angular/platform-browser-dynamic": "~17.3.6",
"@angular/router": "~17.3.6",
"@ngxs/storage-plugin": "^3.8.2",
"@ngxs/store": "^3.8.2",
"lazysizes": "^5.3.2",
"ng-lazyload-image": "^9.1.2",
"ngx-clipboard": "~15.1.0",
"primeflex": "~3.1.3",
"primeicons": "~5.0.0",
"primeng": "~13.2.1",
"quill": "^1.3.7",
"rxjs": "~6.6.0",
"tslib": "^2.1.0",
"zone.js": "~0.11.4"
"ng-lazyload-image": "^9.1.3",
"ng2-pdf-viewer": "^9.0.0",
"ngx-clipboard": "~16.0.0",
"package.json": "^2.0.1",
"primeflex": "^3.3.1",
"primeicons": "^7.0.0",
"primeng": "^17.13.0",
"quill": "^2.0.0",
"rxjs": "~7.8.1",
"tslib": "^2.6.2",
"zone.js": "~0.14.4",
"ngx-extended-pdf-viewer": "^19.0.0"
},
"devDependencies": {
"@angular-devkit/build-angular": "^13.2.6",
"@angular/cdk": "~13.2.6",
"@angular/cli": "~13.2.6",
"@angular/compiler-cli": "~13.2.6",
"@angular/localize": "~13.2.6",
"@types/jasmine": "~3.10.3",
"@types/node": "^14.0.0",
"jasmine-core": "~4.0.1",
"karma": "~6.3.0",
"karma-chrome-launcher": "~3.1.0",
"karma-coverage": "~2.0.3",
"karma-jasmine": "~4.0.0",
"karma-jasmine-html-reporter": "^1.5.0",
"@angular-devkit/build-angular": "^17.3.6",
"@angular/cdk": "~17.3.6",
"@angular/cli": "~17.3.6",
"@angular/compiler-cli": "~17.3.6",
"@angular/localize": "~17.3.6",
"@types/jasmine": "~5.1.4",
"@types/node": "^18.19.31",
"jasmine-core": "~5.1.2",
"karma": "~6.4.3",
"karma-chrome-launcher": "~3.2.0",
"karma-coverage": "~2.2.1",
"karma-jasmine": "~5.1.0",
"karma-jasmine-html-reporter": "^2.1.0",
"lite-server": "^2.6.1",
"typescript": "~4.4.2"
"typescript": "~5.4.5"
}
}
......@@ -9,6 +9,8 @@ import {AuthGuard} from "./guard/auth.guard";
import {ChangePasswordComponent} from "./component/change-password/change-password.component";
import {HelpComponent} from "./component/help/help.component";
import {AppComponent} from "./app.component";
import {ETrainingComponent} from "./component/e-training/e-training.component";
import {RequestResourceComponent} from "./component/request-resource/request-resource.component";
const routes: Routes = [
{path: '', component: HomeComponent, pathMatch: 'full'},
......@@ -16,12 +18,15 @@ const routes: Routes = [
{path: 'home', component: HomeComponent, pathMatch: 'full'},
{path:'resource/approve', component:ApproveResourceComponent, pathMatch:'full',canActivate:[AuthGuard]},
{path:'resource/add', component:AddResourceComponent, pathMatch:'full'},
{path:'resource/request', component:RequestResourceComponent, pathMatch:'full'},
{path:'resource/edit/:id',component:AddResourceComponent,pathMatch:'full',canActivate:[AuthGuard]},
{path:'resource/:id/:lang', component:ResourceComponent, pathMatch:'full'},
{path:'resource/:id', component:ResourceComponent, pathMatch:'full'},
{path:'login', component:LoginComponent, pathMatch:'full'},
{path:'help', component:HelpComponent, pathMatch:'full'},
{path:'changePassword/:token', component:ChangePasswordComponent, pathMatch:'full'}
{path:'changePassword/:token', component:ChangePasswordComponent, pathMatch:'full'},
{path:'e_training', component:ETrainingComponent, pathMatch:'full'}
......
......@@ -11,7 +11,7 @@ import {AccordionModule} from 'primeng/accordion';
import {MessageService, SharedModule} from "primeng/api";
import {CheckboxModule} from 'primeng/checkbox';
import {FormsModule, ReactiveFormsModule} from "@angular/forms";
import {DataViewModule} from "primeng/dataview";
import { DataViewModule } from 'primeng/dataview';
import {RatingModule} from "primeng/rating";
import {HTTP_INTERCEPTORS, HttpClientModule} from "@angular/common/http";
import {MultiSelectModule} from 'primeng/multiselect';
......@@ -59,6 +59,11 @@ import {DividerModule} from 'primeng/divider';
import {ProgressSpinner, ProgressSpinnerModule} from "primeng/progressspinner";
import {TabViewModule} from 'primeng/tabview';
import {EditorModule} from "primeng/editor";
import { ETrainingComponent } from './component/e-training/e-training.component';
import {OrderListModule} from "primeng/orderlist";
import { RequestResourceComponent } from './component/request-resource/request-resource.component';
import {PdfViewerModule} from "ng2-pdf-viewer";
import {NgxExtendedPdfViewerModule} from "ngx-extended-pdf-viewer";
@NgModule({
declarations: [
......@@ -72,58 +77,63 @@ import {EditorModule} from "primeng/editor";
FooterComponent,
ChangePasswordComponent,
CheckPasswordDirective,
HelpComponent
HelpComponent,
ETrainingComponent,
RequestResourceComponent,
],
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
MenubarModule,
ButtonModule,
MenuModule,
AccordionModule,
SharedModule,
FormsModule,
DataViewModule,
RatingModule,
HttpClientModule,
MultiSelectModule,
DropdownModule,
InputTextModule,
TooltipModule,
CardModule,
TagModule,
InputTextModule,
CheckboxModule,
ButtonModule,
RadioButtonModule,
InputTextareaModule,
FileUploadModule,
ChipsModule,
MessagesModule,
MessageModule,
ToastModule,
PanelModule,
CascadeSelectModule,
DialogModule,
TableModule,
NgxsModule.forRoot([UserState], {developmentMode: !environment.production}),
NgxsStoragePluginModule.forRoot(),
ReactiveFormsModule,
ToastModule,
ImageModule,
ConfirmPopupModule,
ConfirmDialogModule,
LazyLoadImageModule,
BadgeModule,
ClipboardModule,
AvatarModule,
AvatarGroupModule,
DividerModule,
ProgressSpinnerModule,
TabViewModule,
EditorModule,
OrderListModule,
PdfViewerModule,
NgxExtendedPdfViewerModule,
],
imports: [
BrowserModule,
BrowserAnimationsModule,
AppRoutingModule,
MenubarModule,
ButtonModule,
MenuModule,
AccordionModule,
SharedModule,
FormsModule,
DataViewModule,
RatingModule,
HttpClientModule,
MultiSelectModule,
DropdownModule,
InputTextModule,
TooltipModule,
CardModule,
TagModule,
InputTextModule,
CheckboxModule,
ButtonModule,
RadioButtonModule,
InputTextareaModule,
FileUploadModule,
ChipsModule,
MessagesModule,
MessageModule,
ToastModule,
PanelModule,
CascadeSelectModule,
DialogModule,
TableModule,
NgxsModule.forRoot([UserState], {developmentMode: !environment.production}),
NgxsStoragePluginModule.forRoot(),
ReactiveFormsModule,
ToastModule,
ImageModule,
ConfirmPopupModule,
ConfirmDialogModule,
LazyLoadImageModule,
BadgeModule,
ClipboardModule,
AvatarModule,
AvatarGroupModule,
DividerModule,
ProgressSpinnerModule,
TabViewModule,
EditorModule
],
providers: [MessageService,ConfirmationService,
{provide: LocationStrategy, useClass: HashLocationStrategy},
{
......@@ -134,4 +144,5 @@ import {EditorModule} from "primeng/editor";
],
bootstrap: [AppComponent]
})
export class AppModule { }
export class AppModule {
}
......@@ -15,7 +15,7 @@
<div class="field grid">
<label for="description" class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{long_desc}">Long description (in English, 500 words)</label>
<div class="col-12 md:col-10">
<textarea id="description" name="description" #description='ngModel' type="text" rows="4" pInputTextarea [(ngModel)]="resource.description" required [ngClass]="!description.valid ? 'ng-invalid ng-dirty' : ''"></textarea>
<textarea id="description" name="description" #description='ngModel' type="text" rows="10" pInputTextarea [(ngModel)]="resource.description" required [ngClass]="!description.valid ? 'ng-invalid ng-dirty' : ''"></textarea>
<!-- <p-editor required id="description" name="descridescription" #description='ngModel' [(ngModel)]="resource.description" [style]="{'height':'320px'}" [ngClass]="!description.valid ? 'ng-invalid ng-dirty' : ''"></p-editor>-->
<div [hidden]="description.valid" class="text-xs p-error" i18n="@@{long_required}">
Long description is required
......@@ -26,8 +26,8 @@
<div class="field grid">
<label for="descriptionNative" class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{long_native}">Long description (in native language, if not English, 500 words)</label>
<div class="col-12 md:col-10">
<textarea id="descriptionNative" name="descriptionNative" type="text" rows="4" pInputTextarea [(ngModel)]="resource.descriptionNative"></textarea>
. </div>
<textarea id="descriptionNative" name="descriptionNative" type="text" rows="10" pInputTextarea [(ngModel)]="resource.descriptionNative"></textarea>
</div>
</div>
<div class="field grid">
<label class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{sectors}">Sectors</label>
......@@ -95,7 +95,7 @@
<div class="field grid">
<label class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{resourceType}">Resource type</label>
<div class="col-12 md:col-10">
<p-dropdown [options]="resourceTypes" [required]="true" #resourceType='ngModel' dataKey="name" name="resourceTypes" optionLabel="{{locale === 'en' ? 'name' : 'name_'+locale}}" i18n-placeholder="@@{select_resource_type}" [(ngModel)]="resource.resourceType" [ngClass]="!resourceType.valid ? 'ng-invalid ng-dirty' : ''"></p-dropdown>
<p-dropdown [options]="resourceTypes" [required]="true" placeholder="Select resource type" #resourceType='ngModel' dataKey="name" name="resourceTypes" optionLabel="{{locale === 'en' ? 'name' : 'name_'+locale}}" i18n-placeholder="@@{select_resource_type}" [(ngModel)]="resource.resourceType" [ngClass]="!resourceType.valid ? 'ng-invalid ng-dirty' : ''"></p-dropdown>
<div [hidden]="resourceType.valid" class="text-xs p-error" i18n="@@{resource_type_required}">
Resource type is required
</div>
......@@ -104,7 +104,7 @@
<div class="field grid">
<label class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{language}">Resource language</label>
<div class="col-12 md:col-10">
<p-dropdown [showClear]=true [options]="languages" name="language" id="language" dataKey="name" optionLabel="{{locale === 'en' ? 'name' : 'name_'+locale}}" i18n-defaultLabel="@@{select_language}" [(ngModel)]="resource.language"></p-dropdown>
<p-dropdown [showClear]=true [options]="languages" name="language" id="language" dataKey="name" optionLabel="{{locale === 'en' ? 'name' : 'name_'+locale}}" placeholder="Select resource type"i18n-placeholder="@@{select_language}" [(ngModel)]="resource.language"></p-dropdown>
</div>
</div>
<!--ne vidim smisao dodavanja slika kad se nigde ne prikazuje-->
......@@ -143,13 +143,13 @@
<div class="field grid" *ngIf="!edit">
<label class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{upload_resource}">Upload resource content</label>
<div class="col-12 md:col-10">
<p-fileUpload name="resources" required [multiple]=true [fileLimit]=5 i18n-chooseLabel="@@{choose}" chooseLabel="Choose" [maxFileSize]=10242880 [auto]=true [showUploadButton]=false [customUpload]=true (uploadHandler)="fileUploader('content',$event)"></p-fileUpload>
<p-fileUpload name="resources" required [multiple]=true [fileLimit]=10 i18n-chooseLabel="@@{choose}" chooseLabel="Choose" [maxFileSize]=10242880 [auto]=true [showUploadButton]=false [customUpload]=true (uploadHandler)="fileUploader('content',$event)"></p-fileUpload>
</div>
</div>
<div class="field grid" *ngIf="edit">
<label class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{upload_resource}">Change resource content</label>
<div class="col-12 md:col-10 ">
<p-panel class="col-12 md:col-10 p-d-block">
<p-panel class="col-12 md:col-10 p-d-block" *ngIf="resource.files != undefined && resource.files.length >0">
<div *ngFor="let file of resource.files" class="flex justify-content-between mb-2 ">
<div class="col-8 md:col-8">
<button pButton type="button" label="{{file.description}}" class="p-button-link button-link text-left" (click)="downloadFile(file.description)"></button>
......@@ -157,7 +157,7 @@
<div class="col-2 md:col-2"><button pButton type="button" label="Delete" icon="pi pi-trash" (click)="delete(file.fileIdentifier)" [loading]="false" class="p-button-danger"></button></div>
</div>
</p-panel>
<p-fileUpload name="resources" required [multiple]=true [fileLimit]=5 i18n-chooseLabel="@@{choose}" chooseLabel="Choose" [maxFileSize]=5242880 [auto]=true [showUploadButton]=false [customUpload]=true (uploadHandler)="fileUploader('content',$event)"></p-fileUpload>
<p-fileUpload name="resources" required [multiple]=true [fileLimit]=10 i18n-chooseLabel="@@{choose}" chooseLabel="Choose" [maxFileSize]=5242880 [auto]=true [showUploadButton]=false [customUpload]=true (uploadHandler)="fileUploader('content',$event)"></p-fileUpload>
</div>
</div>
......@@ -174,9 +174,33 @@
</div>
</div>
<div class="field grid">
<label class="col-12 mb-2 md:col-2 md:mb-0"i18n="@@{link_restriction}">Up to 5 links to further reading</label>
<label class="col-12 mb-2 md:col-2 md:mb-0"i18n="@@{link_restriction}">Up to 10 links to further reading</label>
<div class="col-12 md:col-10 flex flex-wrap">
<ng-container *ngFor="let link of resource.links; let linkIndex = index; trackBy:track;" >
<div class="col-5 pr-2 pb-2 pl-0">
<input pInputText type="text" name="linktitle_{{linkIndex}}" [(ngModel)]="link.name" placeholder="Link title" />
</div>
<div class="col-5 pr-2 pb-2">
<input pInputText type="text" name="linkurl_{{linkIndex}}" [(ngModel)]="link.url" placeholder="Link URL"/>
</div>
<div *ngIf="linkIndex==0" class="col-1 pb-2">
<button pButton type="button" (click)="addNewLink()" icon="pi pi-plus" [disabled]="resource.links?.length==10"></button>
</div>
<div class="col-1 pb-2">
<button *ngIf="linkIndex !=0" pButton type="button" icon="pi pi-trash" class="p-button-danger" (click)="removeLink(linkIndex)"></button>
</div>
</ng-container>
<!-- <p-chips [(ngModel)]="resource.links" name="links" [max]=5 i18n-placeholder="@@{enter_links}" placeholder="Enter relevant links" [allowDuplicate]=false></p-chips>-->
</div>
</div>
<div class="field grid">
<label class="col-12 mb-2 md:col-2 md:mb-0"i18n="@@{youtube}">Add youtube link</label>
<div class="col-12 md:col-10">
<p-chips [(ngModel)]="resource.links" name="links" [max]=5 i18n-placeholder="@@{enter_links}" placeholder="Enter relevant links" [allowDuplicate]=false></p-chips>
<input id="youtube" type="text" name="youtube" pInputText [(ngModel)]="resource.youtube">
</div>
</div>
......@@ -208,7 +232,7 @@
<div class="col-12 field-checkbox">
<p-checkbox [(ngModel)]="termChecked" [binary]="true" name="termCheckede" id="termChecked" [ngClass]="!termChecked? 'ng-invalid ng-dirty' : ''"></p-checkbox>
<label for="termChecked"><ng-container i18n="@@{termCondition1}">by ticking this box you confirm that you have read and accept</ng-container> <a href="https://ipmworks.net/ipmworks/file/get/63b6b7c0d7f8f46f5b2a28b3"><ng-container i18n="@@{part1}"> Part 1 </ng-container></a>
<ng-container i18n="@@{termCondition2}">of the Toolbox Terms and Conditions. You can contact </ng-container><a href="mailto:IPMWORKS-WP4@inrae.fr">IPMWORKS-WP4@inrae.fr </a> <ng-container i18n="@@{termCondiotion3}">at any time to amend or remove your submission.</ng-container>
<ng-container i18n="@@{termCondition2}">of the Toolbox Terms and Conditions. You can contact </ng-container><a href="mailto:IPMWORKS-WP4@inrae.fr">IPMWORKS-WP4&#64;inrae.fr </a> <ng-container i18n="@@{termCondiotion3}">at any time to amend or remove your submission.</ng-container>
</label>
<!-- <button pButton type="button" (click)="showTerms()" label="Toolbox Terms and Conditions" [ngStyle]="{color:'var(--red-500)'}" class="p-button-link pl-2"></button>
<p-dialog header="Terms and Conditions" [(visible)]="displayTerms" [style]="{width: '50vw'}">
......@@ -220,12 +244,12 @@
</div>
</div>
<div class="col-12 pt-3 justify-content-center flex" *ngIf="!edit">
<p-button i18n-label="@@{back}" label="Back" icon="pi pi-step-backward" class="pr-5"routerLink="/home" type="button" ></p-button>
<p-button i18n-label="save_resource" label="Save resource" icon="pi pi-save" [loading]="false" type="submit" [disabled]="resourceForm.form.invalid || !termChecked"></p-button>
<p-button i18n-label="@@{back}" label="Back" class="pr-5"routerLink="/home" type="button" ></p-button>
<p-button i18n-label="save_resource" label="Save resource" [loading]="false" type="submit" [disabled]="resourceForm.form.invalid || !termChecked"></p-button>
</div>
<div class="col-12 pt-3 justify-content-center flex" *ngIf="edit" >
<p-button i18n-label="@@{back}" label="Back" icon="pi pi-step-backward" class="pr-5"routerLink="/resource/{{resource.idResource}}" type="button" ></p-button>
<p-button i18n-label="save_resource" label="Save resource" icon="pi pi-save" [loading]="false" type="submit" [disabled]="resourceForm.form.invalid || !termChecked"></p-button>
<p-button i18n-label="@@{back}" label="Back" class="pr-5"routerLink="/resource/{{resource.idResource}}" type="button" ></p-button>
<p-button i18n-label="save_resource" label="Save resource" [loading]="false" type="submit" [disabled]="resourceForm.form.invalid || !termChecked"></p-button>
</div>
</div>
</form>
......@@ -269,3 +293,5 @@
</div>
</p-dialog>
<p-confirmDialog></p-confirmDialog>
import {Component, Inject, LOCALE_ID, OnInit} from '@angular/core';
import {ResourceType, Language, Region, Sector, Project, Resource, Pest, Crop} from "../../model/resource";
import {ResourceType, Language, Region, Sector, Project, Resource, Pest, Crop, Link} from "../../model/resource";
import {ResourceService} from "../../service/resource.service";
import {ConfirmationService, MessageService} from 'primeng/api';
import {ActivatedRoute, Router} from "@angular/router";
......@@ -38,7 +38,6 @@ export class AddResourceComponent implements OnInit {
logoExist:boolean = false;
displayTerms = false;
termChecked = false;
constructor(private resourceService:ResourceService, private route: ActivatedRoute, private messageService: MessageService, private router: Router, @Inject(LOCALE_ID) public locale: string, private confirmationService: ConfirmationService) { }
ngOnInit(): void {
......@@ -72,6 +71,9 @@ export class AddResourceComponent implements OnInit {
this.resourceService.hasImage(this.resourceId,"logo").subscribe( data =>{
this.logoExist = data
});
}else{
this.resource.links = []
this.resource.links.push({name:"",url:""})
}
}
......@@ -122,6 +124,7 @@ export class AddResourceComponent implements OnInit {
this.resource.pests = selectedPests;
this.resource.pests.push(this.newPest);
this.pests.push(this.newPest);
this.resourceService.addCrop(this.newPest).subscribe()
this.newPest={};
this.displayPestModal=false;
}
......@@ -139,6 +142,7 @@ export class AddResourceComponent implements OnInit {
this.resource.crops = selectedCrops;
this.resource.crops.push(this.newCrop);
this.crops.push(this.newCrop);
this.resourceService.addCrop(this.newCrop).subscribe()
this.newCrop={};
this.displayCropModal=false;
}
......@@ -189,4 +193,20 @@ export class AddResourceComponent implements OnInit {
console.log(error)
});
}
addNewLink() {
// @ts-ignore
this.resource.links.push({
name: "",
url: "",
});
}
removeLink( linkIndex: number) {
// @ts-ignore
this.resource.links.splice(linkIndex, 1);
}
track(index: number, item: Link) {
return index;
}
}
.archived{
opacity: 50%;
background-color: lightgray !important;
}
......@@ -11,10 +11,10 @@
</tr>
</ng-template>
<ng-template pTemplate="body" let-resource>
<tr>
<tr [ngClass]="{'archived':resource.hide}">
<td>{{resource.resourceName}}</td>
<td>{{resource.resourceType?.name}}</td>
<td>{{resource.creationDate| date:"d.M.yyyy, h:mm a"}}</td>
<td>{{resource.creationDate| date:"dd.MM.yyyy, h:mm a"}}</td>
<td i18n>Manually</td>
<td>
<button pButton type="button" routerLink="/resource/{{resource.idResource}}" icon="pi pi-pencil"></button>
......
<div class="card pt-6 pl-6 pr-6">
<div class="mb-3 flex">
<img class="col-12" src="assets/e-learning.png">
</div>
<h2>H2020 IPMWORKS e-learning training modules</h2>
<div class="text-justify mb-3">
The IPMWORKS e-learning modules have been prepared based on successful experiences within the project network, including technical aspects of IPM strategies, farm performance or co-innovation and method for farm hub coaching, targeting both farmers and advisers. Modules on agroecosystem approach, on holistic pest management examples and on the key topic of policies are also included to frame the technical ones. </div>
<div class="text-justify mb-3">
The materials that compose the modules focus on IPM technical aspects, IPM efficiency to gain sustainability, and methods for coaching farmers towards the adoption of cost-effective IPM strategies, based on both existing IPM resources and holistic management examples produced by the IPMWORKS network. These materials consist of, on the one hand, presentations reflecting the theoretical content and the selected resources for each theme, and, on the other hand, recorded videos of the lectures of these presentations.</div>
<div class="text-justify mb-3">
These module packages can be adapted to national needs and local contexts, since they have been produced to be used like an interactive training catalogue. In line with this purpose, the modules are divided in short chapters, enabling the access to specific chapters according to the national needs and local contexts of the modules’ users. </div>
<p-accordion >
<p-accordionTab class="text-xl" header="Module 1: Agrosystem/Agroecosystem: Concepts and theory. Holistic approach to IPM">
<div class="text-justify text-base">
Module 1 focuses on the concepts and theory of agro-ecosystems, including the holistic approach of IPM. It begins by outlining what an agro-ecosystem is and what the objectives are for the progress of agriculture in the world. It also introduces the three groups of organisms that cause crop losses along with the impact of arthropod pests, diseases and weeds on crop yields. In addition, it introduces landscape ecology and epidemiology and agro-ecosystem management and the holistic concept of IPM. The module contains a case study: protected crops, which exposes the evolution of pest control in EU greenhouses, and the introduction of biological control. In terms of the Agroecosystem and the limitations for IPM implementation, the case study presents tools for managing the landscape around the greenhouses in order to facilitate the colonisation by beneficial insects.
<p>Module leaders: Joaquín Balduque (IAMZ-CIHEAM), Antonio López-Francos (IAMZ-CIHEAM) and Ramón Albajes, University of Lleida (external collaborator, IAMZ-CIHEAM).</p>
<div class="text-base">
<p><a href="https://ipmworks.net/toolbox/#/resource/65aa8e5d97c50523c43c57af" target="_blank">1.0. Introduction</a></p>
<p><a href="https://ipmworks.net/toolbox/#/resource/65aa8f6197c50523c43c57b3" target="_blank">1.1. What an agroecosystem is</a></p>
<p><a href="https://ipmworks.net/toolbox/#/resource/65aa902697c50523c43c57b8" target="_blank">1.2. Objectives for the progress of agriculture in the World: simultaneous increase of the productivity and sustainability</a></p>
<p><a href="https://ipmworks.net/toolbox/#/resource/65aa90d497c50523c43c57bd" target="_blank">1.3. The three groups of organisms that cause crop losses</a></p>
<p><a href="https://ipmworks.net/toolbox/#/resource/65aa918d97c50523c43c57c5" target="_blank">1.4. Impact of arthropods pests, diseases, and weeds on crop yield</a></p>
<p><a href="https://ipmworks.net/toolbox/#/resource/65aa921f97c50523c43c57c9" target="_blank">1.5. Landscape ecology & epidemiology and agroecosystem management</a></p>
<p><a href="https://ipmworks.net/toolbox/#/resource/65aa92c897c50523c43c57cd" target="_blank">1.6. A general survey of agroecosystem management for IPM. Holistic IPM concept</a></p>
<p><a href="https://ipmworks.net/toolbox/#/resource/65aa934297c50523c43c57d1" target="_blank">1.7. Two case studies: protected and arable crops</a></p>
<p><a href="https://ipmworks.net/toolbox/#/resource/65aa93b897c50523c43c57d9" target="_blank">1.8. Open questions for reflection and discussion</a></p>
</div>
</div>
</p-accordionTab>
<p-accordionTab class="text-xl" header="Module 2: Plant health risk challenges and Policy context in the EU">
<div class="text-justify text-base">
Module 2 presents the Plant health risk challenges and Policy context in the EU. It starts presenting the risks and challenges for Plant Health in the present decade, including pest resurgence and emerging risks and also addressing the current EU legislation. Examples of resurgent pests are included for arthropod pests (Frankliniella occidentalis), plant pathogens (Xylella fastidiosa) and weeds (Amaranthus palmeri), including the risk factors for each of them. Furthermore, Module 2 presents a case study based on how the SUD has been implemented in Denmark and exposes new and future EU legislation on pesticides and a closer look on the IPM principles.
<p>Module leaders: Per Kudsk (AU) and Ramón Albajes, University of Lleida (external collaborator, IAMZ-CIHEAM).</p>
<div>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aa944c97c50523c43c57dd" target="_blank">2.1. Risks and Challenges for Plant Health in the present decade. Pest resurgence and emerging risks</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aa94cf97c50523c43c57e3" target="_blank">2.2. Current EU legislation</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aa954597c50523c43c57e7" target="_blank">2.3. Case study: How the SUD has been implemented in Denmark</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aa95df97c50523c43c57eb" target="_blank">2.4. New and future EU legislation on pesticides and a closer look on the IPM principles</a></p>
</div>
</div>
</p-accordionTab>
<p-accordionTab class="text-xl" header="Module 3: Integrated Weed Management (IWM)">
<div class="text-justify text-base">
Module 3 starts presenting the principles of IWM and the biology of weeds. For the technical aspects of IWM, this module strongly relies on material previously released by the H2020 IWMPRAISE project. This material is presenting a comprehensive number of IWM tactics, accessible for the IPMWORKS e-learning modules users. These resources include available IWM tools for Perennial crops / Narrow row crops / Broad row crops and perennial weeds / annual weeds. The IWMPRAISE booklets of experimental trials in Europe are also presented, including results, tools and strategies identified in Denmark, Spain, France, Switzerland, Italy, Netherlands, Slovenia, and United Kingdom. Furthermore, IWMPRAISE sheets, made as one-pagers which give a short and concise description of each IWM tool or tactic are also introduced. The IPM strategy of cultivar choice is also exposed, in the case study of winter wheat. As a complement to IWMPRAISE material, this module includes two case studies, namely the case study based on an 18-year IWM experiment in arable field crops in France, and the case study of an IWM experiment on arable vegetables in The Netherlands. Case studies outline a number of IPM tools for preventing establishment and competition and reducing multiplication of weeds, along with results on cost-efficiency. <p>Module leaders: Nicolas Munier-Jolain (INRAE), Mette Sønderskov (AU) and Marleen Riemens (WR).</p>
<div>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aa96a797c50523c43c57f0" target="_blank">3.1. Introduction to integrated weed management</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aa973e97c50523c43c57f5" target="_blank">3.2. Principles of IWM, triangles and hexagons</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aa97cf97c50523c43c57fc" target="_blank">3.3. The biology of weeds</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aa97cf97c50523c43c57fc" target="_blank">3.4. Individual IWM tactics</a></p>
<p class="pl-4"><a href="https://ipmworks.net/toolbox/en/#/resource/65aa991a97c50523c43c5805" target="_blank">3.4.1. Choosing a cultivar with high competitive ability</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aa99f297c50523c43c580b" target="_blank">3.5. Case study #1 French case, arable crops</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aa9ccd97c50523c43c5812" target="_blank">3.6. Case study #2 Dutch case, arable vegetables</a></p>
</div>
</div>
</p-accordionTab>
<p-accordionTab class="text-xl" header="Module 4: Integrated Disease Management (IDM)">
<div class="text-justify text-base">
Module 4 focuses on diseases management and on the challenges we are facing in agriculture, considering three main aspects, which are climate change, the need and request to reduce the use of plant protection products, and last but not least, the resistance management. The module gets into the context of Sustainable Agriculture and applied epidemiology for disease control. In addition, it presents 3 cases studies: Arable crops (wheat), Horticultural crops (processing tomato) and Perennial crops (grapevine). This module introduces the multiple modelling approach Decision Support Systems (DSSs). The content present different IPM tools for the following crops / diseases with 3 cases studies: i) Wheat / Fusarium head blight, ii) Tomato / Downy mildew, Alternaria leaf blight and Bacteriosis and iii) Grapevine / Downy mildew.
<p>Module leader: Tito Caffi (UCSC).</p>
<div>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aa9e5797c50523c43c581c" target="_blank">4.1. Current challenges in disease control</a></p>
<p><a href="https://ipmworks.net/toolbox/#/resource/65aa9ec597c50523c43c5829" target="_blank">4.2. Disease management in the context of Sustainable Agriculture</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aa9f3e97c50523c43c5833" target="_blank">4.3. Applied epidemiology for disease control</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aa9fba97c50523c43c583b" target="_blank">4.4. Case study. Arable crops: wheat</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aaa02b97c50523c43c5846" target="_blank">4.5. Case study. Horticultural crops: processing tomato</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65aaa08f97c50523c43c584e" target="_blank">4.6. Case study. Perennial crops: grapevine</a></p>
</div>
</div>
</p-accordionTab>
<p-accordionTab class="text-xl" header="Module 5: Integrated Invertebrate Pest Management (IIPM)">
<div class="text-justify text-base">
Module 5 focuses on invertebrate pest management. This module introduces the concept of the art of doing nothing as a core philosophy for pest management. And finally, the wide range of IPM tactics available for invertebrate pest management are introduced. Specific examples on IPM tactics are provided in the rest of the module.
<p>Module leader: Mark Ramsden (ADAS) and Eleanor Dearlove (ADAS).</p>
<div>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae3c7b97c50523c43c5860" target="_blank">5.1. Introduction to Invertebrate Pest Management</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae3cfb97c50523c43c586d" target="_blank">5.2. Injury and damage caused by invertebrate pests</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae3d7397c50523c43c5882" target="_blank">5.3. Agronomic, mechanical, and physical management options</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae3de597c50523c43c588d" target="_blank">5.4. Decision Support Systems and monitoring as part of Invertebrate IPM</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae3e5a97c50523c43c5897" target="_blank">5.5. Biocontrol of invertebrate pests</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae3ed797c50523c43c58b0" target="_blank">5.6. Synthetic Chemical Pesticides Resistance Management</a></p>
</div>
</div>
</p-accordionTab>
<p-accordionTab class="text-xl" header="Module 6: Holistic IPM examples">
<div class="text-justify text-base">
Module 6: Holistic IPM examples presents one chapter per each of the 5 agricultural sectors represented in IPMWORKS: arable crops, vineyard, orchards, vegetables, and horticulture, including different holistic IPM strategies in each of these sectors.
<p>Module leaders: Joaquín Balduque (IAMZ-CIHEAM), Antonio López-Francos (IAMZ-CIHEAM), Carlos Lozano, Aragon Government (external collaborator, IAMZ-CIHEAM), Geert Kessel (WUR), David Lafond (ACTA/IFV), Dieter Depraetere (INAGRO) and Eduardo Crisol (COEXPHAL).</p>
<div>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae40fc97c50523c43c58b5" target="_blank">6.1. Orchards. Carlos Lozano, Aragon Government (external collaborator, IAMZ-CIHEAM).</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae418b97c50523c43c58d1" target="_blank">6.2. Arable crops. Geert Kessel (WUR).</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae420797c50523c43c58db" target="_blank">6.3. Vineyards. David Lafond (ACTA/IFV).</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae427897c50523c43c58ec" target="_blank">6.4. Outdoor vegetables. Dieter Depraetere (INAGRO).</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae42f197c50523c43c58f7" target="_blank">6.5. Greenhouse – horticulture. Eduardo Crisol (COEXPHAL).</a></p>
</div>
</div>
</p-accordionTab>
<p-accordionTab class="text-xl" header="Module 7: Assessment of an IPM system">
<div class="text-justify text-base">
Module 7 cover the Assessment of an IPM system. It presents how, when redesigning cropping and farming systems to adopt more IPM so as to reduce pesticides use, we need to be aware of the diversity of assessment topics. This is important, both to convince farmers to adopt IPM and to inform policymakers about the consequences of promoting the adoption of IPM.
<p>Module leader: Nicolas Munier-Jolain (INRAE).</p>
<div>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae438097c50523c43c5919" target="_blank">7.1. Introduction</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae43f397c50523c43c591d" target="_blank">7.2. Measuring pesticide use and impact</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae446197c50523c43c5922" target="_blank">7.3. Assessment of cost-efficiency of low-pesticide IPM-based cropping system </a></p>
</div>
</div>
</p-accordionTab>
<p-accordionTab class="text-xl" header="Module 8: Soft skills for facilitating interactive learning and demonstration on IPM">
<div class="text-justify text-base">
Module 8 is dedicated to technical methods of implementation of IPM, social skills and group coaching for advisors and collective coaching of farmers through peer-to-peer learning and in-farm co-innovation processes. Given the changes in practices, it is important to ensure how they can be facilitated with farmers. The (new) approach for advisors engaged in coaching farmers towards more holistic IPM requires a balance between being an expert and being a facilitator. The module relies on experiences in the IPMWORKS project farmer groups that we call hubs, coordinated by so-called hub coaches.
<p>Module leaders: Calypso Picaud (APCA/CRAO), Laure Triste (EVILVO), Simon Lox (EVILVO), Seerp Wigboldus (WR) and Harm Brinks (DELPHY).</p>
<div>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae44e297c50523c43c592a" target="_blank">8.0. Introduction</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae45fd97c50523c43c5931" target="_blank">8.1. Changing role of advisors</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae491e97c50523c43c593a" target="_blank">8.2. Tools for developing and facilitating a meeting</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae498797c50523c43c5944" target="_blank">8.3. Facilitation of group meeting</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae49fe97c50523c43c594c" target="_blank">8.4. Let’s talk about IPM</a></p>
<p><a href="https://ipmworks.net/toolbox/en/#/resource/65ae4bc297c50523c43c5952" target="_blank">8.5. Soft skills for facilitating interactive learning and demonstration of IPM</a></p>
</div>
</div>
</p-accordionTab>
</p-accordion>
</div>
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ETrainingComponent } from './e-training.component';
describe('ETrainingComponent', () => {
let component: ETrainingComponent;
let fixture: ComponentFixture<ETrainingComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ ETrainingComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(ETrainingComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-e-training',
templateUrl: './e-training.component.html',
styleUrls: ['./e-training.component.css']
})
export class ETrainingComponent implements OnInit {
constructor() { }
ngOnInit(): void {
}
}
.footer{
background-image: url('/toolbox/assets/footer.jpg');
background-image: url('/toolbox/en/assets/footer.jpg');
height: 415px;
background-position: center;
padding: 0;
}
.footer-ribbon{
background-color: #00662e;
background-color: #097b32;
color:white;
}
.footer-white{
......
<footer class="footer flex align-items-end col-12">
<footer class="footer flex align-items-end xl:col-12">
<div class="footer-white flex flex-row">
<div>
<img src="">
......@@ -10,9 +10,9 @@
<img src="">
</div>
</div>
<div class="footer-ribbon flex col-12 align-items-center">
<div class="footer-ribbon xl:flex xl:col-12 align-items-center">
<div class="pl-8 pt-2">
<img src="assets/EUFlag.png"/>
<img src="assets/EUFlag.png" style="height: 50px;"/>
</div>
<div>
<p class="pl-5 pt-2 align-self-center" i18n="@@{project_ack}">
......
<p-menubar [model]="items" [ngStyle]="{'display': hideheader}">
<ng-template pTemplate="start">
<a href="http://ipmworks.net">
<img src="assets/logo.jpg" height="97" class="pl-6 mr-8" alt="brand logo">
<img src="assets/logo.jpg" height="97" class="lg:pl-6 lg:mr-8" alt="brand logo">
</a>
</ng-template>
<ng-template pTemplate="end">
......
......@@ -46,6 +46,12 @@ export class HeaderMenuComponent implements OnInit,OnDestroy{
target:"_blank"
},
{
label: $localize `E-trainings`,
url:'#/e_training',
styleClass:"pr-2",
target:"_blank"
},
{
label: $localize `Approve`,
routerLink:'/resource/approve',
styleClass:"pr-2",
......@@ -70,7 +76,7 @@ export class HeaderMenuComponent implements OnInit,OnDestroy{
visible:this.logged
},
{
label: $localize `Login`,
label: $localize `Admin Login`,
routerLink:'/login',
styleClass:"pr-2",
visible:!this.logged
......@@ -135,8 +141,8 @@ export class HeaderMenuComponent implements OnInit,OnDestroy{
return logged;
}
ngOnDestroy(): void {
this.destroyed.next();
this.destroyed.complete();
//this.destroyed.next();
//this.destroyed.complete();
}
......
......@@ -39,3 +39,26 @@
cursor: pointer;
}
@media only screen and (min-width: 1441px) {
.fillimg {
background-repeat: no-repeat !important;
background-size: contain !important;
min-height: 200px !important
}
.fixheight {
min-height: 190px !important;
}
}
@media only screen and (max-width: 1440px) {
.fillimg {
background-repeat: no-repeat !important;
background-size: contain !important;
min-height: 140px !important
}
.fixheight {
min-height: 190px !important;
}
}
<p-messages severity="info" [enableService]="false" *ngIf="!close">
<p-messages [styleClass]="'button-light-green'" [enableService]="false" *ngIf="!close">
<ng-template pTemplate>
<span class="p-message-icon pi pi-info-circle"></span>
<span class="p-message-summary" i18n>Disclaimer</span>
......@@ -7,40 +7,26 @@
</ng-template>
</p-messages>
<div class="grid pt-6 pl-6 flex-wrap">
<div class="md:col-3">
<div class="grid md:pt-6 md:pl-6 flex-wrap">
<div class="xl:col-2 col-12">
<form #searchForm="ngForm" (ngSubmit)="searchResource()">
<p class="text-xl" i18n="@@{sectors}">Sectors</p>
<p-multiSelect i18n-defaultLabel="@@{select_sector}" defaultLabel="Select sector" [options]="sectors" name="sector" [(ngModel)]="searchModel.sector" optionLabel="{{locale === 'en' ? 'name' : 'name_'+locale}}">
<p-multiSelect i18n-placeholder="@@{select_sector}" placeholder="Select sector" [options]="sectors" name="sector" [(ngModel)]="searchModel.sector" optionLabel="{{locale === 'en' ? 'name' : 'name_'+locale}}">
</p-multiSelect>
<p class="text-xl" i18n="@@{country_origin}">Country of origin</p>
<p-multiSelect i18n-defaultLabel="@@{select_region}" defaultLabel="Select region" [options]="regions" name="region" [(ngModel)]="searchModel.region" optionLabel="{{locale === 'en' ? 'name' : 'name_'+locale}}"></p-multiSelect>
<!-- <div class="field">
<p class="text-xl">Pest type</p>
<p-dropdown autoWidth="false" [style]="{'width':'100%'}" placeholder="Select pest type" [options]="pestType" name="pestType"[(ngModel)]="searchModel.pestType" optionLabel="name" ></p-dropdown>
</div>-->
<p-multiSelect i18n-placeholder="@@{select_region}" placeholder="Select region" [options]="regions" name="region" [(ngModel)]="searchModel.region" optionLabel="{{locale === 'en' ? 'name' : 'name_'+locale}}"></p-multiSelect>
<p class="text-xl" i18n="@@{project}">Project</p>
<p-dropdown autoWidth="false" [style]="{'width':'100%'}" i18n-placeholder="@@{select_project}" placeholder="Select project" [(ngModel)]="searchModel.project" [options]="projects" name="project" optionLabel="name" ></p-dropdown>
<p-dropdown autoWidth="false" [style]="{'width':'100%'}" i18n-placeholder="@@{select_project}" placeholder="Select project" [(ngModel)]="searchModel.project" [options]="projects" name="project" optionLabel="name" ></p-dropdown>
<p class="text-xl" i18n="@@{resource_types}">Resource types</p>
<p-multiSelect i18n-placeholder="@@{select_resource_type}" placeholder="Select resource type" name="resourceType" [(ngModel)]="searchModel.resourceType" [options]="contentTypes" optionLabel="{{locale === 'en' ? 'name' : 'name_'+locale}}">
</p-multiSelect>
<div class="button-right pt-3" *ngIf="!more">
<button pButton type="button" i18n-pTooltip="@@{more_filters}" pTooltip="More filters..." icon="pi pi-plus" class="p-button-text p-button-sm p-button-rounded p-button-outlined " (click)="toggleFilters()"></button>
</div>
<!-- <div class="button-right pt-3" *ngIf="more">
<button pButton type="button" icon="pi pi-minus" i18n-pTooltip="@@{less_filters}" pTooltip="Less filters..."
class="p-button-text p-button-sm p-button-rounded p-button-outlined " (click)="toggleFilters()"></button>
</div>-->
<div *ngIf="more">
<div>
<p class="text-xl" i18n="@@{search_title}">Resource title</p>
<input id="title" name="title" type="text" pInputText [(ngModel)]="searchModel.title">
<p class="text-xl" i18n="@@{specific_pest}">Specific pest</p>
<p-multiSelect i18n-defaultLabel="@@{select_pests}" defaultLabel="Select pests" [options]="pests" optionLabel="commonName" filterBy="commonName,latinName,eppo" [(ngModel)]="searchModel.pest" name="pest">
<p-multiSelect i18n-placeholder="@@{select_pests}" placeholder="Select pests" [options]="pests" optionLabel="commonName" filterBy="commonName,latinName,eppo" [(ngModel)]="searchModel.pest" name="pest">
<ng-template let-pest pTemplate="item">
<div>{{pest.commonName}} <i *ngIf="pest.latinName !=undefined">
({{pest.latinName}}, {{pest.eppo}})</i></div>
......@@ -49,7 +35,7 @@
<p class="text-xl" i18n="@specific_crop">Specific crop</p>
<p-multiSelect i18n-defaultLabel="@@{select_crops}" defaultLabel="Select crops" [options]="crops" optionLabel="commonName" filterBy="commonName,latinName,eppo" [(ngModel)]="searchModel.crop" name="crop">
<p-multiSelect i18n-placeholder="@@{select_crops}" placeholder="Select crops" [options]="crops" optionLabel="commonName" filterBy="commonName,latinName,eppo" [(ngModel)]="searchModel.crop" name="crop">
<ng-template let-crop pTemplate="item">
<div>{{crop.commonName}} <i *ngIf="crop.latinName !=undefined">
({{crop.latinName}}, {{crop.eppo}})</i></div>
......@@ -57,61 +43,76 @@
</p-multiSelect>
<p class="text-xl" i18n="@@{languages}">Resource language</p>
<p-multiSelect i18n-defaultLabel="@@{select_language}" defaultLabel="Select language" [selectionLimit]="1" [options]="languages" name="language" [(ngModel)]="searchModel.language" optionLabel="{{locale === 'en' ? 'name' : 'name_'+locale}}"></p-multiSelect>
<!--<h3>Arbitrary text search</h3>
<input type="text" pInputText [(ngModel)]="searchTerm"/>-->
<p-multiSelect i18n-placeholder="@@{select_language}" placeholder="Select language" [options]="languages" name="language" [(ngModel)]="searchModel.language" optionLabel="{{locale === 'en' ? 'name' : 'name_'+locale}}"></p-multiSelect>
</div>
<div class="flex justify-content-center">
<div class="pt-3 pr-3">
<p-button type="submit" i18n-label="@@{search}" label="Search" [disabled] = "isEmptySearch()" icon="pi pi-search" [loading]="serachRunning"></p-button>
<p-button type="submit" i18n-label="@@{search}" label="Search" [disabled] = "isEmptySearch()" [loading]="serachRunning"></p-button>
</div>
<div class="pt-3 pl-3">
<p-button type="submit" i18n-label="@@{reset}" label="Reset" icon="pi pi-refresh" (click)="resetSearch()" [loading]="false"></p-button>
<p-button type="submit" i18n-label="@@{reset}" label="Reset" (click)="resetSearch()" [loading]="false"></p-button>
</div>
</div>
<div class="flex justify-content-center mt-4">
<button [style.background-color] ="'#f3b967'" pButton type="submit" i18n-label="@@{request_resource}" label="Request resource" routerLink="/resource/request" [loading]="false"></button>
</div>
</form>
</div>
<div class="md:col-9">
<p-card>
<p-dataView [value]="resources" [lazy]="true" (onLazyLoad)="onPageChange($event)" (onPage)="onPageChange($event)" [totalRecords]="totalElements" [paginator]="true" [rowsPerPageOptions]=[12,24,48,96] [rows]="12" layout="grid">
<ng-template let-resource pTemplate="gridItem">
<div class="card col-12 md:col-4 flex flex-column p-3 mt-3 hoverResource">
<div class="pb-1 align-self-end">
<p-tag *ngIf="resource.resourceType" [rounded]=true value="{{getResourceType(resource)}}">
</p-tag>
<p-avatar *ngIf="resource.external" shape="circle" icon="pi pi-external-link"></p-avatar>
<div class="xl:col-10 col-12">
<p-dataView [value]="resources" [lazy]="true" (onLazyLoad)="onPageChange($event)" (onPage)="onPageChange($event)" [totalRecords]="totalElements" [paginator]="true" paginatorDropdownAppandTo="body" rowsPerPageOptions=[12,24,48,96] [rows]="12" layout="grid">
<ng-template pTemplate="grid" let-resources>
<div class="grid grid-nogutter">
<div class="xl:col-3 lg:col-4 md:col-6 px-3" *ngFor="let resource of resources">
<a routerLink="/resource/{{resource.idResource}}/{{getLang()}}" target="_blank" style="color:black !important;text-decoration:none !important;">
<div class="card flex flex-column p-0 hoverResource">
<div [style.background]="'url('+imagePath+'/'+resource.idResource+')'" class="fillimg">
</div>
<div class="pl-3 pt-3 mb-3 flex flex-column justify-content-between fixheight">
<div>
<p-tag [style]="{'background-color': '#0a4b27 !important'}" *ngIf="resource.sectors && resource.sectors.length >1" [rounded]=true value="{{getRegion(resource)}}"> </p-tag>
<p-tag [style]="{'background-color': '#0a4b27 !important'}" *ngIf="resource.sectors && resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'arable.jpg'" [rounded]=true value="{{getRegion(resource)}}"> </p-tag>
<p-tag [style]="{'background-color': '#0a4b27 !important'}" *ngIf="resource.sectors && resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'orchard.jpg'" [rounded]=true value="{{getRegion(resource)}}"> </p-tag>
<p-tag [style]="{'background-color': '#097b32 !important'}" *ngIf="resource.sectors && resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'vegetables.jpg'" [rounded]=true value="{{getRegion(resource)}}"> </p-tag>
<p-tag [style]="{'background-color': '#0a4b27 !important'}" *ngIf="resource.sectors && resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'vineyard.jpg'" [rounded]=true value="{{getRegion(resource)}}"> </p-tag>
<p-tag [style]="{'background-color': '#0a4b27 !important'}" *ngIf="resource.sectors && resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'greenhouse.jpg'" [rounded]=true value="{{getRegion(resource)}}"> </p-tag>
</div>
<div routerLink="/resource/{{resource.idResource}}">
<img [src]="imagePath+'/'+resource.idResource" class="imageSizeHome"/>
<div class="flex flex-column">
<div class="pt-1 align-self-end">
<p-tag [rounded]=true severity="success" icon="pi pi-globe" value="{{getRegion(resource)}}">
</p-tag>
<p-tag *ngIf="getProject(resource)!== null" [rounded]=true severity="warning" icon="pi pi-book" value="{{getProject(resource)}}">
</p-tag>
</div>
</div>
<p-tag [style]="{'background-color': '#f3b967 !important'}" class="pl-2" *ngIf="resource.resourceType && resource.sectors.length >1" [rounded]=true value="{{getResourceType(resource)}}"></p-tag>
<p-tag [style]="{'background-color': '#f3b967 !important'}" class="pl-2" *ngIf="resource.resourceType && resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'arable.jpg'" [rounded]=true value="{{getResourceType(resource)}}"></p-tag>
<p-tag [style]="{'background-color': '#f3b967 !important'}" class="pl-2" *ngIf="resource.resourceType && resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'orchard.jpg'" [rounded]=true value="{{getResourceType(resource)}}"></p-tag>
<p-tag [style]="{'background-color': '#f3b967 !important'}" class="pl-2" *ngIf="resource.resourceType && resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'vegetables.jpg'" [rounded]=true value="{{getResourceType(resource)}}"></p-tag>
<p-tag [style]="{'background-color': '#eda33f !important'}" class="pl-2" *ngIf="resource.resourceType && resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'vineyard.jpg'" [rounded]=true value="{{getResourceType(resource)}}"></p-tag>
<p-tag [style]="{'background-color': '#eda33f !important'}" class="pl-2" *ngIf="resource.resourceType && resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'greenhouse.jpg'" [rounded]=true value="{{getResourceType(resource)}}"></p-tag>
</div>
<p-avatar class="pl-2" *ngIf="resource.external" shape="circle" icon="pi pi-external-link"></p-avatar>
<p class="text-center">{{resource.resourceName}}</p>
</div>
<div class="align-self-center">
<a routerLink="/resource/{{resource.idResource}}/{{getLang()}}" target="_blank" [style]="'text-decoration:unset'">
<button pButton type="button" icon="pi pi-forward" class="p-button-outlined mr-4" i18n-pTooltip="@@{find_more}" pTooltip="See more..."></button>
</a>
<!--<button pButton type="button" icon="pi pi-share-alt" class="p-button-outlined" pTooltip="Copy link for sharing" ngxClipboard [cbContent]="getPermLink(resource.idResource)" (click)=linkCopied(getPermLink(resource.idResource))></button>-->
<p class="text-sm">{{resource.resourceName}}</p>
<div>
<a routerLink="/resource/{{resource.idResource}}/{{getLang()}}" target="_blank">
<button [style.background-color] ="'#f3b967'" pButton label="Learn more..." icon="pi pi-angle-double-right" iconPos="right" class="p-button-rounded text-sm" ></button>
</a>
<!-- <button *ngIf="resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'arable.jpg'" [style.background-color] ="'#f3b967'" pButton label="Learn more..." icon="pi pi-angle-double-right" iconPos="right" class="p-button-rounded" routerLink="/resource/{{resource.idResource}}/{{getLang()}}" ></button>-->
<!-- <button *ngIf="resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'orchard.jpg'" [style.background-color] ="'#f3b967'" pButton label="Learn more..." icon="pi pi-angle-double-right" iconPos="right" class="p-button-rounded" routerLink="/resource/{{resource.idResource}}/{{getLang()}}" ></button>-->
<!-- <button *ngIf="resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'vegetables.jpg'" [style.background-color] ="'#f3b967'" pButton label="Learn more..." icon="pi pi-angle-double-right" iconPos="right" class="p-button-rounded" routerLink="/resource/{{resource.idResource}}/{{getLang()}}" ></button>-->
<!-- <button *ngIf="resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'vineyard.jpg'" [style.background-color] ="'#0a4b27'" pButton label="Learn more..." icon="pi pi-angle-double-right" iconPos="right" class="p-button-rounded" routerLink="/resource/{{resource.idResource}}/{{getLang()}}" ></button>-->
<!-- <button *ngIf="resource.sectors.length == 1 && resource.sectors[0].sectorIcon == 'greenhouse.jpg'" [style.background-color] ="'#eda33f'" pButton label="Learn more..." icon="pi pi-angle-double-right" iconPos="right" class="p-button-rounded" routerLink="/resource/{{resource.idResource}}/{{getLang()}}" ></button>-->
</div>
</div>
</div>
</div>
</a>
</div>
</div>
</ng-template>
<ng-template let-item pTemplate="paginatordropdownitem" i18n="@@{per_page}">
<ng-template #mydiv let-item pTemplate="paginatordropdownitem" i18n="@@{per_page}">
{{item.value}} - per page
</ng-template>
</p-dataView>
<div class="justify-content-center flex pt-3" *ngIf="totalElements>0" i18n="@@{number_of_results}">Number of results: {{totalElements}}</div>
</p-card>
</div>
</p-dataView>
<div class="justify-content-center flex pt-3" *ngIf="totalElements && totalElements>0" i18n="@@{number_of_results}">Number of results: {{totalElements}}</div>
</div>
</div>
......@@ -23,12 +23,12 @@ import {NavigationEnd, Router} from "@angular/router";
styleUrls: ['./home.component.css']
})
export class HomeComponent implements OnInit{
resources: Resource[] = [];
resources: Resource[] | undefined = [];
totalResources: Resource[] = [];
search:boolean=false;
pageableResponse?: PageableResource;
pageSize = 10;
totalElements: number = 0;
totalElements: number | undefined = 0;
sectors: Sector[] = [];
regions: Region[] = [];
projects: Project[] = [];
......@@ -76,12 +76,13 @@ export class HomeComponent implements OnInit{
this.resourceService.getAllCrops().subscribe((crops: Crop[]) => {
this.crops = crops;});
this.resourceService.getAllResources().subscribe((resources: PageableResource) => {
// @ts-ignore
this.resources = resources.content;
// @ts-ignore
this.totalElements = resources.totalElements;
this.search = false;
this.serachRunning=false;
if(resources !=undefined){
this.resources = resources.content;
this.totalElements = resources.totalElements;
this.search = false;
this.serachRunning=false;
}
});
}
public closeDisclaimer(){
......@@ -92,7 +93,6 @@ export class HomeComponent implements OnInit{
this.more = !this.more;
}
public searchResource(){
// @ts-ignore
this.serachRunning = true;
this.resourceService.searchResource(this.searchModel).subscribe((resources: Resource[]) => {
this.resources = resources;
......@@ -117,9 +117,7 @@ export class HomeComponent implements OnInit{
}
populate(ret: PageableResource) {
this.pageableResponse = ret;
// @ts-ignore
this.resources = this.pageableResponse?.content;
// @ts-ignore
this.totalElements = this.pageableResponse.totalElements;
}
public resetSearch(){
......@@ -175,4 +173,9 @@ export class HomeComponent implements OnInit{
}
return "";
}
openInNewTab(rute:string) {
console.log(rute)
var lng = this.getLang()
this.router.navigateByUrl(rute+'/'+lng, { skipLocationChange: true });
}
}
<div class="card pt-6 pl-6 pr-6">
<p class="text-3xl" i18n="@@{add_resource}">Request a resource</p>
<form #resourceForm="ngForm" (ngSubmit)="saveResource()">
<div class="p-fluid">
<div class="field grid">
<label for="title" class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{short_desc}">Short description</label>
<div class="col-12 md:col-10">
<input id="title" name="title" #title='ngModel' type="text" pInputText [(ngModel)]="resource.resourceName" required [ngClass]="!title.valid ? 'ng-invalid ng-dirty' : ''">
<div [hidden]="title.valid" class="text-xs p-error " i18n="@@{short_desc_required}">
Short description is required
</div>
</div>
</div>
<div class="field grid">
<label for="description" class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{long_desc}">Long description (in English, 500 words)</label>
<div class="col-12 md:col-10">
<textarea id="description" name="description" #description='ngModel' type="text" rows="10" pInputTextarea [(ngModel)]="resource.description" required [ngClass]="!description.valid ? 'ng-invalid ng-dirty' : ''"></textarea>
<div [hidden]="description.valid" class="text-xs p-error" i18n="@@{long_required}">
Long description is required
</div>
</div>
</div>
<div class="field grid">
<label for="descriptionNative" class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{long_native}">Long description (in native language, if not English, 500 words)</label>
<div class="col-12 md:col-10">
<textarea id="descriptionNative" name="descriptionNative" type="text" rows="10" pInputTextarea [(ngModel)]="resource.descriptionNative"></textarea>
</div>
</div>
<div class="field grid">
<label class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{sectors}">Sectors</label>
<div class="col-12 md:col-10">
<p-multiSelect id="sector" name="sector" #sector='ngModel' i18n-defaultLabel="@@{select_sector}" [options]="sectors" dataKey="name" optionLabel="{{locale === 'en' ? 'name' : 'name_'+locale}}" [(ngModel)]="resource.sectors">
</p-multiSelect>
</div>
</div>
<div class="field grid">
<label class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{country_origin}">Country of origin</label>
<div class="col-12 md:col-10">
<p-multiSelect name="region" #region='ngModel' i18n-defaultLabel="@@{select_region}" dataKey="name" [options]="regions" optionLabel="name" [(ngModel)]="resource.regions"></p-multiSelect>
</div>
</div>
<div class="field grid">
<label class="col-12 mb-2 md:col-2 md:mb-0"><ng-container i18n="@@{relevant_pests"}>Relevant pests</ng-container>
<i class="pl-3 pi pi-question-circle" i18n-pTooltip="@@{pest_tooltip}" pTooltip="You can enter common English name, Latin name or EPPO to select pest. Choose Other to add new pest."></i>
</label>
<div class="col-12 md:col-10">
<p-multiSelect name="pests" i18n-defaultLabel="@@{select_pests}" defaultLabel="Select pests" [options]="pests" optionLabel="commonName" filterBy="commonName,latinName,eppo" [(ngModel)]="resource.pests" (onChange)="openPestModal()">
<ng-template let-pest pTemplate="item">
<div>{{pest.commonName}} <i *ngIf="pest.latinName !=undefined">
({{pest.latinName}}, {{pest.eppo}})</i></div>
</ng-template>
</p-multiSelect>
</div>
</div>
<div class="field grid">
<label class="col-12 mb-2 md:col-2 md:mb-0"><ng-container i18n="@@{relevant_crops}">Relevant crops</ng-container>
<i class="pl-3 pi pi-question-circle" i18n-pTooltip="@@{crop_tooltip}" pTooltip="You can enter common English name, Latin name or EPPO to select crop. Choose Other to add new crop."></i>
</label>
<div class="col-12 md:col-10">
<p-multiSelect name="crops" i18n-defaultLabel="@@{select_crops}" defaultLabel="Select crops" [options]="crops" optionLabel="commonName" filterBy="commonName,latinName,eppo" [(ngModel)]="resource.crops" (onChange)="openCropModal()">
<ng-template let-crop pTemplate="item">
<div>{{crop.commonName}} <i *ngIf="crop.latinName !=undefined">
({{crop.latinName}}, {{crop.eppo}})</i></div>
</ng-template>
</p-multiSelect>
</div>
</div>
<div class="field grid">
<label for="contactOrg" class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{contactInstitution}" i18n="@@{contactInstitution}">Contact institution</label>
<div class="col-12 md:col-10">
<input id="contactOrg" name="contactOrg" type="text" pInputText [(ngModel)]="resource.contactInstitution">
</div>
</div>
<div class="field grid">
<label for="contactEmail" class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{contactEmail}">Contact email</label>
<div class="col-12 md:col-10">
<input id="contactEmail" name="contactEmail" type="text" pInputText [(ngModel)]="resource.contactEmail">
</div>
</div>
<div class="field grid">
<label for="contactPhone" class="col-12 mb-2 md:col-2 md:mb-0" i18n="@@{contactPhone}">Contact phone</label>
<div class="col-12 md:col-10">
<input id="contactPhone" name="contactPhone" type="text" pInputText [(ngModel)]="resource.contactPhone">
</div>
</div>
<div class="field grid">
<div class="col-12 field-checkbox">
<p-checkbox [(ngModel)]="termChecked" [binary]="true" name="termCheckede" id="termChecked" [ngClass]="!termChecked? 'ng-invalid ng-dirty' : ''"></p-checkbox>
<label for="termChecked"><ng-container i18n="@@{termCondition1}">by ticking this box you confirm that you have read and accept</ng-container> <a href="https://ipmworks.net/ipmworks/file/get/63b6b7c0d7f8f46f5b2a28b3"><ng-container i18n="@@{part1}"> Part 1 </ng-container></a>
<ng-container i18n="@@{termCondition2}">of the Toolbox Terms and Conditions. You can contact </ng-container><a href="mailto:IPMWORKS-WP4@inrae.fr">IPMWORKS-WP4&#64;inrae.fr </a> <ng-container i18n="@@{termCondiotion3}">at any time to amend or remove your submission.</ng-container>
</label>
</div>
<div [hidden]="termChecked" class="text-xs p-error" i18n="@@{required}">
This is required
</div>
</div>
<div class="col-12 pt-3 justify-content-center flex">
<p-button i18n-label="@@{back}" label="Back" class="pr-5"routerLink="/home" type="button" ></p-button>
<p-button i18n-label="save_resource" label="Send request" [loading]="false" type="submit" [disabled]="resourceForm.form.invalid || !termChecked"></p-button>
</div>
</div>
</form>
</div>
<p-toast></p-toast>
<p-dialog id="pestModal" header="Add new pest" [(visible)]="displayPestModal">
<div class="field">
<label i18n="@@{commonName}" >English common name</label>
<input id="commonName" type="text" pInputText [(ngModel)]="newPest.commonName"/>
</div>
<div class="field">
<label i18n="@@{latinName}">Latin name</label>
<input id="latinName" type="text" pInputText [(ngModel)]="newPest.latinName"/>
</div>
<div class="field">
<label>EPPO</label>
<input id="eppo" type="text" pInputText [(ngModel)]="newPest.eppo" />
</div>
<div class="field button-center">
<button pButton type="button" class="p-button-help mr-3" i18n-label="@@{cancel}" label="Cancel" (click)="displayPestModal=false" ></button>
<button pButton type="button" i18n-label="submit" label="Submit" (click)="addPest()"></button>
</div>
</p-dialog>
<p-dialog id="cropModal" name="cropModal" header="Add new crop" [(visible)]="displayCropModal">
<div class="field">
<label i18n="@@{commonName}">English common name</label>
<input id="commonNameCrop" type="text" pInputText [(ngModel)]="newCrop.commonName" />
</div>
<div class="field">
<label i18n="@@{latinName}">Latin name</label>
<input id="latinNameCrop" type="text" pInputText [(ngModel)]="newCrop.latinName"/>
</div>
<div class="field">
<label>EPPO</label>
<input id="eppoCrop" type="text" pInputText [(ngModel)]="newCrop.eppo"/>
</div>
<div class="field button-center">
<button pButton type="button" class="p-button-help mr-3" i18n-label="@@{cancel}" label="Cancel" (click)="displayCropModal=false" ></button>
<button pButton type="button" i18n-label="submit" label="Submit" (click)="addCrop()" ></button>
</div>
</p-dialog>
<p-confirmDialog></p-confirmDialog>
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { RequestResourceComponent } from './request-resource.component';
describe('RequestResourceComponent', () => {
let component: RequestResourceComponent;
let fixture: ComponentFixture<RequestResourceComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
declarations: [ RequestResourceComponent ]
})
.compileComponents();
});
beforeEach(() => {
fixture = TestBed.createComponent(RequestResourceComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});
import {Component, Inject, LOCALE_ID, OnInit} from '@angular/core';
import {Crop, Language, Pest, Project, Region, Resource, ResourceType, Sector} from "../../model/resource";
import {FormControl} from "@angular/forms";
import {environment} from "../../../environments/environment";
import {ResourceService} from "../../service/resource.service";
import {ActivatedRoute, Router} from "@angular/router";
import {ConfirmationService, MessageService} from "primeng/api";
@Component({
selector: 'app-request-resource',
templateUrl: './request-resource.component.html',
styleUrls: ['./request-resource.component.css']
})
export class RequestResourceComponent implements OnInit {
sectors: Sector[] = [];
regions: Region[] = [];
resourceTypes: ResourceType[] = [];
pests:Pest[] = [];
crops: Crop [] = [];
resource: Resource = {};
displayPestModal=false;
displayCropModal=false;
newPest:Pest = {};
newCrop: Crop = {};
resourceControl = new FormControl('');
displayTerms = false;
termChecked = false;
constructor(private resourceService:ResourceService, private route: ActivatedRoute, private messageService: MessageService, private router: Router, @Inject(LOCALE_ID) public locale: string, private confirmationService: ConfirmationService) { }
ngOnInit(): void {
this.resourceService.getAllSectors().subscribe((sectors: Sector[]) => {
this.sectors = sectors;});
this.resourceService.getAllRegions().subscribe((regions: Region[]) => {
this.regions = regions;});
this.resourceService.getAllPests().subscribe((pests: Pest[]) => {
this.pests = pests;});
this.resourceService.getAllCrops().subscribe((crops: Crop[]) => {
this.crops = crops;});
this.resourceService.getAllResourceTypes().subscribe((contentTypes: ResourceType[]) => {
this.resourceTypes = contentTypes;});
}
saveResource(){
this.resource.canEdit=true;
// @ts-ignore
this.resource.approved=false
this.resource.resourceType = this.resourceTypes.filter(r=>r.name=='Request')[0]
this.resourceService.saveResource(this.resource,false).subscribe((data: Resource) => {
this.resource = data;
this.router.navigate(['/home']);
},error => {
this.messageService.add({severity: 'error', detail: 'Some error occurred!'})
});
}
public openPestModal(){
// @ts-ignore
if (this.resource.pests.filter(e => e.commonName === 'Other').length > 0) {
this.displayPestModal=true;
}
}
public addPest(){
// @ts-ignore
var selectedPests = this.resource.pests.filter(function(el) { return el.commonName != "Other"; });
this.resource.pests = selectedPests;
this.resource.pests.push(this.newPest);
this.pests.push(this.newPest);
// this.resourceService.addCrop(this.newPest).subscribe()
this.newPest={};
this.displayPestModal=false;
}
public openCropModal(){
// @ts-ignore
if (this.resource.crops.filter(e => e.commonName === 'Other').length > 0) {
this.displayCropModal=true;
}
}
public addCrop(){
// @ts-ignore
var selectedCrops = this.resource.crops.filter(function(el) { return el.commonName != "Other"; });
this.resource.crops = selectedCrops;
this.resource.crops.push(this.newCrop);
this.crops.push(this.newCrop);
//this.resourceService.addCrop(this.newCrop).subscribe()
this.newCrop={};
this.displayCropModal=false;
}
showTerms(){
this.displayTerms = true;
}
}
......@@ -29,4 +29,5 @@
}
.keep-format{
white-space: pre-wrap;
text-align: justify;
}
<div class="grid pt-6 pl-6 flex flex-wrap">
<div class="grid md:pt-6 md:pl-6">
<div class="flex col-12 justify-content-center">
<p class="text-3xl">{{resource.resourceName}}
</p>
......@@ -9,18 +9,34 @@
</div>
<div class="col-12">
<p-panel class="col-12 inline">
<div class="flex align-items-center"><div class="col-3 inline my-0" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{project}">Project</div><div class="my-0">{{resource.project}}</div></div>
<div class="flex align-items-center"><div class="col-3 inline my-0" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{language}">Resource language</div><div class="my-0">{{resource.language?.name}}</div></div>
<div class="flex align-items-center"><div class="col-3 inline my-0" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{resourceOrigin}">Resource origin</div> <div class="my-0 overflow-text"><a href="{{resource.resourceOrigin}}" target="_blank">{{resource.resourceOrigin}}</a></div></div>
<div class="flex align-items-center"> <div class="col-3 inline my-0" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{resourceType}">Resource type</div><div class="my-0">{{resource.resourceType?.name}}</div></div>
<div class="flex align-items-center"><div class="col-3 inline my-0" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{contactInstitution}">Organization name</div><div class="my-0">{{resource.contactInstitution}}</div></div>
<div class="flex align-items-center"><div class="col-3 inline my-0"[ngStyle]="{color:'var(--surface-500)'}" i18n="@@{contactEmail}">Contact email</div><div class="my-0"></div>{{resource.contactEmail}}</div>
<div class="flex align-items-center"><div class="col-3 inline my-0"[ngStyle]="{color:'var(--surface-500)'}" i18n="@@{contactPhone}">Contact phone</div><div class="my-0">{{resource.contactPhone}}</div></div>
<div class="flex align-items-center"><div class="col-3 inline my-0" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{citation}">Citation (DOI)</div><div class="overflow-text my-0">{{resource.citation}}</div></div>
<div class="flex align-items-center"><div class="md:col-3 col-5 inline my-0" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{project}">Project</div><div class="my-0">{{resource.project}}</div></div>
<div class="flex align-items-center"><div class="md:col-3 col-5 inline my-0" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{language}">Resource language</div><div class="my-0">{{resource.language?.name}}</div></div>
<div class="flex align-items-center"><div class="md:col-3 col-5 inline my-0" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{resourceOrigin}">Resource origin</div> <div class="my-0 overflow-text"><a href="{{resource.resourceOrigin}}" target="_blank">{{resource.resourceOrigin}}</a></div></div>
<div class="flex align-items-center"> <div class="md:col-3 col-5 inline my-0" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{resourceType}">Resource type</div><div class="my-0">{{resource.resourceType?.name}}</div></div>
<div class="flex align-items-center"><div class="md:col-3 col-5 inline my-0" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{contactInstitution}">Organization name</div><div class="my-0">{{resource.contactInstitution}}</div></div>
<div class="flex align-items-center"><div class="md:col-3 col-5 inline my-0"[ngStyle]="{color:'var(--surface-500)'}" i18n="@@{contactEmail}">Contact email</div><div class="my-0"></div>{{resource.contactEmail}}</div>
<div class="flex align-items-center"><div class="md:col-3 col-5 inline my-0"[ngStyle]="{color:'var(--surface-500)'}" i18n="@@{contactPhone}">Contact phone</div><div class="my-0">{{resource.contactPhone}}</div></div>
<div class="flex align-items-center"><div class="md:col-3 col-5 inline my-0" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{citation}">Citation (DOI)</div><div class="overflow-text my-0">{{resource.citation}}</div></div>
<div class="flex align-items-center"><div class="md:col-3 col-5 inline my-0" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{creationDate}">Creation date</div><div class="overflow-text my-0">{{resource.creationDate | date:"dd. MM. yyyy."}}</div></div>
</p-panel>
</div>
<p-panel class="col-12" i18n-header="@@{find_more}" header="Find out more" *ngIf="(resource.files != undefined) || ((resource.links != undefined))">
<div [ngClass]="{'pr-5': resource.youtube, 'col-12': !resource.youtube}">
<div *ngFor="let file of resource.files" class="pb-5" >
<i class="pi pi-file p-mr-2" style="font-size: 2rem"></i>
<button pButton type="button" label="{{file.description}}" class="p-button-link button-link"
(mouseover)="displayPreviewModal=true;selectedFile=filePath+'/'+file.description"
(click)="downloadFile(file.description)" ></button>
</div>
<div class="mt-2" *ngFor="let link of resource.links" >
<i class="pi pi-link mr-2 " style="font-size: 2rem" *ngIf="link.url !=''"></i>
<a class="link-wrap" href="{{link.url}}" target="_blank">{{link.name}}</a>
</div>
</div>
</p-panel>
</div>
<div class="md:col-6 flex flex-column">
<div class="md:col-6 md:flex md:flex-column">
<p-panel i18n-header="@@{short_summary}" header="Short summary" class="col-12 p-d-block">
<div *ngIf="resource.descriptionNative == undefined" class="flex keep-format" [innerHTML]="resource.description"></div>
<p-tabView *ngIf="resource.descriptionNative != undefined">
......@@ -47,7 +63,7 @@
<div class="inline col-3" [ngStyle]="{color:'var(--surface-500)'}"i18n="@@{relevant_pests}">Relevant pest(s)</div>
<div class="col-9">
<div *ngFor="let pest of resource.pests" class="inline-flex pr-2 pb-2">
<p-badge severity="danger" value={{pest.commonName}}></p-badge>
<p-badge [styleClass]="'button-dark-orange'" value={{pest.commonName}}></p-badge>
</div>
</div>
</div>
......@@ -55,44 +71,62 @@
<div class="inline col-3" [ngStyle]="{color:'var(--surface-500)'}" i18n="@@{relevant_crops}"> Relevant crop(s)</div>
<div class="col-9">
<div class="inline-flex pr-2 pb-2" *ngFor="let crop of resource.crops">
<p-badge severity="success" value={{crop.commonName}}></p-badge>
<p-badge [styleClass]="'button-light-green'" value={{crop.commonName}}></p-badge>
</div>
</div>
</div>
</p-panel>
<p-panel class="col-12 p-d-block" i18n-header="@@{find_more}" header="Find out more" *ngIf="(resource.files != undefined) || (resource.links != undefined)">
<div *ngFor="let file of resource.files" >
<i class="pi pi-file p-mr-2" style="font-size: 2rem"></i>
<button pButton type="button" label="{{file.description}}" class="p-button-link button-link" (click)="downloadFile(file.description)"></button>
</div>
<div class="mt-2" *ngFor="let link of resource.links" >
<i class="pi pi-link p-mr-2" style="font-size: 2rem"></i>
<a class="link-wrap" href="{{link}}" target="_blank">{{link}}</a>
</div>
</p-panel>
</div>
<div class="col-12 pt-3 flex justify-content-center">
<div class="pr-2">
<p-button i18n-label="@@{back_to_search}" label="Back to search" icon="pi pi-search" routerLink="/home" [loading]="false"></p-button>
<p-button i18n-label="@@{share}" label="Share" icon="pi pi-share-alt" class="ml-3"(click)=linkCopied(getPermLink(resource.idResource)) [loading]="false"></p-button>
<p-button i18n-label="@@{download}" label="Download" icon="pi pi-share-alt" class="ml-3"(click)=download(resource) [loading]="false"></p-button>
<div class="col-12 pt-3 embed-responsive embed-responsive-16by9" *ngIf="resource.youtube !=undefined">
<iframe [src]='safeURL' allowfullscreen width="100%" height="500px"></iframe>
</div>
</div>
<!-- <div class="md:col-6 md:flex">-->
<!-- <p-panel class="flex-1 pt-3 pb-3 pr-3" i18n-header="@@{find_more}" header="Find out more" *ngIf="(resource.files != undefined) || ((resource.links != undefined))">-->
<!-- <div [ngClass]="{'pr-5': resource.youtube, 'col-12': !resource.youtube}">-->
<!-- <div *ngFor="let file of resource.files" class="pb-5" >-->
<!-- <i class="pi pi-file p-mr-2" style="font-size: 2rem"></i>-->
<!-- <button pButton type="button" label="{{file.description}}" class="p-button-link button-link"-->
<!-- (mouseover)="displayPreviewModal=true;selectedFile=filePath+'/'+file.description"-->
<!-- (click)="downloadFile(file.description)" ></button>-->
<!-- </div>-->
<!-- <div class="mt-2" *ngFor="let link of resource.links" >-->
<!-- <i class="pi pi-link mr-2 " style="font-size: 2rem" *ngIf="link.url !=''"></i>-->
<!-- <a class="link-wrap" href="{{link.url}}" target="_blank">{{link.name}}</a>-->
<!-- </div>-->
<!-- </div>-->
<!-- </p-panel>-->
<!-- </div>-->
<!-- <div class="md:col-6 md:flex embed-responsive embed-responsive-16by9" *ngIf="resource.youtube !=undefined">-->
<!-- <iframe [src]='safeURL' allowfullscreen width="100%" height="500px"></iframe>-->
<!-- </div>-->
<div class="col-12 pt-3 flex justify-content-center md:flex-row flex-column">
<div class="pr-2 flex flex-wrap md:flex-row flex-column">
<p-button i18n-label="@@{back_to_search}" label="Back to search" class="md:my-0 my-2" routerLink="/home" [loading]="false"></p-button>
<p-button i18n-label="@@{share}" label="Share" class="md:ml-3 md:my-0 my-2"(click)=linkCopied(getPermLink(resource.idResource)) [loading]="false"></p-button>
<p-button i18n-label="@@{download}" label="Download" class="md:ml-3 md:my-0 my-2 "(click)=download(resource) [loading]="false"></p-button>
<p-button i18n-label="@@{comment}" label="Comment" class="md:ml-3 md:my-0 my-2"(click)=toogleCommentModal() [loading]="false"></p-button>
</div>
<div class="pr-2" *ngIf="!resource.approved && resource.canEdit && (loggeduser| async)?.roles?.includes('ADMIN')">
<p-button i18n-label="@@{approve}" label="Approve" icon="pi pi-check" (onClick)="approve($event)" [loading]="false"></p-button>
<div class="pr-2 md:my-0 my-2" *ngIf="!resource.approved && resource.canEdit && (loggeduser| async)?.roles?.includes('ADMIN')">
<p-button i18n-label="@@{approve}" label="Approve" (onClick)="approve($event)" [loading]="false"></p-button>
</div>
<div class="pr-2 md:my-0 my-2" *ngIf="(loggeduser| async)?.roles?.includes('ADMIN') && resource.canEdit">
<p-button i18n-label="@@{edit}" label="Edit" routerLink="/resource/edit/{{resourceId}}" [loading]="false"></p-button>
</div>
<div class="pr-2" *ngIf="(loggeduser| async)?.roles?.includes('ADMIN') && resource.canEdit">
<p-button i18n-label="@@{edit}" label="Edit" icon="pi pi-pencil" routerLink="/resource/edit/{{resourceId}}" [loading]="false"></p-button>
<div class="pr-2 md:my-0 my-2" *ngIf="(loggeduser| async)?.roles?.includes('ADMIN') && resource.canEdit">
<p-button i18n-label="@@{delete]" label="Delete" (onClick)="delete($event)" [loading]="false"></p-button>
</div>
<div *ngIf="(loggeduser| async)?.roles?.includes('ADMIN') && resource.canEdit">
<p-button i18n-label="@@{delete]" label="Delete" icon="pi pi-trash" (onClick)="delete($event)" [loading]="false"></p-button>
<div class="pr-2 md:my-0 my-2" *ngIf="(loggeduser| async)?.roles?.includes('ADMIN') && resource.canEdit && resource.approved">
<p-button i18n-label="@@{archive]" label="Archive" (onClick)="archive($event)" [loading]="false"></p-button>
</div>
</div>
</div>
<p-toast position="bottom-center" key="bc"></p-toast>
<p-confirmDialog></p-confirmDialog>
<p-dialog id="shareModal" name="shareModal" header="Copy link to share" [(visible)]="displayModal" [style]="{width: '40vw'}">
<div class="field">
<label i18n="@@{link}">Link</label>
......@@ -103,3 +137,37 @@
<button pButton type="button" class="p-button-help" label="Ok" (click)="displayModal=false" ></button>
</div>
</p-dialog>
<p-dialog id="commentModal" name="commentModal" header="Comment resource" [(visible)]="displayCommentModal" [style]="{width: '40vw'}">
<div>
<label>{{resource.resourceName}}</label>
</div>
<div class="mt-4">
<textarea id="comment" name="comment" type="text" rows="10" pInputTextarea [(ngModel)]="comment.text"></textarea>
</div>
<div class="field">
<label i18n="@@{email}">Your email</label>
<input id="commenterEmail" type="text" [(ngModel)]="comment.commenterEmail" pInputText/>
</div>
<div class="field flex justify-content-center mt-4">
<button pButton type="button" label="Cancel" (click)=toogleCommentModal() ></button>
<button pButton type="button" class="ml-3" label="Submit" [disabled]="comment.text?.length == 0" (click)=sendEmail() ></button>
</div>
</p-dialog>
<p-dialog id="previewModal" name="previewModal" header="Preview" [(visible)]="displayPreviewModal">
<div>
<pdf-viewer
src="{{selectedFile}}"
[rotation]="0"
[original-size]="false"
[render-text]="true"
[show-all]="true"
style="width: 50vw; height: 50vh">
</pdf-viewer>
<!-- <ngx-extended-pdf-viewer [src]="'{{selectedFile}}'"></ngx-extended-pdf-viewer>-->
</div>
</p-dialog>
......@@ -2,13 +2,14 @@ import { Component, OnInit } from '@angular/core';
import {ResourceService} from "../../service/resource.service";
import {ActivatedRoute, Router} from "@angular/router";
import {environment} from "../../../environments/environment";
import {Resource} from "../../model/resource";
import {Comment, Resource} from "../../model/resource";
import {ConfirmationService, MessageService} from "primeng/api";
import {Observable} from "rxjs";
import {User} from "../../model/user";
import {UserState} from "../../states/user.state";
import {Store} from "@ngxs/store";
import {HttpResponse} from "@angular/common/http";
import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser';
@Component({
selector: 'app-resource',
......@@ -24,10 +25,15 @@ export class ResourceComponent implements OnInit {
lang = null;
displayModal=false;
copiedLink="";
comment:Comment = {text:"",commenterEmail:""};
displayCommentModal = false;
safeURL?:SafeResourceUrl;
displayPreviewModal = false
selectedFile= ""
// @ts-ignore
public loggeduser: Observable<User> = this.store.select(UserState.userDetails);
constructor(private resourceService:ResourceService, private route: ActivatedRoute,
constructor(private resourceService:ResourceService, private route: ActivatedRoute, private sanitizer:DomSanitizer,
private router: Router, private store:Store, private messageService:MessageService, private confirmationService: ConfirmationService) { }
ngOnInit(): void {
......@@ -39,8 +45,12 @@ export class ResourceComponent implements OnInit {
// @ts-ignore
this.resourceService.getResource(this.resourceId,this.lang).subscribe(data =>{
this.resource =data;
});
if (this.resource.youtube !=undefined){
this.safeURL = this.sanitizer.bypassSecurityTrustResourceUrl(this.resource.youtube.replace('watch?v=','embed/'));
}
});
}
downloadFile(fileName: any): void {
this.resourceService.downloadFile(fileName).subscribe((file: any) => {
......@@ -57,6 +67,7 @@ export class ResourceComponent implements OnInit {
});
}
approve(event: Event) {
this.confirmationService.confirm({
message: 'Are you sure that you want to approve resource?',
......@@ -73,6 +84,22 @@ export class ResourceComponent implements OnInit {
}
});
}
archive(event: Event) {
this.confirmationService.confirm({
message: 'Are you sure that you want to archive resource?',
icon: 'pi pi-exclamation-triangle',
accept: () => {
// @ts-ignore
this.resourceService.archiveResource(this.resourceId).subscribe(r => {
this.messageService.add({severity: 'success', detail: 'Resource has been archived.'});
this.router.navigate(['/home'])
}, error => {
this.messageService.add({severity: 'error', detail: 'Some error occured!'});
}
);
}
});
}
delete(event: Event) {
this.confirmationService.confirm({
message: 'Are you sure that you want to delete resource?',
......@@ -131,4 +158,21 @@ export class ResourceComponent implements OnInit {
anchor.click();
document.body.removeChild(anchor);
}
public toogleCommentModal(){
// @ts-ignore
this.displayCommentModal = !this.displayCommentModal;
this.comment.text=""
this.comment.commenterEmail=""
}
public sendEmail(){
// @ts-ignore
this.resourceService.sendEmail(this.resource.idResource,this.comment).subscribe( r =>{
this.toogleCommentModal();
this.messageService.add({severity: 'success', detail: 'Your comment is sent to email IPMWORKS-WP4@inrae.fr.'});
})
}
}
......@@ -3,7 +3,8 @@ export interface Resource {
resourceName?: string;
description?: string;
descriptionNative?:string;
links?:string[];
links?:Link[];
youtube?:string
files?:any[];
resourceOrigin?: string;
resourceType?: ResourceType;
......@@ -23,8 +24,13 @@ export interface Resource {
creationDate?:Date;
approved?:boolean;
external?:boolean;
hide?:boolean;
}
export class Link{
name?:string;
url?:string;
}
export class Crop{
public idCrop?:string;
public commonName?: string;
......@@ -86,3 +92,7 @@ export class PageableResource {
totalElements: number|undefined;
totalPages?: number =0;
}
export class Comment{
public text?: string;
public commenterEmail?: string;
}
......@@ -14,7 +14,7 @@ import {
Keyword,
Pest,
Crop,
PageableResource, FileDesc
PageableResource, FileDesc, Comment
} from "../model/resource";
import {SearchModel} from "../model/search-model";
......@@ -43,6 +43,9 @@ export class ResourceService {
public approveResource(id:string) {
return this._httpClient.get<Resource>(`${AppConfig.ApiPaths.approveResource}`+"/"+id);
}
public archiveResource(id:string) {
return this._httpClient.get<Resource>(`${AppConfig.ApiPaths.archiveResource}`+"/"+id);
}
public deleteResource(id:string) {
return this._httpClient.get<Resource>(`${AppConfig.ApiPaths.deleteResource}`+"/"+id);
}
......@@ -63,8 +66,8 @@ export class ResourceService {
return this._httpClient.get<any>(`${AppConfig.ApiPaths.getFileById}`+"/"+id, httpOptions);
}
public saveResource(resource: Resource,edit:boolean) {
resource.creationDate = new Date();
if(!edit){
resource.creationDate = new Date();
resource.approved = false;
}
return this._httpClient.post<Resource>(`${AppConfig.ApiPaths.saveResource}`, resource);
......@@ -127,7 +130,12 @@ export class ResourceService {
public getAllKeywords() {
return this._httpClient.get<Keyword[]>(`${AppConfig.ApiPaths.getAllKeywords}`);
}
public addCrop(crop:Crop) {
return this._httpClient.post(`${AppConfig.ApiPaths.addCrop}`,crop);
}
public addPest(pest:Pest) {
return this._httpClient.post(`${AppConfig.ApiPaths.addPest}`,pest);
}
public getAllHelpFilesDesc() {
return this._httpClient.get<FileDesc[]>(`${AppConfig.ApiPaths.getAllHelpFilesDesc}`);
}
......@@ -135,4 +143,7 @@ export class ResourceService {
return this._httpClient.post(`${AppConfig.ApiPaths.download}`,resource,{responseType: 'blob' as 'blob', observe: 'response'})
}
public sendEmail(idResource:string, comment:Comment) {
return this._httpClient.post(`${AppConfig.ApiPaths.comment}` + "/" + idResource, comment)
}
}
src/assets/EUFlag.png

9.24 KB | W: | H:

src/assets/EUFlag.png

52.1 KB | W: | H:

src/assets/EUFlag.png
src/assets/EUFlag.png
src/assets/EUFlag.png
src/assets/EUFlag.png
  • 2-up
  • Swipe
  • Onion skin
......@@ -12,6 +12,7 @@ export class AppConfig {
approveResource: `${AppConfig.Origin}/admin/approve`,
deleteResource: `${AppConfig.Origin}/admin/delete`,
archiveResource: `${AppConfig.Origin}/admin/archive`,
deleteFile: `${AppConfig.Origin}/file/delete`,
......@@ -24,6 +25,7 @@ export class AppConfig {
addFile: `${AppConfig.Origin}/resource/add`,
addHelpFile: `${AppConfig.Origin}/file/add`,
download: `${AppConfig.Origin}/resource/download`,
comment: `${AppConfig.Origin}/resource/comment`,
getAllLanguages: `${AppConfig.Origin}/codebooks/getAllLanguages`,
......@@ -34,6 +36,8 @@ export class AppConfig {
getAllPests: `${AppConfig.Origin}/codebooks/getAllPests`,
getAllCrops: `${AppConfig.Origin}/codebooks/getAllCrops`,
getAllKeywords: `${AppConfig.Origin}/codebooks/getAllKeywords`,
addPest:`${AppConfig.Origin}/codebooks/savePest`,
addCrop:`${AppConfig.Origin}/codebooks/saveCrop`,
getAllHelpFilesDesc: `${AppConfig.Origin}/file/help/list`,
login:`${AppConfig.Origin}/auth/authenticate`,
......
*{
font-family: 'Roboto', sans-serif;
font-family: OpenSans, sans-serif;
}
.container-fluid {
min-height: 100vh;
......@@ -9,7 +10,7 @@
margin:-8px;
background-color:white !important;
min-height:170px;
border-bottom: 10px solid #71B532 !important;
border-bottom: 10px solid #097b32 !important;
justify-content: space-between !important;
align-items: baseline !important;
}
......@@ -49,10 +50,10 @@
justify-content: center;
}
.p-button.p-button-outlined{
color:#00662e !important;
color:#097b32 !important;
}
.p-button:not(.p-button-outlined){
background-color:#00662e;
background-color:#097b32;
}
.p-grid {
......@@ -70,8 +71,15 @@
.p-menuitem-text{
color: #003519 !important;
}
.p-message .p-message-summary{
color:white !important;
}
.p-message .p-message-detail{
color:white !important;
}
.p-message.p-message-info{
background:#71B532 !important;
background:#0a4b27 !important;
color:white !important;
}
.p-message.p-message-info .p-message-icon{
......@@ -90,3 +98,33 @@
.p-avatar{
background-color: white !important;
}
.button-dark-green{
background-color: #0a4b27 !important;
}
.button-light-green{
background-color: #097b32 !important;
}
.button-dark-orange{
background-color: #eda33f !important;
}
.button-light-orange{
background: #f3b967 !important;
}
.p-button:enabled:hover{
background-color: #0a4b27 !important;
}
.p-button.p-button-link:enabled:hover{
background-color: white !important;
}
.p-message .p-message-icon, .p-message-close-icon{
color:white !important;
}
.p-accordion-header-text{
color: #097b32 !important;
font-weight: bolder !important;
}
:host ::ng-deep .ng2-pdf-viewer-container {
height: auto !important;
overflow-y: hidden !important;
}
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment