Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions jsx/Form.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -162,6 +162,7 @@ type checkboxProps = {
required?: boolean
errorMessage?: string
elementClass?: string
style?: object
onUserInput?: (name: string, value: any) => void
}
/**
Expand Down
16 changes: 13 additions & 3 deletions jsx/Form.js
Original file line number Diff line number Diff line change
Expand Up @@ -2187,7 +2187,9 @@ export class CheckboxElement extends React.Component {
let elementClass = this.props.class + ' ' + this.props.offset;
const divStyle = this.props.class === 'checkbox-inline'
? {paddingRight: '5px'}
: {paddingRight: '5px', display: 'inline-block'};
: this.props.class === 'checkbox-flex' ?
{paddingRight: '5px', display: 'flex'}
: {paddingRight: '5px', display: 'inline-block'};

// Add required asterix
if (this.props.required) {
Expand All @@ -2201,9 +2203,12 @@ export class CheckboxElement extends React.Component {
}

return (
<div className={elementClass}>
<div className={elementClass} style={this.props.style}>
<div className="col-sm-12">
<label htmlFor={this.props.id}>
<label htmlFor={this.props.id}
style={
this.props.class === 'checkbox-flex'
? {display: 'flex'} : {}}>
<div style={divStyle}>
<input
type="checkbox"
Expand All @@ -2213,6 +2218,9 @@ export class CheckboxElement extends React.Component {
required={this.props.required}
disabled={this.props.disabled}
onChange={this.handleChange}
style={
this.props.class === 'checkbox-flex' ? {marginTop: '0'} : {}
}
/>
</div>
{errorMessage}
Expand All @@ -2237,6 +2245,7 @@ CheckboxElement.propTypes = {
errorMessage: PropTypes.string,
elementClass: PropTypes.string,
onUserInput: PropTypes.func,
style: PropTypes.object,
};

CheckboxElement.defaultProps = {
Expand All @@ -2247,6 +2256,7 @@ CheckboxElement.defaultProps = {
offset: 'col-sm-offset-3',
class: 'checkbox-inline',
elementClass: 'checkbox-inline col-sm-offset-3',
style: {},
onUserInput: function() {
console.warn('onUserInput() callback is not set');
},
Expand Down
62 changes: 48 additions & 14 deletions modules/dataquery/jsx/components/filterableselectgroup.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,15 @@ type SelectGroup = {
* @param {string?} props.placeholder - An optional placeholder value when no elements are selected
* @param {object} props.groups - Groups to select the dropdown into
* @param {function} props.mapGroupName - A mapper from backend to frontend name for groups
* @param {string?} props.label - Select input label
* @returns {React.ReactElement} - The element
*/
function FilterableSelectGroup(props: {
onChange: (module: string, value: string) => void,
placeholder?: string,
groups: object,
mapGroupName?: (module: string) => string,
label?: string,
}) {
const {t} = useTranslation();
const groups: SelectGroup[] = [];
Expand Down Expand Up @@ -73,20 +75,52 @@ function FilterableSelectGroup(props: {
};
return (
<div>
<Select options={groups} onChange={selected}
noOptionsMessage={() => t('No options', {ns: 'loris'})}
menuPortalTarget={document.body}
styles={{menuPortal:
/**
* Add a z-index to ensure the element stays visible
*
* @param {object} base - the base CSS
* @returns {object} - the new CSS with z-index added
*/
(base) => ({...base, zIndex: 9999})}
}
placeholder={placeholder}
/>
{props?.label ?
<label style={{width: '100%', fontSize: '24px'}}>
{props.label}
<Select options={groups} onChange={selected}
noOptionsMessage={() => t('No options', {ns: 'loris'})}
menuPortalTarget={document.body}
styles={{menuPortal:
/**
* Add a z-index to ensure the element stays visible
*
* @param {object} base - the base CSS
* @returns {object} - the new CSS with z-index added
*/
(base) => ({...base, zIndex: 9999}),
valueContainer:
/**
* Adds appropriate zIndex to the react select's base CSS
*
* @param {object} base - The current CSS
* @returns {object} New CSS with z-index added
*/
(base) => ({
...base,
fontSize: '14px',
fontWeight: 400,
}),
}}
placeholder={placeholder}
/>
</label>
: (
<Select options={groups} onChange={selected}
noOptionsMessage={() => t('No options', {ns: 'loris'})}
menuPortalTarget={document.body}
styles={{menuPortal:
/**
* Add a z-index to ensure the element stays visible
*
* @param {object} base - the base CSS
* @returns {object} - the new CSS with z-index added
*/
(base) => ({...base, zIndex: 9999})}
}
placeholder={placeholder}
/>
)}
</div>
);
}
Expand Down
180 changes: 115 additions & 65 deletions modules/dataquery/jsx/definefields.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ function QueryField(props: {
* @returns {object} New CSS with z-index added
*/
(base) => ({...base, zIndex: 9999}),
valueContainer:
/**
* Adds appropriate zIndex to the react select's base CSS
*
* @param {object} base - The current CSS
* @returns {object} New CSS with z-index added
*/
(base) => ({
...base,
maxHeight: '150px',
overflowY: 'auto',
}),
}
}
closeMenuOnSelect={false}
Expand All @@ -132,7 +144,8 @@ function QueryField(props: {
style={{
cursor: 'pointer',
display: 'flex',
justifyContent: 'space-between',
flexDirection: 'column',
marginBottom: '4px',
}}
onClick={() => props.onFieldToggle(
props.module,
Expand All @@ -141,8 +154,10 @@ function QueryField(props: {
selectedVisits,
)}>
<dl>
<dt>{item}</dt>
<dd>{value.description} {download}</dd>
<dt style={{fontSize: '18px', wordBreak: 'break-word'}}>{item}</dt>
<dd
style={{wordBreak: 'break-word'}}
>{value.description} {download}</dd>
</dl>
{visits}
</div>);
Expand Down Expand Up @@ -340,78 +355,112 @@ function DefineFields(props: {
const selectedVisits = props.defaultVisits.map((el) => {
return {value: el, label: el};
});
defaultVisits = <div style={{paddingBottom: '1em', display: 'flex'}}>
<h4 style={{paddingRight: '1ex'}}>{t('Default Visits',
{ns: 'dataquery'})}</h4>
<Select options={allVisits}
isMulti
onChange={props.onChangeDefaultVisits}
placeholder={t('Select Visits', {ns: 'dataquery'})}
noOptionsMessage={() => t('No options', {ns: 'loris'})}
menuPortalTarget={document.body}
styles={
{menuPortal:
/**
* Adds appropriate zIndex to the react select's base CSS
*
* @param {object} base - The current CSS
* @returns {object} New CSS with z-index added
*/
(base) => ({...base, zIndex: 9999}),
}
}
value={selectedVisits}
closeMenuOnSelect={false}
/>
<div>
<CheckboxElement label={t('Sync with selected fields',
{ns: 'dataquery'})}
name="syncVisits"
value={syncVisits}
onUserInput={
(name: string, value: boolean) => setSyncVisits(value)
} />
defaultVisits = <div style={{
display: 'flex',
flexDirection: 'column',
marginBottom: '16px'}}>
<div style={{marginBottom: '8px'}}>
<CheckboxElement
label={t('Sync visit selection across selected fields',
{ns: 'dataquery'})}
name="syncVisits"
class="checkbox-flex"
offset=""
value={syncVisits}
style={{}}
onUserInput={
(name: string, value: boolean) => setSyncVisits(value)
} />
</div>
{syncVisits && <div style={{marginBottom: '16px'}}>
<Select options={allVisits}
isMulti
onChange={props.onChangeDefaultVisits}
placeholder={t('Select Visits', {ns: 'dataquery'})}
noOptionsMessage={() => t('No options', {ns: 'loris'})}
menuPortalTarget={document.body}
styles={
{menuPortal:
/**
* Adds appropriate zIndex to the react select's base CSS
*
* @param {object} base - The current CSS
* @returns {object} New CSS with z-index added
*/
(base) => ({...base, zIndex: 9999}),
valueContainer:
/**
* Adds appropriate zIndex to the react select's base CSS
*
* @param {object} base - The current CSS
* @returns {object} New CSS with z-index added
*/
(base) => ({
...base,
maxHeight: '200px',
overflowY: 'auto',
}),
}
}
value={selectedVisits}
closeMenuOnSelect={false}
/></div>}
</div>;
}

fieldList = (<div>
<div style={{display: 'flex', flexWrap: 'wrap',
justifyContent: 'space-between'}}>
<h2>{
t('{{columnName}} fields', {ns: 'dataquery', columnName: cname})
}</h2>
<div style={{marginTop: '1em',
<div style={{display: 'flex', flexDirection: 'column',
marginTop: '32px'}}>
<div style={{
display: 'flex',
flexWrap: 'nowrap',
flexDirection: 'column',
}}>
{defaultVisits}
<div className="input-group">
<input onChange={setFilter}
className='form-control'
type="text"
placeholder={t('Filter within category', {ns: 'dataquery'})}
aria-describedby="input-filter-addon"
value={activeFilter} />
<span className="input-group-addon">
<span className="glyphicon glyphicon-search"/>
</span>
</div>
<div style={{margin: '1ex',
<div style={{
width: '100%',
display: 'flex',
flexWrap: 'wrap',
flexDirection: 'row',
justifyContent: 'space-around',
}}>
<button type="button" className="btn btn-primary"
onClick={addAll}>
{t('Add all', {ns: 'dataquery'})}
</button>
<button type="button" className="btn btn-primary"
onClick={removeAll}>
{t('Remove all', {ns: 'dataquery'})}
</button>
marginBottom: '8px',
alignItems: 'center',
justifyContent: 'space-between'}}>
<div className="input-group"
style={{width: '50%', display: 'flex'}}>
<input onChange={setFilter}
className='form-control'
type="text"
placeholder={t(`Filter within ${cname}`, {ns: 'dataquery'})}
aria-describedby="input-filter-addon"
value={activeFilter}
style={{borderRadius: '32px 0 0 32px'}}/>
<span className="input-group-addon"
style={{
borderRadius: '0 32px 32px 0',
height: '34px',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
padding: '0 20px',
cursor: 'pointer',
}}
id="input-filter-addon">
<span className="glyphicon glyphicon-search"/>
</span>
</div>
<div style={{
display: 'flex',
flexWrap: 'wrap',
flexDirection: 'row',
justifyContent: 'space-around',
}}>
<button type="button" className="btn btn-primary"
onClick={addAll}>
{t('Add all', {ns: 'dataquery'})}
</button>
<button type="button" className="btn btn-primary"
onClick={removeAll}>
{t('Remove all', {ns: 'dataquery'})}
</button>
</div>
</div>
</div>
</div>
Expand All @@ -423,10 +472,11 @@ function DefineFields(props: {
<div>
<div style={{display: 'flex', flexWrap: 'nowrap'}}>
<div style={{width: '80vw', padding: '1em'}}>
<h1>{t('Available Fields', {ns: 'dataquery'})}</h1>
<FilterableSelectGroup groups={props.allCategories.categories}
mapGroupName={(key) => props.allCategories.modules[key]}
onChange={props.onCategoryChange}
label={t('Select a field', {ns: 'dataquery'})}
placeholder={t('Available Fields', {ns: 'dataquery'})}
/>
{fieldList}
</div>
Expand Down
4 changes: 2 additions & 2 deletions modules/dataquery/locale/dataquery.pot
Original file line number Diff line number Diff line change
Expand Up @@ -515,13 +515,13 @@ msgstr ""
msgid "Remove all"
msgstr ""

msgid "Filter within category"
msgid "Filter within ${cname}"
msgstr ""

msgid "Default Visits"
msgstr ""

msgid "Sync with selected fields"
msgid "Sync visit selection across selected fields"
msgstr ""

msgid "Select a category"
Expand Down
Loading
Loading