Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature: Improve syncing experience #43

Open
wants to merge 12 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions Controllers/TimeTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use Leantime\Core\Controller\Controller;
use Leantime\Core\Controller\Frontcontroller;
use Leantime\Domain\Auth\Services\Auth;
use Leantime\Domain\Users\Services\Users;
use Leantime\Plugins\TimeTable\Helpers\TimeTableActionHandler;
use Symfony\Component\HttpFoundation\Response;
use Leantime\Plugins\TimeTable\Services\TimeTable as TimeTableService;
Expand All @@ -18,12 +17,14 @@
use Leantime\Domain\Setting\Repositories\Setting as SettingRepository;
use Leantime\Domain\Timesheets\Repositories\Timesheets as TimesheetRepository;
use Leantime\Core\UI\Template;
use \Illuminate\Http\JsonResponse as JsonResponse;

/**
* TimeTable controller.
*/
class TimeTable extends Controller
{

private TimeTableService $timeTableService;
protected LanguageCore $language;
private SettingRepository $settings;
Expand All @@ -49,6 +50,18 @@ public function init(TimeTableService $timeTableService, LanguageCore $language,
$this->timesheetRepository = $timesheetRepository;
}

public function getAllTickets(): JsonResponse
{
$allTickets = $this->timeTableService->getAllTickets() ?? [];
return response()->json(['result' => $allTickets]);
}

public function getAllProjects(): JsonResponse
{
$allProjects = $this->timeTableService->getAllProjects() ?? [];
return response()->json(['result' => $allProjects]);
}

/**
* @return Response
* @throws \Exception
Expand Down Expand Up @@ -91,7 +104,6 @@ public function get(): Response
$ticketCacheExpiration = $this->settings->getSetting('itk-leantime-timetable.ticketCacheExpiration') ?? 1200;
$fromDate = CarbonImmutable::now()->startOfWeek()->startOfDay();
$toDate = CarbonImmutable::now()->endOfWeek()->startOfDay();
$allStateLabels = $this->timeTableService->getAllStateLabels();
$allUsers = $this->timeTableService->getAllUsers();
$canCrossManage = Auth::userIsAtLeast(Roles::$admin, true);
$userId = $canCrossManage && isset($_GET['manageAsUserId']) ? $_GET['manageAsUserId'] : session('userdata.id');
Expand Down Expand Up @@ -201,7 +213,6 @@ public function get(): Response
$this->template->assign('ticketCacheExpiration', $ticketCacheExpiration);
$this->template->assign('fromDate', $fromDate);
$this->template->assign('toDate', $toDate);
$this->template->assign('allStateLabels', json_encode($allStateLabels));
$this->template->assign('requireTimeRegistrationComment', $this->settings->getSetting('itk-leantime-timetable.requireTimeRegistrationComment') ?? 0);
$this->template->assign('allUsers', $allUsers);
$this->template->assign('userId', $userId);
Expand Down
83 changes: 81 additions & 2 deletions Repositories/TimeTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@

use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use Illuminate\Contracts\Container\BindingResolutionException;
use Leantime\Core\Db\Db as DbCore;
use Leantime\Domain\Tickets\Repositories\Tickets as TicketRepository;
use PDO;

/**
Expand All @@ -17,15 +19,18 @@ class TimeTable
*/
private null|DbCore $db = null;

private TicketRepository $ticketRepo;

/**
* __construct - get db connection
*
* @access public
* @return void
*/
public function __construct(DbCore $db)
public function __construct(DbCore $db, TicketRepository $ticketRepo)
{
$this->db = $db;
$this->ticketRepo = $ticketRepo;
}

/**
Expand Down Expand Up @@ -249,8 +254,9 @@ public function addTimelogOnTicket(array $values)
* @param array<int|string, mixed> $statusListSeed An array of default status definitions to seed the state labels.
* @return array<string, array<int|string, mixed>> An associative array where keys are project IDs and values are arrays of state labels.
*/
public function getAllStateLabels(array $statusListSeed): array
private function getAllStateLabels(array $statusListSeed): array
{
$statusListSeed = $this->ticketRepo->statusListSeed;
$sql = 'SELECT `key`, `value` FROM zp_settings WHERE `key` LIKE :keyPattern';
$stmn = $this->db->database->prepare($sql);
$stmn->bindValue(':keyPattern', 'projectsettings.%.ticketlabels', PDO::PARAM_STR);
Expand Down Expand Up @@ -346,4 +352,77 @@ public function getAllUsers(): array
];
}, $users);
}

/**
* getAllTickets - Retrieves all tickets for the authenticated user, filters them based on their status,
* and includes additional information such as project details and the last work date.
*
* @access public
* @return array An array of filtered tickets with their associated details.
*/
public function getAllTickets(): array
{
$userId = session('userdata.id');
$statusListSeed = $this->ticketRepo->statusListSeed;
$allStateLabels = $this->getAllStateLabels($statusListSeed);

$sql = 'SELECT
t.id,
t.headline,
LOWER(t.type) as type,
t.tags,
t.projectId,
p.name as projectName, -- Fetch project name via JOIN
t.editorId,
t.hourRemaining,
t.date,
MAX(ts.modified) as lastModified
FROM zp_tickets t
LEFT JOIN zp_projects p ON t.projectId = p.id
LEFT JOIN zp_timesheets ts ON t.id = ts.ticketId AND ts.userId = :userId
WHERE t.type NOT IN (:story, :milestone)
GROUP BY t.id
ORDER BY (t.editorId = :userId) DESC, lastModified DESC';
$stmn = $this->db->database->prepare($sql);
$stmn->bindValue(':story', 'story', PDO::PARAM_STR);
$stmn->bindValue(':milestone', 'milestone', PDO::PARAM_STR);
$stmn->bindValue(':userId', $userId, PDO::PARAM_INT);
$stmn->execute();
$tickets = $stmn->fetchAll(PDO::FETCH_ASSOC);
$stmn->closeCursor();

// Pre-compute status label mappings
$stateLabelMappings = array_map(function ($labels) {
return array_column($labels, 'statusType');
}, $allStateLabels);

// Filter tickets using pre-computed mappings
$filteredTickets = [];
foreach ($tickets as $ticket) {
$projectId = $ticket['projectId'] ?? null;
$status = $ticket['status'] ?? null;
if (!isset($stateLabelMappings[$projectId][$status]) || $stateLabelMappings[$projectId][$status] !== 'DONE') {
$filteredTickets[] = $ticket;
}
}

return $filteredTickets;
}

public function getAllProjects(): array
{
$sql = 'SELECT id, name FROM zp_projects';
$stmn = $this->db->database->prepare($sql);
$stmn->execute();
$projects = $stmn->fetchAll(PDO::FETCH_ASSOC);
$stmn->closeCursor();

return array_map(function ($project) {
return [
'id' => $project['id'],
'name' => $project['name'],
'type' => 'project',
];
}, $projects);
}
}
63 changes: 47 additions & 16 deletions Services/TimeTable.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,14 @@
use Carbon\CarbonInterface;
use Leantime\Plugins\TimeTable\Repositories\TimeTable as TimeTableRepository;
use Leantime\Domain\Tickets\Repositories\Tickets as TicketRepository;
use Carbon\CarbonImmutable;


/**
* Time table services file.
*/
class TimeTable
{
private TimeTableRepository $timeTableRepo;
private TicketRepository $ticketRepo;

/**
* @var array<string, string>
Expand All @@ -28,13 +27,11 @@ class TimeTable
* constructor
*
* @param TimeTableRepository $timeTableRepo
* @param TicketRepository $ticketRepo
* @return void
*/
public function __construct(TimeTableRepository $timeTableRepo, TicketRepository $ticketRepo)
public function __construct(TimeTableRepository $timeTableRepo)
{
$this->timeTableRepo = $timeTableRepo;
$this->ticketRepo = $ticketRepo;
}

/**
Expand Down Expand Up @@ -113,17 +110,6 @@ public function addTimelogOnTicket(array $values)
$this->timeTableRepo->addTimelogOnTicket($values);
}

/**
* Retrieves all state labels for all projects.
*
* @return array<string, array<int|string, mixed>> The state labels grouped by project IDs.
*/
public function getAllStateLabels(): array
{
$statusListSeed = $this->ticketRepo->statusListSeed;
return $this->timeTableRepo->getAllStateLabels($statusListSeed);
}

/**
* Retrieves all users from the repository.
*
Expand All @@ -133,4 +119,49 @@ public function getAllUsers(): array
{
return $this->timeTableRepo->getAllUsers();
}

public function getAllTickets(): array
{
$tickets = $this->timeTableRepo->getAllTickets();

$formattedTickets = [
'children' => array_map(function ($ticket) {
return [
'id' => $ticket['id'],
'text' => $ticket['headline'],
'type' => $ticket['type'],
'tags' => $ticket['tags'],
'projectName' => $ticket['projectName'] ?? 'Removed project',
'projectId' => $ticket['projectId'],
'editorId' => $ticket['editorId'],
'hoursLeft' => $ticket['hourRemaining'],
'createdDate' => $ticket['date'],
];
}, $tickets),
];

return $formattedTickets;
}

public function getAllProjects(): array
{
$projects = $this->timeTableRepo->getAllProjects();
$projectGroup = [
'id' => 'project',
'text' => 'Projects',
'children' => [],
'index' => 1,
];

foreach ($projects as $project) {
$projectGroup['children'][] = [
'id' => $project['id'],
'text' => $project['name'],
'type' => 'project',
'client' => $project['clientName'] ?? null,
];
}

return $projectGroup;
}
}
5 changes: 2 additions & 3 deletions Templates/timetable.blade.php
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,6 @@
<div class="maincontent">
<div class="maincontentinner">
<div class="timetable">
<input type="hidden" id="all-state-labels" value="{{ $allStateLabels }}" />
<form method="POST">
<input type="hidden" name="action" value="adjustPeriod">
<div class="flex-container gap-3 tools">
Expand Down Expand Up @@ -105,7 +104,7 @@ class="timetable-to-today btn btn-default">{{ __('timeTable.button_show_this_wee
$description = $timesheetDate[0]['description'] ?? null;
$requireTimeRegistrationComment = $requireTimeRegistrationComment ?? 0;
$isMissingDescription = isset($hours) & (trim($description) === '') && $requireTimeRegistrationComment !== 0;

// accumulate hours
if ($hours) {
if (isset($totalHours[$weekDateAccessor])) {
Expand All @@ -115,7 +114,7 @@ class="timetable-to-today btn btn-default">{{ __('timeTable.button_show_this_wee
}
$rowTotal += $hours; // add to row total
}

$weekendClass = isset($weekDate) && $weekDate->isWeekend() ? 'weekend' : '';
$todayClass = isset($weekDate) && $weekDate->isToday() ? 'today' : '';
$newWeekClass = isset($weekDate) && $weekDate->isMonday() ? 'new-week' : ''; // Add new-week class for Mondays
Expand Down
29 changes: 15 additions & 14 deletions assets/timeTable.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ import TimeTableApiHandler from "./timeTableApiHandler";
jQuery(document).ready(function ($) {
const pluginSettings = {
userId: $("select[name='manageAsUserId'] > option:selected").val(),
allStateLabels: $("#all-state-labels").val(),
};

class TimeTable {
Expand Down Expand Up @@ -84,18 +83,7 @@ jQuery(document).ready(function ($) {
".timetable-ticket-input",
);

// Register event handlers
this.registerEventHandlers();

this.toggleVisualLoaders();
this.isFetching = true;
TimeTableApiHandler.fetchTicketData(pluginSettings.allStateLabels).then(
() => {
this.isFetching = false;
this.populateLastUpdated();
this.initTicketSearch();
},
);

flatpickr("#dateRange", {
mode: "range",
Expand Down Expand Up @@ -154,6 +142,19 @@ jQuery(document).ready(function ($) {
$wrapper.addClass("open");
}
});

// Register event handlers
this.registerEventHandlers();

this.toggleVisualLoaders();
this.isFetching = true;
TimeTableApiHandler.fetchTicketData().then(
() => {
this.isFetching = false;
this.populateLastUpdated();
this.initTicketSearch();
},
);
}

/**
Expand Down Expand Up @@ -698,7 +699,7 @@ jQuery(document).ready(function ($) {
const pageSize = 50;
const userId = pluginSettings.userId;

// Sort tickets by editorId and created date.
/*// Sort tickets by editorId and created date.
tickets.sort((a, b) => {
if (a.editorId === userId && b.editorId !== userId) {
return -1;
Expand All @@ -709,7 +710,7 @@ jQuery(document).ready(function ($) {
const dateB = new Date(b.createdDate);
return dateB - dateA;
}
});
});*/

// Exclude tickets that are already present in the table.

Expand Down
Loading
Loading