Skip to content

Commit

Permalink
Using a double click as a shortcut to open item details in item lists…
Browse files Browse the repository at this point in the history
… (exercises, assignments, solutions...). This is opt-in, configurable in user UI settings.
  • Loading branch information
krulis-martin committed Jul 30, 2023
1 parent 1e76f2f commit 21ca63f
Show file tree
Hide file tree
Showing 19 changed files with 633 additions and 475 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ const AssignmentTableRow = ({
discussionOpen,
setSelected = null,
selected = false,
doubleClickPush = null,
intl: { locale },
links: {
ASSIGNMENT_DETAIL_URI_FACTORY,
Expand All @@ -57,7 +58,15 @@ const AssignmentTableRow = ({
GROUP_ASSIGNMENTS_URI_FACTORY,
},
}) => (
<tr>
<tr
onDoubleClick={
doubleClickPush &&
!setSelected &&
(() =>
doubleClickPush(
userId ? ASSIGNMENT_DETAIL_SPECIFIC_USER_URI_FACTORY(id, userId) : ASSIGNMENT_DETAIL_URI_FACTORY(id)
))
}>
{setSelected && (
<td className="text-nowrap shrink-col">
<NiceCheckbox name={id} checked={selected} onChange={setSelected} />
Expand Down Expand Up @@ -219,6 +228,7 @@ AssignmentTableRow.propTypes = {
showSecondDeadline: PropTypes.bool,
setSelected: PropTypes.func,
selected: PropTypes.bool,
doubleClickPush: PropTypes.func,
groupsAccessor: PropTypes.func,
discussionOpen: PropTypes.func,
links: PropTypes.object,
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { Table } from 'react-bootstrap';
import { withRouter } from 'react-router';
import { FormattedMessage, injectIntl } from 'react-intl';

import { isReady, isLoading, getJsData } from '../../../../redux/helpers/resourceManager';
import ShadowAssignmentsTableRow from './ShadowAssignmentsTableRow';
import { compareShadowAssignments } from '../../../helpers/assignments';
import { LoadingIcon } from '../../../icons';
import { UserUIDataContext } from '../../../../helpers/contexts';
import { EMPTY_LIST, EMPTY_OBJ } from '../../../../helpers/common';

const ShadowAssignmentsTable = ({
Expand All @@ -16,77 +18,88 @@ const ShadowAssignmentsTable = ({
stats = EMPTY_OBJ,
isAdmin = false,
intl: { locale },
history: { push },
}) => (
<Table hover={shadowAssignments.size > 0} className="mb-0">
{shadowAssignments.size > 0 && (
<thead>
<tr>
<th className="shrink-col" />
<th>
<FormattedMessage id="app.assignments.name" defaultMessage="Assignment name" />
</th>
<th>
<FormattedMessage id="generic.created" defaultMessage="Created" />
</th>
<th>
<FormattedMessage id="app.assignments.deadline" defaultMessage="Deadline" />
</th>
<UserUIDataContext.Consumer>
{({ openOnDoubleclick = false }) => (
<Table hover={shadowAssignments.size > 0} className="mb-0">
{shadowAssignments.size > 0 && (
<thead>
<tr>
<th className="shrink-col" />
<th>
<FormattedMessage id="app.assignments.name" defaultMessage="Assignment name" />
</th>
<th>
<FormattedMessage id="generic.created" defaultMessage="Created" />
</th>
<th>
<FormattedMessage id="app.assignments.deadline" defaultMessage="Deadline" />
</th>

<th className="text-center text-nowrap">
{!isAdmin ? (
<FormattedMessage id="app.assignments.points" defaultMessage="Points" />
) : (
<FormattedMessage id="app.assignments.maxPoints" defaultMessage="Max. Points" />
)}
</th>
<th className="text-center text-nowrap">
{!isAdmin ? (
<FormattedMessage id="app.assignments.points" defaultMessage="Points" />
) : (
<FormattedMessage id="app.assignments.maxPoints" defaultMessage="Max. Points" />
)}
</th>

{!isAdmin && (
<th>
<FormattedMessage id="app.shadowAssignmentPointsDetail.note" defaultMessage="Note" />
</th>
)}
{!isAdmin && (
<th>
<FormattedMessage id="app.shadowAssignmentPointsDetail.note" defaultMessage="Note" />
</th>
)}

<th className="shrink-col" />
</tr>
</thead>
)}
<tbody>
{shadowAssignments.size === 0 && (
<tr>
<td className="text-center em-padding text-muted">
<FormattedMessage
id="app.shadowAssignmentsTable.noAssignments"
defaultMessage="There are no shadow assignments."
/>
</td>
</tr>
)}
<th className="shrink-col" />
</tr>
</thead>
)}
<tbody>
{shadowAssignments.size === 0 && (
<tr>
<td className="text-center em-padding text-muted">
<FormattedMessage
id="app.shadowAssignmentsTable.noAssignments"
defaultMessage="There are no shadow assignments."
/>
</td>
</tr>
)}

{shadowAssignments.some(isLoading) && (
<tr>
<td className="text-center em-padding" colSpan={isAdmin ? 5 : 4}>
<LoadingIcon gapRight />
<FormattedMessage id="app.shadowAssignmentsTable.loading" defaultMessage="Loading shadow assignments..." />
</td>
</tr>
)}
{shadowAssignments.some(isLoading) && (
<tr>
<td className="text-center em-padding" colSpan={isAdmin ? 5 : 4}>
<LoadingIcon gapRight />
<FormattedMessage
id="app.shadowAssignmentsTable.loading"
defaultMessage="Loading shadow assignments..."
/>
</td>
</tr>
)}

{shadowAssignments
.filter(isReady)
.map(getJsData)
.sort(compareShadowAssignments)
.map(assignment => (
<ShadowAssignmentsTableRow
key={assignment.id}
item={assignment}
userId={userId}
locale={locale}
stats={Object.keys(stats).length !== 0 ? stats.assignments.find(item => item.id === assignment.id) : null}
isAdmin={isAdmin}
/>
))}
</tbody>
</Table>
{shadowAssignments
.filter(isReady)
.map(getJsData)
.sort(compareShadowAssignments)
.map(assignment => (
<ShadowAssignmentsTableRow
key={assignment.id}
item={assignment}
userId={userId}
locale={locale}
stats={
Object.keys(stats).length !== 0 ? stats.assignments.find(item => item.id === assignment.id) : null
}
isAdmin={isAdmin}
doubleClickPush={openOnDoubleclick ? push : null}
/>
))}
</tbody>
</Table>
)}
</UserUIDataContext.Consumer>
);

ShadowAssignmentsTable.propTypes = {
Expand All @@ -95,6 +108,9 @@ ShadowAssignmentsTable.propTypes = {
stats: PropTypes.object,
isAdmin: PropTypes.bool,
intl: PropTypes.shape({ locale: PropTypes.string.isRequired }).isRequired,
history: PropTypes.shape({
push: PropTypes.func.isRequired,
}),
};

export default injectIntl(ShadowAssignmentsTable);
export default withRouter(injectIntl(ShadowAssignmentsTable));
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,10 @@ const ShadowAssignmentsTableRow = ({
item: { id, localizedTexts, createdAt, deadline, isBonus, isPublic, maxPoints, points, permissionHints },
userId,
isAdmin,
doubleClickPush,
links: { SHADOW_ASSIGNMENT_DETAIL_URI_FACTORY, SHADOW_ASSIGNMENT_EDIT_URI_FACTORY },
}) => (
<tr>
<tr onDoubleClick={doubleClickPush && (() => doubleClickPush(SHADOW_ASSIGNMENT_DETAIL_URI_FACTORY(id)))}>
<td className="text-nowrap shrink-col">
{permissionHints.update && <VisibleIcon visible={isPublic} gapLeft gapRight />}
<MaybeBonusAssignmentIcon id={id} isBonus={isBonus} gapLeft gapRight />
Expand Down Expand Up @@ -100,6 +101,7 @@ ShadowAssignmentsTableRow.propTypes = {
userId: PropTypes.string,
links: PropTypes.object,
isAdmin: PropTypes.bool,
doubleClickPush: PropTypes.func,
};

export default withLinks(ShadowAssignmentsTableRow);

0 comments on commit 21ca63f

Please sign in to comment.