Skip to content

Commit

Permalink
PR Feature/1570-layercomparerselection (#1573)
Browse files Browse the repository at this point in the history
* layercomparer, admin and client. chosenLayers

* LayerComparerLayerList

* setting.service, layercomparer

* LayerComparer ol_uid chosenLayers compare

* Compare layers layerswitcher with layercomparer

* Removed setLayers([]) and setBaseLayers([]) from chosenLayers

* Changed label SelectDropdown, chosen layers

* return null and filter null, layercomparer admin+client

* Removed layer.name

* .filter .map layercomparer both admin and client

* Changed from layerswitcher to LayerMenuConfig in model. layercomparer in admin

* LayerComparer comments
  • Loading branch information
Sunix71 authored Jan 7, 2025
1 parent 8c0035b commit fccf4b7
Show file tree
Hide file tree
Showing 5 changed files with 439 additions and 35 deletions.
159 changes: 159 additions & 0 deletions apps/admin/src/views/components/LayerComparerLayerList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
import React from "react";

class LayerComparerLayerList extends React.Component {
constructor(props) {
super(props);
this.state = {
filterText: "",
sortAsc: true,
chosenLayers: this.props.chosenLayers || [],
};
}

componentDidUpdate(prevProps) {
if (prevProps.chosenLayers !== this.props.chosenLayers) {
this.setState({ chosenLayers: this.props.chosenLayers });
}
}

handleFilterChange = (e) => {
this.setState({ filterText: e.target.value });
};

handleSortToggle = () => {
this.setState((prevState) => ({ sortAsc: !prevState.sortAsc }));
};

handleLayerToggle = (layer) => {
this.setState((prevState) => {
const { chosenLayers } = prevState;
const exists = chosenLayers.some((l) => l.id === layer.id);
let updated;
if (exists) {
updated = chosenLayers.filter((l) => l.id !== layer.id);
} else {
updated = [...chosenLayers, layer];
}

if (this.props.onChosenLayersChange) {
this.props.onChosenLayersChange(updated);
}

return { chosenLayers: updated };
});
};

getFilteredAndSortedLayers() {
const { allLayers = [] } = this.props;
const { filterText, sortAsc } = this.state;

const filteredLayers = allLayers
.filter((layer) =>
(layer.caption || layer.id || "")
.toLowerCase()
.includes(filterText.toLowerCase())
)
.sort((a, b) => {
const aVal = (a.caption || a.id || "").toLowerCase();
const bVal = (b.caption || b.id || "").toLowerCase();
if (aVal < bVal) return sortAsc ? -1 : 1;
if (aVal > bVal) return sortAsc ? 1 : -1;
return 0;
});

return filteredLayers;
}

selectAllLayers = () => {
const filteredLayers = this.getFilteredAndSortedLayers();
const { chosenLayers } = this.state;

const allSelected =
filteredLayers.length > 0 &&
filteredLayers.every((layer) =>
chosenLayers.some((chosen) => chosen.id === layer.id)
);

let updated;
if (allSelected) {
updated = chosenLayers.filter(
(chosen) => !filteredLayers.some((fLayer) => fLayer.id === chosen.id)
);
} else {
const missing = filteredLayers.filter(
(l) => !chosenLayers.some((chosen) => chosen.id === l.id)
);
updated = [...chosenLayers, ...missing];
}

this.setState({ chosenLayers: updated });
if (this.props.onChosenLayersChange) {
this.props.onChosenLayersChange(updated);
}
};

render() {
const { chosenLayers, filterText, sortAsc } = this.state;
const filteredLayers = this.getFilteredAndSortedLayers();

const containerStyle = {
maxWidth: "600px",
border: "1px solid #ccc",
padding: "10px",
textAlign: "left",
};

const listContainerStyle = {
maxHeight: "200px",
overflowY: "auto",
border: "1px solid #ddd",
padding: "5px",
marginTop: "10px",
};

return (
<div style={containerStyle}>
<h3>Lager</h3>
<div style={{ marginBottom: "10px" }}>
<input
type="text"
placeholder="Filtrera"
value={filterText}
onChange={this.handleFilterChange}
style={{ marginRight: "10px", width: "80%" }}
/>
<button
type="button"
onClick={this.handleSortToggle}
style={{ marginRight: "10px" }}
>
Sortera {sortAsc ? "A-Ö" : "Ö-A"}
</button>
<button type="button" onClick={this.selectAllLayers}>
Välj alla / rensa alla
</button>
</div>

<div style={listContainerStyle}>
<ul style={{ listStyle: "none", padding: 0, margin: 0 }}>
{filteredLayers.map((layer) => {
const isChecked = chosenLayers.some((l) => l.id === layer.id);
return (
<li key={layer.id} style={{ marginBottom: "5px" }}>
<input
type="checkbox"
checked={isChecked}
onChange={() => this.handleLayerToggle(layer)}
/>{" "}
{layer.caption || layer.id}
</li>
);
})}
</ul>
</div>
</div>
);
}
}

export default LayerComparerLayerList;
117 changes: 117 additions & 0 deletions apps/admin/src/views/tools/layercomparer.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import Button from "@material-ui/core/Button";
import SaveIcon from "@material-ui/icons/SaveSharp";
import { withStyles } from "@material-ui/core/styles";
import { blue } from "@material-ui/core/colors";
import LayerComparerLayerList from "../components/LayerComparerLayerList";

const ColorButtonBlue = withStyles((theme) => ({
root: {
Expand All @@ -24,6 +25,9 @@ const defaultState = {
instruction: "",
visibleAtStart: false,
visibleForGroups: [],
chosenLayers: [],
selectChosenLayers: false,
layers: [],
};

class LayerComparer extends Component {
Expand All @@ -49,14 +53,99 @@ class LayerComparer extends Component {
visibleForGroups: tool.options.visibleForGroups
? tool.options.visibleForGroups
: [],
chosenLayers: tool.options.chosenLayers
? tool.options.chosenLayers
: [],
selectChosenLayers: tool.options.selectChosenLayers,
});
this.loadLayers();
} else {
this.setState({
active: false,
});
}
}

handleSelectChosenLayersChange = (checked) => {
this.setState((prevState) => ({
selectChosenLayers: checked,
chosenLayers: checked ? prevState.chosenLayers : [],
showNonBaseLayersInSelect: checked
? false
: prevState.showNonBaseLayersInSelect,
}));

if (checked) {
this.loadLayers();
}
};

/* Extracts all layers from the provided options, including both grouped layers and baselayers.
Initializes an empty array to store the collected layers.
Defines a helper function to recursively collect layers from each group.
If a group contains layers, those layers are added to the layers array.
If a group contains subgroups, the helper function is called recursively for each subgroup.
Iterates over each group in options.groups and collects their layers using the helper function.
Adds all baselayers from options.baselayers to the layers array.
Returns the complete array of collected layers.*/
getLayersFromGroupsAndBaselayers(options) {
const layers = [];

function collectLayersFromGroup(group) {
if (group.layers) {
layers.push(...group.layers);
}
if (group.groups) {
group.groups.forEach(collectLayersFromGroup);
}
}

if (options.groups) {
options.groups.forEach(collectLayersFromGroup);
}

if (options.baselayers) {
layers.push(...options.baselayers);
}

return layers;
}

/*
* Loads layers based on the current map configuration.
* 1. Retrieves the layer menu configuration from the model.
* 2. Logs an error and exits if the configuration is missing.
* 3. Extracts layers from groups and baselayers using a helper method.
* 4. Retrieves all available layers from the model.
* 5. Filters and maps the extracted layers to match the available layers.
* 6. Updates the component's state with the filtered layers.
*/
loadLayers() {
const mapConfig = this.props.model.get("layerMenuConfig");

if (!mapConfig) {
console.error("Map configuration could not be loaded.");
return;
}

const layerMenuConfigLayers =
this.getLayersFromGroupsAndBaselayers(mapConfig);

const allLayers = this.props.model.get("layers");

const comparedLayers = layerMenuConfigLayers
.filter((lsLayer) => allLayers.some((al) => al.id === lsLayer.id))
.map((lsLayer) => {
const realLayer = allLayers.find((al) => al.id === lsLayer.id);
return {
id: realLayer.id,
caption: realLayer.caption || "Okänt lager",
};
});

this.setState({ layers: comparedLayers });
}

/**
*
*/
Expand Down Expand Up @@ -118,6 +207,8 @@ class LayerComparer extends Component {
Function.prototype.call,
String.prototype.trim
),
chosenLayers: this.state.chosenLayers,
selectChosenLayers: this.state.selectChosenLayers,
},
};

Expand Down Expand Up @@ -202,6 +293,7 @@ class LayerComparer extends Component {
*
*/
render() {
const { layers } = this.state;
return (
<div>
<form>
Expand Down Expand Up @@ -286,6 +378,7 @@ class LayerComparer extends Component {
this.handleInputChange(e);
}}
checked={this.state.showNonBaseLayersInSelect}
disabled={this.state.selectChosenLayers}
/>
&nbsp;
<label
Expand Down Expand Up @@ -315,6 +408,30 @@ class LayerComparer extends Component {
value={this.state.instruction ? atob(this.state.instruction) : ""}
/>
</div>
<div>
<label style={{ paddingBottom: "20px" }}>
<input
type="checkbox"
checked={this.state.selectChosenLayers}
onChange={(e) =>
this.handleSelectChosenLayersChange(e.target.checked)
}
/>
Aktivera "Välj lager"
</label>
</div>
<div>
{this.state.selectChosenLayers && (
<LayerComparerLayerList
allLayers={layers}
chosenLayers={this.state.chosenLayers}
onChosenLayersChange={(updatedLayers) =>
this.setState({ chosenLayers: updatedLayers })
}
/>
)}
</div>

{this.renderVisibleForGroups()}
</form>
</div>
Expand Down
29 changes: 29 additions & 0 deletions apps/backend/server/apis/v2/services/settings.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,24 @@ class SettingsService {
return group;
};

const removeLayerIdFromLayerComparer = (layerComparerOptions) => {
// Remove the layerId from the chosenLayers array
if (Array.isArray(layerComparerOptions.chosenLayers)) {
const initialLength = layerComparerOptions.chosenLayers.length;
layerComparerOptions.chosenLayers =
layerComparerOptions.chosenLayers.filter(
(layer) => layer.id !== layerId
);

// If any layers were removed, mark as modified
if (layerComparerOptions.chosenLayers.length !== initialLength) {
modified = true;
}
}

return layerComparerOptions;
};

// Helper function, used to remove references to a layer from Search tool's options
const removeLayerIdFromSearchSources = (searchSources) => {
const index = searchSources.findIndex((l) => l === layerId);
Expand Down Expand Up @@ -251,6 +269,17 @@ class SettingsService {
);
}

// LayerComparer processing
const layerComparerToolIndex = json.tools.findIndex(
(t) => t.type === "layercomparer"
);
const layerComparerOptions = json.tools[layerComparerToolIndex]?.options;

if (layerComparerOptions) {
json.tools[layerComparerToolIndex].options =
removeLayerIdFromLayerComparer(layerComparerOptions);
}

// If any of the above resulted in modified file, write the changes.
// Make sure to first check that we really have new options to write
// as we don't want to write an undefined "object".
Expand Down
Loading

0 comments on commit fccf4b7

Please sign in to comment.