Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions projects/admin-core/assets/locale/messages.admin-core.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@
<source>Copy application <x id="INTERPOLATION" equiv-text="{{data.application.title}}"/></source>
<target>Anwendung kopieren <x id="INTERPOLATION" equiv-text="{{data.application.title}}"/></target>
</trans-unit>
<trans-unit id="admin-core.application.copy-layers-info" datatype="html">
<source>Select one or more layers that are available for copying features from. If no layers are selected, all layers will be available. Note that incompatible layer geometry types may prevent successful copying.</source>
<target>Wählen Sie eine oder mehrere Ebenen aus, von denen Features kopiert werden können. Wenn keine Ebenen ausgewählt sind, stehen alle Ebenen zur Verfügung. Beachten Sie, dass inkompatible Geometrietypen der Ebenen ein erfolgreiches Kopieren verhindern können.</target>
</trans-unit>
<trans-unit id="admin-core.application.create-application" datatype="html">
<source>Create application</source>
<target>Anwendung erstellen</target>
Expand Down
3 changes: 3 additions & 0 deletions projects/admin-core/assets/locale/messages.admin-core.en.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,9 @@
<trans-unit id="admin-core.application.copy-application" datatype="html">
<source>Copy application <x id="INTERPOLATION" equiv-text="{{data.application.title}}"/></source>
</trans-unit>
<trans-unit id="admin-core.application.copy-layers-info" datatype="html">
<source>Select one or more layers that are available for copying features from. If no layers are selected, all layers will be available. Note that incompatible layer geometry types may prevent successful copying.</source>
</trans-unit>
<trans-unit id="admin-core.application.create-application" datatype="html">
<source>Create application</source>
</trans-unit>
Expand Down
4 changes: 4 additions & 0 deletions projects/admin-core/assets/locale/messages.admin-core.nl.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,10 @@
<source>Copy application <x id="INTERPOLATION" equiv-text="{{data.application.title}}"/></source>
<target>Kopieer applicatie <x id="INTERPOLATION" equiv-text="{{data.application.title}}"/></target>
</trans-unit>
<trans-unit id="admin-core.application.copy-layers-info" datatype="html">
<source>Select one or more layers that are available for copying features from. If no layers are selected, all layers will be available. Note that incompatible layer geometry types may prevent successful copying.</source>
<target>Selecteer één of meerdere lagen waarvan objecten kunnen worden gekopiëerd. Als geen lagen zijn aangevinkt is dit mogelijk van alle lagen. Let op dat door incompatibele geometrie-types een object mogelijk niet gekopiëerd kan worden.</target>
</trans-unit>
<trans-unit id="admin-core.application.create-application" datatype="html">
<source>Create application</source>
<target>Applicatie aanmaken</target>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import { GeolocationConfigComponent } from './geolocation-config/geolocation-con
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';
import { SharedAdminComponentsModule } from '../../shared/components';

@NgModule({
declarations: [
Expand All @@ -39,6 +40,7 @@ import { TocComponentConfigComponent } from './toc-config/toc-component-config.c
BaseComponentConfigComponent,
SelectUploadModule,
MarkdownEditorComponent,
SharedAdminComponentsModule,
],
exports: [
ComponentsListComponent,
Expand All @@ -50,7 +52,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`, TocComponentConfigComponent);
configurationComponentService.registerConfigurationComponents(BaseComponentTypeEnum.TOC, $localize `:@@admin-core.application.component-table-of-contents:Table of contents`, BaseComponentConfigComponent);
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);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
div {
margin-bottom: 8px;
}

.copy-layers {
max-width: 500px;
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,22 @@
<div [formGroup]="formGroup">
<mat-checkbox formControlName="closeAfterAddFeature"
i18n="@@admin-core.components.edit-close-after-add-feature">Close window after adding new feature</mat-checkbox>

<div class="copy-layers">
<div class="copy-layers-info">
<span i18n="@@admin-core.application.copy-layers-info">Select one or more layers that are available for copying features from. If no layers are selected, all layers will be available. Note that incompatible layer geometry types may prevent successful copying.</span>
</div>
<tm-admin-list-filter [formControl]="copyLayerFilter"
[filterTerm]="copyLayerFilterSignal()"
i18n-label="@@admin-core.application.filter-tree"
label="Filter application layers"></tm-admin-list-filter>
<mat-selection-list (selectionChange)="onCopyLayerSelectionChange($event)">
@for (layer of filteredLayerList(); track layer.id) {
<mat-list-option [value]="layer.id" [selected]="layer.selected">
<div class="layer-label">{{ layer.label }}</div>
</mat-list-option>
}
</mat-selection-list>
</div>
</div>
</tm-admin-base-component-config>
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import { ChangeDetectionStrategy, Component, DestroyRef, Input, inject } from '@angular/core';
import { ChangeDetectionStrategy, Component, DestroyRef, Input, inject, signal, OnInit, computed, effect } from '@angular/core';
import {
BaseComponentTypeEnum, EditConfigModel,
} 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';
import { debounceTime, take } from 'rxjs';
import { MatSelectionListChange } from '@angular/material/list';
import { selectExtendedAppLayerNodesForSelectedApplication } from '../../state/application.selectors';
import { Store } from '@ngrx/store';
import { FilterHelper, LoadingStateEnum } from '@tailormap-viewer/shared';
import { selectCatalogLoadStatus } from '../../../catalog/state/catalog.selectors';
import { loadCatalog } from '../../../catalog/state/catalog.actions';

@Component({
selector: 'tm-admin-edit-component-config',
Expand All @@ -15,10 +21,10 @@ import { debounceTime } from 'rxjs';
changeDetection: ChangeDetectionStrategy.OnPush,
standalone: false,
})
export class EditComponentConfigComponent implements ConfigurationComponentModel<EditConfigModel> {
export class EditComponentConfigComponent implements ConfigurationComponentModel<EditConfigModel>, OnInit {
private componentConfigService = inject(ComponentConfigurationService);
private destroyRef = inject(DestroyRef);

private store$ = inject(Store);

@Input()
public type: BaseComponentTypeEnum | undefined;
Expand All @@ -39,8 +45,36 @@ export class EditComponentConfigComponent implements ConfigurationComponentModel
public formGroup = new FormGroup({
closeAfterAddFeature: new FormControl<boolean>(false),
});
public selectedCopyLayers = signal<string[]>([]);

// Not in formGroup for config properties, used for layer filter control
public copyLayerFilter = new FormControl<string>('');
public copyLayerFilterSignal = signal<string>('');
public allLayers = this.store$.selectSignal(selectExtendedAppLayerNodesForSelectedApplication);

public filteredLayerList = computed(() => {
const allLayers = this.allLayers();
const selectedLayerIds = this.selectedCopyLayers();
const filterTerm = this.copyLayerFilterSignal();
const layersWithSelected = allLayers.map(layer => ({
...layer,
selected: selectedLayerIds.includes(layer.id),
}));
if (filterTerm) {
return FilterHelper.filterByTerm(layersWithSelected, filterTerm, l => l.label);
}
return layersWithSelected;
});

constructor() {
this.store$.select(selectCatalogLoadStatus)
.pipe(take(1))
.subscribe(loadStatus => {
if (loadStatus === LoadingStateEnum.INITIAL || loadStatus === LoadingStateEnum.FAILED) {
this.store$.dispatch(loadCatalog());
}
});

this.formGroup.valueChanges
.pipe(takeUntilDestroyed(this.destroyRef), debounceTime(250))
.subscribe(() => {
Expand All @@ -49,14 +83,38 @@ export class EditComponentConfigComponent implements ConfigurationComponentModel
}
this.saveConfig();
});

effect(() => {
this.componentConfigService.updateConfigForKey<EditConfigModel>(this.type, 'copyLayerIds', this.selectedCopyLayers());
});
}

public ngOnInit(): void {
this.copyLayerFilter.valueChanges
.pipe(takeUntilDestroyed(this.destroyRef))
.subscribe(filterTerm => {
this.copyLayerFilterSignal.set(filterTerm || '');
});
}

public initForm(config: EditConfigModel | undefined) {
this.formGroup.patchValue({ closeAfterAddFeature: config?.closeAfterAddFeature ?? false }, { emitEvent: false });
this.selectedCopyLayers.set(config?.copyLayerIds ?? []);
}

private saveConfig() {
this.componentConfigService.updateConfigForKey<EditConfigModel>(this.type, 'closeAfterAddFeature', this.formGroup.value.closeAfterAddFeature);
}

public onCopyLayerSelectionChange($event: MatSelectionListChange) {
const selectedLayers = [...this.selectedCopyLayers()];
$event.options.forEach(option => {
if (option.selected) {
selectedLayers.push(option.value);
} else {
selectedLayers.splice(selectedLayers.indexOf(option.value), 1);
}
});
this.selectedCopyLayers.set(selectedLayers);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { ExtendedGeoServiceModel } from '../../catalog/models/extended-geo-service.model';
import { ExtendedFeatureTypeModel } from '../../catalog/models/extended-feature-type.model';
import { ExtendedGeoServiceLayerModel } from '../../catalog/models/extended-geo-service-layer.model';
import { AppLayerSettingsModel, AppTreeLayerNodeModel } from '@tailormap-admin/admin-api';

export interface ExtendedAppTreeLayerNodeModel extends AppTreeLayerNodeModel {
label: string;
appLayerSettings: AppLayerSettingsModel;
geoService: ExtendedGeoServiceModel | undefined;
geoServiceLayer: ExtendedGeoServiceLayerModel | undefined;
featureType: ExtendedFeatureTypeModel | undefined;
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import { ApplicationModelHelper } from '../helpers/application-model.helper';
import { GeoServiceLayerInApplicationModel } from '../models/geo-service-layer-in-application.model';
import { ExtendedGeoServiceLayerModel } from '../../catalog/models/extended-geo-service-layer.model';
import { ExtendedFilterGroupModel } from '../models/extended-filter-group.model';
import { ExtendedAppTreeLayerNodeModel } from '../models/extended-app-tree-layer-node.model';

const selectApplicationState = createFeatureSelector<ApplicationState>(applicationStateKey);

Expand Down Expand Up @@ -205,6 +206,36 @@ export const selectStylingConfig = createSelector(selectDraftApplication, applic

export const selectFilterGroups = createSelector(selectDraftApplication, application => application?.settings?.filterGroups || []);

export const selectExtendedAppLayerNodesForSelectedApplication = createSelector(
selectAppLayerNodesForSelectedApplication,
selectGeoServices,
selectGeoServiceLayers,
selectSelectedApplicationLayerSettings,
selectFeatureTypes,
(appLayerTreeNodes, geoServices, geoServiceLayers, layerSettings, featureTypes) => {
const geoServiceLayerMap = ApplicationTreeHelper.getLayerMap(geoServiceLayers);
return appLayerTreeNodes
.filter(node => ApplicationModelHelper.isLayerTreeNode(node))
.map((appLayerNode): ExtendedAppTreeLayerNodeModel => {
const geoServiceLayer = geoServiceLayerMap.get(ApplicationTreeHelper.getLayerMapKey(appLayerNode.layerName, appLayerNode.serviceId));
const geoService = geoServices.find(service => service.id === geoServiceLayer?.serviceId);
const appLayerSettings = layerSettings[appLayerNode.id];
const featureType = featureTypes.find(ft => {
return ft.featureSourceId === geoServiceLayer?.layerSettings?.featureType?.featureSourceId.toString()
&& ft.name === geoServiceLayer.layerSettings?.featureType?.featureTypeName;
});
return {
...appLayerNode,
label: ApplicationTreeHelper.getTreeModelLabel(appLayerNode, geoServiceLayerMap, layerSettings, 'layer'),
appLayerSettings,
geoService,
geoServiceLayer,
featureType,
};
});
},
);

export const selectFilterableLayersForApplication = createSelector(
selectAppLayerNodesForSelectedApplication,
selectGeoServiceLayers,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ import { ComponentBaseConfigModel } from '../component-base-config.model';

export interface EditConfigModel extends ComponentBaseConfigModel {
closeAfterAddFeature: boolean;
copyLayerIds?: string[];
}
4 changes: 0 additions & 4 deletions projects/core/assets/locale/messages.core.de.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -427,10 +427,6 @@
<target>Löschen des Features fehlgeschlagen</target>
</trans-unit>
<trans-unit id="core.edit.edit" datatype="html">
<source>Edit</source>
<target>Bearbeiten</target>
</trans-unit>
<trans-unit id="core.edit.edit-feature-tooltip" datatype="html">
<source>Edit feature</source>
<target>Objekt bearbeiten</target>
</trans-unit>
Expand Down
3 changes: 0 additions & 3 deletions projects/core/assets/locale/messages.core.en.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -321,9 +321,6 @@
<source>Delete feature failed</source>
</trans-unit>
<trans-unit id="core.edit.edit" datatype="html">
<source>Edit</source>
</trans-unit>
<trans-unit id="core.edit.edit-feature-tooltip" datatype="html">
<source>Edit feature</source>
</trans-unit>
<trans-unit id="core.edit.error-getting-features" datatype="html">
Expand Down
8 changes: 2 additions & 6 deletions projects/core/assets/locale/messages.core.nl.xlf
Original file line number Diff line number Diff line change
Expand Up @@ -427,10 +427,6 @@
<target>Object verwijderen mislukt</target>
</trans-unit>
<trans-unit id="core.edit.edit" datatype="html">
<source>Edit</source>
<target>Bewerken</target>
</trans-unit>
<trans-unit id="core.edit.edit-feature-tooltip" datatype="html">
<source>Edit feature</source>
<target>Object bewerken</target>
</trans-unit>
Expand Down Expand Up @@ -472,11 +468,11 @@
</trans-unit>
<trans-unit id="core.edit.select-feature-to-edit" datatype="html">
<source>Select which feature to edit</source>
<target>Selecteer een object om te bewerken</target>
<target>Object om te bewerken</target>
</trans-unit>
<trans-unit id="core.edit.select-layer" datatype="html">
<source>Select layer to edit</source>
<target>Selecteer een laag om te bewerken</target>
<target>Laag om te bewerken</target>
</trans-unit>
<trans-unit id="core.edit.true" datatype="html">
<source>True</source>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { ApplicationMapModule } from '../../map/application-map.module';
import { EditSelectFeatureComponent } from './edit-select-feature/edit-select-feature.component';
import { SelectFieldComponent } from './fields/select-field/select-field.component';
import { CoreSharedModule } from '../../shared';

import { MatBadge } from '@angular/material/badge';

@NgModule({
declarations: [
Expand All @@ -30,6 +30,7 @@ import { CoreSharedModule } from '../../shared';
EffectsModule.forFeature([EditEffects]),
ApplicationMapModule,
CoreSharedModule,
MatBadge,
],
exports: [
EditComponent,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,7 @@
[allowCollapse]="true"
[collapsed]="dialogCollapsed$ | async"
(expandCollapseDialog)="expandCollapseDialog()"
dialogTitle="Edit"
i18n-dialogTitle="@@core.edit.edit">
[dialogTitle]="dialogTitle$ | async">
@let currentFeature = currentFeature$ | async;
@let layerDetails = layerDetails$ | async;
@if (currentFeature && layerDetails) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { render, screen } from '@testing-library/angular';
import { EditDialogComponent } from './edit-dialog.component';
import { provideMockStore } from '@ngrx/store/testing';
import { SharedModule } from '@tailormap-viewer/shared';
import { LoadingStateEnum, SharedModule } from '@tailormap-viewer/shared';
import { NoopAnimationsModule } from '@angular/platform-browser/animations';
import { AttributeType, getAppLayerModel, getFeatureModel, UniqueValuesService } from '@tailormap-viewer/api';
import { MatIconTestingModule } from '@angular/material/icon/testing';
Expand All @@ -15,6 +15,8 @@ import { of } from 'rxjs';
import { ViewerLayoutService } from '../../../services/viewer-layout/viewer-layout.service';
import { CoreSharedModule } from '../../../shared';
import { getMapServiceMock } from '../../../test-helpers/map-service.mock.spec';
import { EditMapToolService } from '../services/edit-map-tool.service';
import { coreStateKey, initialCoreState, selectViewerLoadingState, ViewerState } from '../../../state';

const getFeatureInfo = (): FeatureWithMetadataModel => {
return {
Expand Down Expand Up @@ -42,9 +44,13 @@ const setup = async (getLayerDetails = false, selectors: any[] = []) => {
},
{ provide: EditFeatureService, useValue: {} },
getMapServiceMock().provider,
provideMockStore({ initialState: { [editStateKey]: { ...initialEditState } }, selectors }),
provideMockStore({ initialState: {
[editStateKey]: { ...initialEditState },
[coreStateKey]: { ...initialCoreState, viewer: { components: [] } as ViewerState },
}, selectors }),
{ provide: UniqueValuesService, useValue: { clearCaches: jest.fn() } },
{ provide: ViewerLayoutService, useValue: { setLeftPadding: jest.fn(), setRightPadding: jest.fn() } },
{ provide: EditMapToolService, useValue: { allEditGeometry$: of() } },
],
schemas: [CUSTOM_ELEMENTS_SCHEMA],
});
Expand All @@ -63,7 +69,7 @@ describe('EditDialogComponent', () => {
{ selector: selectSelectedEditFeature, value: getFeatureInfo() },
{ selector: selectEditDialogVisible, value: true },
]);
expect(await screen.findByText('Edit')).toBeInTheDocument();
expect(await screen.findByText('Edit feature')).toBeInTheDocument();
expect(await screen.findByText('Close')).toBeInTheDocument();
expect(await screen.findByText('Save')).toBeInTheDocument();
expect(await screen.findByText('Delete')).toBeInTheDocument();
Expand Down
Loading
Loading