@eeacms/volto-cca-policy 0.2.57 → 0.2.59

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.
package/CHANGELOG.md CHANGED
@@ -4,7 +4,30 @@ All notable changes to this project will be documented in this file. Dates are d
4
4
 
5
5
  Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog).
6
6
 
7
- ### [0.2.57](https://github.com/eea/volto-cca-policy/compare/0.2.56...0.2.57) - 22 July 2024
7
+ ### [0.2.59](https://github.com/eea/volto-cca-policy/compare/0.2.58...0.2.59) - 12 August 2024
8
+
9
+ #### :hammer_and_wrench: Others
10
+
11
+ - Don't hardcode to last 5 years [Tiberiu Ichim - [`475d7e1`](https://github.com/eea/volto-cca-policy/commit/475d7e17a8faeec9115298bd38f30db51b038a36)]
12
+ ### [0.2.58](https://github.com/eea/volto-cca-policy/compare/0.2.57...0.2.58) - 12 August 2024
13
+
14
+ #### :house: Internal changes
15
+
16
+ - style: Automated code fix [eea-jenkins - [`30f4774`](https://github.com/eea/volto-cca-policy/commit/30f4774d7d21cb5bbb4f2782a42c0223fde00e90)]
17
+
18
+ #### :hammer_and_wrench: Others
19
+
20
+ - Improve css for broken links [Tiberiu Ichim - [`ef17b71`](https://github.com/eea/volto-cca-policy/commit/ef17b71c4ae6c19202e110f8baca0055d05ad670)]
21
+ - Update GeolocationWidgetMapContainer.jsx [Tiberiu Ichim - [`3da08d2`](https://github.com/eea/volto-cca-policy/commit/3da08d2476bb73a792843d4bc20b3219cb32f65f)]
22
+ - Add test [Tiberiu Ichim - [`751ed81`](https://github.com/eea/volto-cca-policy/commit/751ed81a26de0fde987ab51fcb0bb70ceaeea600)]
23
+ - Stylint fix [Tiberiu Ichim - [`303bb86`](https://github.com/eea/volto-cca-policy/commit/303bb865cdcbb34af23e6f635a0bc9eb41782ef9)]
24
+ - Add start-backend target [Tiberiu Ichim - [`2dbf5df`](https://github.com/eea/volto-cca-policy/commit/2dbf5df311347350f8c42ee3daf3dbd2a840c85a)]
25
+ - No console.log [Tiberiu Ichim - [`06125f9`](https://github.com/eea/volto-cca-policy/commit/06125f9e65de369caacf71a00a8c77d7bc0202b3)]
26
+ - Fixes [Tiberiu Ichim - [`4f00318`](https://github.com/eea/volto-cca-policy/commit/4f00318c0bbb1aea68348cf7efa5684ed1b68fef)]
27
+ - Add filters and sorting [Tiberiu Ichim - [`f6aa329`](https://github.com/eea/volto-cca-policy/commit/f6aa329610180b6e72e879bc38c2c51ed5e65d6c)]
28
+ - Use react-table [Tiberiu Ichim - [`9d6af3a`](https://github.com/eea/volto-cca-policy/commit/9d6af3a0dfcf99bf52c6619ef14f62a047aa0b73)]
29
+ - Add brokenlinks component [Tiberiu Ichim - [`d9a6230`](https://github.com/eea/volto-cca-policy/commit/d9a6230f94021ee2900830284ef2fda8563fe5d0)]
30
+ ### [0.2.57](https://github.com/eea/volto-cca-policy/compare/0.2.56...0.2.57) - 23 July 2024
8
31
 
9
32
  ### [0.2.56](https://github.com/eea/volto-cca-policy/compare/0.2.55...0.2.56) - 22 July 2024
10
33
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eeacms/volto-cca-policy",
3
- "version": "0.2.57",
3
+ "version": "0.2.59",
4
4
  "description": "@eeacms/volto-cca-policy: Volto add-on",
5
5
  "main": "src/index.js",
6
6
  "author": "European Environment Agency: IDM2 A-Team",
@@ -39,6 +39,7 @@
39
39
  "@eeacms/volto-slate-label": "^0.6.0",
40
40
  "@eeacms/volto-tabs-block": "^7.5.1",
41
41
  "@elastic/search-ui": "1.21.2",
42
+ "@tanstack/react-table": "8.19.3",
42
43
  "d3-array": "^2.12.1",
43
44
  "jotai": "^1.6.0",
44
45
  "query-string": "7.1.0",
@@ -69,7 +69,7 @@ const makeSearchBlockQuery = ({ base, query, field, value }) => {
69
69
  const makeEEASearchQuery = ({ base, field, value, extraFilters }) => {
70
70
  // TODO: don't hardcode the language
71
71
  const allFields = [
72
- ['issued.date', 'Last 5 years'],
72
+ // ['issued.date', 'Last 5 years'],
73
73
  ['language', 'en'],
74
74
  [field, value],
75
75
  ...(extraFilters?.map(({ id, value }) => [id, value]) || []),
@@ -0,0 +1,284 @@
1
+ import { expandToBackendURL } from '@plone/volto/helpers';
2
+ import { injectLazyLibs } from '@plone/volto/helpers/Loadable';
3
+ import React from 'react';
4
+ import {
5
+ Button,
6
+ Table,
7
+ TableBody,
8
+ TableCell,
9
+ TableHeader,
10
+ TableHeaderCell,
11
+ TableRow,
12
+ } from 'semantic-ui-react';
13
+
14
+ import './brokenlinks.less';
15
+
16
+ function Filter({ column }) {
17
+ const columnFilterValue = column.getFilterValue();
18
+ const { filterVariant } = column.columnDef.meta ?? {};
19
+ const handleRangeNumberChangeMin = React.useCallback(
20
+ (value) => {
21
+ column.setFilterValue((old) => [value, old?.[1]]);
22
+ },
23
+ [column],
24
+ );
25
+ const handleRangeNumberChangeMax = React.useCallback(
26
+ (value) => column.setFilterValue((old) => [old?.[0], value]),
27
+ [column],
28
+ );
29
+
30
+ const handleTextChange = React.useCallback(
31
+ (value) => column.setFilterValue(value),
32
+ [column],
33
+ );
34
+
35
+ return filterVariant === 'range' ? (
36
+ <div>
37
+ <div className="flex space-x-2">
38
+ {/* See faceted column filters example for min max values functionality */}
39
+ <DebouncedInput
40
+ type="number"
41
+ value={columnFilterValue?.[0] ?? ''}
42
+ onChange={handleRangeNumberChangeMin}
43
+ placeholder={`Min`}
44
+ className="w-24 border shadow rounded"
45
+ />
46
+ <DebouncedInput
47
+ type="number"
48
+ value={columnFilterValue?.[1] ?? ''}
49
+ onChange={handleRangeNumberChangeMax}
50
+ placeholder={`Max`}
51
+ className="w-24 border shadow rounded"
52
+ />
53
+ </div>
54
+ <div className="h-1" />
55
+ </div>
56
+ ) : filterVariant === 'select' ? (
57
+ <select
58
+ onBlur={(e) => column.setFilterValue(e.target.value)}
59
+ onChange={(e) => column.setFilterValue(e.target.value)}
60
+ value={columnFilterValue?.toString()}
61
+ >
62
+ {/* See faceted column filters example for dynamic select options */}
63
+ <option value="">All</option>
64
+ <option value="complicated">complicated</option>
65
+ <option value="relationship">relationship</option>
66
+ <option value="single">single</option>
67
+ </select>
68
+ ) : (
69
+ <DebouncedInput
70
+ className="w-36 border shadow rounded"
71
+ onChange={handleTextChange}
72
+ placeholder={`Search...`}
73
+ type="text"
74
+ value={columnFilterValue ?? ''}
75
+ />
76
+ // See faceted column filters example for datalist search suggestions
77
+ );
78
+ }
79
+
80
+ // A typical debounced input react component
81
+ function DebouncedInput({
82
+ value: initialValue,
83
+ onChange,
84
+ debounce = 500,
85
+ ...props
86
+ }) {
87
+ const [value, setValue] = React.useState(initialValue);
88
+
89
+ React.useEffect(() => {
90
+ setValue(initialValue);
91
+ }, [initialValue]);
92
+
93
+ React.useEffect(() => {
94
+ const timeout = setTimeout(() => {
95
+ onChange(value);
96
+ }, debounce);
97
+
98
+ return () => clearTimeout(timeout);
99
+ }, [value, debounce, onChange]);
100
+
101
+ return (
102
+ <input
103
+ {...props}
104
+ value={value}
105
+ onChange={(e) => setValue(e.target.value)}
106
+ />
107
+ );
108
+ }
109
+
110
+ export function BrokenLinksComponent({ reactTable }) {
111
+ const { createColumnHelper } = reactTable;
112
+
113
+ const [results, setResults] = React.useState({});
114
+
115
+ React.useEffect(() => {
116
+ const url = expandToBackendURL('/@broken_links');
117
+ let isMounted = true;
118
+ async function handler() {
119
+ try {
120
+ const response = await fetch(url);
121
+ const results = await response.json();
122
+ const data = Array.from(Object.values(results.broken_links));
123
+ if (isMounted) setResults(data);
124
+ } catch {
125
+ // eslint-disable-next-line no-console
126
+ console.error('Error in fetching broken links');
127
+ }
128
+ }
129
+ handler();
130
+ return () => (isMounted = false);
131
+ }, []);
132
+
133
+ const columnHelper = createColumnHelper();
134
+ const columns = React.useMemo(
135
+ () => [
136
+ columnHelper.accessor('url', {
137
+ header: () => 'URL',
138
+ cell: (info) => <a href={info.getValue()}>{info.getValue()}</a>,
139
+ filterFn: 'includesString',
140
+ }),
141
+ columnHelper.accessor('status', {
142
+ header: () => 'Status',
143
+ filterFn: 'includesString',
144
+ }),
145
+ columnHelper.accessor('date', {
146
+ header: () => 'Last checked',
147
+ filterFn: 'includesString',
148
+ }),
149
+
150
+ columnHelper.accessor('object_url', {
151
+ header: () => 'Reference from',
152
+ cell: (info) => <a href={info.getValue()}>{info.getValue()}</a>,
153
+ filterFn: 'includesString',
154
+ }),
155
+ ],
156
+ [columnHelper],
157
+ );
158
+
159
+ return (
160
+ <FilteredTable data={results} columns={columns} reactTable={reactTable} />
161
+ );
162
+ }
163
+
164
+ function FilteredTable({ reactTable, data, columns }) {
165
+ const {
166
+ useReactTable,
167
+ getPaginationRowModel,
168
+ getCoreRowModel,
169
+ flexRender,
170
+ getFilteredRowModel,
171
+ getSortedRowModel,
172
+ } = reactTable;
173
+
174
+ const table = useReactTable({
175
+ data,
176
+ columns,
177
+ getCoreRowModel: getCoreRowModel(),
178
+ getPaginationRowModel: getPaginationRowModel(),
179
+ getFilteredRowModel: getFilteredRowModel(),
180
+ getSortedRowModel: getSortedRowModel(),
181
+ });
182
+
183
+ return (
184
+ <div className="broken-links-table ui container">
185
+ <Table>
186
+ <TableHeader>
187
+ {table.getHeaderGroups().map((headerGroup) => (
188
+ <TableRow key={headerGroup.id}>
189
+ {headerGroup.headers.map((header) => (
190
+ <TableHeaderCell key={header.id} className={header.id}>
191
+ {header.isPlaceholder ? null : (
192
+ <>
193
+ <div
194
+ tabIndex="-1"
195
+ role="button"
196
+ onKeyDown={header.column.getToggleSortingHandler()}
197
+ {...{
198
+ className: header.column.getCanSort()
199
+ ? 'cursor-pointer select-none'
200
+ : '',
201
+ onClick: header.column.getToggleSortingHandler(),
202
+ }}
203
+ >
204
+ {flexRender(
205
+ header.column.columnDef.header,
206
+ header.getContext(),
207
+ )}
208
+ {{
209
+ asc: ' 🔼',
210
+ desc: ' 🔽',
211
+ }[header.column.getIsSorted()] ?? null}
212
+ </div>
213
+ {header.column.getCanFilter() ? (
214
+ <div>
215
+ <Filter column={header.column} />
216
+ </div>
217
+ ) : null}
218
+ </>
219
+ )}
220
+ </TableHeaderCell>
221
+ ))}
222
+ </TableRow>
223
+ ))}
224
+ </TableHeader>
225
+ <TableBody>
226
+ {table.getRowModel().rows.map((row) => {
227
+ return (
228
+ <TableRow key={row.id}>
229
+ {row.getVisibleCells().map((cell) => (
230
+ <TableCell key={cell.id}>
231
+ {flexRender(cell.column.columnDef.cell, cell.getContext())}
232
+ </TableCell>
233
+ ))}
234
+ </TableRow>
235
+ );
236
+ })}
237
+ </TableBody>
238
+ </Table>
239
+ <div className="pagination">
240
+ <Button
241
+ onClick={() => table.firstPage()}
242
+ disabled={!table.getCanPreviousPage()}
243
+ >
244
+ {'<<'}
245
+ </Button>
246
+ <Button
247
+ onClick={() => table.previousPage()}
248
+ disabled={!table.getCanPreviousPage()}
249
+ >
250
+ {'<'}
251
+ </Button>
252
+ <Button
253
+ onClick={() => table.nextPage()}
254
+ disabled={!table.getCanNextPage()}
255
+ >
256
+ {'>'}
257
+ </Button>
258
+ <Button
259
+ onClick={() => table.lastPage()}
260
+ disabled={!table.getCanNextPage()}
261
+ >
262
+ {'>>'}
263
+ </Button>
264
+ <select
265
+ value={table.getState().pagination.pageSize}
266
+ onChange={(e) => {
267
+ table.setPageSize(Number(e.target.value));
268
+ }}
269
+ onBlur={(e) => {
270
+ table.setPageSize(Number(e.target.value));
271
+ }}
272
+ >
273
+ {[10, 20, 30, 40, 50].map((pageSize) => (
274
+ <option key={pageSize} value={pageSize}>
275
+ {pageSize}
276
+ </option>
277
+ ))}
278
+ </select>
279
+ </div>
280
+ </div>
281
+ );
282
+ }
283
+
284
+ export default injectLazyLibs(['reactTable'])(BrokenLinksComponent);
@@ -0,0 +1,30 @@
1
+ import React from 'react';
2
+ import { MemoryRouter } from 'react-router-dom';
3
+ import configureStore from 'redux-mock-store';
4
+ import '@testing-library/jest-dom/extend-expect';
5
+ import { render } from '@testing-library/react';
6
+ import { Provider } from 'react-intl-redux';
7
+ import { BrokenLinksComponent } from './BrokenLinks';
8
+
9
+ const mockStore = configureStore();
10
+
11
+ describe('BrokenLinksComponent', () => {
12
+ it('should render the component', async () => {
13
+ const store = mockStore({
14
+ userSession: { token: '1234' },
15
+ intl: {
16
+ locale: 'en',
17
+ messages: {},
18
+ },
19
+ });
20
+ const reactTable = await import('@tanstack/react-table');
21
+ const { container } = render(
22
+ <Provider store={store}>
23
+ <MemoryRouter>
24
+ <BrokenLinksComponent reactTable={reactTable} />
25
+ </MemoryRouter>
26
+ </Provider>,
27
+ );
28
+ expect(container).toBeTruthy();
29
+ });
30
+ });
@@ -0,0 +1,21 @@
1
+ .broken-links-table {
2
+ td {
3
+ max-width: 200px;
4
+ }
5
+
6
+ a {
7
+ display: block;
8
+ overflow: hidden;
9
+ text-overflow: ellipsis;
10
+ white-space: nowrap;
11
+ // max-width: 200px;
12
+ }
13
+
14
+ .cursor-pointer {
15
+ cursor: pointer;
16
+ }
17
+
18
+ .select-none {
19
+ user-select: none;
20
+ }
21
+ }
@@ -1,11 +1,13 @@
1
1
  import React, { useState } from 'react';
2
2
  import PropTypes from 'prop-types';
3
- import { Input } from 'semantic-ui-react';
3
+ import { Input, Label } from 'semantic-ui-react';
4
4
  import config from '@plone/volto/registry';
5
5
 
6
6
  import { injectIntl } from 'react-intl';
7
7
  import { FormFieldWrapper } from '@plone/volto/components';
8
- import MapContainer from '@eeacms/volto-cca-policy/components/theme/Widgets/GeolocationWidgetMapContainer';
8
+ import MapContainer from './GeolocationWidgetMapContainer';
9
+
10
+ import './geolocation.css';
9
11
 
10
12
  const defaultValue = {
11
13
  latitude: 55.6761,
@@ -16,6 +18,7 @@ const GeolocationWidget = (props) => {
16
18
  const { id, value, onChange } = props;
17
19
 
18
20
  const [address, setAddress] = useState('');
21
+ const [isFetching, setIsFetching] = useState();
19
22
 
20
23
  const handleAddressChange = (event) => {
21
24
  setAddress(event.target.value);
@@ -34,9 +37,11 @@ const GeolocationWidget = (props) => {
34
37
  const path = `${base}${corsProxyPath}/${url}`;
35
38
 
36
39
  let locations;
40
+ setIsFetching(true);
37
41
  try {
38
42
  const response = await fetch(path);
39
43
  locations = await response.json();
44
+ setIsFetching(false);
40
45
  } catch (e) {
41
46
  // eslint-disable-next-line no-console
42
47
  console.log('error in fetching location', e);
@@ -59,10 +64,19 @@ const GeolocationWidget = (props) => {
59
64
  <div className="ui form">
60
65
  <div className="inline fields">
61
66
  <div className="field">
62
- <Input type="text" value={address} onChange={handleAddressChange} />
67
+ <Input
68
+ type="text"
69
+ value={address}
70
+ onChange={handleAddressChange}
71
+ onKeyDown={(e) => {
72
+ if (e.key === 'Enter') handleSearch(e);
73
+ }}
74
+ />
63
75
  </div>
64
76
  <div className="field">
65
- <button onClick={handleSearch}>Search</button>
77
+ <button onClick={handleSearch}>
78
+ {isFetching ? 'Loading' : 'Search'}
79
+ </button>
66
80
  </div>
67
81
  </div>
68
82
  </div>
@@ -70,10 +84,14 @@ const GeolocationWidget = (props) => {
70
84
  key={mapKey}
71
85
  longitude={value?.longitude || defaultValue.longitude}
72
86
  latitude={value?.latitude || defaultValue.latitude}
87
+ onChange={({ latitude, longitude }) =>
88
+ onChange(id, { ...value, longitude, latitude })
89
+ }
73
90
  />
74
91
  <div className="ui form">
75
92
  <div className="inline fields">
76
93
  <div className="field">
94
+ <Label>Latitude</Label>
77
95
  <Input
78
96
  type="number"
79
97
  placeholder="latitude"
@@ -84,6 +102,7 @@ const GeolocationWidget = (props) => {
84
102
  />
85
103
  </div>
86
104
  <div className="field">
105
+ <Label>Longitude</Label>
87
106
  <Input
88
107
  type="number"
89
108
  placeholder="longitude"
@@ -1,12 +1,72 @@
1
- import React, { useState } from 'react';
1
+ import { openlayers as ol } from '@eeacms/volto-openlayers-map';
2
2
  import {
3
3
  Controls,
4
4
  Interactions,
5
5
  Layer,
6
- Map,
7
6
  Layers,
7
+ Map,
8
8
  } from '@eeacms/volto-openlayers-map/api';
9
- import { openlayers as ol } from '@eeacms/volto-openlayers-map';
9
+ import React, { useState } from 'react';
10
+ import { useMapContext } from '@eeacms/volto-openlayers-map/hocs';
11
+
12
+ function PinInteraction({ longitude, latitude, onChange }) {
13
+ const mapContext = useMapContext();
14
+ const { addLayer, addInteraction, map } = mapContext;
15
+
16
+ React.useEffect(() => {
17
+ if (
18
+ !map ||
19
+ typeof latitude === 'undefined' ||
20
+ typeof longitude === 'undefined'
21
+ )
22
+ return;
23
+
24
+ // Create a feature (the pin) and set it to be draggable
25
+ const pin = new ol.ol.Feature({
26
+ geometry: new ol.geom.Point(ol.proj.fromLonLat([longitude, latitude])), // Initial location
27
+ });
28
+
29
+ // Style for the pin
30
+ pin.setStyle(
31
+ new ol.style.Style({
32
+ image: new ol.style.Icon({
33
+ anchor: [0.5, 1],
34
+ src: 'https://openlayers.org/en/latest/examples/data/icon.png',
35
+ }),
36
+ }),
37
+ );
38
+
39
+ // Create a vector layer to hold the pin
40
+ const vectorSource = new ol.source.Vector({
41
+ features: [pin],
42
+ });
43
+
44
+ const vectorLayer = new ol.layer.Vector({
45
+ source: vectorSource,
46
+ });
47
+
48
+ map.addLayer(vectorLayer);
49
+
50
+ // Add drag interaction
51
+ const dragInteraction = new ol.interaction.Modify({
52
+ source: vectorSource,
53
+ pixelTolerance: 20,
54
+ });
55
+
56
+ map.addInteraction(dragInteraction);
57
+
58
+ // Log the new position when the pin is dragged
59
+ dragInteraction.on('modifyend', function (event) {
60
+ const feature = event.features.getArray()[0];
61
+ const coordinates = feature.getGeometry().getCoordinates();
62
+ const lonLat = ol.proj.toLonLat(coordinates);
63
+ const [longitude, latitude] = lonLat;
64
+ onChange({ latitude, longitude });
65
+ });
66
+ }, [addInteraction, addLayer, map, onChange, latitude, longitude]);
67
+
68
+ return null;
69
+ }
10
70
 
11
71
  const TileSetLoader = (props) => {
12
72
  const [tileWMSSources, setTileWMSSources] = useState([]);
@@ -31,7 +91,7 @@ const TileSetLoader = (props) => {
31
91
  };
32
92
 
33
93
  const MapContainer = (props) => {
34
- const { longitude, latitude, source } = props;
94
+ const { longitude, latitude, source, onChange } = props;
35
95
  return (
36
96
  <Map
37
97
  view={{
@@ -44,15 +104,20 @@ const MapContainer = (props) => {
44
104
  >
45
105
  <Layers>
46
106
  <Controls attribution={false} zoom={false} />
107
+ <PinInteraction
108
+ latitude={latitude}
109
+ longitude={longitude}
110
+ onChange={onChange}
111
+ />
47
112
  <Interactions
48
113
  doubleClickZoom={true}
49
- dragAndDrop={false}
114
+ dragAndDrop={true}
50
115
  dragPan={true}
51
116
  keyboardPan={true}
52
117
  keyboardZoom={true}
53
118
  mouseWheelZoom={true}
54
119
  pointer={true}
55
- select={false}
120
+ select={true}
56
121
  />
57
122
  <Layer.Tile source={source} zIndex={0} />
58
123
  </Layers>
@@ -0,0 +1,3 @@
1
+ .geolocation-field .ol-map {
2
+ cursor: pointer;
3
+ }
package/src/index.js CHANGED
@@ -1,3 +1,4 @@
1
+ import loadable from '@loadable/component';
1
2
  import { compose } from 'redux';
2
3
  import { Sitemap } from '@plone/volto/components';
3
4
  import DefaultView from '@plone/volto/components/theme/View/DefaultView';
@@ -35,6 +36,7 @@ import europeanComissionLogo from '@eeacms/volto-cca-policy/../theme/assets/imag
35
36
  import eeaWhiteLogo from '@eeacms/volto-eea-design-system/../theme/themes/eea/assets/logo/eea-logo-white.svg';
36
37
 
37
38
  import './slate-styles.less';
39
+ import BrokenLinks from './components/theme/Views/BrokenLinks';
38
40
 
39
41
  const getEnv = () => (typeof window !== 'undefined' ? window.env : process.env);
40
42
 
@@ -59,8 +61,8 @@ const applyConfig = (config) => {
59
61
  ...(config.settings.externalRoutes || []),
60
62
  {
61
63
  match: {
62
- path: new RegExp(voltoLocationsRegex),
63
64
  exact: false,
65
+ path: new RegExp(voltoLocationsRegex),
64
66
  strict: false,
65
67
  },
66
68
  url(payload) {
@@ -75,10 +77,10 @@ const applyConfig = (config) => {
75
77
  'nominatim.openstreetmap.org',
76
78
  ];
77
79
 
78
- // if (!config.settings.loadables.d3)
79
- // config.settings.loadables.d3 = loadable.lib(() => import('d3'));
80
- // if (!config.settings.loadables.d3Geo)
81
- // config.settings.loadables.d3Geo = loadable.lib(() => import('d3-geo'));
80
+ if (!config.settings.loadables.reactTable)
81
+ config.settings.loadables.reactTable = loadable.lib(() =>
82
+ import('@tanstack/react-table'),
83
+ );
82
84
 
83
85
  config.settings.dateLocale = 'en-gb';
84
86
  config.settings.isMultilingual = true;
@@ -376,9 +378,19 @@ const applyConfig = (config) => {
376
378
  component: Sitemap,
377
379
  },
378
380
 
381
+ {
382
+ path: `/broken-links`,
383
+ component: BrokenLinks,
384
+ },
385
+
379
386
  ...(config.addonRoutes || []),
380
387
  ];
381
388
 
389
+ config.settings.nonContentRoutes = [
390
+ ...config.settings.nonContentRoutes,
391
+ '/broken-links',
392
+ ];
393
+
382
394
  config.settings.appExtras = [
383
395
  ...(config.settings.appExtras || []),
384
396
  {
@@ -1,3 +1,4 @@
1
- ol.ui.list, .ui.bulleted.list {
1
+ ol.ui.list,
2
+ .ui.bulleted.list {
2
3
  margin-left: 0;
3
- }
4
+ }
@@ -23,8 +23,8 @@
23
23
  .view-wrapper > .ui.list,
24
24
  [id='page-document'] > .ui.bulleted.list,
25
25
  .view-wrapper > .ui.bulleted.list {
26
- margin-left: auto !important;
27
26
  margin-right: auto !important;
27
+ margin-left: auto !important;
28
28
  }
29
29
 
30
30
  .ui.ordered.list,