Skip to content

Commit 15aaf51

Browse files
committed
[#3688] PR feedback
1 parent 7678f19 commit 15aaf51

File tree

16 files changed

+309
-119
lines changed

16 files changed

+309
-119
lines changed

docker/docker-compose.objecttypes.yml docker/docker-compose.objects-apis.yml

+4-5
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,18 @@ version: '3'
22

33
services:
44
db:
5-
image: postgres
5+
image: postgres:${PG_VERSION:-14}
66
environment:
77
- POSTGRES_USER=${DB_USER:-objecttypes}
88
- POSTGRES_PASSWORD=${DB_PASSWORD:-objecttypes}
99

10-
web:
11-
image: maykinmedia/objecttypes-api
10+
objecttypes-web:
11+
image: maykinmedia/objecttypes-api:${OBJECTTYPES_VERSION:-2.1.1}
1212
environment:
1313
- DJANGO_SETTINGS_MODULE=objecttypes.conf.docker
1414
- SECRET_KEY=${SECRET_KEY:-fgv=c0hz&tl*8*3m3893@m+1pstrvidc9e^5@fpspmg%cy$15d}
1515
- ALLOWED_HOSTS=*
16-
- UWSGI_PORT=8001
1716
ports:
18-
- 8001:8001
17+
- 8001:8000
1918
depends_on:
2019
- db

docker/objects-apis/README.md

+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
# Objects APIs
2+
3+
The `docker-compose.objects-apis.yml` compose file is available to run an instance of the Objects and Objecttypes API.
4+
5+
(For now, only Objecttypes is available).
6+
7+
## docker compose
8+
9+
Start an instance in your local environment from the parent directory:
10+
11+
```bash
12+
docker compose -f docker-compose.objects-apis.yml up -d
13+
```
14+
15+
Create a super user:
16+
17+
```bash
18+
docker compose -f docker-compose.objects-apis.yml exec objecttypes-web src/manage.py createsuperuser
19+
```
20+
21+
This brings up Objecttypes, the admin interface is accessible at http://localhost:8001/admin/.
22+
23+
## Load fixtures
24+
25+
Before re-recording the related VCR tests, you must load some fixtures:
26+
27+
```bash
28+
cat objects-apis/fixtures/objecttypes_api_fixtures.json | docker compose -f docker-compose.objects-apis.yml exec -T objecttypes-web src/manage.py loaddata --format=json -
29+
```

docker/objecttypes/README.md

-31
This file was deleted.

src/openapi.yaml

+12-2
Original file line numberDiff line numberDiff line change
@@ -3804,7 +3804,10 @@ paths:
38043804
/api/v2/registration/plugins/objects-api/object-types:
38053805
get:
38063806
operationId: registration_plugins_objects_api_object_types_list
3807-
description: List the available Objecttypes.
3807+
description: |-
3808+
List the available Objecttypes.
3809+
3810+
Note that the response data is essentially proxied from the configured Objecttypes API.
38083811
tags:
38093812
- registration
38103813
security:
@@ -3830,7 +3833,10 @@ paths:
38303833
/api/v2/registration/plugins/objects-api/object-types/{submission_uuid}/versions:
38313834
get:
38323835
operationId: registration_plugins_objects_api_object_types_versions_list
3833-
description: List the available versions for an Objecttype.
3836+
description: |-
3837+
List the available versions for an Objecttype.
3838+
3839+
Note that the response data is essentially proxied from the configured Objecttypes API.
38343840
parameters:
38353841
- in: path
38363842
name: submission_uuid
@@ -8498,7 +8504,11 @@ components:
84988504
version:
84998505
type: integer
85008506
title: Integer version of the Objecttype.
8507+
status:
8508+
type: string
8509+
title: Status of the object type version
85018510
required:
8511+
- status
85028512
- version
85038513
PaginatedFormDefinitionList:
85048514
type: object

src/openforms/contrib/objects_api/clients/objecttypes.py

+1-8
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,10 @@
1-
from typing import Any, Literal, TypeAlias
1+
from typing import Any
22
from uuid import UUID
33

44
from zgw_consumers.nlx import NLXClient
55

66
from openforms.utils.api_clients import PaginatedResponseData, pagination_helper
77

8-
DataClassification: TypeAlias = Literal[
9-
"confidential", "intern", "open", "strictly_confidential"
10-
]
11-
128

139
class ObjecttypesClient(NLXClient):
1410

@@ -38,13 +34,10 @@ def _get_paginated(
3834

3935
def list_objecttypes(
4036
self,
41-
data_classification: DataClassification | None = None,
4237
page: int | None = None,
4338
page_size: int | None = None,
4439
) -> list[dict[str, Any]]:
4540
query_params = {}
46-
if data_classification is not None:
47-
query_params["dataClassification"] = data_classification
4841

4942
return self._get_paginated(
5043
"objecttypes", page=page, page_size=page_size, query_params=query_params

src/openforms/js/components/admin/form_design/registrations/objectsapi/ObjectsApiOptionsFormFields.js

+28-23
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
import {produce} from 'immer';
2-
import React, {useContext, useMemo, useState} from 'react';
2+
import React, {useContext, useState} from 'react';
33
import {useIntl} from 'react-intl';
44
import useAsync from 'react-use/esm/useAsync';
55

6-
import Loader from 'components/admin/Loader';
76
import {CustomFieldTemplate} from 'components/admin/RJSFWrapper';
87
import {
98
REGISTRATION_OBJECTTYPES_ENDPOINT,
@@ -26,6 +25,15 @@ const Wrapper = ({children}) => (
2625
</form>
2726
);
2827

28+
const getObjecttypeVersionsEndpoint = objecttype => {
29+
const bits = [
30+
'/api/v2/registration/plugins/objects-api/object-types',
31+
encodeURIComponent(objecttype.uuid),
32+
'versions',
33+
];
34+
return bits.join('/');
35+
};
36+
2937
const ObjectsApiOptionsFormFields = ({index, name, schema, formData, onChange}) => {
3038
const intl = useIntl();
3139
const validationErrors = useContext(ValidationErrorContext);
@@ -48,10 +56,8 @@ const ObjectsApiOptionsFormFields = ({index, name, schema, formData, onChange})
4856

4957
// For existing registration options where the URL might not be valid
5058
// will default to a textinput in that case
51-
const unknownObjecttype = useMemo(
52-
() => objecttype && !availableObjecttypes.map(o => o.url).includes(objecttype),
53-
[availableObjecttypes, objecttype]
54-
);
59+
const isUnknownObjecttype =
60+
objecttype && availableObjecttypes.find(o => o.url === objecttype) === undefined;
5561

5662
const onFieldChange = event => {
5763
const {name, value} = event.target;
@@ -78,25 +84,24 @@ const ObjectsApiOptionsFormFields = ({index, name, schema, formData, onChange})
7884

7985
const {loading: objecttypeVersionLoading, error: objecttypeVersionLoadingError} =
8086
useAsync(async () => {
81-
if (!objecttype) return;
87+
if (!objecttype) {
88+
setAvailableObjecttypeVersions([]);
89+
return;
90+
}
8291

83-
const response = await get(
84-
REGISTRATION_OBJECTTYPE_VERSIONS_ENDPOINT.replace(
85-
'{objecttypeUuid}',
86-
availableObjecttypes.find(o => o.url === objecttype).uuid
87-
)
92+
const url = getObjecttypeVersionsEndpoint(
93+
availableObjecttypes.find(o => o.url === objecttype)
8894
);
95+
const response = await get(url);
96+
8997
if (!response.ok) {
9098
throw new Error('Error when loading objecttype versions');
9199
}
92100

93101
setAvailableObjecttypeVersions(response.data);
94102
}, [objecttype]);
95103

96-
const hasApiError = useMemo(
97-
() => objecttypesLoadingError || objecttypeVersionLoadingError,
98-
[objecttypesLoadingError, objecttypeVersionLoadingError]
99-
);
104+
const hasApiError = objecttypesLoadingError || objecttypeVersionLoadingError;
100105

101106
return (
102107
<Wrapper>
@@ -115,13 +120,13 @@ const ObjectsApiOptionsFormFields = ({index, name, schema, formData, onChange})
115120
errors={buildErrorsComponent('objecttype')}
116121
displayLabel
117122
>
118-
{unknownObjecttype || hasApiError ? (
123+
{isUnknownObjecttype || hasApiError ? (
119124
<TextInput
120125
id="root_objecttype"
121126
name="objecttype"
122127
value={objecttype}
123128
onChange={onFieldChange}
124-
allowBlank={true}
129+
allowBlank
125130
/>
126131
) : (
127132
<Select
@@ -130,11 +135,10 @@ const ObjectsApiOptionsFormFields = ({index, name, schema, formData, onChange})
130135
choices={
131136
objecttypesLoading
132137
? LOADING_OPTION
133-
: availableObjecttypes.map(ot => [ot.url, `${ot.name} (${ot.uuid})`])
138+
: availableObjecttypes.map(ot => [ot.url, `${ot.name}`])
134139
}
135140
value={objecttype}
136141
onChange={onFieldChange}
137-
allowBlank={true}
138142
/>
139143
)}
140144
</CustomFieldTemplate>
@@ -152,7 +156,7 @@ const ObjectsApiOptionsFormFields = ({index, name, schema, formData, onChange})
152156
errors={buildErrorsComponent('objecttypeVersion')}
153157
displayLabel
154158
>
155-
{unknownObjecttype || hasApiError ? (
159+
{isUnknownObjecttype || hasApiError ? (
156160
<NumberInput
157161
id="root_objecttypeVersion"
158162
name="objecttypeVersion"
@@ -167,11 +171,12 @@ const ObjectsApiOptionsFormFields = ({index, name, schema, formData, onChange})
167171
choices={
168172
objecttypeVersionLoading
169173
? LOADING_OPTION
170-
: availableObjecttypeVersions.map(otv => [otv.version, otv.version])
174+
: availableObjecttypeVersions
175+
.sort((v1, v2) => v2.version - v1.version)
176+
.map(otv => [otv.version, otv.version])
171177
}
172178
value={objecttypeVersion}
173179
onChange={onFieldChange}
174-
allowBlank={true}
175180
/>
176181
)}
177182
</CustomFieldTemplate>

src/openforms/js/components/admin/form_design/registrations/objectsapi/ObjectsApiOptionsFormFields.stories.js

+7-1
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,14 @@ export default {
4747
name: 'Tree',
4848
namePlural: 'Trees',
4949
},
50+
{
51+
url: 'https://objecttypen.nl/api/v1/objecttypes/2c77babf-a967-4057-9969-0200320d23f2',
52+
uuid: '2c77babf-a967-4057-9969-0200320d23f2',
53+
name: 'Person',
54+
namePlural: 'Persons',
55+
},
5056
]),
51-
mockObjecttypeVersionsGet('2c77babf-a967-4057-9969-0200320d23f1', [{version: 1}]),
57+
mockObjecttypeVersionsGet([{version: 1}]),
5258
],
5359
},
5460
},

src/openforms/js/components/admin/form_design/registrations/objectsapi/mocks.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ export const mockObjecttypesGet = objecttypes =>
77
return res(ctx.json(objecttypes));
88
});
99

10-
export const mockObjecttypeVersionsGet = (objecttypeUuid, versions) =>
10+
export const mockObjecttypeVersionsGet = versions =>
1111
rest.get(
12-
`${BASE_URL}/api/v2/registration/plugins/objects-api/object-types/${objecttypeUuid}/versions`,
12+
`${BASE_URL}/api/v2/registration/plugins/objects-api/object-types/:uuid/versions`,
1313
(req, res, ctx) => {
1414
return res(ctx.json(versions));
1515
}

src/openforms/js/components/admin/form_design/registrations/objectsapi/utils.js

+3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
import React from 'react';
22

3+
// TODO This is duplicated from the ZGW registration, but will be cleaned up
4+
// with the backend UI refactor.
5+
36
const getFieldErrors = (name, index, errors, field) => {
47
const errorMessages = [];
58

src/openforms/registrations/contrib/objects_api/api/serializers.py

+1
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ class ObjecttypeVersionSerializer(serializers.Serializer):
1919
version = serializers.IntegerField(
2020
label=_("Integer version of the Objecttype."),
2121
)
22+
status = serializers.CharField(label=_("Status of the object type version"))

src/openforms/registrations/contrib/objects_api/api/views.py

+4
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
class ObjecttypesListView(ListMixin, views.APIView):
1818
"""
1919
List the available Objecttypes.
20+
21+
Note that the response data is essentially proxied from the configured Objecttypes API.
2022
"""
2123

2224
authentication_classes = (authentication.SessionAuthentication,)
@@ -36,6 +38,8 @@ def get_objects(self) -> list[dict[str, Any]]:
3638
class ObjecttypeVersionsListView(ListMixin, views.APIView):
3739
"""
3840
List the available versions for an Objecttype.
41+
42+
Note that the response data is essentially proxied from the configured Objecttypes API.
3943
"""
4044

4145
authentication_classes = (authentication.SessionAuthentication,)

src/openforms/registrations/contrib/objects_api/tests/files/vcr_cassettes/ObjecttypesClientTest/ObjecttypesClientTest.test_list_objecttypes_data_classification.yaml

-36
This file was deleted.

0 commit comments

Comments
 (0)