Create a workflow statistics page from Jira

This commit is contained in:
JOSEPH LE 2024-05-20 16:30:57 +07:00
parent 010fe6e650
commit 9b630fe1e1
3 changed files with 320 additions and 342 deletions

View File

@ -76,7 +76,7 @@ class JiraService
"assignee = '%s' AND status IN ('backlog', 'todo', 'in progress')",
$accountId
),
'maxResults' => 10,
'maxResults' => 50,
'startAt' => $startAt
];
@ -104,7 +104,7 @@ class JiraService
$body = [
'jql' => "worklogAuthor = '{$accountId}'AND worklogDate >= '{$startDate}' AND worklogDate <= '{$endDate}'",
'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'project'],
'maxResults' => 50
'maxResults' => 100
];
$response = $this->client->post('/rest/api/3/search', [
@ -134,7 +134,7 @@ class JiraService
]
])->then(function ($checkApiResponse) use ($issueId, $index) {
$checkApi = json_decode($checkApiResponse->getBody()->getContents(), true);
$maxResults = 50;
$maxResults = 100;
$totalWorklogs = $checkApi['total'];
return $this->client->getAsync("/rest/api/3/issue/{$issueId}/worklog", [
'query' => [

View File

@ -116,8 +116,13 @@ const Tracking = () => {
}
useEffect(()=>{
setInterval(()=>{
if(listTracking.data.length === 0){
getAllTracking()
}
setInterval(()=>{
if(window.location.pathname.includes('tracking')){
getAllTracking()
}
}, 7000)
}, [])
return (

View File

@ -117,7 +117,7 @@ const Worklogs = () => {
startDate:
localStorage.getItem('data') !== null
? JSON.parse(localStorage.getItem('data')!).date.startDate
: moment(Date.now()).format('YYYY-MM-DD'),
: moment(Date.now()-604800000).format('YYYY-MM-DD'),
endDate:
localStorage.getItem('data') !== null
? JSON.parse(localStorage.getItem('data')!).date.endDate
@ -186,22 +186,34 @@ const Worklogs = () => {
</div>
<Box
display={'flex'}
w={'30%'}
style={{
float: 'right',
// margin: '10px',
flexFlow: 'column',
}}
>
<Text fz={12} fs={'italic'} c={'red'} fw={600} mt={'md'}>
{`* The current data is from ${JSON.parse(localStorage.getItem('data')!).date.startDate} to ${JSON.parse(localStorage.getItem('data')!).date.endDate}`}
</Text>
<Text fz={12} fs={'italic'} c={'red'} fw={600}>
{`* If you need data outside this time period, please select a date and click "Search" to update the latest data.`}
</Text>
<Box w={'100%'} display={'flex'} style={{ flexFlow: 'column' }}>
<Box
w={'100%'}
display={'flex'}
style={{
alignItems: 'end',
justifyContent: 'space-between',
// justifyContent: 'space-between',
flexWrap: 'wrap',
}}
>
<DateInput
size="xs"
label="From date:"
value={new Date(date.startDate)}
w={'40%'}
w={'20%'}
clearable
onChange={(e) => {
setDate({ ...date, startDate: moment(e).format('YYYY-MM-DD') })
setDate({ ...date, startDate: moment(e).format('YYYY-MM-DD') });
}}
/>
<DateInput
@ -209,27 +221,38 @@ const Worklogs = () => {
label="To date:"
value={new Date(date.endDate)}
clearable
w={'40%'}
m={"0 10px"}
w={'20%'}
onChange={(e) => {
setDate({ ...date, endDate: moment(e).format('YYYY-MM-DD') })
setDate({ ...date, endDate: moment(e).format('YYYY-MM-DD') });
}}
/>
<Button
size="xs"
onClick={() => {
getAllWorklogs()
getAllWorklogs();
}}
>
Search
</Button>
</Box>
</Box>
</Box>
{/* Box main content */}
<Box display={'flex'} mt={'lg'}>
<Box w={'10%'} >
<Box display={'flex'} mt={'lg'} style={{ flexWrap: 'wrap' }}>
<Box w={{ base: '100%', md: '15%' }} mb={'lg'}>
<Text fw={700} fz={14}>
Members
</Text>
<Box style={{border:"solid 1px gray", padding:"10px", marginRight:"10px", borderRadius:"5px", boxShadow: '1px 1px 5px 1px gray',}}>
<Box
style={{
border: 'solid 1px gray',
padding: '10px 20px',
marginRight: '10px',
borderRadius: '5px',
boxShadow: '1px 1px 5px 1px gray',
}}
>
{worklogs.map((w) => (
<Box
key={w.username}
@ -252,10 +275,9 @@ const Worklogs = () => {
</Box>
))}
</Box>
</Box>
<Box
w={'90%'}
w={{ base: '100%', md: '85%' }}
h={'85vh'}
display={'flex'}
style={{ overflowX: 'auto', flexFlow: 'column' }}
@ -271,52 +293,39 @@ const Worklogs = () => {
borderRadius: '5px',
borderColor: '#afafaf',
marginBottom: '10px',
backgroundColor:
index % 2 === 0 ? 'rgb(201 201 201 / 28%)' : 'white',
backgroundColor: index % 2 === 0 ? 'rgb(201 201 201 / 28%)' : 'white',
}}
>
<Text ta={'left'} mb={'xs'} fw={800} display={'flex'}>
<Avatar
src={user.user.avatarUrls['48x48']}
size={'sm'}
m={'0 5px'}
/>
<Avatar src={user.user.avatarUrls['48x48']} size={'sm'} m={'0 5px'} />
{user.username}(
{user?.information.issues.reduce(
(total: number, issue: Issue) => {
var totalSpent = issue.fields.worklog.worklogs?.reduce(
(accumulator: number, currentValue: WorkLog) => {
{user?.information.issues.reduce((total, issue) => {
const totalSpent = issue.fields.worklog.worklogs?.reduce(
(accumulator, currentValue) => {
if (
parseInt(moment(date.startDate).format('YYYYMMDD')) <=
parseInt(
moment(currentValue.started).format('YYYYMMDD'),
) &&
parseInt(
moment(currentValue.started).format('YYYYMMDD'),
) <=
parseInt(moment(currentValue.started).format('YYYYMMDD')) &&
parseInt(moment(currentValue.started).format('YYYYMMDD')) <=
parseInt(moment(date.endDate).format('YYYYMMDD')) &&
currentValue.updateAuthor.displayName ===
user.username
currentValue.updateAuthor.displayName === user.username
) {
return accumulator + currentValue.timeSpentSeconds
return accumulator + currentValue.timeSpentSeconds;
}
return accumulator
return accumulator;
},
0,
)
return total + totalSpent
},
0,
) /
);
return total + totalSpent;
}, 0) /
60 /
60}
h)
</Text>
{/* Box issue-todo */}
<Box display={'flex'} style={{ justifyContent: 'space-between' }}>
<Box display={'flex'} style={{ justifyContent: 'space-between', flexWrap: 'wrap' }}>
{/* Box issue */}
<Box
w={'50%'}
w={{ base: '100%', md: '50%' }}
style={{
border: 'solid 1px gray',
borderRadius: '5px',
@ -358,16 +367,12 @@ const Worklogs = () => {
>
{/* Box information issue */}
<Box>
<Text
fz={14}
display={'flex'}
style={{ alignItems: 'start' }}
>
<Text fz={14} c={iss.fields.status.statusCategory.colorName}>
<b>{iss.fields.status.name}</b>
</Text>
<Text fz={14} display={'flex'} style={{ alignItems: 'start' }}>
<b>Summary:</b>{' '}
<Box
display={'flex'}
style={{ alignItems: 'center' }}
>
<Box display={'flex'} style={{ alignItems: 'center' }}>
<Avatar
src={iss.fields.project?.avatarUrls['16x16']}
size={'xs'}
@ -377,54 +382,40 @@ const Worklogs = () => {
{iss.fields.project.name}
</Text>
</Box>
<a
href={`https://apactechvn.atlassian.net/browse/${iss.key}`}
target="_blank"
>
<a href={`https://apactechvn.atlassian.net/browse/${iss.key}`} target="_blank">
{iss.fields.summary}
</a>
</Text>
<Text fz={14}>
<b>Estimate:</b>{' '}
{iss.fields.timeoriginalestimate / 60 / 60}h
<b>Estimate:</b> {iss.fields.timeoriginalestimate / 60 / 60}h
</Text>
<Text fz={14}>
<b>Total time spent:</b>{' '}
{iss.fields.timespent / 60 / 60}h
<b>Total time spent:</b> {iss.fields.timespent / 60 / 60}h
</Text>
<Text fz={14}>
<b>Time spent <span style={{fontSize:"11px"}}>({date.startDate === date.endDate ? date.startDate : date.startDate+" to "+date.endDate})</span>:</b>
{' '}{iss.fields.worklog.worklogs?.reduce(
<b>
Time spent{' '}
<span style={{ fontSize: '11px' }}>
(
accumulator: number,
currentValue: WorkLog,
) => {
if (
parseInt(
moment(date.startDate).format('YYYYMMDD'),
) <=
parseInt(
moment(currentValue.started).format(
'YYYYMMDD',
),
) &&
parseInt(
moment(currentValue.started).format(
'YYYYMMDD',
),
) <=
parseInt(
moment(date.endDate).format('YYYYMMDD'),
) &&
currentValue.updateAuthor.displayName ===
user.username
) {
return (
accumulator +
currentValue.timeSpentSeconds
{date.startDate === date.endDate
? date.startDate
: date.startDate + ' to ' + date.endDate}
)
</span>
:
</b>{' '}
{iss.fields.worklog.worklogs?.reduce(
(accumulator, currentValue) => {
if (
parseInt(moment(date.startDate).format('YYYYMMDD')) <=
parseInt(moment(currentValue.started).format('YYYYMMDD')) &&
parseInt(moment(currentValue.started).format('YYYYMMDD')) <=
parseInt(moment(date.endDate).format('YYYYMMDD')) &&
currentValue.updateAuthor.displayName === user.username
) {
return accumulator + currentValue.timeSpentSeconds;
}
return accumulator
return accumulator;
},
0,
) /
@ -435,10 +426,8 @@ const Worklogs = () => {
</Box>
{iss.fields.worklog.worklogs?.map((log, index) => {
if (
moment(date.startDate).format('YYYYMMDD') <=
moment(log.started).format('YYYYMMDD') &&
moment(log.started).format('YYYYMMDD') <=
moment(date.endDate).format('YYYYMMDD') &&
moment(date.startDate).format('YYYYMMDD') <= moment(log.started).format('YYYYMMDD') &&
moment(log.started).format('YYYYMMDD') <= moment(date.endDate).format('YYYYMMDD') &&
log.updateAuthor.displayName === user.username
) {
return (
@ -453,36 +442,28 @@ const Worklogs = () => {
}}
>
<Text fz={13}>
<b>Start date:</b>{' '}
{moment(log.started).format(
'HH:mm YYYY/MM/DD',
)}
<b>Start date:</b> {moment(log.started).format('HH:mm YYYY/MM/DD')}
</Text>
<Text fz={13}>
<b>Time spent:</b> {log.timeSpent}
</Text>
{log?.comment &&
log?.comment?.content[0]?.content[0]
?.text && (
{log?.comment && log?.comment?.content[0]?.content[0]?.text && (
<Text fz={13}>
<b>Comment:</b>{' '}
{log?.comment &&
log?.comment?.content[0]?.content[0]
?.text}
<b>Comment:</b> {log?.comment?.content[0]?.content[0]?.text}
</Text>
)}
</Box>
)
);
}
})}
</Box>
)
);
}
})}
</Box>
{/* Box todo */}
<Box
w={'49%'}
w={{ base: '100%', md: '49%' }}
style={{
border: 'solid 1px gray',
borderRadius: '5px',
@ -521,16 +502,9 @@ const Worklogs = () => {
{iss.fields.project.name}
</Text>
</Box>
<Text
fz={14}
display={'flex'}
style={{ alignItems: 'start' }}
>
<Text fz={14} display={'flex'} style={{ alignItems: 'start' }}>
<b style={{ marginRight: '5px' }}>Summary:</b>
<a
href={`https://apactechvn.atlassian.net/browse/${iss.key}`}
target="_blank"
>
<a href={`https://apactechvn.atlassian.net/browse/${iss.key}`} target="_blank">
{iss.fields.summary}
</a>
</Text>
@ -540,12 +514,11 @@ const Worklogs = () => {
<Text fz={13}>
<b>Estimate:</b> {iss.fields.timeoriginalestimate / 60 / 60}h
</Text>
<Text fz={'14'}>
<b style={{ marginRight: '5px' }}>Status:</b>
{iss.fields.status.name}
<Text fz={14} c={iss.fields.status.statusCategory.colorName}>
<b>{iss.fields.status.name}</b>
</Text>
</Box>
)
);
})}
</Box>
</Box>