Merge branch 'develop' into feature/AW6526Angular20
Some checks failed
FarmMaps.Develop/FarmMapsLib/pipeline/head There was a failure building this commit

# Conflicts:
#	package-lock.json
This commit is contained in:
2026-01-20 17:38:21 +01:00
51 changed files with 4002 additions and 3203 deletions

View File

@@ -294,5 +294,31 @@
}, },
"cli": { "cli": {
"analytics": false "analytics": false
},
"schematics": {
"@schematics/angular:component": {
"type": "component"
},
"@schematics/angular:directive": {
"type": "directive"
},
"@schematics/angular:service": {
"type": "service"
},
"@schematics/angular:guard": {
"typeSeparator": "."
},
"@schematics/angular:interceptor": {
"typeSeparator": "."
},
"@schematics/angular:module": {
"typeSeparator": "."
},
"@schematics/angular:pipe": {
"typeSeparator": "."
},
"@schematics/angular:resolver": {
"typeSeparator": "."
}
} }
} }

5616
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -11,24 +11,24 @@
}, },
"private": true, "private": true,
"dependencies": { "dependencies": {
"@angular-eslint/eslint-plugin": "^18.2.0", "@angular-eslint/eslint-plugin": "20.7.0",
"@angular/animations": "19.2.18", "@angular/animations": "20.3.16",
"@angular/common": "19.2.18", "@angular/common": "20.3.16",
"@angular/compiler": "19.2.18", "@angular/compiler": "20.3.16",
"@angular/core": "19.2.18", "@angular/core": "20.3.16",
"@angular/forms": "19.2.18", "@angular/forms": "20.3.16",
"@angular/platform-browser": "19.2.18", "@angular/platform-browser": "20.3.16",
"@angular/platform-browser-dynamic": "19.2.18", "@angular/platform-browser-dynamic": "20.3.16",
"@angular/router": "19.2.18", "@angular/router": "20.3.16",
"@farmmaps/common": "file:dist/common", "@farmmaps/common": "file:dist/common",
"@farmmaps/common-map": "file:dist/common-map", "@farmmaps/common-map": "file:dist/common-map",
"@farmmaps/common-map3d": "file:dist/common-map3d", "@farmmaps/common-map3d": "file:dist/common-map3d",
"@farmmaps/ng-openlayers": "file:dist/ng-openlayers", "@farmmaps/ng-openlayers": "file:dist/ng-openlayers",
"@microsoft/signalr": "^3.1.16", "@microsoft/signalr": "^3.1.16",
"@ng-bootstrap/ng-bootstrap": "^18.0.0", "@ng-bootstrap/ng-bootstrap": "^19.0.0",
"@ngrx/effects": "19.2.1", "@ngrx/effects": "20.1.0",
"@ngrx/router-store": "19.2.1", "@ngrx/router-store": "20.1.0",
"@ngrx/store": "19.2.1", "@ngrx/store": "20.1.0",
"@popperjs/core": "^2.11.8", "@popperjs/core": "^2.11.8",
"angular-oauth2-oidc": "^17.0.2", "angular-oauth2-oidc": "^17.0.2",
"assert": "^2.0.0", "assert": "^2.0.0",
@@ -39,8 +39,8 @@
"core-js": "^2.6.12", "core-js": "^2.6.12",
"https-browserify": "^1.0.0", "https-browserify": "^1.0.0",
"moment": "^2.29.4", "moment": "^2.29.4",
"ngrx-store-localstorage": "19.0.2", "ngrx-store-localstorage": "20.1.0",
"ngx-avatars": "1.9.3", "ngx-avatars": "1.10.0",
"ngx-clipboard": "^16.0.0", "ngx-clipboard": "^16.0.0",
"ngx-image-cropper": "^7.0.0", "ngx-image-cropper": "^7.0.0",
"ngx-uploadx": "7.0.1", "ngx-uploadx": "7.0.1",
@@ -61,12 +61,12 @@
"@rollup/rollup-linux-x64-gnu": "^4.21.2" "@rollup/rollup-linux-x64-gnu": "^4.21.2"
}, },
"devDependencies": { "devDependencies": {
"@angular-builders/custom-webpack": "19.0.1", "@angular-builders/custom-webpack": "20.0.0",
"@angular-devkit/build-angular": "19.2.19", "@angular-devkit/build-angular": "20.3.14",
"@angular/cli": "19.2.19", "@angular/cli": "20.3.14",
"@angular/compiler-cli": "19.2.18", "@angular/compiler-cli": "20.3.16",
"@angular/language-service": "19.2.18", "@angular/language-service": "20.3.16",
"@angular/localize": "19.2.18", "@angular/localize": "20.3.16",
"@types/arcgis-rest-api": "^10.4.5", "@types/arcgis-rest-api": "^10.4.5",
"@types/jasmine": "~2.8.8", "@types/jasmine": "~2.8.8",
"@types/jasminewd2": "^2.0.9", "@types/jasminewd2": "^2.0.9",
@@ -85,7 +85,7 @@
"karma-coverage-istanbul-reporter": "^3.0.3", "karma-coverage-istanbul-reporter": "^3.0.3",
"karma-jasmine": "^5.1.0", "karma-jasmine": "^5.1.0",
"karma-jasmine-html-reporter": "^2.0.0", "karma-jasmine-html-reporter": "^2.0.0",
"ng-packagr": "^19.2.2", "ng-packagr": "^20.3.2",
"protractor": "~7.0.0", "protractor": "~7.0.0",
"ts-node": "^8.8.1", "ts-node": "^8.8.1",
"typescript": "~5.8.3" "typescript": "~5.8.3"

View File

@@ -8,11 +8,11 @@
"tslib": "^2.0.0" "tslib": "^2.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"@angular/core": "19.2.18", "@angular/core": "20.3.16",
"ngrx-store-localstorage": "19.0.2", "ngrx-store-localstorage": "20.1.0",
"@ngrx/effects": "19.2.1", "@ngrx/effects": "20.1.0",
"@ngrx/router-store": "19.2.1", "@ngrx/router-store": "20.1.0",
"@ngrx/store": "19.2.1", "@ngrx/store": "20.1.0",
"tassign": "^1.0.0" "tassign": "^1.0.0"
} }
} }

View File

@@ -1,31 +1,50 @@
<div> <div>
<div class="layerlist" *ngIf="itemLayers.length > 0;else noLayers"> @if (itemLayers.length > 0) {
<div class="layerlist">
<div class="list-group"> <div class="list-group">
<div *ngFor="let itemLayer of itemLayers" class="list-group-item list-group-item-action p-2 text-truncate" [ngClass]="{'active' : selectedLayer==itemLayer}"> @for (itemLayer of itemLayers; track itemLayer) {
<div class="list-group-item list-group-item-action p-2 text-truncate" [ngClass]="{'active' : selectedLayer==itemLayer}">
<div (click)="handleSelectLayer($event,itemLayer)" [title]="itemLayer.item.name">{{itemLayer.item.name}}</div> <div (click)="handleSelectLayer($event,itemLayer)" [title]="itemLayer.item.name">{{itemLayer.item.name}}</div>
<div class="mt-1" *ngIf="selectedLayer==itemLayer && !baseLayers"> @if (selectedLayer==itemLayer && !baseLayers) {
<div class="mt-1">
<span class="btn-group"> <span class="btn-group">
<a title="Toggle visibility"href="#" class="btn btn-light btn-sm" (click)="handleToggleVisibility($event,itemLayer)"><i class="fa" aria-hidden="true" [ngClass]="{'fa-eye':!itemLayer.visible,'fa-eye-slash':itemLayer.visible}"></i></a> <a title="Toggle visibility"href="#" class="btn btn-light btn-sm" (click)="handleToggleVisibility($event,itemLayer)"><i class="fa" aria-hidden="true" [ngClass]="{'fa-eye':!itemLayer.visible,'fa-eye-slash':itemLayer.visible}"></i></a>
<a title="Transparency 25%" *ngIf="itemLayer.visible" href="#" class="btn btn-light btn-sm" (click)="handleSetOpacity($event,itemLayer,0.25)">25%</a> @if (itemLayer.visible) {
<a title="Transparency 50%" *ngIf="itemLayer.visible" href="#" class="btn btn-light btn-sm" (click)="handleSetOpacity($event,itemLayer,0.5)">50%</a> <a title="Transparency 25%" href="#" class="btn btn-light btn-sm" (click)="handleSetOpacity($event,itemLayer,0.25)">25%</a>
<a title="Transparency 75%" *ngIf="itemLayer.visible" href="#" class="btn btn-light btn-sm" (click)="handleSetOpacity($event,itemLayer,0.75)">75%</a> }
<a title="No transparency" *ngIf="itemLayer.visible" href="#" class="btn btn-light btn-sm" (click)="handleSetOpacity($event,itemLayer,1)">100%</a> @if (itemLayer.visible) {
<a title="Transparency 50%" href="#" class="btn btn-light btn-sm" (click)="handleSetOpacity($event,itemLayer,0.5)">50%</a>
}
@if (itemLayer.visible) {
<a title="Transparency 75%" href="#" class="btn btn-light btn-sm" (click)="handleSetOpacity($event,itemLayer,0.75)">75%</a>
}
@if (itemLayer.visible) {
<a title="No transparency" href="#" class="btn btn-light btn-sm" (click)="handleSetOpacity($event,itemLayer,1)">100%</a>
}
</span> </span>
<a href="#" title="Zoom to extent" class="btn btn-light btn-sm" (click)="handleZoomToExtent($event,itemLayer)"><i class="far fa-search-plus" aria-hidden="true"></i></a> <a href="#" title="Zoom to extent" class="btn btn-light btn-sm" (click)="handleZoomToExtent($event,itemLayer)"><i class="far fa-search-plus" aria-hidden="true"></i></a>
<span *ngIf="firstLayer(itemLayer)"><a href="#" title="Toggle legend" class="btn btn-light btn-sm" (click)="itemLayer.legendVisible=toggleLegend($event,itemLayer.legendVisible)"><i class="far fa-chart-bar" aria-hidden="true"></i></a></span> @if (firstLayer(itemLayer)) {
<span *ngIf="!dataLayers" class="float-end"><a href="#" title="Remove overlay" class="btn btn-light btn-sm" (click)="handleDelete($event,itemLayer)"><i class="fas fa-layer-minus" aria-hidden="true"></i></a></span> <span><a href="#" title="Toggle legend" class="btn btn-light btn-sm" (click)="itemLayer.legendVisible=toggleLegend($event,itemLayer.legendVisible)"><i class="far fa-chart-bar" aria-hidden="true"></i></a></span>
}
@if (!dataLayers) {
<span class="float-end"><a href="#" title="Remove overlay" class="btn btn-light btn-sm" (click)="handleDelete($event,itemLayer)"><i class="fas fa-layer-minus" aria-hidden="true"></i></a></span>
}
</div> </div>
<div *ngIf="itemLayer.legendVisible"> }
@if (itemLayer.legendVisible) {
<div>
<div class="card legend"> <div class="card legend">
<fm-map-layer-legend [layer]="firstLayer(itemLayer)" (click)="handleLegendClick($event,itemLayer);" [histogramenabled]="true"></fm-map-layer-legend> <fm-map-layer-legend [layer]="firstLayer(itemLayer)" (click)="handleLegendClick($event,itemLayer);" [histogramenabled]="true"></fm-map-layer-legend>
</div> </div>
</div> </div>
}
</div>
}
</div> </div>
</div> </div>
</div> } @else {
</div>
<ng-template #noLayers>
<div class="list-group"> <div class="list-group">
<div class="list-group-item" i18n>No layers</div> <div class="list-group-item" i18n>No layers</div>
</div> </div>
</ng-template> }
</div>

View File

@@ -1,18 +1,27 @@
<div #layerValues class="layer-values"> <div #layerValues class="layer-values">
<div class="cross" *ngIf="enabled$ | async"> @if (enabled$ | async) {
<div class="cross" >
<div class="pointer"></div> <div class="pointer"></div>
<div class="values-container border border-dark rounded p-2" *ngIf="(layerValues$ | async ) as layers"> @if ((layerValues$ | async ); as layers) {
<div class="values-container border border-dark rounded p-2">
<div class="lonlat pb-2 "><span class="font-weight-bold">{{lonlat$}}</span><i class="ms-2 fal fa-copy" (click)="copyToClipboard()"></i> </div> <div class="lonlat pb-2 "><span class="font-weight-bold">{{lonlat$}}</span><i class="ms-2 fal fa-copy" (click)="copyToClipboard()"></i> </div>
<ul class="value-list p-0 mb-0" *ngIf="layers.length>0 ;else no_data"> @if (layers.length>0 ) {
<li class="border-top pt-1 pb-1 value" *ngFor="let layerValue of layers"> <ul class="value-list p-0 mb-0">
@for (layerValue of layers; track layerValue) {
<li class="border-top pt-1 pb-1 value">
<div>{{layerValue.layerName}}</div> <div>{{layerValue.layerName}}</div>
<div>{{layerValue.date|date}}</div> <div>{{layerValue.date|date}}</div>
<div><span *ngIf="layerValue.quantity"><span class="me-1">{{layerValue.quantity}}</span> </span><span class="me-1 font-weight-bold">{{getScaledValue(layerValue)}}</span><span>{{layerValue.unit}}</span></div> <div>@if (layerValue.quantity) {
<span><span class="me-1">{{layerValue.quantity}}</span> </span>
}<span class="me-1 font-weight-bold">{{getScaledValue(layerValue)}}</span><span>{{layerValue.unit}}</span></div>
</li> </li>
}
</ul> </ul>
<ng-template #no_data> } @else {
<div i18n class="border-top pt-1 pb-1">No data at location</div> <div i18n class="border-top pt-1 pb-1">No data at location</div>
</ng-template> }
</div> </div>
}
</div> </div>
}
</div> </div>

View File

@@ -1,14 +1,20 @@
<div class="card border-0"> <div class="card border-0">
<div class="card-body" *ngIf="(schemeItem|async);let schemeItem"> @if ((schemeItem|async); as schemeItem) {
<div class="card-body">
<fm-back-button></fm-back-button> <fm-back-button></fm-back-button>
<h4 i18n>Farm</h4> <h4 i18n>Farm</h4>
<h3>{{schemeItem.name}}</h3> <h3>{{schemeItem.name}}</h3>
<div *ngIf="features;let features"> @if (features; as features) {
<div>
<div class="cropfields"> <div class="cropfields">
<div class="row m-0 ps-3 pe-3" *ngFor="let feature of features" [ngClass]="{'selected':isFeatureSelected(feature)}" (click)="handleFeatureClick(feature)" (mouseenter)="handleFeatureMouseEnter(feature)" (mouseleave)="handleFeatureMouseLeave(feature)"> @for (feature of features; track feature) {
<div class="row m-0 ps-3 pe-3" [ngClass]="{'selected':isFeatureSelected(feature)}" (click)="handleFeatureClick(feature)" (mouseenter)="handleFeatureMouseEnter(feature)" (mouseleave)="handleFeatureMouseLeave(feature)">
<fm-map-feature-list-feature-container [feature]="feature"></fm-map-feature-list-feature-container> <fm-map-feature-list-feature-container [feature]="feature"></fm-map-feature-list-feature-container>
</div> </div>
}
</div> </div>
</div> </div>
}
</div> </div>
}
</div> </div>

View File

@@ -2,12 +2,16 @@
<div class="card-body"> <div class="card-body">
<fm-back-button></fm-back-button> <fm-back-button></fm-back-button>
<h3><i class="far fa-farm"></i>&nbsp;<span i18n>Farms</span></h3> <h3><i class="far fa-farm"></i>&nbsp;<span i18n>Farms</span></h3>
<div *ngIf="features;let features"> @if (features; as features) {
<div>
<div class="farms"> <div class="farms">
<div class="row m-0 ps-3 pe-3" *ngFor="let feature of features"[ngClass]="{'selected':isFeatureSelected(feature)}" (click)="handleFeatureClick(feature)" (mouseenter)="handleFeatureMouseEnter(feature)" (mouseleave)="handleFeatureMouseLeave(feature)"> @for (feature of features; track feature) {
<div class="row m-0 ps-3 pe-3"[ngClass]="{'selected':isFeatureSelected(feature)}" (click)="handleFeatureClick(feature)" (mouseenter)="handleFeatureMouseEnter(feature)" (mouseleave)="handleFeatureMouseLeave(feature)">
<fm-map-feature-list-feature-container [feature]="feature"></fm-map-feature-list-feature-container> <fm-map-feature-list-feature-container [feature]="feature"></fm-map-feature-list-feature-container>
</div> </div>
}
</div> </div>
</div> </div>
}
</div> </div>
</div> </div>

View File

@@ -1,4 +1,5 @@
<div *ngIf="feature;let feature" class="d-flex m-0"> @if (feature; as feature) {
<div class="d-flex m-0">
<div class="p-2"> <div class="p-2">
<div class="thumbnail"> <div class="thumbnail">
<fm-map-feature-thumbnail [feature]="feature"></fm-map-feature-thumbnail> <fm-map-feature-thumbnail [feature]="feature"></fm-map-feature-thumbnail>
@@ -12,3 +13,4 @@
<span>{{feature.get('dataenddate')|date}}</span> </div> <span>{{feature.get('dataenddate')|date}}</span> </div>
</div> </div>
</div> </div>
}

View File

@@ -1,6 +1,8 @@
<div *ngIf="feature;let feature" class="row m-0"> @if (feature; as feature) {
<div class="row m-0">
<div class="col p-2"> <div class="col p-2">
<h1 class="card-title" title="{{feature.get('name')}}">{{feature.get('name')}}</h1> <h1 class="card-title" title="{{feature.get('name')}}">{{feature.get('name')}}</h1>
<div class="card-text">{{feature.get('datadate')|date:'shortDate'}}</div> <div class="card-text">{{feature.get('datadate')|date:'shortDate'}}</div>
</div> </div>
</div> </div>
}

View File

@@ -1,12 +1,18 @@
<div *ngIf="feature;let feature" class="row m-0"> @if (feature; as feature) {
<div class="row m-0">
<div class="col-3 w-25 m-0 p-2 thumbnail"> <div class="col-3 w-25 m-0 p-2 thumbnail">
<img *ngIf="feature.get('thumbnail')" [src]="config.getConfig('apiEndPoint') + '/api/v1/items/'+feature.get('code')+'/thumbnail'" /> @if (feature.get('thumbnail')) {
<div *ngIf="!feature.get('thumbnail')" [style.background-color]="itemTypeService.getColor(feature.get('itemType'))"> <img [src]="config.getConfig('apiEndPoint') + '/api/v1/items/'+feature.get('code')+'/thumbnail'" />
}
@if (!feature.get('thumbnail')) {
<div [style.background-color]="itemTypeService.getColor(feature.get('itemType'))">
<i [ngClass]="itemTypeService.getIcon(feature.get('itemType'))"></i> <i [ngClass]="itemTypeService.getIcon(feature.get('itemType'))"></i>
</div> </div>
}
</div> </div>
<div class="col p-2"> <div class="col p-2">
<h1 class="card-title" title="{{feature.get('name')}}"><i [ngClass]="itemTypeService.getIcon(feature.get('itemType'))" [style.color]="itemTypeService.getColor(feature.get('itemType'))"></i>&nbsp;{{feature.get('name')}}</h1> <h1 class="card-title" title="{{feature.get('name')}}"><i [ngClass]="itemTypeService.getIcon(feature.get('itemType'))" [style.color]="itemTypeService.getColor(feature.get('itemType'))"></i>&nbsp;{{feature.get('name')}}</h1>
<div class="card-text">{{feature.get('datadate')|date:'shortDate'}}</div> <div class="card-text">{{feature.get('datadate')|date:'shortDate'}}</div>
</div> </div>
</div> </div>
}

View File

@@ -1,14 +1,20 @@
<div class="card border-0"> <div class="card border-0">
<div class="card-body" *ngIf="(schemeItem|async);let schemeItem"> @if ((schemeItem|async); as schemeItem) {
<div class="card-body">
<fm-back-button></fm-back-button> <fm-back-button></fm-back-button>
<h4 i18n>Farm</h4> <h4 i18n>Farm</h4>
<h3>{{schemeItem.name}}</h3> <h3>{{schemeItem.name}}</h3>
<div *ngIf="features;let features"> @if (features; as features) {
<div>
<div class="cropfields"> <div class="cropfields">
<div class="row m-0 ps-3 pe-3" *ngFor="let feature of features" [ngClass]="{'selected':isFeatureSelected(feature)}" (click)="handleFeatureClick(feature)" (mouseenter)="handleFeatureMouseEnter(feature)" (mouseleave)="handleFeatureMouseLeave(feature)"> @for (feature of features; track feature) {
<div class="row m-0 ps-3 pe-3" [ngClass]="{'selected':isFeatureSelected(feature)}" (click)="handleFeatureClick(feature)" (mouseenter)="handleFeatureMouseEnter(feature)" (mouseleave)="handleFeatureMouseLeave(feature)">
<fm-map-feature-list-feature-container [feature]="feature"></fm-map-feature-list-feature-container> <fm-map-feature-list-feature-container [feature]="feature"></fm-map-feature-list-feature-container>
</div> </div>
}
</div> </div>
</div> </div>
}
</div> </div>
}
</div> </div>

View File

@@ -1,6 +1,10 @@
<div *ngIf="features;let features"> @if (features; as features) {
<div>
<fm-back-button></fm-back-button> <fm-back-button></fm-back-button>
<div class="row m-0 ps-3 pe-3" *ngFor="let feature of features" [ngClass]="{'selected':isFeatureSelected(feature)}" (click)="handleFeatureClick(feature)" (mouseenter)="handleFeatureMouseEnter(feature)" (mouseleave)="handleFeatureMouseLeave(feature)"> @for (feature of features; track feature) {
<div class="row m-0 ps-3 pe-3" [ngClass]="{'selected':isFeatureSelected(feature)}" (click)="handleFeatureClick(feature)" (mouseenter)="handleFeatureMouseEnter(feature)" (mouseleave)="handleFeatureMouseLeave(feature)">
<fm-map-feature-list-feature-container [feature]="feature"></fm-map-feature-list-feature-container> <fm-map-feature-list-feature-container [feature]="feature"></fm-map-feature-list-feature-container>
</div> </div>
}
</div> </div>
}

View File

@@ -1,4 +1,6 @@
<div *ngIf="item;let item" class="widget" [style.background-color]="itemTypeService.getColor(item.itemType)"> @if (item; as item) {
<div class="widget" [style.background-color]="itemTypeService.getColor(item.itemType)">
<div class="align-middle icon" [ngClass]="itemTypeService.getIcon(item.itemType)"></div> <div class="align-middle icon" [ngClass]="itemTypeService.getIcon(item.itemType)"></div>
<div class="title">{{item.name}}</div> <div class="title">{{item.name}}</div>
</div> </div>
}

View File

@@ -1,7 +1,11 @@
<div *ngIf="items;let items" class="widget-container pt-0"> @if (items; as items) {
<div class="widget" *ngFor="let item of items" (click)="handleItemClick(item)"> <div class="widget-container pt-0">
@for (item of items; track item) {
<div class="widget" (click)="handleItemClick(item)">
<div class="content"> <div class="content">
<fm-map-item-list-item-container [item]="item" class="item-container"></fm-map-item-list-item-container> <fm-map-item-list-item-container [item]="item" class="item-container"></fm-map-item-list-item-container>
</div> </div>
</div> </div>
}
</div> </div>
}

View File

@@ -1,7 +1,11 @@
<div *ngIf="widgets;let widgets" class="widget-container pt-0"> @if (widgets; as widgets) {
<div class="widget" *ngFor="let widget of widgets"> <div class="widget-container pt-0">
@for (widget of widgets; track widget) {
<div class="widget">
<div class="content"> <div class="content">
<ng-template #widgetTemplate></ng-template> <ng-template #widgetTemplate></ng-template>
</div> </div>
</div> </div>
}
</div> </div>
}

View File

@@ -19,12 +19,14 @@
<fm-map-layer-list [itemLayers]="overlayLayers|async" [selectedLayer]="selectedOverlayLayer|async" (onDelete)="handleOnDelete($event)" (onToggleVisibility)="handleOnToggleVisibility($event)" (onSetOpacity)="handleOnSetOpacity($event)" (onZoomToExtent)="handleZoomToExtent($event)" (onSelectLayer)="handleSelectOverlayLayer($event)"></fm-map-layer-list> <fm-map-layer-list [itemLayers]="overlayLayers|async" [selectedLayer]="selectedOverlayLayer|async" (onDelete)="handleOnDelete($event)" (onToggleVisibility)="handleOnToggleVisibility($event)" (onSetOpacity)="handleOnSetOpacity($event)" (onZoomToExtent)="handleZoomToExtent($event)" (onSelectLayer)="handleSelectOverlayLayer($event)"></fm-map-layer-list>
</div> </div>
</li> </li>
<li class="nav-item py-0" *ngIf="selectedItemLayer$ | async as selectedItemLayer"> @if (selectedItemLayer$ | async; as selectedItemLayer) {
<li class="nav-item py-0">
<span><i class="fal fa-layer-group" aria-hidden="true"></i>&nbsp;<span i18n>Overlay slider</span><span class="slideButton"><a href="#" title="Compare" class="btn btn-light btn-sm" (click)="handleToggleShowDatalayerSlide($event)"><i class="fal fa-sliders-h-square"></i></a></span></span> <span><i class="fal fa-layer-group" aria-hidden="true"></i>&nbsp;<span i18n>Overlay slider</span><span class="slideButton"><a href="#" title="Compare" class="btn btn-light btn-sm" (click)="handleToggleShowDatalayerSlide($event)"><i class="fal fa-sliders-h-square"></i></a></span></span>
<div class="mb-4"> <div class="mb-4">
<fm-map-layer-list [dataLayers]="true" [itemLayers]="[selectedItemLayer]" [selectedLayer]="selectedItemLayer" (onToggleVisibility)="handleOnToggleVisibility($event)" (onSetOpacity)="handleOnSetOpacity($event)" (onZoomToExtent)="handleZoomToExtent($event)" (onSelectLayer)="handleSelectOverlayLayer($event)"></fm-map-layer-list> <fm-map-layer-list [dataLayers]="true" [itemLayers]="[selectedItemLayer]" [selectedLayer]="selectedItemLayer" (onToggleVisibility)="handleOnToggleVisibility($event)" (onSetOpacity)="handleOnSetOpacity($event)" (onZoomToExtent)="handleZoomToExtent($event)" (onSelectLayer)="handleSelectOverlayLayer($event)"></fm-map-layer-list>
</div> </div>
</li> </li>
}
<li class="nav-item py-0"> <li class="nav-item py-0">
<span><i class="fal fa-layer-group" aria-hidden="true"></i>&nbsp;<span i18n>Aerial photos</span></span> <span><i class="fal fa-layer-group" aria-hidden="true"></i>&nbsp;<span i18n>Aerial photos</span></span>
<div class="mb-4"> <div class="mb-4">

View File

@@ -8,8 +8,8 @@
<div class="col-8 nopadding" ><span i18n>Max</span>:</div> <div class="col-8 nopadding" ><span i18n>Max</span>:</div>
<div class="col-4 pull-left nopadding">{{ getScaledValue(histogram.max)| number:'1.0-2'}}</div> <div class="col-4 pull-left nopadding">{{ getScaledValue(histogram.max)| number:'1.0-2'}}</div>
<ng-container *ngIf="showConfidenceInterval()"> @if (showConfidenceInterval()) {
<div class="col-8 nopadding"><span i18n>Confidence interval</span>:</div> <div class="col-8 nopadding"><span i18n>Confidence interval</span>:</div>
<div class="col-4 pull-left nopadding">{{ getScaledValue(histogram.confidence * 100)| number:'1.0-0'}}%</div> <div class="col-4 pull-left nopadding">{{ getScaledValue(histogram.confidence * 100)| number:'1.0-0'}}%</div>
</ng-container> }
</div> </div>

View File

@@ -1,46 +1,66 @@
<table class="container" *ngIf="showLegend()"> @if (showLegend()) {
<table class="container">
<tr> <tr>
<td colspan="3"> <td colspan="3">
<div class="title"> <div class="title">
<h4 *ngIf="showTitle">{{layer.name}}</h4> @if (showTitle) {
<b *ngIf="layer.unit">({{layer.unit}})</b> <h4>{{layer.name}}</h4>
}
@if (layer.unit) {
<b>({{layer.unit}})</b>
}
</div> </div>
</td> </td>
<td> <td>
<a i18n-title title="more info"><i class="fal fa-info-circle text-primary" (click)="hideHistogramDetails = !hideHistogramDetails"></i></a> <a i18n-title title="more info"><i class="fal fa-info-circle text-primary" (click)="hideHistogramDetails = !hideHistogramDetails"></i></a>
</td> </td>
<td colspan="2"> <td colspan="2">
<div class="title" *ngIf="histogramenabled"> @if (histogramenabled) {
<div class="title">
<h4>{{histogram}}</h4> <h4>{{histogram}}</h4>
<b *ngIf="histogramunit">({{histogramunit}})</b> @if (histogramunit) {
<b>({{histogramunit}})</b>
}
</div> </div>
}
</td> </td>
</tr> </tr>
<tr *ngFor="let entry of layer.renderer.colorMap.entries; let i = index "> @for (entry of layer.renderer.colorMap.entries; track entry; let i = $index) {
<tr>
<td class="legend-items"><span [style.background-color]="getAlphaHex(entry.color)" [style.border-color]="getHex(entry.color)"class="color"></span></td> <td class="legend-items"><span [style.background-color]="getAlphaHex(entry.color)" [style.border-color]="getHex(entry.color)"class="color"></span></td>
<td class="legend-items-text"><span *ngIf="!entry.label">{{getScaledValue(entry.value,layer.scale) | number:'1.0-2'}} {{legendunit}}</span><span *ngIf="entry.label">{{entry.label}}</span></td> <td class="legend-items-text">@if (!entry.label) {
<span>{{getScaledValue(entry.value,layer.scale) | number:'1.0-2'}} {{legendunit}}</span>
}@if (entry.label) {
<span>{{entry.label}}</span>
}</td>
<td class="histogram-items"> <td class="histogram-items">
<div *ngIf="showHistogram()"> @if (showHistogram()) {
<div>
<span class="bar" [style.background-color]="getHex(entry.color)" [style.width]="getPart(layer.renderer, i)"> <span class="bar" [style.background-color]="getHex(entry.color)" [style.width]="getPart(layer.renderer, i)">
</span> </span>
<span *ngIf="getPercentage(layer.renderer,i) as percentage" class="bar-label">{{percentage | number:'1.0-2'}} %</span> @if (getPercentage(layer.renderer,i); as percentage) {
<span class="bar-label">{{percentage | number:'1.0-2'}} %</span>
}
</div> </div>
}
</td> </td>
</tr> </tr>
<tr *ngIf="showHistogram()"> }
@if (showHistogram()) {
<tr>
<td colspan="4" class="pb-1 pt-1"> <td colspan="4" class="pb-1 pt-1">
<div class="info" [ngbCollapse]="hideHistogramDetails"> <div class="info" [ngbCollapse]="hideHistogramDetails">
<ng-container *ngIf="bandContainsStatistics(); else histogram"> @if (bandContainsStatistics()) {
<fm-map-statistics-details [statistics]="layer.renderer.band.statistics" [scale]="layer.scale"></fm-map-statistics-details> <fm-map-statistics-details [statistics]="layer.renderer.band.statistics" [scale]="layer.scale"></fm-map-statistics-details>
</ng-container> } @else {
<ng-template #histogram>
<fm-map-histogram-details [histogram]="layer.renderer.band.histogram" [scale]="layer.scale"></fm-map-histogram-details> <fm-map-histogram-details [histogram]="layer.renderer.band.histogram" [scale]="layer.scale"></fm-map-histogram-details>
</ng-template> }
</div> </div>
</td> </td>
</tr> </tr>
}
</table> </table>
}

View File

@@ -29,8 +29,8 @@
<div class="col-4 pull-left nopadding">{{getSquaredScaledValue(statistics.variance)| number:'1.0-2'}}</div> <div class="col-4 pull-left nopadding">{{getSquaredScaledValue(statistics.variance)| number:'1.0-2'}}</div>
<div class="col-8 nopadding"><span i18n>Coefficient of variation</span>:</div> <div class="col-8 nopadding"><span i18n>Coefficient of variation</span>:</div>
<div class="col-4 pull-left nopadding">{{statistics.variationCoefficient | number:'1.0-2'}}</div> <div class="col-4 pull-left nopadding">{{statistics.variationCoefficient | number:'1.0-2'}}</div>
<ng-container *ngIf="statistics.confidenceIntervalLow !== undefined"> @if (statistics.confidenceIntervalLow !== undefined) {
<div class="col-8 nopadding">90% <span i18n>Confidence interval</span>:</div> <div class="col-8 nopadding">90% <span i18n>Confidence interval</span>:</div>
<div class="col-4 pull-left nopadding">{{getScaledValue(statistics.confidenceIntervalLow) | number:'1.0-2'}} - {{getScaledValue(statistics.confidenceIntervalHigh) | number:'1.0-2'}}</div> <div class="col-4 pull-left nopadding">{{getScaledValue(statistics.confidenceIntervalLow) | number:'1.0-2'}} - {{getScaledValue(statistics.confidenceIntervalHigh) | number:'1.0-2'}}</div>
</ng-container> }
</div> </div>

View File

@@ -1,4 +1,4 @@
<ng-container *ngIf="{ @if ({
mapState:mapState$|async, mapState:mapState$|async,
extent:extent$|async, extent:extent$|async,
baseLayers:baseLayers$|async, baseLayers:baseLayers$|async,
@@ -22,23 +22,25 @@
styles:styles$|async, styles:styles$|async,
selectedFeature:selectedFeature$|async, selectedFeature:selectedFeature$|async,
fullscreen:fullscreen$|async, fullscreen:fullscreen$|async,
showDataLayerSlide:showDataLayerSlide$|async showDataLayerSlide:showDataLayerSlide$|async,
} as state"> menuVisible:menuVisible$|async,
}; as state) {
<aol-map #map (moveEnd)="handleOnMoveEnd($event)" (click)="handleOnMouseDown($event)" (dblClick)="handleShowLayerValues($event)" [ngClass]="{'panel-visible':state.panelVisible,'fullscreen':state.fullscreen }" class="map"> <aol-map #map (moveEnd)="handleOnMoveEnd($event)" (click)="handleOnMouseDown($event)" (dblClick)="handleShowLayerValues($event)" [ngClass]="{'panel-visible':state.panelVisible,'fullscreen':state.fullscreen }" class="map">
<div> <div>
</div> </div>
<aol-view [zoom]="state.mapState.zoom" [rotation]="state.mapState.rotation"> <aol-view [zoom]="state.mapState.zoom" [rotation]="state.mapState.rotation">
<aol-coordinate [x]="state.mapState.xCenter" [y]="state.mapState.yCenter" [srid]="'EPSG:4326'"></aol-coordinate> <aol-coordinate [x]="state.mapState.xCenter" [y]="state.mapState.yCenter" [srid]="'EPSG:4326'"></aol-coordinate>
<fm-map-zoom-to-extent [extent]="state.extent" [animate]="true"></fm-map-zoom-to-extent> <fm-map-zoom-to-extent [extent]="state.extent" [animate]="true"></fm-map-zoom-to-extent>
</aol-view> </aol-view>
<aol-interaction-default></aol-interaction-default> <aol-interaction-default></aol-interaction-default>
<aol-interaction-dragrotateandzoom></aol-interaction-dragrotateandzoom> <aol-interaction-dragrotateandzoom></aol-interaction-dragrotateandzoom>
<fm-map-item-layers [itemLayers]="state.baseLayers"></fm-map-item-layers> <fm-map-item-layers [itemLayers]="state.baseLayers"></fm-map-item-layers>
<fm-map-item-layers *ngIf="!overrideOverlayLayers" [itemLayers]="state.overlayLayers"></fm-map-item-layers> @if (!overrideOverlayLayers) {
<fm-map-item-layers *ngIf="!overrideSelectedItemLayer" [itemLayer]="state.selectedItemLayer" (onPrerender)="handlePrerender($event)"></fm-map-item-layers> <fm-map-item-layers [itemLayers]="state.overlayLayers"></fm-map-item-layers>
}
@if (!overrideSelectedItemLayer) {
<fm-map-item-layers [itemLayer]="state.selectedItemLayer" (onPrerender)="handlePrerender($event)"></fm-map-item-layers>
}
<aol-layer-vector> <aol-layer-vector>
<fm-map-item-source-vector [styles]="state.styles" [features]="state.features" (onFeatureSelected)="handleFeatureClick($event)" (onFeatureHover)="handleFeatureHover($event)" [selectedFeature]="state.selectedFeature" [selectedItem]="state.selectedItem"></fm-map-item-source-vector> <fm-map-item-source-vector [styles]="state.styles" [features]="state.features" (onFeatureSelected)="handleFeatureClick($event)" (onFeatureHover)="handleFeatureHover($event)" [selectedFeature]="state.selectedFeature" [selectedItem]="state.selectedItem"></fm-map-item-source-vector>
</aol-layer-vector> </aol-layer-vector>
@@ -59,37 +61,49 @@
</div> </div>
</div> </div>
<fm-map-file-drop-target [parentCode]="state.parentCode" (onFileDropped)="handleFileDropped($event)"></fm-map-file-drop-target> <fm-map-file-drop-target [parentCode]="state.parentCode" (onFileDropped)="handleFileDropped($event)"></fm-map-file-drop-target>
@if (noContent) {
<div *ngIf="noContent"> <div>
<fm-map-map-search #mapSearch [openedModalName]="state.openedModalName" (onOpenModal)="handleOpenModal($event)" (onCloseModal)="handleCloseModal()" [ngClass]="{'menuVisible':state.menuVisible}" (onToggleMenu)="handleToggleMenu($event)" (onSearchCollapse)="handleSearchCollapse($event)" (onSearchExpand)="handleSearchExpand($event)" [collapsed]="state.searchCollapsed" [searchMinified]="state.searchMinified" (onSearch)="handleSearch($event)" (onClear)="handleClearSearch($event)" [filterOptions]="state.queryState" [clearEnabled]="state.clearEnabled" [period]="state.period" (onPeriodChange)="handlePeriodChange($event)" (onCitySearch)="handleCitySearch($event)"></fm-map-map-search> <fm-map-map-search #mapSearch [openedModalName]="state.openedModalName" (onOpenModal)="handleOpenModal($event)" (onCloseModal)="handleCloseModal()" [ngClass]="{'menuVisible':state.menuVisible}" (onToggleMenu)="handleToggleMenu($event)" (onSearchCollapse)="handleSearchCollapse($event)" (onSearchExpand)="handleSearchExpand($event)" [collapsed]="state.searchCollapsed" [searchMinified]="state.searchMinified" (onSearch)="handleSearch($event)" (onClear)="handleClearSearch($event)" [filterOptions]="state.queryState" [clearEnabled]="state.clearEnabled" [period]="state.period" (onPeriodChange)="handlePeriodChange($event)" (onCitySearch)="handleCitySearch($event)"></fm-map-map-search>
</div> </div>
}
<div class="side-panel-container"> <div class="side-panel-container">
<fm-side-panel [resizeable]="true" (onResize)="handlePanelResize($event)" [visible]="state.panelVisible && noContent" [collapsed]="state.panelCollapsed" [collapsable]="false" [extrawide]="state.panelExtraWide"> <fm-side-panel [resizeable]="true" (onResize)="handlePanelResize($event)" [visible]="state.panelVisible && noContent" [collapsed]="state.panelCollapsed" [collapsable]="false" [extrawide]="state.panelExtraWide">
<div class="panel-wrapper" *ngIf="noContent"> @if (noContent) {
<div class="panel-top bg-secondary" *ngIf="!(state.searchMinified)"> <div class="panel-wrapper">
@if (!(state.searchMinified)) {
<div class="panel-top bg-secondary">
</div> </div>
}
<div class="panel-bottom"> <div class="panel-bottom">
@if (!(state.selectedItem)) {
<div *ngIf="!(state.selectedItem)"> <div>
<fm-map-feature-list-container [features]="state.features" [selectedFeature]="state.selectedFeature" [queryState]="state.queryState" [clickedFeature]="clickedFeature"></fm-map-feature-list-container> <fm-map-feature-list-container [features]="state.features" [selectedFeature]="state.selectedFeature" [queryState]="state.queryState" [clickedFeature]="clickedFeature"></fm-map-feature-list-container>
</div> </div>
}
<div *ngIf="state.selectedItem;let item"> @if (state.selectedItem; as item) {
<div>
<fm-map-selected-item-container [item]="item" [parentItem]="state.parentItem" [itemLayer]="state.selectedItemLayer" [overlayLayers]="state.overlayLayers"></fm-map-selected-item-container> <fm-map-selected-item-container [item]="item" [parentItem]="state.parentItem" [itemLayer]="state.selectedItemLayer" [overlayLayers]="state.overlayLayers"></fm-map-selected-item-container>
</div> </div>
<div *ngIf="state.features.length == 0" class="no-results m-2"> }
<div *ngIf="state.queryState.query">Cannot find <span>{{state.queryState?.query}}</span></div> @if (state.features.length == 0) {
<div *ngIf="state.queryState?.tags">Cannot find tag <span>{{state.queryState?.tags}}</span></div> <div class="no-results m-2">
</div> @if (state.queryState.query) {
<div>Cannot find <span>{{state.queryState?.query}}</span></div>
}
@if (state.queryState?.tags) {
<div>Cannot find tag <span>{{state.queryState?.tags}}</span></div>
}
</div>
}
</div> </div>
</div> </div>
}
</fm-side-panel> </fm-side-panel>
<fm-side-panel [resizeable]="true" [visible]="!noContent" [extrawide]="state.panelExtraWide"> <fm-side-panel [resizeable]="true" [visible]="!noContent" [extrawide]="state.panelExtraWide">
<router-outlet (activate)="handleSidepaneloutletActivate($event)" (deactivate)="handleSidepaneloutletDeactivate($event)"></router-outlet> <router-outlet (activate)="handleSidepaneloutletActivate($event)" (deactivate)="handleSidepaneloutletDeactivate($event)"></router-outlet>
</fm-side-panel> </fm-side-panel>
</div> </div>
</aol-map> </aol-map>
</ng-container> }

View File

@@ -1,5 +1,6 @@
<div class="spacer"></div> <div class="spacer"></div>
<div *ngIf="item;let item"> @if (item; as item) {
<div>
<div class="card border-0"> <div class="card border-0">
<div class="card-body"> <div class="card-body">
<fm-back-button></fm-back-button> <fm-back-button></fm-back-button>
@@ -9,7 +10,9 @@
<div class="card-text"><span>{{areaInHa(item)| number:'1.2-2'}} ha</span>&nbsp;<span>{{item.data.cropTypeName}}</span></div> <div class="card-text"><span>{{areaInHa(item)| number:'1.2-2'}} ha</span>&nbsp;<span>{{item.data.cropTypeName}}</span></div>
<div class="card-text"><span>{{item.data.startDate|date}}</span> - <span>{{item.data.endDate|date}}</span> </div> <div class="card-text"><span>{{item.data.startDate|date}}</span> - <span>{{item.data.endDate|date}}</span> </div>
<ul class="p-0 mt-2"> <ul class="p-0 mt-2">
<li *ngIf="item.isEditable"><a href="#" (click)="handleOnEdit(item)"><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i>&nbsp;<span i18n>Edit</span></a></li> @if (item.isEditable) {
<li><a href="#" (click)="handleOnEdit(item)"><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i>&nbsp;<span i18n>Edit</span></a></li>
}
</ul> </ul>
</div> </div>
</div> </div>
@@ -17,3 +20,4 @@
<fm-map-item-widget-list [item]="item"></fm-map-item-widget-list> <fm-map-item-widget-list [item]="item"></fm-map-item-widget-list>
</div> </div>
</div> </div>
}

View File

@@ -1,37 +1,51 @@
<div class="spacer"></div> <div class="spacer"></div>
<div *ngIf="item;let item"> @if (item; as item) {
<div>
<div class="card border-0"> <div class="card border-0">
<div class="card-body"> <div class="card-body">
<fm-back-button></fm-back-button> <fm-back-button></fm-back-button>
<div class="card menu-card"> <div class="card menu-card">
<h2 *ngIf="parentOfItemType('vnd.farmmaps.itemtype.cropfield')">{{parentItem.name}}</h2> @if (parentOfItemType('vnd.farmmaps.itemtype.cropfield')) {
<h2>{{parentItem.name}}</h2>
}
<h1>{{item.name}}</h1> <h1>{{item.name}}</h1>
</div> </div>
<ng-container *ngIf="item?.data.layers;let layers"> @if (item?.data.layers; as layers) {
<div class="legend-container"> <div class="legend-container">
<div class="card menu-card"> <div class="card menu-card">
<div *ngIf="layers.length>1"> @if (layers.length>1) {
<div>
<select (change)="onLayerChanged($event.target.value)"> <select (change)="onLayerChanged($event.target.value)">
<option *ngFor="let l of layers;" [value]="l.index" [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option> @for (l of layers; track l) {
<option [value]="l.index" [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option>
}
</select> </select>
</div> </div>
}
<fm-map-layer-legend [showTitle]="layers.length == 1" <fm-map-layer-legend [showTitle]="layers.length == 1"
[layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend> [layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend>
</div> </div>
</div> </div>
<div class="card menu-card"> <div class="card menu-card">
<ul class="p-0 mt-2"> <ul class="p-0 mt-2">
<li *ngIf="item.isEditable"><a href="#" class="ms-1 me-1" (click)="handleOnEdit(item)"><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i>&nbsp;<span i18n>Edit</span></a></li> @if (item.isEditable) {
<ng-container *ngIf="itemTypeService.isLayer(item)"> <li><a href="#" class="ms-1 me-1" (click)="handleOnEdit(item)"><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i>&nbsp;<span i18n>Edit</span></a></li>
<li *ngIf="!getItemLayer(item,itemLayer.layerIndex)"><a href="#" (click)="handleAddAsLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-plus" aria-hidden="true" i18n-title title="Add as layer"></i>&nbsp;<span i18n>Add as overlay</span></a></li> }
<li *ngIf="getItemLayer(item,itemLayer.layerIndex)"><a href="#" (click)="handleRemoveLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i>&nbsp;<span i18n>Remove overlay</span></a></li> @if (itemTypeService.isLayer(item)) {
</ng-container> @if (!getItemLayer(item,itemLayer.layerIndex)) {
<li><a href="#" (click)="handleAddAsLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-plus" aria-hidden="true" i18n-title title="Add as layer"></i>&nbsp;<span i18n>Add as overlay</span></a></li>
}
@if (getItemLayer(item,itemLayer.layerIndex)) {
<li><a href="#" (click)="handleRemoveLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i>&nbsp;<span i18n>Remove overlay</span></a></li>
}
}
<li><fm-item-link class="text-primary p-0" [itemCode]="item.code" pathSuffix="data" [showText]="true"></fm-item-link></li> <li><fm-item-link class="text-primary p-0" [itemCode]="item.code" pathSuffix="data" [showText]="true"></fm-item-link></li>
<li><a href="#" (click)="download($event,item,layers,itemLayer.layerIndex)"><i class="fal fa-download" aria-hidden="true" i18n-title title="Download"></i>&nbsp;<span i18n>Download</span></a></li> <li><a href="#" (click)="download($event,item,layers,itemLayer.layerIndex)"><i class="fal fa-download" aria-hidden="true" i18n-title title="Download"></i>&nbsp;<span i18n>Download</span></a></li>
</ul> </ul>
</div> </div>
<fm-map-zoom-to-show-alert [layer]="itemLayer?.layer"></fm-map-zoom-to-show-alert> <fm-map-zoom-to-show-alert [layer]="itemLayer?.layer"></fm-map-zoom-to-show-alert>
</ng-container> }
</div> </div>
</div> </div>
</div> </div>
}

View File

@@ -1,35 +1,49 @@
<div class="spacer"></div> <div class="spacer"></div>
<div *ngIf="item;let item"> @if (item; as item) {
<div>
<div class="card border-0"> <div class="card border-0">
<div class="card-body"> <div class="card-body">
<fm-back-button></fm-back-button> <fm-back-button></fm-back-button>
<div class="card menu-card"> <div class="card menu-card">
<h2 *ngIf="parentOfItemType('vnd.farmmaps.itemtype.cropfield')">{{parentItem.name}}</h2> @if (parentOfItemType('vnd.farmmaps.itemtype.cropfield')) {
<h2>{{parentItem.name}}</h2>
}
<h1>{{item.name}}</h1> <h1>{{item.name}}</h1>
</div> </div>
<ng-container *ngIf="item?.data.layers;let layers"> @if (item?.data.layers; as layers) {
<div class="legend-container"> <div class="legend-container">
<div class="card menu-card"> <div class="card menu-card">
<div *ngIf="layers.length>1"> @if (layers.length>1) {
<div>
<select (change)="onLayerChanged($event.target.value)"> <select (change)="onLayerChanged($event.target.value)">
<option *ngFor="let l of layers;" [value]="l.index" [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option> @for (l of layers; track l) {
<option [value]="l.index" [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option>
}
</select> </select>
</div> </div>
}
<fm-map-layer-legend [showTitle]="layers.length==1" [layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend> <fm-map-layer-legend [showTitle]="layers.length==1" [layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend>
</div> </div>
</div> </div>
<div class="card menu-card"> <div class="card menu-card">
<ul class="p-0 mt-2"> <ul class="p-0 mt-2">
<li *ngIf="item.isEditable"><a href="#" class="mt-1 me-1" (click)="handleOnEdit(item)" ><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i>&nbsp;<span i18n>Edit</span></a></li> @if (item.isEditable) {
<ng-container *ngIf="itemTypeService.isLayer(item)"> <li><a href="#" class="mt-1 me-1" (click)="handleOnEdit(item)" ><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i>&nbsp;<span i18n>Edit</span></a></li>
<li *ngIf="!getItemLayer(item,itemLayer.layerIndex)"><a href="#" (click)="handleAddAsLayer(item,itemLayer.layerIndex)" ><i class="fas fa-layer-olus" aria-hidden="true" i18n-title title="Add as layer"></i>&nbsp;<span i18n>Add as overlay</span></a></li> }
<li *ngIf="getItemLayer(item,itemLayer.layerIndex)"><a href="#" (click)="handleRemoveLayer(item,itemLayer.layerIndex)" ><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i>&nbsp;<span i18n>Remove overlay</span></a></li> @if (itemTypeService.isLayer(item)) {
</ng-container> @if (!getItemLayer(item,itemLayer.layerIndex)) {
<li><a href="#" (click)="handleAddAsLayer(item,itemLayer.layerIndex)" ><i class="fas fa-layer-olus" aria-hidden="true" i18n-title title="Add as layer"></i>&nbsp;<span i18n>Add as overlay</span></a></li>
}
@if (getItemLayer(item,itemLayer.layerIndex)) {
<li><a href="#" (click)="handleRemoveLayer(item,itemLayer.layerIndex)" ><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i>&nbsp;<span i18n>Remove overlay</span></a></li>
}
}
<li><a href="#" (click)="download($event,item,layers,itemLayer.layerIndex)"><i class="fal fa-download" aria-hidden="true" i18n-title title="Download"></i>&nbsp;<span i18n>Download</span></a></li> <li><a href="#" (click)="download($event,item,layers,itemLayer.layerIndex)"><i class="fal fa-download" aria-hidden="true" i18n-title title="Download"></i>&nbsp;<span i18n>Download</span></a></li>
</ul> </ul>
</div> </div>
</ng-container> }
<fm-map-zoom-to-show-alert [layer]="itemLayer?.layer"></fm-map-zoom-to-show-alert> <fm-map-zoom-to-show-alert [layer]="itemLayer?.layer"></fm-map-zoom-to-show-alert>
</div> </div>
</div> </div>
</div> </div>
}

View File

@@ -1,52 +1,70 @@
<div class="spacer"></div> <div class="spacer"></div>
<div *ngIf="selectedItem();let item"> @if (selectedItem(); as item) {
<div>
<div class="card border-0"> <div class="card border-0">
<div class="card-body"> <div class="card-body">
<fm-back-button></fm-back-button> <fm-back-button></fm-back-button>
<div class="card menu-card"> <div class="card menu-card">
<h2 *ngIf="parentOfItemType('vnd.farmmaps.itemtype.cropfield')">{{parentItem.name}}</h2> @if (parentOfItemType('vnd.farmmaps.itemtype.cropfield')) {
<h2>{{parentItem.name}}</h2>
}
<h1>{{item.name}}</h1> <h1>{{item.name}}</h1>
</div> </div>
<ng-container *ngIf="item?.data.layers;let layers"> @if (item?.data.layers; as layers) {
<div class="legend-container"> <div class="legend-container">
<div class="card menu-card"> <div class="card menu-card">
<h5><span i18n>Date</span>: {{temporalService.selectedDate(itemLayer)}}</h5> <h5><span i18n>Date</span>: {{temporalService.selectedDate(itemLayer)}}</h5>
<div class="d-flex justify-content-between"> <div class="d-flex justify-content-between">
<div> <div>
<button *ngIf="temporalService.hasPrevious(itemLayer)" type="button" class="btn btn-link p-0" (click)="handlePreviousTemporal($event)"> @if (temporalService.hasPrevious(itemLayer)) {
<button type="button" class="btn btn-link p-0" (click)="handlePreviousTemporal($event)">
<i class="fal fa-arrow-circle-left" aria-hidden="true" i18n-title title="Previous"></i>&nbsp;{{ temporalService.previousDate(itemLayer) }} <i class="fal fa-arrow-circle-left" aria-hidden="true" i18n-title title="Previous"></i>&nbsp;{{ temporalService.previousDate(itemLayer) }}
</button> </button>
}
</div> </div>
<div> <div>
<button *ngIf="temporalService.hasNext(itemLayer)" type="button" class="btn btn-link p-0" (click)="handleNextTemporal($event)"> @if (temporalService.hasNext(itemLayer)) {
<button type="button" class="btn btn-link p-0" (click)="handleNextTemporal($event)">
{{ temporalService.nextDate(itemLayer)}}&nbsp;<i class="fal fa-arrow-circle-right" aria-hidden="true" i18n-title title="Next"></i> {{ temporalService.nextDate(itemLayer)}}&nbsp;<i class="fal fa-arrow-circle-right" aria-hidden="true" i18n-title title="Next"></i>
</button> </button>
}
</div> </div>
</div> </div>
<fm-map-zoom-to-show-alert [layer]="currentItemLayer()?.layer"></fm-map-zoom-to-show-alert> <fm-map-zoom-to-show-alert [layer]="currentItemLayer()?.layer"></fm-map-zoom-to-show-alert>
</div> </div>
<div class="card menu-card pt-2"> <div class="card menu-card pt-2">
<div *ngIf="layers.length>1"> @if (layers.length>1) {
<div>
<select (change)="onLayerChanged($event.target.value)"> <select (change)="onLayerChanged($event.target.value)">
<option *ngFor="let l of layers;" [value]="l.index" [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option> @for (l of layers; track l) {
<option [value]="l.index" [selected]="itemLayer.layerIndex == l.index">{{l.name}}</option>
}
</select> </select>
</div> </div>
}
<fm-map-layer-legend [showTitle]="layers.length == 1" <fm-map-layer-legend [showTitle]="layers.length == 1"
[layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend> [layer]="layer(layers,itemLayer.layerIndex)" [histogramenabled]="true"></fm-map-layer-legend>
</div> </div>
</div> </div>
<div class="card menu-card"> <div class="card menu-card">
<ul class="p-0 mt-2"> <ul class="p-0 mt-2">
<li *ngIf="item.isEditable"><a href="#" class="mt-1 me-1" (click)="handleOnEdit(item)"><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i>&nbsp;<span i18n>Edit</span></a></li> @if (item.isEditable) {
<ng-container *ngIf="itemTypeService.isLayer(item)"> <li><a href="#" class="mt-1 me-1" (click)="handleOnEdit(item)"><i class="fal fa-pencil" aria-hidden="true" i18n-title title="Edit"></i>&nbsp;<span i18n>Edit</span></a></li>
<li *ngIf="!getItemLayer(item,itemLayer.layerIndex)"><a href="#" (click)="handleAddAsLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-plus" aria-hidden="true" i18n-title title="Add as layer"></i>&nbsp;<span i18n>Add as overlay</span></a></li> }
<li *ngIf="getItemLayer(item,itemLayer.layerIndex)"><a href="#" (click)="handleRemoveLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i>&nbsp;<span i18n>Remove overlay</span></a></li> @if (itemTypeService.isLayer(item)) {
</ng-container> @if (!getItemLayer(item,itemLayer.layerIndex)) {
<li><a href="#" (click)="handleAddAsLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-plus" aria-hidden="true" i18n-title title="Add as layer"></i>&nbsp;<span i18n>Add as overlay</span></a></li>
}
@if (getItemLayer(item,itemLayer.layerIndex)) {
<li><a href="#" (click)="handleRemoveLayer(item,itemLayer.layerIndex)"><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i>&nbsp;<span i18n>Remove overlay</span></a></li>
}
}
<li><a href="#" (click)="handleGoToChart(item)"><i class="fal fa-line-chart" aria-hidden="true" i18m-title title="Show chart"></i>&nbsp;<span i18n>Show chart</span></a></li> <li><a href="#" (click)="handleGoToChart(item)"><i class="fal fa-line-chart" aria-hidden="true" i18m-title title="Show chart"></i>&nbsp;<span i18n>Show chart</span></a></li>
<li><a href="#" (click)="download($event,item,layers,itemLayer.layerIndex)"><i class="fal fa-download" aria-hidden="true" i18n-title title="Download"></i>&nbsp;<span i18n>Download</span></a></li> <li><a href="#" (click)="download($event,item,layers,itemLayer.layerIndex)"><i class="fal fa-download" aria-hidden="true" i18n-title title="Download"></i>&nbsp;<span i18n>Download</span></a></li>
</ul> </ul>
</div> </div>
</ng-container> }
</div> </div>
</div> </div>
</div> </div>
}

View File

@@ -1,4 +1,5 @@
<div *ngIf="item;let item"> @if (item; as item) {
<div>
<div class="card border-0"> <div class="card border-0">
<fm-thumbnail [item]="item" [edit]="item.isEditable"></fm-thumbnail> <fm-thumbnail [item]="item" [edit]="item.isEditable"></fm-thumbnail>
</div> </div>
@@ -8,14 +9,23 @@
<h1 class="card-title">{{item.name}}</h1> <h1 class="card-title">{{item.name}}</h1>
<div class="card menu-card"> <div class="card menu-card">
<ul class="p-0 mt-2"> <ul class="p-0 mt-2">
<li *ngIf="itemTypeService.hasViewer(item)"><a href="#" (click)="handleOnView(item)" class="btn btn-outline-secondary"><i class="fal fa-eye" aria-hidden="true" title="View"></i>&nbsp;<span i18n>View</span></a></li> @if (itemTypeService.hasViewer(item)) {
<li *ngIf="item.isEditable"><a href="#" (click)="handleOnEdit(item)"><i class="fal fa-pencil" aria-hidden="true" title="Edit"></i> <span i18n>Edit</span></a></li> <li><a href="#" (click)="handleOnView(item)" class="btn btn-outline-secondary"><i class="fal fa-eye" aria-hidden="true" title="View"></i>&nbsp;<span i18n>View</span></a></li>
<ng-container *ngIf="itemTypeService.isLayer(item)"> }
<li *ngIf="!getItemLayer(item)"><a href="#" (click)="handleAddAsLayer(item)"><i class="fas fa-layer-plus" aria-hidden="true" i18n-title title="Add as layer"></i>&nbsp;<span i18n>Add as overlay</span></a></li> @if (item.isEditable) {
<li *ngIf="getItemLayer(item)"><a href="#" (click)="handleRemoveLayer(item)"><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i>&nbsp;<span i18n>Remove overlay</span></a></li> <li><a href="#" (click)="handleOnEdit(item)"><i class="fal fa-pencil" aria-hidden="true" title="Edit"></i> <span i18n>Edit</span></a></li>
</ng-container> }
@if (itemTypeService.isLayer(item)) {
@if (!getItemLayer(item)) {
<li><a href="#" (click)="handleAddAsLayer(item)"><i class="fas fa-layer-plus" aria-hidden="true" i18n-title title="Add as layer"></i>&nbsp;<span i18n>Add as overlay</span></a></li>
}
@if (getItemLayer(item)) {
<li ><a href="#" (click)="handleRemoveLayer(item)"><i class="fas fa-layer-minus" aria-hidden="true" i18n-title title="Remove overlay"></i>&nbsp;<span i18n>Remove overlay</span></a></li>
}
}
</ul> </ul>
</div> </div>
</div> </div>
</div> </div>
</div> </div>
}

View File

@@ -1,6 +1,16 @@
<div [ngSwitch]="stage"> <div>
<h6 *ngSwitchCase="StageEnum.DevelopmentPreAlpha" style="color:darkred" [ngbTooltip]="info"><b><span i18n>Stage:Pre-alpha</span></b></h6> @switch (stage) {
<h6 *ngSwitchCase="StageEnum.DevelopmentAlpha" style="color:red" [ngbTooltip]="info"><b><span i18n>Stage:Alpha</span></b></h6> @case (StageEnum.DevelopmentPreAlpha) {
<h6 *ngSwitchCase="StageEnum.DevelopmentBeta" style="color:orange" [ngbTooltip]="info" ><b><span i18n>Stage:Beta</span></b></h6> <h6 style="color:darkred" [ngbTooltip]="info"><b><span i18n>Stage:Pre-alpha</span></b></h6>
<h6 *ngSwitchCase="StageEnum.ReleaseCandidate" style="color:green" [ngbTooltip]="info" ><b><span i18n>Stage:RC</span></b></h6> }
@case (StageEnum.DevelopmentAlpha) {
<h6 style="color:red" [ngbTooltip]="info"><b><span i18n>Stage:Alpha</span></b></h6>
}
@case (StageEnum.DevelopmentBeta) {
<h6 style="color:orange" [ngbTooltip]="info" ><b><span i18n>Stage:Beta</span></b></h6>
}
@case (StageEnum.ReleaseCandidate) {
<h6 style="color:green" [ngbTooltip]="info" ><b><span i18n>Stage:RC</span></b></h6>
}
}
</div> </div>

View File

@@ -3,7 +3,7 @@
"compilerOptions": { "compilerOptions": {
"outDir": "../../out-tsc/lib", "outDir": "../../out-tsc/lib",
"module": "es2015", "module": "es2015",
"moduleResolution": "node", "moduleResolution": "bundler",
"declaration": true, "declaration": true,
"sourceMap": true, "sourceMap": true,
"inlineSources": true, "inlineSources": true,
@@ -18,9 +18,7 @@
], ],
"paths": { "paths": {
"@angular/*": [ "@angular/*": [
"node_modules/@angular/*" "node_modules/@angular/*"
] ]
} }
}, },

View File

@@ -3,7 +3,7 @@
"compilerOptions": { "compilerOptions": {
"outDir": "../../out-tsc/lib", "outDir": "../../out-tsc/lib",
"module": "es2015", "module": "es2015",
"moduleResolution": "node", "moduleResolution": "bundler",
"declaration": true, "declaration": true,
"sourceMap": true, "sourceMap": true,
"inlineSources": true, "inlineSources": true,
@@ -18,9 +18,7 @@
], ],
"paths": { "paths": {
"@angular/*": [ "@angular/*": [
"node_modules/@angular/*" "node_modules/@angular/*"
] ]
} }
}, },

View File

@@ -8,8 +8,8 @@
"tslib": "^2.0.0" "tslib": "^2.0.0"
}, },
"peerDependencies": { "peerDependencies": {
"@angular/common": "19.2.18", "@angular/common": "20.3.16",
"@angular/core": "19.2.18", "@angular/core": "20.3.16",
"cesium": "^1.97.0", "cesium": "^1.97.0",
"ol-cesium": ">=2.13.0" "ol-cesium": ">=2.13.0"
} }

View File

@@ -4,7 +4,7 @@
"outDir": "../../out-tsc/lib", "outDir": "../../out-tsc/lib",
"target": "es2015", "target": "es2015",
"module": "es2015", "module": "es2015",
"moduleResolution": "node", "moduleResolution": "bundler",
"declaration": true, "declaration": true,
"sourceMap": true, "sourceMap": true,
"inlineSources": true, "inlineSources": true,
@@ -19,9 +19,7 @@
], ],
"paths": { "paths": {
"@angular/*": [ "@angular/*": [
"node_modules/@angular/*" "node_modules/@angular/*"
] ]
} }
}, },

View File

@@ -4,7 +4,7 @@
"outDir": "../../out-tsc/lib", "outDir": "../../out-tsc/lib",
"target": "es2015", "target": "es2015",
"module": "es2015", "module": "es2015",
"moduleResolution": "node", "moduleResolution": "bundler",
"declaration": true, "declaration": true,
"sourceMap": true, "sourceMap": true,
"inlineSources": true, "inlineSources": true,
@@ -19,9 +19,7 @@
], ],
"paths": { "paths": {
"@angular/*": [ "@angular/*": [
"node_modules/@angular/*" "node_modules/@angular/*"
] ]
} }
}, },

View File

@@ -5,20 +5,20 @@
"registry": "https://repository.akkerweb.nl/repository/npm-hosted/" "registry": "https://repository.akkerweb.nl/repository/npm-hosted/"
}, },
"peerDependencies": { "peerDependencies": {
"@ng-bootstrap/ng-bootstrap": "^18.0.0", "@ng-bootstrap/ng-bootstrap": "^19.0.0",
"@angular/common": "19.2.18", "@angular/common": "20.3.16",
"@angular/core": "19.2.18", "@angular/core": "20.3.16",
"@angular/forms": "19.2.18", "@angular/forms": "20.3.16",
"@ngrx/effects": "19.2.1", "@ngrx/effects": "20.1.0",
"@ngrx/router-store": "19.2.1", "@ngrx/router-store": "20.1.0",
"@ngrx/store": "19.2.1", "@ngrx/store": "20.1.0",
"tassign": "^1.0.0", "tassign": "^1.0.0",
"bootstrap": "^5.3.3", "bootstrap": "^5.3.3",
"@microsoft/signalr": "^3.1.16", "@microsoft/signalr": "^3.1.16",
"ngx-uploadx": "7.0.1", "ngx-uploadx": "7.0.1",
"angular-oauth2-oidc": "^17.0.2", "angular-oauth2-oidc": "^17.0.2",
"moment": "^2.29.4", "moment": "^2.29.4",
"ngx-avatars": "1.9.3", "ngx-avatars": "1.10.0",
"ngx-image-cropper": "^7.0.0", "ngx-image-cropper": "^7.0.0",
"ngx-clipboard": "^16.0.0" "ngx-clipboard": "^16.0.0"
} }

View File

@@ -6,8 +6,12 @@
<router-outlet name="menu" class="ms-4"></router-outlet> <router-outlet name="menu" class="ms-4"></router-outlet>
<div class="collapse navbar-collapse pageonly"> <div class="collapse navbar-collapse pageonly">
<a class="btn btn-primary ms-auto" role="button" [routerLink]="[ startPage == null?'/map':startPage]"> <a class="btn btn-primary ms-auto" role="button" [routerLink]="[ startPage == null?'/map':startPage]">
<span *ngIf="(user|async)==null" i18n>Sign in</span> @if ((user|async)==null) {
<span *ngIf="(user|async)!=null" i18n>To app</span> <span i18n>Sign in</span>
}
@if ((user|async)!=null) {
<span i18n>To app</span>
}
</a> </a>
</div> </div>
</div> </div>
@@ -29,9 +33,9 @@
</div> </div>
</div> </div>
</fm-side-panel> </fm-side-panel>
<ng-container *ngIf="showUploadProgress"> @if (showUploadProgress) {
<fm-resumable-file-upload></fm-resumable-file-upload> <fm-resumable-file-upload></fm-resumable-file-upload>
</ng-container> }
<div class="user-menu apponly"> <div class="user-menu apponly">
<fm-setting-menu [user]="user|async" [showMenu]="settingMenuVisible|async" [backgroundColor]="settingMenuBackgroundColor|async"></fm-setting-menu> <fm-setting-menu [user]="user|async" [showMenu]="settingMenuVisible|async" [backgroundColor]="settingMenuBackgroundColor|async"></fm-setting-menu>
<fm-help-menu [user]="user|async" [showMenu]="helpMenuVisible|async"></fm-help-menu> <fm-help-menu [user]="user|async" [showMenu]="helpMenuVisible|async"></fm-help-menu>

View File

@@ -1,6 +1,6 @@
import { Component, OnInit, OnDestroy, Inject, Optional, ViewEncapsulation, RendererFactory2, PLATFORM_ID, ChangeDetectionStrategy, HostListener, Input } from '@angular/core'; import { Component, OnInit, OnDestroy, Inject, Optional, ViewEncapsulation, RendererFactory2, PLATFORM_ID, ChangeDetectionStrategy, HostListener, Input, DOCUMENT } from '@angular/core';
import { Router, NavigationStart, NavigationEnd, RouteConfigLoadStart, RouteConfigLoadEnd, ActivatedRoute, PRIMARY_OUTLET } from '@angular/router'; import { Router, NavigationStart, NavigationEnd, RouteConfigLoadStart, RouteConfigLoadEnd, ActivatedRoute, PRIMARY_OUTLET } from '@angular/router';
import { Meta, Title, MetaDefinition } from '@angular/platform-browser'; import { DOCUMENT } from "@angular/common"; import { Meta, Title, MetaDefinition } from '@angular/platform-browser';
import { Subscription, Observable } from 'rxjs'; import { Subscription, Observable } from 'rxjs';
import { distinctUntilChanged } from 'rxjs/operators'; import { distinctUntilChanged } from 'rxjs/operators';
import { Store, Action } from '@ngrx/store'; import { Store, Action } from '@ngrx/store';

View File

@@ -1,4 +1,5 @@
<div *ngIf="show()" class="back-button mb-2"> @if (show()) {
<div class="back-button mb-2">
<i class="fal fa-arrow-left"></i>&nbsp;<span i18n="@FmBackButton">Back</span> <i class="fal fa-arrow-left"></i>&nbsp;<span i18n="@FmBackButton">Back</span>
</div> </div>
}

View File

@@ -7,10 +7,12 @@
</div> </div>
<div class="modal-body"> <div class="modal-body">
<div class="cropper"> <div class="cropper">
<div *ngIf="!isImageLoaded" class="no-image" (click)="fileInput.click()"> @if (!isImageLoaded) {
<div class="no-image" (click)="fileInput.click()">
<i class="fal fa-image"></i> <i class="fal fa-image"></i>
<div i18n>No image selected</div> <div i18n>No image selected</div>
</div> </div>
}
<image-cropper #imageCropper output="base64" <image-cropper #imageCropper output="base64"
[imageChangedEvent]="imageChangedEvent" [imageChangedEvent]="imageChangedEvent"
[maintainAspectRatio]="true" [maintainAspectRatio]="true"

View File

@@ -1,16 +1,28 @@
<div *ngIf="gradientItems" class="form-control gradient-select" (click)="handleToggleList()"> @if (gradientItems) {
<div *ngIf="selectedItem"> <div class="form-control gradient-select" (click)="handleToggleList()">
<div *ngIf="showLabel">{{selectedItem?.name}}</div> @if (selectedItem) {
<div>
@if (showLabel) {
<div>{{selectedItem?.name}}</div>
}
<fm-gradient [gradientItem]="selectedItem"></fm-gradient> <fm-gradient [gradientItem]="selectedItem"></fm-gradient>
</div> </div>
}
<div class="gradient-list" [ngClass]="{'visible':listVisible}"> <div class="gradient-list" [ngClass]="{'visible':listVisible}">
<ul *ngIf="gradientItems"> @if (gradientItems) {
<li *ngFor="let item of gradientItems" (click)="handleSelect(item)" [ngClass]="{'bg-primary':isSelected(item),'text-white':isSelected(item)} "> <ul>
@for (item of gradientItems; track item) {
<li (click)="handleSelect(item)" [ngClass]="{'bg-primary':isSelected(item),'text-white':isSelected(item)} ">
<div>{{item?.name}}</div> <div>{{item?.name}}</div>
<div><fm-gradient [gradientItem]="item"></fm-gradient></div> <div><fm-gradient [gradientItem]="item"></fm-gradient></div>
</li> </li>
}
</ul> </ul>
<div *ngIf="showAdd" class="addGradient"><a href="#" i18n (click)="handleAdd($event)" >Add gradient</a></div> }
@if (showAdd) {
<div class="addGradient"><a href="#" i18n (click)="handleAdd($event)" >Add gradient</a></div>
}
</div> </div>
</div> </div>
}

View File

@@ -1 +1 @@
<span class="item-link" (click)="copylink(copiedtt)" triggers="manual" ngbTooltip="Link copied" #copiedtt="ngbTooltip" ><i ngbTooltip='Copy link' class="fa-solid fa-link"></i> <span *ngIf="showText" i18n>Copy link</span></span> <span class="item-link" (click)="copylink(copiedtt)" triggers="manual" ngbTooltip="Link copied" #copiedtt="ngbTooltip" ><i ngbTooltip='Copy link' class="fa-solid fa-link"></i> @if (showText) {<span i18n>Copy link</span>}</span>

View File

@@ -2,19 +2,29 @@
<div> <div>
<div class="card"> <div class="card">
<div class="card-header p-3 bg-primary text-white"> <div class="card-header p-3 bg-primary text-white">
<span *ngIf="uploadService.isUploading">Uploading files (<span>{{uploadService.totalProgress | number:'1.1-1'}}</span> %)</span> @if (uploadService.isUploading) {
<span *ngIf="uploadService.isUploading == false">Uploaded <span>{{uploadService.files.length}}</span> files</span> <span>Uploading files (<span>{{uploadService.totalProgress | number:'1.1-1'}}</span> %)</span>
}
@if (uploadService.isUploading == false) {
<span>Uploaded <span>{{uploadService.files.length}}</span> files</span>
}
<span title="Cancel" class="fal fa-times float-end" (click)="uploadService.close()"></span><span title="Minimize" class="fal fa-chevron-down float-end me-2" (click)="uploadService.toggleMinimize()" [ngClass]="{'fa-chevron-down': uploadService.isMinimized == false, 'fa-chevron-up':uploadService.isMinimized}"></span> <span title="Cancel" class="fal fa-times float-end" (click)="uploadService.close()"></span><span title="Minimize" class="fal fa-chevron-down float-end me-2" (click)="uploadService.toggleMinimize()" [ngClass]="{'fa-chevron-down': uploadService.isMinimized == false, 'fa-chevron-up':uploadService.isMinimized}"></span>
</div> </div>
<div [ngClass]="{'minimized': uploadService.isMinimized }"> <div [ngClass]="{'minimized': uploadService.isMinimized }">
<div class="card-block p-3"> <div class="card-block p-3">
<ul class="list-unstyled"> <ul class="list-unstyled">
<li *ngFor="let file of uploadService.files" class="upload-file busy" [ngClass]="{'done': file.success,'busy':file.success == false,'error': file.error }"> @for (file of uploadService.files; track file) {
<div *ngIf="file.success == false"><span class="file-name" [attr.title]="file?.fileName">{{file.fileName}}</span><span class="fal fa-times" title="Cancel" (click)="uploadService.cancelFile(file)"></span><span class="fal fa-check"></span></div> <li class="upload-file busy" [ngClass]="{'done': file.success,'busy':file.success == false,'error': file.error }">
<div *ngIf="file.success"><a href="#" (click)="handleUploadedFileClick($event,file)" class="file-name" [attr.title]="file?.fileName">{{file.fileName}}</a><span class="fal fa-check"></span></div> @if (file.success == false) {
<div><span class="file-name" [attr.title]="file?.fileName">{{file.fileName}}</span><span class="fal fa-times" title="Cancel" (click)="uploadService.cancelFile(file)"></span><span class="fal fa-check"></span></div>
}
@if (file.success) {
<div><a href="#" (click)="handleUploadedFileClick($event,file)" class="file-name" [attr.title]="file?.fileName">{{file.fileName}}</a><span class="fal fa-check"></span></div>
}
<div class="progress-container"><div class="progress-bar" [style.width]="file.progress+'%'"></div></div> <div class="progress-container"><div class="progress-bar" [style.width]="file.progress+'%'"></div></div>
<div class="errormessage">{{file.errorMessage}}</div> <div class="errormessage">{{file.errorMessage}}</div>
</li> </li>
}
</ul> </ul>
</div> </div>
</div> </div>

View File

@@ -1,7 +1,9 @@
<div class="side-panel hidden" [ngClass]="{'hidden':!visible,'collapsed':collapsed,'resizeable':(resizeable && mobile),'resizing':resizing,'left':left,'extrawide':extrawide}" [ngStyle]="{'top':top}"> <div class="side-panel hidden" [ngClass]="{'hidden':!visible,'collapsed':collapsed,'resizeable':(resizeable && mobile),'resizing':resizing,'left':left,'extrawide':extrawide}" [ngStyle]="{'top':top}">
<div *ngIf="collapsable" class="arrow rounded-end p-2" (click)="handleToggleClick($event)"> @if (collapsable) {
<div class="arrow rounded-end p-2" (click)="handleToggleClick($event)">
<i class="fal fa-chevron-left" aria-hidden="true"></i> <i class="fal fa-chevron-left" aria-hidden="true"></i>
</div> </div>
}
<div draggable="true" class="resizegrip" (dragstart)="handleStartGripDrag($event)" (touchstart)="handleStartGripDrag($event)" (dragend)="handleEndGripDrag()" (touchend)="handleEndGripDrag()" (drag)="handleGripDrag($event)" (touchmove)="handleGripDrag($event)"> <div draggable="true" class="resizegrip" (dragstart)="handleStartGripDrag($event)" (touchstart)="handleStartGripDrag($event)" (dragend)="handleEndGripDrag()" (touchend)="handleEndGripDrag()" (drag)="handleGripDrag($event)" (touchmove)="handleGripDrag($event)">
<div></div> <div></div>
<span class="rounded"></span> <span class="rounded"></span>

View File

@@ -1,6 +1,8 @@
<div class="tags"> <div class="tags">
<span class="tag rounded bg-primary text-white" *ngFor="let tag of tags;"><span>{{tag}}</span> <i @for (tag of tags; track tag) {
(click)="handleDeleteTag(tag)" class="fal fa-times" aria-hidden="true"></i></span><input <span class="tag rounded bg-primary text-white"><span>{{tag}}</span> <i
(click)="handleDeleteTag(tag)" class="fal fa-times" aria-hidden="true"></i></span>
}<input
type="text" #tagInputElement type="text" #tagInputElement
(blur)="handleBlur($event, false)" (blur)="handleBlur($event, false)"
(keyup)="handleKeyUp($event)" (keyup)="handleKeyUp($event)"

View File

@@ -1,8 +1,14 @@
<div #thumbnail class="thumbnail" [style.background-color]="itemTypeService.getColor(item.itemType)" > <div #thumbnail class="thumbnail" [style.background-color]="itemTypeService.getColor(item.itemType)" >
<div class="content"> <div class="content">
<img *ngIf="hasThumbnail()" class="card-img-top" [src]="getThumbnailUrl(item)" /> @if (hasThumbnail()) {
<div *ngIf="!hasThumbnail()" class="large-icon" [style.font-size]="getFontSize()" [style.line-height]="getLineHeight()"><i [ngClass]="itemTypeService.getIcon(item.itemType)"></i></div> <img class="card-img-top" [src]="getThumbnailUrl(item)" />
<div *ngIf="canEdit()" class="edit btn btn-secondary rounded-circle" (click)="onEditClick()"><i class="fal fa-camera"></i></div> }
@if (!hasThumbnail()) {
<div class="large-icon" [style.font-size]="getFontSize()" [style.line-height]="getLineHeight()"><i [ngClass]="itemTypeService.getIcon(item.itemType)"></i></div>
}
@if (canEdit()) {
<div class="edit btn btn-secondary rounded-circle" (click)="onEditClick()"><i class="fal fa-camera"></i></div>
}
</div> </div>
</div> </div>

View File

@@ -1,16 +1,22 @@
<div> <div>
<div (click)="toggle($event)" class="rounded-circle menu-button hidden" [ngClass]="{'hidden':!user}"> <div (click)="toggle($event)" class="rounded-circle menu-button hidden" [ngClass]="{'hidden':!user}">
<span *ngIf="user"><fm-avatar [user]="user" size="40"></fm-avatar></span> @if (user) {
<span><fm-avatar [user]="user" size="40"></fm-avatar></span>
}
<div class="menu hidden" [ngClass]="{'hidden':!showMenu}"> <div class="menu hidden" [ngClass]="{'hidden':!showMenu}">
<div class="card" *ngIf="user"> @if (user) {
<div class="card">
<div class="card-body"> <div class="card-body">
<div class="username">{{user.name}}</div> <div class="username">{{user.name}}</div>
<div *ngIf="getProvider(); let provider"> @if (getProvider(); as provider) {
<div>
<small><span i18n>Provider</span><span> {{provider}}</span></small> <small><span i18n>Provider</span><span> {{provider}}</span></small>
</div> </div>
}
<div><a href="#" (click)="logout($event)" i18n>logout</a></div> <div><a href="#" (click)="logout($event)" i18n>logout</a></div>
</div> </div>
</div> </div>
}
<router-outlet name="user-menu"></router-outlet> <router-outlet name="user-menu"></router-outlet>
</div> </div>
</div> </div>

View File

@@ -1,5 +1,5 @@
import { Injectable, Injector, Inject } from '@angular/core'; import { Injectable, Injector, Inject, DOCUMENT } from '@angular/core';
import { DOCUMENT } from '@angular/common'
import { AppConfig } from "./app.config"; import { AppConfig } from "./app.config";
import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http'; import { HttpRequest, HttpHandler, HttpEvent, HttpInterceptor } from '@angular/common/http';
import { OAuthService } from 'angular-oauth2-oidc'; import { OAuthService } from 'angular-oauth2-oidc';

View File

@@ -3,7 +3,7 @@
"compilerOptions": { "compilerOptions": {
"outDir": "../../out-tsc/lib", "outDir": "../../out-tsc/lib",
"module": "es2015", "module": "es2015",
"moduleResolution": "node", "moduleResolution": "bundler",
"declaration": true, "declaration": true,
"sourceMap": true, "sourceMap": true,
"inlineSources": true, "inlineSources": true,

View File

@@ -3,7 +3,7 @@
"compilerOptions": { "compilerOptions": {
"outDir": "../../out-tsc/lib", "outDir": "../../out-tsc/lib",
"module": "es2015", "module": "es2015",
"moduleResolution": "node", "moduleResolution": "bundler",
"declaration": true, "declaration": true,
"sourceMap": true, "sourceMap": true,
"inlineSources": true, "inlineSources": true,
@@ -18,9 +18,7 @@
], ],
"paths": { "paths": {
"@angular/*": [ "@angular/*": [
"node_modules/@angular/*" "node_modules/@angular/*"
] ]
} }
}, },

View File

@@ -31,8 +31,8 @@
"tslib": "^2.3.0" "tslib": "^2.3.0"
}, },
"peerDependencies": { "peerDependencies": {
"@angular/common": "19.2.18", "@angular/common": "20.3.16",
"@angular/core": "19.2.18", "@angular/core": "20.3.16",
"ol": "^8.2.0" "ol": "^8.2.0"
} }
} }

View File

@@ -3,7 +3,7 @@
"compilerOptions": { "compilerOptions": {
"outDir": "../../out-tsc/lib", "outDir": "../../out-tsc/lib",
"module": "es2015", "module": "es2015",
"moduleResolution": "node", "moduleResolution": "bundler",
"declaration": true, "declaration": true,
"sourceMap": true, "sourceMap": true,
"inlineSources": true, "inlineSources": true,

View File

@@ -3,7 +3,7 @@
"compilerOptions": { "compilerOptions": {
"outDir": "../../out-tsc/lib", "outDir": "../../out-tsc/lib",
"module": "es2015", "module": "es2015",
"moduleResolution": "node", "moduleResolution": "bundler",
"declaration": true, "declaration": true,
"sourceMap": true, "sourceMap": true,
"inlineSources": true, "inlineSources": true,
@@ -18,9 +18,7 @@
], ],
"paths": { "paths": {
"@angular/*": [ "@angular/*": [
"node_modules/@angular/*" "node_modules/@angular/*"
] ]
} }
}, },

View File

@@ -7,7 +7,7 @@
"declaration": false, "declaration": false,
"esModuleInterop": true, "esModuleInterop": true,
"module": "es2020", "module": "es2020",
"moduleResolution": "node", "moduleResolution": "bundler",
"emitDecoratorMetadata": true, "emitDecoratorMetadata": true,
"experimentalDecorators": true, "experimentalDecorators": true,
"importHelpers": true, "importHelpers": true,