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
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ gem 'resource_api', git: 'https://github.com/performant-software/resource-api.gi
gem 'jwt_auth', git: 'https://github.com/performant-software/jwt-auth.git', tag: 'v0.1.3'

# Core data
gem 'core_data_connector', git: 'https://github.com/performant-software/core-data-connector.git', tag: 'v0.1.121'
gem 'core_data_connector', git: 'https://github.com/performant-software/core-data-connector.git', tag: 'v0.1.122'

# IIIF
gem 'triple_eye_effable', git: 'https://github.com/performant-software/triple-eye-effable.git', tag: 'v0.2.7'
Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
GIT
remote: https://github.com/performant-software/core-data-connector.git
revision: c29a4f5d0ac39ecac405b08481dd21db171be081
tag: v0.1.121
revision: f10cb17b4bf53c0389c6d3d23e25eb6173c00759
tag: v0.1.122
specs:
core_data_connector (0.1.0)
activerecord-postgis-adapter (~> 11.0)
Expand Down
8 changes: 4 additions & 4 deletions client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
"dependencies": {
"@bunchtogether/vite-plugin-flow": "^1.0.2",
"@clerk/react": "^6.0.1",
"@performant-software/geospatial": "^3.1.7",
"@performant-software/semantic-components": "^3.1.7",
"@performant-software/shared-components": "^3.1.7",
"@performant-software/user-defined-fields": "^3.1.7",
"@performant-software/geospatial": "^3.1.17",
"@performant-software/semantic-components": "^3.1.17",
"@performant-software/shared-components": "^3.1.17",
"@performant-software/user-defined-fields": "^3.1.17",
"@peripleo/maplibre": "^0.8.7",
"@peripleo/peripleo": "^0.8.7",
"@samvera/clover-iiif": "^2.18.3",
Expand Down
70 changes: 70 additions & 0 deletions client/src/components/MapCertaintyControl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// @flow

import cx from 'classnames';
import React, { useCallback, useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { TbCircleDashed } from 'react-icons/tb';
import { MapControl } from '@performant-software/geospatial';
import styles from './MapCertaintyControl.module.css';

type Props = {
data: any,
onChange: (data: any) => void
};

const MapCertaintyControl = (props: Props) => {
const { t } = useTranslation();
const [showCertaintyRadiusInput, setShowCertaintyRadiusInput] = useState(false);

const certaintyRadius = useMemo(() => (
props.data?.certainty_radius || 0
), [props.data]);

const onCertaintyRadiusChange = useCallback((e) => {
const radius = parseFloat(e.target.value) || 0;

props.onChange({
...props.data,
certainty_radius: radius
});
}, [props.data, props.onChange]);

return (
<MapControl
position='bottom-left'
>
<div className={styles.certaintyRadiusControl}>
<button
className={cx(
'mapbox-gl-draw_ctrl-draw-btn',
'layer-button'
)}
onClick={() => setShowCertaintyRadiusInput(!showCertaintyRadiusInput)}
title={t('PlaceForm.labels.certaintyRadius')}
type='button'
>
<TbCircleDashed />
</button>
{ showCertaintyRadiusInput && (
<div
className={cx(
styles.certaintyRadiusInputContainer,
'mapbox-gl-draw_ctrl-draw-btn'
)}
>
<input
className='ui input'
type='number'
value={certaintyRadius}
min={0}
step={0.01}
onChange={onCertaintyRadiusChange}
/>
</div>
)}
</div>
</MapControl>
);
};

export default MapCertaintyControl;
21 changes: 21 additions & 0 deletions client/src/components/MapCertaintyControl.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
.certaintyRadiusControl {
display: inline-flex;
justify-content: center;
align-items: center;
margin: 0;
padding: 0;
}

.certaintyRadiusControl .certaintyRadiusInputContainer {
margin: 0;
height: 20px;
position: absolute;
left: 40px;
top: -2px;
width: 100px;
background-color: white;
}

.certaintyRadiusControl > .ui.input {
margin: 0;
}
36 changes: 32 additions & 4 deletions client/src/components/PlaceForm.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// @flow

import {
CertaintyLayer,
GeoJsonLayer,
LayerMenu,
MapControl,
Expand Down Expand Up @@ -29,6 +30,7 @@ import PlaceLayerModal from './PlaceLayerModal';
import PlaceLayerUtils from '../utils/PlaceLayers';
import PlaceNameModal from './PlaceNameModal';
import styles from './PlaceForm.module.css';
import MapCertaintyControl from './MapCertaintyControl';

type Props = EditContainerProps & {
item: PlaceType
Expand Down Expand Up @@ -62,7 +64,7 @@ const PlaceForm = (props: Props) => {
}, [geocoding]);

/**
* Memo-izes the names of the passed place layers.
* Memoizes the names of the passed place layers.
*/
const layerNames = useMemo(() => _.pluck(props.item.place_layers, 'name'), [props.item.place_layers]);

Expand Down Expand Up @@ -115,7 +117,7 @@ const PlaceForm = (props: Props) => {

/**
* Sets map geometry data on the item, destroying any existing geometry record
* if all geometry is deleted.
* if all geometry is deleted.
*/
useEffect(() => {
if (mapData !== null) {
Expand All @@ -124,7 +126,12 @@ const PlaceForm = (props: Props) => {
place_geometry: { id: props.item.place_geometry.id, _destroy: true }
});
} else {
props.onSetState({ place_geometry: mapData })
props.onSetState({
place_geometry: {
geometry_json: mapData.geometry_json || props.item.place_geometry?.geometry_json,
properties: mapData.properties || props.item.place_geometry?.properties
}
});
}
}
}, [mapData, props.item.place_geometry?.id]);
Expand All @@ -134,7 +141,20 @@ const PlaceForm = (props: Props) => {
*
* @type {function(*): *}
*/
const onMapChange = useCallback((data) => setMapData({ geometry_json: data }), []);
const onMapChange = (data) => setMapData({
properties: props.item.place_geometry?.properties,
geometry_json: data
});

/**
* Sets the new map properties on the state.
*
* @type {function(*): *}
*/
const onPropertiesChange = (data) => setMapData({
geometry_json: props.item.place_geometry?.geometry_json,
properties: data
});

/**
* Sets the uploaded file as the GeoJSON object.
Expand Down Expand Up @@ -246,6 +266,10 @@ const PlaceForm = (props: Props) => {
WebkitBoxShadow: 'rgba(0, 0, 0, 0.1) 0px 10px 15px -3px, rgba(0, 0, 0, 0.05) 0px 4px 6px -2px'
}}
>
<CertaintyLayer
geometry={{ geometry: props.item.place_geometry?.geometry_json }}
certaintyRadius={props.item.place_geometry?.properties?.certainty_radius || 0}
/>
<MapControl
position='bottom-left'
>
Expand Down Expand Up @@ -282,6 +306,10 @@ const PlaceForm = (props: Props) => {
onSelection={onUpload}
/>
</MapControl>
<MapCertaintyControl
data={props.item.place_geometry?.properties}
onChange={onPropertiesChange}
/>
<LayerMenu
names={layerNames}
>
Expand Down
3 changes: 2 additions & 1 deletion client/src/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -504,7 +504,8 @@
"location": "Location",
"names": "Names",
"polygonMode": "Polygon mode",
"pointMode": "Point mode"
"pointMode": "Point mode",
"certaintyRadius": "Certainty radius (in KM)"
},
"placeLayers": {
"columns": {
Expand Down
2 changes: 1 addition & 1 deletion client/src/transforms/Place.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ class Place extends BaseTransform {
}

/**
* Returns the place for POST/PUT requests as a plain Javascript object.
* Returns the place for POST/PUT requests as a plain JavaScript object.
*
* @param place
*
Expand Down
5 changes: 3 additions & 2 deletions client/src/transforms/PlaceGeometry.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,16 @@ class PlaceGeometry extends BaseTransform {
*
* @param place
*
* @returns {{place_geometry: (*&{geometry_json: string})}}
* @returns {{place_geometry: (*&{geometry_json: string, properties: string})}}
*/
toPayload(place: PlaceType) {
const { place_geometry: placeGeometry } = place;

return {
[this.getParameterName()]: {
..._.pick(placeGeometry, this.getPayloadKeys()),
geometry_json: JSON.stringify(placeGeometry?.geometry_json)
geometry_json: JSON.stringify(placeGeometry?.geometry_json),
properties: placeGeometry?.properties
}
};
}
Expand Down
3 changes: 2 additions & 1 deletion client/src/types/Place.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,8 @@ export type PlaceName = {

export type PlaceGeometry = {
id: number,
geometry_json: string
geometry_json: string,
properties: string
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should properties be a required string or an (optional?) object with certainty_radius as an optional key?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question - I think at the point that the type is used (when the data is being transformed to go to the server), the JSON has been stringified, so that's why geometry_json is also a string.

};

export type Place = {
Expand Down
32 changes: 16 additions & 16 deletions client/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1846,10 +1846,10 @@
remark-rehype "^11.1.0"
unified "^11.0.4"

"@performant-software/geospatial@^3.1.7":
version "3.1.7"
resolved "https://registry.yarnpkg.com/@performant-software/geospatial/-/geospatial-3.1.7.tgz#59a3db0f97888ecdba3e3fac4306712412f6c2e1"
integrity sha512-TZC7BJKetg8YFWdcCqCWe/ThCmSHEpISiT6b/QFCwjp/Lat2UBee/qpsfBybDesL24ainMfEit5ZsHS0fNh/4w==
"@performant-software/geospatial@^3.1.17":
version "3.1.17"
resolved "https://registry.yarnpkg.com/@performant-software/geospatial/-/geospatial-3.1.17.tgz#7ef6dc4663a7e6b4333a5fa3d9a836ef00b360a6"
integrity sha512-kfb3DC5KV6AaE85whW1c15UXdRlacbLeyhhzxBsh64YHORORuIvKF4MKOTO9nQzcjwuuDDkWhuIg9oVWTsefEg==
dependencies:
"@allmaps/maplibre" "^1.0.0-beta.25"
"@mapbox/mapbox-gl-draw" "1.4.3"
Expand All @@ -1861,10 +1861,10 @@
react-map-gl "^8.0.4"
underscore "^1.13.7"

"@performant-software/semantic-components@^3.1.7":
version "3.1.7"
resolved "https://registry.yarnpkg.com/@performant-software/semantic-components/-/semantic-components-3.1.7.tgz#bc4a130ca9a95fe7f9abb2ec39b88d34d8e739fc"
integrity sha512-XQ0UyIoO77sZFjhVWp4V3V3VdtqTpZdN8mbL71HlsYA6ZXJfgBeFs58VLX9mEMGpKMnCATpw5FLqikWGrOkhQg==
"@performant-software/semantic-components@^3.1.17":
version "3.1.17"
resolved "https://registry.yarnpkg.com/@performant-software/semantic-components/-/semantic-components-3.1.17.tgz#9aeede214994dc5dd802743671623251e2d92235"
integrity sha512-D8nCVALu91lM+YAu6zUpDHX9shhxJjUhkD/qmKPhaOgYhzsOGUzy72wuUYRcNu1Y1MTx14d1f09K/qeBAEcmaA==
dependencies:
"@react-google-maps/api" "^2.20.7"
axios "^1.10.0"
Expand All @@ -1882,10 +1882,10 @@
zotero-api-client "^0.40.0"
zotero-translation-client "^5.0.1"

"@performant-software/shared-components@^3.1.7":
version "3.1.7"
resolved "https://registry.yarnpkg.com/@performant-software/shared-components/-/shared-components-3.1.7.tgz#f4618db460003fa92349cc2d5aa9d93085f20be9"
integrity sha512-uLfIdG1kYGUwfa8B28EaI92bnBJz6ya2Idol+b1h/OY9Yu2z643aAMSEiERtAm4ufRnxzMkSeBOzJUWcUd3jnw==
"@performant-software/shared-components@^3.1.17":
version "3.1.17"
resolved "https://registry.yarnpkg.com/@performant-software/shared-components/-/shared-components-3.1.17.tgz#f57880443a40b72f2ce415ac6a641b2bcfd8e108"
integrity sha512-LMXFiUHKmjX223aWqiui+wRzGuLPhPw6hS2YbPudfE+2Fx0jhoMfq0Ks4tMXmhgfdms7bNw8XAfyD+OG6CEGDg==
dependencies:
"@rails/activestorage" "^8.0.201"
"@react-google-maps/api" "^2.20.7"
Expand All @@ -1901,10 +1901,10 @@
underscore "^1.13.7"
zotero-translation-client "^5.0.1"

"@performant-software/user-defined-fields@^3.1.7":
version "3.1.7"
resolved "https://registry.yarnpkg.com/@performant-software/user-defined-fields/-/user-defined-fields-3.1.7.tgz#d6d5b2177f6ec3215db0668abcaa9e6801252a06"
integrity sha512-Wx6dIn0avVELoOhnsz6VpaE9w2p6AaeKi8mDxfM01AMoXXYrDMrwea+ch2LAUZ08t5UHfarvHDcyjMqvTW0T7g==
"@performant-software/user-defined-fields@^3.1.17":
version "3.1.17"
resolved "https://registry.yarnpkg.com/@performant-software/user-defined-fields/-/user-defined-fields-3.1.17.tgz#95b5a58151f3f61a1f4ab5f018fd8b06f4b87e3c"
integrity sha512-3U4bWTIvvfAZvVce4ue3xIQrJOJ/nU4mFsAYxKltBll65ZTL6I1LZ3yadVE2UTGirUKPwjzIh7UbwM9u4nZdfw==
dependencies:
i18next "^25.3.2"
semantic-ui-react "^2.1.5"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# This migration comes from core_data_connector (originally 20260402204230)
class AddPropertiesToPlaceGeometries < ActiveRecord::Migration[8.0]
def change
add_column :core_data_connector_place_geometries, :properties, :jsonb, default: {}
end
end
3 changes: 2 additions & 1 deletion db/schema.rb

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.