diff --git a/projects/admin-core/assets/locale/messages.admin-core.de.xlf b/projects/admin-core/assets/locale/messages.admin-core.de.xlf
index fd7834b58..b6b394e0d 100644
--- a/projects/admin-core/assets/locale/messages.admin-core.de.xlf
+++ b/projects/admin-core/assets/locale/messages.admin-core.de.xlf
@@ -1610,6 +1610,10 @@
Search title
Suchtitel
+
+ Show edit layer icon
+ Symbol zum Bearbeiten der Ebene anzeigen
+
Feature type settings updated
Feature-Typ-Einstellungen aktualisiert
diff --git a/projects/admin-core/assets/locale/messages.admin-core.en.xlf b/projects/admin-core/assets/locale/messages.admin-core.en.xlf
index a95fcd349..7788a2edd 100644
--- a/projects/admin-core/assets/locale/messages.admin-core.en.xlf
+++ b/projects/admin-core/assets/locale/messages.admin-core.en.xlf
@@ -1187,6 +1187,9 @@
Search title
+
+ Show edit layer icon
+
Feature type settings updated
diff --git a/projects/admin-core/assets/locale/messages.admin-core.nl.xlf b/projects/admin-core/assets/locale/messages.admin-core.nl.xlf
index 4aa79cf84..ded9ff2ba 100644
--- a/projects/admin-core/assets/locale/messages.admin-core.nl.xlf
+++ b/projects/admin-core/assets/locale/messages.admin-core.nl.xlf
@@ -1609,6 +1609,10 @@
Search title
Zoeken titel
+
+ Show edit layer icon
+ Toon icoon voor het bewerken van de laag
+
Feature type settings updated
Feature type instellingen aangepast
diff --git a/projects/admin-core/src/lib/application/components/components.module.ts b/projects/admin-core/src/lib/application/components/components.module.ts
index 5b90ee54a..20dd2e3fb 100644
--- a/projects/admin-core/src/lib/application/components/components.module.ts
+++ b/projects/admin-core/src/lib/application/components/components.module.ts
@@ -16,6 +16,7 @@ import { EditComponentConfigComponent } from './edit-config/edit-component-confi
import { GeolocationConfigComponent } from './geolocation-config/geolocation-config.component';
import { InfoConfigComponent } from './info-config/info-config.component';
import { DrawingConfigComponent } from './drawing-config/drawing-config.component';
+import { TocComponentConfigComponent } from './toc-config/toc-component-config.component';
@NgModule({
declarations: [
@@ -30,6 +31,7 @@ import { DrawingConfigComponent } from './drawing-config/drawing-config.componen
GeolocationConfigComponent,
InfoConfigComponent,
DrawingConfigComponent,
+ TocComponentConfigComponent,
],
imports: [
CommonModule,
@@ -48,7 +50,7 @@ export class ComponentsModule {
const configurationComponentService = inject(ConfigurationComponentRegistryService);
/* eslint-disable max-len */
- configurationComponentService.registerConfigurationComponents(BaseComponentTypeEnum.TOC, $localize `:@@admin-core.application.component-table-of-contents:Table of contents`, BaseComponentConfigComponent);
+ configurationComponentService.registerConfigurationComponents(BaseComponentTypeEnum.TOC, $localize `:@@admin-core.application.component-table-of-contents:Table of contents`, TocComponentConfigComponent);
configurationComponentService.registerConfigurationComponents(BaseComponentTypeEnum.LEGEND, $localize `:@@admin-core.application.component-legend:Legend`, BaseComponentConfigComponent);
configurationComponentService.registerConfigurationComponents(BaseComponentTypeEnum.DRAWING, $localize `:@@admin-core.application.component-drawing:Drawing`, DrawingConfigComponent);
configurationComponentService.registerConfigurationComponents(BaseComponentTypeEnum.PRINT, $localize `:@@admin-core.application.component-print:Print`, BaseComponentConfigComponent);
diff --git a/projects/admin-core/src/lib/application/components/toc-config/toc-component-config.component.css b/projects/admin-core/src/lib/application/components/toc-config/toc-component-config.component.css
new file mode 100644
index 000000000..e69de29bb
diff --git a/projects/admin-core/src/lib/application/components/toc-config/toc-component-config.component.html b/projects/admin-core/src/lib/application/components/toc-config/toc-component-config.component.html
new file mode 100644
index 000000000..674ec6f01
--- /dev/null
+++ b/projects/admin-core/src/lib/application/components/toc-config/toc-component-config.component.html
@@ -0,0 +1,10 @@
+
+
+ Show edit layer icon
+
+
diff --git a/projects/admin-core/src/lib/application/components/toc-config/toc-component-config.component.ts b/projects/admin-core/src/lib/application/components/toc-config/toc-component-config.component.ts
new file mode 100644
index 000000000..8522e03ff
--- /dev/null
+++ b/projects/admin-core/src/lib/application/components/toc-config/toc-component-config.component.ts
@@ -0,0 +1,60 @@
+import { ChangeDetectionStrategy, Component, DestroyRef, Input, inject } from '@angular/core';
+import {
+ BaseComponentTypeEnum, TocConfigModel,
+} from '@tailormap-viewer/api';
+import { FormControl, FormGroup } from '@angular/forms';
+import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
+import { ComponentConfigurationService } from '../../services/component-configuration.service';
+import { ConfigurationComponentModel } from '../configuration-component.model';
+import { debounceTime } from 'rxjs';
+
+@Component({
+ selector: 'tm-admin-edit-component-config',
+ templateUrl: './toc-component-config.component.html',
+ styleUrls: ['./toc-component-config.component.css'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+ standalone: false,
+})
+export class TocComponentConfigComponent implements ConfigurationComponentModel {
+ private componentConfigService = inject(ComponentConfigurationService);
+ private destroyRef = inject(DestroyRef);
+
+ @Input()
+ public type: BaseComponentTypeEnum | undefined;
+
+ @Input()
+ public label: string | undefined;
+
+ @Input()
+ public set config(config: TocConfigModel | undefined) {
+ this._config = config;
+ this.initForm(config);
+ }
+ public get config() {
+ return this._config;
+ }
+ private _config: TocConfigModel | undefined;
+
+ public formGroup = new FormGroup({
+ showEditLayerIcon: new FormControl(false),
+ });
+
+ constructor() {
+ this.formGroup.valueChanges
+ .pipe(takeUntilDestroyed(this.destroyRef), debounceTime(250))
+ .subscribe(() => {
+ if (!this.formGroup.valid) {
+ return;
+ }
+ this.saveConfig();
+ });
+ }
+
+ public initForm(config: TocConfigModel | undefined) {
+ this.formGroup.patchValue({ showEditLayerIcon: config?.showEditLayerIcon ?? false }, { emitEvent: false });
+ }
+
+ private saveConfig() {
+ this.componentConfigService.updateConfigForKey(this.type, 'showEditLayerIcon', this.formGroup.value.showEditLayerIcon);
+ }
+}
diff --git a/projects/api/src/lib/models/component-config/index.ts b/projects/api/src/lib/models/component-config/index.ts
index 3059481bc..778dc845e 100644
--- a/projects/api/src/lib/models/component-config/index.ts
+++ b/projects/api/src/lib/models/component-config/index.ts
@@ -7,3 +7,4 @@ export * from './edit-config.model';
export * from './geolocation-config.model';
export * from './info-component-config.model';
export * from './drawing-component-config.model';
+export * from './toc-config.model';
diff --git a/projects/api/src/lib/models/component-config/toc-config.model.ts b/projects/api/src/lib/models/component-config/toc-config.model.ts
new file mode 100644
index 000000000..fdbc53854
--- /dev/null
+++ b/projects/api/src/lib/models/component-config/toc-config.model.ts
@@ -0,0 +1,5 @@
+import { ComponentBaseConfigModel } from '../component-base-config.model';
+
+export interface TocConfigModel extends ComponentBaseConfigModel {
+ showEditLayerIcon?: boolean;
+}
diff --git a/projects/core/assets/locale/messages.core.de.xlf b/projects/core/assets/locale/messages.core.de.xlf
index 4a0c35998..ae107d8ee 100644
--- a/projects/core/assets/locale/messages.core.de.xlf
+++ b/projects/core/assets/locale/messages.core.de.xlf
@@ -1126,6 +1126,10 @@
Details for
Details für
+
+ Edit layer
+ Ebene bearbeiten
+
Filter by layer name...
Nach Ebenennamen filtern...
diff --git a/projects/core/assets/locale/messages.core.en.xlf b/projects/core/assets/locale/messages.core.en.xlf
index 03d703323..d1d4be459 100644
--- a/projects/core/assets/locale/messages.core.en.xlf
+++ b/projects/core/assets/locale/messages.core.en.xlf
@@ -845,6 +845,9 @@
Details for
+
+ Edit layer
+
Filter by layer name...
diff --git a/projects/core/assets/locale/messages.core.nl.xlf b/projects/core/assets/locale/messages.core.nl.xlf
index de6a022e0..c8095d022 100644
--- a/projects/core/assets/locale/messages.core.nl.xlf
+++ b/projects/core/assets/locale/messages.core.nl.xlf
@@ -1126,6 +1126,10 @@
Details for
Details voor
+
+ Edit layer
+ Laag bewerken
+
Filter by layer name...
Filter op laagnaam...
diff --git a/projects/core/src/lib/components/toc/toc-node-layer/toc-node-layer.component.html b/projects/core/src/lib/components/toc/toc-node-layer/toc-node-layer.component.html
index 2cc2610cd..a1d0aab30 100644
--- a/projects/core/src/lib/components/toc/toc-node-layer/toc-node-layer.component.html
+++ b/projects/core/src/lib/components/toc/toc-node-layer/toc-node-layer.component.html
@@ -31,5 +31,14 @@
matListItemMeta>
}
+ @if (isInScale() && isLayerEditable() && node.checked) {
+
+
+ }
}
diff --git a/projects/core/src/lib/components/toc/toc-node-layer/toc-node-layer.component.ts b/projects/core/src/lib/components/toc/toc-node-layer/toc-node-layer.component.ts
index f65b284a7..7da79fa55 100644
--- a/projects/core/src/lib/components/toc/toc-node-layer/toc-node-layer.component.ts
+++ b/projects/core/src/lib/components/toc/toc-node-layer/toc-node-layer.component.ts
@@ -29,9 +29,15 @@ export class TocNodeLayerComponent {
@Input()
public filteredLayerIds: string[] = [];
+ @Input()
+ public editableLayerIds: string[] = [];
+
@Output()
public zoomToScale = new EventEmitter();
+ @Output()
+ public editLayer = new EventEmitter();
+
public isLevel() {
return this.node?.type === 'level';
}
@@ -56,6 +62,10 @@ export class TocNodeLayerComponent {
return this.filteredLayerIds.includes(this.node?.id || '');
}
+ public isLayerEditable() {
+ return this.editableLayerIds.includes(this.node?.id || '');
+ }
+
public zoomToLayer($event: MouseEvent, node: TreeModel) {
$event.stopPropagation();
const scales: number[] = [];
@@ -72,4 +82,7 @@ export class TocNodeLayerComponent {
this.zoomToScale.emit(zoomToScale);
}
+ public editLayerClicked(node: TreeModel) {
+ this.editLayer.emit(node.id);
+ }
}
diff --git a/projects/core/src/lib/components/toc/toc/toc.component.html b/projects/core/src/lib/components/toc/toc/toc.component.html
index 7e731a222..9f6b379c2 100644
--- a/projects/core/src/lib/components/toc/toc/toc.component.html
+++ b/projects/core/src/lib/components/toc/toc/toc.component.html
@@ -6,7 +6,10 @@
[layersWithoutWebMercator]="layersWithoutWebMercator()"
[tiles3DLayerIds]="tiles3DLayerIds()"
[filteredLayerIds]="filteredLayerIds()"
- (zoomToScale)="zoomToScale($event)">
+ [editableLayerIds]="config?.showEditLayerIcon && editComponentEnabled ? editableLayerIds() : []"
+ (zoomToScale)="zoomToScale($event)"
+ (editLayer)="editLayer($event)"
+ >
@if (visible$ | async) {
diff --git a/projects/core/src/lib/components/toc/toc/toc.component.spec.ts b/projects/core/src/lib/components/toc/toc/toc.component.spec.ts
index 2b038cbcd..bcf1bbfce 100644
--- a/projects/core/src/lib/components/toc/toc/toc.component.spec.ts
+++ b/projects/core/src/lib/components/toc/toc/toc.component.spec.ts
@@ -3,7 +3,7 @@ import { render, screen, waitFor } from '@testing-library/angular';
import { createMockStore } from '@ngrx/store/testing';
import { MenubarService } from '../../menubar';
import { of } from 'rxjs';
-import { SharedModule } from '@tailormap-viewer/shared';
+import { LoadingStateEnum, SharedModule } from '@tailormap-viewer/shared';
import userEvent from '@testing-library/user-event';
import { MatIconTestingModule } from '@angular/material/icon/testing';
import {
@@ -21,6 +21,7 @@ import { Store } from '@ngrx/store';
import { TocNodeDetailsComponent } from '../toc-node-details/toc-node-details.component';
import { getMapServiceMock } from '../../../test-helpers/map-service.mock.spec';
import { selectFilteredLayerIds } from '../../../state/filter-state/filter.selectors';
+import { selectComponentsConfig, selectViewerLoadingState } from '../../../state';
const buildMockStore = (selectedLayer = '') => {
const layers = [
@@ -44,6 +45,8 @@ const buildMockStore = (selectedLayer = '') => {
{ selector: selectLayersWithoutWebMercatorIds, value: [] },
{ selector: select3dTilesLayers, value: [] },
{ selector: selectFilteredLayerIds, value: [] },
+ { selector: selectViewerLoadingState, value: LoadingStateEnum.LOADED },
+ { selector: selectComponentsConfig, value: [] },
],
});
};
diff --git a/projects/core/src/lib/components/toc/toc/toc.component.ts b/projects/core/src/lib/components/toc/toc/toc.component.ts
index 096f04957..af5fa502a 100644
--- a/projects/core/src/lib/components/toc/toc/toc.component.ts
+++ b/projects/core/src/lib/components/toc/toc/toc.component.ts
@@ -8,15 +8,17 @@ import { map, tap } from 'rxjs/operators';
import { MenubarService } from '../../menubar';
import { TocMenuButtonComponent } from '../toc-menu-button/toc-menu-button.component';
import { Store } from '@ngrx/store';
-import { AppLayerModel, BaseComponentTypeEnum } from '@tailormap-viewer/api';
+import { AppLayerModel, BaseComponentConfigHelper, BaseComponentTypeEnum, EditConfigModel, TocConfigModel } from '@tailormap-viewer/api';
import { MapService } from '@tailormap-viewer/map';
import { selectFilteredLayerTree, selectFilterEnabled } from '../state/toc.selectors';
import { toggleFilterEnabled } from '../state/toc.actions';
import {
- select3dTilesLayers, selectIn3dView, selectLayersWithoutWebMercatorIds, selectSelectedNode, selectSelectedNodeId,
+ select3dTilesLayers, selectEditableLayers, selectIn3dView, selectLayersWithoutWebMercatorIds, selectSelectedNode, selectSelectedNodeId,
} from '../../../map/state/map.selectors';
import { moveLayerTreeNode, setLayerVisibility, toggleSelectedLayerId, toggleLevelExpansion } from '../../../map/state/map.actions';
import { selectFilteredLayerIds } from '../../../state/filter-state/filter.selectors';
+import { setEditActive, setSelectedEditLayer } from '../../edit/state/edit.actions';
+import { ComponentConfigHelper } from '../../../shared';
interface AppLayerTreeModel extends BaseTreeModel {
metadata: AppLayerModel;
@@ -38,7 +40,6 @@ export class TocComponent implements OnInit, OnDestroy {
private mapService = inject(MapService);
private ngZone = inject(NgZone);
-
private destroyed = new Subject();
public visible$: Observable = of(false);
public scale: number | null = null;
@@ -54,6 +55,11 @@ export class TocComponent implements OnInit, OnDestroy {
public layersWithoutWebMercator: Signal = signal([]);
public tiles3DLayerIds: Signal = signal([]);
public filteredLayerIds: Signal = signal([]);
+ public editableLayerIds: Signal = signal([]);
+
+ public config: TocConfigModel | undefined;
+
+ public editComponentEnabled = !BaseComponentConfigHelper.isComponentDisabledByDefault(BaseComponentTypeEnum.EDIT);
public ngOnInit(): void {
this.visible$ = this.menubarService.isComponentVisible$(BaseComponentTypeEnum.TOC);
@@ -94,11 +100,29 @@ export class TocComponent implements OnInit, OnDestroy {
this.menubarService.registerComponent({ type: BaseComponentTypeEnum.TOC, component: TocMenuButtonComponent });
+ ComponentConfigHelper.useInitialConfigForComponent(
+ this.store$,
+ BaseComponentTypeEnum.TOC,
+ config => {
+ this.config = config;
+ },
+ );
+
+ ComponentConfigHelper.useInitialConfigForComponent(
+ this.store$,
+ BaseComponentTypeEnum.EDIT,
+ config => {
+ this.editComponentEnabled = config.enabled;
+ },
+ );
+
this.in3D = this.store$.selectSignal(selectIn3dView);
this.layersWithoutWebMercator = this.store$.selectSignal(selectLayersWithoutWebMercatorIds);
const tiles3DLayers = this.store$.selectSignal(select3dTilesLayers);
this.tiles3DLayerIds = computed(() => tiles3DLayers().map(l => l.id));
this.filteredLayerIds = this.store$.selectSignal(selectFilteredLayerIds);
+ const editableLayers = this.store$.selectSignal(selectEditableLayers);
+ this.editableLayerIds = computed(() => editableLayers().map(layer => layer.id));
}
public getDropZoneConfig() {
@@ -139,4 +163,8 @@ export class TocComponent implements OnInit, OnDestroy {
this.mapService.zoomToScale(minScale);
}
+ public editLayer(layer: string) {
+ this.store$.dispatch(setSelectedEditLayer( { layer }));
+ this.store$.dispatch(setEditActive({ active: true }));
+ }
}