z onclick dodać onkeydown/onkeypress equivalent
+
+ **ItemTagNotWithinContainerTagCheck (1 bug):**
+ - templates/tasks/task_single.php — sprawdzić i naprawić wg SonarQube message
+
+ **Inne MINOR HTML bugs (3):**
+ - Sprawdzić wg SonarQube messages i naprawić
+
+ WAŻNE: Dodawać scope="col" masowo do
jest bezpieczne — nie zmienia renderowania.
+ Przy duplikatach ID sprawdzić czy JavaScript nie referuje stare ID.
+
+
+ Odczytać naprawione szablony i sprawdzić, że:
+ - Brak zduplikowanych ID w HTML
+ - Wszystkie
mają scope="col" lub id
+ - Elementy onclick mają keyboard equivalent
+
+ AC-2 satisfied: Wszystkie HTML template bugs naprawione
+
+
+
+
+ Reskan SonarQube:
+ 1. Uruchomię sonar-scanner automatycznie
+ 2. Poczekam na wyniki
+ 3. Sprawdzę metryki przez MCP
+
+ Reskan zostanie wykonany automatycznie. Wyniki w SUMMARY.md.
+
+
+
+
+
+
+## DO NOT CHANGE
+- config.php (konfiguracja)
+- index.php (punkt wejścia)
+- autoload/Controllers/** (nowe controllery — nie modyfikować)
+- autoload/Domain/** (nowy kod Domain — nie modyfikować w tym planie)
+
+## SCOPE LIMITS
+- Naprawiamy TYLKO issues typu BUG z SonarQube
+- NIE naprawiamy Code Smells (osobna faza)
+- NIE zmieniamy logiki biznesowej
+- NIE refaktoryzujemy kodu poza minimum wymagane do naprawy buga
+- NIE dodajemy nowych zależności
+
+
+
+
+Before declaring plan complete:
+- [ ] Wszystkie 8 PHP logic bugs naprawione
+- [ ] Wszystkie 20 PHP convention bugs naprawione
+- [ ] Wszystkie 3 CRITICAL HTML duplicate ID bugs naprawione
+- [ ] Wszystkie 22 MAJOR HTML th scope bugs naprawione
+- [ ] Wszystkie 5 MINOR HTML/accessibility bugs naprawione
+- [ ] Reskan SonarQube potwierdza redukcję bugów
+- [ ] Żadna logika biznesowa nie została zmieniona
+- [ ] All acceptance criteria met
+
+
+
+- Bugs w SonarQube: 0 (cel) lub < 5 (akceptowalne)
+- Reliability Rating: B lub lepsza (poprawa z D)
+- Żadne nowe bugi nie zostały wprowadzone
+- Aplikacja działa bez regresji
+
+
+
diff --git a/.vscode/ftp-kr.json b/.vscode/ftp-kr.json
index 5de7c10..8be197d 100644
--- a/.vscode/ftp-kr.json
+++ b/.vscode/ftp-kr.json
@@ -15,6 +15,7 @@
"/.vscode",
"/.serena",
"/.claude",
+ "/.paul",
"CLAUDE.md"
]
}
\ No newline at end of file
diff --git a/.vscode/ftp-kr.sync.cache.json b/.vscode/ftp-kr.sync.cache.json
index 57bff4a..f4ea1d0 100644
--- a/.vscode/ftp-kr.sync.cache.json
+++ b/.vscode/ftp-kr.sync.cache.json
@@ -1,6 +1,12 @@
{
"ftp://host700513.hostido.net.pl@www@crmpro.projectpro.pl": {
"public_html": {
+ "AGENTS.md": {
+ "type": "-",
+ "size": 1074,
+ "lmtime": 1772750359672,
+ "modified": false
+ },
"ajax.php": {
"type": "-",
"size": 1340,
@@ -121,8 +127,8 @@
},
"class.Tasks.php": {
"type": "-",
- "size": 27574,
- "lmtime": 1772534579077,
+ "size": 28140,
+ "lmtime": 1772751184044,
"modified": false
},
"class.Users.php": {
@@ -644,14 +650,14 @@
},
"task_edit.php": {
"type": "-",
- "size": 35593,
- "lmtime": 1772534468454,
+ "size": 35730,
+ "lmtime": 1772751310836,
"modified": false
},
"task_popup.php": {
"type": "-",
- "size": 39914,
- "lmtime": 1772534728286,
+ "size": 41065,
+ "lmtime": 1772751327122,
"modified": false
},
"task_single.php": {
@@ -802,12 +808,6 @@
"size": 230708,
"lmtime": 1771920013460,
"modified": false
- },
- "AGENTS.md": {
- "type": "-",
- "size": 250,
- "lmtime": 1772530976286,
- "modified": false
}
}
},
diff --git a/autoload/controls/class.Tasks.php b/autoload/controls/class.Tasks.php
index 3f44ac4..417fa8f 100644
--- a/autoload/controls/class.Tasks.php
+++ b/autoload/controls/class.Tasks.php
@@ -331,6 +331,25 @@ class Tasks
exit;
}
+ static public function task_change_parent() {
+ global $mdb;
+
+ $task_id = (int)\S::get( 'task_id' );
+ $parent_id = (int)\S::get( 'parent_id' );
+
+ if ( $task_id and $task_id === $parent_id )
+ $parent_id = 0;
+
+ $parent_value = $parent_id > 0 ? $parent_id : null;
+
+ if ( $mdb -> update( 'tasks', [ 'parent_id' => $parent_value ], [ 'id' => $task_id ] ) ) {
+ echo json_encode( [ 'status' => 'success' ] );
+ } else {
+ echo json_encode( [ 'status' => 'error' ] );
+ }
+ exit;
+ }
+
static public function task_change_priority() {
global $mdb;
@@ -568,6 +587,7 @@ class Tasks
'user' => $user,
'statuses' => \factory\Tasks::get_statuses(),
'projects' => \factory\Projects::user_projects( $user['id'] ),
+ 'parent_tasks' => \factory\Tasks::parent_tasks( $user['id'] ),
'all_users' => \factory\Users::users_list()
] );
exit;
diff --git a/templates/tasks/main_view.php b/templates/tasks/main_view.php
index 0fb0405..5013334 100644
--- a/templates/tasks/main_view.php
+++ b/templates/tasks/main_view.php
@@ -706,6 +706,37 @@
});
});
+ // change task parent
+ $( 'body' ).on( 'change', 'select[name="task_parent"]', function() {
+ var task_id = $( this ).attr( 'task_id' );
+ var parent_id = $( this ).val();
+
+ $.ajax({
+ url: '/tasks/task_change_parent/',
+ type: 'POST',
+ data: {
+ task_id: task_id,
+ parent_id: parent_id
+ },
+ success: function( response )
+ {
+ var data = jQuery.parseJSON( response );
+ if ( data.status == 'success' )
+ {
+ var projects = jQuery( 'input[name="projects"]:checked' ).map(function() {
+ return this.value;
+ }).get();
+ projects.join( "," );
+ var users = jQuery( 'input[name="users"]:checked' ).map(function() {
+ return this.value;
+ }).get();
+ close_task_popup();
+ reload_tasks( projects, users );
+ }
+ }
+ });
+ });
+
$( 'body' ).on( 'change', 'select[name="task_status"]', function() {
var task_id = $( this ).attr( 'task_id' );
var status = $( this ).val();
diff --git a/templates/tasks/task_popup.php b/templates/tasks/task_popup.php
index edcc0db..5fef117 100644
--- a/templates/tasks/task_popup.php
+++ b/templates/tasks/task_popup.php
@@ -265,6 +265,18 @@
endforeach;?>
+