Skip to content

Commit

Permalink
Providing standard navigation for pipeline pages.
Browse files Browse the repository at this point in the history
  • Loading branch information
krulis-martin committed Dec 29, 2021
1 parent 23bd230 commit ce36e76
Show file tree
Hide file tree
Showing 10 changed files with 181 additions and 62 deletions.
20 changes: 19 additions & 1 deletion src/components/layout/Navigation/Navigation.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ import ExercisesNameContainer from '../../../containers/ExercisesNameContainer';
import GroupsNameContainer from '../../../containers/GroupsNameContainer';
import ShadowAssignmentNameContainer from '../../../containers/ShadowAssignmentNameContainer';
import UsersNameContainer from '../../../containers/UsersNameContainer';
import { AssignmentIcon, ExerciseIcon, GroupIcon, ShadowAssignmentIcon } from '../../icons';
import PipelineNameContainer from '../../../containers/PipelineNameContainer';
import { AssignmentIcon, ExerciseIcon, GroupIcon, PipelineIcon, ShadowAssignmentIcon } from '../../icons';

import styles from './Navigation.less';

Expand Down Expand Up @@ -49,6 +50,7 @@ const Navigation = ({
exerciseId = null,
assignmentId = null,
shadowId = null,
pipelineId = null,
userId = null,
emphasizeUser = false,
links,
Expand Down Expand Up @@ -135,6 +137,21 @@ const Navigation = ({
</span>
)}

{pipelineId && (
<span>
<OverlayTrigger
placement="bottom"
overlay={
<Tooltip id="pipelineIconTooltip">
<FormattedMessage id="app.navigation.pipeline" defaultMessage="Pipeline" />
</Tooltip>
}>
<PipelineIcon gapRight className="text-muted" />
</OverlayTrigger>
<PipelineNameContainer pipelineId={pipelineId} noLink />
</span>
)}

{userId && !emphasizeUser && (
<UsersNameContainer
userId={userId}
Expand Down Expand Up @@ -167,6 +184,7 @@ Navigation.propTypes = {
exerciseId: PropTypes.string,
assignmentId: PropTypes.string,
shadowId: PropTypes.string,
pipelineId: PropTypes.string,
userId: PropTypes.string,
emphasizeUser: PropTypes.bool,
links: PropTypes.array,
Expand Down
40 changes: 40 additions & 0 deletions src/components/layout/Navigation/PipelineNavigation.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';

import Navigation from './Navigation';
import withLinks from '../../../helpers/withLinks';
import { PipelineIcon, EditIcon } from '../../icons';

const PipelineNavigation = ({
pipelineId,
canViewDetail = false,
canEdit = false,
links: { PIPELINE_URI_FACTORY, PIPELINE_EDIT_URI_FACTORY },
}) => (
<Navigation
pipelineId={pipelineId}
links={[
canViewDetail && {
caption: <FormattedMessage id="app.navigation.pipeline" defaultMessage="Pipeline" />,
link: PIPELINE_URI_FACTORY(pipelineId),
icon: <PipelineIcon gapRight />,
},
canEdit && {
caption: <FormattedMessage id="app.navigation.edit" defaultMessage="Edit" />,
link: PIPELINE_EDIT_URI_FACTORY(pipelineId),
icon: <EditIcon gapRight />,
},
]}
/>
);

PipelineNavigation.propTypes = {
pipelineId: PropTypes.string.isRequired,
canViewDetail: PropTypes.bool,
canEdit: PropTypes.bool,
isLoggedInUser: PropTypes.bool,
links: PropTypes.object.isRequired,
};

export default withLinks(PipelineNavigation);
1 change: 1 addition & 0 deletions src/components/layout/Navigation/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ export { default as AssignmentNavigation } from './AssignmentNavigation';
export { default as AssignmentSolutionNavigation } from './AssignmentSolutionNavigation';
export { default as ExerciseNavigation } from './ExerciseNavigation';
export { default as GroupNavigation } from './GroupNavigation';
export { default as PipelineNavigation } from './PipelineNavigation';
export { default as ReferenceSolutionNavigation } from './ReferenceSolutionNavigation';
export { default as ShadowAssignmentNavigation } from './ShadowAssignmentNavigation';
export { default as UserNavigation } from './UserNavigation';
64 changes: 64 additions & 0 deletions src/containers/PipelineNameContainer/PipelineNameContainer.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
import { connect } from 'react-redux';
import { FormattedMessage } from 'react-intl';
import { Link } from 'react-router-dom';

import { fetchPipelineIfNeeded } from '../../redux/modules/pipelines';
import { getPipeline } from '../../redux/selectors/pipelines';
import ResourceRenderer from '../../components/helpers/ResourceRenderer';
import { LoadingIcon } from '../../components/icons';
import withLinks from '../../helpers/withLinks';

class PipelineNameContainer extends Component {
componentDidMount = () => this.props.loadPipelineIfNeeded();

componentDidUpdate(prevProps) {
if (this.props.pipelineId !== prevProps.pipelineId) {
this.props.loadPipelineIfNeeded();
}
}

render() {
const {
pipelineId,
pipeline,
noLink = false,
links: { PIPELINE_URI_FACTORY },
} = this.props;
return (
<ResourceRenderer
resource={pipeline}
loading={
<>
<LoadingIcon gapRight />
<FormattedMessage id="generic.loading" defaultMessage="Loading..." />
</>
}>
{pipeline =>
noLink ? <>{pipeline.name}</> : <Link to={PIPELINE_URI_FACTORY(pipelineId)}>{pipeline.name}</Link>
}
</ResourceRenderer>
);
}
}

PipelineNameContainer.propTypes = {
pipelineId: PropTypes.string.isRequired,
pipeline: ImmutablePropTypes.map,
noLink: PropTypes.bool,
loadPipelineIfNeeded: PropTypes.func.isRequired,
links: PropTypes.object.isRequired,
};

export default withLinks(
connect(
(state, { pipelineId }) => ({
pipeline: getPipeline(pipelineId)(state),
}),
(dispatch, { pipelineId }) => ({
loadPipelineIfNeeded: () => dispatch(fetchPipelineIfNeeded(pipelineId)),
})
)(PipelineNameContainer)
);
2 changes: 2 additions & 0 deletions src/containers/PipelineNameContainer/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
import PipelineNameContainer from './PipelineNameContainer';
export default PipelineNameContainer;
2 changes: 1 addition & 1 deletion src/locales/cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,7 @@
"app.navigation.group": "Skupina",
"app.navigation.groupAssignments": "Úlohy ve skupině",
"app.navigation.groupInfo": "Info skupiny",
"app.navigation.pipeline": "Pipeline",
"app.navigation.referenceSolution": "Referenční řešení",
"app.navigation.shadowAssignment": "Stínová úloha",
"app.navigation.solution": "Řešení",
Expand Down Expand Up @@ -1102,7 +1103,6 @@
"app.passwordStrength.somewhatOk": "Šlo by to i lépe.",
"app.passwordStrength.unknown": "...",
"app.passwordStrength.worst": "Nevyhovující",
"app.pipeline.editSettings": "Upravit pipeline",
"app.pipeline.exercises": "Úlohy:",
"app.pipeline.failedDetail": "Načítání detailů pipeline selhalo. Ujistěte se prosím, že jste připojeni k Internetu a zkuste to později.",
"app.pipeline.loadingDetail": "Načítám podrobnosti pipeline",
Expand Down
2 changes: 1 addition & 1 deletion src/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -1073,6 +1073,7 @@
"app.navigation.group": "Group",
"app.navigation.groupAssignments": "Group Assignments",
"app.navigation.groupInfo": "Group Info",
"app.navigation.pipeline": "Pipeline",
"app.navigation.referenceSolution": "Reference Solution",
"app.navigation.shadowAssignment": "Shadow Assignment",
"app.navigation.solution": "Solution",
Expand Down Expand Up @@ -1102,7 +1103,6 @@
"app.passwordStrength.somewhatOk": "You can do better.",
"app.passwordStrength.unknown": "...",
"app.passwordStrength.worst": "Unsatisfactory",
"app.pipeline.editSettings": "Edit pipeline",
"app.pipeline.exercises": "Exercises:",
"app.pipeline.failedDetail": "Loading the details of the pipeline failed. Please make sure you are connected to the Internet and try again later.",
"app.pipeline.loadingDetail": "Loading pipeline detail",
Expand Down
1 change: 1 addition & 0 deletions src/locales/whitelist_cs.json
Original file line number Diff line number Diff line change
Expand Up @@ -112,6 +112,7 @@
"app.homepage.githubLink",
"app.homepage.title",
"app.instancesTable.admin",
"app.navigation.pipeline",
"app.passwordStrength.ok",
"app.passwordStrength.unknown",
"app.pipelines.boxesTable.port",
Expand Down
13 changes: 10 additions & 3 deletions src/pages/EditPipeline/EditPipeline.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import { reset } from 'redux-form';
import { defaultMemoize } from 'reselect';

import Page from '../../components/layout/Page';
import { PipelineNavigation } from '../../components/layout/Navigation';
import Box from '../../components/widgets/Box';
import Callout from '../../components/widgets/Callout';
import EditPipelineForm from '../../components/forms/EditPipelineForm';
Expand All @@ -26,7 +27,7 @@ import { runtimeEnvironmentsSelector } from '../../redux/selectors/runtimeEnviro
import { isLoggedAsSuperAdmin } from '../../redux/selectors/users';

import withLinks from '../../helpers/withLinks';
import { arrayToObject } from '../../helpers/common';
import { arrayToObject, hasPermissions } from '../../helpers/common';

// convert pipeline data into initial structure for pipeline edit metadata form
const perpareInitialPipelineData = ({ name, description, version, parameters, author }) => ({
Expand Down Expand Up @@ -114,7 +115,13 @@ class EditPipeline extends Component {
icon={<EditIcon />}
title={<FormattedMessage id="app.editPipeline.title" defaultMessage="Change Pipeline Settings and Contents" />}>
{pipeline => (
<div>
<>
<PipelineNavigation
pipelineId={pipeline.id}
canViewDetail={hasPermissions(pipeline, 'viewDetail')}
canEdit={hasPermissions(pipeline, 'update')}
/>

<Row>
<Col lg={12}>
<Callout variant="warning">
Expand Down Expand Up @@ -192,7 +199,7 @@ class EditPipeline extends Component {
</Box>
</Col>
</Row>
</div>
</>
)}
</Page>
);
Expand Down
Loading

0 comments on commit ce36e76

Please sign in to comment.