widgets/time-tracking-report/src/app/time-table-general.js (212 lines of code) (raw):
import React, {useCallback} from 'react';
import PropTypes from 'prop-types';
import classNames from 'classnames';
import {i18n} from 'hub-dashboard-addons/dist/localization';
import UserLink from '../../../../components/src/user-link/user-link';
import SpentTimeValue from '../../../../components/src/spent-time-value/spent-time-value';
import SpentTimeProgress from '../../../../components/src/spent-time-progress/spent-time-progress';
import IssueLink from '../../../../components/src/issue-link/issue-link';
import './style/report-time-sheet.scss';
import './style/time-sheet-body.scss';
const TimeTableGeneralGroupLine = ({
line, fetchHub, isSubTitle, lineIdx,
activeLineIdx, onActivateLine, homeUrl, fetchYouTrack
}) => {
const activateLine = useCallback(
() => onActivateLine(lineIdx), [lineIdx]
);
return (
<div
onMouseEnter={activateLine}
className={classNames(
'time-sheet-body-general__row', {
'time-sheet-body-general__row_subtitle': isSubTitle,
'time-sheet-body-general__row_hovered': activeLineIdx === lineIdx
}
)}
>
<div className="time-sheet-body-general__row-left">
<TimeTableGeneralGroupTitle
defaultText={line.text}
meta={line.meta}
fetchHub={fetchHub}
fetchYouTrack={fetchYouTrack}
homeUrl={homeUrl}
/>
</div>
<div className="time-sheet-body-general__row-right">
{
!!line.estimation && !!line.estimation.value &&
<SpentTimeProgress
spent={line.totalSpentTime}
estimated={line.estimation}
>
<SpentTimeValue value={line.spentTime}/>
</SpentTimeProgress>
}
{
(!line.estimation || !line.estimation.value) &&
<SpentTimeValue value={line.spentTime}/>
}
</div>
</div>
);
};
TimeTableGeneralGroupLine.propTypes = {
line: PropTypes.object.isRequired,
lineIdx: PropTypes.number,
activeLineIdx: PropTypes.number,
onActivateLine: PropTypes.func,
fetchHub: PropTypes.func.isRequired,
fetchYouTrack: PropTypes.func.isRequired,
isSubTitle: PropTypes.bool,
homeUrl: PropTypes.string
};
const TimeTableGeneralGroupTitle = ({
meta, fetchHub, fetchYouTrack, defaultText, homeUrl
}) => {
if (!meta) {
return (
<span className="yt-table__cell_link-identifier">
{defaultText}
</span>
);
}
const link = meta.isIssue
? (
<IssueLink
issue={{
id: meta.id,
idReadable: meta.title,
summary: meta.description
}}
homeUrl={homeUrl}
fetchYouTrack={fetchYouTrack}
className="yt-table__cell_link-identifier"
/>
) : (
<UserLink
className="yt-table__cell_link-identifier"
user={
{ringId: meta.id, login: meta.title}
}
fetchHub={fetchHub}
homeUrl={homeUrl}
/>
);
return (
<span>
{link}
<span>{meta.description}</span>
</span>
);
};
TimeTableGeneralGroupTitle.propTypes = {
fetchHub: PropTypes.func.isRequired,
fetchYouTrack: PropTypes.func.isRequired,
meta: PropTypes.object,
defaultText: PropTypes.string,
homeUrl: PropTypes.string
};
const TimeTableGeneralGroup = ({
group, linesStartIdx, grouping, fetchHub,
fetchYouTrack, activeLineIdx, onActivateLine, homeUrl
}) => (
<div
className={classNames(
'yt-table__group',
{'yt-table__group_not-bordered': (linesStartIdx === 0)}
)}
>
{
!!grouping &&
<TimeTableGeneralGroupLine
line={group}
fetchHub={fetchHub}
fetchYouTrack={fetchYouTrack}
homeUrl={homeUrl}
isSubTitle={true}
lineIdx={linesStartIdx}
activeLineIdx={activeLineIdx}
onActivateLine={onActivateLine}
/>
}
{
group.childrenLines.map((line, idx) => (
<TimeTableGeneralGroupLine
key={`general-group-line-${line.id}`}
line={line}
homeUrl={homeUrl}
fetchHub={fetchHub}
fetchYouTrack={fetchYouTrack}
activeLineIdx={activeLineIdx}
onActivateLine={onActivateLine}
lineIdx={grouping ? (linesStartIdx + idx + 1) : (linesStartIdx + idx)}
/>
))
}
</div>
);
TimeTableGeneralGroup.propTypes = {
group: PropTypes.object.isRequired,
grouping: PropTypes.object,
linesStartIdx: PropTypes.number,
fetchHub: PropTypes.func.isRequired,
fetchYouTrack: PropTypes.func.isRequired,
activeLineIdx: PropTypes.number,
onActivateLine: PropTypes.func,
homeUrl: PropTypes.string
};
const TimeTableGeneral = ({
grouping, generalGroups, totalSpentTime,
fetchHub, fetchYouTrack, presentationControlsPanel, homeUrl, fixedHeader,
onActivateLine, activeLineIdx, sumOfGroupSizesBeforeCurrentGroup,
width
}) =>
(
<div
className={classNames({
'time-sheet-body-general': true,
'time-sheet-body-general_fixed': fixedHeader
})}
style={(fixedHeader && width) ? {width} : null}
>
<div
className={classNames({
'time-sheet-body-general__header': true,
'time-sheet-body-general__header_fixed': fixedHeader
})}
style={(fixedHeader && width) ? {width} : null}
>
<div className="time-sheet-body-general__axys-title">
{ presentationControlsPanel }
</div>
<div className="time-sheet-body-general__row time-sheet-body-general__row_total">
<div className="time-sheet-body-general__row-left">
{ i18n('Total time') }
</div>
<div className="time-sheet-body-general__row-right">
<SpentTimeValue value={totalSpentTime}/>
</div>
</div>
</div>
{
generalGroups.map((group, idx) => (
<TimeTableGeneralGroup
key={`data-group-${group.id}`}
group={group}
homeUrl={homeUrl}
linesStartIdx={
grouping
? (sumOfGroupSizesBeforeCurrentGroup[idx] + idx)
: sumOfGroupSizesBeforeCurrentGroup[idx]
}
grouping={grouping}
fetchYouTrack={fetchYouTrack}
fetchHub={fetchHub}
onActivateLine={onActivateLine}
activeLineIdx={activeLineIdx}
/>
))
}
</div>
);
TimeTableGeneral.propTypes = {
generalGroups: PropTypes.array.isRequired,
totalSpentTime: PropTypes.object,
grouping: PropTypes.object,
isIssueView: PropTypes.bool,
fetchHub: PropTypes.func.isRequired,
fetchYouTrack: PropTypes.func.isRequired,
presentationControlsPanel: PropTypes.node,
activeLineIdx: PropTypes.number,
onActivateLine: PropTypes.func,
sumOfGroupSizesBeforeCurrentGroup: PropTypes.array,
fixedHeader: PropTypes.bool,
homeUrl: PropTypes.string,
width: PropTypes.number
};
export default TimeTableGeneral;