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 {
}
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>
......
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;
}
}
......@@ -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;
}
......@@ -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