diff --git a/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributeSelector.scss b/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributeSelector.scss
index c57bfb66a4..cde65b75c0 100644
--- a/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributeSelector.scss
+++ b/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributeSelector.scss
@@ -2,8 +2,8 @@
.attribute-selector {
display: flex;
+ width: 100%;
justify-content: space-between;
- margin: 0 0.5rem;
border-top: none;
border-left: none;
border-right: none;
diff --git a/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesList.js b/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesList.js
new file mode 100644
index 0000000000..e11e1cfc20
--- /dev/null
+++ b/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesList.js
@@ -0,0 +1,66 @@
+import './AttributesList.scss'
+
+import React, { useMemo } from 'react'
+import * as PropTypes from 'prop-types'
+
+import * as ObjectUtils from '@core/objectUtils'
+import * as Survey from '@core/survey/survey'
+import * as NodeDef from '@core/survey/nodeDef'
+
+import { useSurvey, useSurveyPreferredLang } from '@webapp/store/survey'
+
+import AttributeSelector from './AttributeSelector'
+
+export const AttributesList = (props) => {
+ const {
+ canSelectAttributes,
+ nodeDefContext,
+ nodeDefLabelType,
+ nodeDefUuidsAttributes,
+ onToggleAttribute,
+ showAncestorsLabel,
+ attributeDefs,
+ } = props
+
+ const survey = useSurvey()
+ const lang = useSurveyPreferredLang()
+ const childDefsByParentUuid = useMemo(
+ () => ObjectUtils.groupByProp(NodeDef.keys.parentUuid)(attributeDefs),
+ [attributeDefs]
+ )
+
+ return Object.entries(childDefsByParentUuid).map(([parentDefUuid, childDefs]) => {
+ const childDefParentDef = Survey.getNodeDefByUuid(parentDefUuid)(survey)
+
+ return childDefs.map((childDef, index) => {
+ const parentHeadingVisible = index === 0 && childDefParentDef !== nodeDefContext
+ return (
+
+ {parentHeadingVisible && (
+
+ {NodeDef.getLabelWithType({ nodeDef: childDefParentDef, lang, type: nodeDefLabelType })}
+
+ )}
+
+
+ )
+ })
+ })
+}
+
+AttributesList.propTypes = {
+ attributeDefs: PropTypes.array.isRequired,
+ canSelectAttributes: PropTypes.bool,
+ nodeDefContext: PropTypes.object.isRequired,
+ nodeDefLabelType: PropTypes.string,
+ nodeDefUuidsAttributes: PropTypes.array,
+ onToggleAttribute: PropTypes.func,
+ showAncestorsLabel: PropTypes.bool,
+}
diff --git a/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesList.scss b/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesList.scss
new file mode 100644
index 0000000000..97ccc7ec95
--- /dev/null
+++ b/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesList.scss
@@ -0,0 +1,10 @@
+.attribute-selector-wrapper {
+ display: flex;
+ flex-direction: column;
+ margin: 0 0.2rem;
+
+ .attribute-selector-parent-entity-heading {
+ font-style: italic;
+ font-size: small;
+ }
+}
diff --git a/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesSelector.js b/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesSelector.js
index 50835826cb..9cc3e5d81f 100644
--- a/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesSelector.js
+++ b/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesSelector.js
@@ -10,11 +10,12 @@ import * as NodeDef from '@core/survey/nodeDef'
import ExpansionPanel from '@webapp/components/expansionPanel'
import { Checkbox } from '@webapp/components/form'
-import { useSurvey, useSurveyCycleKey } from '@webapp/store/survey'
+import { useSurvey, useSurveyCycleKey, useSurveyPreferredLang } from '@webapp/store/survey'
import { useAuthCanUseAnalysis } from '@webapp/store/user'
+import { useI18n } from '@webapp/store/system'
import AttributeSelector from './AttributeSelector'
-import { useI18n } from '@webapp/store/system'
+import { AttributesList } from './AttributesList'
const minDefsToShowSelectAll = 5
@@ -26,7 +27,6 @@ const AttributesSelector = (props) => {
filterTypes = [],
filterChainUuids = [],
includeEntityFrequencySelector = false,
- lang,
nodeDefLabelType = NodeDef.NodeDefLabelTypes.label,
nodeDefUuidEntity = null,
nodeDefUuidsAttributes = [],
@@ -44,6 +44,7 @@ const AttributesSelector = (props) => {
const i18n = useI18n()
const survey = useSurvey()
const cycle = useSurveyCycleKey()
+ const lang = useSurveyPreferredLang()
const canUseAnalysis = useAuthCanUseAnalysis()
const nodeDefContext = Survey.getNodeDefByUuid(nodeDefUuidEntity)(survey)
@@ -118,38 +119,35 @@ const AttributesSelector = (props) => {
onChange={onSelectAll}
/>
)}
- {visibleChildDefs.map((childDef) => (
-
- ))}
+
)}
{showAncestors && nodeDefAncestor && (
)}
@@ -163,7 +161,6 @@ AttributesSelector.propTypes = {
filterTypes: PropTypes.array,
filterChainUuids: PropTypes.array,
includeEntityFrequencySelector: PropTypes.bool,
- lang: PropTypes.string.isRequired,
nodeDefUuidEntity: PropTypes.string,
nodeDefUuidsAttributes: PropTypes.array,
nodeDefUuidsToExclude: PropTypes.array,
diff --git a/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesSelector.scss b/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesSelector.scss
index b71f02502e..d88829f497 100644
--- a/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesSelector.scss
+++ b/webapp/components/survey/NodeDefsSelector/AttributesSelector/AttributesSelector.scss
@@ -7,4 +7,6 @@
display: grid;
align-content: start;
grid-row-gap: 0.3rem;
+
+
}
diff --git a/webapp/components/survey/NodeDefsSelector/NodeDefsSelector.js b/webapp/components/survey/NodeDefsSelector/NodeDefsSelector.js
index b7b7e96aef..3f96dd9f35 100644
--- a/webapp/components/survey/NodeDefsSelector/NodeDefsSelector.js
+++ b/webapp/components/survey/NodeDefsSelector/NodeDefsSelector.js
@@ -13,7 +13,7 @@ import * as NodeDefUIProps from '@webapp/components/survey/SurveyForm/nodeDefs/n
import { ButtonIconFilter } from '@webapp/components/buttons'
import { useI18n } from '@webapp/store/system'
-import { useSurvey, useSurveyPreferredLang } from '@webapp/store/survey'
+import { useSurvey } from '@webapp/store/survey'
import AttributesSelector from './AttributesSelector'
import EntitySelector from './EntitySelector'
@@ -36,7 +36,6 @@ const NodeDefsSelector = (props) => {
const i18n = useI18n()
const survey = useSurvey()
- const lang = useSurveyPreferredLang()
const [filterTypes, setFilterTypes] = useState([])
const [filterChainUuids, setFilterChainUuids] = useState([])
@@ -111,7 +110,6 @@ const NodeDefsSelector = (props) => {
{nodeDefUuidEntity && (
{
} = props
const survey = useSurvey()
- const lang = useSurveyPreferredLang()
const hierarchy = Survey.getHierarchy(NodeDef.isEntity)(survey)
const variablesPrevSteps = getPrevCalculations({ nodeDefUuidEntity, survey })
@@ -96,7 +95,6 @@ const NodeDefsSelectorAggregate = (props) => {
NodeDef.isCode(nodeDef) || NodeDef.isTaxon(nodeDef) || NodeDef.isKey(nodeDef)
}
@@ -112,7 +110,6 @@ const NodeDefsSelectorAggregate = (props) => {
!NodeDef.isKey(nodeDef)}
includeEntityFrequencySelector