@plone/volto 17.0.0-alpha.7 → 17.0.0-alpha.9
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/.yarn/install-state.gz +0 -0
- package/CHANGELOG.md +82 -0
- package/locales/ca/LC_MESSAGES/volto.po +146 -0
- package/locales/ca.json +1 -1
- package/locales/de/LC_MESSAGES/volto.po +146 -0
- package/locales/de.json +1 -1
- package/locales/en/LC_MESSAGES/volto.po +146 -0
- package/locales/en.json +1 -1
- package/locales/es/LC_MESSAGES/volto.po +146 -0
- package/locales/es.json +1 -1
- package/locales/eu/LC_MESSAGES/volto.po +146 -0
- package/locales/eu.json +1 -1
- package/locales/fi/LC_MESSAGES/volto.po +4762 -0
- package/locales/fi.json +1 -1
- package/locales/fr/LC_MESSAGES/volto.po +146 -0
- package/locales/fr.json +1 -1
- package/locales/it/LC_MESSAGES/volto.po +146 -0
- package/locales/it.json +1 -1
- package/locales/ja/LC_MESSAGES/volto.po +146 -0
- package/locales/ja.json +1 -1
- package/locales/nl/LC_MESSAGES/volto.po +801 -643
- package/locales/nl.json +1 -1
- package/locales/pt/LC_MESSAGES/volto.po +146 -0
- package/locales/pt.json +1 -1
- package/locales/pt_BR/LC_MESSAGES/volto.po +146 -0
- package/locales/pt_BR.json +1 -1
- package/locales/ro/LC_MESSAGES/volto.po +146 -0
- package/locales/ro.json +1 -1
- package/locales/volto.pot +147 -1
- package/locales/zh_CN/LC_MESSAGES/volto.po +146 -0
- package/locales/zh_CN.json +1 -1
- package/package.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Table/TableBlockEdit.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Text/DefaultTextBlockEditor.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Text/DetachedTextBlockEditor.json +1 -1
- package/packages/volto-slate/build/messages/src/blocks/Text/SlashMenu.json +1 -1
- package/packages/volto-slate/build/messages/src/editor/plugins/AdvancedLink/index.json +1 -1
- package/packages/volto-slate/build/messages/src/editor/plugins/Link/index.json +1 -1
- package/packages/volto-slate/build/messages/src/editor/plugins/Table/index.json +1 -1
- package/packages/volto-slate/build/messages/src/elementEditor/messages.json +1 -1
- package/packages/volto-slate/build/messages/src/widgets/HtmlSlateWidget.json +1 -1
- package/packages/volto-slate/build/messages/src/widgets/RichTextWidgetView.json +1 -1
- package/packages/volto-slate/package.json +1 -1
- package/packages/volto-slate/src/blocks/Text/SlashMenu.jsx +4 -3
- package/packages/volto-slate/src/editor/deserialize.js +0 -1
- package/razzle.config.js +5 -0
- package/src/actions/index.js +6 -0
- package/src/actions/relations/rebuild.js +25 -0
- package/src/actions/relations/relations.js +86 -0
- package/src/actions/relations/relations.test.js +15 -0
- package/src/components/index.js +1 -0
- package/src/components/manage/BlockChooser/BlockChooser.jsx +8 -3
- package/src/components/manage/BlockChooser/BlockChooser.test.jsx +5 -0
- package/src/components/manage/Contents/Contents.jsx +5 -1
- package/src/components/manage/Contents/ContentsItem.jsx +6 -0
- package/src/components/manage/Controlpanels/Controlpanels.jsx +9 -0
- package/src/components/manage/Controlpanels/Relations/BrokenRelations.jsx +66 -0
- package/src/components/manage/Controlpanels/Relations/Relations.jsx +114 -0
- package/src/components/manage/Controlpanels/Relations/RelationsListing.jsx +479 -0
- package/src/components/manage/Controlpanels/Relations/RelationsMatrix.jsx +531 -0
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel.jsx +3 -3
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipListing.jsx +51 -82
- package/src/components/manage/Controlpanels/Users/UserGroupMembershipMatrix.jsx +79 -75
- package/src/components/manage/Toast/Toast.jsx +1 -1
- package/src/components/theme/NotFound/NotFound.jsx +55 -41
- package/src/components/theme/View/RenderBlocks.jsx +7 -1
- package/src/components/theme/Widgets/RelationsWidget.jsx +13 -11
- package/src/config/ControlPanels.js +2 -0
- package/src/constants/ActionTypes.js +4 -0
- package/src/constants/Languages.js +8 -4
- package/src/helpers/Api/Api.js +1 -1
- package/src/helpers/Html/Html.jsx +3 -1
- package/src/helpers/Html/Html.test.jsx +5 -0
- package/src/helpers/MessageLabels/MessageLabels.js +72 -0
- package/src/reducers/actions/actions.js +1 -1
- package/src/reducers/breadcrumbs/breadcrumbs.js +1 -1
- package/src/reducers/index.js +2 -0
- package/src/reducers/navigation/navigation.js +1 -1
- package/src/reducers/relations/relations.js +173 -0
- package/src/reducers/types/types.js +1 -1
- package/src/routes.js +5 -0
- package/theme/themes/pastanaga/extras/userscontrolpanel.less +99 -76
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
"id": "An error has occurred while editing \"{name}\" field. We have been notified and we are looking into it. Please save your work and retry. If the issue persists please contact the site administrator.",
|
|
4
4
|
"defaultMessage": "An error has occurred while editing \"{name}\" field. We have been notified and we are looking into it. Please save your work and retry. If the issue persists please contact the site administrator."
|
|
5
5
|
}
|
|
6
|
-
]
|
|
6
|
+
]
|
|
@@ -3,4 +3,4 @@
|
|
|
3
3
|
"id": "An error has occurred while rendering \"{name}\" field. We have been notified and we are looking into it. If the issue persists please contact the site administrator.",
|
|
4
4
|
"defaultMessage": "An error has occurred while rendering \"{name}\" field. We have been notified and we are looking into it. If the issue persists please contact the site administrator."
|
|
5
5
|
}
|
|
6
|
-
]
|
|
6
|
+
]
|
|
@@ -110,7 +110,7 @@ const PersistentSlashMenu = ({ editor }) => {
|
|
|
110
110
|
|
|
111
111
|
const [slashMenuSelected, setSlashMenuSelected] = React.useState(0);
|
|
112
112
|
|
|
113
|
-
const
|
|
113
|
+
const hasAllowedBlocks = !isEmpty(allowedBlocks);
|
|
114
114
|
const slashCommand = data.plaintext
|
|
115
115
|
?.toLowerCase()
|
|
116
116
|
.trim()
|
|
@@ -119,12 +119,13 @@ const PersistentSlashMenu = ({ editor }) => {
|
|
|
119
119
|
const availableBlocks = React.useMemo(
|
|
120
120
|
() =>
|
|
121
121
|
filter(blocksConfig, (item) =>
|
|
122
|
-
|
|
122
|
+
hasAllowedBlocks
|
|
123
123
|
? allowedBlocks.includes(item.id)
|
|
124
124
|
: typeof item.restricted === 'function'
|
|
125
125
|
? !item.restricted({ properties, block: item })
|
|
126
126
|
: !item.restricted,
|
|
127
127
|
)
|
|
128
|
+
.filter((block) => Boolean(block.title && block.id))
|
|
128
129
|
.filter((block) => {
|
|
129
130
|
// typed text is a substring of the title or id
|
|
130
131
|
const title = translateBlockTitle(block, intl).toLowerCase();
|
|
@@ -150,7 +151,7 @@ const PersistentSlashMenu = ({ editor }) => {
|
|
|
150
151
|
intl,
|
|
151
152
|
properties,
|
|
152
153
|
slashCommand,
|
|
153
|
-
|
|
154
|
+
hasAllowedBlocks,
|
|
154
155
|
],
|
|
155
156
|
);
|
|
156
157
|
|
package/razzle.config.js
CHANGED
|
@@ -341,6 +341,11 @@ const defaultModify = ({
|
|
|
341
341
|
|
|
342
342
|
if (config.devServer) {
|
|
343
343
|
config.devServer.static.watch.ignored = /node_modules\/(?!@plone\/volto)/;
|
|
344
|
+
config.snapshot = {
|
|
345
|
+
managedPaths: [
|
|
346
|
+
/^(.+?[\\/]node_modules[\\/](?!(@plone[\\/]volto))(@.+?[\\/])?.+?)[\\/]/,
|
|
347
|
+
],
|
|
348
|
+
};
|
|
344
349
|
}
|
|
345
350
|
|
|
346
351
|
return config;
|
package/src/actions/index.js
CHANGED
|
@@ -71,6 +71,12 @@ export {
|
|
|
71
71
|
purgeMessages,
|
|
72
72
|
} from '@plone/volto/actions/messages/messages';
|
|
73
73
|
export { getNavigation } from '@plone/volto/actions/navigation/navigation';
|
|
74
|
+
export {
|
|
75
|
+
createRelations,
|
|
76
|
+
deleteRelations,
|
|
77
|
+
queryRelations,
|
|
78
|
+
} from '@plone/volto/actions/relations/relations';
|
|
79
|
+
export { rebuildRelations } from '@plone/volto/actions/relations/rebuild';
|
|
74
80
|
export { listRoles } from '@plone/volto/actions/roles/roles';
|
|
75
81
|
export {
|
|
76
82
|
getSchema,
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Rebuild relations action.
|
|
3
|
+
* @module actions/relations/rebuild
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { REBUILD_RELATIONS } from '@plone/volto/constants/ActionTypes';
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Rebuild relation function.
|
|
10
|
+
* @function rebuildRelations
|
|
11
|
+
* @param {Boolean} flush Flush intids
|
|
12
|
+
* @returns {Object} Rebuild relation action.
|
|
13
|
+
*/
|
|
14
|
+
export function rebuildRelations(flush = false) {
|
|
15
|
+
let path = '/@relations';
|
|
16
|
+
var searchParams = new URLSearchParams();
|
|
17
|
+
searchParams.append('rebuild', '1');
|
|
18
|
+
flush && searchParams.append('flush', '1');
|
|
19
|
+
const searchParamsToString = searchParams.toString();
|
|
20
|
+
path += `?${searchParamsToString}`;
|
|
21
|
+
return {
|
|
22
|
+
type: REBUILD_RELATIONS,
|
|
23
|
+
request: { op: 'get', path: path },
|
|
24
|
+
};
|
|
25
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relations actions.
|
|
3
|
+
* @module actions/relations/relations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
CREATE_RELATIONS,
|
|
8
|
+
DELETE_RELATIONS,
|
|
9
|
+
LIST_RELATIONS,
|
|
10
|
+
} from '@plone/volto/constants/ActionTypes';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Create relation function.
|
|
14
|
+
* @function createRelations
|
|
15
|
+
* @param {Object|Array} content Relation data.
|
|
16
|
+
* @returns {Object} Create relation action.
|
|
17
|
+
*/
|
|
18
|
+
export function createRelations(content) {
|
|
19
|
+
return {
|
|
20
|
+
type: CREATE_RELATIONS,
|
|
21
|
+
request: {
|
|
22
|
+
op: 'post',
|
|
23
|
+
path: '/@relations',
|
|
24
|
+
data: {
|
|
25
|
+
items: content,
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Delete relation function.
|
|
33
|
+
* @function deleteRelations
|
|
34
|
+
* @param {string} id Relation id
|
|
35
|
+
* @returns {Object} Delete relation action.
|
|
36
|
+
*/
|
|
37
|
+
export function deleteRelations(content) {
|
|
38
|
+
return {
|
|
39
|
+
type: DELETE_RELATIONS,
|
|
40
|
+
request: {
|
|
41
|
+
op: 'del',
|
|
42
|
+
path: `/@relations`,
|
|
43
|
+
data: {
|
|
44
|
+
items: content,
|
|
45
|
+
},
|
|
46
|
+
},
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* Query relations
|
|
52
|
+
* @function queryRelations
|
|
53
|
+
* @param {string} relation Name of relation
|
|
54
|
+
* @param {boolean} onlyBroken
|
|
55
|
+
* @returns {Object} List relations action
|
|
56
|
+
*/
|
|
57
|
+
export function queryRelations(
|
|
58
|
+
relation = null,
|
|
59
|
+
onlyBroken = false,
|
|
60
|
+
subrequest = null,
|
|
61
|
+
source = null,
|
|
62
|
+
target = null,
|
|
63
|
+
query_source = null,
|
|
64
|
+
query_target = null,
|
|
65
|
+
) {
|
|
66
|
+
let path = '/@relations';
|
|
67
|
+
var searchParams = new URLSearchParams();
|
|
68
|
+
relation && searchParams.append('relation', relation);
|
|
69
|
+
onlyBroken && searchParams.append('onlyBroken', onlyBroken);
|
|
70
|
+
source && searchParams.append('source', source);
|
|
71
|
+
target && searchParams.append('target', target);
|
|
72
|
+
query_source && searchParams.append('query_source', query_source);
|
|
73
|
+
query_target && searchParams.append('query_target', query_target);
|
|
74
|
+
const searchParamsToString = searchParams.toString();
|
|
75
|
+
if (searchParamsToString) {
|
|
76
|
+
path += `?${searchParamsToString}`;
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
type: LIST_RELATIONS,
|
|
80
|
+
subrequest,
|
|
81
|
+
request: {
|
|
82
|
+
op: 'get',
|
|
83
|
+
path: path,
|
|
84
|
+
},
|
|
85
|
+
};
|
|
86
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { queryRelations } from './relations';
|
|
2
|
+
import { LIST_RELATIONS } from '@plone/volto/constants/ActionTypes';
|
|
3
|
+
|
|
4
|
+
describe('Relations action', () => {
|
|
5
|
+
describe('queryRelations', () => {
|
|
6
|
+
it('should create an action to get relations of type "relatedItems"', () => {
|
|
7
|
+
const relation = 'relatedItems';
|
|
8
|
+
const action = queryRelations(relation);
|
|
9
|
+
|
|
10
|
+
expect(action.type).toEqual(LIST_RELATIONS);
|
|
11
|
+
expect(action.request.op).toEqual('get');
|
|
12
|
+
expect(action.request.path).toEqual(`/@relations?relation=${relation}`);
|
|
13
|
+
});
|
|
14
|
+
});
|
|
15
|
+
});
|
package/src/components/index.js
CHANGED
|
@@ -89,6 +89,7 @@ export ContentTypeSchema from '@plone/volto/components/manage/Controlpanels/Cont
|
|
|
89
89
|
export ContentTypesActions from '@plone/volto/components/manage/Controlpanels/ContentTypesActions';
|
|
90
90
|
export UsersControlpanel from '@plone/volto/components/manage/Controlpanels/Users/UsersControlpanel';
|
|
91
91
|
export UserGroupMembershipControlPanel from '@plone/volto/components/manage/Controlpanels/Users/UserGroupMembershipControlPanel';
|
|
92
|
+
export Relations from '@plone/volto/components/manage/Controlpanels/Relations/Relations';
|
|
92
93
|
export GroupsControlpanel from '@plone/volto/components/manage/Controlpanels/Groups/GroupsControlpanel';
|
|
93
94
|
export RulesControlpanel from '@plone/volto/components/manage/Controlpanels/Rules/Rules';
|
|
94
95
|
export AddRuleControlpanel from '@plone/volto/components/manage/Controlpanels/Rules/AddRule';
|
|
@@ -33,17 +33,22 @@ const BlockChooser = ({
|
|
|
33
33
|
properties = {},
|
|
34
34
|
}) => {
|
|
35
35
|
const intl = useIntl();
|
|
36
|
-
const
|
|
36
|
+
const hasAllowedBlocks = !isEmpty(allowedBlocks);
|
|
37
37
|
|
|
38
38
|
const filteredBlocksConfig = filter(blocksConfig, (item) => {
|
|
39
|
+
// Check if the block is well formed (has at least id and title)
|
|
40
|
+
const blockIsWellFormed = Boolean(item.title && item.id);
|
|
41
|
+
if (!blockIsWellFormed) {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
39
44
|
if (showRestricted) {
|
|
40
|
-
if (
|
|
45
|
+
if (hasAllowedBlocks) {
|
|
41
46
|
return allowedBlocks.includes(item.id);
|
|
42
47
|
} else {
|
|
43
48
|
return true;
|
|
44
49
|
}
|
|
45
50
|
} else {
|
|
46
|
-
if (
|
|
51
|
+
if (hasAllowedBlocks) {
|
|
47
52
|
return allowedBlocks.includes(item.id);
|
|
48
53
|
} else {
|
|
49
54
|
// Overload restricted as a function, so we can decide the availability of a block
|
|
@@ -1013,6 +1013,7 @@ class Contents extends Component {
|
|
|
1013
1013
|
sort_order: this.state.sort_order,
|
|
1014
1014
|
metadata_fields: '_all',
|
|
1015
1015
|
b_size: 100000000,
|
|
1016
|
+
show_inactive: true,
|
|
1016
1017
|
...(this.state.filter && { SearchableText: `${this.state.filter}*` }),
|
|
1017
1018
|
});
|
|
1018
1019
|
} else {
|
|
@@ -1024,6 +1025,7 @@ class Contents extends Component {
|
|
|
1024
1025
|
...(this.state.filter && { SearchableText: `${this.state.filter}*` }),
|
|
1025
1026
|
b_size: this.state.pageSize,
|
|
1026
1027
|
b_start: this.state.currentPage * this.state.pageSize,
|
|
1028
|
+
show_inactive: true,
|
|
1027
1029
|
});
|
|
1028
1030
|
}
|
|
1029
1031
|
}
|
|
@@ -1785,7 +1787,9 @@ class Contents extends Component {
|
|
|
1785
1787
|
<Menu.Header
|
|
1786
1788
|
content={this.props.intl.formatMessage(
|
|
1787
1789
|
messages.selected,
|
|
1788
|
-
{
|
|
1790
|
+
{
|
|
1791
|
+
count: this.state.selected.length,
|
|
1792
|
+
},
|
|
1789
1793
|
)}
|
|
1790
1794
|
/>
|
|
1791
1795
|
<Input
|
|
@@ -169,6 +169,12 @@ export const ContentsItemComponent = ({
|
|
|
169
169
|
<FormattedMessage id="Expired" defaultMessage="Expired" />
|
|
170
170
|
</Button>
|
|
171
171
|
)}
|
|
172
|
+
{item.EffectiveDate !== 'None' &&
|
|
173
|
+
new Date(item.EffectiveDate).getTime() > new Date().getTime() && (
|
|
174
|
+
<Button className="button-margin effective-future" size="mini">
|
|
175
|
+
<FormattedMessage id="Scheduled" defaultMessage="Scheduled" />
|
|
176
|
+
</Button>
|
|
177
|
+
)}
|
|
172
178
|
</Link>
|
|
173
179
|
</Table.Cell>
|
|
174
180
|
{map(indexes, (index) => (
|
|
@@ -90,6 +90,10 @@ const messages = defineMessages({
|
|
|
90
90
|
id: 'Content Rules',
|
|
91
91
|
defaultMessage: 'Content Rules',
|
|
92
92
|
},
|
|
93
|
+
relations: {
|
|
94
|
+
id: 'Relations',
|
|
95
|
+
defaultMessage: 'Relations',
|
|
96
|
+
},
|
|
93
97
|
});
|
|
94
98
|
|
|
95
99
|
/**
|
|
@@ -153,6 +157,11 @@ function Controlpanels({
|
|
|
153
157
|
group: intl.formatMessage(messages.general),
|
|
154
158
|
title: intl.formatMessage(messages.urlmanagement),
|
|
155
159
|
},
|
|
160
|
+
{
|
|
161
|
+
'@id': '/relations',
|
|
162
|
+
group: intl.formatMessage(messages.content),
|
|
163
|
+
title: intl.formatMessage(messages.relations),
|
|
164
|
+
},
|
|
156
165
|
{
|
|
157
166
|
'@id': '/moderate-comments',
|
|
158
167
|
group: intl.formatMessage(messages.content),
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
import React, { useEffect } from 'react';
|
|
2
|
+
import { uniqBy } from 'lodash';
|
|
3
|
+
import { FormattedMessage } from 'react-intl';
|
|
4
|
+
import { useSelector, useDispatch } from 'react-redux';
|
|
5
|
+
import { Divider, Segment, Table } from 'semantic-ui-react';
|
|
6
|
+
import { queryRelations } from '@plone/volto/actions';
|
|
7
|
+
import { flattenToAppURL } from '@plone/volto/helpers';
|
|
8
|
+
import { UniversalLink } from '@plone/volto/components';
|
|
9
|
+
|
|
10
|
+
const BrokenRelations = () => {
|
|
11
|
+
const dispatch = useDispatch();
|
|
12
|
+
const brokenRelationStats = useSelector(
|
|
13
|
+
(state) => state.relations?.stats?.broken || {},
|
|
14
|
+
);
|
|
15
|
+
const brokenRelations = useSelector(
|
|
16
|
+
(state) => state.relations?.subrequests?.broken?.relations,
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
dispatch(queryRelations(null, true, 'broken'));
|
|
21
|
+
}, [dispatch]);
|
|
22
|
+
|
|
23
|
+
return brokenRelations && Object.keys(brokenRelations).length > 0 ? (
|
|
24
|
+
<>
|
|
25
|
+
<Divider section hidden />
|
|
26
|
+
<Segment>
|
|
27
|
+
<h3>
|
|
28
|
+
<FormattedMessage
|
|
29
|
+
id="Broken relations"
|
|
30
|
+
defaultMessage="Broken relations"
|
|
31
|
+
/>
|
|
32
|
+
</h3>
|
|
33
|
+
{Object.keys(brokenRelations).map((relationname) => (
|
|
34
|
+
<div key={relationname}>
|
|
35
|
+
<Divider section hidden />
|
|
36
|
+
<h4>
|
|
37
|
+
{brokenRelationStats[relationname]} broken <i>{relationname}</i>{' '}
|
|
38
|
+
relations
|
|
39
|
+
</h4>
|
|
40
|
+
<Table>
|
|
41
|
+
<Table.Body>
|
|
42
|
+
{uniqBy(brokenRelations[relationname].items, function (el) {
|
|
43
|
+
return el[0];
|
|
44
|
+
}).map((el) => (
|
|
45
|
+
<Table.Row key={el[0]}>
|
|
46
|
+
<Table.Cell>
|
|
47
|
+
<UniversalLink
|
|
48
|
+
href={`${flattenToAppURL(el[0])}/edit`}
|
|
49
|
+
openLinkInNewTab={true}
|
|
50
|
+
>
|
|
51
|
+
{flattenToAppURL(el[0])}
|
|
52
|
+
</UniversalLink>
|
|
53
|
+
</Table.Cell>
|
|
54
|
+
<Table.Cell>{el[1]}</Table.Cell>
|
|
55
|
+
</Table.Row>
|
|
56
|
+
))}
|
|
57
|
+
</Table.Body>
|
|
58
|
+
</Table>
|
|
59
|
+
</div>
|
|
60
|
+
))}
|
|
61
|
+
</Segment>
|
|
62
|
+
</>
|
|
63
|
+
) : null;
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
export default BrokenRelations;
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relations Control Panel
|
|
3
|
+
*/
|
|
4
|
+
import React, { useEffect } from 'react';
|
|
5
|
+
import { find } from 'lodash';
|
|
6
|
+
import { useSelector } from 'react-redux';
|
|
7
|
+
import { Portal } from 'react-portal';
|
|
8
|
+
import { useHistory } from 'react-router';
|
|
9
|
+
import { Link, useLocation } from 'react-router-dom';
|
|
10
|
+
import { FormattedMessage, useIntl } from 'react-intl';
|
|
11
|
+
import { useDispatch } from 'react-redux';
|
|
12
|
+
import { Divider, Message, Segment } from 'semantic-ui-react';
|
|
13
|
+
import { Helmet, messages } from '@plone/volto/helpers';
|
|
14
|
+
import { listActions } from '@plone/volto/actions';
|
|
15
|
+
import { Icon, Toolbar } from '@plone/volto/components';
|
|
16
|
+
import { getParentUrl } from '@plone/volto/helpers';
|
|
17
|
+
import RelationsMatrix from '@plone/volto/components/manage/Controlpanels/Relations/RelationsMatrix';
|
|
18
|
+
import backSVG from '@plone/volto/icons/back.svg';
|
|
19
|
+
|
|
20
|
+
const RelationsControlPanel = () => {
|
|
21
|
+
const intl = useIntl();
|
|
22
|
+
const history = useHistory();
|
|
23
|
+
const location = useLocation();
|
|
24
|
+
const dispatch = useDispatch();
|
|
25
|
+
|
|
26
|
+
const brokenRelations = useSelector(
|
|
27
|
+
(state) => state.relations?.stats?.broken,
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
const relations_stats = useSelector((state) => state.relations?.stats?.stats);
|
|
31
|
+
const actions = useSelector((state) => state.actions?.actions ?? {});
|
|
32
|
+
const can_edit = find(actions.object, {
|
|
33
|
+
id: 'edit',
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
useEffect(() => {
|
|
37
|
+
dispatch(listActions('/'));
|
|
38
|
+
}, [dispatch]);
|
|
39
|
+
|
|
40
|
+
return (
|
|
41
|
+
<>
|
|
42
|
+
<div className="relations-control-panel">
|
|
43
|
+
<Helmet title={intl.formatMessage(messages.relations)} />
|
|
44
|
+
{can_edit ? (
|
|
45
|
+
<Segment.Group raised>
|
|
46
|
+
<Segment className="primary">
|
|
47
|
+
{brokenRelations && Object.keys(brokenRelations).length > 0 ? (
|
|
48
|
+
<React.Fragment>
|
|
49
|
+
<Message warning>
|
|
50
|
+
<FormattedMessage
|
|
51
|
+
id="Some relations are broken. Please fix."
|
|
52
|
+
defaultMessage="Some relations are broken. Please fix."
|
|
53
|
+
/>
|
|
54
|
+
</Message>
|
|
55
|
+
<Divider hidden />
|
|
56
|
+
</React.Fragment>
|
|
57
|
+
) : null}
|
|
58
|
+
<h1>
|
|
59
|
+
<FormattedMessage id="Relations" defaultMessage="Relations" />
|
|
60
|
+
</h1>
|
|
61
|
+
{!relations_stats ? (
|
|
62
|
+
<React.Fragment>
|
|
63
|
+
<Divider hidden />
|
|
64
|
+
<Message warning>
|
|
65
|
+
<FormattedMessage
|
|
66
|
+
id="Please upgrade to plone.restapi >= 8.35.3."
|
|
67
|
+
defaultMessage="Please upgrade to plone.restapi >= 8.35.3."
|
|
68
|
+
/>
|
|
69
|
+
</Message>
|
|
70
|
+
</React.Fragment>
|
|
71
|
+
) : null}
|
|
72
|
+
</Segment>
|
|
73
|
+
<Segment>
|
|
74
|
+
<RelationsMatrix />
|
|
75
|
+
</Segment>
|
|
76
|
+
</Segment.Group>
|
|
77
|
+
) : (
|
|
78
|
+
<Segment.Group>
|
|
79
|
+
<Segment>
|
|
80
|
+
<FormattedMessage id="Relations" defaultMessage="Relations" />
|
|
81
|
+
<Divider hidden />
|
|
82
|
+
<FormattedMessage
|
|
83
|
+
id="You have not the required permission for this control panel."
|
|
84
|
+
defaultMessage="You have not the required permission for this control panel."
|
|
85
|
+
/>
|
|
86
|
+
</Segment>
|
|
87
|
+
</Segment.Group>
|
|
88
|
+
)}
|
|
89
|
+
</div>
|
|
90
|
+
|
|
91
|
+
{__CLIENT__ && (
|
|
92
|
+
<Portal node={document.getElementById('toolbar')}>
|
|
93
|
+
<Toolbar
|
|
94
|
+
pathname={location.pathname}
|
|
95
|
+
hideDefaultViewButtons
|
|
96
|
+
inner={
|
|
97
|
+
<Link
|
|
98
|
+
className="item"
|
|
99
|
+
to="#"
|
|
100
|
+
onClick={() => {
|
|
101
|
+
history.push(getParentUrl(location.pathname));
|
|
102
|
+
}}
|
|
103
|
+
>
|
|
104
|
+
<Icon name={backSVG} className="contents circled" size="30px" />
|
|
105
|
+
</Link>
|
|
106
|
+
}
|
|
107
|
+
/>
|
|
108
|
+
</Portal>
|
|
109
|
+
)}
|
|
110
|
+
</>
|
|
111
|
+
);
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
export default RelationsControlPanel;
|