@eeacms/volto-cca-policy 1.0.1 → 1.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. package/.github/workflows/betterleaks.yml +133 -0
  2. package/.gitleaks.toml +89 -0
  3. package/CHANGELOG.md +262 -1
  4. package/README.md +59 -0
  5. package/RELEASE.md +1 -1
  6. package/jest-addon.config.js +7 -3
  7. package/package.json +3 -2
  8. package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueCardItem.jsx +228 -0
  9. package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueCardItem.test.jsx +167 -0
  10. package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueContentView.jsx +189 -0
  11. package/src/components/Search/NavigatorCatalogue/NavigatorCatalogueMapView.jsx +11 -0
  12. package/src/components/Search/NavigatorCatalogue/utils.js +101 -0
  13. package/src/components/Search/NavigatorCatalogue/utils.test.js +132 -0
  14. package/src/components/Search/NavigatorGuide/NavigatorGuideContentView.jsx +409 -0
  15. package/src/components/Search/NavigatorGuide/NavigatorGuideLayout.jsx +8 -0
  16. package/src/components/index.js +2 -0
  17. package/src/components/manage/Blocks/CollectionStatistics/CollectionStatsView.test.jsx +2 -0
  18. package/src/components/theme/CompareTools/CompareToolsPanel.jsx +151 -0
  19. package/src/components/theme/CompareTools/CompareToolsPanel.test.jsx +96 -0
  20. package/src/components/theme/CompareTools/CompareToolsView.jsx +468 -0
  21. package/src/components/theme/CompareTools/utils.js +111 -0
  22. package/src/components/theme/CompareTools/utils.test.jsx +217 -0
  23. package/src/components/theme/Views/ExtendedToolView.jsx +409 -0
  24. package/src/components/theme/Views/ExtendedToolView.test.jsx +436 -0
  25. package/src/constants.js +1 -0
  26. package/src/customizations/@plone-collective/volto-rss-provider/express-middleware.js +1 -1
  27. package/src/customizations/volto/components/theme/View/LinkView.jsx +1 -1
  28. package/src/customizations/volto/reducers/breadcrumbs/breadcrumbs.js +1 -1
  29. package/src/customizations/volto/server.jsx +1 -1
  30. package/src/helpers/Utils.jsx +29 -0
  31. package/src/helpers/index.js +3 -0
  32. package/src/index.js +31 -2
  33. package/src/search/index.js +6 -0
  34. package/src/search/navigator_catalogue/config.js +89 -0
  35. package/src/search/navigator_catalogue/facets.js +86 -0
  36. package/src/search/navigator_catalogue/views.js +28 -0
  37. package/src/search/navigator_guide/config.js +70 -0
  38. package/src/search/navigator_guide/facets.js +31 -0
  39. package/src/search/navigator_guide/guideSteps.js +93 -0
  40. package/src/slate-styles.less +4 -0
  41. package/src/state.js +1 -0
  42. package/theme/elements/button.overrides +0 -11
  43. package/theme/elements/label.overrides +15 -0
  44. package/theme/globals/blocks.less +3 -2
  45. package/theme/globals/navigator.less +967 -0
  46. package/theme/globals/site.overrides +5 -0
  47. package/theme/tokens/colors.less +2 -0
@@ -0,0 +1,217 @@
1
+ import React from 'react';
2
+ import { fireEvent, render, screen } from '@testing-library/react';
3
+ import '@testing-library/jest-dom';
4
+ import { Provider as JotaiProvider } from 'jotai';
5
+ import { applyConfigurationSchema, rebind } from '@eeacms/search';
6
+ import runRequest from '@eeacms/search/lib/runRequest';
7
+ import {
8
+ MAX_COMPARE_TOOLS,
9
+ fetchResultsByUid,
10
+ getCompareLocation,
11
+ getCompareToolTitle,
12
+ getCompareToolUid,
13
+ getPathname,
14
+ useCompareTools,
15
+ } from './utils';
16
+
17
+ jest.mock('@eeacms/search', () => ({
18
+ applyConfigurationSchema: jest.fn((config) => config),
19
+ rebind: jest.fn((config) => config),
20
+ }));
21
+
22
+ jest.mock('@eeacms/search/lib/runRequest', () => jest.fn());
23
+
24
+ jest.mock('@plone/volto/helpers/Url/Url', () => ({
25
+ flattenToAppURL: (url) => url.replace('https://example.com', ''),
26
+ }));
27
+
28
+ const CompareHarness = ({ tool }) => {
29
+ const { isLimitReached, isSelected, setSelected, toggle } =
30
+ useCompareTools(tool);
31
+
32
+ return (
33
+ <>
34
+ <span data-testid="selected">{String(isSelected)}</span>
35
+ <span data-testid="limit">{String(isLimitReached)}</span>
36
+ <button type="button" onClick={toggle}>
37
+ Toggle
38
+ </button>
39
+ <button type="button" onClick={() => setSelected(true)}>
40
+ Select
41
+ </button>
42
+ <button type="button" onClick={() => setSelected(false)}>
43
+ Remove
44
+ </button>
45
+ </>
46
+ );
47
+ };
48
+
49
+ const renderCompareHarness = (tool, initialTools = []) => {
50
+ window.localStorage.setItem(
51
+ 'cca-compare-tools',
52
+ JSON.stringify(initialTools),
53
+ );
54
+
55
+ return render(
56
+ <JotaiProvider>
57
+ <CompareHarness tool={tool} />
58
+ </JotaiProvider>,
59
+ );
60
+ };
61
+
62
+ describe('Compare Tools utilities', () => {
63
+ beforeEach(() => {
64
+ jest.clearAllMocks();
65
+ window.localStorage.clear();
66
+ });
67
+
68
+ it('resolves comparison identifiers and titles from supported shapes', () => {
69
+ expect(getCompareToolUid({ cca_uid: { raw: 'cca-id' } })).toBe('cca-id');
70
+ expect(getCompareToolUid({ UID: 'plone-id' })).toBe('plone-id');
71
+ expect(getCompareToolUid({ _result: { cca_uid: { raw: 'raw-id' } } })).toBe(
72
+ 'raw-id',
73
+ );
74
+ expect(getCompareToolUid({})).toBe('');
75
+ expect(getCompareToolTitle({ title: 'Tool title' })).toBe('Tool title');
76
+ expect(getCompareToolTitle({})).toBe('');
77
+ });
78
+
79
+ it('normalizes paths and removes query strings and hashes', () => {
80
+ expect(getPathname()).toBe('');
81
+ expect(getPathname('https://example.com/en/tools/?a=1#result')).toBe(
82
+ '/en/tools',
83
+ );
84
+ expect(getPathname('/en/tools')).toBe('/en/tools');
85
+ });
86
+
87
+ it('builds a localized comparison location with at most four tools', () => {
88
+ const tools = [
89
+ { uid: 'one' },
90
+ { uid: '' },
91
+ { uid: 'two' },
92
+ { uid: 'three' },
93
+ { uid: 'four' },
94
+ { uid: 'five' },
95
+ ];
96
+
97
+ expect(
98
+ getCompareLocation(
99
+ tools,
100
+ { landingPageURL: '/en/navigator/tool-catalogue' },
101
+ '/en/navigator/tool-catalogue?q=test',
102
+ 'ro',
103
+ ),
104
+ ).toEqual({
105
+ pathname: '/ro/navigator/compare',
106
+ search: '?uid=one&uid=two&uid=three',
107
+ state: { returnURL: '/en/navigator/tool-catalogue?q=test' },
108
+ });
109
+ expect(MAX_COMPARE_TOOLS).toBe(4);
110
+ expect(getCompareLocation([], {}, undefined)).toEqual({
111
+ pathname: '/en/navigator/compare',
112
+ search: '',
113
+ state: { returnURL: undefined },
114
+ });
115
+ });
116
+
117
+ it('fetches and converts matching search results', async () => {
118
+ class ResultModel {
119
+ constructor(hit, config) {
120
+ this.hit = hit;
121
+ this.config = config;
122
+ }
123
+ }
124
+ const appConfig = {
125
+ index_name: 'data_searchui',
126
+ resultItemModel: { factory: 'resultModel' },
127
+ };
128
+ const registry = {
129
+ searchui: { navigatorCatalogueSearch: appConfig },
130
+ resolve: { resultModel: ResultModel },
131
+ };
132
+ runRequest.mockResolvedValue({
133
+ body: { hits: { hits: [{ _id: 'one' }, { _id: 'two' }] } },
134
+ });
135
+
136
+ const results = await fetchResultsByUid(['one', 'two'], registry);
137
+
138
+ expect(rebind).toHaveBeenCalledWith(appConfig);
139
+ expect(applyConfigurationSchema).toHaveBeenCalledWith(appConfig);
140
+ expect(runRequest).toHaveBeenCalledWith(
141
+ {
142
+ index: 'data_searchui',
143
+ size: 2,
144
+ query: {
145
+ bool: {
146
+ minimum_should_match: 1,
147
+ should: [
148
+ { terms: { 'cca_uid.keyword': ['one', 'two'] } },
149
+ { terms: { cca_uid: ['one', 'two'] } },
150
+ ],
151
+ },
152
+ },
153
+ },
154
+ appConfig,
155
+ );
156
+ expect(results).toHaveLength(2);
157
+ expect(results[0]).toBeInstanceOf(ResultModel);
158
+ });
159
+
160
+ it('handles missing hits and configurations without an index', async () => {
161
+ const registry = {
162
+ searchui: {
163
+ navigatorCatalogueSearch: {
164
+ resultItemModel: { factory: 'resultModel' },
165
+ },
166
+ },
167
+ resolve: { resultModel: class ResultModel {} },
168
+ };
169
+ runRequest.mockResolvedValue({});
170
+
171
+ await expect(fetchResultsByUid(['one'], registry)).resolves.toEqual([]);
172
+ expect(runRequest.mock.calls[0][0]).not.toHaveProperty('index');
173
+ });
174
+
175
+ it('adds, toggles, and removes a comparison tool', () => {
176
+ renderCompareHarness({ uid: 'one', title: 'Tool one' });
177
+
178
+ expect(screen.getByTestId('selected')).toHaveTextContent('false');
179
+ expect(screen.getByTestId('limit')).toHaveTextContent('false');
180
+
181
+ fireEvent.click(screen.getByText('Toggle'));
182
+ expect(screen.getByTestId('selected')).toHaveTextContent('true');
183
+ expect(
184
+ JSON.parse(window.localStorage.getItem('cca-compare-tools')),
185
+ ).toEqual([{ uid: 'one', title: 'Tool one' }]);
186
+
187
+ fireEvent.click(screen.getByText('Select'));
188
+ expect(screen.getByTestId('selected')).toHaveTextContent('true');
189
+
190
+ fireEvent.click(screen.getByText('Remove'));
191
+ expect(screen.getByTestId('selected')).toHaveTextContent('false');
192
+ expect(
193
+ JSON.parse(window.localStorage.getItem('cca-compare-tools')),
194
+ ).toEqual([]);
195
+ });
196
+
197
+ it('does not add tools without an identifier', () => {
198
+ renderCompareHarness({ title: 'Missing UID' });
199
+
200
+ fireEvent.click(screen.getByText('Select'));
201
+ expect(screen.getByTestId('selected')).toHaveTextContent('false');
202
+ });
203
+
204
+ it('enforces the comparison limit', () => {
205
+ const initialTools = Array.from(
206
+ { length: MAX_COMPARE_TOOLS },
207
+ (_, index) => ({
208
+ uid: `tool-${index}`,
209
+ }),
210
+ );
211
+ renderCompareHarness({ uid: 'extra' }, initialTools);
212
+
213
+ expect(screen.getByTestId('limit')).toHaveTextContent('true');
214
+ fireEvent.click(screen.getByText('Select'));
215
+ expect(screen.getByTestId('selected')).toHaveTextContent('false');
216
+ });
217
+ });
@@ -0,0 +1,409 @@
1
+ import { Button, Container, Grid, Icon } from 'semantic-ui-react';
2
+ import {
3
+ CompareToolsPanel,
4
+ PortalMessage,
5
+ } from '@eeacms/volto-cca-policy/components';
6
+ import {
7
+ HTMLField,
8
+ TextField,
9
+ BooleanField,
10
+ VocabularyField,
11
+ ContentMetadata,
12
+ ItemLogo,
13
+ DocumentsList,
14
+ } from '@eeacms/volto-cca-policy/helpers';
15
+ import { defineMessages, useIntl } from 'react-intl';
16
+ import config from '@plone/volto/registry';
17
+ import { useCompareTools } from '../CompareTools/utils';
18
+ import { formatFunctionalityScore } from '../../Search/NavigatorCatalogue/utils';
19
+
20
+ const ExtendedToolView = (props) => {
21
+ const { content = {} } = props;
22
+ const {
23
+ title = '',
24
+ acronym = '',
25
+ long_description,
26
+ tool_provider,
27
+ public_private_mode,
28
+ hyperlink,
29
+ description,
30
+ coder_1,
31
+ coder_2,
32
+ only_interactive_support_tool,
33
+ adaptation_cycle_step,
34
+ updating_cycle_of_the_tool,
35
+ language_accessibility,
36
+ free_access,
37
+ intended_user_groups,
38
+ place_of_implementation,
39
+ type_of_data,
40
+ data_sources,
41
+ license_status,
42
+ user_support_provisions,
43
+ tool_validation_use,
44
+ number_of_users_tool,
45
+ tool_provider_mode,
46
+ adaptation_support_cycle_step,
47
+ tool_available_english,
48
+ tool_available_language,
49
+ type_of_outputs,
50
+ temporality_of_data,
51
+ spatial_resolution,
52
+ underlying_data_maintenance,
53
+ // nature_based_solution,
54
+ // just_resilience,
55
+ // cost_benefit_ratio,
56
+ accessibility_and_usability,
57
+ functionality,
58
+ strengths_and_possible_limitations,
59
+ } = content;
60
+
61
+ const availableLanguageValues = [];
62
+ if (tool_available_english) {
63
+ availableLanguageValues.push('English');
64
+ }
65
+ if (tool_available_language) {
66
+ availableLanguageValues.push(tool_available_language);
67
+ }
68
+ const availableLanguageText = availableLanguageValues.join(', ');
69
+ const hasHyperlink = Boolean(hyperlink && hyperlink.length > 0);
70
+ const hasCompareTool = Boolean(content.UID);
71
+
72
+ const item_title = acronym ? title + ' (' + acronym + ')' : title;
73
+ const compareTool = {
74
+ uid: content.UID,
75
+ title,
76
+ href: content['@id'],
77
+ };
78
+ const { isSelected, isLimitReached, toggle } = useCompareTools(compareTool);
79
+
80
+ const messages = defineMessages({
81
+ yes: { id: 'YES', defaultMessage: 'YES' },
82
+ no: { id: 'NO', defaultMessage: 'NO' },
83
+ intended_user_groups: {
84
+ id: 'Intended User Groups',
85
+ defaultMessage: 'Intended User Groups',
86
+ },
87
+ tool_provider: { id: 'Tool provider', defaultMessage: 'Tool provider' },
88
+ only_interactive_support_tool: {
89
+ id: 'Only online interactive support tool',
90
+ defaultMessage: 'Only online interactive support tool',
91
+ },
92
+ adaptation_cycle_step: {
93
+ id: 'Supports ≥1 adaptation cycle step',
94
+ defaultMessage: 'Supports ≥1 adaptation cycle step',
95
+ },
96
+ updating_cycle_of_the_tool: {
97
+ id: 'Updating cycle of the tool',
98
+ defaultMessage: 'Updating cycle of the tool',
99
+ },
100
+ language_accessibility: {
101
+ id: 'Language Accessibility',
102
+ defaultMessage: 'Language Accessibility',
103
+ },
104
+ free_access: {
105
+ id: 'Free [full or core functionality] access',
106
+ defaultMessage: 'Free [full or core functionality] access',
107
+ },
108
+ place_of_implementation: {
109
+ id: 'Place of implementation',
110
+ defaultMessage: 'Place of implementation',
111
+ },
112
+ type_of_data: { id: 'Type of data', defaultMessage: 'Type of data' },
113
+ data_sources: { id: 'Data sources', defaultMessage: 'Data sources' },
114
+ license_status: { id: 'License status', defaultMessage: 'License status' },
115
+ user_support_provisions: {
116
+ id: 'User support provisions',
117
+ defaultMessage: 'User support provisions',
118
+ },
119
+ tool_validation_use: {
120
+ id: 'Tool validation use',
121
+ defaultMessage: 'Tool validation use',
122
+ },
123
+ number_of_users_tool: {
124
+ id: 'Number of users / uptake',
125
+ defaultMessage: 'Number of users / uptake',
126
+ },
127
+ tool_provider_mode: {
128
+ id: 'Tool provider',
129
+ defaultMessage: 'Tool provider',
130
+ },
131
+ adaptation_support_cycle_step: {
132
+ id: 'Adaptation Support Cycle Step',
133
+ defaultMessage: 'Adaptation Support Cycle Step',
134
+ },
135
+ tool_available_language: {
136
+ id: 'Available language',
137
+ defaultMessage: 'Available language',
138
+ },
139
+ type_of_outputs: {
140
+ id: 'Type of outputs',
141
+ defaultMessage: 'Type of outputs',
142
+ },
143
+ temporality_of_data: {
144
+ id: 'Temporality of data',
145
+ defaultMessage: 'Temporality of data',
146
+ },
147
+ nature_based_solution: {
148
+ id: 'Nature-based solution',
149
+ defaultMessage: 'Nature-based solution',
150
+ },
151
+ just_resilience: {
152
+ id: 'Just resilience',
153
+ defaultMessage: 'Just resilience',
154
+ },
155
+ cost_benefit_ratio: {
156
+ id: 'Cost-benefit ratio',
157
+ defaultMessage: 'Cost-benefit ratio',
158
+ },
159
+ accessibility_and_usability: {
160
+ id: 'Accessibility and usability',
161
+ defaultMessage: 'Accessibility and usability',
162
+ },
163
+ functionality: { id: 'Functionality', defaultMessage: 'Functionality' },
164
+ strengths_and_possible_limitations: {
165
+ id: 'Strengths and possible limitations of the tool',
166
+ defaultMessage: 'Strengths and possible limitations of the tool',
167
+ },
168
+ public_private_mode: {
169
+ id: 'Public/private',
170
+ defaultMessage: 'Public/private',
171
+ },
172
+ spatial_resolution: {
173
+ id: 'Spatial resolution',
174
+ defaultMessage: 'Spatial resolution',
175
+ },
176
+ underlying_data_maintenance: {
177
+ id: 'Underlying data maintenance',
178
+ defaultMessage: 'Underlying data maintenance',
179
+ },
180
+ addToComparison: {
181
+ id: 'Add to comparison',
182
+ defaultMessage: 'Add to comparison',
183
+ },
184
+ openTool: {
185
+ id: 'Open tool',
186
+ defaultMessage: 'Open tool',
187
+ },
188
+ share: {
189
+ id: 'Share',
190
+ defaultMessage: 'Share',
191
+ },
192
+ linkCopied: {
193
+ id: 'Link copied',
194
+ defaultMessage: 'Link copied',
195
+ },
196
+ });
197
+ const intl = useIntl();
198
+
199
+ const {
200
+ blocks: { blocksConfig },
201
+ } = config;
202
+ const TitleBlockView = blocksConfig?.title?.view || (() => null);
203
+ const titleBlockData = { ...content, title: item_title, image: '' };
204
+
205
+ return (
206
+ <div className="db-item-view">
207
+ <TitleBlockView
208
+ {...props}
209
+ data={{
210
+ '@type': 'title',
211
+ info: [{ description: '' }],
212
+ hideContentType: true,
213
+ hideCreationDate: true,
214
+ hideModificationDate: true,
215
+ hidePublishingDate: true,
216
+ hideDownloadButton: false,
217
+ hideShareButton: false,
218
+ subtitle: 'Tool',
219
+ }}
220
+ metadata={titleBlockData}
221
+ properties={titleBlockData}
222
+ />
223
+ <Container>
224
+ {(hasHyperlink || hasCompareTool) && (
225
+ <div className="extended-tool-compare-action">
226
+ {hasHyperlink && (
227
+ <Button
228
+ as="a"
229
+ primary
230
+ href={hyperlink}
231
+ target="_blank"
232
+ rel="noopener noreferrer"
233
+ >
234
+ <Icon className="ri-external-link-line" />
235
+ <span>{intl.formatMessage(messages.openTool)}</span>
236
+ </Button>
237
+ )}
238
+ {hasCompareTool && (
239
+ <Button
240
+ primary
241
+ inverted
242
+ disabled={isSelected || isLimitReached}
243
+ aria-pressed={isSelected}
244
+ onClick={toggle}
245
+ >
246
+ <Icon className="ri-layout-column-line" />
247
+ <span>{intl.formatMessage(messages.addToComparison)}</span>
248
+ </Button>
249
+ )}
250
+ </div>
251
+ )}
252
+ <CompareToolsPanel />
253
+ <PortalMessage content={content} />
254
+ <Grid columns="12">
255
+ <Grid.Row>
256
+ <Grid.Column
257
+ mobile={12}
258
+ tablet={12}
259
+ computer={8}
260
+ className="col-left"
261
+ >
262
+ <ItemLogo {...props} />
263
+
264
+ <HTMLField value={long_description} />
265
+ <TextField
266
+ label={intl.formatMessage(messages.tool_provider)}
267
+ value={tool_provider}
268
+ />
269
+ <TextField
270
+ label={intl.formatMessage(messages.public_private_mode)}
271
+ value={public_private_mode}
272
+ />
273
+ <HTMLField value={description} />
274
+ <TextField label="Coder1" value={coder_1} />
275
+ <TextField label="Coder2" value={coder_2} />
276
+ <BooleanField
277
+ label={intl.formatMessage(
278
+ messages.only_interactive_support_tool,
279
+ )}
280
+ value={only_interactive_support_tool}
281
+ yesLabel={intl.formatMessage(messages.yes)}
282
+ noLabel={intl.formatMessage(messages.no)}
283
+ />
284
+ <BooleanField
285
+ label={intl.formatMessage(messages.adaptation_cycle_step)}
286
+ value={adaptation_cycle_step}
287
+ yesLabel={intl.formatMessage(messages.yes)}
288
+ noLabel={intl.formatMessage(messages.no)}
289
+ />
290
+ <BooleanField
291
+ label={intl.formatMessage(messages.updating_cycle_of_the_tool)}
292
+ value={updating_cycle_of_the_tool}
293
+ yesLabel={intl.formatMessage(messages.yes)}
294
+ noLabel={intl.formatMessage(messages.no)}
295
+ />
296
+ <BooleanField
297
+ label={intl.formatMessage(messages.language_accessibility)}
298
+ value={language_accessibility}
299
+ yesLabel={intl.formatMessage(messages.yes)}
300
+ noLabel={intl.formatMessage(messages.no)}
301
+ />
302
+ <BooleanField
303
+ label={intl.formatMessage(messages.free_access)}
304
+ value={free_access}
305
+ yesLabel={intl.formatMessage(messages.yes)}
306
+ noLabel={intl.formatMessage(messages.no)}
307
+ />
308
+ <VocabularyField
309
+ label={intl.formatMessage(messages.intended_user_groups)}
310
+ values={intended_user_groups}
311
+ />
312
+ <VocabularyField
313
+ label={intl.formatMessage(messages.place_of_implementation)}
314
+ values={place_of_implementation}
315
+ />
316
+ <VocabularyField
317
+ label={intl.formatMessage(messages.type_of_data)}
318
+ values={type_of_data}
319
+ />
320
+ <VocabularyField
321
+ label={intl.formatMessage(messages.data_sources)}
322
+ values={data_sources}
323
+ />
324
+ <VocabularyField
325
+ label={intl.formatMessage(messages.license_status)}
326
+ values={license_status}
327
+ />
328
+ <VocabularyField
329
+ label={intl.formatMessage(messages.user_support_provisions)}
330
+ values={user_support_provisions}
331
+ />
332
+ <VocabularyField
333
+ label={intl.formatMessage(messages.tool_validation_use)}
334
+ values={tool_validation_use}
335
+ />
336
+ <VocabularyField
337
+ label={intl.formatMessage(messages.number_of_users_tool)}
338
+ values={number_of_users_tool}
339
+ />
340
+ <VocabularyField
341
+ label={intl.formatMessage(messages.tool_provider_mode)}
342
+ values={tool_provider_mode}
343
+ />
344
+ <VocabularyField
345
+ label={intl.formatMessage(
346
+ messages.adaptation_support_cycle_step,
347
+ )}
348
+ values={adaptation_support_cycle_step}
349
+ />
350
+ <TextField
351
+ label={intl.formatMessage(messages.tool_available_language)}
352
+ value={availableLanguageText}
353
+ />
354
+ <VocabularyField
355
+ label={intl.formatMessage(messages.type_of_outputs)}
356
+ values={type_of_outputs}
357
+ />
358
+ <VocabularyField
359
+ label={intl.formatMessage(messages.temporality_of_data)}
360
+ values={temporality_of_data}
361
+ />
362
+ <TextField
363
+ label={intl.formatMessage(messages.spatial_resolution)}
364
+ value={spatial_resolution}
365
+ />
366
+ <TextField
367
+ label={intl.formatMessage(messages.functionality)}
368
+ value={
369
+ functionality === null || functionality === undefined
370
+ ? null
371
+ : formatFunctionalityScore(functionality)
372
+ }
373
+ />
374
+ <TextField
375
+ label={intl.formatMessage(messages.underlying_data_maintenance)}
376
+ value={underlying_data_maintenance}
377
+ />
378
+ <VocabularyField
379
+ label={intl.formatMessage(messages.accessibility_and_usability)}
380
+ values={
381
+ accessibility_and_usability
382
+ ? [accessibility_and_usability]
383
+ : []
384
+ }
385
+ />
386
+ <TextField
387
+ label={intl.formatMessage(
388
+ messages.strengths_and_possible_limitations,
389
+ )}
390
+ value={strengths_and_possible_limitations}
391
+ />
392
+ </Grid.Column>
393
+ <Grid.Column
394
+ mobile={12}
395
+ tablet={12}
396
+ computer={4}
397
+ className="col-right"
398
+ >
399
+ <ContentMetadata {...props} />
400
+ <DocumentsList {...props} />
401
+ </Grid.Column>
402
+ </Grid.Row>
403
+ </Grid>
404
+ </Container>
405
+ </div>
406
+ );
407
+ };
408
+
409
+ export default ExtendedToolView;