Skip to content

Feat(Popup): Use external data to find categorical labels#185

Open
arnaudfnr wants to merge 10 commits into
mainfrom
arnaudfnr/177-use_external_data_for_labels
Open

Feat(Popup): Use external data to find categorical labels#185
arnaudfnr wants to merge 10 commits into
mainfrom
arnaudfnr/177-use_external_data_for_labels

Conversation

@arnaudfnr

@arnaudfnr arnaudfnr commented Jul 5, 2026

Copy link
Copy Markdown
Collaborator

WHAT CHANGES

Backend

  • Add endpoint to return the content of a list of catalog resources
  • Update Forest Inventory external data with latest update from Cathalijne

Frontend

  • Move Fallback renderer component to its own module so it can be reused, + improve design
  • Add api client methods to fetch external data
  • Modify popup rendered to accept Promisefunction for external data
  • Add ErrorBoundary & Suspense for Popup rendering, because now it needs to load external data (maybe we could make the load fail non blocking)
  • Use external data to find labels of forest name, tree species & taxons in forest inventory

=> No labels have been provided for socio eco data yet

Capture.video.du.2026-07-05.23-00-51.mp4

@arnaudfnr arnaudfnr linked an issue Jul 5, 2026 that may be closed by this pull request
@arnaudfnr arnaudfnr force-pushed the arnaudfnr/177-use_external_data_for_labels branch from fccda2b to 3a176a2 Compare July 5, 2026 21:21
@arnaudfnr arnaudfnr marked this pull request as ready for review July 5, 2026 21:24
try {
const isValid = await verifyToken(token);
if (isValid) {
setToken(storedToken);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Good catch 🤦

Comment thread backend/all4trees/views.py Outdated
Comment on lines +30 to +31
if not request.user.has_perm("users.view_data"):
return Response(status=status.HTTP_403_FORBIDDEN)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

We can define a custom class CanViewData follow this practice: https://www.django-rest-framework.org/api-guide/permissions/#setting-the-permission-policy. Permissions classes would be "IsAuthenticated & CanViewData"

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I know but I went for the less code / quicker option here 😄

Comment thread backend/all4trees/views.py Outdated
@api_view(["POST"])
@permission_classes([IsAuthenticated])
def resource_list_view(request, layer_id):
# authorization: ensure user has the custom add_data permission

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
# authorization: ensure user has the custom add_data permission
# authorization: ensure user has the custom view_data permission

Comment thread backend/all4trees/views.py Outdated

resources_payload = {}
for resource_name in resource_list:
target_path = catalog_path / f"{layer_id}" / f"{resource_name}.parquet"

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Shall we check layer id is defined or an existing path ?

data={data.treeDiversity.relative_abundance}
metadata={metadata}
externalData={metadata}
proj={rawData.projet}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Can we keep full-verbose naming for proops ? "project" instead of "proj" ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

alright

Comment on lines +13 to +24
// t must be passed to the fallback render function because the error boundary fallback component cannot call hooks like useTranslation
// See https://react.dev/warnings/invalid-hook-call-warning
// > 🔴 Do not call Hooks in class components.
// while ErrorBoundary is a class component: https://github.com/bvaughn/react-error-boundary/blob/main/lib/components/ErrorBoundary.tsx#L45
export function getFallbackRender({
retry,
t,
}: {
retry?: () => void;
t: TFunction<"common", undefined>;
}) {
function FallbackRender({ error }: FallbackProps) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

You can just extract the JSX into a Functional component, no ?

const FallbackRender= (...) => {
  const { t } = useTranslation();
  ...
}

<ErrorBoundary
      fallbackRender={(...) => <FallbackRender ... />}

```

You can't use hooks in class components but you can use Functional Components though

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

maybe 🤷 I just reused the code of @severo from #175 and I did not catch that

/>
</Suspense>
</ErrorBoundary>
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Comments on the behavior:

  • Now people have to be logged in to see data => Can't share data to the public now, so, it wouldn't make sense to be able to land on the map view
  • IMO, the boundary should be restricted to the data slice it is related to. Here, it's to fetch the label only, right ? This should be the data slice wrapped in the Boundary.
  • But then comes again the question about: what is pubicly accessible, what should be hidden, what to dislay in case of failure (for public access) ?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Well your comments are absolutely right.
In the new final data, there is a new field "conf" for confidentiality that I did not integrate yet.

So the behavior will be :

  • When a user is not connected, they will see all data publicly available (conf=1 , yes that's illogic)
  • External data won't be protected (to confirm with Cathalijne, so yes the current behavior is going to change) so even public users will see the labels. But this requires to think about the backend a little bit here, that's why I protected the resources for now. We can also open it for the time we think about that.
  • You are right, maybe we can just wrap the indicators that require the promise inside the boundary. We could also make a silent fail with a fallback to values. I think I just wanted to play with the ErroBoundary stuff after having seen it from @severo ^^

Comment on lines +25 to +42
// Retrieve external data before rendering popup
const [reloadKey, setReloadKey] = useState(0);
const externalDataPromise = useMemo(
() =>
fetchData({
force: reloadKey > 0,
promiseFunc,
}),
[reloadKey, promiseFunc],
);

const retry = useCallback(() => {
setReloadKey((k) => k + 1);
}, []);
const fallbackRender = useMemo(
() => getFallbackRender({ retry, t }),
[retry, t],
);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

As far as we used it in my company, so far, you pass the retry function to the FallbackRender, it contains a reload button, and that's all : on demand refetch from the error boundary. No need for state, memoization, callbacks, cache.

Interally, we can do a retry on fail for 3 times for instance (it's just a loop while getting error. But things can be remain simple

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

I see. Maybe we could improve that later, it's a bit off of what I'm trying to do here and as I said in the previous command it's basically a copy and paste of @severo work, can we have the debate on mattermost it it's important to you ?


return (
<ErrorBoundary
fallbackRender={fallbackRender}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

The fallback render component should have the same height limitation as provided in childrenProps.className

"undefined": "not found"
},
"error": {
"pleaseLogon": "Please sign in",

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
"pleaseLogon": "Please sign in",
"pleaseLogin": "Please sign in",

(french key)

@david-bretaud-dev david-bretaud-dev left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

A couple of improvements we can bring to the code.

The main thing that struck me though was the need to be logged in to see the full popup -not just the label-
(Since we have access to the whole style.json anyway, this limitation does not rely exist)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Chore(Webapp): Use labels in external data instead of form data

2 participants