update doing

This commit is contained in:
JOSEPH LE 2024-09-16 07:47:38 +07:00
parent cfe9ee5da9
commit 8c06526757
10 changed files with 4761 additions and 5 deletions

View File

@ -246,4 +246,18 @@ class JiraController extends Controller
// dd($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);
}
}
}

View File

@ -149,6 +149,7 @@ class TimekeepingController extends Controller
return response()->json(['status' => true, 'message' => 'Add successfully']);
}
public function updateCacheMonth(Request $request)

View File

@ -103,6 +103,7 @@ Route::middleware('api')
Route::get('/all-project', [JiraController::class, 'getAllProject']);
Route::get('/all-issue-by-project', [JiraController::class, 'fetchIssuesByProject']);
Route::get('/worklogs', [JiraController::class, 'getAllUserWorkLogs'])->middleware('check.permission:admin.staff');
Route::get('/allocation', [JiraController::class, 'getAllUserDoing'])->middleware('check.permission:admin.staff');
});
Route::group([

View File

@ -73,7 +73,7 @@ class JiraService
'expand' => ['names', 'schema', 'operations'],
'fields' => ['summary', 'status', 'timeoriginalestimate', 'timespent', 'assignee', 'project'],
'jql' => sprintf(
"assignee = '%s' AND status IN ('backlog', 'todo', 'in progress')",
"assignee = '%s' AND status IN ('backlog', 'to do', 'in progress')",
$accountId
),
'maxResults' => 50,
@ -188,4 +188,64 @@ class JiraService
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;
}
}

View File

@ -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');
});
}
};

View File

@ -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 getAllIssuesByProject = API_URL + 'v1/admin/jira/all-issue-by-project'
export const getAllUserWorklogs = API_URL + 'v1/admin/jira/worklogs'
export const getAllUserDoing = API_URL + 'v1/admin/jira/allocation'
//Timekeeping
export const getTheTimesheet = API_URL + 'v1/admin/timekeeping'

View File

@ -20,11 +20,13 @@ import {
} from '@mantine/core'
import { notifications } from '@mantine/notifications'
import {
IconBinaryTree2,
IconCalendar,
IconCalendarClock,
IconDevices,
IconLayoutSidebarLeftExpand,
IconLayoutSidebarRightExpand,
IconListCheck,
IconLogout,
// IconMail,
IconMoon,
@ -35,13 +37,12 @@ import {
IconSun,
IconTicket,
IconUsersGroup,
IconZoomExclamation,
IconZoomExclamation
} from '@tabler/icons-react'
import { useCallback, useEffect, useState } from 'react'
import { useLocation, useNavigate } from 'react-router-dom'
import PasswordRequirementInput from '../PasswordRequirementInput/PasswordRequirementInput'
import classes from './NavbarSimpleColored.module.css'
import { IconListCheck } from '@tabler/icons-react'
const data = [
// { link: '/dashboard', label: 'Dashboard', icon: IconHome },
@ -94,6 +95,12 @@ const data = [
icon: IconZoomExclamation,
group: 'admin',
},
{
link: '/allocation',
label: 'Personnel allocation',
icon: IconBinaryTree2,
group: 'admin',
},
// { link: '/jira', label: 'Jira', icon: IconSubtask },
// { link: '/custom-theme', label: 'Custom Theme', icon: IconBrush },
// { link: '/general-setting', label: 'General Setting', icon: IconSettings },
@ -400,7 +407,7 @@ const Navbar = ({
</span>
</a>
<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 ? (
<IconLayoutSidebarLeftExpand
className={classes.linkIcon}

View File

@ -48,7 +48,7 @@
font-size: var(--mantine-font-size-sm);
color: rgb(161, 161, 161);
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);
font-weight: 500;
cursor: pointer;

File diff suppressed because it is too large Load Diff

View File

@ -2,6 +2,7 @@
import ResetPassword from '@/components/Authentication/ResetPassword'
import BasePage from '@/components/BasePage/BasePage'
import ProtectedRoute from '@/components/ProtectedRoute/ProtectedRoute'
import Allocation from '@/pages/Allocation/Allocation'
import PageLogin from '@/pages/Auth/Login/Login'
import LeaveManagement from '@/pages/LeaveManagement/LeaveManagement'
import PageNotFound from '@/pages/NotFound/NotFound'
@ -174,6 +175,20 @@ const mainRoutes = [
</ProtectedRoute>
),
},
{
path: '/allocation',
element: (
<ProtectedRoute mode="route" permission="admin">
<BasePage
main={
<>
<Allocation />
</>
}
></BasePage>
</ProtectedRoute>
),
},
// {
// path: '/packages',
// element: (