update allocation
This commit is contained in:
parent
fe75a08c3d
commit
a855787a47
|
|
@ -260,4 +260,14 @@ class JiraController extends Controller
|
||||||
return response()->json(['error' => $e->getMessage()], 500);
|
return response()->json(['error' => $e->getMessage()], 500);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDetailIssueById(Request $request)
|
||||||
|
{
|
||||||
|
$data = $this->jiraService->getDetailIssueByKey($request->issueKey);
|
||||||
|
|
||||||
|
return response()->json([
|
||||||
|
'data' => $data,
|
||||||
|
'status' => true
|
||||||
|
], 200);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -104,6 +104,7 @@ Route::middleware('api')
|
||||||
Route::get('/all-issue-by-project', [JiraController::class, 'fetchIssuesByProject']);
|
Route::get('/all-issue-by-project', [JiraController::class, 'fetchIssuesByProject']);
|
||||||
Route::get('/worklogs', [JiraController::class, 'getAllUserWorkLogs'])->middleware('check.permission:admin.staff');
|
Route::get('/worklogs', [JiraController::class, 'getAllUserWorkLogs'])->middleware('check.permission:admin.staff');
|
||||||
Route::get('/allocation', [JiraController::class, 'getAllUserDoing'])->middleware('check.permission:admin.staff');
|
Route::get('/allocation', [JiraController::class, 'getAllUserDoing'])->middleware('check.permission:admin.staff');
|
||||||
|
Route::get('/issue/detail', [JiraController::class, 'getDetailIssueById'])->middleware('check.permission:admin.staff');
|
||||||
});
|
});
|
||||||
|
|
||||||
Route::group([
|
Route::group([
|
||||||
|
|
|
||||||
|
|
@ -238,9 +238,9 @@ class JiraService
|
||||||
$users_data[$user['displayName']]['total_est'] = 0;
|
$users_data[$user['displayName']]['total_est'] = 0;
|
||||||
$body = [
|
$body = [
|
||||||
'expand' => ['names', 'schema'],
|
'expand' => ['names', 'schema'],
|
||||||
'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'assignee', 'project'],
|
'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'assignee', 'project', 'updated'],
|
||||||
'jql' => sprintf(
|
'jql' => sprintf(
|
||||||
"assignee = '%s' AND status IN ('to do', 'in progress')",
|
"assignee = '%s' AND status IN ('to do', 'in progress') ORDER BY updated DESC",
|
||||||
$user['accountId']
|
$user['accountId']
|
||||||
),
|
),
|
||||||
'maxResults' => 50,
|
'maxResults' => 50,
|
||||||
|
|
@ -289,4 +289,11 @@ class JiraService
|
||||||
return ['projects' => $groupedIssues, 'users' => $users_data, 'warningList' => $user_warning];
|
return ['projects' => $groupedIssues, 'users' => $users_data, 'warningList' => $user_warning];
|
||||||
// return $projects;
|
// return $projects;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getDetailIssueByKey($issueKey)
|
||||||
|
{
|
||||||
|
$issueResponse = $this->client->get("/rest/api/3/issue/{$issueKey}?expand=changelog");
|
||||||
|
$issueDetail = json_decode($issueResponse->getBody()->getContents(), true);
|
||||||
|
return $issueDetail;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ export const getAllProjects = API_URL + 'v1/admin/jira/all-project'
|
||||||
export const getAllIssuesByProject = API_URL + 'v1/admin/jira/all-issue-by-project'
|
export const getAllIssuesByProject = API_URL + 'v1/admin/jira/all-issue-by-project'
|
||||||
export const getAllUserWorklogs = API_URL + 'v1/admin/jira/worklogs'
|
export const getAllUserWorklogs = API_URL + 'v1/admin/jira/worklogs'
|
||||||
export const getAllUserDoing = API_URL + 'v1/admin/jira/allocation'
|
export const getAllUserDoing = API_URL + 'v1/admin/jira/allocation'
|
||||||
|
export const getDetailIssByKey = API_URL + 'v1/admin/jira/issue/detail'
|
||||||
|
|
||||||
//Timekeeping
|
//Timekeeping
|
||||||
export const getTheTimesheet = API_URL + 'v1/admin/timekeeping'
|
export const getTheTimesheet = API_URL + 'v1/admin/timekeeping'
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,20 @@
|
||||||
import {
|
import {
|
||||||
Avatar,
|
Avatar,
|
||||||
|
Badge,
|
||||||
Box,
|
Box,
|
||||||
Card,
|
Card,
|
||||||
Loader,
|
Loader,
|
||||||
|
Modal,
|
||||||
Popover,
|
Popover,
|
||||||
Text
|
Text,
|
||||||
|
Tooltip
|
||||||
} from '@mantine/core'
|
} from '@mantine/core'
|
||||||
import { useDisclosure } from '@mantine/hooks'
|
import { useDisclosure } from '@mantine/hooks'
|
||||||
import { useEffect, useState } from 'react'
|
import { useEffect, useState } from 'react'
|
||||||
import classes from './Allocation.module.css'
|
import classes from './Allocation.module.css'
|
||||||
import { get } from '@/rtk/helpers/apiService'
|
import { get } from '@/rtk/helpers/apiService'
|
||||||
import { getAllUserDoing } from '@/api/Admin'
|
import { getAllUserDoing, getDetailIssByKey } from '@/api/Admin'
|
||||||
|
import moment from 'moment'
|
||||||
interface UserInfo {
|
interface UserInfo {
|
||||||
self: string
|
self: string
|
||||||
accountId: string
|
accountId: string
|
||||||
|
|
@ -42,6 +46,7 @@ interface IssueFields {
|
||||||
timeoriginalestimate: number
|
timeoriginalestimate: number
|
||||||
project: ProjectInfo
|
project: ProjectInfo
|
||||||
status: StatusInfo
|
status: StatusInfo
|
||||||
|
updated: string
|
||||||
}
|
}
|
||||||
|
|
||||||
interface ProjectInfo {
|
interface ProjectInfo {
|
||||||
|
|
@ -71,7 +76,9 @@ interface StatusInfo {
|
||||||
}
|
}
|
||||||
|
|
||||||
const Allocation = () => {
|
const Allocation = () => {
|
||||||
const [loading, { toggle }] = useDisclosure(true)
|
const [loading, setLoading] = useState(true)
|
||||||
|
const [opened, setOpened] = useState(false)
|
||||||
|
const [issDetail, setIssDetail] = useState("")
|
||||||
// const [data, setData] = useState<any>({
|
// const [data, setData] = useState<any>({
|
||||||
// projects: {
|
// projects: {
|
||||||
// IPS_Pro: {
|
// IPS_Pro: {
|
||||||
|
|
@ -3281,7 +3288,7 @@ const Allocation = () => {
|
||||||
try {
|
try {
|
||||||
const res = await get(getAllUserDoing)
|
const res = await get(getAllUserDoing)
|
||||||
if (res.status) {
|
if (res.status) {
|
||||||
toggle()
|
setLoading(false)
|
||||||
setData(res.data)
|
setData(res.data)
|
||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
|
@ -3289,6 +3296,30 @@ const Allocation = () => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// console.log(data)
|
// console.log(data)
|
||||||
|
|
||||||
|
const getStateChanges = (changelog:any) => {
|
||||||
|
return changelog.histories.map((history:any) => {
|
||||||
|
const author = history.author.displayName;
|
||||||
|
const created = history.created;
|
||||||
|
const changes = history.items.map((item:any) => {
|
||||||
|
return `${item.field} changed from ${item.fromString} ➔ ${item.toString}`;
|
||||||
|
}).join(', ');
|
||||||
|
|
||||||
|
return changes ? `${author} made changes on ${created}: ${changes}` : null;
|
||||||
|
}).filter(Boolean).join('\n');
|
||||||
|
};
|
||||||
|
|
||||||
|
const getDetailIssueByKey = async(key:string) =>{
|
||||||
|
try {
|
||||||
|
const res = await get(getDetailIssByKey, {issueKey: key})
|
||||||
|
if(res.status){
|
||||||
|
setIssDetail(getStateChanges(res?.data?.changelog))
|
||||||
|
setOpened(true)
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
console.log(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
getAll()
|
getAll()
|
||||||
}, [])
|
}, [])
|
||||||
|
|
@ -3436,10 +3467,19 @@ const Allocation = () => {
|
||||||
</Box>
|
</Box>
|
||||||
</Popover.Target>
|
</Popover.Target>
|
||||||
<Popover.Dropdown>
|
<Popover.Dropdown>
|
||||||
<Text size="xs">
|
|
||||||
|
<Text size="xs" style={{maxHeight:'50vh', overflow:'auto'}}>
|
||||||
{userData.issues?.map((iss: Issue) => {
|
{userData.issues?.map((iss: Issue) => {
|
||||||
|
const date = new Date(iss.fields.updated)
|
||||||
return (
|
return (
|
||||||
<Box>
|
<Tooltip label='Click to view history'>
|
||||||
|
<Box className={ Date.now() - date.getTime() > 172800000*5 ? classes['blinking-background']: ''}
|
||||||
|
style={{margin:'10px 0', borderRadius:'10px', cursor:'pointer'}}
|
||||||
|
onClick={async()=>{
|
||||||
|
setLoading(true)
|
||||||
|
await getDetailIssueByKey(iss.key)
|
||||||
|
setLoading(false)}}
|
||||||
|
>
|
||||||
<Text fw={600}>
|
<Text fw={600}>
|
||||||
<a
|
<a
|
||||||
href={
|
href={
|
||||||
|
|
@ -3464,18 +3504,24 @@ const Allocation = () => {
|
||||||
</Text>
|
</Text>
|
||||||
<Text fw={600} ml={'50px'}>
|
<Text fw={600} ml={'50px'}>
|
||||||
Time spent:{' '}
|
Time spent:{' '}
|
||||||
{iss.fields.timespent / 60 / 60}
|
<Badge size='xs' bg={'orange'}>{iss.fields.timespent / 60 / 60}h</Badge>
|
||||||
</Text>
|
</Text>
|
||||||
<Text fw={600} ml={'50px'}>
|
<Text fw={600} ml={'50px'}>
|
||||||
EST:{' '}
|
EST:{' '}
|
||||||
{iss.fields.timeoriginalestimate /
|
<Badge size='xs'>{iss.fields.timeoriginalestimate /
|
||||||
60 /
|
60 /
|
||||||
60}
|
60}h</Badge>
|
||||||
|
</Text>
|
||||||
|
<Text fw={600} ml={'50px'}>
|
||||||
|
Updated:{' '}
|
||||||
|
<Badge size='xs'>{iss.fields.updated}</Badge>
|
||||||
</Text>
|
</Text>
|
||||||
</Box>
|
</Box>
|
||||||
|
</Tooltip>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
</Popover.Dropdown>
|
</Popover.Dropdown>
|
||||||
</Popover>
|
</Popover>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
@ -3549,7 +3595,11 @@ const Allocation = () => {
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</div>
|
</div>
|
||||||
|
<Modal title={<b>HISTORY</b>} onClose={()=>setOpened(false) } opened={opened} fullScreen>
|
||||||
|
<pre>{issDetail}</pre>
|
||||||
|
</Modal>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue