Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DTT (Staging > Test) [robo-dtt] #34635

Merged
merged 21 commits into from
May 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
21 commits
Select commit Hold shift + click to select a range
b163ad8
Refactor span->label so clicking functionName selects the function
Apr 21, 2020
a1c4783
Add 'Select all functions' checkbox
Apr 23, 2020
ef48aa2
Update tests to account for additional checkbox
Apr 23, 2020
1258c0a
Filter invalid functions from state.selectedFunctions and from select…
Apr 23, 2020
1e7e774
Add fallback if comment is undefined
Apr 23, 2020
f461146
Switch conditional order, only check if function is valid if it's sel…
Apr 23, 2020
1391464
Unit test selecting/de-selecting functions
Apr 23, 2020
6568e3b
Clean up boxChecked conditional / return early
Apr 23, 2020
cc20ffc
Merge branch 'staging' into lib-select-all
Apr 24, 2020
5b7d5d9
Add clarification comments
Apr 30, 2020
2f65f59
Add uniqueIds to element ids to ensure uniqueness
Apr 30, 2020
ca5359f
Use uniqueId for input id and label htmlFor attrs
May 4, 2020
0336a36
change manage students secrets column headers and add tooltip
Erin007 May 4, 2020
5ccbc51
customize show/hide secret button text based on logintype
Erin007 May 4, 2020
7182e08
test that the password column shows when it should and has correct he…
Erin007 May 4, 2020
307d44c
check the password cell contents for word, picture and email sections
Erin007 May 4, 2020
955cc14
Merge branch 'staging' into lib-select-all
May 5, 2020
e888574
Merge pull request #34599 from code-dot-org/section-setup-req-5
Erin007 May 5, 2020
42e8a50
Merge pull request #34412 from code-dot-org/lib-select-all
May 5, 2020
78d4d3d
Revert "Add parent email to new contact rollups process"
bencodeorg May 5, 2020
6c23dfb
Merge pull request #34634 from code-dot-org/revert-34541-contact-roll…
bencodeorg May 5, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
9 changes: 7 additions & 2 deletions apps/i18n/common/en_us.json
Original file line number Diff line number Diff line change
Expand Up @@ -823,9 +823,10 @@
"hideFullList": "Hide full list",
"hideGeneratedCode": "Hide Code",
"hideHiddenSections": "Hide hidden sections",
"hidePicture": "Hide picture",
"hideProjectSharingColumn": "Hide project sharing column",
"hideSection": "Hide Section",
"hideSecret": "Hide secret",
"hideWords": "Hide words",
"hideToolbarHelper": "Press **_A_A** and choose **Hide Toolbar** to see the full screen.",
"hideToolbox": "(Hide)",
"hintHeader": "Here's a tip:",
Expand Down Expand Up @@ -1224,6 +1225,7 @@
"plLandingStartSurvey": "Start survey",
"plugged": "Plugged",
"pluggedLessonsNote": "*Online or ‘plugged’ lessons are automatically marked as complete on your behalf once 80% of your class has completed 60% of the available lesson.",
"picturePassword": "Picture password",
"policyViolation": "This project contains information that cannot be shared with others. Please contact the app owner to fix the contents of their app.",
"positionAbsoluteDown": "down",
"positionAbsoluteOver": "over",
Expand Down Expand Up @@ -1463,6 +1465,7 @@
"schoolNotFoundCheckboxLabel": "I cannot find my school above",
"schoolNotFoundDescription": "Sorry, we couldn't find your school. Please enter information below.",
"score": "score",
"secretWords": "Secret words",
"section": "Section",
"sectionWithColon": "Section:",
"sectionCode": "Section Code",
Expand All @@ -1485,6 +1488,7 @@
"seePrivacyPolicy": "(See our privacy policy)",
"select": "Select",
"selectACourse": "Select a course or unit",
"selectAllFunctions": "Select all functions",
"selectAnOption": "Please select an option...",
"selectAssessment": "Select an assessment or survey",
"selectAssignedLibrarySections": "Select one or more sections to assign this library to",
Expand Down Expand Up @@ -1561,11 +1565,12 @@
"showBlocksHeader": "Show Blocks",
"showCodeHeader": "Show Code",
"showGeneratedCode": "Show code",
"showPicture": "Show picture",
"showSection": "Show Section",
"showSecret": "Show secret",
"showTextHeader": "Show Text",
"showToolbox": "Show Toolbox",
"showVersionsHeader": "Version History",
"showWords": "Show words",
"signup": "Sign up for the intro course",
"signUpButton": "Sign up",
"signupFormSchoolOrOrganization": "School / Organization",
Expand Down
169 changes: 127 additions & 42 deletions apps/src/code-studio/components/libraries/LibraryPublisher.jsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/*global dashboard*/
import React from 'react';
import PropTypes from 'prop-types';
import _ from 'lodash';
import libraryParser from './libraryParser';
import i18n from '@cdo/locale';
import color from '@cdo/apps/util/color';
Expand All @@ -12,15 +13,21 @@ const styles = {
alert: {
color: color.red,
width: '90%',
paddingTop: 8
paddingTop: 8,
fontStyle: 'italic'
},
functionSelector: {
display: 'flex',
alignItems: 'center',
margin: '10px 10px 10px 0'
},
largerCheckbox: {
width: 20,
height: 20,
marginLeft: 0,
marginRight: 10,
marginTop: 10,
marginBottom: 10
height: 20
},
functionLabel: {
margin: 0,
fontSize: 20
},
info: {
fontSize: 12,
Expand Down Expand Up @@ -68,15 +75,29 @@ export default class LibraryPublisher extends React.Component {
onShareTeacherLibrary: PropTypes.func
};

state = {
publishState: PublishState.DEFAULT,
libraryName: libraryParser.suggestName(
this.props.libraryDetails.libraryName
),
libraryDescription: this.props.libraryDetails.libraryDescription,
selectedFunctions: this.props.libraryDetails.selectedFunctions,
profaneWords: null
};
constructor(props) {
super(props);

// Filter out already-published functions that are now invalid.
const initialSelectedFunctions = props.libraryDetails.selectedFunctions;
let validSelectedFunctions = {};
props.libraryDetails.sourceFunctionList.forEach(sourceFunction => {
if (
initialSelectedFunctions[sourceFunction.functionName] &&
this.isFunctionValid(sourceFunction)
) {
validSelectedFunctions[sourceFunction.functionName] = true;
}
});

this.state = {
publishState: PublishState.DEFAULT,
libraryName: libraryParser.suggestName(props.libraryDetails.libraryName),
libraryDescription: props.libraryDetails.libraryDescription,
selectedFunctions: validSelectedFunctions,
profaneWords: null
};
}

setLibraryName = event => {
const {libraryName} = this.state;
Expand Down Expand Up @@ -205,7 +226,32 @@ export default class LibraryPublisher extends React.Component {
);
};

boxChecked = name => {
hasComment = sourceFunction => {
return (sourceFunction.comment || '').length > 0;
};

duplicateFunction = sourceFunction => {
const {sourceFunctionList} = this.props.libraryDetails;
const {functionName} = sourceFunction;
return (
sourceFunctionList.filter(source => source.functionName === functionName)
.length > 1
);
};

isFunctionValid = sourceFunction => {
return (
this.hasComment(sourceFunction) && !this.duplicateFunction(sourceFunction)
);
};

boxChecked = sourceFunction => {
// No-op if function is invalid
if (!this.isFunctionValid(sourceFunction)) {
return;
}

const name = sourceFunction.functionName;
this.setState(state => {
state.selectedFunctions[name] = !state.selectedFunctions[name];
return state;
Expand All @@ -217,36 +263,29 @@ export default class LibraryPublisher extends React.Component {
const {sourceFunctionList} = this.props.libraryDetails;
return sourceFunctionList.map(sourceFunction => {
const {functionName, comment} = sourceFunction;
const noComment = comment.length === 0;
const duplicateFunction =
sourceFunctionList.filter(
source => source.functionName === functionName
).length > 1;
const shouldDisable = noComment || duplicateFunction;
let checked = selectedFunctions[functionName] || false;
if (shouldDisable && checked) {
checked = false;
this.setState(state => {
state.selectedFunctions[functionName] = false;
return state;
});
}
const checked = selectedFunctions[functionName] || false;
const functionId = _.uniqueId(`${functionName}-`);

return (
<div key={functionName}>
<input
style={styles.largerCheckbox}
type="checkbox"
disabled={shouldDisable}
name={functionName}
checked={checked}
onChange={() => this.boxChecked(functionName)}
/>
<span>{functionName}</span>
<br />
{noComment && (
<div style={styles.functionSelector}>
<input
style={styles.largerCheckbox}
type="checkbox"
id={functionId}
disabled={!this.isFunctionValid(sourceFunction)}
name={functionName}
checked={checked}
onChange={() => this.boxChecked(sourceFunction)}
/>
<label htmlFor={functionId} style={styles.functionLabel}>
{functionName}
</label>
</div>
{!this.hasComment(sourceFunction) && (
<p style={styles.alert}>{i18n.libraryExportNoCommentError()}</p>
)}
{duplicateFunction && (
{this.duplicateFunction(sourceFunction) && (
<p style={styles.alert}>
{i18n.libraryExportDuplicationFunctionError()}
</p>
Expand Down Expand Up @@ -305,9 +344,43 @@ export default class LibraryPublisher extends React.Component {
);
};

allFunctionsSelected = () => {
const {sourceFunctionList} = this.props.libraryDetails;
const {selectedFunctions} = this.state;

let allSelected = true;
sourceFunctionList.forEach(sourceFunction => {
// If any *valid* functions are not selected, set allSelected to false.
if (
!selectedFunctions[sourceFunction.functionName] &&
this.isFunctionValid(sourceFunction)
) {
allSelected = false;
}
});

return allSelected;
};

toggleAllFunctionsSelected = () => {
if (this.allFunctionsSelected()) {
this.setState({selectedFunctions: {}});
} else {
const {sourceFunctionList} = this.props.libraryDetails;
let selectedFunctions = {};
sourceFunctionList.forEach(sourceFunction => {
if (this.isFunctionValid(sourceFunction)) {
selectedFunctions[sourceFunction.functionName] = true;
}
});
this.setState({selectedFunctions});
}
};

render() {
const {alreadyPublished} = this.props.libraryDetails;
const {onShareTeacherLibrary} = this.props;
const selectAllCheckboxId = _.uniqueId('func-select-all-');

return (
<div>
Expand All @@ -316,6 +389,18 @@ export default class LibraryPublisher extends React.Component {
<Heading2>{i18n.description()}</Heading2>
{this.displayDescription()}
<Heading2>{i18n.catProcedures()}</Heading2>
<div style={styles.functionSelector}>
<input
style={styles.largerCheckbox}
type="checkbox"
id={selectAllCheckboxId}
checked={this.allFunctionsSelected()}
onChange={this.toggleAllFunctionsSelected}
/>
<label htmlFor={selectAllCheckboxId} style={styles.functionLabel}>
{i18n.selectAllFunctions()}
</label>
</div>
{this.displayFunctions()}
<div style={styles.info}>{i18n.libraryFunctionRequirements()}</div>
<div style={{position: 'relative'}}>
Expand Down
39 changes: 36 additions & 3 deletions apps/src/templates/manageStudents/ManageStudentsTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,41 @@ class ManageStudentsTable extends Component {

// Cell formatters.

passwordHeaderFormatter = () => {
const {loginType} = this.props;
const passwordLabels = {};
passwordLabels[SectionLoginType.picture] = i18n.picturePassword();
passwordLabels[SectionLoginType.word] = i18n.secretWords();
passwordLabels[SectionLoginType.email] = i18n.password();
const passwordTooltips = {};
passwordTooltips[
SectionLoginType.picture
] = i18n.editSectionLoginTypePicDesc();
passwordTooltips[
SectionLoginType.word
] = i18n.editSectionLoginTypeWordDesc();
passwordTooltips[
SectionLoginType.email
] = i18n.editSectionLoginTypeEmailDesc();
return (
<span style={styles.verticalAlign}>
<div data-for="password" data-tip="" id="password-header">
{passwordLabels[loginType]}
</div>
<ReactTooltip
id="password"
class="react-tooltip-hover-stay"
role="tooltip"
effect="solid"
place="top"
delayHide={1000}
>
<div>{passwordTooltips[loginType]}</div>
</ReactTooltip>
</span>
);
};

passwordFormatter = (loginType, {rowData}) => {
const {sectionId} = this.props;
const resetDisabled = this.isEditingDisabled(rowData.userType);
Expand Down Expand Up @@ -395,8 +430,6 @@ class ManageStudentsTable extends Component {

getColumns = sortable => {
const {loginType} = this.props;
const passwordLabel =
loginType === SectionLoginType.email ? i18n.password() : i18n.secret();
let dataColumns = [
{
property: 'name',
Expand Down Expand Up @@ -467,7 +500,7 @@ class ManageStudentsTable extends Component {
{
property: 'password',
header: {
label: passwordLabel,
formatters: [this.passwordHeaderFormatter],
props: {
style: {
...tableLayoutStyles.headerCell,
Expand Down
12 changes: 10 additions & 2 deletions apps/src/templates/manageStudents/ShowSecret.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,14 @@ class ShowSecret extends Component {
render() {
const {resetDisabled} = this.props;
const tooltipId = resetDisabled && _.uniqueId();
const showButtonText =
this.props.loginType === SectionLoginType.word
? i18n.showWords()
: i18n.showPicture();
const hideButtonText =
this.props.loginType === SectionLoginType.word
? i18n.hideWords()
: i18n.hidePicture();

return (
<div>
Expand All @@ -89,7 +97,7 @@ class ShowSecret extends Component {
__useDeprecatedTag
onClick={this.show}
color={Button.ButtonColor.white}
text={i18n.showSecret()}
text={showButtonText}
/>
)}
{this.state.isShowing && (
Expand Down Expand Up @@ -123,7 +131,7 @@ class ShowSecret extends Component {
__useDeprecatedTag
onClick={this.hide}
color={Button.ButtonColor.white}
text={i18n.hideSecret()}
text={hideButtonText}
/>
</div>
)}
Expand Down