feat: Add wiki integration to task management

- Implemented a multi-select dropdown for associating tasks with wiki entries in the task edit form.
- Enhanced task popup to display related wiki entries with visibility controls based on user permissions.
- Updated the wiki main view to support bulk actions for categories, including deletion and search functionality.
- Created a new database migration for establishing many-to-many relationships between tasks and wiki entries.
- Improved styling for wiki components to enhance user experience.
- Added a new AGENTS.md file to outline communication and change management protocols.
This commit is contained in:
2026-03-03 11:52:04 +01:00
parent 447b75bf3e
commit 7c2a42a66f
13 changed files with 747 additions and 98 deletions

View File

@@ -35,6 +35,23 @@ if ( is_array( $this -> clients ) )
foreach ( $this -> clients as $client )
$clients[ $client[ 'id' ] ] = $client[ 'firm' ];
$wiki_categories = ( isset( $this -> wiki_categories ) and is_array( $this -> wiki_categories ) ) ? $this -> wiki_categories : [];
$current_user_id = isset( $this -> user['id'] ) ? (int)$this -> user['id'] : 0;
if ( !count( $wiki_categories ) and $current_user_id > 0 )
$wiki_categories = \factory\Wiki::get_categories_for_user( $current_user_id );
if ( !count( $wiki_categories ) )
$wiki_categories = \factory\Wiki::get_all_categories();
$task_wiki_ids = isset( $this -> task['wiki_ids'] ) && is_array( $this -> task['wiki_ids'] ) ? array_map( 'intval', $this -> task['wiki_ids'] ) : [];
$wiki_values = [];
if ( is_array( $wiki_categories ) )
foreach ( $wiki_categories as $wiki_category )
{
$wiki_id = isset( $wiki_category['id'] ) ? (int)$wiki_category['id'] : 0;
if ( !$wiki_id )
continue;
$wiki_values[ $wiki_id ] = isset( $wiki_category['name'] ) ? (string)$wiki_category['name'] : (string)$wiki_id;
}
$parent_tasks = [ 0 => '--- wybierz zadanie nadrzędne ---' ];
if ( is_array( $this -> parent_tasks ) )
foreach ( $this -> parent_tasks as $parent_task )
@@ -130,6 +147,20 @@ ob_start();
'values' => $parent_tasks
] );
?>
<div class="form_group">
<label class="label">Powiazane Wiki:</label>
<div class="input">
<? if ( is_array( $wiki_categories ) and count( $wiki_categories ) ):?>
<select name="wiki_ids[]" id="wiki_ids" class="form-control" multiple>
<? foreach ( $wiki_values as $wiki_id => $wiki_name ):?>
<option value="<?= (int)$wiki_id;?>" <? if ( in_array( (int)$wiki_id, $task_wiki_ids ) ):?>selected="selected"<? endif;?>><?= htmlspecialchars( $wiki_name );?></option>
<? endforeach;?>
</select>
<? else:?>
<div class="task-wiki-empty">Brak dostepnych wpisow Wiki.</div>
<? endif;?>
</div>
</div>
<?= \Html::select( [
'label' => 'Status',
'name' => 'status',
@@ -434,6 +465,29 @@ ob_start();
font-style: italic;
}
#wiki_ids + .select2-container {
width: 100% !important;
}
#wiki_ids + .select2-container .select2-selection--multiple {
min-height: 38px;
border: 1px solid #cfd8e3;
border-radius: 4px;
padding: 2px 6px;
}
#wiki_ids + .select2-container .select2-selection__choice {
margin-top: 4px;
max-width: 100%;
overflow-wrap: anywhere;
word-break: break-word;
}
.task-wiki-empty {
color: #6b7280;
font-style: italic;
}
.task-edit-message {
margin: 12px 0 16px 0;
padding: 12px 16px;
@@ -957,12 +1011,12 @@ echo $grid -> draw();
height: '100'
});
$( '#project_id, #client_id, #status, #parent_id, #priority' ).select2({
$( '#project_id, #client_id, #status, #parent_id, #priority, #wiki_ids' ).select2({
theme: 'bootstrap-5',
minimumResultsForSearch: 0
});
$( '#project_id, #client_id, #status, #parent_id, #priority' ).on( 'select2:open', function() {
$( '#project_id, #client_id, #status, #parent_id, #priority, #wiki_ids' ).on( 'select2:open', function() {
setTimeout( function() {
var search_field = document.querySelector( '.select2-container--open .select2-search__field' );
if ( search_field )

View File

@@ -26,6 +26,10 @@
$checklist_count = is_array( $this -> task['actions'] ) ? count( $this -> task['actions'] ) : 0;
$comments_count = is_array( $this -> task['comments'] ) ? count( $this -> task['comments'] ) : 0;
$attachments_count = is_array( $this -> task_attachments ) ? count( $this -> task_attachments ) : 0;
$popup_wiki_data = \factory\Tasks::task_wiki_entries_for_user( (int)$this -> task['id'], (int)$this -> user['id'] );
$task_wiki_entries = isset( $popup_wiki_data['entries'] ) && is_array( $popup_wiki_data['entries'] ) ? $popup_wiki_data['entries'] : [];
$wiki_visible_count = isset( $popup_wiki_data['visible_count'] ) ? (int)$popup_wiki_data['visible_count'] : 0;
$wiki_hidden_count = isset( $popup_wiki_data['hidden_count'] ) ? (int)$popup_wiki_data['hidden_count'] : 0;
?>
<?
$task_description_html = htmlspecialchars_decode( (string)$this -> task['text'] );
@@ -74,6 +78,7 @@
<a href="#" class="js-task-tab-btn" data-tab="checklist" role="tab" aria-selected="false">Lista kontrolna (<?= (int)$checklist_count;?>)</a>
<a href="#" class="js-task-tab-btn" data-tab="comments" role="tab" aria-selected="false">Komentarze (<?= (int)$comments_count;?>)</a>
<a href="#" class="js-task-tab-btn" data-tab="attachments" role="tab" aria-selected="false">Za&#322;&#261;czniki (<?= (int)$attachments_count;?>)</a>
<a href="#" class="js-task-tab-btn" data-tab="wiki" role="tab" aria-selected="false">Wiki (<?= (int)$wiki_visible_count;?>)</a>
<? if ( $this -> user['id'] == 1 ):?>
<a href="#" class="js-task-tab-btn" data-tab="users" role="tab" aria-selected="false">Uczestnicy</a>
<? endif;?>
@@ -177,6 +182,35 @@
</ul>
</div>
</div>
<div class="task-tab-panel" data-tab="wiki">
<div class="box">
<h3>Powiazane wpisy Wiki</h3>
<? if ( $wiki_hidden_count > 0 ):?>
<div class="alert alert-warning" style="margin-bottom: 12px;">
Nie masz dostepu do <?= (int)$wiki_hidden_count;?> powiazanych wpisow Wiki.
</div>
<? endif;?>
<? if ( is_array( $task_wiki_entries ) and count( $task_wiki_entries ) ):?>
<div class="task-wiki-list">
<? foreach ( $task_wiki_entries as $wiki_entry ):?>
<div class="task-wiki-entry">
<h4><?= htmlspecialchars( (string)$wiki_entry['name'] );?></h4>
<div class="task-wiki-content">
<?= (string)$wiki_entry['text'];?>
<? if ( $this -> user['id'] == 1 or $this -> user['id'] == 3 ):?>
<? if ( isset( $wiki_entry['text_admin'] ) and (string)$wiki_entry['text_admin'] !== '' ):?>
<div class="task-wiki-admin"><?= (string)$wiki_entry['text_admin'];?></div>
<? endif;?>
<? endif;?>
</div>
</div>
<? endforeach;?>
</div>
<? else:?>
<div class="task-wiki-empty">Brak widocznych wpisow Wiki dla tego zadania.</div>
<? endif;?>
</div>
</div>
<? if ( $this -> user['id'] == 1 ):?>
<div class="task-tab-panel" data-tab="users">
<div class="task-users-edit">
@@ -407,6 +441,36 @@
font-weight: 600;
}
.task_popup .task_details .task-wiki-list {
display: grid;
gap: 12px;
}
.task_popup .task_details .task-wiki-entry {
border: 1px solid #e5e7eb;
border-radius: 8px;
padding: 12px;
background: #fff;
}
.task_popup .task_details .task-wiki-entry h4 {
margin: 0 0 8px 0;
font-size: 14px;
font-weight: 700;
color: #1f3d72;
}
.task_popup .task_details .task-wiki-content {
font-size: 13px;
line-height: 1.5;
}
.task_popup .task_details .task-wiki-admin {
margin-top: 10px;
padding-top: 10px;
border-top: 1px dashed #d1d5db;
}
.task_popup .task_details .task-wiki-empty {
color: #6b7280;
font-style: italic;
}
/* Lightbox - powiększanie zdjęć w opisie */
.task_popup .task_details .description img {
cursor: zoom-in;
@@ -676,8 +740,16 @@
if ( !tab_panels.length )
return;
var allowed_tabs = [ 'description', 'checklist', 'comments', 'attachments', 'users' ];
var selected_tab = allowed_tabs.indexOf( tab_name ) >= 0 ? tab_name : 'description';
var available_tabs = [];
tab_buttons.each( function() {
var tab = $( this ).attr( 'data-tab' );
if ( tab )
available_tabs.push( tab );
});
var selected_tab = available_tabs.indexOf( tab_name ) >= 0 ? tab_name : 'description';
if ( available_tabs.indexOf( selected_tab ) < 0 && available_tabs.length )
selected_tab = available_tabs[0];
tab_panels.each( function() {
var panel = $( this );