Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 9 additions & 10 deletions src/components/Groups/GroupTopButtons/GroupTopButtons.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,22 +29,21 @@ const GroupTopButtons = ({
/>
</Button>
</LinkContainer>}

<LinkContainer to={GROUP_INFO_URI_FACTORY(group.id)}>
<Button bsStyle="primary">
<InfoIcon />{' '}
<FormattedMessage id="app.group.info" defaultMessage="Group Info" />
</Button>
</LinkContainer>
{!group.organizational &&
<LinkContainer to={GROUP_DETAIL_URI_FACTORY(group.id)}>
<Button bsStyle="primary">
<GroupIcon />{' '}
<FormattedMessage
id="app.group.detailButton"
defaultMessage="Group Detail"
/>
</Button>
</LinkContainer>}

<LinkContainer to={GROUP_DETAIL_URI_FACTORY(group.id)}>
<Button bsStyle="primary">
<GroupIcon />{' '}
<FormattedMessage id="app.group.detail" defaultMessage="Group Detail" />
</Button>
</LinkContainer>

{canLeaveJoin &&
<LeaveJoinGroupButtonContainer
userId={userId}
Expand Down
36 changes: 25 additions & 11 deletions src/components/Groups/GroupTree/GroupTree.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,17 +28,30 @@ class GroupTree extends Component {
/>
</TreeView>;

renderButtons = groupId => {
const { links: { GROUP_INFO_URI_FACTORY } } = this.props;
renderButtons = (groupId, organizational) => {
const {
links: { GROUP_INFO_URI_FACTORY, GROUP_DETAIL_URI_FACTORY }
} = this.props;
return (
<span>
<LinkContainer to={GROUP_INFO_URI_FACTORY(groupId)}>
<LinkContainer
to={
organizational
? GROUP_INFO_URI_FACTORY(groupId)
: GROUP_DETAIL_URI_FACTORY(groupId)
}
>
<Button bsStyle="primary" bsSize="xs" className="btn-flat">
<Icon name="group" />{' '}
<FormattedMessage
id="app.group.detailButton"
defaultMessage="Group Detail"
/>
{organizational
? <FormattedMessage
id="app.group.info"
defaultMessage="Group Info"
/>
: <FormattedMessage
id="app.group.detail"
defaultMessage="Group Detail"
/>}
</Button>
</LinkContainer>
</span>
Expand Down Expand Up @@ -80,8 +93,7 @@ class GroupTree extends Component {
isPublic = false,
groups,
currentGroupId = null,
visibleGroupsMap = null,
links: { GROUP_INFO_URI_FACTORY }
visibleGroupsMap = null
} = this.props;

const group = groups.get(id);
Expand All @@ -94,7 +106,8 @@ class GroupTree extends Component {
localizedTexts,
canView,
childGroups,
primaryAdminsIds
primaryAdminsIds,
organizational
} = getJsData(group);

const actualVisibleGroupsMap =
Expand All @@ -117,11 +130,12 @@ class GroupTree extends Component {
id={id}
level={level}
admins={primaryAdminsIds}
organizational={organizational}
isPublic={isPublic}
isOpen={currentGroupId === id || isOpen}
actions={
currentGroupId !== id && canView
? this.renderButtons(id, GROUP_INFO_URI_FACTORY(id))
? this.renderButtons(id, organizational)
: undefined
}
>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import GroupIcon from '../../icons/GroupIcon';
import LoadingIcon from '../../icons/LoadingIcon';
import Button from '../../widgets/FlatButton';

const OrganizationalGroupButton = ({
organizational,
pending,
setOrganizational
}) =>
<Button
bsStyle="info"
onClick={setOrganizational(!organizational)}
disabled={pending}
>
{pending
? <LoadingIcon />
: <GroupIcon organizational={!organizational} />}&nbsp;&nbsp;
{organizational === true
? <FormattedMessage
id="app.organizationalGroupButton.unset"
defaultMessage="Change to Regular Group"
/>
: <FormattedMessage
id="app.organizationalGroupButton.set"
defaultMessage="Change to Organizational Group"
/>}
</Button>;

OrganizationalGroupButton.propTypes = {
organizational: PropTypes.bool.isRequired,
pending: PropTypes.bool.isRequired,
setOrganizational: PropTypes.func.isRequired
};

export default OrganizationalGroupButton;
1 change: 1 addition & 0 deletions src/components/buttons/OrganizationalGroupButton/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default from './OrganizationalGroupButton';
26 changes: 14 additions & 12 deletions src/components/forms/EditAssignmentForm/EditAssignmentForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -206,18 +206,6 @@ const EditAssignmentForm = ({
}
/>

<Field
name="isPublic"
component={CheckboxField}
onOff
label={
<FormattedMessage
id="app.editAssignmentForm.isPublic"
defaultMessage="Visible to students"
/>
}
/>

<hr />

<h4>
Expand Down Expand Up @@ -245,6 +233,20 @@ const EditAssignmentForm = ({
</Col>
)}
</Row>

<hr />

<Field
name="isPublic"
component={CheckboxField}
onOff
label={
<FormattedMessage
id="app.editAssignmentForm.isPublic"
defaultMessage="Visible to students"
/>
}
/>
</FormBox>
</div>;

Expand Down
1 change: 0 additions & 1 deletion src/components/forms/EditGroupForm/EditGroupForm.js
Original file line number Diff line number Diff line change
Expand Up @@ -283,7 +283,6 @@ const validate = ({ localizedTexts = [], hasThreshold, threshold }) => {
};

export default reduxForm({
form: 'editGroup',
enableReinitialize: true,
keepDirtyOnReinitialize: false,
validate
Expand Down
8 changes: 7 additions & 1 deletion src/components/icons/GroupIcon.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
import React from 'react';
import PropTypes from 'prop-types';
import Icon from 'react-fontawesome';

const GroupIcon = props => <Icon {...props} name="users" />;
const GroupIcon = ({ organizational = false, ...props }) =>
<Icon {...props} name={organizational ? 'sitemap' : 'users'} />;

GroupIcon.propTypes = {
organizational: PropTypes.bool
};

export default GroupIcon;
22 changes: 21 additions & 1 deletion src/components/widgets/TreeView/TreeViewLeaf.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { FormattedMessage } from 'react-intl';
import { OverlayTrigger, Tooltip } from 'react-bootstrap';
import Icon from 'react-fontawesome';

import { LoadingIcon } from '../../icons';
import { LoadingIcon, GroupIcon } from '../../icons';
import LevelGap from './LevelGap';
import GroupsName from '../../../components/Groups/GroupsName';
import UsersNameContainer from '../../../containers/UsersNameContainer';
Expand All @@ -14,6 +14,7 @@ const TreeViewLeaf = ({
loading = false,
title,
admins,
organizational,
isPublic,
icon = 'square-o',
onClick,
Expand Down Expand Up @@ -43,6 +44,24 @@ const TreeViewLeaf = ({
</em>
</small>)
</span>}
{organizational &&
<OverlayTrigger
placement="bottom"
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we have any other placement="bottom"? I'd prefer "top" if it will look decent.

overlay={
<Tooltip id={`${id}-organizational-tooltip`}>
<FormattedMessage
id="app.groupTree.treeViewLeaf.organizationalTooltip"
defaultMessage="The group is organizational (it does not have any students or assignments)"
/>
</Tooltip>
}
>
<GroupIcon
organizational={true}
className="text-muted"
style={{ marginLeft: '0.5em' }}
/>
</OverlayTrigger>}
{isPublic &&
<OverlayTrigger
placement="bottom"
Expand Down Expand Up @@ -72,6 +91,7 @@ TreeViewLeaf.propTypes = {
PropTypes.shape({ type: PropTypes.oneOf([FormattedMessage, GroupsName]) })
]).isRequired,
admins: PropTypes.array,
organizational: PropTypes.bool,
isPublic: PropTypes.bool,
icon: PropTypes.string,
onClick: PropTypes.func,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';

import OrganizationalGroupButton from '../../components/buttons/OrganizationalGroupButton';
import { setOrganizational } from '../../redux/modules/groups';
import {
groupSelector,
groupOrganizationalPendingChange
} from '../../redux/selectors/groups';
import ResourceRenderer from '../../components/helpers/ResourceRenderer';

const OrganizationalGroupButtonContainer = ({
group,
pending,
setOrganizational
}) =>
<ResourceRenderer resource={group}>
{({ organizational }) =>
<OrganizationalGroupButton
organizational={organizational}
pending={pending}
setOrganizational={setOrganizational}
/>}
</ResourceRenderer>;

OrganizationalGroupButtonContainer.propTypes = {
id: PropTypes.string.isRequired,
group: ImmutablePropTypes.map,
pending: PropTypes.bool.isRequired,
setOrganizational: PropTypes.func.isRequired
};

const mapStateToProps = (state, { id }) => ({
group: groupSelector(id)(state),
pending: groupOrganizationalPendingChange(id)(state)
});

const mapDispatchToProps = (dispatch, { id }) => ({
setOrganizational: organizational => () =>
dispatch(setOrganizational(id, organizational))
});

export default connect(mapStateToProps, mapDispatchToProps)(
OrganizationalGroupButtonContainer
);
1 change: 1 addition & 0 deletions src/containers/OrganizationalGroupButtonContainer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export default from './OrganizationalGroupButtonContainer';
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ class SisIntegrationContainer extends Component {
>
<Icon name="group" />{' '}
<FormattedMessage
id="app.group.detailButton"
id="app.group.detail"
defaultMessage="Group Detail"
/>
</Button>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ class SisSupervisorGroupsContainer extends Component {
>
<Icon name="group" />{' '}
<FormattedMessage
id="app.group.detailButton"
id="app.group.detail"
defaultMessage="Group Detail"
/>
</Button>
Expand Down
11 changes: 8 additions & 3 deletions src/locales/cs.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"app.EditLimitsForm.cloneAll.yesNoQuestion": "Opravdu chcete použít tyto limity pro všechny testy a všechna běhové prostředí? Povšimněte si prosím, že individuální běhová prostředí mají rozdílné výkonostní charakteristiky.",
"app.EditLimitsForm.cloneHorizontal.yesNoQuestion": "Opravdu chcete použít tyto limity pro všechna běhová prostředí tohoto testu? Povšimněte si prosím, že individuální běhová prostředí mají rozdílné výkonostní charakteristiky.",
"app.EditLimitsForm.cloneAll.yesNoQuestion": "Opravdu chcete použít tyto limity pro všechny testy a všechna běhové prostředí? Povšimněte si prosím, že individuální běhová prostředí mají rozdílné výkonnostní charakteristiky.",
"app.EditLimitsForm.cloneHorizontal.yesNoQuestion": "Opravdu chcete použít tyto limity pro všechna běhová prostředí tohoto testu? Povšimněte si prosím, že individuální běhová prostředí mají rozdílné výkonnostní charakteristiky.",
"app.EditLimitsForm.validation.NaN": "Poskytnutá hodnota není číslo.",
"app.EditLimitsForm.validation.outOfRange": "Poskytnutá úloha je mimo rozsah. Prozkoumejte omezení limit pro více informací.",
"app.ExercisePrefixIcons.isLocked": "Úloha je zamčena autorem a nemůže být zadávána",
Expand Down Expand Up @@ -289,6 +289,7 @@
"app.editGroup.deleteGroup": "Smazat skupinu",
"app.editGroup.deleteGroupWarning": "Smazání skupiny odstraní také všechny podskupiny, skupinové úlohy a zadané úlohy včetně studentských řešení.",
"app.editGroup.description": "Změnit nastavení skupiny",
"app.editGroup.organizationalExplain": "Běžné skupiny jsou platformou spojující studenty a zadané úlohy. Organizační skupiny slouží pouze k vytváření hierarchie, takže v nich nesmí být přihlášení studenti a nesmí obsahovat zadané úlohy.",
"app.editGroup.title": "Upravit skupinu",
"app.editGroupForm.createGroup": "Vytvořit skupinu",
"app.editGroupForm.description": "Popis skupiny:",
Expand Down Expand Up @@ -638,8 +639,9 @@
"app.group.adminsView.addSupervisor": "Přidat vedoucího",
"app.group.createExercise": "Přidat skupinovou úlohu",
"app.group.description": "Přehled detailů skupiny a zadaných úloh",
"app.group.detailButton": "Detail skupiny",
"app.group.detail": "Detail skupiny",
"app.group.info": "Group Info",
"app.group.organizationalExplain": "Tato skupina je organizační, takže nemůže mít žádné studenty ani zadané úlohy. Nicméně úlohy spojené s touto skupinou je možné zadat v podskupinách.",
"app.group.spervisorsView.addStudent": "Přidat studenta",
"app.group.spervisorsView.groupExercises": "Skupinové úlohy",
"app.group.spervisorsView.resultsTable": "Výsledky",
Expand All @@ -653,6 +655,7 @@
"app.groupDetail.threshold": "Minimální procentuální počet bodů potřebných ke splnění tohoto kurzu:",
"app.groupResultsTableRow.noResults": "Nyní zde nejsou žádné výsledky k zobrazení.",
"app.groupTree.loading": "Načítání...",
"app.groupTree.treeViewLeaf.organizationalTooltip": "Skupina je organizační (nemá žádné studenty ani zadané úlohy)",
"app.groupTree.treeViewLeaf.publicTooltip": "Skupina je veřejná",
"app.groups.joinGroupButton": "Stát se členem",
"app.groups.leaveGroupButton": "Opustit skupinu",
Expand Down Expand Up @@ -761,6 +764,8 @@
"app.notifications.hideAll": "Pouze nové notifikace",
"app.notifications.showAll": "Zobrazit {count, plural, one {jednu starou notifikaci} two {dvě staré notifikace} other {# starých notifikací}}",
"app.notifications.title": "{count, plural, =0 {Nemáte žádnou novou notifikaci} one {Máte novou notifikaci} =2 {Máte dvě nové notifikace} =3 {Máte tři nové notifikace} =4 {Máte čtyři nové notifikace} other {Máte # nových notifikací}}",
"app.organizationalGroupButton.set": "Změnit na organizační skupinu",
"app.organizationalGroupButton.unset": "Změnit na běžnou skupinu",
"app.page.exercises.failed": "Načítání seznamu úloh selhalo",
"app.page.exercises.failedDescription": "Omlouváme se za nepříjemnosti, zkuste to prosím později.",
"app.page.exercises.loading": "Načítání seznamu úloh ...",
Expand Down
Loading