From 2e2335841909ef0f25c2616f8b34ed152d726a8e Mon Sep 17 00:00:00 2001
From: Dominik Blunk <dominik@blunk.ch>
Date: Mon, 12 Sep 2011 15:49:06 +0200
Subject: [PATCH] Implemented project specific tags

@see http://www.mantisbt.org/bugs/view.php?id=9716

To enable this feature run a Mantis update (new column "project_id" in tag table is required)
and set the config value $g_tag_project_specific_enabled to ON (defaults to OFF)

If project specific tags are enabled the following happens:

a) All existing tags will be considered as "global" (tags are saved with project_id = 0).
   Every "global" tag may be used in all projects.

b) Newly created tags are related to the current project (project of the bug precisely).
   These tags are only available within the same project scope.

c) No special handling of "parent projects" - a parent project is equal to a child project.
   Either tags for the parent project exists or not - no usage of "collected child project tags"

d) The tag - project relation may be edited in the tag management section. The tag overview
   shows only "global" tags and tags for the current project.

e) The filter shows only "global" tags and tags for the current project. Therefore filtering
   issues for specific tag(s) over multiple projects works only with "global" tags.

f) When switching $g_tag_project_specific_enabled between ON and OFF the existing tags will keep
   its project relation. New tags will always be "global" for "all projects". This makes sure that
   existing "project specific" tags are not unintentionally "globally" available

Other improvements:

- Added auth_reauthenticate() to the manage_tags_page.php
- Added the print_manage_menu() to tag_view_page.php and tag_update_page.php to improve
  usability (navigation back to tags overview after viewing/editing a tag)
---
 admin/schema.php                    |    4 ++
 bug_actiongroup_attach_tags_inc.php |    3 +-
 config_defaults_inc.php             |    7 +++
 core/tag_api.php                    |   97 ++++++++++++++++++++++++-----------
 manage_tags_page.php                |   27 ++++++++--
 tag_attach.php                      |    6 ++-
 tag_create.php                      |    9 +++-
 tag_update.php                      |    8 +++-
 tag_update_page.php                 |   24 +++++++--
 tag_view_page.php                   |   22 +++++---
 10 files changed, 150 insertions(+), 57 deletions(-)

diff --git a/admin/schema.php b/admin/schema.php
index d2b6940..505dd9b 100644
--- a/admin/schema.php
+++ b/admin/schema.php
@@ -608,3 +608,7 @@ $upgrade[] = Array( 'CreateIndexSQL', Array( 'idx_tag_name', db_get_table( 'mant
 $upgrade[] = Array( 'CreateIndexSQL', Array( 'idx_bug_tag_tag_id', db_get_table( 'mantis_bug_tag_table' ), 'tag_id' ) );
 $upgrade[] = Array( 'CreateIndexSQL', Array( 'idx_email_id', db_get_table( 'mantis_email_table' ), 'email_id', array( 'DROP' ) ), Array( 'db_index_exists', Array( db_get_table( 'mantis_email_table' ), 'idx_email_id') ) );
 $upgrade[] = Array( 'UpdateFunction', 'correct_multiselect_custom_fields_db_format' );
+
+/* 190 */
+$upgrade[] = Array( 'AddColumnSQL', Array( db_get_table( 'mantis_tag_table' ), "project_id I UNSIGNED NOTNULL DEFAULT '0'" ) );
+$upgrade[] = Array( 'CreateIndexSQL', Array( 'idx_project_id', db_get_table( 'mantis_tag_table' ), 'project_id' ) );
diff --git a/bug_actiongroup_attach_tags_inc.php b/bug_actiongroup_attach_tags_inc.php
index 3105acf..fca39b6 100644
--- a/bug_actiongroup_attach_tags_inc.php
+++ b/bug_actiongroup_attach_tags_inc.php
@@ -108,9 +108,10 @@
 		global $g_action_attach_tags_attach, $g_action_attach_tags_create;
 
 		$t_user_id = auth_get_current_user_id();
+		$t_bug = bug_get( $p_bug_id );
 
 		foreach( $g_action_attach_tags_create as $t_tag_row ) {
-			$t_tag_row['id'] = tag_create( $t_tag_row['name'], $t_user_id );
+			$t_tag_row['id'] = tag_create( $t_tag_row['name'], $t_user_id, '', $t_bug->project_id );
 			$g_action_attach_tags_attach[] = $t_tag_row;
 		}
 		$g_action_attach_tags_create = array();
diff --git a/config_defaults_inc.php b/config_defaults_inc.php
index 59b4764..2261a05 100644
--- a/config_defaults_inc.php
+++ b/config_defaults_inc.php
@@ -3506,6 +3506,13 @@
 	/***************
 	 * Bug Tagging *
 	 ***************/
+	
+	/**
+	 * When enabled tags will be project specific unless explicitely set to "global"
+	 * in the manage tags section
+	 * @global int $g_tag_project_specific_enabled
+	 */
+	$g_tag_project_specific_enabled = OFF;
 
 	/**
 	 * String that will separate tags as entered for input
diff --git a/core/tag_api.php b/core/tag_api.php
index fd31424..6a1b224 100644
--- a/core/tag_api.php
+++ b/core/tag_api.php
@@ -65,14 +65,15 @@ function tag_ensure_exists( $p_tag_id ) {
  * Determine if a given name is unique (not already used).
  * Uses a case-insensitive search of the database for existing tags with the same name.
  * @param string Tag name
+ * @param integer Project ID
  * @return boolean True if name is unique
  */
-function tag_is_unique( $p_name ) {
+function tag_is_unique( $p_name, $p_project_id = 0 ) {
 	$c_name = trim( $p_name );
 	$t_tag_table = db_get_table( 'mantis_tag_table' );
 
-	$query = 'SELECT id FROM ' . $t_tag_table . ' WHERE ' . db_helper_like( 'name' );
-	$result = db_query_bound( $query, Array( $c_name ) );
+	$query = 'SELECT id FROM ' . $t_tag_table . ' WHERE ' . db_helper_like( 'name' ) . " AND project_id = " . db_param();
+	$result = db_query_bound( $query, Array( $c_name, $p_project_id ) );
 
 	return db_num_rows( $result ) == 0;
 }
@@ -80,9 +81,10 @@ function tag_is_unique( $p_name ) {
 /**
  * Ensure that a name is unique.
  * @param string Tag name
+ * @param integer Project ID
  */
-function tag_ensure_unique( $p_name ) {
-	if( !tag_is_unique( $p_name ) ) {
+function tag_ensure_unique( $p_name, $p_project_id = 0 ) {
+	if( !tag_is_unique( $p_name, $p_project_id ) ) {
 		trigger_error( ERROR_TAG_DUPLICATE, ERROR );
 	}
 }
@@ -136,9 +138,10 @@ function tag_cmp_name( $p_tag1, $p_tag2 ) {
  * id = -1 and the tag name, and if the name is invalid, a row is returned with
  * id = -2 and the tag name.  The resulting array is then sorted by tag name.
  * @param string Input string to parse
+ * @param int Project ID
  * @return array Rows of tags parsed from input string
  */
-function tag_parse_string( $p_string ) {
+function tag_parse_string( $p_string, $p_project_id = 0 ) {
 	$t_tags = array();
 
 	$t_strings = explode( config_get( 'tag_separator' ), $p_string );
@@ -149,19 +152,27 @@ function tag_parse_string( $p_string ) {
 		}
 
 		$t_matches = array();
-		$t_tag_row = tag_get_by_name( $t_name );
+		$t_tag_row = tag_get_by_name( $t_name, $p_project_id );
 		if( $t_tag_row !== false ) {
 			$t_tags[] = $t_tag_row;
 		} else {
-			if( tag_name_is_valid( $t_name, $t_matches ) ) {
-				$t_id = -1;
+			if ( config_get( 'tag_project_specific_enabled' ) && $p_project_id > 0 ) {
+				// check if "global" tag exists
+				$t_tag_row = tag_get_by_name( $t_name, 0 );
+			}
+			if( $t_tag_row !== false ) {
+				$t_tags[] = $t_tag_row;
 			} else {
-				$t_id = -2;
+				if( tag_name_is_valid( $t_name, $t_matches ) ) {
+					$t_id = -1;
+				} else {
+					$t_id = -2;
+				}
+				$t_tags[] = array(
+					'id' => $t_id,
+					'name' => $t_name,
+				);
 			}
-			$t_tags[] = array(
-				'id' => $t_id,
-				'name' => $t_name,
-			);
 		}
 	}
 	usort( $t_tags, 'tag_cmp_name' );
@@ -189,6 +200,10 @@ function tag_parse_filters( $p_string ) {
 
 		if( !is_blank( $t_name ) && tag_name_is_valid( $t_name, $t_matches, $t_prefix ) ) {
 			$t_tag_row = tag_get_by_name( $t_matches[1] );
+			if( $t_tag_row === false && config_get( 'tag_project_specific_enabled' ) ) {
+				// no "global" tag found -> check project specific tag
+				$t_tag_row = tag_get_by_name( $t_matches[1], helper_get_current_project() );
+			}
 			if( $t_tag_row !== false ) {
 				$t_filter = utf8_substr( $t_name, 0, 1 );
 
@@ -238,14 +253,17 @@ function tag_get( $p_tag_id ) {
 /**
  * Return a tag row for the given name.
  * @param string Tag name
+ * @param int Project ID
  * @return Tag row
  */
-function tag_get_by_name( $p_name ) {
+function tag_get_by_name( $p_name, $p_project_id = 0 ) {
 	$t_tag_table = db_get_table( 'mantis_tag_table' );
+	$t_params = array( $p_name, $p_project_id );
 
 	$query = "SELECT * FROM $t_tag_table
-					WHERE " . db_helper_like( 'name' );
-	$result = db_query_bound( $query, Array( $p_name ) );
+					WHERE " . db_helper_like( 'name' ) ."
+					and project_id = " . db_param();
+	$result = db_query_bound( $query, $t_params );
 
 	if( 0 == db_num_rows( $result ) ) {
 		return false;
@@ -279,13 +297,14 @@ function tag_get_field( $p_tag_id, $p_field_name ) {
  * @param string Tag name
  * @param integer User ID
  * @param string Description
+ * @param integer Project ID
  * @return integer Tag ID
  */
-function tag_create( $p_name, $p_user_id = null, $p_description = '' ) {
+function tag_create( $p_name, $p_user_id = null, $p_description = '', $p_project_id = 0 ) {
 	access_ensure_global_level( config_get( 'tag_create_threshold' ) );
 
 	tag_ensure_name_is_valid( $p_name );
-	tag_ensure_unique( $p_name );
+	tag_ensure_unique( $p_name, $p_project_id );
 
 	if( null == $p_user_id ) {
 		$p_used_id = auth_get_current_user_id();
@@ -294,12 +313,17 @@ function tag_create( $p_name, $p_user_id = null, $p_description = '' ) {
 	}
 
 	$c_user_id = db_prepare_int( $p_user_id );
+	$c_project_id = db_prepare_int( $p_project_id );
+	if ( !config_get( 'tag_project_specific_enabled' ) ) {
+		$c_project_id = 0;
+	}
 	$c_date_created = db_now();
 
 	$t_tag_table = db_get_table( 'mantis_tag_table' );
 
 	$query = "INSERT INTO $t_tag_table
 				( user_id,
+				  project_id,
 				  name,
 				  description,
 				  date_created,
@@ -310,10 +334,11 @@ function tag_create( $p_name, $p_user_id = null, $p_description = '' ) {
 				  " . db_param() . ",
 				  " . db_param() . ",
 				  " . db_param() . ",
+				  " . db_param() . ",
 				  " . db_param() . "
 				)";
 
-	db_query_bound( $query, Array( $c_user_id, trim( $p_name ), trim( $p_description ), $c_date_created, $c_date_created ) );
+	db_query_bound( $query, Array( $c_user_id, $c_project_id, trim( $p_name ), trim( $p_description ), $c_date_created, $c_date_created ) );
 	return db_insert_id( $t_tag_table );
 }
 
@@ -322,9 +347,10 @@ function tag_create( $p_name, $p_user_id = null, $p_description = '' ) {
  * @param integer Tag ID
  * @param string Tag name
  * @param integer User ID
+ * @param integer Project ID
  * @param string Description
  */
-function tag_update( $p_tag_id, $p_name, $p_user_id, $p_description ) {
+function tag_update( $p_tag_id, $p_name, $p_user_id, $p_description, $p_project_id = 0 ) {
 	user_ensure_exists( $p_user_id );
 
 	if( auth_get_current_user_id() == tag_get_field( $p_tag_id, 'user_id' ) ) {
@@ -352,11 +378,19 @@ function tag_update( $p_tag_id, $p_name, $p_user_id, $p_description ) {
 
 	$query = "UPDATE $t_tag_table
 					SET user_id=" . db_param() . ",
-						name=" . db_param() . ",
-						description=" . db_param() . ",
+						name=" . db_param() . ",";
+	if ( $p_project_id >= 0 ) {
+		$query .= " 	project_id=" . db_param() . ",";
+	}
+	$query .= "			description=" . db_param() . ",
 						date_updated=" . db_param() . "
 					WHERE id=" . db_param();
-	db_query_bound( $query, Array( (int)$p_user_id, $p_name, $p_description, $c_date_updated, $c_tag_id ) );
+	if ( $p_project_id >= 0 ) {
+		db_query_bound( $query, Array( (int)$p_user_id, $p_name, $p_project_id, $p_description, $c_date_updated, $c_tag_id ) );
+	}
+	else {
+		db_query_bound( $query, Array( (int)$p_user_id, $p_name, $p_description, $c_date_updated, $c_tag_id ) );
+	}
 
 	if( $t_rename ) {
 		$t_bugs = tag_get_bugs_attached( $p_tag_id );
@@ -408,12 +442,13 @@ function tag_get_candidates_for_bug( $p_bug_id ) {
 	$t_params = array();
 	if ( 0 != $p_bug_id ) {
 		$t_bug_tag_table = db_get_table( 'mantis_bug_tag_table' );
-
+		$t_bug = bug_get( $p_bug_id );
+		$t_params[] = $p_bug_id;
 		if ( db_is_mssql() ) {
-			$t_params[] = $p_bug_id;
 			$query = "SELECT t.id FROM $t_tag_table t
 					LEFT JOIN $t_bug_tag_table b ON t.id=b.tag_id
-					WHERE b.bug_id IS NULL OR b.bug_id != " . db_param();
+					WHERE (b.bug_id IS NULL OR b.bug_id != " . db_param() .")
+					AND project_id IN (0, " . $t_bug->project_id . ")";
 			$result = db_query_bound( $query, $t_params );
 
 			$t_subquery_results = array();
@@ -426,12 +461,12 @@ function tag_get_candidates_for_bug( $p_bug_id ) {
 			$query = "SELECT id, name, description FROM $t_tag_table WHERE id IN (
 					SELECT t.id FROM $t_tag_table t
 					LEFT JOIN $t_bug_tag_table b ON t.id=b.tag_id
-					WHERE b.bug_id IS NULL OR b.bug_id != " . db_param() .
-				')';
+					WHERE (b.bug_id IS NULL OR b.bug_id != " . db_param() . ")
+					AND project_id IN (0, " . $t_bug->project_id . ")
+				)";
 		}
-		$t_params[] = $p_bug_id;
 	} else {
-		$query = 'SELECT id, name, description FROM ' . $t_tag_table;
+		$query = 'SELECT id, name, description FROM ' . $t_tag_table . " WHERE project_id IN (0, " . helper_get_current_project() . ")";
 	}
 
 	$query .= ' ORDER BY name ASC ';
diff --git a/manage_tags_page.php b/manage_tags_page.php
index 0718160..f0908ad 100644
--- a/manage_tags_page.php
+++ b/manage_tags_page.php
@@ -32,6 +32,8 @@ require_once( 'tag_api.php' );
 require_once( 'user_pref_api.php' );
 require_once( 'form_api.php' );
 
+auth_reauthenticate();
+
 access_ensure_global_level( config_get( 'tag_edit_threshold' ) );
 
 compress_enable();
@@ -78,11 +80,10 @@ echo '</tr></table>';
 
 $t_where_params = array();
 
-if ( $f_filter === 'ALL' ) {
-	$t_where = '';
-} else {
+$t_where = "WHERE project_id in (0, " . helper_get_current_project() . ")";
+if ( $f_filter !== 'ALL' ) {
 	$t_where_params[] = $f_filter . '%';
-	$t_where = 'WHERE ' . db_helper_like( 'name' );
+	$t_where .= ' AND ' . db_helper_like( 'name' );
 }
 
 # Set the number of Tags per page.
@@ -141,7 +142,8 @@ $t_result = db_query_bound( $t_query, $t_where_params, $t_per_page, $t_offset );
 		</td>
 	</tr>
 	<tr class="row-category">
-		<td width="25%"><?php echo lang_get( 'tag_name' ) ?></td>
+		<td width="20%"><?php echo lang_get( 'tag_name' ) ?></td>
+		<td width="20%"><?php echo lang_get( 'project_name' ) ?></td>
 		<td width="20%"><?php echo lang_get( 'tag_creator' ) ?></td>
 		<td width="20%"><?php echo lang_get( 'tag_created' ) ?></td>
 		<td width="20%"><?php echo lang_get( 'tag_updated' ) ?></td>
@@ -157,6 +159,7 @@ foreach ( $t_result as $t_tag_row ) {
 		<?php } else { ?>
 		<td><?php echo $t_tag_name ?></td>
 		<?php } ?>
+		<td><?php echo string_display_line( project_get_name( $t_tag_row['project_id'] ) ) ?></td>
 		<td><?php echo string_display_line( user_get_name( $t_tag_row['user_id'] ) ) ?></td>
 		<td><?php echo date( config_get( 'normal_date_format' ), $t_tag_row['date_created'] ) ?></td>
 		<td><?php echo date( config_get( 'normal_date_format' ), $t_tag_row['date_updated'] ) ?></td>
@@ -204,7 +207,19 @@ foreach ( $t_result as $t_tag_row ) {
 			<?php echo sprintf( lang_get( 'tag_separate_by' ), config_get( 'tag_separator' ) ); ?>
 		</td>
 	</tr>
-	<tr class="row-2">
+	<?php if ( config_get( 'tag_project_specific_enabled' ) ) { ?>
+	<tr class="row-2" valign="top">
+		<td class="category">
+			<?php echo lang_get( 'project_name' ) ?>
+		</td>
+		<td>
+			<select name="project_id">
+				<?php print_project_option_list( helper_get_current_project(), true ) ?>
+			</select>
+		</td>
+	</tr>
+	<?php } ?>
+	<tr class="row-1">
 		<td class="category">
 			<?php echo lang_get( 'tag_description' ) ?>
 		</td>
diff --git a/tag_attach.php b/tag_attach.php
index 14086f7..09b908b 100644
--- a/tag_attach.php
+++ b/tag_attach.php
@@ -32,6 +32,8 @@
 	form_security_validate( 'tag_attach' );
 
 	$f_bug_id = gpc_get_int( 'bug_id' );
+	$t_bug = bug_get( $f_bug_id );
+	$t_project_id = $t_bug->project_id;
 	$f_tag_select = gpc_get_int( 'tag_select' );
 	$f_tag_string = gpc_get_string( 'tag_string' );
 
@@ -43,7 +45,7 @@
 	 *     to the APIs.  This is to allow other clients of the API to support such
 	 *     functionality.  The access level checks should also be moved to the API.
 	 */
-	$t_tags = tag_parse_string( $f_tag_string );
+	$t_tags = tag_parse_string( $f_tag_string, $t_project_id );
 	$t_can_create = access_has_global_level( config_get( 'tag_create_threshold' ) );
 
 	$t_tags_create = array();
@@ -117,7 +119,7 @@
 		// end failed to attach tag
 	} else {
 		foreach( $t_tags_create as $t_tag_row ) {
-			$t_tag_row['id'] = tag_create( $t_tag_row['name'], $t_user_id );
+			$t_tag_row['id'] = tag_create( $t_tag_row['name'], $t_user_id, '', $t_project_id );
 			$t_tags_attach[] = $t_tag_row;
 		}
 
diff --git a/tag_create.php b/tag_create.php
index fa9662f..83c62fe 100644
--- a/tag_create.php
+++ b/tag_create.php
@@ -32,6 +32,13 @@ form_security_validate( 'tag_create' );
 
 $f_tag_name = gpc_get_string( 'name' );
 $f_tag_description = gpc_get_string( 'description' );
+if ( config_get( 'tag_project_specific_enabled' ) ) {
+	$f_project_id = gpc_get_int( 'project_id' );
+}
+else {
+	$f_project_id = 0;
+}
+
 
 $t_tag_user = auth_get_current_user_id();
 
@@ -39,7 +46,7 @@ if ( !is_null( $f_tag_name )) {
 	$t_tags = tag_parse_string( $f_tag_name );
 	foreach ( $t_tags as $t_tag_row ) {
 		if ( -1 == $t_tag_row['id'] ) {
-			tag_create( $t_tag_row['name'], $t_tag_user, $f_tag_description );
+			tag_create( $t_tag_row['name'], $t_tag_user, $f_tag_description, $f_project_id );
 		}
 	}
 }
diff --git a/tag_update.php b/tag_update.php
index 1252f89..310b40c 100644
--- a/tag_update.php
+++ b/tag_update.php
@@ -35,6 +35,12 @@
 
 	$f_tag_id = gpc_get_int( 'tag_id' );
 	$t_tag_row = tag_get( $f_tag_id );
+	if ( config_get( 'tag_project_specific_enabled' ) ) {
+		$f_project_id = gpc_get_int( 'project_id' );
+	}
+	else {
+		$f_project_id = -1;
+	}
 
 	if ( !( access_has_global_level( config_get( 'tag_edit_threshold' ) )
 		|| ( auth_get_current_user_id() == $t_tag_row['user_id'] )
@@ -65,7 +71,7 @@
 		$t_update = true;
 	}
 
-	tag_update( $f_tag_id, $f_new_name, $f_new_user_id, $f_new_description );
+	tag_update( $f_tag_id, $f_new_name, $f_new_user_id, $f_new_description, $f_project_id );
 
 	form_security_purge( 'tag_update' );
 
diff --git a/tag_update_page.php b/tag_update_page.php
index 69de115..323aac6 100644
--- a/tag_update_page.php
+++ b/tag_update_page.php
@@ -49,6 +49,8 @@
 	}
 
 	html_page_top( sprintf( lang_get( 'tag_update' ), $t_name ) );
+	
+	print_manage_menu( '' );
 ?>
 
 <br />
@@ -69,16 +71,26 @@
 
 <!-- Info -->
 <tr class="row-category">
-	<td width="15%"><?php echo lang_get( 'tag_id' ) ?></td>
+	<td width="5%"><?php echo lang_get( 'tag_id' ) ?></td>
 	<td width="25%"><?php echo lang_get( 'tag_name' ) ?></td>
-	<td width="20%"><?php echo lang_get( 'tag_creator' ) ?></td>
-	<td width="20%"><?php echo lang_get( 'tag_created' ) ?></td>
-	<td width="20%"><?php echo lang_get( 'tag_updated' ) ?></td>
+	<td width="25%"><?php echo lang_get( 'project_name' ) ?></td>
+	<td width="15%"><?php echo lang_get( 'tag_creator' ) ?></td>
+	<td width="15%"><?php echo lang_get( 'tag_created' ) ?></td>
+	<td width="15%"><?php echo lang_get( 'tag_updated' ) ?></td>
 </tr>
 
 <tr <?php echo helper_alternate_class() ?>>
 	<td><?php echo $t_tag_row['id'] ?></td>
 	<td><input type="text" <?php echo helper_get_tab_index() ?> name="name" value="<?php echo $t_name ?>"/></td>
+	<td>
+		<?php if ( config_get( 'tag_project_specific_enabled' ) ) { ?>
+		<select name="project_id">
+			<?php print_project_option_list( $t_tag_row['project_id'], true ) ?>
+		</select>
+		<?php } else {
+			print( project_get_name( $t_tag_row['project_id'] ) );
+		} ?>
+	</td>
 	<td><?php
 			if ( access_has_global_level( config_get( 'tag_edit_threshold' ) ) ) {
 				if ( ON == config_get( 'use_javascript' ) ) {
@@ -99,13 +111,13 @@
 
 <!-- spacer -->
 <tr class="spacer">
-	<td colspan="5"></td>
+	<td colspan="6"></td>
 </tr>
 
 <!-- Description -->
 <tr <?php echo helper_alternate_class() ?>>
 	<td class="category"><?php echo lang_get( 'tag_description' ) ?></td>
-	<td colspan="4">
+	<td colspan="5">
 		<textarea name="description" <?php echo helper_get_tab_index() ?> cols="80" rows="6"><?php echo string_textarea( $t_description ) ?></textarea>
 	</td>
 </tr>
diff --git a/tag_view_page.php b/tag_view_page.php
index 1eb3e7f..7a811a6 100644
--- a/tag_view_page.php
+++ b/tag_view_page.php
@@ -39,6 +39,8 @@
 	$t_description = string_display( $t_tag_row['description'] );
 
 	html_page_top( sprintf( lang_get( 'tag_details' ), $t_name ) );
+	
+	print_manage_menu( '' );
 ?>
 
 <br />
@@ -57,16 +59,18 @@
 
 <!-- Info -->
 <tr class="row-category">
-	<td width="15%"><?php echo lang_get( 'tag_id' ) ?></td>
-	<td width="25%"><?php echo lang_get( 'tag_name' ) ?></td>
-	<td width="20%"><?php echo lang_get( 'tag_creator' ) ?></td>
-	<td width="20%"><?php echo lang_get( 'tag_created' ) ?></td>
-	<td width="20%"><?php echo lang_get( 'tag_updated' ) ?></td>
+	<td width="10%"><?php echo lang_get( 'tag_id' ) ?></td>
+	<td width="30%"><?php echo lang_get( 'tag_name' ) ?></td>
+	<td width="30%"><?php echo lang_get( 'project_name' ) ?></td>
+	<td width="10%"><?php echo lang_get( 'tag_creator' ) ?></td>
+	<td width="10%"><?php echo lang_get( 'tag_created' ) ?></td>
+	<td width="10%"><?php echo lang_get( 'tag_updated' ) ?></td>
 </tr>
 
 <tr <?php echo helper_alternate_class() ?>>
 	<td><?php echo $t_tag_row['id'] ?></td>
 	<td><?php echo $t_name ?></td>
+	<td><?php echo string_display_line( project_get_name( $t_tag_row['project_id'] ) ) ?></td>
 	<td><?php echo string_display_line( user_get_name($t_tag_row['user_id']) ) ?></td>
 	<td><?php echo date( config_get( 'normal_date_format' ), $t_tag_row['date_created'] ) ?> </td>
 	<td><?php echo date( config_get( 'normal_date_format' ), $t_tag_row['date_updated'] ) ?> </td>
@@ -74,13 +78,13 @@
 
 <!-- spacer -->
 <tr class="spacer">
-	<td colspan="5"></td>
+	<td colspan="6"></td>
 </tr>
 
 <!-- Description -->
 <tr <?php echo helper_alternate_class() ?>>
 	<td class="category"><?php echo lang_get( 'tag_description' ) ?></td>
-	<td colspan="4"><?php echo $t_description ?></td>
+	<td colspan="5"><?php echo $t_description ?></td>
 </tr>
 
 <!-- Statistics -->
@@ -98,7 +102,7 @@
 
 			echo ( $i > 0 ? '<tr '.helper_alternate_class().'>' : '' );
 			echo "<td><a href='tag_view_page.php?tag_id=$t_tag[id]' title='$t_description'>$t_name</a></td>\n";
-			echo '<td colspan="3">';
+			echo '<td colspan="4">';
 			print_bracket_link( 'search.php?tag_string='.urlencode("+$t_tag_row[name]".config_get('tag_separator')."+$t_name"), sprintf( lang_get( 'tag_related_issues' ), $t_tag['count'] ) );
 			echo '</td></tr>';
 
@@ -109,7 +113,7 @@
 
 <!-- Buttons -->
 <tr>
-	<td colspan="5">
+	<td colspan="6">
 <?php
 	$t_can_edit = access_has_global_level( config_get( 'tag_edit_threshold' ) );
 	$t_can_edit_own = $t_can_edit || auth_get_current_user_id() == tag_get_field( $f_tag_id, 'user_id' )
-- 
1.7.4.msysgit.0

