Ongoing migration

This commit is contained in:
phil 2024-02-27 11:52:00 +05:30
parent c489a83285
commit 38ff5b8e59
23 changed files with 155 additions and 271 deletions

View file

@ -1,36 +1,17 @@
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http' import { HttpClient, HttpHeaders, HttpResponse } from '@angular/common/http'
import { Observable, forkJoin } from 'rxjs' import { Observable, forkJoin } from 'rxjs'
import { map } from 'rxjs/operators' import { map } from 'rxjs/operators'
import { Apollo, gql } from 'apollo-angular'
import { WebsocketService } from '../_services/websocket.service' import { WebsocketService } from '../_services/websocket.service'
const getLayerQuery = gql` import { MapService, MaplibreStyle } from '../openapi'
query mapboxStyle($store: String!) {
mapboxStyle (store: $store) {
paint
layout
attribution
}
}
`
export class MapboxStyle {
constructor(
public paint: string,
public layout: string,
public attribution: string,
) {}
}
export class MapboxDataAndStyle { export class MapboxDataAndStyle {
constructor( constructor(
public data: object, public data: object,
public style: MapboxStyle, public style: MaplibreStyle,
) {} ) {}
} }
@ -39,7 +20,8 @@ export class MapboxDataAndStyle {
export class GeoJsonService { export class GeoJsonService {
constructor( constructor(
private _http: HttpClient, private _http: HttpClient,
private apollo: Apollo // private apollo: Apollo,
public mapService: MapService,
) {} ) {}
getLayer(url: string, params?: object): Observable<object> { getLayer(url: string, params?: object): Observable<object> {
@ -51,20 +33,10 @@ export class GeoJsonService {
}) })
} }
getStyle(store: string): Observable<MapboxStyle> { getStyle(store: string): Observable<MaplibreStyle> {
return this.apollo.query({ return this.mapService.getLayerStyleApiMapLayerStyleStoreGet(
query: getLayerQuery, {store: store}
variables: { )
store: store
},
errorPolicy: 'all',
}).pipe(map(
result => new MapboxStyle(
result['data']['mapboxStyle']['paint'],
result['data']['mapboxStyle']['layout'],
result['data']['mapboxStyle']['attribution'],
)
))
} }
getAll(url: string, store: string, params?: object): Observable<MapboxDataAndStyle> { getAll(url: string, store: string, params?: object): Observable<MapboxDataAndStyle> {

View file

@ -2,7 +2,7 @@
<mat-toolbar fxFlex="2em" id='top-toolbar'> <mat-toolbar fxFlex="2em" id='top-toolbar'>
<span <span
style='font-family:GisafSymbols' style='font-family:GisafSymbols'
matTooltip="Gisaf v. {{ version['version'] }} ({{ version['date'] | date: 'dd/MM/yyyy' }})" matTooltip="Gisaf v. {{ version }}"
matTooltipPosition="below" matTooltipPosition="below"
class='gisafIcon' class='gisafIcon'
> >

View file

@ -52,7 +52,7 @@ export class AppComponent implements OnInit {
this.title = res.title || this.title this.title = res.title || this.title
this.titleService.setTitle(res.windowTitle || this.title) this.titleService.setTitle(res.windowTitle || this.title)
this.configService.setConf(res) this.configService.setConf(res)
this.authenticationService.roles = res.user.roles || [] this.authenticationService.roles = res.user?.roles || []
if (res.redirect && (window != window.top)) { if (res.redirect && (window != window.top)) {
// Refusing to be embedded in an iframe // Refusing to be embedded in an iframe
let loc = res.redirect + window.location.pathname let loc = res.redirect + window.location.pathname

View file

@ -6,6 +6,7 @@ export class Config {
map = {} map = {}
proj = {} proj = {}
measures = {} measures = {}
geo = {}
} }
@Injectable({ @Injectable({
@ -15,7 +16,8 @@ export class ConfigService {
defaultConf: Config = { defaultConf: Config = {
'map': {}, 'map': {},
'proj': {}, 'proj': {},
'measures': {} 'measures': {},
'geo': {}
} }
hasConf = new ReplaySubject<undefined>() hasConf = new ReplaySubject<undefined>()
@ -37,6 +39,7 @@ export class ConfigService {
setConf(c: Object) { setConf(c: Object) {
this.conf.value.map = c['map'] this.conf.value.map = c['map']
this.conf.value.proj = c['proj'] this.conf.value.proj = c['proj']
this.conf.value.geo = c['geo']
this.conf.value.measures = c['measures'] this.conf.value.measures = c['measures']
this.conf.next(this.conf.value) this.conf.next(this.conf.value)
this.hasConf.next(undefined) this.hasConf.next(undefined)

View file

@ -7,7 +7,7 @@
<mat-option *ngFor="let bm of mapDataService.mapInitData.baseMaps" <mat-option *ngFor="let bm of mapDataService.mapInitData.baseMaps"
(onSelectionChange)="selChange($event, bm)" (onSelectionChange)="selChange($event, bm)"
[value]="bm.name" [value]="bm.name"
[title]="bm.pprint()" [title]="bm.stores.join(', ')"
> >
{{ bm.name }} {{ bm.name }}
</mat-option> </mat-option>

View file

@ -5,8 +5,9 @@ import { combineLatest } from 'rxjs'
import { MapControlService } from '../map-control.service' import { MapControlService } from '../map-control.service'
import { MatOptionSelectionChange } from '@angular/material/core' import { MatOptionSelectionChange } from '@angular/material/core'
import { BaseMap, MapDataService } from '../map-data.service' import { MapDataService } from '../map-data.service'
import { UntypedFormGroup, UntypedFormControl } from '@angular/forms' import { UntypedFormGroup, UntypedFormControl } from '@angular/forms'
import { BaseMapWithStores } from '../../openapi'
@Component({ @Component({
selector: 'gisaf-map-base-map', selector: 'gisaf-map-base-map',
@ -31,7 +32,6 @@ export class BaseMapComponent implements OnInit {
let baseMapParams = params.get('baseMap') let baseMapParams = params.get('baseMap')
if (baseMapParams) { if (baseMapParams) {
let baseMapNameList = baseMapParams ? baseMapParams.split(',') : [] let baseMapNameList = baseMapParams ? baseMapParams.split(',') : []
baseMapNameList.forEach( baseMapNameList.forEach(
baseMapName => { baseMapName => {
let baseMap = this._getBaseMapByName(baseMapName) let baseMap = this._getBaseMapByName(baseMapName)
@ -43,7 +43,7 @@ export class BaseMapComponent implements OnInit {
) )
this.mapControlService.addBaseMap$.subscribe( this.mapControlService.addBaseMap$.subscribe(
(baseMap: BaseMap) => { (baseMap: BaseMapWithStores) => {
let existingIndex = this.mapDataService.mapInitData.baseMaps.findIndex(bm => bm.name == baseMap.name) let existingIndex = this.mapDataService.mapInitData.baseMaps.findIndex(bm => bm.name == baseMap.name)
if (existingIndex > -1) { if (existingIndex > -1) {
this.mapDataService.mapInitData.baseMaps.splice(existingIndex, 1) this.mapDataService.mapInitData.baseMaps.splice(existingIndex, 1)
@ -60,11 +60,11 @@ export class BaseMapComponent implements OnInit {
this.formGroup.addControl('baseMaps', new UntypedFormControl()) this.formGroup.addControl('baseMaps', new UntypedFormControl())
} }
protected _getBaseMapByName(name: string): BaseMap { protected _getBaseMapByName(name: string): BaseMapWithStores {
return this.mapDataService.mapInitData.baseMaps.find(bm => bm.name == name) return this.mapDataService.mapInitData.baseMaps.find(bm => bm.name == name)
} }
selChange(evt: MatOptionSelectionChange, baseMap: BaseMap) { selChange(evt: MatOptionSelectionChange, baseMap: BaseMapWithStores) {
if (evt.isUserInput) { if (evt.isUserInput) {
if (evt.source.selected) { if (evt.source.selected) {
this.mapControlService.addBaseMapLayers(baseMap.stores) this.mapControlService.addBaseMapLayers(baseMap.stores)

View file

@ -23,7 +23,7 @@
</button> </button>
<mat-menu #bmMenu="matMenu"> <mat-menu #bmMenu="matMenu">
<button mat-menu-item <button mat-menu-item
*ngFor="let baseStyle of mapDataService.mapInitData.baseStyles" *ngFor="let baseStyle of mapDataService.mapInitData?.baseStyles"
(click)="mapControlService.baseStyleName.next(baseStyle.name)"> (click)="mapControlService.baseStyleName.next(baseStyle.name)">
{{ baseStyle.name }} {{ baseStyle.name }}
</button> </button>
@ -147,19 +147,19 @@
<mat-menu #toolsMenu="matMenu" class='extended-width'> <mat-menu #toolsMenu="matMenu" class='extended-width'>
<button mat-menu-item <button mat-menu-item
(click)="downloadSelectedLayers('gpkg')"> (click)="downloadSelectedLayers('gpkg')">
Download Geopackage of selected layers (EPSG {{ (configService.conf | async).proj['srid'] }}) Download Geopackage of selected layers (EPSG {{ (configService.conf | async).geo['srid'] }})
</button> </button>
<button mat-menu-item [disabled]=true <button mat-menu-item [disabled]=true
(click)="downloadSelectedLayers('dxf')"> (click)="downloadSelectedLayers('dxf')">
Download DXF of selected layers (EPSG {{ (configService.conf | async).proj['srid'] }}) Download DXF of selected layers (EPSG {{ (configService.conf | async).geo['srid'] }})
</button> </button>
<button mat-menu-item [disabled]=true <button mat-menu-item [disabled]=true
(click)="downloadSelectedLayers('dxf', true)"> (click)="downloadSelectedLayers('dxf', true)">
Download DXF of selected layers (reprojected to EPSG {{ (configService.conf | async).proj['srid_for_proj'] }}) Download DXF of selected layers (reprojected to EPSG {{ (configService.conf | async).geo['srid_for_proj'] }})
</button> </button>
<button mat-menu-item <button mat-menu-item
(click)="downloadSelectedLayers('shapefile')"> (click)="downloadSelectedLayers('shapefile')">
Download Shapefiles of selected layers (EPSG {{ (configService.conf | async).proj['srid'] }}) [<i><b>Deprecated</b>: use Geopackage</i>] Download Shapefiles of selected layers (EPSG {{ (configService.conf | async).geo['srid'] }}) [<i><b>Deprecated</b>: use Geopackage</i>]
</button> </button>
</mat-menu> </mat-menu>
<button mat-raised-button [disabled]="!canCreateBaseMap" <button mat-raised-button [disabled]="!canCreateBaseMap"

View file

@ -7,11 +7,12 @@ import { ConfigService } from '../../config.service'
import { MapControlService } from '../map-control.service' import { MapControlService } from '../map-control.service'
import { TreeLayerItemComponent } from '../tree-layer-item/tree-layer-item.component' import { TreeLayerItemComponent } from '../tree-layer-item/tree-layer-item.component'
import { InfoDataService, TaggedLayer } from '../../info/info-data.service' import { InfoDataService, TaggedLayer } from '../../info/info-data.service'
import { BaseMap, MapDataService, BaseStyle } from '../map-data.service' import { MapDataService, BaseStyle } from '../map-data.service'
import { LayerNode } from '../models' import { LayerNode } from '../models'
import { AuthenticationService } from '../../_services/authentication.service' import { AuthenticationService } from '../../_services/authentication.service'
import { CreateBaseMapDialogComponent } from './create-base-map-dialog' import { CreateBaseMapDialogComponent } from './create-base-map-dialog'
import { MatDialog } from '@angular/material/dialog' import { MatDialog } from '@angular/material/dialog'
import { BaseMapWithStores } from '../../openapi'
@Component({ @Component({
selector: 'gisaf-map-controls', selector: 'gisaf-map-controls',
@ -179,7 +180,7 @@ export class MapControlsComponent implements OnInit {
result.baseMapName, result.baseMapName,
result.stores result.stores
).subscribe( ).subscribe(
(baseMap: BaseMap) => this.mapControlService.addBaseMap.next(baseMap) (baseMap: BaseMapWithStores) => this.mapControlService.addBaseMap.next(baseMap)
) )
) )
} }

View file

@ -9,7 +9,7 @@ import { WebSocketSubject } from 'rxjs/webSocket'
import { MatSnackBar } from '@angular/material/snack-bar' import { MatSnackBar } from '@angular/material/snack-bar'
import { Map, MapMouseEvent, LayerSpecification, import { Map, MapMouseEvent, LayerSpecification,
GeoJSONSourceSpecification, FitBoundsOptions, ExpressionSpecification } from 'maplibre-gl' GeoJSONSourceSpecification, FitBoundsOptions, ExpressionSpecification, Source, GeoJSONSource } from 'maplibre-gl'
import Point from '@mapbox/point-geometry' import Point from '@mapbox/point-geometry'
import * as bbox from '@turf/bbox' import * as bbox from '@turf/bbox'
@ -607,8 +607,8 @@ export class GisafMapboxComponent implements OnInit, OnDestroy {
console.log('Empty layer', layerDef.store) console.log('Empty layer', layerDef.store)
return return
} }
let mapboxPaint = JSON.parse(resp.style.paint) let mapboxPaint = resp.style?.paint
let mapboxLayout = JSON.parse(resp.style.layout) let mapboxLayout = resp.style?.layout
this.layerDefs[layerDef.store] = layerDef this.layerDefs[layerDef.store] = layerDef
// Make sure ids are not in properties (like postGis to_GeoJson) // Make sure ids are not in properties (like postGis to_GeoJson)
@ -642,7 +642,7 @@ export class GisafMapboxComponent implements OnInit, OnDestroy {
type: "geojson", type: "geojson",
data: data data: data
}, },
attribution: resp.style.attribution attribution: resp.style?.attribution
} }
this.layers[layerDef.store] = layer this.layers[layerDef.store] = layer
@ -731,7 +731,7 @@ export class GisafMapboxComponent implements OnInit, OnDestroy {
'fill-extrusion-opacity': 0.7, 'fill-extrusion-opacity': 0.7,
} }
highlightedLayer['paint'] = { highlightedLayer['paint'] = {
'fill-extrusion-height': (mapboxPaint && mapboxPaint['fill-extrusion-height']) || 5, 'fill-extrusion-height': (mapboxPaint && <number>mapboxPaint['fill-extrusion-height']) || 5,
'fill-extrusion-opacity': 0.9, 'fill-extrusion-opacity': 0.9,
'fill-extrusion-color': 'red', 'fill-extrusion-color': 'red',
} }
@ -840,8 +840,7 @@ export class GisafMapboxComponent implements OnInit, OnDestroy {
}) })
ws.subscribe({ ws.subscribe({
next: (data: GeoJSON.FeatureCollection) => { next: (data: GeoJSON.FeatureCollection) => {
// XXX: remove typings (maplibre 2.x) let source: Source = this.map.getSource(layerDef.store)
let source = <any>this.map.getSource(layerDef.store)
if (!source) { if (!source) {
// Unsubscribe from channel on server // Unsubscribe from channel on server
console.warn('Live WS: cannot getSource for WS message: ', layerDef.store, data) console.warn('Live WS: cannot getSource for WS message: ', layerDef.store, data)
@ -850,7 +849,7 @@ export class GisafMapboxComponent implements OnInit, OnDestroy {
}) })
return return
} }
source.setData(data) (<GeoJSONSource>source).setData(data)
}, },
error: err => { error: err => {
console.error('Websocket', layerDef.store, err) console.error('Websocket', layerDef.store, err)

View file

@ -7,9 +7,8 @@ import { MatButton } from '@angular/material/button'
import { Position } from 'geojson' import { Position } from 'geojson'
import distance from '@turf/distance' import distance from '@turf/distance'
import { Units } from '@turf/helpers' import { Units } from '@turf/helpers'
//import { GeoJSONSource } from 'maplibre-gl'
import { MapService } from '@maplibre/ngx-maplibre-gl' import { MapService } from '@maplibre/ngx-maplibre-gl'
import { POINT_CONVERSION_HYBRID } from 'constants' import { GeoJSONSource, MapMouseEvent } from 'maplibre-gl'
const LAYER_LINE = 'gisaf-ruler-line' const LAYER_LINE = 'gisaf-ruler-line'
@ -107,7 +106,7 @@ export class GisafRulerDirective {
return n == 0 ? '0' : n < 1 ? `${(n * 1000).toFixed(2)} m`: `${n.toFixed(3)} km` return n == 0 ? '0' : n < 1 ? `${(n * 1000).toFixed(2)} m`: `${n.toFixed(3)} km`
} }
onMapClick(evt) { onMapClick(evt: MapMouseEvent) {
const newCoordinate = [evt.lngLat.lng, evt.lngLat.lat] const newCoordinate = [evt.lngLat.lng, evt.lngLat.lat]
if (this.lineDrawn) { if (this.lineDrawn) {
@ -222,10 +221,8 @@ export class GisafRulerDirective {
}, },
}) })
//this.lineSource = <GeoJSONSource>map.getSource(SOURCE_LINE) this.lineSource = <GeoJSONSource>map.getSource(SOURCE_LINE)
//this.symbolSource = <GeoJSONSource>map.getSource(SOURCE_SYMBOL) this.symbolSource = <GeoJSONSource>map.getSource(SOURCE_SYMBOL)
this.lineSource = map.getSource(SOURCE_LINE)
this.symbolSource = map.getSource(SOURCE_SYMBOL)
} }
removeLayers() { removeLayers() {

View file

@ -3,8 +3,9 @@ import { Subject, BehaviorSubject, forkJoin } from 'rxjs'
import { ConfigService } from '../config.service' import { ConfigService } from '../config.service'
import { LayerNode } from './models' import { LayerNode } from './models'
import { Store, BaseMap } from './map-data.service' import { Store } from './map-data.service'
import { TaggedLayer, Feature, FeatureWithField } from '../info/info-data.service' import { TaggedLayer, Feature, FeatureWithField } from '../info/info-data.service'
import { BaseMapWithStores } from '../openapi'
@Injectable({ @Injectable({
@ -40,7 +41,7 @@ export class MapControlService {
public hasTags = new BehaviorSubject<boolean>(false) public hasTags = new BehaviorSubject<boolean>(false)
public layerLoaded = new Subject<LayerNode>() public layerLoaded = new Subject<LayerNode>()
public baseStyleName = new BehaviorSubject<string>(this.configService.conf.value.map['style']) public baseStyleName = new BehaviorSubject<string>(this.configService.conf.value.map['style'])
public addBaseMap = new Subject<BaseMap>() public addBaseMap = new Subject<BaseMapWithStores>()
public mapLoaded = new BehaviorSubject<boolean>(false) public mapLoaded = new BehaviorSubject<boolean>(false)
public layerTreeLoaded = new BehaviorSubject<boolean>(false) public layerTreeLoaded = new BehaviorSubject<boolean>(false)
@ -119,15 +120,15 @@ export class MapControlService {
this.hasTags.next(flag) this.hasTags.next(flag)
} }
addBaseMapLayers(baseMapLayers: Store[]) { addBaseMapLayers(baseMapLayers: string[]) {
for (let item of baseMapLayers) { for (let item of baseMapLayers) {
this._baseMapLayerAdd.next(item) this._baseMapLayerAdd.next(new Store(item))
} }
} }
removeBaseMapLayers(baseMapLayers: Store[]) { removeBaseMapLayers(baseMapLayers: string[]) {
for (let item of baseMapLayers) { for (let item of baseMapLayers) {
this._baseMapLayerRemove.next(item) this._baseMapLayerRemove.next(new Store(item))
} }
} }

View file

@ -1,142 +1,12 @@
import { Injectable } from '@angular/core' import { Injectable } from '@angular/core'
import { Observable, forkJoin, BehaviorSubject } from 'rxjs' import { Observable, forkJoin, BehaviorSubject, of } from 'rxjs'
import { map } from 'rxjs/operators' import { map } from 'rxjs/operators'
import { Apollo, gql } from 'apollo-angular'
import { StyleSpecification } from 'maplibre-gl' import { StyleSpecification } from 'maplibre-gl'
import { TreeData, PrimaryGroupNode, LayerNode } from './models' // import { TreeData, PrimaryGroupNode, LayerNode } from './models'
import { MapControlService } from './map-control.service' import { MapControlService } from './map-control.service'
import { MapService, MapInitData } from '../openapi' import { MapService, MapInitData, BaseMapWithStores } from '../openapi'
// XXX: unused
const baseStyleListQuery = gql`
query base_style_list {
base_style_list {
name
}
}
`
const baseStyleQuery = gql`
query base_style(
$name: String!
) {
base_style(name: $name) {
name
style
}
}
`
const baseMapQuery = gql`
query baseMap {
baseMap {
name
stores {
name
}
}
}
`
const createBaseMapQuery = gql`
mutation createBaseMap(
$baseMapName: String!
$stores: [String]!
) {
createBaseMap(
baseMapName: $baseMapName,
stores: $stores,
) {
baseMap {
name
stores {
name
}
}
}
}
`
const geomGroupQuery = gql`
query geomGroup {
geomGroup {
name
title
description
}
}
`
const storeQuery = gql`
query stores {
stores {
name
store
rawSurveyStore
style
zIndex
count
type
gisType
description
custom
group
icon
symbol
live
tagPlugins
viewableRole
}
}
`
const mapInitDataQuery = gql`
query mapInitData {
mapInitData {
baseMaps {
name
stores {
name
}
}
baseStyles {
name
}
groups {
name
title
description
}
stores {
name
store
rawSurveyStore
style
zIndex
count
type
gisType
description
custom
group
icon
symbol
live
tagPlugins
viewableRole
}
}
}
`
const gisTypeSymbolMap = {
Point: '\ue32b',
Line: '\ue32c',
Polygon: '\ue32d',
}
export class BaseStyle { export class BaseStyle {
constructor( constructor(
@ -151,26 +21,6 @@ export class Store {
) {} ) {}
} }
export class BaseMap {
constructor(
public name: string,
public stores: Store[],
) {}
pprint() {
return this.stores.map(store => store.name).join(', ')
}
}
// export class MapInitData {
// constructor(
// public baseStyles: BaseStyle[] = [],
// public baseMaps: BaseMap[] = [],
// public groups: PrimaryGroupNode[] = [],
// public stores: LayerNode[] = [],
// ) {}
// }
@Injectable() @Injectable()
export class MapDataService { export class MapDataService {
constructor( constructor(
@ -190,7 +40,7 @@ export class MapDataService {
public mapInitDataLoaded = new BehaviorSubject<boolean>(false) public mapInitDataLoaded = new BehaviorSubject<boolean>(false)
mapInitDataLoaded$ = this.mapInitDataLoaded.asObservable() mapInitDataLoaded$ = this.mapInitDataLoaded.asObservable()
mapInitData: MapInitData mapInitData: MapInitData = {}
getMapInitData(): Observable<MapInitData> { getMapInitData(): Observable<MapInitData> {
return this.mapService.getInitDataApiMapInitDataGet().pipe(map( return this.mapService.getInitDataApiMapInitDataGet().pipe(map(
@ -267,22 +117,24 @@ export class MapDataService {
// )) // ))
// } // }
public createBaseMap(baseMapName: string, stores: string[]): Observable<BaseMap> { public createBaseMap(baseMapName: string, stores: string[]): Observable<BaseMapWithStores> {
return this.apollo.mutate({ console.log('TODO: createBaseMap')
mutation: createBaseMapQuery, return of({name: '', stores:[]})
variables: { // return this.apollo.mutate({
baseMapName: baseMapName, // mutation: createBaseMapQuery,
stores: stores // variables: {
} // baseMapName: baseMapName,
}).pipe(map( // stores: stores
res => { // }
let bm: object = res['data']['createBaseMap']['baseMap'] // }).pipe(map(
return new BaseMap( // res => {
bm['name'], // let bm: object = res['data']['createBaseMap']['baseMap']
bm['stores'].map((store: object) => new Store(store['name'])) // return new BaseMap(
) // bm['name'],
} // bm['stores'].map((store: object) => new Store(store['name']))
)) // )
// }
// ))
} }
// XXX: unused // XXX: unused
@ -295,15 +147,17 @@ export class MapDataService {
// } // }
getBaseStyle(styleName: string): Observable<BaseStyle> { getBaseStyle(styleName: string): Observable<BaseStyle> {
return this.apollo.query({ console.log('TODO: getBaseStyle')
query: baseStyleQuery, return of({name: ''})
variables: { // return this.apollo.query({
name: styleName // query: baseStyleQuery,
} // variables: {
}).pipe(map( // name: styleName
data => new BaseStyle(data['data']['base_style']['name'], // }
JSON.parse(data['data']['base_style']['style'])) // }).pipe(map(
)) // data => new BaseStyle(data['data']['base_style']['name'],
// JSON.parse(data['data']['base_style']['style']))
// ))
} }
// getStores(): Observable<LayerNode[]> { // getStores(): Observable<LayerNode[]> {

View file

@ -44,11 +44,11 @@ export class LayerNode extends Node {
mapSubscription: Subscription mapSubscription: Subscription
constructor( constructor(
public store: string,
public name: string, public name: string,
public group: string, public group: string,
public icon: string, public icon: string,
public symbol: string, public symbol: string,
public store: string,
public rawSurveyStore: string, public rawSurveyStore: string,
public type: string, public type: string,
public gisType: string, public gisType: string,
@ -60,12 +60,13 @@ export class LayerNode extends Node {
public custom: boolean = false, public custom: boolean = false,
public tagPlugins: string[] = [], public tagPlugins: string[] = [],
public viewableRole: string, public viewableRole: string,
public category?: string,
) { ) {
super(name) super(name)
} }
getUrl() { getUrl() {
return 'gj/'+this.store return 'api/gj/'+this.store
} }
hasChildren() { hasChildren() {

View file

@ -46,7 +46,7 @@
<ng-template matMenuContent let-node="node"> <ng-template matMenuContent let-node="node">
<button mat-menu-item (click)="downloadGpkg(node)"> <button mat-menu-item (click)="downloadGpkg(node)">
<mat-icon>file_download</mat-icon> <mat-icon>file_download</mat-icon>
<span>Download Geopackage (EPSG {{ (configService.conf | async).proj['srid'] }})</span> <span>Download Geopackage (EPSG {{ (configService.conf | async).geo['srid'] }})</span>
</button> </button>
</ng-template> </ng-template>
</mat-menu> </mat-menu>

View file

@ -15,6 +15,7 @@ import { Node, PrimaryGroupNode, LayerNode, TreeData } from '../models'
import { MapControlService } from '../map-control.service' import { MapControlService } from '../map-control.service'
import { MapDataService, Store } from '../map-data.service' import { MapDataService, Store } from '../map-data.service'
import { Feature, FeatureWithField } from '../../info/info-data.service' import { Feature, FeatureWithField } from '../../info/info-data.service'
import { CategoryGroup } from '../../openapi'
@Injectable() @Injectable()
@ -145,23 +146,45 @@ export class TreeLayerComponent implements OnInit {
// Build a mapping object for faster assignment // Build a mapping object for faster assignment
// XXX: Typescript doesn't provide Object.fromEntries, otherwise it should be: // XXX: Typescript doesn't provide Object.fromEntries, otherwise it should be:
//let pgs = Object.fromEntries(treeData.primaryGroups.map(pg=>[pg.name, pg])) //let pgs = Object.fromEntries(treeData.primaryGroups.map(pg=>[pg.name, pg]))
let pgs = {} let pgs: Record<string, PrimaryGroupNode> = {}
this.mapDataService.mapInitData.groups.forEach( this.mapDataService.mapInitData.groups.forEach(
pg => pgs[pg.name] = pg pg => pgs[pg.name] = new PrimaryGroupNode(
pg.name,
pg.long_name,
pg.long_name)
) )
this.mapDataService.mapInitData.stores.forEach( this.mapDataService.mapInitData.stores.forEach(
node => { store => {
let group: PrimaryGroupNode = pgs[node.group] let group: PrimaryGroupNode = pgs[store.group]
if (!group) { if (!group) {
console.warn('No group (' + node.group + ') for layer node ' + node.store) console.warn('No group (' + store.group + ') for layer node ' + store.name)
return return
} }
group.children.push(node) group.children.push(new LayerNode(
store.name,
store.long_name,
store.group,
store.symbol, //store.icon,
store.symbol, //|| gisTypeSymbolMap[layer['gisType']],
'', //store.rawSurveyStore,
'', //store.type,
store.gis_type,
{}, //JSON.parse(store.style),
store.z_index,
store.count,
store.description,
store.is_live,
store.custom,
[], //store.tagPlugins,
store.viewable_role,
store.category
))
// console.log(this.mapDataService, group.children)
} }
) )
this.database.setData(this.mapDataService.mapInitData.groups) this.database.setData(Object.values(pgs)) //this.mapDataService.mapInitData.groups)
this.loading = false this.loading = false
this.mapControlService.layerTreeLoaded.complete() this.mapControlService.layerTreeLoaded.complete()
this.cdr.markForCheck() this.cdr.markForCheck()

View file

@ -21,7 +21,7 @@ export type OpenAPIConfig = {
export const OpenAPI: OpenAPIConfig = { export const OpenAPI: OpenAPIConfig = {
BASE: '', BASE: '',
VERSION: '2023.4.dev34+g5dacc90.d20240212', VERSION: '2023.4.dev37+gb00bf1f.d20240226',
WITH_CREDENTIALS: false, WITH_CREDENTIALS: false,
CREDENTIALS: 'include', CREDENTIALS: 'include',
TOKEN: undefined, TOKEN: undefined,

View file

@ -9,7 +9,7 @@ export type { OpenAPIConfig } from './core/OpenAPI';
export type { AdminBasket } from './models/AdminBasket'; export type { AdminBasket } from './models/AdminBasket';
export type { Attachment } from './models/Attachment'; export type { Attachment } from './models/Attachment';
export type { BaseMap } from './models/BaseMap'; export type { BaseMapWithStores } from './models/BaseMapWithStores';
export type { BaseStyle } from './models/BaseStyle'; export type { BaseStyle } from './models/BaseStyle';
export type { BasketDefault } from './models/BasketDefault'; export type { BasketDefault } from './models/BasketDefault';
export type { Body_login_for_access_token_api_token_post } from './models/Body_login_for_access_token_api_token_post'; export type { Body_login_for_access_token_api_token_post } from './models/Body_login_for_access_token_api_token_post';
@ -30,6 +30,7 @@ export type { InfoCategory } from './models/InfoCategory';
export type { InfoItem } from './models/InfoItem'; export type { InfoItem } from './models/InfoItem';
export type { Map } from './models/Map'; export type { Map } from './models/Map';
export type { MapInitData } from './models/MapInitData'; export type { MapInitData } from './models/MapInitData';
export type { MaplibreStyle } from './models/MaplibreStyle';
export type { Measures } from './models/Measures'; export type { Measures } from './models/Measures';
export type { PlotBaseLine } from './models/PlotBaseLine'; export type { PlotBaseLine } from './models/PlotBaseLine';
export type { PlotBgShape } from './models/PlotBgShape'; export type { PlotBgShape } from './models/PlotBgShape';

View file

@ -2,8 +2,8 @@
/* istanbul ignore file */ /* istanbul ignore file */
/* tslint:disable */ /* tslint:disable */
/* eslint-disable */ /* eslint-disable */
export type BaseMap = { export type BaseMapWithStores = {
id?: (number | null);
name: string; name: string;
stores: Array<string>;
}; };

View file

@ -16,8 +16,8 @@ export type CategoryRead = {
style: (string | null); style: (string | null);
symbol: (string | null); symbol: (string | null);
mapbox_type_custom: (string | null); mapbox_type_custom: (string | null);
mapbox_paint: (Record<string, any> | null); mapbox_paint: (Record<string, (Record<string, any> | number | string)> | null);
mapbox_layout: (Record<string, any> | null); mapbox_layout: (Record<string, (Record<string, any> | number | string)> | null);
viewable_role: (string | null); viewable_role: (string | null);
extra: (Record<string, any> | null); extra: (Record<string, any> | null);
/** /**

View file

@ -2,13 +2,13 @@
/* istanbul ignore file */ /* istanbul ignore file */
/* tslint:disable */ /* tslint:disable */
/* eslint-disable */ /* eslint-disable */
import type { BaseMap } from './BaseMap'; import type { BaseMapWithStores } from './BaseMapWithStores';
import type { BaseStyle } from './BaseStyle'; import type { BaseStyle } from './BaseStyle';
import type { CategoryGroup } from './CategoryGroup'; import type { CategoryGroup } from './CategoryGroup';
import type { Store } from './Store'; import type { Store } from './Store';
export type MapInitData = { export type MapInitData = {
baseStyles?: Array<BaseStyle>; baseStyles?: Array<BaseStyle>;
baseMaps?: Array<BaseMap>; baseMaps?: Array<BaseMapWithStores>;
groups?: Array<CategoryGroup>; groups?: Array<CategoryGroup>;
stores?: Array<Store>; stores?: Array<Store>;
}; };

View file

@ -0,0 +1,10 @@
/* generated using openapi-typescript-codegen -- do no edit */
/* istanbul ignore file */
/* tslint:disable */
/* eslint-disable */
export type MaplibreStyle = {
paint?: (Record<string, (Record<string, any> | number | string)> | null);
layout?: (Record<string, (Record<string, any> | number | string)> | null);
attribution?: (string | null);
};

View file

@ -4,6 +4,7 @@
/* eslint-disable */ /* eslint-disable */
export type Store = { export type Store = {
name: string; name: string;
category?: (string | null);
auto_import: boolean; auto_import: boolean;
count?: (number | null); count?: (number | null);
custom: boolean; custom: boolean;
@ -18,7 +19,6 @@ export type Store = {
minor_group_2: (string | null); minor_group_2: (string | null);
gis_type: string; gis_type: string;
status: string; status: string;
store: string;
style: (string | null); style: (string | null);
symbol: (string | null); symbol: (string | null);
title: string; title: string;

View file

@ -7,6 +7,7 @@ import { HttpClient } from '@angular/common/http';
import type { Observable } from 'rxjs'; import type { Observable } from 'rxjs';
import type { BaseStyle } from '../models/BaseStyle'; import type { BaseStyle } from '../models/BaseStyle';
import type { MapInitData } from '../models/MapInitData'; import type { MapInitData } from '../models/MapInitData';
import type { MaplibreStyle } from '../models/MaplibreStyle';
import { OpenAPI } from '../core/OpenAPI'; import { OpenAPI } from '../core/OpenAPI';
import { request as __request } from '../core/request'; import { request as __request } from '../core/request';
@Injectable({ @Injectable({
@ -46,4 +47,25 @@ export class MapService {
}, },
}); });
} }
/**
* Get Layer Style
* @returns any Successful Response
* @throws ApiError
*/
public getLayerStyleApiMapLayerStyleStoreGet({
store,
}: {
store: string,
}): Observable<(MaplibreStyle | null)> {
return __request(OpenAPI, this.http, {
method: 'GET',
url: '/api/map/layer_style/{store}',
path: {
'store': store,
},
errors: {
422: `Validation Error`,
},
});
}
} }