<commit_before>import { React, PropTypes, styled, observer } from 'vendor';
import { Icon } from 'shared';
import { Row } from 'react-sticky-table';

import LoadingScreen from 'shared/components/loading-animation';
import { colors } from 'theme';
import ScoresHelper, { UNWORKED } from '../../helpers/scores';
import ExtensionIcon, { EIcon } from '../../components/icons/extension';
import InfoIcon from '../../components/icons/info';
import SortIcon from '../../components/icons/sort';
import SearchInput from '../../components/search-input';
import TutorLink from '../../components/link';
import { CornerTriangle, TriangleCSS } from '../../components/dropped-question';
import GrantExtension from './grant-extension';
import DropQuestions from './drop-questions';
import PublishScores from '../../components/buttons/publish-scores';
import ResultTooltip from './result-tooltip';

import {
    StyledStickyTable, Cell, CellContents,
    Heading, HeadingTop, HeadingMiddle, HeadingBottom,
    SplitCell, ColumnHeading as BasicColumnHeading,
    LateWork, Total, ColumnFooter,
    TableBottom, Definitions, Entry, Term, Definition,
    ControlsWrapper, ControlGroup,
    OrderIcon, NameWrapper,
} from './table-elements';

const ColumnHeading = styled(BasicColumnHeading)`
  background: ${props => props.variant === 'q' ? colors.templates.homework.background : colors.neutral.lighter};
`;

const ResultWrapper = styled.div`
  display: flex;
  justify-content: center;
  align-items: center;
`;

const DroppedIcon = styled.div`
  ${TriangleCSS}
  border-width: 0 1.2rem 1.2rem 0;
`;

const UngradedIcon = styled.span`
  color: ${colors.neutral.std};
  font-size: 1.2rem;
  line-height: 1.4rem;
  letter-spacing: 0.38px;
`;

const OrangeInfoIcon = (
    <InfoIcon
        color="#f36a31"
        tooltip="Students received different numbers of Tutor-selected questions.
        This can happen when questions aren’t available, a student works an assignment late,
        a student hasn’t started the assignment, or a personalized question is dropped."
    />
);

const StudentColumnHeader = observer(({ ux }) => (
    <Cell leftBorder={true}>
        <CellContents>
            <ColumnHeading first={true}>
                <HeadingTop
                    onClick={() => ux.changeRowSortingOrder(0, ux.reverseNameOrder ? 'first_name' : 'name')}
                    aria-label="Sort by student name"
                    role="button"
                >
          Student Name
                    <SortIcon sort={ux.sortForColumn(0, ux.reverseNameOrder ? 'first_name' : 'name')} />
                </HeadingTop>
                <HeadingMiddle>
                    {ux.nameOrderHeader}
                    <OrderIcon
                        variant="toggleOrder"
                        onClick={ux.toggleNameOrder}
                        aria-label="Toggle firstname lastname order"
                    />
                </HeadingMiddle>
                <HeadingBottom>
          Available Points
                </HeadingBottom>
            </ColumnHeading>
            <ColumnHeading>
                <HeadingTop
                    onClick={() => ux.changeRowSortingOrder(0, 'total')}
                    aria-label="Sort by student total"
                    role="button"
                >
          Total
                    <SortIcon sort={ux.sortForColumn(0, 'total')} />
                </HeadingTop>
                <HeadingMiddle>
                    <SplitCell
                        variant={!ux.displayTotalInPercent ? 'active' : ''}
                        onClick={() => ux.displayTotalInPercent = false}
                        aria-label="Display total in points"
                        role="button"
                    >
            #
                    </SplitCell>
                    <SplitCell variant="divider">
            |
                    </SplitCell>
                    <SplitCell
                        variant={ux.displayTotalInPercent ? 'active' : ''}
                        onClick={() => ux.displayTotalInPercent = true}
                        aria-label="Display total in percent"
                        role="button"
                    >
            %
                    </SplitCell>
                </HeadingMiddle>
                <HeadingBottom>
                    {ux.scores.hasEqualQuestions ?
                        ScoresHelper.formatPoints(ux.scores.availablePoints) :
                        <OrangeInfoIcon/>
                    }
                </HeadingBottom>
            </ColumnHeading>
            <ColumnHeading>
                <HeadingTop>
          Late work
                </HeadingTop>
                <HeadingMiddle>
                    {ux.planScores.grading_template.humanLateWorkPenaltyApplied}
                </HeadingMiddle>
                <HeadingBottom>
                    {ux.planScores.grading_template.humanLateWorkPenalty}
                </HeadingBottom>
            </ColumnHeading>
        </CellContents>
    </Cell>
));

const StudentCell = observer(({ ux, student, striped, border }) => (
    <Cell striped={striped} border={border}>
        <CellContents>
            <NameWrapper first>
                <TutorLink
                    to="viewTask"
                    params={{
                        courseId: ux.course.id,
                        id: student.task_id,
                    }}
                >
                    {ux.reverseNameOrder ? student.reversedName : student.name}
                </TutorLink>
            </NameWrapper>
            <Total>
                {ux.displayTotalInPercent ?
                    student.humanTotalFraction : ( ux.scores.hasEqualQuestions ?
                        student.humanTotalPoints : student.humanTotalWithAvailablePoints)}
            </Total>
            <LateWork>
                {student.late_work_point_penalty ?
                    `${ScoresHelper.formatLatePenalty(student.late_work_point_penalty)}` : '0'}
                {ux.wasGrantedExtension(student.role_id) &&
          <ExtensionIcon extension={student.extension} timezone={ux.course.timezone} />}
            </LateWork>
        </CellContents>
    </Cell>
));


const AssignmentHeading = observer(({ ux, heading }) => (
    <Cell onClick={() => ux.changeRowSortingOrder(heading.index, 'question')}>
        <ColumnHeading variant="q">
            <HeadingTop>
                {heading.title}
                <SortIcon sort={ux.sortForColumn(heading.index, 'question')} />
            </HeadingTop>
            <HeadingMiddle>
                {heading.type}
            </HeadingMiddle>
            <HeadingBottom>
                {heading.someQuestionsDropped &&
                <CornerTriangle color="blue"
                    data-test-id="dropped-question-indicator"
                    data-question-id={`Q${heading.question_id}`}
                    tooltip={heading.everyQuestionZeroed ? 'Points changed to 0' :
                        (heading.everyQuestionFullCredit ? 'Full credit given to all students':
                            'Question dropped for one or more students')}
                />}
                {(heading.someQuestionsDropped &&
                     !heading.everyQuestionZeroed &&
                     !heading.everyQuestionFullCredit) ? <OrangeInfoIcon/> :
                    ScoresHelper.formatPoints(heading.points)}
            </HeadingBottom>
        </ColumnHeading>
    </Cell>
));

const TaskResult = observer(({ result, striped }) => {
    let body;

    if (!result) {
        body = 'n/a';
    } else if (result.needs_grading) {
        body = (
            <>
                {result.submitted_late && <Icon variant="lateWork" />}
                <UngradedIcon>{result.displayValue}</UngradedIcon>
            </>
        );<commit_msg>Moved in-template logic in homework scores to separate components<commit_after>import { React, PropTypes, styled, observer } from 'vendor';
import { Icon } from 'shared';
import { Row } from 'react-sticky-table';

import LoadingScreen from 'shared/components/loading-animation';
import { colors } from 'theme';
import ScoresHelper, { UNWORKED } from '../../helpers/scores';
import ExtensionIcon, { EIcon } from '../../components/icons/extension';
import InfoIcon from '../../components/icons/info';
import SortIcon from '../../components/icons/sort';
import SearchInput from '../../components/search-input';
import TutorLink from '../../components/link';
import { CornerTriangle, TriangleCSS } from '../../components/dropped-question';
import GrantExtension from './grant-extension';
import DropQuestions from './drop-questions';
import PublishScores from '../../components/buttons/publish-scores';
import ResultTooltip from './result-tooltip';

import {
    StyledStickyTable, Cell, CellContents,
    Heading, HeadingTop, HeadingMiddle, HeadingBottom,
    SplitCell, ColumnHeading as BasicColumnHeading,
    LateWork, Total, ColumnFooter,
    TableBottom, Definitions, Entry, Term, Definition,
    ControlsWrapper, ControlGroup,
    OrderIcon, NameWrapper,
} from './table-elements';

const ColumnHeading = styled(BasicColumnHeading)`
  background: ${props => props.variant === 'q' ? colors.templates.homework.background : colors.neutral.lighter};
`;

const ResultWrapper = styled.div`
  display: flex;
  justify-content: center;
  align-items: center;
`;

const DroppedIcon = styled.div`
  ${TriangleCSS}
  border-width: 0 1.2rem 1.2rem 0;
`;

const UngradedIcon = styled.span`
  color: ${colors.neutral.std};
  font-size: 1.2rem;
  line-height: 1.4rem;
  letter-spacing: 0.38px;
`;

const OrangeInfoIcon = (
    <InfoIcon
        color="#f36a31"
        tooltip="Students received different numbers of Tutor-selected questions.
        This can happen when questions aren’t available, a student works an assignment late,
        a student hasn’t started the assignment, or a personalized question is dropped."
    />
);

const TotalPointsHeading = observer(({ ux }) => {
    if (ux.scores.hasEqualQuestions) {
        return (<span>{ScoresHelper.formatPoints(ux.scores.availablePoints)}</span>);
    }

    return (<OrangeInfoIcon/>);
});

const AssignmentHeadingPoints = observer(({ heading }) => {
    let cellContents;

    if (!heading.someQuestionsDropped ||
        heading.everyQuestionZeroed ||
        heading.everyQuestionFullCredit) {
        cellContents = (<span>{ScoresHelper.formatPoints(heading.points)}</span>);

        if (!heading.someQuestionsDropped) {
            return cellContents;
        }
    }
    else {
        cellContents = (<OrangeInfoIcon/>);
    }

    const triangleTooltip = heading.everyQuestionZeroed ? 'Points changed to 0' :
        (heading.everyQuestionFullCredit ? 'Full credit given to all students':
            'Question dropped for one or more students');

    return (
        <>
            <CornerTriangle color="blue"
                data-test-id="dropped-question-indicator"
                data-question-id={`Q${heading.question_id}`}
                tooltip={triangleTooltip}
            />

            {cellContents}
        </>
    );
});

const StudentColumnHeader = observer(({ ux }) => (
    <Cell leftBorder={true}>
        <CellContents>
            <ColumnHeading first={true}>
                <HeadingTop
                    onClick={() => ux.changeRowSortingOrder(0, ux.reverseNameOrder ? 'first_name' : 'name')}
                    aria-label="Sort by student name"
                    role="button"
                >
          Student Name
                    <SortIcon sort={ux.sortForColumn(0, ux.reverseNameOrder ? 'first_name' : 'name')} />
                </HeadingTop>
                <HeadingMiddle>
                    {ux.nameOrderHeader}
                    <OrderIcon
                        variant="toggleOrder"
                        onClick={ux.toggleNameOrder}
                        aria-label="Toggle firstname lastname order"
                    />
                </HeadingMiddle>
                <HeadingBottom>
          Available Points
                </HeadingBottom>
            </ColumnHeading>
            <ColumnHeading>
                <HeadingTop
                    onClick={() => ux.changeRowSortingOrder(0, 'total')}
                    aria-label="Sort by student total"
                    role="button"
                >
          Total
                    <SortIcon sort={ux.sortForColumn(0, 'total')} />
                </HeadingTop>
                <HeadingMiddle>
                    <SplitCell
                        variant={!ux.displayTotalInPercent ? 'active' : ''}
                        onClick={() => ux.displayTotalInPercent = false}
                        aria-label="Display total in points"
                        role="button"
                    >
            #
                    </SplitCell>
                    <SplitCell variant="divider">
            |
                    </SplitCell>
                    <SplitCell
                        variant={ux.displayTotalInPercent ? 'active' : ''}
                        onClick={() => ux.displayTotalInPercent = true}
                        aria-label="Display total in percent"
                        role="button"
                    >
            %
                    </SplitCell>
                </HeadingMiddle>
                <HeadingBottom>
                    <TotalPointsHeading ux={ux} />
                </HeadingBottom>
            </ColumnHeading>
            <ColumnHeading>
                <HeadingTop>
          Late work
                </HeadingTop>
                <HeadingMiddle>
                    {ux.planScores.grading_template.humanLateWorkPenaltyApplied}
                </HeadingMiddle>
                <HeadingBottom>
                    {ux.planScores.grading_template.humanLateWorkPenalty}
                </HeadingBottom>
            </ColumnHeading>
        </CellContents>
    </Cell>
));

const StudentCell = observer(({ ux, student, striped, border }) => (
    <Cell striped={striped} border={border}>
        <CellContents>
            <NameWrapper first>
                <TutorLink
                    to="viewTask"
                    params={{
                        courseId: ux.course.id,
                        id: student.task_id,
                    }}
                >
                    {ux.reverseNameOrder ? student.reversedName : student.name}
                </TutorLink>
            </NameWrapper>
            <Total>
                {ux.displayTotalInPercent ?
                    student.humanTotalFraction : ( ux.scores.hasEqualQuestions ?
                        student.humanTotalPoints : student.humanTotalWithAvailablePoints)}
            </Total>
            <LateWork>
                {student.late_work_point_penalty ?
                    `${ScoresHelper.formatLatePenalty(student.late_work_point_penalty)}` : '0'}
                {ux.wasGrantedExtension(student.role_id) &&
          <ExtensionIcon extension={student.extension} timezone={ux.course.timezone} />}
            </LateWork>
        </CellContents>
    </Cell>
));


const AssignmentHeading = observer(({ ux, heading }) => (
    <Cell onClick={() => ux.changeRowSortingOrder(heading.index, 'question')}>
        <ColumnHeading variant="q">
            <HeadingTop>
                {heading.title}
                <SortIcon sort={ux.sortForColumn(heading.index, 'question')} />
            </HeadingTop>
            <HeadingMiddle>
                {heading.type}
            </HeadingMiddle>
            <HeadingBottom>
                <AssignmentHeadingPoints heading={heading} />
            </HeadingBottom>
        </ColumnHeading>
    </Cell>
));

const TaskResult = observer(({ result, striped }) => {
    let body;

    if (!result) {
        body = 'n/a';
    } else if (result.needs_grading) {
        body = (
            <>
                {result.submitted_late && <Icon variant="lateWork" />}
                <UngradedIcon>{result.displayValue}</UngradedIcon>
            </>
        );
{'fraction_non_alphanumeric': 0.11356683523756009, 'fraction_numerical': 0.002871948554660673, 'mean_word_length': 1.701636026311351, 'pattern_counts': {'":': 0, '<': 151, '<?xml version=': 0, '>': 173, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6643192', 'n_tokens_mistral': 4318, 'n_tokens_neox': 4039, 'n_words': 821}