Skip to content

Commit 743335e

Browse files
authored
Merge pull request #3680 from pKallert/feature/AddInactiveContentDimensionsDropdown
FEATURE: Display document status of other dimensions in dimension dropdown
2 parents 288d75c + 318f860 commit 743335e

File tree

8 files changed

+163
-16
lines changed

8 files changed

+163
-16
lines changed

Resources/Private/Translations/en/Main.xlf

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -380,6 +380,12 @@
380380
<trans-unit id="copyNodeTypeNameToClipboard" xml:space="preserve">
381381
<source>Copy node type to clipboard</source>
382382
</trans-unit>
383+
<trans-unit id="dimensions.doesNotExistsInDimension" xml:space="preserve">
384+
<source>The current document does not exist in the dimension</source>
385+
</trans-unit>
386+
<trans-unit id="dimensions.combinationNotAllowed" xml:space="preserve">
387+
<source>This combination of dimensions is not allowed</source>
388+
</trans-unit>
383389
<trans-unit id="invalidValue" xml:space="preserve">
384390
<source>Invalid value</source>
385391
</trans-unit>

packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/DimensionSelector.js

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,9 @@ export default class DimensionSelector extends PureComponent {
4949
label: presetConfiguration?.label,
5050
value: presetName,
5151
disallowed: presetConfiguration?.disallowed,
52-
group: presetConfiguration?.group
52+
covered: presetConfiguration?.covered,
53+
group: presetConfiguration?.group,
54+
url: presetConfiguration?.url
5355
};
5456
}
5557
);

packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/DimensionSelectorOption.js

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,24 +3,57 @@ import PropTypes from 'prop-types';
33
import style from './style.module.css';
44
// eslint-disable-next-line camelcase
55
import SelectBox_Option_SingleLine from '@neos-project/react-ui-components/src/SelectBox_Option_SingleLine/index';
6+
import mergeClassNames from 'classnames';
7+
import {neos} from '@neos-project/neos-ui-decorators';
8+
9+
@neos(globalRegistry => ({
10+
i18nRegistry: globalRegistry.get('i18n')
11+
}))
612

713
export default class DimensionSelectorOption extends PureComponent {
814
static propTypes = {
915
option: PropTypes.shape({
1016
label: PropTypes.string.isRequired,
11-
disallowed: PropTypes.bool
12-
})
17+
disallowed: PropTypes.bool,
18+
covered: PropTypes.bool,
19+
url: PropTypes.string
20+
}),
21+
i18nRegistry: PropTypes.object.isRequired
1322
};
1423

1524
render() {
16-
const {option} = this.props;
25+
const {option, i18nRegistry} = this.props;
26+
const className = mergeClassNames({
27+
[style.disallowed]: option.disallowed,
28+
[style.notCovered]: !option.covered
29+
});
30+
31+
if (!option.disallowed && option.covered && option.url) {
32+
const linkOptions = {
33+
href: option.url,
34+
target: '_blank',
35+
rel: 'noopener noreferrer',
36+
onClick: (event) => event.preventDefault()
37+
}
38+
return (
39+
40+
// eslint-disable-next-line camelcase
41+
<SelectBox_Option_SingleLine
42+
{...this.props}
43+
className={className}
44+
linkOptions={linkOptions}
45+
/>
46+
);
47+
}
48+
option.title = option.disallowed ?
49+
i18nRegistry.translate('Neos.Neos.Ui:Main:dimensions.combinationNotAllowed') :
50+
i18nRegistry.translate('Neos.Neos.Ui:Main:dimensions.doesNotExistsInDimension')
1751

1852
return (
1953
// eslint-disable-next-line camelcase
2054
<SelectBox_Option_SingleLine
2155
{...this.props}
22-
className={option.disallowed ? style.dimmed : ''}
23-
label={option.label}
56+
className={className}
2457
/>
2558
);
2659
}

packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/index.js

Lines changed: 48 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,9 @@ SelectedPreset.propTypes = {
3131
@connect($transform({
3232
contentDimensions: selectors.CR.ContentDimensions.byName,
3333
allowedPresets: selectors.CR.ContentDimensions.allowedPresets,
34-
activePresets: selectors.CR.ContentDimensions.activePresets
34+
activePresets: selectors.CR.ContentDimensions.activePresets,
35+
getNodeByContextPath: selectors.CR.Nodes.nodeByContextPath,
36+
documentNode: selectors.CR.Nodes.documentNodeSelector
3537
}), {
3638
selectPreset: actions.CR.ContentDimensions.selectPreset,
3739
setAllowed: actions.CR.ContentDimensions.setAllowed
@@ -45,6 +47,8 @@ export default class DimensionSwitcher extends PureComponent {
4547
activePresets: PropTypes.object.isRequired,
4648
allowedPresets: PropTypes.object.isRequired,
4749
selectPreset: PropTypes.func.isRequired,
50+
getNodeByContextPath: PropTypes.func.isRequired,
51+
documentNode: PropTypes.object.isRequired,
4852
setAllowed: PropTypes.func.isRequired,
4953

5054
i18nRegistry: PropTypes.object.isRequired
@@ -153,11 +157,21 @@ export default class DimensionSwitcher extends PureComponent {
153157
this.setState({isOpen: false});
154158
}
155159

160+
createDirectDimensionsLink = (dimensionName, presetName) => {
161+
const {documentNode} = this.props;
162+
163+
const nodeContextPath = documentNode.properties._path + ';' + dimensionName + '=' + presetName
164+
const uri = new URL(window.location.href);
165+
uri.searchParams.set('node', nodeContextPath);
166+
return uri.toString();
167+
}
168+
156169
renderSingleDimensionSelector = (dimensionName, contentDimensionsObject) => {
157170
const dimensionConfiguration = contentDimensionsObject[dimensionName];
158171
const icon = this.getDimensionIcon(dimensionName, contentDimensionsObject);
159172
// First look for active preset in transient state, else take it from activePresets prop
160173
const activePreset = this.getEffectivePresets(this.state.transientPresets)[dimensionName];
174+
161175
return (
162176
<DimensionSelector
163177
isLoading={this.state.loadingPresets[dimensionName]}
@@ -253,15 +267,46 @@ export default class DimensionSwitcher extends PureComponent {
253267
return null;
254268
}
255269

270+
getDocumentDimensions(dimensionName) {
271+
const {getNodeByContextPath, documentNode, allowedPresets, contentDimensions} = this.props;
272+
const currentDocumentNode = getNodeByContextPath(documentNode.contextPath)
273+
if (!currentDocumentNode.dimensions || currentDocumentNode.length === 0) {
274+
return allowedPresets[dimensionName]
275+
}
276+
277+
const variants = [...currentDocumentNode.otherNodeVariants];
278+
variants.push(currentDocumentNode.dimensions)
279+
280+
for (const dimensionKey of Object.keys(contentDimensions)) {
281+
if (dimensionKey === dimensionName || Object.keys(contentDimensions).length === 1) {
282+
break;
283+
}
284+
Object.entries(variants).forEach(entry => {
285+
const [key, value] = entry;
286+
if (value[dimensionKey] !== this.state.transientPresets[dimensionKey]) {
287+
delete variants[key]
288+
}
289+
});
290+
}
291+
const dimensions = []
292+
Object.values(variants).forEach(entry => {
293+
dimensions.push(entry[dimensionName]);
294+
});
295+
296+
return dimensions;
297+
}
298+
256299
presetsForDimension(dimensionName) {
257300
const {contentDimensions, allowedPresets, i18nRegistry} = this.props;
258301
const dimensionConfiguration = $get(dimensionName, contentDimensions);
259-
302+
const documentDimensions = this.getDocumentDimensions(dimensionName);
260303
return mapValues(dimensionConfiguration.presets,
261304
(presetConfiguration, presetName) => {
262305
return Object.assign({}, presetConfiguration, {
263306
label: i18nRegistry.translate(presetConfiguration.label),
264-
disallowed: !(allowedPresets[dimensionName] && allowedPresets[dimensionName].includes(presetName))
307+
disallowed: !(allowedPresets[dimensionName] && allowedPresets[dimensionName].includes(presetName)),
308+
covered: documentDimensions.some(dimension => presetConfiguration.values.includes(dimension)),
309+
url: (Object.keys(contentDimensions).length === 1) ? this.createDirectDimensionsLink(dimensionName, presetName) : null
265310
});
266311
});
267312
}

packages/neos-ui/src/Containers/PrimaryToolbar/DimensionSwitcher/style.module.css

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,8 +60,31 @@
6060
}
6161
}
6262

63-
.dimmed {
64-
filter: opacity(50%);
63+
.notCovered {
64+
position: relative;
65+
background-image: repeating-linear-gradient(-45deg, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0) 12px, #323232 0, #323232 23px);
66+
}
67+
.notCovered:after {
68+
content: '';
69+
position: absolute;
70+
height: 100%;
71+
width: 3px;
72+
top: 0px;
73+
left: 0px;
74+
background-color: var(--colors-Warn);
75+
}
76+
.disallowed {
77+
position: relative;
78+
background-color: #323232;
79+
}
80+
.disallowed:after {
81+
content: '';
82+
position: absolute;
83+
height: 100%;
84+
width: 3px;
85+
top: 0px;
86+
left: 0px;
87+
background-color: var(--colors-Error);
6588
}
6689

6790
.selectPreset + .selectPreset {

packages/react-ui-components/src/ListPreviewElement/style.module.css

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
}
1818
.listPreviewElement--isHighlighted {
1919
background-color: var(--colors-PrimaryBlue) !important;
20+
background-image: none !important;
2021
}
2122

2223
.listPreviewElement--isHighlighted > span {

packages/react-ui-components/src/SelectBox_Option_SingleLine/selectBox_Option_SingleLine.js

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,34 +3,57 @@ import React, {PureComponent} from 'react';
33
import PropTypes from 'prop-types';
44
import ListPreviewElement from '../ListPreviewElement';
55
import mergeClassNames from 'classnames';
6+
import style from './style.module.css';
67

78
class SelectBox_Option_SingleLine extends PureComponent {
89
static propTypes = {
910
option: PropTypes.shape({
1011
label: PropTypes.string.isRequired,
1112
icon: PropTypes.string,
12-
disabled: PropTypes.bool
13+
disabled: PropTypes.bool,
14+
title: PropTypes.string
1315
}).isRequired,
1416

1517
disabled: PropTypes.bool,
1618

17-
className: PropTypes.string
19+
className: PropTypes.string,
20+
21+
icon: PropTypes.string,
22+
23+
linkOptions: PropTypes.shape({
24+
href: PropTypes.string.isRequired,
25+
target: PropTypes.string,
26+
rel: PropTypes.string,
27+
onClick: PropTypes.func
28+
})
1829
}
1930

2031
render() {
21-
const {option, className, disabled, icon} = this.props;
32+
const {option, className, disabled, icon, linkOptions} = this.props;
2233

2334
const isDisabled = disabled || option.disabled;
2435

2536
const finalClassNames = mergeClassNames({
26-
[className]: className
37+
[className]: className,
38+
[style.linkedItem]: linkOptions
39+
});
40+
const linkClassname = mergeClassNames({
41+
[style.dropdownLink]: true,
42+
[style.hasIcon]: (Boolean(option.icon || icon))
2743
});
2844

2945
const previewElementIcon = option.icon ? option.icon : (icon ? icon : null);
3046

3147
return (
3248
<ListPreviewElement {...this.props} icon={previewElementIcon} disabled={isDisabled} className={finalClassNames}>
33-
<span title={option.label}>{option.label}</span>
49+
{linkOptions ? (
50+
<a
51+
{...linkOptions}
52+
className={linkClassname}
53+
title={option.title ? option.title : option.label}>{option.label}</a>
54+
) : (
55+
<span title={option.title ? option.title : option.label}>{option.label}</span>
56+
)}
3457
</ListPreviewElement>
3558
);
3659
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
.dropdownLink {
2+
color: white;
3+
padding: 5px 14px;
4+
display: inline-block;
5+
width: 100%;
6+
7+
}
8+
.hasIcon {
9+
width: calc(100% - 2em);
10+
padding: 5px 0px;
11+
}
12+
.linkedItem {
13+
padding: 0px !important;
14+
}

0 commit comments

Comments
 (0)