Skip to content

Commit

Permalink
Merge branch 'develop'
Browse files Browse the repository at this point in the history
  • Loading branch information
sbrunato committed Mar 4, 2024
2 parents d0b89c6 + dcaf325 commit 47d0e7c
Show file tree
Hide file tree
Showing 24 changed files with 584 additions and 141 deletions.
7 changes: 7 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
# Release history

## 3.6.0 (2024-03-04)

- New `reload eodag environment` button [(#139)](https://github.com/CS-SI/eodag-labextension/pull/139)
- Customizable map default settings [(#143)](https://github.com/CS-SI/eodag-labextension/pull/143)
- Handlers patterns fix and code refactoring [(#142)](https://github.com/CS-SI/eodag-labextension/pull/142)[(#144)](https://github.com/CS-SI/eodag-labextension/pull/144)
- Updates dependencies and developement tools versions [(#138)](https://github.com/CS-SI/eodag-labextension/pull/138)

## 3.5.0 (2024-02-08)

- New `provider` filtering [(#127)](https://github.com/CS-SI/eodag-labextension/pull/127)
Expand Down
1 change: 1 addition & 0 deletions NOTICE
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Open source projects:
* Notebook: BSD
* Python (interpreter and standard library): PSFL
* Setuptools: MIT
* Shapely: BSD
* Tornado: Apache v2.0

* Javascript:
Expand Down
15 changes: 13 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ Lab. The package consist of a Python Jupyter notebook REST service consumed by t
- [Configuration](#configuration)
- [QuickStart](#quickstart)
- [Search](#search)
- [Settings](#settings)
- [Results overview](#results-overview)
- [Apply to the Jupyter notebook](#apply-to-the-jupyter-notebook)
- [User manual](#user-manual)
Expand Down Expand Up @@ -94,9 +95,19 @@ Once search criteria are filled out, click on:
- `Generate Code` to automatically generate and insert the corresponding eodag search code bellow the active cell.
- `Preview Results` to perform a search in background, display results, and generate search code in a second step.

## Settings

![reload logo](https://raw.githubusercontent.com/CS-SI/eodag-labextension/develop/notebooks/images/eodag_labext_reload_icon.png)
Click on this icon to reload [EODAG configuration](https://eodag.readthedocs.io/en/stable/getting_started_guide/configure.html)
and take into account your updated credentials or providers settings.

![settings logo](https://raw.githubusercontent.com/CS-SI/eodag-labextension/develop/notebooks/images/eodag_labext_settings_icon.png)
Click on this icon to open EODAG-Labextension settings. You will be enable to choose whether newly inserted code should
replace existing search code or not.
Click on this icon to open EODAG-Labextension settings. You will be enable to:

- choose whether newly inserted code should replace existing search code or not;
- configure the default map settings.

![settings tab](https://raw.githubusercontent.com/CS-SI/eodag-labextension/develop/notebooks/images/eodag_labext_settings_map.png)

### Results overview

Expand Down
82 changes: 73 additions & 9 deletions eodag_labextension/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,14 @@

"""Tornado web requests handlers"""

import logging
import re

import orjson
import tornado
from eodag.rest.utils import eodag_api, search_products
from eodag import EODataAccessGateway, SearchResult
from eodag.api.core import DEFAULT_ITEMS_PER_PAGE, DEFAULT_PAGE
from eodag.rest.utils import get_datetime
from eodag.utils import parse_qs
from eodag.utils.exceptions import (
AuthenticationError,
Expand All @@ -19,10 +22,15 @@
)
from jupyter_server.base.handlers import APIHandler
from jupyter_server.utils import url_path_join
from shapely.geometry import shape

eodag_api = EODataAccessGateway()

logger = logging.getLogger("eodag-labextension.handlers")


class ProductTypeHandler(APIHandler):
"""Product type listing handlerd"""
"""Product type listing handler"""

@tornado.web.authenticated
def get(self):
Expand All @@ -44,6 +52,15 @@ def get(self):
self.write(orjson.dumps(product_types))


class ReloadHandler(APIHandler):
"""EODAG API reload handler"""

@tornado.web.authenticated
def get(self):
"""Get endpoint"""
eodag_api.__init__()


class ProvidersHandler(APIHandler):
"""Providers listing handler"""

Expand Down Expand Up @@ -92,7 +109,7 @@ def get(self):
returned_providers += [
p
for p in all_providers_list
if first_keyword in p["description"].lower() and p["provider"] not in providers_ids
if first_keyword in (p["description"] or "").lower() and p["provider"] not in providers_ids
]
else:
returned_providers = all_providers_list
Expand Down Expand Up @@ -172,17 +189,33 @@ def post(self, product_type):

arguments = orjson.loads(self.request.body)

# move geom to intersects parameter
# geom
geom = arguments.pop("geom", None)
if geom:
arguments["intersects"] = geom
try:
arguments["geom"] = shape(geom) if geom else None
except Exception:
self.set_status(400)
self.finish({"error": f"Invalid geometry: {str(geom)}"})
return

# dates
try:
arguments["start"], arguments["end"] = get_datetime(arguments)
except ValidationError as e:
self.set_status(400)
self.finish({"error": str(e)})
return

# provider
provider = arguments.pop("provider", None)
if provider and provider != "null":
arguments["provider"] = provider

# We remove potential None values to use the default values of the search method
arguments = dict((k, v) for k, v in arguments.items() if v is not None)

try:
response = search_products(product_type, arguments, stac_formatted=False)
products, total = eodag_api.search(productType=product_type, **arguments)
except ValidationError as e:
self.set_status(400)
self.finish({"error": e.message})
Expand All @@ -204,9 +237,36 @@ def post(self, product_type):
self.finish({"error": str(e)})
return

response = SearchResult(products).as_geojson_object()
response.update(
{
"properties": {
"page": int(arguments.get("page", DEFAULT_PAGE)),
"itemsPerPage": DEFAULT_ITEMS_PER_PAGE,
"totalResults": total,
}
}
)

self.finish(response)


class NotFoundHandler(APIHandler):
"""Not found handler"""

@tornado.web.authenticated
def post(self):
"""Post endpoint"""
self.set_status(404)
self.finish({"error": f"No matching handler for {self.request.uri}"})

@tornado.web.authenticated
def get(self):
"""Get endpoint"""
self.set_status(404)
self.finish({"error": f"No matching handler for {self.request.uri}"})


class MethodAndPathMatch(tornado.routing.PathMatches):
"""Wrapper around `tornado.routing.PathMatches` adding http method matching"""

Expand All @@ -230,17 +290,21 @@ def setup_handlers(web_app, url_path):
base_url = web_app.settings["base_url"]

# matching patterns
host_pattern = ".*$"
host_pattern = r".*$"
product_types_pattern = url_path_join(base_url, url_path, "product-types")
reload_pattern = url_path_join(base_url, url_path, "reload")
providers_pattern = url_path_join(base_url, url_path, "providers")
guess_product_types_pattern = url_path_join(base_url, url_path, "guess-product-type")
search_pattern = url_path_join(base_url, url_path, r"(?P<product_type>[\w-]+)")
search_pattern = url_path_join(base_url, url_path, r"(?P<product_type>[\w\-\.]+)")
default_pattern = url_path_join(base_url, url_path, r".*")

# handlers added for each pattern
handlers = [
(product_types_pattern, ProductTypeHandler),
(reload_pattern, ReloadHandler),
(providers_pattern, ProvidersHandler),
(guess_product_types_pattern, GuessProductTypeHandler),
(MethodAndPathMatch("POST", search_pattern), SearchHandler),
(default_pattern, NotFoundHandler),
]
web_app.add_handlers(host_pattern, handlers)
Binary file modified notebooks/images/eodag_labext_form.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added notebooks/images/eodag_labext_reload_icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added notebooks/images/eodag_labext_settings_map.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 18 additions & 2 deletions notebooks/user_manual.ipynb
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,25 @@
"<span style=\"clear: left; display:block;\"></span>\n",
"Once search criteria are filled out, click on:\n",
"- `Generate Code` to automatically generate and insert the corresponding eodag search code bellow the active cell.\n",
"- `Preview Results` to perform a search in background, display results, and generate search code in a second step.\n",
"- `Preview Results` to perform a search in background, display results, and generate search code in a second step."
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Settings\n",
"\n",
"![reload logo](https://raw.githubusercontent.com/CS-SI/eodag-labextension/develop/notebooks/images/eodag_labext_reload_icon.png)\n",
"Click on this icon to reload [EODAG configuration](https://eodag.readthedocs.io/en/stable/getting_started_guide/configure.html) \n",
"and take into account your updated credentials or providers settings.\n",
"\n",
"![settings logo](https://raw.githubusercontent.com/CS-SI/eodag-labextension/develop/notebooks/images/eodag_labext_settings_icon.png)\n",
"Click on this icon to open EODAG-Labextension settings. You will be enable to:\n",
"- choose whether newly inserted code should replace existing search code or not;\n",
"- configure the default map settings.\n",
"\n",
"![settings logo](https://raw.githubusercontent.com/CS-SI/eodag-labextension/develop/notebooks/images/eodag_labext_settings_icon.png) Click on this icon to open EODAG-Labextension settings. You will be enable to choose whether newly inserted code should replace existing search code or not."
"![settings tab](https://raw.githubusercontent.com/CS-SI/eodag-labextension/develop/notebooks/images/eodag_labext_settings_map.png)"
]
},
{
Expand Down
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "eodag-labextension",
"version": "3.5.0",
"version": "3.6.0",
"description": "Searching remote sensed imagery from various image providers",
"keywords": [
"jupyter",
Expand Down Expand Up @@ -55,6 +55,7 @@
"@jupyterlab/apputils": "^3.4.8",
"@jupyterlab/cells": "^3.4.8",
"@jupyterlab/notebook": "^3.4.8",
"@jupyterlab/settingregistry": "^3.4.8",
"@terraformer/wkt": "^2.1.2",
"install": "^0.13.0",
"isomorphic-fetch": "^3.0.0",
Expand All @@ -70,7 +71,7 @@
"react-loader-spinner": "^5.3.4",
"react-modal": "3.15.1",
"react-select": "5.4.0",
"react-tooltip": "~4.2.21",
"react-tooltip": "~5.26.3",
"react-virtualized": "^9.22.3"
},
"devDependencies": {
Expand Down
25 changes: 25 additions & 0 deletions schema/plugin.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,31 @@
"description": "Replace the existing search code containing matching comment with the new code.",
"type": "boolean",
"default": false
},
"map": {
"title": "Map settings",
"description": "Settings for editing the center and zoom of the map",
"type": "object",
"properties": {
"lat": {
"title": "Latitude",
"description": "Latitude of the center of the map",
"type": "number",
"default": 46.8
},
"lon": {
"title": "Longitude",
"description": "Longitude of the center of the map",
"type": "number",
"default": 1.8
},
"zoom": {
"title": "Zoom",
"description": "Zoom level of the map",
"type": "number",
"default": 4
}
}
}
},
"additionalProperties": false,
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,7 @@
"eodag[notebook]>=2.8.0",
"orjson",
],
extras_require={"dev": ["black", "pre-commit", "pytest"]},
extras_require={"dev": ["black", "pre-commit", "pytest", "shapely"]},
zip_safe=False,
include_package_data=True,
python_requires=">=3.8",
Expand Down
20 changes: 10 additions & 10 deletions src/Autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import {
SingleValueProps,
ValueContainerProps
} from 'react-select';
import ReactTooltip from 'react-tooltip';
import { Tooltip, PlacesType, VariantType } from 'react-tooltip';
import { OptionTypeBase } from 'react-select/src/types';
import AsyncSelect from 'react-select/async';

Expand All @@ -29,19 +29,19 @@ function NoOptionsMessage(props: any) {
</div>
);
}

const tooltipDark: VariantType = 'dark';
const tooltipRight: PlacesType = 'right';
function Option(props: OptionProps<OptionTypeBase, false>) {
// Tooltip on the right
return (
<div data-for={props.label} data-tip={props.data.description}>
<div
data-tooltip-id={props.label}
data-tooltip-content={props.data.description}
data-tooltip-variant={tooltipDark}
data-tooltip-place={tooltipRight}
>
<components.Option {...props}>{props.children}</components.Option>
<ReactTooltip
id={props.label}
className="jp-Eodag-tooltip"
place="right"
type="dark"
effect="solid"
/>
<Tooltip id={props.label} className="jp-Eodag-tooltip" />
</div>
);
}
Expand Down
Loading

0 comments on commit 47d0e7c

Please sign in to comment.