diff --git a/app/Domain/Tickets/Js/ticketsController.js b/app/Domain/Tickets/Js/ticketsController.js index f4389aeb2..da56af97d 100644 --- a/app/Domain/Tickets/Js/ticketsController.js +++ b/app/Domain/Tickets/Js/ticketsController.js @@ -1177,16 +1177,19 @@ export const initTicketsTable = function (groupBy) { } }, - "dom": '<"top">rt<"bottom"><"clear">', - "searching": false, - "stateSave": true, + "dom": '<"top"f>rt<"bottom"lip><"clear">', + "pagingType": "full_numbers", + "pageLength": 10, + "lengthMenu": [[10, 25, 50, -1], [10, 25, 50, "All"]], + "searching": true, + "stateSave": false, "displayLength":100, "order": defaultOrder, "columnDefs": [ - { "visible": false, "targets": 10 }, - { "visible": false, "targets": 11 }, + { "visible": false, "targets": 10, "searchable": false }, + { "visible": false, "targets": 11, "searchable": false }, { "target": "no-sort", "orderable": false}, - ], + ], "footerCallback": function ( row, data, start, end, display ) { var api = this.api(), data; @@ -1200,7 +1203,6 @@ export const initTicketsTable = function (groupBy) { // computing column Total of the complete result - var plannedHours = api .column(10) .data() @@ -1263,6 +1265,29 @@ export const initTicketsTable = function (groupBy) { }); + function format(d) { + return "foo"; + // d[6]; + } + + // Add event listener for opening and closing child row + jQuery('.ticketTable tbody').on('click', 'td.dt-control', function (e) { + let tr = e.target.closest('tr'); + // let tr = jQuery(this).closest('tr'); + let row = allTickets.row(tr); + + console.log("Row data is", row.data()); + + if (row.child.isShown()) { + row.child.hide(); + tr.removeClass('shown'); + } else { + row.child(format(row.data())).show(); + tr.addClass('shown'); + } + }); + + var buttons = new jQuery.fn.dataTable.Buttons(allTickets.table(0), { buttons: [ { @@ -1310,6 +1335,31 @@ export const initTicketsTable = function (groupBy) { allTickets.draw(); }); + + // Testing add row + function addNewRow() { + allTickets.row + .add([ + "col 1", + "col 2", + "col 3", + "col 4", + "col 5", + "col 6", + "col 7", + "col 8", + "col 9", + "col 10", + "col 11", + "col 12", + ]) + .draw(false); + + } + + // document.querySelector('#addRow').addEventListener('click', addNewRow); + jQuery('#addRow').on('click', addNewRow); + }); }; diff --git a/app/Domain/Tickets/Templates/includes/ticketFilter.blade.php b/app/Domain/Tickets/Templates/includes/ticketFilter.blade.php index a68d14ae2..2b183f9ab 100644 --- a/app/Domain/Tickets/Templates/includes/ticketFilter.blade.php +++ b/app/Domain/Tickets/Templates/includes/ticketFilter.blade.php @@ -115,8 +115,6 @@ {{ __('buttons.search') }} - - diff --git a/app/Domain/Tickets/Templates/showAll.blade.php b/app/Domain/Tickets/Templates/showAll.blade.php index 5951e0fa4..e48635a7d 100644 --- a/app/Domain/Tickets/Templates/showAll.blade.php +++ b/app/Domain/Tickets/Templates/showAll.blade.php @@ -62,378 +62,398 @@ $allTickets = $allTicketGroups['all']['items']; } ?> - - - - - -
- - - - - dispatchTplEvent('allTicketsTable.before', ['tickets' => $allTicketGroups]); ?> - - - - - - - - - - - - - - - - - - dispatchTplEvent('allTicketsTable.beforeHead', ['tickets' => $allTickets]); ?> - - dispatchTplEvent('allTicketsTable.beforeHeadRow', ['tickets' => $allTickets]); ?> - - - - - - - - - - - - - - - - - dispatchTplEvent('allTicketsTable.afterHeadRow', ['tickets' => $allTickets]); ?> - - dispatchTplEvent('allTicketsTable.afterHead', ['tickets' => $allTickets]); ?> - - dispatchTplEvent('allTicketsTable.beforeFirstRow', ['tickets' => $allTickets]); ?> - $row) {?> - - dispatchTplEvent('allTicketsTable.afterRowStart', ['rowNum' => $rowNum, 'tickets' => $allTickets]); ?> - - - - - - - - - - - - - escape($row['milestoneHeadline']) : $tpl->__('label.no_milestone'); - - $milestoneColor = $tpl->escape($row['milestoneColor']); - $milestoneDropdownId = 'milestoneDropdownMenuLink' . $row['id']; - $noMilestoneLabel = $tpl->__('label.no_milestone'); - ?> - - - - - - 0 ? $priorities[$row['priority']] : $tpl->__('label.priority_unkown'); - - $dropdownId = 'priorityDropdownMenuLink' . $row['id']; - ?> - - - - " . $tpl->escape($row['editorFirstname']) . ''; - } else { - $userText = "" . $tpl->__('dropdown.not_assigned') . ''; - } - - $dropdownId = 'userDropdownMenuLink' . $row['id']; - ?> - - - - escape($row['sprintName']) : $tpl->__('links.no_list'); - - $dropdownId = 'sprintDropdownMenuLink' . $row['id']; - ?> - - - - - - - __('text.anytime'); - } else { - $date = new DateTime($row['dateToFinish']); - $date = $date->format($tpl->__('language.dateformat')); - } - ?> - - - - - - - - - dispatchTplEvent('allTicketsTable.beforeRowEnd', ['tickets' => $allTickets, 'rowNum' => $rowNum]); ?> - - - dispatchTplEvent('allTicketsTable.afterLastRow', ['tickets' => $allTickets]); ?> - - dispatchTplEvent('allTicketsTable.afterBody', ['tickets' => $allTickets]); ?> - - - - - - - - - - - -
__('label.id') ?>__('label.title') ?>__('label.todo_status') ?>__('label.milestone') ?>__('label.effort') ?>__('label.priority') ?>__('label.editor') ?>.__('label.sprint') ?>__('label.tags') ?>__('label.due_date') ?>__('label.planned_hours') ?>__('label.estimated_hours_remaining') ?>__('label.booked_hours') ?>
- #e($row['id']) ?> - - 0) { ?> - escape($row['parentHeadline']) ?> - //
- - e($row['headline']) ?> -
- - - {{ $name }} - - - - {{ __('dropdown.choose_status') }} - - - @foreach ($statusLabels as $key => $label) - - {{ $label['name'] }} + + + + @foreach ($allTicketGroups as $group) + @if ($group['label'] != 'all') + + {{ $group['more-info'] }} +
+ @endif + + @php + $allTickets = $group['items']; + $tpl->dispatchTplEvent('allTicketsTable.before', ['tickets' => $allTicketGroups]); + @endphp + + + {{ $tpl->__('label.id') }} + {{ $tpl->__('label.title') }} + {{ $tpl->__('label.todo_status') }} + {{ $tpl->__('label.milestone') }} + {{ $tpl->__('label.effort') }} + {{ $tpl->__('label.priority') }} + {{ $tpl->__('label.editor') }} + {{ $tpl->__('label.sprint') }} + {{ $tpl->__('label.tags') }} + {{ $tpl->__('label.due_date') }} + {{ $tpl->__('label.planned_hours') }} + {{ $tpl->__('label.estimated_hours_remaining') }} + {{ $tpl->__('label.booked_hours') }} + + + @endforeach + + + + @foreach ($allTicketGroups as $group) + @php $allTickets = $group['items']; @endphp + + @foreach ($allTickets as $rowNum => $row) + + @php + // Status handling + if (isset($statusLabels[$row['status']])) { + $class = $statusLabels[$row['status']]['class']; + $name = $statusLabels[$row['status']]['name']; + $sortKey = $statusLabels[$row['status']]['sortKey']; + $selectedKey = $row['status']; + } else { + $class = 'label-important'; + $name = 'new'; + $sortKey = 0; + $selectedKey = null; + } + + // Milestone handling + $milestoneHeadline = $row['milestoneid'] != '' && $row['milestoneid'] != 0 + ? $tpl->escape($row['milestoneHeadline']) + : $tpl->__('label.no_milestone'); + $milestoneColor = $tpl->escape($row['milestoneColor']); + $milestoneDropdownId = 'milestoneDropdownMenuLink' . $row['id']; + $noMilestoneLabel = $tpl->__('label.no_milestone'); + + // Effort handling + $effortText = $row['storypoints'] != '' && $row['storypoints'] > 0 + ? $efforts['' . $row['storypoints']] ?? $row['storypoints'] + : $tpl->__('label.story_points_unkown'); + $dropdownId = 'effortDropdownMenuLink' . $row['id']; + + // Priority handling + $priorityText = $row['priority'] != '' && $row['priority'] > 0 + ? $priorities[$row['priority']] + : $tpl->__('label.priority_unkown'); + $dropdownId = 'priorityDropdownMenuLink' . $row['id']; + + // User Text and Image Handling + if ($row['editorFirstname'] != '') { + $userText = "" . $tpl->escape($row['editorFirstname']) . ''; + } else { + $userText = "" . $tpl->__('dropdown.not_assigned') . ''; + } + $dropdownId = 'userDropdownMenuLink' . $row['id']; + + // Sprint handling + $sprintHeadline = $row['sprint'] != '' && $row['sprint'] != 0 && $row['sprint'] != -1 + ? $tpl->escape($row['sprintName']) + : $tpl->__('links.no_list'); + $dropdownId = 'sprintDropdownMenuLink' . $row['id']; + + // Due date handling + if ($row['dateToFinish'] == '0000-00-00 00:00:00' || $row['dateToFinish'] == '1969-12-31 00:00:00') { + $date = $tpl->__('text.anytime'); + } else { + $date = new DateTime($row['dateToFinish']); + $date = $date->format($tpl->__('language.dateformat')); + } + @endphp + + + #{{ $tpl->e($row['id']) }} + + + {{--repeat_output_issue data-order="{{ $tpl->e($row['headline']) }}" --}} + + @if ($row['dependingTicketId'] > 0) + + + {{ $tpl->escape($row['parentHeadline']) }} + + +
+ @endif + + {{ $tpl->e($row['headline']) }} + +
+ + + + + {{ $name }} + + + + {{ __('dropdown.choose_status') }} - @endforeach - -
- - - {{ $milestoneHeadline }} - - - - {{ __('dropdown.choose_milestone') }} - - - - {{ $noMilestoneLabel }} - - - @foreach ($tpl->get('milestones') as $milestone) - - {{ $tpl->escape($milestone->headline) }} + + @foreach ($statusLabels as $key => $label) + + {{ $label['name'] }} + + @endforeach + + + + + + + {{ $milestoneHeadline }} + + + + {{ __('dropdown.choose_milestone') }} - @endforeach - - - 0 ? $efforts['' . $row['storypoints']] ?? $row['storypoints'] : $tpl->__('label.story_points_unkown'); - - $dropdownId = 'effortDropdownMenuLink' . $row['id']; - ?> - - - - - - {{ $effortText }} - - - - {{ __('dropdown.how_big_todo') }} - - - @foreach ($efforts as $effortKey => $effortValue) - - {{ $effortValue }} + + + {{ $noMilestoneLabel }} - @endforeach - - - - - - {{ $priorityText }} - - - - {{ __('dropdown.select_priority') }} - - - @foreach ($priorities as $priorityKey => $priorityValue) - - {{ $priorityValue }} + + @foreach ($tpl->get('milestones') as $milestone) + + {{ $tpl->escape($milestone->headline) }} + + @endforeach + + + + + + + {{ $effortText }} + + + + {{ __('dropdown.how_big_todo') }} - @endforeach - - - - - {!! $userText !!} - - - - {{ __('dropdown.choose_user') }} - - - @foreach ($tpl->get('users') as $user) - - - {{ sprintf($tpl->__('text.full_name'), $tpl->escape($user['firstname']), $tpl->escape($user['lastname'])) }} + + @foreach ($efforts as $effortKey => $effortValue) + + {{ $effortValue }} + + @endforeach + + + + + + + {{ $priorityText }} + + + + {{ __('dropdown.select_priority') }} - @endforeach - - - - - {{ $sprintHeadline }} - - - - {{ __('dropdown.choose_list') }} - - - - {{ __('label.not_assigned_to_list') }} - - - @foreach ($tpl->get('sprints') as $sprint) - - {{ $tpl->escape($sprint->name) }} + + @foreach ($priorities as $priorityKey => $priorityValue) + + {{ $priorityValue }} + + @endforeach + + + + + + + {!! $userText !!} + + + + {{ __('dropdown.choose_user') }} - @endforeach - - - - -
- get('users') as $user) + + + {{ sprintf($tpl->__('text.full_name'), $tpl->escape($user['firstname']), $tpl->escape($user['lastname'])) }} + + @endforeach + + + + + + + {{ $sprintHeadline }} + - foreach ($tagsArray as $tag) { - echo "" . $tpl->escape($tag) . ''; - } + + {{ __('dropdown.choose_list') }} + - ?> -
- -
- - - - - - - - - - @include('tickets::includes.ticketsubmenu', [ - 'ticket' => $row, - 'onTheClock' => $onTheClock, - ]) -
- dispatchTplEvent('allTicketsTable.afterClose', ['tickets' => $allTickets]); ?> - - -
- - - - - - + + {{ __('label.not_assigned_to_list') }} + + + @foreach ($tpl->get('sprints') as $sprint) + + {{ $tpl->escape($sprint->name) }} + + @endforeach + + + + + @if ($row['tags'] != '') + @php $tagsArray = explode(',', $row['tags']); @endphp +
+ @foreach ($tagsArray as $tag) + {{ $tpl->escape($tag) }} + @endforeach +
+ @endif +
+ + + + + + + + + + + + + + + {{ $row['bookedHours'] === null || $row['bookedHours'] == '' ? '0' : $row['bookedHours'] }} + + + + @include('tickets::includes.ticketsubmenu', [ + 'ticket' => $row, + 'onTheClock' => $onTheClock, + ]) + + + + @endforeach + + @if ($group['label'] != 'all') + + @endif + @endforeach + + + + + + + + + + + + + + + {{-- button to add row --}} + {{--

--}} + @@ -462,5 +482,19 @@ class="quickDueDates secretInput" data-id="" name="date dispatchTplEvent('scripts.beforeClose'); ?> }); + + function toggleDetails(row) { + const id = row.getAttribute('data-id'); + const detailsRow = document.querySelector(`tr[data-parent="${id}"]`); + const expandIcon = row.querySelector('.expand-icon'); + + if (detailsRow.classList.contains('hidden')) { + detailsRow.classList.remove('hidden'); + expandIcon.textContent = '-'; + } else { + detailsRow.classList.add('hidden'); + expandIcon.textContent = '+'; + } + } @endsection diff --git a/app/Views/Templates/components/elements/table/cell.blade.php b/app/Views/Templates/components/elements/table/cell.blade.php new file mode 100644 index 000000000..9d5e044b0 --- /dev/null +++ b/app/Views/Templates/components/elements/table/cell.blade.php @@ -0,0 +1,3 @@ +merge(['class' => 'px-6 py-4 text-sm text-gray-500']) }}> + {{ $slot }} + \ No newline at end of file diff --git a/app/Views/Templates/components/elements/table/footer.blade.php b/app/Views/Templates/components/elements/table/footer.blade.php new file mode 100644 index 000000000..46a18cd62 --- /dev/null +++ b/app/Views/Templates/components/elements/table/footer.blade.php @@ -0,0 +1,3 @@ +merge(['class' => 'text-left text-xs font-medium text-gray-500 tracking-wider']) }}> + {{ $slot }} + \ No newline at end of file diff --git a/app/Views/Templates/components/elements/table/header-cell.blade.php b/app/Views/Templates/components/elements/table/header-cell.blade.php new file mode 100644 index 000000000..319dcd95e --- /dev/null +++ b/app/Views/Templates/components/elements/table/header-cell.blade.php @@ -0,0 +1,3 @@ +merge(['class' => 'px-6 py-3']) }}> + {{ $slot }} + \ No newline at end of file diff --git a/app/Views/Templates/components/elements/table/header.blade.php b/app/Views/Templates/components/elements/table/header.blade.php new file mode 100644 index 000000000..46a18cd62 --- /dev/null +++ b/app/Views/Templates/components/elements/table/header.blade.php @@ -0,0 +1,3 @@ +merge(['class' => 'text-left text-xs font-medium text-gray-500 tracking-wider']) }}> + {{ $slot }} + \ No newline at end of file diff --git a/app/Views/Templates/components/elements/table/index.blade.php b/app/Views/Templates/components/elements/table/index.blade.php new file mode 100644 index 000000000..881007501 --- /dev/null +++ b/app/Views/Templates/components/elements/table/index.blade.php @@ -0,0 +1,24 @@ +@props([ + 'header', + 'body', + 'footer', + 'extraClass' => '' +]) + +merge(['class' => 'table table-bordered min-w-full bg-white border-separate border-spacing-0 '.$extraClass ]) }}> + @if(isset($header)) + + {{ $header }} + + @endif + + + {{ $body }} + + + @if(isset($footer)) + + {{ $footer }} + + @endif +
diff --git a/app/Views/Templates/components/elements/table/row.blade.php b/app/Views/Templates/components/elements/table/row.blade.php new file mode 100644 index 000000000..87e57c419 --- /dev/null +++ b/app/Views/Templates/components/elements/table/row.blade.php @@ -0,0 +1,3 @@ +merge(['class' => 'hover:bg-gray-50']) }}> + {{ $slot }} + \ No newline at end of file