update doing
This commit is contained in:
parent
cfe9ee5da9
commit
8c06526757
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -149,6 +149,7 @@ class TimekeepingController extends Controller
|
|||
|
||||
return response()->json(['status' => true, 'message' => 'Add successfully']);
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function updateCacheMonth(Request $request)
|
||||
|
|
|
|||
|
|
@ -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([
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 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'
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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: (
|
||||
|
|
|
|||
Loading…
Reference in New Issue