update doing
This commit is contained in:
parent
cfe9ee5da9
commit
8c06526757
|
|
@ -246,4 +246,18 @@ class JiraController extends Controller
|
||||||
// dd($tasksByUser);
|
// dd($tasksByUser);
|
||||||
return $tasksByUser;
|
return $tasksByUser;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public function getAllUserDoing(Request $request)
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
$doing = $this->jiraService->getAllUserDoing();
|
||||||
|
return response()->json([
|
||||||
|
'data' => $doing,
|
||||||
|
'status' => true
|
||||||
|
], 200);
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
return response()->json(['error' => $e->getMessage()], 500);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -149,6 +149,7 @@ class TimekeepingController extends Controller
|
||||||
|
|
||||||
return response()->json(['status' => true, 'message' => 'Add successfully']);
|
return response()->json(['status' => true, 'message' => 'Add successfully']);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public function updateCacheMonth(Request $request)
|
public function updateCacheMonth(Request $request)
|
||||||
|
|
|
||||||
|
|
@ -103,6 +103,7 @@ Route::middleware('api')
|
||||||
Route::get('/all-project', [JiraController::class, 'getAllProject']);
|
Route::get('/all-project', [JiraController::class, 'getAllProject']);
|
||||||
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::group([
|
Route::group([
|
||||||
|
|
|
||||||
|
|
@ -73,7 +73,7 @@ class JiraService
|
||||||
'expand' => ['names', 'schema', 'operations'],
|
'expand' => ['names', 'schema', 'operations'],
|
||||||
'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'assignee', 'project'],
|
'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'assignee', 'project'],
|
||||||
'jql' => sprintf(
|
'jql' => sprintf(
|
||||||
"assignee = '%s' AND status IN ('backlog', 'todo', 'in progress')",
|
"assignee = '%s' AND status IN ('backlog', 'to do', 'in progress')",
|
||||||
$accountId
|
$accountId
|
||||||
),
|
),
|
||||||
'maxResults' => 50,
|
'maxResults' => 50,
|
||||||
|
|
@ -188,4 +188,64 @@ class JiraService
|
||||||
|
|
||||||
return $workLogs;
|
return $workLogs;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function getAllUserDoing()
|
||||||
|
{
|
||||||
|
$users = $this->getAllUsers();
|
||||||
|
// $projects = $this->getAllProjects();
|
||||||
|
$groupedIssues = [];
|
||||||
|
$users_data = [];
|
||||||
|
foreach ($users as $user) {
|
||||||
|
$users_data[$user['displayName']]['user'] = $user;
|
||||||
|
$users_data[$user['displayName']]['total_spent'] = 0;
|
||||||
|
$users_data[$user['displayName']]['total_est'] = 0;
|
||||||
|
$body = [
|
||||||
|
'expand' => ['names', 'schema'],
|
||||||
|
'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'assignee', 'project'],
|
||||||
|
'jql' => sprintf(
|
||||||
|
"assignee = '%s' AND status IN ('to do', 'in progress')",
|
||||||
|
$user['accountId']
|
||||||
|
),
|
||||||
|
'maxResults' => 50,
|
||||||
|
'startAt' => 0
|
||||||
|
];
|
||||||
|
|
||||||
|
$response = $this->client->post('/rest/api/3/search', [
|
||||||
|
'body' => json_encode($body)
|
||||||
|
]);
|
||||||
|
|
||||||
|
$issues = json_decode($response->getBody()->getContents(), true);
|
||||||
|
|
||||||
|
foreach ($issues['issues'] as $issue) {
|
||||||
|
$projectName = $issue['fields']['project']['name'];
|
||||||
|
$username = $issue['fields']['assignee']['displayName'];
|
||||||
|
|
||||||
|
if (!isset($groupedIssues[$projectName])) {
|
||||||
|
$groupedIssues[$projectName] = [];
|
||||||
|
$groupedIssues[$projectName]['project'] = $issue['fields']['project'];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isset($groupedIssues[$projectName]['users'][$username])) {
|
||||||
|
$groupedIssues[$projectName]['users'][$username] = [];
|
||||||
|
$groupedIssues[$projectName]['users'][$username]['user'] = $issue['fields']['assignee'];
|
||||||
|
$groupedIssues[$projectName]['users'][$username]['p_total_spent'] = 0;
|
||||||
|
$groupedIssues[$projectName]['users'][$username]['p_total_est'] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
$groupedIssues[$projectName]['users'][$username]['issues'][] = $issue;
|
||||||
|
$groupedIssues[$projectName]['users'][$username]['p_total_spent'] = $groupedIssues[$projectName]['users'][$username]['p_total_spent'] + $issue['fields']['timespent'];
|
||||||
|
$groupedIssues[$projectName]['users'][$username]['p_total_est'] = $groupedIssues[$projectName]['users'][$username]['p_total_est'] + ($issue['fields']['timeoriginalestimate'] ?? 0);
|
||||||
|
|
||||||
|
$users_data[$user['displayName']]['total_spent'] = $users_data[$user['displayName']]['total_spent'] + $issue['fields']['timespent'];
|
||||||
|
$users_data[$user['displayName']]['total_est'] = $users_data[$user['displayName']]['total_est'] + ($issue['fields']['timeoriginalestimate'] ?? 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return ['projects' => $groupedIssues, 'users' => $users_data];
|
||||||
|
// return $projects;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
use Illuminate\Database\Migrations\Migration;
|
||||||
|
use Illuminate\Database\Schema\Blueprint;
|
||||||
|
use Illuminate\Support\Facades\Schema;
|
||||||
|
|
||||||
|
return new class extends Migration
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* Run the migrations.
|
||||||
|
*/
|
||||||
|
public function up(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->string('avatar');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reverse the migrations.
|
||||||
|
*/
|
||||||
|
public function down(): void
|
||||||
|
{
|
||||||
|
Schema::table('users', function (Blueprint $table) {
|
||||||
|
$table->dropColumn('avatar');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
@ -14,6 +14,7 @@ export const exportIssues = API_URL + 'v1/admin/jira/export-issues'
|
||||||
export const getAllProjects = API_URL + 'v1/admin/jira/all-project'
|
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'
|
||||||
|
|
||||||
//Timekeeping
|
//Timekeeping
|
||||||
export const getTheTimesheet = API_URL + 'v1/admin/timekeeping'
|
export const getTheTimesheet = API_URL + 'v1/admin/timekeeping'
|
||||||
|
|
|
||||||
|
|
@ -20,11 +20,13 @@ import {
|
||||||
} from '@mantine/core'
|
} from '@mantine/core'
|
||||||
import { notifications } from '@mantine/notifications'
|
import { notifications } from '@mantine/notifications'
|
||||||
import {
|
import {
|
||||||
|
IconBinaryTree2,
|
||||||
IconCalendar,
|
IconCalendar,
|
||||||
IconCalendarClock,
|
IconCalendarClock,
|
||||||
IconDevices,
|
IconDevices,
|
||||||
IconLayoutSidebarLeftExpand,
|
IconLayoutSidebarLeftExpand,
|
||||||
IconLayoutSidebarRightExpand,
|
IconLayoutSidebarRightExpand,
|
||||||
|
IconListCheck,
|
||||||
IconLogout,
|
IconLogout,
|
||||||
// IconMail,
|
// IconMail,
|
||||||
IconMoon,
|
IconMoon,
|
||||||
|
|
@ -35,13 +37,12 @@ import {
|
||||||
IconSun,
|
IconSun,
|
||||||
IconTicket,
|
IconTicket,
|
||||||
IconUsersGroup,
|
IconUsersGroup,
|
||||||
IconZoomExclamation,
|
IconZoomExclamation
|
||||||
} from '@tabler/icons-react'
|
} from '@tabler/icons-react'
|
||||||
import { useCallback, useEffect, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import { useLocation, useNavigate } from 'react-router-dom'
|
import { useLocation, useNavigate } from 'react-router-dom'
|
||||||
import PasswordRequirementInput from '../PasswordRequirementInput/PasswordRequirementInput'
|
import PasswordRequirementInput from '../PasswordRequirementInput/PasswordRequirementInput'
|
||||||
import classes from './NavbarSimpleColored.module.css'
|
import classes from './NavbarSimpleColored.module.css'
|
||||||
import { IconListCheck } from '@tabler/icons-react'
|
|
||||||
|
|
||||||
const data = [
|
const data = [
|
||||||
// { link: '/dashboard', label: 'Dashboard', icon: IconHome },
|
// { link: '/dashboard', label: 'Dashboard', icon: IconHome },
|
||||||
|
|
@ -94,6 +95,12 @@ const data = [
|
||||||
icon: IconZoomExclamation,
|
icon: IconZoomExclamation,
|
||||||
group: 'admin',
|
group: 'admin',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
link: '/allocation',
|
||||||
|
label: 'Personnel allocation',
|
||||||
|
icon: IconBinaryTree2,
|
||||||
|
group: 'admin',
|
||||||
|
},
|
||||||
// { link: '/jira', label: 'Jira', icon: IconSubtask },
|
// { link: '/jira', label: 'Jira', icon: IconSubtask },
|
||||||
// { link: '/custom-theme', label: 'Custom Theme', icon: IconBrush },
|
// { link: '/custom-theme', label: 'Custom Theme', icon: IconBrush },
|
||||||
// { link: '/general-setting', label: 'General Setting', icon: IconSettings },
|
// { link: '/general-setting', label: 'General Setting', icon: IconSettings },
|
||||||
|
|
@ -400,7 +407,7 @@ const Navbar = ({
|
||||||
</span>
|
</span>
|
||||||
</a>
|
</a>
|
||||||
<div className={classes.footer}></div>
|
<div className={classes.footer}></div>
|
||||||
<a href="#" className={classes.link} onClick={handleSetCompactMenu}>
|
<a href="#" className={classes.link} onClick={handleSetCompactMenu} style={{margin:"0 20px", padding:"0 0 10px 0"}}>
|
||||||
{isCompactMenu ? (
|
{isCompactMenu ? (
|
||||||
<IconLayoutSidebarLeftExpand
|
<IconLayoutSidebarLeftExpand
|
||||||
className={classes.linkIcon}
|
className={classes.linkIcon}
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@
|
||||||
font-size: var(--mantine-font-size-sm);
|
font-size: var(--mantine-font-size-sm);
|
||||||
color: rgb(161, 161, 161);
|
color: rgb(161, 161, 161);
|
||||||
padding: var(--mantine-spacing-xs) var(--mantine-spacing-sm);
|
padding: var(--mantine-spacing-xs) var(--mantine-spacing-sm);
|
||||||
margin: var(--mantine-spacing-xs);
|
margin: 0 var(--mantine-spacing-xs);
|
||||||
border-radius: var(--mantine-radius-sm);
|
border-radius: var(--mantine-radius-sm);
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load Diff
|
|
@ -2,6 +2,7 @@
|
||||||
import ResetPassword from '@/components/Authentication/ResetPassword'
|
import ResetPassword from '@/components/Authentication/ResetPassword'
|
||||||
import BasePage from '@/components/BasePage/BasePage'
|
import BasePage from '@/components/BasePage/BasePage'
|
||||||
import ProtectedRoute from '@/components/ProtectedRoute/ProtectedRoute'
|
import ProtectedRoute from '@/components/ProtectedRoute/ProtectedRoute'
|
||||||
|
import Allocation from '@/pages/Allocation/Allocation'
|
||||||
import PageLogin from '@/pages/Auth/Login/Login'
|
import PageLogin from '@/pages/Auth/Login/Login'
|
||||||
import LeaveManagement from '@/pages/LeaveManagement/LeaveManagement'
|
import LeaveManagement from '@/pages/LeaveManagement/LeaveManagement'
|
||||||
import PageNotFound from '@/pages/NotFound/NotFound'
|
import PageNotFound from '@/pages/NotFound/NotFound'
|
||||||
|
|
@ -174,6 +175,20 @@ const mainRoutes = [
|
||||||
</ProtectedRoute>
|
</ProtectedRoute>
|
||||||
),
|
),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
path: '/allocation',
|
||||||
|
element: (
|
||||||
|
<ProtectedRoute mode="route" permission="admin">
|
||||||
|
<BasePage
|
||||||
|
main={
|
||||||
|
<>
|
||||||
|
<Allocation />
|
||||||
|
</>
|
||||||
|
}
|
||||||
|
></BasePage>
|
||||||
|
</ProtectedRoute>
|
||||||
|
),
|
||||||
|
},
|
||||||
// {
|
// {
|
||||||
// path: '/packages',
|
// path: '/packages',
|
||||||
// element: (
|
// element: (
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue