Skip to content

Commit

Permalink
Merge branch 'refs/heads/beta' into release/2.024.17
Browse files Browse the repository at this point in the history
  • Loading branch information
JacquelineMorrissette committed May 10, 2024
2 parents ea6171b + 4502bd5 commit 83c4241
Show file tree
Hide file tree
Showing 18 changed files with 377 additions and 107 deletions.
15 changes: 12 additions & 3 deletions dependencies/pip/dev_requirements.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
# This file is autogenerated by pip-compile with python 3.10
# To update, run:
#
# pip-compile dependencies/pip/dev_requirements.in
#
-e git+https://github.com/dimagi/django-digest@419f7306443f9a800b07d832b2cc147941062d59#egg=django_digest
# via -r dependencies/pip/requirements.in
-e git+https://github.com/trevoriancox/django-dont-vary-on.git@01a804122b7ddcdc22f50b40993f91c27b03bef6#egg=django-dont-vary-on
# via -r dependencies/pip/requirements.in
-e git+https://github.com/kobotoolbox/formpack.git@3b6c89a00c77693a775ef91b68d6965678a7e4fe#egg=formpack
-e git+https://github.com/kobotoolbox/formpack.git@443a8e940756976a9f88fb577dbbc53510726536#egg=formpack
# via -r dependencies/pip/requirements.in
-e git+https://github.com/kobotoolbox/kobo-service-account.git@8ee76730106ff8dc0ee2539c8e6a567aea4ed9ee#egg=kobo-service-account
# via -r dependencies/pip/requirements.in
Expand Down Expand Up @@ -530,6 +530,15 @@ six==1.16.0
# via
# asttokens
# azure-core
# bcrypt
# click-repl
# django-organizations
# google-auth
# google-auth-httplib2
# grpcio
# mongomock
# paramiko
# pathlib2
# isodate
# python-dateutil
smsapi-client==2.9.5
Expand Down
2 changes: 1 addition & 1 deletion dependencies/pip/requirements.in
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
# https://github.com/bndr/pipreqs is a handy utility, too.

# formpack
-e git+https://github.com/kobotoolbox/formpack.git@3b6c89a00c77693a775ef91b68d6965678a7e4fe#egg=formpack
-e git+https://github.com/kobotoolbox/formpack.git@443a8e940756976a9f88fb577dbbc53510726536#egg=formpack

# service-account
-e git+https://github.com/kobotoolbox/kobo-service-account.git@8ee76730106ff8dc0ee2539c8e6a567aea4ed9ee#egg=kobo-service-account
Expand Down
11 changes: 8 additions & 3 deletions dependencies/pip/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
#
# This file is autogenerated by pip-compile with Python 3.10
# by the following command:
# This file is autogenerated by pip-compile with python 3.10
# To update, run:
#
# pip-compile dependencies/pip/requirements.in
#
-e git+https://github.com/dimagi/django-digest@419f7306443f9a800b07d832b2cc147941062d59#egg=django_digest
# via -r dependencies/pip/requirements.in
-e git+https://github.com/trevoriancox/django-dont-vary-on.git@01a804122b7ddcdc22f50b40993f91c27b03bef6#egg=django-dont-vary-on
# via -r dependencies/pip/requirements.in
-e git+https://github.com/kobotoolbox/formpack.git@3b6c89a00c77693a775ef91b68d6965678a7e4fe#egg=formpack
-e git+https://github.com/kobotoolbox/formpack.git@443a8e940756976a9f88fb577dbbc53510726536#egg=formpack
# via -r dependencies/pip/requirements.in
-e git+https://github.com/kobotoolbox/kobo-service-account.git@8ee76730106ff8dc0ee2539c8e6a567aea4ed9ee#egg=kobo-service-account
# via -r dependencies/pip/requirements.in
Expand Down Expand Up @@ -443,6 +443,11 @@ shortuuid==1.0.13
six==1.16.0
# via
# azure-core
# click-repl
# django-organizations
# google-auth
# google-auth-httplib2
# grpcio
# isodate
# python-dateutil
smsapi-client==2.9.5
Expand Down
38 changes: 22 additions & 16 deletions jsapp/js/components/modals/koboModal.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
@use 'scss/breakpoints';
@use 'sass:color';
@use 'js/components/common/icon';
@use 'js/components/common/button';

$kobo-modal-elements-height-min: sizes.$x60;
$kobo-modal-width-min: 280px;
Expand Down Expand Up @@ -32,6 +33,13 @@ $kobo-modal-header-icon-margin: sizes.$x10;

@media all and (max-height: breakpoints.$b480) {
transform: translate(-50%, -50%);

// This ensures that modal layout is better adapting to very short screens.
.kobo-modal__header,
.kobo-modal__content,
.kobo-modal__footer {
min-height: $kobo-modal-elements-height-min;
}
}

@media all and (min-height: (breakpoints.$b480 + 1px)) {
Expand All @@ -47,13 +55,6 @@ $kobo-modal-header-icon-margin: sizes.$x10;
width: $kobo-modal-width-medium;
}

// This ensures that modal layout is better adapting to very short screens.
.kobo-modal__header,
.kobo-modal__content,
.kobo-modal__footer {
min-height: $kobo-modal-elements-height-min;
}

.kobo-modal__footer--isCentered {
justify-content: center !important;
}
Expand All @@ -65,15 +66,15 @@ $kobo-modal-header-icon-margin: sizes.$x10;
padding: $kobo-modal-padding;
border-radius: sizes.$x6 sizes.$x6 0 0;

&.kobo-modal__header--red {
background-color: color.change(colors.$kobo-red, $alpha: 0.1);
}
&.kobo-modal__header--grey {
background-color: colors.$kobo-gray-98;
}
&.kobo-modal__header--white {
background-color: colors.$kobo-white;
}
&.kobo-modal__header--red {
background-color: color.change(colors.$kobo-red, $alpha: 0.1);
}
&.kobo-modal__header--grey {
background-color: colors.$kobo-gray-98;
}
&.kobo-modal__header--white {
background-color: colors.$kobo-white;
}

h1 {
@include mixins.centerRowFlex;
Expand All @@ -83,6 +84,11 @@ $kobo-modal-header-icon-margin: sizes.$x10;
font-weight: 700;
margin: 0;
line-height: 1;

// If there is close button, we need to limit the width (for a long content)
&:not(:only-child) {
max-width: calc(100% - button.$button-height-s);
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ export default function TagsResponseForm(props: TagsResponseFormProps) {
}}
onlyUnique
addOnBlur
addOnPaste
// We set this intentionally, because we don't want the pasted text
// to be split, automatically transformed into tags, or already typed
// in text to be lost after pasting.
addOnPaste={false}
disabled={!props.canEdit}
/>
</section>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export default function ProcessingSidebar(props: ProcessingSidebarProps) {

return (
<div className={styles.root}>
<SidebarDisplaySettings />
<SidebarDisplaySettings assetContent={props.asset.content}/>

<div className={styles.displays}>
{Array.from(translations).map((translation) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,16 @@
margin: 0 !important;
overflow-y: auto;
}

.questionList {
margin: 12px 0 0 36px;
}

.checkbox {
padding: sizes.$x12;
margin-top: sizes.$x6;
max-height: sizes.$x140; // ~4.5 times the size of a checkbox, makes 4 checkboxes visible
border: 1px solid colors.$kobo-gray-92;
border-radius: sizes.$x2;
overflow-y: auto;
}
132 changes: 117 additions & 15 deletions jsapp/js/components/processing/sidebar/sidebarDisplaySettings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,20 @@ import ToggleSwitch from 'js/components/common/toggleSwitch';
import Button from 'js/components/common/button';
import {AsyncLanguageDisplayLabel} from 'js/components/languages/languagesUtils';
import type {LanguageCode} from 'js/components/languages/languagesStore';
import type {AssetContent} from 'js/dataInterface';
import {getActiveTab} from 'js/components/processing/routes.utils';
import styles from './sidebarDisplaySettings.module.scss';
import MultiCheckbox from 'js/components/common/multiCheckbox';
import type {MultiCheckboxItem} from 'js/components/common/multiCheckbox';
import cx from 'classnames';

export default function SidebarDisplaySettings() {
interface SidebarDisplaySettingsProps {
assetContent: AssetContent | undefined;
}

export default function SidebarDisplaySettings(
props: SidebarDisplaySettingsProps
) {
const [store] = useState(() => singleProcessingStore);
const [isModalOpen, setIsModalOpen] = useState<boolean>(false);

Expand All @@ -28,6 +38,24 @@ export default function SidebarDisplaySettings() {
store.getDisplays(activeTab)
);

function getInitialFields() {
if (!props.assetContent?.survey) {
return [];
}

const allQuestions = store.getAllSidebarQuestions();
const hiddenFields = store.getHiddenSidebarQuestions();

// Remove the fields hidden in the store so it persists when
// across navigating submissions.
const questionsList = allQuestions.filter(
(question) => !hiddenFields.includes(question.name)
);
return questionsList;
}

const [selectedFields, setSelectedFields] = useState(getInitialFields());

// Every time user changes the tab, we need to load the stored displays list
// for that tab.
useEffect(() => {
Expand Down Expand Up @@ -70,6 +98,56 @@ export default function SidebarDisplaySettings() {
);
}

function isFieldChecked(questionName: string) {
return selectedFields.some((field) => field.name === questionName);
}

function getCheckboxes() {
if (!props.assetContent?.survey) {
return [];
}

const checkboxes = store.getAllSidebarQuestions().map((question) => {
return {
label: question.label,
checked: isFieldChecked(question.name),
name: question.name,
disabled: !selectedDisplays.includes(StaticDisplays.Data),
};
});

return checkboxes;
}

// To make the code a little simpler later on, we need an inverse array here
// to send to the the display, and a normal array to keep track of the
// checkboxes in this modal.
function onCheckboxesChange(list: MultiCheckboxItem[]) {
const newList = list
.filter((question) => question.checked)
.map((question) => {
return {name: question.name, label: question.label};
});

setSelectedFields(newList);
}

function applyFieldsSelection() {
const hiddenList = getCheckboxes()
.filter((question) => !question.checked)
.map((question) => question.name) || [];

store.setHiddenSidebarQuestions(hiddenList);
}

function resetFieldsSelection() {
// Since we check the store for hidden fields and use that to get our
// checkboxes, using `applyFieldsSelection` here would never actually
// reset the checkboxes visually so we explicitly set it to empty here.
store.setHiddenSidebarQuestions([]);
setSelectedFields(getInitialFields());
}

return (
<div className={styles.root}>
<Button
Expand All @@ -82,7 +160,12 @@ export default function SidebarDisplaySettings() {
/>
<KoboModal
isOpen={isModalOpen}
onRequestClose={() => setIsModalOpen(false)}
onRequestClose={() => {
// Reset modals and checkboxes if user closed modal without applying
setSelectedDisplays(store.getDisplays(activeTab));
setSelectedFields(getInitialFields());
setIsModalOpen(false);
}}
size='medium'
>
<KoboModalHeader>{t('Customize display settings')}</KoboModalHeader>
Expand All @@ -100,20 +183,37 @@ export default function SidebarDisplaySettings() {

if (entry in StaticDisplays) {
const staticDisplay = entry as StaticDisplays;
const isSubmissionData = staticDisplay === StaticDisplays.Data;

return (
<li className={styles.display} key={entry}>
<ToggleSwitch
onChange={(isChecked) => {
if (isChecked) {
enableDisplay(entry);
} else {
disableDisplay(entry);
}
}}
checked={isEnabled}
label={getStaticDisplayText(staticDisplay)}
/>
</li>
<>
<li className={cx(styles.display)} key={entry}>
<ToggleSwitch
onChange={(isChecked) => {
if (isChecked) {
enableDisplay(entry);
} else {
disableDisplay(entry);
}
}}
checked={isEnabled}
label={getStaticDisplayText(staticDisplay)}
/>

{isSubmissionData && props.assetContent?.survey && (
<div className={styles.questionList}>
{t('Select the submission data to display.')}
<div className={styles.checkbox}>
<MultiCheckbox
type='bare'
items={getCheckboxes()}
onChange={onCheckboxesChange}
/>
</div>
</div>
)}
</li>
</>
);
} else {
return (
Expand Down Expand Up @@ -154,6 +254,7 @@ export default function SidebarDisplaySettings() {
// Apply reset to local state of selected displays. This is needed
// because the modal component (and its state) is kept alive even
// when the modal is closed.
resetFieldsSelection();
setSelectedDisplays(store.getDisplays(activeTab));
setIsModalOpen(false);
}}
Expand All @@ -166,6 +267,7 @@ export default function SidebarDisplaySettings() {
color='light-blue'
size='m'
onClick={() => {
applyFieldsSelection();
store.setDisplays(activeTab, selectedDisplays);
setIsModalOpen(false);
}}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,13 @@ export default function SidebarSubmissionData(

/** We want only the processing related data (the actual form questions) */
function getQuestionsToHide(): string[] {
return [
const metaQuestions = [
singleProcessingStore.currentQuestionName || '',
...Object.keys(ADDITIONAL_SUBMISSION_PROPS),
...Object.keys(META_QUESTION_TYPES),
];

return metaQuestions.concat(store.getHiddenSidebarQuestions());
}

return (
Expand Down
Loading

0 comments on commit 83c4241

Please sign in to comment.