View Issue Details

IDProjectCategoryView StatusLast Update
0010020mantisbtbugtrackerpublic2017-07-27 02:30
Reporterolegos Assigned To 
PrioritynormalSeverityfeatureReproducibilityN/A
Status acknowledgedResolutionopen 
Summary0010020: Threading for notes
Description

It would be nice if it were possible to see issue notes in a threaded way, similarly to some web forums that support threading. I imagine each note would have a Reply button, and there would be a way to switch to a threaded view.

Tagspatch
Attached Files
bugnote-answers.patch (12,890 bytes)   
Index: bugnote_add_inc.php
===================================================================
--- bugnote_add_inc.php	(revision 211)
+++ bugnote_add_inc.php	(working copy)
@@ -30,6 +30,7 @@
 <?php
 	collapse_open( 'bugnote_add' );
 ?>
+<a name="bugnote_add"></a>
 <form name="bugnoteadd" method="post" action="bugnote_add.php">
 <?php echo form_security_field( 'bugnote_add' ) ?>
 <input type="hidden" name="bug_id" value="<?php echo $f_bug_id ?>" />
@@ -70,6 +71,15 @@
 </tr>
 <?php } ?>
 
+<tr class="row-1">
+	<td class="category">
+		Parent-Bugnote-ID: 
+	</td>
+	<td>
+		<input type="text" name="parent_bugnote_id" id="parent_bugnote_id" value="0" size="3" />
+	</td>
+</tr>
+
 <?php if ( config_get('time_tracking_enabled') ) { ?>
 <?php if ( access_has_bug_level( config_get( 'time_tracking_edit_threshold' ), $f_bug_id ) ) { ?>
 <tr <?php echo helper_alternate_class() ?>>
@@ -97,11 +107,7 @@
 <?php } ?>
 
 <?php event_signal( 'EVENT_BUGNOTE_ADD_FORM', array( $f_bug_id ) ); ?>
-<tr>
-	<td class="center" colspan="2">
-		<input type="submit" class="button" value="<?php echo lang_get( 'add_bugnote_button' ) ?>"  onclick="this.disabled=1;document.bugnoteadd.submit();" />
-	</td>
-</tr>
+
 </table>
 </form>
 <?php
Index: bugnote_delete.php
===================================================================
--- bugnote_delete.php	(revision 211)
+++ bugnote_delete.php	(working copy)
@@ -52,6 +52,25 @@
 		access_ensure_bugnote_level( config_get( 'delete_bugnote_threshold' ), $f_bugnote_id );
 	}
 
+	$t_bugnote_table = db_get_table( 'mantis_bugnote_table' );
+	$query = "	SELECT *
+		          	FROM $t_bugnote_table
+		          	WHERE bug_id=" . db_param() . " AND parent_bugnote_id=" . db_param();
+	$result = db_query_bound( $query, Array( $t_bug_id , $f_bugnote_id ) );
+	$bugnote_count = db_num_rows( $result );	
+	
+	if($bugnote_count > 0){
+		html_page_top();		
+		
+		echo "<br />\n<div align=\"center\">\n";
+		print_hr();
+		echo "\n" . lang_get('delete_bugnote_delete_child_bugnotes_first') . "\n";		
+		print_hr();
+		echo "</div>\n";		
+		
+		html_page_bottom();		
+		exit; 
+	}else{
 	helper_ensure_confirmed( lang_get( 'delete_bugnote_sure_msg' ),
 							 lang_get( 'delete_bugnote_button' ) );
 
@@ -63,3 +82,4 @@
 	form_security_purge( 'bugnote_delete' );
 
 	print_successful_redirect( string_get_bug_view_url( $t_bug_id ) . '#bugnotes' );
+	}
Index: bugnote_view_inc.php
===================================================================
--- bugnote_view_inc.php	(revision 211)
+++ bugnote_view_inc.php	(working copy)
@@ -27,8 +27,14 @@
 /**
  * Requires bugnote API
  */
+
 require_once( 'current_user_api.php' );
 
+showBugnotes($f_bug_id);  
+ 
+function showBugnotes($f_bug_id, $t_parent_bugnote_id = 0){
+	global $g_project_override, $tpl_bug_id, $t_bugnote; 
+	
 # grab the user id currently logged in
 $t_user_id = auth_get_current_user_id();
 
@@ -41,7 +47,14 @@
 
 # get the bugnote data
 $t_bugnote_order = current_user_get_pref( 'bugnote_order' );
-$t_bugnotes = bugnote_get_all_visible_bugnotes( $f_bug_id, $t_bugnote_order, 0, $t_user_id );
+	if($t_parent_bugnote_id > 0){
+		$t_bugnotes = bugnote_get_all_visible_bugnotes( $f_bug_id, $t_bugnote_order, 0, $t_user_id, $t_parent_bugnote_id);
+		if(count($t_bugnotes) < 1){
+			return 0;
+		}
+	}else{
+		$t_bugnotes = bugnote_get_all_visible_bugnotes( $f_bug_id, $t_bugnote_order, 0, $t_user_id, 0);
+	}
 
 #precache users
 $t_bugnote_users = array();
@@ -51,6 +64,8 @@
 user_cache_array_rows( $t_bugnote_users );
 
 $num_notes = count( $t_bugnotes );
+	
+	if($t_parent_bugnote_id < 1){
 ?>
 
 <?php # Bugnotes BEGIN ?>
@@ -68,6 +83,11 @@
 	</td>
 </tr>
 <?php
+	}else{
+		?>
+		<table width="100%" cellspacing="1">
+		<?php
+	}
 	# no bugnotes
 	if ( 0 == $num_notes ) {
 ?>
@@ -108,11 +128,12 @@
 			$t_bugnote_css		= 'bugnote-public';
 			$t_bugnote_note_css	= 'bugnote-note-public';
 		}
+			
 ?>
 <tr class="bugnote" id="c<?php echo $t_bugnote->id ?>">
         <td class="<?php echo $t_bugnote_css ?>">
 		<?php print_avatar( $t_bugnote->reporter_id ); ?>
-		<span class="small">(<a href="<?php echo string_get_bugnote_view_url($t_bugnote->bug_id, $t_bugnote->id) ?>" title="<?php echo lang_get( 'bugnote_link_title' ) ?>"><?php echo $t_bugnote_id_formatted ?>)</a></span><br />
+			<span class="small">(<a href="<?php echo string_get_bugnote_view_url($t_bugnote->bug_id, $t_bugnote->id) ?>" title="<?php echo lang_get( 'bugnote_link_title' ) ?>"><?php echo $t_bugnote_id_formatted ?>)</a></span> 
 		<?php
 			echo print_user( $t_bugnote->reporter_id );
 		?>
@@ -129,13 +150,12 @@
 		<span class="small">[ <?php echo lang_get( 'private' ) ?> ]</span>
 		<?php } ?>
 		<br />
-		<span class="small"><?php echo date( $t_normal_date_format, $t_bugnote->date_submitted ); ?></span><br />
-		<?php
+			<span class="small"><?php echo date( $t_normal_date_format, $t_bugnote->date_submitted ); ?></span><?php
 		if ( $t_bugnote_modified ) {
-			echo '<span class="small">' . lang_get( 'edited_on') . lang_get( 'word_separator' ) . date( $t_normal_date_format, $t_bugnote->last_modified ) . '</span><br />';
+				echo '<span class="small">, ' . lang_get( 'edited_on') . lang_get( 'word_separator' ) . date( $t_normal_date_format, $t_bugnote->last_modified ) . '</span>';
 		}
 		?>
-		<br /><div class="small">
+			<div class="small">
 		<?php
 			# bug must be open to be editable
 			if ( !bug_is_readonly( $f_bug_id ) ) {
@@ -171,6 +191,10 @@
 						print_button( 'bugnote_set_view_state.php?private=1&bugnote_id=' . $t_bugnote->id, lang_get( 'make_private' ) );
 					}
 				}
+					
+					?>
+					[<a href="#bugnote_add" onclick="document.getElementById('parent_bugnote_id').value='<?php echo $t_bugnote->id; ?>';">Antworten</a>]
+					<?php
 			}
 		?>
 		</div>
@@ -211,29 +235,58 @@
 					break;
 			}
 
-			echo string_display_links( $t_bugnote->note );;
+				$note = str_replace(array('<','>'), array('&lt;','&gt;'), $t_bugnote->note); 
+				echo string_display_links(	$note	);	
 		?>
 	</td>
 </tr>
 <?php event_signal( 'EVENT_VIEW_BUGNOTE', array( $f_bug_id, $t_bugnote->id, VS_PRIVATE == $t_bugnote->view_state ) ); ?>
+	<?php
+		// Child-Bugnotes
+		$t_childBugnotes = bugnote_get_all_visible_bugnotes( $f_bug_id, $t_bugnote_order, 0, $t_user_id, $t_bugnote->id);
+		if(count($t_childBugnotes) > 0){
+			?>
+			<tr>
+				<td colspan="2">
+					<table width="100%" cellspacing="0">
+						<tr>
+							<td width="10">&nbsp;</td>
+							<td>
+							<?php
+							$t_total_time += showBugnotes($f_bug_id, $t_bugnote->id); 
+							?>
+							</td>
+						</tr>
+					</table>
+				</td>
+			</tr>
+			<?php
+		}
+		
+		if($t_parent_bugnote_id < 1){
+		?>
 <tr class="spacer">
 	<td colspan="2"></td>
 </tr>
 <?php
+		}
+		
 	} # end for loop
 
-	if ( $t_total_time > 0 && access_has_bug_level( config_get( 'time_tracking_view_threshold' ), $f_bug_id ) ) {
+		if ($t_parent_bugnote_id < 1 && $t_total_time > 0 && access_has_bug_level( config_get( 'time_tracking_view_threshold' ), $f_bug_id ) ) {
 		echo '<tr><td colspan="2">', sprintf ( lang_get( 'total_time_for_issue' ), db_minutes_to_hhmm( $t_total_time ) ), '</td></tr>';
 	}
 
+		if($t_parent_bugnote_id < 1){
 	event_signal( 'EVENT_VIEW_BUGNOTES_END', $f_bug_id );
+		}
 ?>
 </table>
 
 <?php
+	if($t_parent_bugnote_id < 1){
 	collapse_closed( 'bugnotes' );
 ?>
-
 <table class="width100" cellspacing="1">
 <tr>
 	<td class="form-title" colspan="2">
@@ -244,3 +297,7 @@
 </table>
 <?php
 	collapse_end( 'bugnotes' );
+	}
+		
+	return $t_total_time; 
+}
\ No newline at end of file
Index: core/bugnote_api.php
===================================================================
--- core/bugnote_api.php	(revision 211)
+++ core/bugnote_api.php	(working copy)
@@ -125,9 +125,11 @@
  * @access public
  */
 function bugnote_add( $p_bug_id, $p_bugnote_text, $p_time_tracking = '0:00', $p_private = false, $p_type = BUGNOTE, $p_attr = '', $p_user_id = null, $p_send_email = TRUE, $p_log_history = TRUE) {
+
 	$c_bug_id = db_prepare_int( $p_bug_id );
 	$c_time_tracking = helper_duration_to_minutes( $p_time_tracking );
 	$c_type = db_prepare_int( $p_type );
+	$c_parent_bugnote_id = gpc_get_int('parent_bugnote_id', 0); 
 
 	if( REMINDER !== $p_type ) {
 		# Check if this is a time-tracking note
@@ -176,10 +178,10 @@
 
 	# insert bugnote info
 	$query = "INSERT INTO $t_bugnote_table
-				(bug_id, reporter_id, bugnote_text_id, view_state, date_submitted, last_modified, note_type, note_attr, time_tracking )
+				(bug_id, parent_bugnote_id, reporter_id, bugnote_text_id, view_state, date_submitted, last_modified, note_type, note_attr, time_tracking )
 			VALUES
-				(" . db_param() . ', ' . db_param() . ',' . db_param() . ', ' . db_param() . ', ' . db_param() . ',' . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ' )';
-	db_query_bound( $query, Array( $c_bug_id, $c_user_id, $t_bugnote_text_id, $t_view_state, db_now(), db_now(), $c_type, $p_attr, $c_time_tracking ) );
+				(" . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ',' . db_param() . ', ' . db_param() . ', ' . db_param() . ', ' . db_param() . ' )';
+	db_query_bound( $query, Array( $c_bug_id, $c_parent_bugnote_id, $c_user_id, $t_bugnote_text_id, $t_view_state, db_now(), db_now(), $c_type, $p_attr, $c_time_tracking ) );
 
 	# get bugnote id
 	$t_bugnote_id = db_insert_id( $t_bugnote_table );
@@ -206,11 +208,13 @@
 	# Event integration
 	event_signal( 'EVENT_BUGNOTE_ADD', array( $p_bug_id, $t_bugnote_id ) );
 
+
 	# only send email if the text is not blank, otherwise, it is just recording of time without a comment.
 	if( TRUE == $p_send_email && !is_blank( $t_bugnote_text ) ) {
 		email_bugnote_add( $p_bug_id );
 	}
 
+
 	return $t_bugnote_id;
 }
 
@@ -353,7 +357,7 @@
  * @return array array of bugnotes
  * @access public
  */
-function bugnote_get_all_visible_bugnotes( $p_bug_id, $p_user_bugnote_order, $p_user_bugnote_limit, $p_user_id = null ) {
+function bugnote_get_all_visible_bugnotes( $p_bug_id, $p_user_bugnote_order, $p_user_bugnote_limit, $p_user_id = null, $p_parent_bugnote_id = 0) {
 	if( $p_user_id === null ) {
 		$t_user_id = auth_get_current_user_id();
 	} else {
@@ -363,7 +367,7 @@
 	$t_project_id = bug_get_field( $p_bug_id, 'project_id' );
 	$t_user_access_level = user_get_access_level( $t_user_id, $t_project_id );
 
-	$t_all_bugnotes = bugnote_get_all_bugnotes( $p_bug_id );
+	$t_all_bugnotes = bugnote_get_all_bugnotes( $p_bug_id, $p_parent_bugnote_id );
 	$t_private_bugnote_threshold = config_get( 'private_bugnote_threshold' );
 
 	$t_private_bugnote_visible = access_compare_level( $t_user_access_level, config_get( 'private_bugnote_threshold' ) );
@@ -407,7 +411,7 @@
  * @return array array of bugnotes
  * @access public
  */
-function bugnote_get_all_bugnotes( $p_bug_id ) {
+function bugnote_get_all_bugnotes( $p_bug_id , $p_parent_bugnote_id = 0) {
 	global $g_cache_bugnotes, $g_cache_bugnote;
 
 	if( !isset( $g_cache_bugnotes ) ) {
@@ -428,12 +432,17 @@
 		$t_query = "SELECT b.*, t.note
 			          	FROM      $t_bugnote_table b
 			          	LEFT JOIN $t_bugnote_text_table t ON b.bugnote_text_id = t.id
-						WHERE b.bug_id=" . db_param() . '
-						ORDER BY b.id ASC';
+						WHERE b.bug_id=" . db_param(); 
+		
+		if($p_parent_bugnote_id > -1){
+			$t_query .= " AND b.parent_bugnote_id=" . db_param(); 
+		}
+					
+		$t_query .= "	ORDER BY b.id ASC";
 		$t_bugnotes = array();
 
 		# BUILD bugnotes array
-		$t_result = db_query_bound( $t_query, array( $p_bug_id ) );
+		$t_result = db_query_bound( $t_query, array( $p_bug_id , $p_parent_bugnote_id ) );
 
 		while( $row = db_fetch_array( $t_result ) ) {
 			$t_bugnote = new BugnoteData;
@@ -454,10 +463,10 @@
 			$g_cache_bugnote[(int)$t_bugnote->id] = $t_bugnote;
 		}
 
-		$g_cache_bugnotes[(int)$p_bug_id] = $t_bugnotes;
+		$g_cache_bugnotes[(int)$p_bug_id . (int)$p_parent_bugnote_id] = $t_bugnotes;
 	}
 
-	return $g_cache_bugnotes[(int)$p_bug_id];
+	return $g_cache_bugnotes[(int)$p_bug_id . (int)$p_parent_bugnote_id];
 }
 
 /**
Index: lang/strings_english.txt
===================================================================
--- lang/strings_english.txt	(revision 211)
+++ lang/strings_english.txt	(working copy)
@@ -96,6 +96,7 @@
 $s_bugnote_link_title = 'Direct link to note';
 $s_delete_bugnote_button = 'Delete Note';
 $s_delete_bugnote_sure_msg = 'Are you sure you wish to delete this note?';
+$s_delete_bugnote_delete_child_bugnotes_first = 'Please delete the Child-Notes first!';
 $s_bug_relationships = 'Relationships';
 $s_empty_password_sure_msg = 'The user has an empty password. Are you sure that is what you want?';
 $s_empty_password_button = 'Use Empty Password';
bugnote-answers.patch (12,890 bytes)   

Relationships

has duplicate 0014212 closedatrol Notes should behave in a more threadlike conversation manner. 

Activities

ant

ant

2011-04-27 07:41

reporter   ~0028708

This would be very useful. Issues with many notes can be hard to follow, and some notes are only relevant to some watchers (eg. reporters, developers).

Being able to create threads for eg. requirements, design, reviews would be a big improvement. As would be the ability to monitor or un-monitor particular threads.

mmmichael

mmmichael

2013-01-11 03:35

reporter   ~0034763

I think this would be an great feature! We have the same Problem with many notes and parallel activity.

Normally we do an "devide an conquere" than and clone the ticket but sometimes it would be great!

mmmichael

mmmichael

2014-06-14 16:12

reporter   ~0040808

I added this feature. Please check the patch and the following sql query.

ALTER TABLE mantis_bugnote_table ADD parent_bugnote_id INT( 10 ) NOT NULL AFTER bug_id ,
ADD INDEX ( parent_bugnote_id ) ;

rogueresearch

rogueresearch

2017-07-26 16:07

reporter   ~0057335

I came here to request the same issue, but found this ticket already exists. So +1 from me I guess...