Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: providers list handler #127

Merged
merged 19 commits into from
Feb 7, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
44 changes: 40 additions & 4 deletions eodag_labextension/handlers.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,51 @@


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

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

get_product_types_kwargs = {}
query_dict = parse_qs(self.request.query)
if "provider" in query_dict and isinstance(query_dict["provider"], list) and len(query_dict["provider"]) > 0:
get_product_types_kwargs["provider"] = query_dict["provider"][0]
product_types = get_product_types(**get_product_types_kwargs)

self.write(json.dumps(product_types))

Product types endpoint filtered by provider not implemented"""

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

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

self.write(json.dumps(get_product_types()))
available_providers_kwargs = {}
query_dict = parse_qs(self.request.query)
if (
"product_type" in query_dict
and isinstance(query_dict["product_type"], list)
and len(query_dict["product_type"]) > 0
):
available_providers_kwargs["product_type"] = query_dict["product_type"][0]
available_providers = eodag_api.available_providers(**available_providers_kwargs)

providers_list = [
dict(
provider=provider,
priority=conf.priority,
description=getattr(conf, "description", None),
url=getattr(conf, "url", None),
)
for provider, conf in eodag_api.providers_config.items()
if provider in available_providers
]
providers_list.sort(key=lambda x: (x["priority"] * -1, x["provider"]))

self.write(json.dumps(providers_list))


class GuessProductTypeHandler(APIHandler):
Expand Down Expand Up @@ -121,12 +155,14 @@ def setup_handlers(web_app, url_path):
# matching patterns
host_pattern = ".*$"
product_types_pattern = url_path_join(base_url, url_path, "product-types")
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-]+)")

# handlers added for each pattern
handlers = [
(product_types_pattern, ProductTypeHandler),
(providers_pattern, ProvidersHandler),
(guess_product_types_pattern, GuessProductTypeHandler),
(MethodAndPathMatch("POST", search_pattern), SearchHandler),
]
Expand Down
53 changes: 5 additions & 48 deletions src/Autocomplete.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,6 @@ import ReactTooltip from 'react-tooltip';
import { OptionTypeBase } from 'react-select/src/types';
import AsyncSelect from 'react-select/async';

import { showErrorMessage } from '@jupyterlab/apputils';
import { URLExt } from '@jupyterlab/coreutils';
import { ServerConnection } from '@jupyterlab/services';
import { EODAG_SERVER_ADRESS } from './config';
import { map } from 'lodash';
import { IOptionTypeBase } from './FormComponent';

function NoOptionsMessage(props: any) {
return (
<div
Expand Down Expand Up @@ -92,57 +85,22 @@ interface IProps {
suggestions: OptionTypeBase[];
value: string;
handleChange: any;
url: string;
label: string;
}

class IntegrationReactSelect extends React.Component<IProps> {
render() {
const { suggestions, value, handleChange } = this.props;
const { label, suggestions, value, handleChange } = this.props;

const currentValue: OptionTypeBase = value
? suggestions.find(e => e.value === value)
: undefined;

const guessProductTypes = async (inputValue: string) => {
const _serverSettings = ServerConnection.makeSettings();
const _eodag_server = URLExt.join(
_serverSettings.baseUrl,
`${EODAG_SERVER_ADRESS}`
);

return fetch(
URLExt.join(_eodag_server, `guess-product-type?keywords=${inputValue}`),
{
credentials: 'same-origin'
}
)
.then(response => {
if (response.status >= 400) {
showErrorMessage(
`Unable to contact the EODAG server. Are you sure the adress is ${_eodag_server}/ ?`,
{}
);
throw new Error('Bad response from server');
}
return response.json();
})
.then(products => {
const guessProductTypes = map(products, product => ({
value: product.ID,
label: product.ID,
description: product.abstract
}));
return guessProductTypes;
});
};

const loadSuggestions = (inputValue: string) =>
new Promise<IOptionTypeBase[]>(resolve => {
resolve(guessProductTypes(inputValue));
});

return (
<div className="jp-EodagWidget-field">
<label className="jp-EodagWidget-input-name">
Product type
{label}
<div
style={{
marginTop: 10
Expand All @@ -153,7 +111,6 @@ class IntegrationReactSelect extends React.Component<IProps> {
classNamePrefix="jp-EodagWidget-select"
cacheOptions
defaultOptions={suggestions}
loadOptions={loadSuggestions}
components={listcomponents}
value={currentValue}
onChange={handleChange}
Expand Down
116 changes: 65 additions & 51 deletions src/FormComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,15 @@
UseFormReturn
} from 'react-hook-form';
import { showErrorMessage } from '@jupyterlab/apputils';
import { URLExt } from '@jupyterlab/coreutils';
import { ServerConnection } from '@jupyterlab/services';
import { map } from 'lodash';
import DatePicker from 'react-datepicker';
import 'react-datepicker/dist/react-datepicker.css';
import 'isomorphic-fetch';
import Autocomplete from './Autocomplete';
import { EODAG_SERVER_ADRESS } from './config';
import SearchService from './SearchService';
import { ChangeEvent } from 'react';
import MapExtentComponent from './MapExtentComponent';
import _ from 'lodash';

Check warning on line 23 in src/FormComponent.tsx

View workflow job for this annotation

GitHub Actions / build

'_' is defined but never used
import { IFormInput } from './types';
import {
CodiconOpenPreview,
Expand All @@ -36,6 +33,7 @@
} from './icones.js';
import ReactTooltip from 'react-tooltip';
import { ThreeDots } from 'react-loader-spinner';
import { useFetchData } from './hooks/useFetchData';

export interface IProps {
handleShowFeature: any;
Expand All @@ -44,10 +42,21 @@
isNotebookCreated: any;
commands: any;
}

export interface IOptionTypeBase {
[key: string]: any;
}

interface IProduct {
ID: string;
abstract: string;
}

interface IProvider {
provider: string;
description: string;
}

export const FormComponent: FC<IProps> = ({
handleShowFeature,
saveFormValues,
Expand All @@ -56,14 +65,16 @@
commands
}) => {
const [productTypes, setProductTypes] = useState<IOptionTypeBase[]>();
const [providers, setProviders] = useState<IOptionTypeBase[]>();
const defaultStartDate: Date = undefined;
const defaultEndDate: Date = undefined;
const [startDate, setStartDate] = useState(undefined);
const [endDate, setEndDate] = useState(undefined);
const [cloud, setCloud] = useState(100);
const [isLoadingSearch, setIsLoadingSearch] = useState(false);
const [openModal, setOpenModal] = useState(true);
const [selectValue, setSelectValue] = useState(null);
const [providersValue, setProvidersValue] = useState(null);
const [productTypesValue, setProductTypesValue] = useState(null);

const {
control,
Expand All @@ -81,53 +92,37 @@
});

useEffect(() => {
// Fetch product types
const _serverSettings = ServerConnection.makeSettings();
const _eodag_server = URLExt.join(
_serverSettings.baseUrl,
`${EODAG_SERVER_ADRESS}`
);
fetch(URLExt.join(_eodag_server, 'product-types/'), {
credentials: 'same-origin'
})
.then(response => {
if (response.status >= 400) {
showErrorMessage(
`Unable to contact the EODAG server. Are you sure the adress is ${_eodag_server}/ ?`,
{}
);
throw new Error('Bad response from server');
}
return response.json();
})
.then(products => {
const productTypes = map(products, product => ({
useFetchData<IProduct>({
queryParams: providersValue
? `product-types?provider=${providersValue}`
: 'product-types',

onSuccess: (products: IProduct[]) => {
const productTypeList: IOptionTypeBase[] = map(products, product => ({
value: product.ID,
label: product.ID,
description: product.abstract
}));
setProductTypes(productTypes);
})
.catch(() => {
showErrorMessage(
`Unable to contact the EODAG server. Are you sure the adress is ${_eodag_server}/ ?`,
{}
);
});
}, []);
setProductTypes(productTypeList);
}
});
}, [providersValue]);

// useEffect(
// () => {
// if (!_.isEmpty(errors)) {
// showErrorMessage(
// 'The following fields are required',
// _.keys(errors).join(', ')
// ).then(() => clearErrors());
// }
// },
// // useEffect is not triggered with only errors as dependency thus we need to list all its elements
// [errors]
// );
useEffect(() => {
useFetchData<IProvider>({
queryParams: productTypesValue
? `providers?product_type=${productTypesValue}`
: 'providers/',
onSuccess: (providers: IProvider[]) => {
const providersList: IOptionTypeBase[] = map(providers, provider => ({
value: provider.provider,
label: provider.provider,
description: provider.description
}));
setProviders(providersList);
}
});
}, [productTypesValue]);

const onSubmit: SubmitHandler<IFormInput> = data => {
if (!isNotebookCreated()) {
Expand Down Expand Up @@ -182,17 +177,36 @@
/>
</div>
<div className="jp-EodagWidget-field">
<Controller
name="providers"
control={control}
rules={{ required: true }}
render={({ field: { onChange, value } }) => (
<Autocomplete
label="Provider"
url="providers?product_type"
suggestions={providers}
value={value}
handleChange={(e: IOptionTypeBase | null) => {
onChange(e?.value);
setProvidersValue(e?.value);
}}
/>
)}
/>
<Controller
name="productType"
control={control}
rules={{ required: true }}
render={({ field: { onChange, value } }) => (
<Autocomplete
label="Product Types"
url="product-types?provider"
suggestions={productTypes}
value={value}
handleChange={(e: IOptionTypeBase | null) => {
onChange(e?.value);
setSelectValue(e?.value);
setProductTypesValue(e?.value);
}}
/>
)}
Expand Down Expand Up @@ -312,7 +326,7 @@
type="submit"
color="primary"
className={
!selectValue
!productTypesValue
? 'jp-EodagWidget-buttons-button jp-EodagWidget-buttons-button__disabled'
: 'jp-EodagWidget-buttons-button'
}
Expand All @@ -327,7 +341,7 @@
<br />
Results
</p>
{!selectValue && (
{!productTypesValue && (
<ReactTooltip
id="btn-preview-results"
className="jp-Eodag-tooltip"
Expand All @@ -343,7 +357,7 @@
type="submit"
color="primary"
className={
!selectValue
!productTypesValue
? 'jp-EodagWidget-buttons-button jp-EodagWidget-buttons-button__disabled'
: 'jp-EodagWidget-buttons-button'
}
Expand All @@ -358,7 +372,7 @@
<br />
Code
</p>
{!selectValue && (
{!productTypesValue && (
<ReactTooltip
id="btn-generate-value"
className="jp-Eodag-tooltip"
Expand Down Expand Up @@ -403,7 +417,7 @@
}: Partial<UseFormReturn<IFormInput>>) => {
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
const { fields, append, remove, update } = useFieldArray({

Check warning on line 420 in src/FormComponent.tsx

View workflow job for this annotation

GitHub Actions / build

'update' is assigned a value but never used
control,
name: 'additionnalParameters'
});
Expand Down
Loading
Loading