Skip to content

Commit

Permalink
Merge pull request #34635 from code-dot-org/staging
Browse files Browse the repository at this point in the history
DTT (Staging > Test) [robo-dtt]
  • Loading branch information
deploy-code-org committed May 5, 2020
2 parents 4aaa84b + 6c23dfb commit a64619d
Show file tree
Hide file tree
Showing 11 changed files with 418 additions and 145 deletions.
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

0 comments on commit a64619d

Please sign in to comment.