[Fusionforge-commits] FusionForge branch master updated. v6.0.5-1756-g97ffe89

Franck Villaume nerville at libremir.placard.fr.eu.org
Thu May 4 13:51:45 CEST 2017


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "FusionForge".

The branch, master has been updated
       via  97ffe89726b1a95bfa03d60a4805fb54d821da14 (commit)
      from  5c02d437ae2ab9d01370cc9aec4ecc46f3602746 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://scm.fusionforge.org/anonscm/gitweb/?p=fusionforge/fusionforge.git;a=commitdiff;h=97ffe89726b1a95bfa03d60a4805fb54d821da14

commit 97ffe89726b1a95bfa03d60a4805fb54d821da14
Author: St├ęphane-Eymeric Bredthauer <sebredthauer at gmail.com>
Date:   Thu May 4 13:28:49 2017 +0200

    Tracker: Artifacts dependencies, part 1

diff --git a/src/common/tracker/Artifact.class.php b/src/common/tracker/Artifact.class.php
index c957df7..b669579 100644
--- a/src/common/tracker/Artifact.class.php
+++ b/src/common/tracker/Artifact.class.php
@@ -127,9 +127,16 @@ class Artifact extends FFObject {
 	/**
 	 * Database result set of related tasks
 	 *
-	 * @var	result	$relatedtasks
+	 * @var	result	$related_tasks
 	 */
-	var $relatedtasks;
+	var $related_tasks;
+
+	/**
+	 * Database result set of children
+	 *
+	 * @var	result	$children
+	 */
+	var $children;
 
 	/**
 	 * cached return value of getVotes
@@ -766,8 +773,8 @@ class Artifact extends FFObject {
 	 * @return	resource	Database result set
 	 */
 	function getRelatedTasks() {
-		if (!$this->relatedtasks) {
-			$this->relatedtasks = db_query_params ('SELECT pt.group_project_id,pt.project_task_id,pt.summary,pt.start_date,pt.end_date,pgl.group_id,pt.status_id,pt.percent_complete,ps.status_name
+		if (!$this->related_tasks) {
+			$this->related_tasks = db_query_params ('SELECT pt.group_project_id,pt.project_task_id,pt.summary,pt.start_date,pt.end_date,pgl.group_id,pt.status_id,pt.percent_complete,ps.status_name
 			FROM project_task pt, project_group_list pgl, project_status ps
 			WHERE pt.group_project_id = pgl.group_project_id
                         AND ps.status_id = pt.status_id
@@ -776,7 +783,7 @@ class Artifact extends FFObject {
 				AND artifact_id = $1)',
 							       array ($this->getID())) ;
 		}
-		return $this->relatedtasks;
+		return $this->related_tasks;
 	}
 
 	/**
@@ -1582,7 +1589,7 @@ class Artifact extends FFObject {
 			// 3) Ensure that only integers are given.
 			// 4) Ensure that id corresponds to valid tracker id.
 			//
-			if ($type == ARTIFACT_EXTRAFIELDTYPE_RELATION) {
+			if ($type == ARTIFACT_EXTRAFIELDTYPE_RELATION || $type == ARTIFACT_EXTRAFIELDTYPE_PARENT) {
 				$value = preg_replace('/\[\#(\d+)\]/', "\\1", trim($extra_fields[$efid]));
 				$value = preg_replace('/\\s+/', ' ', $value);
 				$new = '';
@@ -1919,6 +1926,7 @@ class Artifact extends FFObject {
 				case ARTIFACT_EXTRAFIELDTYPE_TEXT:
 				case ARTIFACT_EXTRAFIELDTYPE_TEXTAREA:
 				case ARTIFACT_EXTRAFIELDTYPE_RELATION:
+				case ARTIFACT_EXTRAFIELDTYPE_PARENT:
 				case ARTIFACT_EXTRAFIELDTYPE_INTEGER:
 				case ARTIFACT_EXTRAFIELDTYPE_DATE:
 				case ARTIFACT_EXTRAFIELDTYPE_DATETIME:
@@ -2050,6 +2058,80 @@ class Artifact extends FFObject {
 		return false;
 	}
 
+	function  getRelations() {
+		$aid = $this->getID();
+		$res = db_query_params ('SELECT *
+		FROM artifact_extra_field_list, artifact_extra_field_data, artifact_group_list, artifact, groups
+		WHERE field_type = $1
+		AND artifact_extra_field_list.extra_field_id=artifact_extra_field_data.extra_field_id
+		AND artifact_group_list.group_artifact_id = artifact_extra_field_list.group_artifact_id
+		AND artifact.artifact_id = artifact_extra_field_data.artifact_id
+		AND groups.group_id = artifact_group_list.group_id
+		AND (field_data = $2 OR field_data LIKE $3 OR field_data LIKE $4 OR field_data LIKE $5)
+		AND artifact.is_deleted = 0
+		ORDER BY artifact_group_list.group_id ASC, name ASC, artifact.artifact_id ASC',
+				array(ARTIFACT_EXTRAFIELDTYPE_RELATION,
+						$aid,
+						"$aid %",
+						"% $aid %",
+						"% $aid"));
+		return $res;
+	}
+
+	function hasChildren() {
+		if (!$this->children) {
+			$res = $this->getChildren();
+		}
+		$nb = db_numrows($this->children);
+		if ($nb>0) {
+			return $nb;
+		}
+		return false;
+	}
+
+	function  getChildren() {
+		$aid = $this->getID();
+		if (!$this->children) {
+			$this->children = db_query_params ('SELECT *
+		FROM artifact_extra_field_list, artifact_extra_field_data, artifact_group_list, artifact, groups
+		WHERE field_type = $1
+		AND artifact_extra_field_list.extra_field_id=artifact_extra_field_data.extra_field_id
+		AND artifact_group_list.group_artifact_id = artifact_extra_field_list.group_artifact_id
+		AND artifact.artifact_id = artifact_extra_field_data.artifact_id
+		AND groups.group_id = artifact_group_list.group_id
+		AND field_data = $2
+		AND artifact.is_deleted = 0
+		ORDER BY artifact_group_list.group_id ASC, name ASC, artifact.artifact_id ASC',
+					array(ARTIFACT_EXTRAFIELDTYPE_PARENT,
+							$aid));
+		}
+		return $this->children;
+	}
+
+	function hasParent() {
+		return ($this->getParent?true:false);
+	}
+
+	function  getParent() {
+		$res = db_query_params ('SELECT field_data FROM
+									artifact_extra_field_data
+									NATURAL INNER JOIN artifact_extra_field_list
+								WHERE
+									field_type = $1
+										AND artifact_id = $2',
+					array(ARTIFACT_EXTRAFIELDTYPE_PARENT,
+							$this->getID()));
+		if (db_numrows($res) == 0) {
+			$return = false;
+		} else {
+			$data = db_fetch_array($res);
+			db_free_result($res);
+			$return = $data['field_data'];
+		}
+		return $return;
+	}
+
+
 	function getPermalink() {
 		return '/tracker/a_follow.php/'.$this->getID();
 	}
diff --git a/src/common/tracker/ArtifactExtraField.class.php b/src/common/tracker/ArtifactExtraField.class.php
index 6f83370..36af66c 100644
--- a/src/common/tracker/ArtifactExtraField.class.php
+++ b/src/common/tracker/ArtifactExtraField.class.php
@@ -51,6 +51,7 @@ define('ARTIFACT_EXTRAFIELDTYPE_DATETIMERANGE', 19);
 define('ARTIFACT_EXTRAFIELDTYPE_DATERANGE', 20);
 define('ARTIFACT_EXTRAFIELDTYPE_EFFORT',21);
 define('ARTIFACT_EXTRAFIELDTYPE_EFFORTRANGE',22);
+define('ARTIFACT_EXTRAFIELDTYPE_PARENT',23);
 
 define ("ARTIFACT_EXTRAFIELDTYPEGROUP_SINGLECHOICE", serialize (array (ARTIFACT_EXTRAFIELDTYPE_SELECT, ARTIFACT_EXTRAFIELDTYPE_RADIO, ARTIFACT_EXTRAFIELDTYPE_STATUS)));
 define ("ARTIFACT_EXTRAFIELDTYPEGROUP_MULTICHOICE", serialize (array (ARTIFACT_EXTRAFIELDTYPE_CHECKBOX, ARTIFACT_EXTRAFIELDTYPE_MULTISELECT)));
@@ -58,6 +59,15 @@ define ("ARTIFACT_EXTRAFIELDTYPEGROUP_CHOICE", serialize (array_merge(unserializ
 define ("ARTIFACT_EXTRAFIELDTYPEGROUP_SPECALCHOICE", serialize(array(ARTIFACT_EXTRAFIELDTYPE_USER, ARTIFACT_EXTRAFIELDTYPE_RELEASE)));
 define ("ARTIFACT_EXTRAFIELDTYPEGROUP_VALUE", serialize (array (ARTIFACT_EXTRAFIELDTYPE_TEXT,ARTIFACT_EXTRAFIELDTYPE_TEXTAREA,ARTIFACT_EXTRAFIELDTYPE_RELATION,ARTIFACT_EXTRAFIELDTYPE_INTEGER,ARTIFACT_EXTRAFIELDTYPE_FORMULA,ARTIFACT_EXTRAFIELDTYPE_DATETIME, ARTIFACT_EXTRAFIELDTYPE_EFFORT)));
 
+define ("ARTIFACT_EXTRAFIELD_AGGREGATION_RULE_NO_AGGREGATION", 0);
+define ("ARTIFACT_EXTRAFIELD_AGGREGATION_RULE_SUM", 1);
+define ("ARTIFACT_EXTRAFIELD_AGGREGATION_RULE_STATUS_CLOSE_RESTRICTED", 2);
+define ("ARTIFACT_EXTRAFIELD_AGGREGATION_RULE_STATUS_CLOSE_UPWARDS", 3);
+
+define ("ARTIFACT_EXTRAFIELD_DISTRIBUTION_RULE_NO_DISTRIBUTION", 0);
+define ("ARTIFACT_EXTRAFIELD_DISTRIBUTION_RULE_STATUS_CLOSE_RECURSIVELY", 1);
+
+
 class ArtifactExtraField extends FFError {
 
 	/**
@@ -123,7 +133,7 @@ class ArtifactExtraField extends FFError {
 	 * @param	int	$disabled		True or false to enable/disable the extrafield
 	 * @return	bool	true on success / false on failure.
 	 */
-	function create($name, $field_type, $attribute1, $attribute2, $is_required = 0, $alias = '', $show100 = true, $show100label = 'none', $description = '', $pattern = '', $parent = 100, $autoassign = 0, $is_hidden_on_submit = 0, $is_disabled = 0) {
+	function create($name, $field_type, $attribute1, $attribute2, $is_required = 0, $alias = '', $show100 = true, $show100label = 'none', $description = '', $pattern = '', $parent = 100, $autoassign = 0, $is_hidden_on_submit = 0, $is_disabled = 0, $aggregation_rule = 0, $distribution_rule = 0) {
 		//
 		//	data validation
 		//
@@ -177,8 +187,8 @@ class ArtifactExtraField extends FFError {
 		}
 
 		db_begin();
-		$result = db_query_params ('INSERT INTO artifact_extra_field_list (group_artifact_id, field_name, field_type, attribute1, attribute2, is_required, alias, show100, show100label, description, pattern, parent, is_hidden_on_submit, is_disabled)
-			VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14)',
+		$result = db_query_params ('INSERT INTO artifact_extra_field_list (group_artifact_id, field_name, field_type, attribute1, attribute2, is_required, alias, show100, show100label, description, pattern, parent, is_hidden_on_submit, is_disabled, aggregation_rule, distribution_rule)
+			VALUES ($1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15,$16)',
 					   array ($this->ArtifactType->getID(),
 							  htmlspecialchars($name),
 							  $field_type,
@@ -192,7 +202,9 @@ class ArtifactExtraField extends FFError {
 							  $pattern,
 							  $parent,
 							  $is_hidden_on_submit,
-							  $is_disabled));
+							  $is_disabled,
+							  $aggregation_rule,
+							  $distribution_rule));
 
 		if ($result && db_affected_rows($result) > 0) {
 			$this->clearError();
@@ -760,7 +772,8 @@ class ArtifactExtraField extends FFError {
 			ARTIFACT_EXTRAFIELDTYPE_RELEASE => _('Release'),
 			ARTIFACT_EXTRAFIELDTYPE_EFFORT => _('Effort'),
 			ARTIFACT_EXTRAFIELDTYPE_FORMULA => _('Formula'),
-			ARTIFACT_EXTRAFIELDTYPE_SLA => _('SLA')
+			ARTIFACT_EXTRAFIELDTYPE_SLA => _('SLA'),
+			ARTIFACT_EXTRAFIELDTYPE_PARENT => _('Parent artifact')
 			);
 	}
 
@@ -896,7 +909,7 @@ class ArtifactExtraField extends FFError {
 	 * @param	int	$parent		Parent extra field id.
 	 * @return	bool	success.
 	 */
-	function update($name, $attribute1, $attribute2, $is_required = 0, $alias = "", $show100 = true, $show100label = 'none', $description = '', $pattern = '', $parent = 100, $autoassign = 0, $is_hidden_on_submit = 0, $is_disabled = 0) {
+	function update($name, $attribute1, $attribute2, $is_required = 0, $alias = "", $show100 = true, $show100label = 'none', $description = '', $pattern = '', $parent = 100, $autoassign = 0, $is_hidden_on_submit = 0, $is_disabled = 0, $aggregation_rule = 0, $distribution_rule = 0) {
 		if (!forge_check_perm ('tracker_admin', $this->ArtifactType->Group->getID())) {
 			$this->setPermissionDeniedError();
 			return false;
@@ -940,9 +953,11 @@ class ArtifactExtraField extends FFError {
 			pattern = $9,
 			parent = $10,
 			is_hidden_on_submit = $11,
-			is_disabled = $12
-			WHERE extra_field_id = $13
-			AND group_artifact_id = $14',
+			is_disabled = $12,
+			aggregation_rule = $13,
+			distribution_rule = $14
+			WHERE extra_field_id = $15
+			AND group_artifact_id = $16',
 					   array (htmlspecialchars($name),
 							  $description,
 							  $attribute1,
@@ -955,6 +970,8 @@ class ArtifactExtraField extends FFError {
 							  $parent,
 							  $is_hidden_on_submit,
 							  $is_disabled,
+							  $aggregation_rule,
+							  $distribution_rule,
 							  $this->getID(),
 							  $this->ArtifactType->getID())) ;
 		if ($result && db_affected_rows($result) > 0) {
@@ -1176,7 +1193,6 @@ class ArtifactExtraField extends FFError {
 	}
 
 	function alphaorderValues() {
-
 		$res = db_query_params ('SELECT element_id FROM artifact_extra_field_elements WHERE extra_field_id=$1 ORDER BY element_name ASC',
 			array($this->getID()));
 		$i = 1;
@@ -1185,11 +1201,11 @@ class ArtifactExtraField extends FFError {
 				return false;
 			$i++;
 		}
-
 		return true;
 	}
 
 	/**
+<<<<<<< 5c02d437ae2ab9d01370cc9aec4ecc46f3602746
 	 *    getMandatoryExtraFields - List of possible user built extra fields
 	 *    set up for this artifact type.
 	 *
@@ -1258,7 +1274,54 @@ class ArtifactExtraField extends FFError {
 
 		return $return;
 	}
+	
+	/**
+	 * getAvailableAggregationRules - the types of text fields and their names available.
+	 *
+	 * @return	array	rules.
+	 */
+	function getAvailableAggregationRules() {
+		$return= array(ARTIFACT_EXTRAFIELD_AGGREGATION_RULE_NO_AGGREGATION => _('Parent value is not depending on children\'s values'));
+		$type = $this->getType();
+		if ($type == ARTIFACT_EXTRAFIELDTYPE_EFFORT) {
+			$return = array_merge($return, array(ARTIFACT_EXTRAFIELD_AGGREGATION_RULE_SUM => _('Parent value is the sum of children\'s values')));
+		}
+		if ($type == ARTIFACT_EXTRAFIELDTYPE_STATUS) {
+			$return = array_merge($return, array(
+													ARTIFACT_EXTRAFIELD_AGGREGATION_RULE_STATUS_CLOSE_RESTRICTED => _('Deny closing the parent, as long as not all children have been closed'),
+													ARTIFACT_EXTRAFIELD_AGGREGATION_RULE_STATUS_CLOSE_UPWARDS => _('Close the parent, after the last child has been closed')
+								));
+		}
+		if (count($return)==1) {
+			$return = array();
+		}
+		return $return;
+	}
+
+	function getAggregationRule() {
+		return $this->data_array['aggregation_rule'];
+	}
 
+	/**
+	* getAvailableDistributionRules- the types of text fields and their names available.
+	*
+	* @return	array	rules.
+	*/
+	function getAvailableDistributionRules() {
+		$return= array(ARTIFACT_EXTRAFIELD_DISTRIBUTION_RULE_NO_DISTRIBUTION => _('Parent value is not depending on children\'s values'));
+		$type = $this->getType();
+		if ($type == ARTIFACT_EXTRAFIELDTYPE_STATUS) {
+			$return = array_merge($return, array(ARTIFACT_EXTRAFIELD_DISTRIBUTION_RULE_STATUS_CLOSE_RECURSIVELY => _('Closure of parent involves recursive closure of children')));
+		}
+		if (count($return)==1) {
+			$return = array();
+		}
+		return $return;
+	}
+
+	function getDistributionRule() {
+		return $this->data_array['distribution_rule'];
+	}
 }
 
 // Local Variables:
diff --git a/src/common/tracker/actions/admin-updates.php b/src/common/tracker/actions/admin-updates.php
index 8859b4d..d3eb823 100644
--- a/src/common/tracker/actions/admin-updates.php
+++ b/src/common/tracker/actions/admin-updates.php
@@ -249,6 +249,8 @@ if (getStringFromRequest('add_extrafield')) {
 	$is_disabled = getStringFromRequest('is_disabled');
 	$defaultArr = getArrayFromRequest('extra_fields', false);
 	$formula = getStringFromRequest('formula');
+	$aggregation_rule = getIntFromRequest('aggregation_rule',0);
+	$distribution_rule = getIntFromRequest('distribution_rule',0);
 	if (isset($defaultArr[$id])) {
 		$default = $defaultArr[$id];
 	} else {
@@ -266,7 +268,7 @@ if (getStringFromRequest('add_extrafield')) {
 		} else {
 			$show100 = 1;
 		}
-		if (!$ac->update($name, $attribute1, $attribute2, $is_required, $alias, $show100, $show100label, $description, $pattern, $parent, $autoassign, $is_hidden_on_submit, $is_disabled)) {
+		if (!$ac->update($name, $attribute1, $attribute2, $is_required, $alias, $show100, $show100label, $description, $pattern, $parent, $autoassign, $is_hidden_on_submit, $is_disabled, $aggregation_rule, $distribution_rule)) {
 			$error_msg .= _('Update failed')._(': ').$ac->getErrorMessage();
 			$ac->clearError();
 		} elseif (!$ac->setFormula($formula)){
diff --git a/src/common/tracker/actions/detail.php b/src/common/tracker/actions/detail.php
index 21aacdf..eec9623 100644
--- a/src/common/tracker/actions/detail.php
+++ b/src/common/tracker/actions/detail.php
@@ -141,20 +141,34 @@ foreach ($pluginsListeners as $pluginsListener) {
 		break;
 	}
 }
+$count=db_numrows($ah->getHistory());
+$nbh = $count? ' ('.$count.')' : '';
 ?>
 <div id="tabber">
 	<ul>
 	<li><a href="#tabber-comments"><?php echo _('Comments').$nb; ?></a></li>
-	<?php if ($group->usesPM()) { ?>
-	<li><a href="#tabber-tasks"><?php echo _('Related Tasks'); ?></a></li>
+	<?php if ($group->usesPM()) {
+		$count= db_numrows($ah->getRelatedTasks());
+		$nbrt = $count? ' ('.$count.')' : '';
+	?>
+	<li><a href="#tabber-tasks"><?php echo _('Related Tasks').$nbrt; ?></a></li>
 	<?php } ?>
 	<li><a href="#tabber-attachments"><?php echo _('Attachments').$nbf; ?></a></li>
 	<?php if ($pluginfound) { ?>
 	<li><a href="#tabber-commits"><?php echo _('Commits'); ?></a></li>
 	<?php } ?>
-	<li><a href="#tabber-changes"><?php echo _('Changes'); ?></a></li>
-	<?php if ($ah->hasRelations()) { ?>
-	<li><a href="#tabber-relations"><?php echo _('Relations'); ?></a></li>
+	<li><a href="#tabber-changes"><?php echo _('Changes').$nbh; ?></a></li>
+	<?php if ($ah->hasRelations()) {
+		$count=db_numrows($ah->getRelations());
+		$nbr = $count? ' ('.$count.')' : '';
+	?>
+	<li><a href="#tabber-relations"><?php echo _('Relations').$nbr; ?></a></li>
+	<?php } ?>
+	<?php if (forge_get_config('use_artefacts_dependencies')) {
+		$count=$ah->hasChildren();
+		$nbc = $count? ' ('.$count.')' : '';
+	?>
+	<li><a href="#tabber-children"><?php echo _('Children').$nbc; ?></a></li>
 	<?php } ?>
 	<?php if (forge_get_config('use_object_associations')) {
 		$anf = '';
@@ -232,7 +246,14 @@ if ($group->usesPM()) {
 	<div id="tabber-changes" class="tabbertab">
 		<?php echo $ah->showHistory(); ?>
 	</div>
-	<?php echo $ah->showRelations();
+	<div id="tabber-relations" class="tabbertab">
+	<?php echo $ah->showRelations(); ?>
+	</div><?php
+	if (forge_get_config('use_artefacts_dependencies')) { ?>
+		<div id="tabber-children" class="tabbertab">
+			<?php echo $ah->showChildren(); ?>
+		</div><?php
+	}
 	if (forge_get_config('use_object_associations')) { ?>
 	<div id="tabber-object-associations" class="tabbertab">
 	<?php if (forge_check_perm ('tracker',$ath->getID(),'submit')) {
diff --git a/src/common/tracker/actions/effort_units.php b/src/common/tracker/actions/effort_units.php
index 83da421..d6314a2 100644
--- a/src/common/tracker/actions/effort_units.php
+++ b/src/common/tracker/actions/effort_units.php
@@ -549,7 +549,6 @@ function postcopy_set(&$effortUnitSet) {
 function update_set(&$effortUnitSet) {
 	global $HTML;
 	$isAutoconvert = (getStringFromRequest('is_autoconvert')=='on'?1:0);
-	var_dump($isAutoconvert);
 	if (!$effortUnitSet->update($isAutoconvert)) {
 		echo $HTML->error_msg(_('Error updating Effort Unit Set')._(':').' '.$effortUnitSet->getErrorMessage());
 		return false;
diff --git a/src/common/tracker/actions/mod-limited.php b/src/common/tracker/actions/mod-limited.php
index 9fca9bd..7437b01 100644
--- a/src/common/tracker/actions/mod-limited.php
+++ b/src/common/tracker/actions/mod-limited.php
@@ -181,19 +181,33 @@ foreach ($pluginsListeners as $pluginsListener) {
 		break;
 	}
 }
+$count=db_numrows($ah->getHistory());
+$nbh = $count? ' ('.$count.')' : '';
 ?>
 	<ul>
 	<li><a href="#tabber-comments"><?php echo _('Comments').$nb; ?></a></li>
-	<?php if ($group->usesPM()) { ?>
-	<li><a href="#tabber-tasks"><?php echo _('Related Tasks'); ?></a></li>
+	<?php if ($group->usesPM()) {
+		$count= db_numrows($ah->getRelatedTasks());
+		$nbrt = $count? ' ('.$count.')' : '';
+	?>
+	<li><a href="#tabber-tasks"><?php echo _('Related Tasks').$nbrt; ?></a></li>
 	<?php } ?>
 	<li><a href="#tabber-attachments"><?php echo _('Attachments').$nbf; ?></a></li>
 	<?php if ($pluginfound) { ?>
 	<li><a href="#tabber-commits"><?php echo _('Commits'); ?></a></li>
 	<?php } ?>
-	<li><a href="#tabber-changes"><?php echo _('Changes'); ?></a></li>
-	<?php if ($ah->hasRelations()) { ?>
-	<li><a href="#tabber-relations"><?php echo _('Relations'); ?></a></li>
+	<li><a href="#tabber-changes"><?php echo _('Changes').$nbh; ?></a></li>
+	<?php if ($ah->hasRelations()) {
+		$count=db_numrows($ah->getRelations());
+		$nbr = $count? ' ('.$count.')' : '';
+	?>
+	<li><a href="#tabber-relations"><?php echo _('Relations').$nbr; ?></a></li>
+	<?php } ?>
+	<?php if (forge_get_config('use_artefacts_dependencies')) {
+		$count=$ah->hasChildren();
+		$nbc = $count? ' ('.$count.')' : '';
+	?>
+	<li><a href="#tabber-children"><?php echo _('Children').$nbc; ?></a></li>
 	<?php } ?>
 	<?php if (forge_get_config('use_object_associations')) {
 		$anf = '';
@@ -257,7 +271,14 @@ echo $ath->renderFiles($group_id, $ah);
 <div id="tabber-changes" class="tabbertab">
 	<?php echo $ah->showHistory(); ?>
 </div>
-<?php echo $ah->showRelations();
+<div id="tabber-relations" class="tabbertab">
+	<?php echo $ah->showRelations(); ?>
+</div><?php
+if (forge_get_config('use_artefacts_dependencies')) { ?>
+	<div id="tabber-children" class="tabbertab">
+		<?php echo $ah->showChildren(); ?>
+	</div><?php
+}
 if (forge_get_config('use_object_associations')) { ?>
 <div id="tabber-object-associations" class="tabbertab">
 	<?php if (forge_check_perm ('tracker',$ath->getID(),'submit')) {
diff --git a/src/common/tracker/actions/mod.php b/src/common/tracker/actions/mod.php
index 5f9e714..31e2ffd 100644
--- a/src/common/tracker/actions/mod.php
+++ b/src/common/tracker/actions/mod.php
@@ -238,22 +238,36 @@ foreach ($pluginsListeners as $pluginsListener) {
 		break;
 	}
 }
+$count=db_numrows($ah->getHistory());
+$nbh = $count? ' ('.$count.')' : '';
 ?>
 	<ul>
 	<li><a href="#tabber-comments"><?php echo _('Comments').$nb; ?></a></li>
-	<?php if ($group->usesPM()) { ?>
-	<li><a href="#tabber-tasks"><?php echo _('Related Tasks'); ?></a></li>
+	<?php if ($group->usesPM()) {
+		$count= db_numrows($ah->getRelatedTasks());
+		$nbrt = $count? ' ('.$count.')' : '';
+	?>
+	<li><a href="#tabber-tasks"><?php echo _('Related Tasks').$nbrt; ?></a></li>
 	<?php } ?>
 	<li><a href="#tabber-attachments"><?php echo _('Attachments').$nbf; ?></a></li>
 	<?php if ($pluginfound) { ?>
 	<li><a href="#tabber-commits"><?php echo _('Commits'); ?></a></li>
 	<?php } ?>
-	<li><a href="#tabber-changes"><?php echo _('Changes'); ?></a></li>
-	<?php if ($ah->hasRelations()) { ?>
-	<li><a href="#tabber-relations"><?php echo _('Relations'); ?></a></li>
+	<li><a href="#tabber-changes"><?php echo _('Changes').$nbh; ?></a></li>
+	<?php if ($ah->hasRelations()) {
+		$count=db_numrows($ah->getRelations());
+		$nbr = $count? ' ('.$count.')' : '';
+	?>
+	<li><a href="#tabber-relations"><?php echo _('Relations').$nbr; ?></a></li>
+	<?php } ?>
+	<?php if (forge_get_config('use_artefacts_dependencies')) {
+		$count=$ah->hasChildren();
+		$nbc = $count? ' ('.$count.')' : '';
+	?>
+	<li><a href="#tabber-children"><?php echo _('Children').$nbc; ?></a></li>
 	<?php } ?>
 	<?php if (forge_get_config('use_object_associations')) {
-			$anf = '';
+		$anf = '';
 		if ($ah->getAssociationCounter()) {
 			$anf = ' ('.$ah->getAssociationCounter().')';
 		} ?>
@@ -335,8 +349,15 @@ echo $ath->renderFiles($group_id, $ah);
 <div id="tabber-changes" class="tabbertab">
 	<?php echo $ah->showHistory(); ?>
 </div>
-	<?php echo $ah->showRelations();
-	if (forge_get_config('use_object_associations')) { ?>
+<div id="tabber-relations" class="tabbertab">
+	<?php echo $ah->showRelations(); ?>
+</div><?php
+if (forge_get_config('use_artefacts_dependencies')) { ?>
+	<div id="tabber-children" class="tabbertab">
+		<?php echo $ah->showChildren(); ?>
+	</div><?php
+}
+if (forge_get_config('use_object_associations')) { ?>
 	<div id="tabber-object-associations" class="tabbertab">
 	<?php if (forge_check_perm ('tracker',$ath->getID(),'submit')) {
 			echo $ah->showAssociations('/tracker/?func=removeassoc&aid='.$ah->getID().'&group_id='.$ath->Group->getID().'&atid='.$ath->getID());
diff --git a/src/common/tracker/include/ArtifactHtml.class.php b/src/common/tracker/include/ArtifactHtml.class.php
index 58b0cad..2f3bbfc 100644
--- a/src/common/tracker/include/ArtifactHtml.class.php
+++ b/src/common/tracker/include/ArtifactHtml.class.php
@@ -189,33 +189,51 @@ function hide_edit_button(id) {
 	}
 
 	function showRelations() {
-		$aid = $this->getID();
+		$result=$this->getRelations();
+		$rows= db_numrows($result);
 		$return = '';
+		if ($rows > 0){
+			$return = '<table class="fullwidth">
+							<tr>
+								<td colspan="2">';
+			$current = '';
+			$end = '';
+			while ($arr = db_fetch_array($result)) {
+				if (forge_check_perm('tracker', $arr['group_artifact_id'], 'read')) {
+					$title = $arr['group_name']._(': ').$arr['name'];
+					if ($title != $current) {
+						$return .= $end.'<strong>'.$title.'</strong>';
+						$current = $title;
+						$end = '<br /><br />';
+					}
+					$text = '[#'.$arr['artifact_id'].']';
+					$url = '/tracker/?func=detail&aid='.$arr['artifact_id'].'&group_id='.$arr['group_id'].'&atid='.$arr['group_artifact_id'];
+					$arg['title'] = util_html_secure($arr['summary']);
+					if ($arr['status_id'] == 2) {
+						$arg['class'] = 'artifact_closed';
+					}
+					$return .= '<br/>   ';
+					$return .= util_make_link($url, $text, $arg).' '.util_make_link($url, $arr['summary']).' <i>('._('Relation')._(': ').$arr['field_name'].')</i>';
+				}
+			}
+			$return .= '</td>
+				</tr>
+				</table>';
+		}
+		return $return;
+	}
 
-		// Search for all relations pointing to this record.
-
-		$res = db_query_params ('SELECT *
-		FROM artifact_extra_field_list, artifact_extra_field_data, artifact_group_list, artifact, groups
-		WHERE field_type=9
-		AND artifact_extra_field_list.extra_field_id=artifact_extra_field_data.extra_field_id
-		AND artifact_group_list.group_artifact_id = artifact_extra_field_list.group_artifact_id
-		AND artifact.artifact_id = artifact_extra_field_data.artifact_id
-		AND groups.group_id = artifact_group_list.group_id
-		AND (field_data = $1 OR field_data LIKE $2 OR field_data LIKE $3 OR field_data LIKE $4)
-		AND artifact.is_deleted = 0
-		ORDER BY artifact_group_list.group_id ASC, name ASC, artifact.artifact_id ASC',
-					array($aid,
-					      "$aid %",
-					      "% $aid %",
-					      "% $aid"));
-		if (db_numrows($res)>0) {
-			$return = '<div id="tabber-relations" class="tabbertab">
-					<table class="fullwidth">
-						<tr>
-							<td colspan="2">';
+	function showChildren() {
+		$result=$this->getChildren();
+		$rows= db_numrows($result);
+		$return = '';
+		if ($rows > 0){
+			$return = '	<table class="fullwidth">
+							<tr>
+								<td colspan="2">';
 			$current = '';
 			$end = '';
-			while ($arr = db_fetch_array($res)) {
+			while ($arr = db_fetch_array($result)) {
 				if (forge_check_perm('tracker', $arr['group_artifact_id'], 'read')) {
 					$title = $arr['group_name']._(': ').$arr['name'];
 					if ($title != $current) {
@@ -223,20 +241,19 @@ function hide_edit_button(id) {
 						$current = $title;
 						$end = '<br /><br />';
 					}
-					$text = '[#'.$arr['artifact_id'].']'.' '.$arr['summary'];
+					$text = '[#'.$arr['artifact_id'].']';
 					$url = '/tracker/?func=detail&aid='.$arr['artifact_id'].'&group_id='.$arr['group_id'].'&atid='.$arr['group_artifact_id'];
 					$arg['title'] = util_html_secure($arr['summary']);
 					if ($arr['status_id'] == 2) {
 						$arg['class'] = 'artifact_closed';
 					}
 					$return .= '<br/>   ';
-					$return .= util_make_link($url, $text, $arg).' <i>('._('Relation')._(': ').$arr['field_name'].')</i>';
+					$return .= util_make_link($url, $text, $arg).' '.util_make_link($url, $arr['summary']).' <i>('._('Parent')._(': ').$arr['field_name'].')</i>';
 				}
 			}
 			$return .= '</td>
 				</tr>
-				</table>
-				</div>';
+				</table>';
 		}
 		return $return;
 	}
diff --git a/src/common/tracker/include/ArtifactTypeHtml.class.php b/src/common/tracker/include/ArtifactTypeHtml.class.php
index 7d98202..db34f4c 100644
--- a/src/common/tracker/include/ArtifactTypeHtml.class.php
+++ b/src/common/tracker/include/ArtifactTypeHtml.class.php
@@ -199,6 +199,7 @@ class ArtifactTypeHtml extends ArtifactType {
                                $types = array(),
                                $status_show_100 = false,
                                $mode = '') {
+		global $HTML;
 		if ($mode == 'NEW') {
 			$efarr = $this->getExtraFields($types, false, false);
 		} else {
@@ -273,7 +274,7 @@ class ArtifactTypeHtml extends ArtifactType {
 						$type == ARTIFACT_EXTRAFIELDTYPE_TEXTAREA) {
 					$value = preg_replace('/((http|https|ftp):\/\/\S+)/',
 								"<a href=\"\\1\" target=\"_blank\">\\1</a>", $value);
-				} elseif ($type == ARTIFACT_EXTRAFIELDTYPE_RELATION) {
+				} elseif ($type == ARTIFACT_EXTRAFIELDTYPE_RELATION || $type == ARTIFACT_EXTRAFIELDTYPE_PARENT) {
 					// Convert artifact id to links.
 					$value = preg_replace_callback('/\b(\d+)\b/', create_function('$matches', 'return _artifactid2url($matches[1], \'title\');'), $value);
 				} elseif ($type == ARTIFACT_EXTRAFIELDTYPE_DATETIME && $value!='') {
@@ -399,10 +400,14 @@ class ArtifactTypeHtml extends ArtifactType {
 				$str = $this->renderSelect($efarr[$i]['extra_field_id'], $selected_node, $status_show_100, $text_100, $show_any, $text_any, $allowed, $attrs);
 
 			} elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_RELATION) {
-
 				$str = $this->renderRelationField($efarr[$i]['extra_field_id'], $selected[$efarr[$i]['extra_field_id']], $efarr[$i]['attribute1'], $efarr[$i]['attribute2'], $attrs);
 				if ($mode == 'UPDATE' || $mode == 'NEW') {
-					$post_name = html_image('ic/forum_edit.png', 37, 15 ,array('title'=>"Click to edit", 'alt'=>"Click to edit", 'onclick'=>"switch2edit(this, 'show$i', 'edit$i')"));
+					$post_name = $HTML->getEditFieldPic(_('Click to edit'), $alt = _('Click to edit'), array('onclick'=>"switch2edit(this, 'show$i', 'edit$i')"));
+				}
+			} elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_PARENT) {
+				$str = $this->renderParentField($efarr[$i]['extra_field_id'], $selected[$efarr[$i]['extra_field_id']], $efarr[$i]['attribute1'], $efarr[$i]['attribute2'], $attrs);
+				if ($mode == 'UPDATE' || $mode == 'NEW') {
+					$post_name = $HTML->getEditFieldPic(_('Click to edit'), $alt = _('Click to edit'), array('onclick'=>"switch2edit(this, 'show$i', 'edit$i')"));
 				}
 			} elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_DATETIME) {
 				$str = $this->renderDatetime($efarr[$i]['extra_field_id'], $selected[$efarr[$i]['extra_field_id']], $attrs);
@@ -601,6 +606,7 @@ class ArtifactTypeHtml extends ArtifactType {
 			} elseif ($efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_TEXT ||
 				$efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_INTEGER ||
 				$efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_RELATION ||
+				$efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_PARENT ||
 				$efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_DATETIME ||
 					$efarr[$i]['field_type'] == ARTIFACT_EXTRAFIELDTYPE_EFFORT) {
 
@@ -1115,6 +1121,7 @@ class ArtifactTypeHtml extends ArtifactType {
 			$keys[$i]=$arr[$i]['element_id'];
 			$vals[$i]=$arr[$i]['element_name'];
 		}
+		$attrs['pattern']='^\d+(\s+\d+)*$';
 		// Convert artifact id to links.
 		$html_contents = preg_replace_callback('/\b(\d+)\b/', create_function('$matches', 'return _artifactid2url($matches[1], \'title\');'), $contents);
 		$edit_contents = $this->renderTextField ($extra_field_id, $contents, $size, $maxlength);
@@ -1123,6 +1130,30 @@ class ArtifactTypeHtml extends ArtifactType {
 	}
 
 	/**
+	 * renderParentField - this function builds a parent field.
+	 *
+	 * @param	int	$extra_field_id	The ID of this field.
+	 * @param	string	$contents	The data for this field.
+	 * @param	string	$size
+	 * @param	string	$maxlength
+	 * @param	array	$attrs		Array of other attributes
+	 * @return	string	text area and data.
+	 */
+	function renderParentField($extra_field_id, $contents, $size, $maxlength, $attrs = array()) {
+		$arr = $this->getExtraFieldElements($extra_field_id);
+		for ($i=0; $i<count($arr); $i++) {
+			$keys[$i]=$arr[$i]['element_id'];
+			$vals[$i]=$arr[$i]['element_name'];
+		}
+		$attrs['pattern']='^\d*$';
+		// Convert artifact id to links.
+		$html_contents = preg_replace_callback('/\b(\d+)\b/', create_function('$matches', 'return _artifactid2url($matches[1], \'title\');'), $contents);
+		$edit_contents = $this->renderTextField ($extra_field_id, $contents, $size, $maxlength);
+		return html_e('div',array_merge(array('id'=>'edit'.$extra_field_id, 'style'=>'display: none', 'title'=>_('Tip: Enter a space-separated list of artifact ids ([#NNN] also accepted)')), $attrs), $edit_contents)
+		.html_e('div',array_merge(array('id'=>'show'.$extra_field_id, 'style'=>'display: block'), $attrs), $html_contents);
+	}
+
+	/**
 	 * renderTextArea - this function builds a text area.
 	 *
 	 * @param	int	$extra_field_id	The ID of this field.
@@ -1548,6 +1579,7 @@ EOS;
 			data: 'rtype=ajax&function=get_formulas_results&group_id='+groupId+'&atid='+atId+'&status='+$("select[name='status_id'] option:selected").text()+'&assigned_to='+$("select[name='assigned_to'] option:selected").text()+'&'+$("[name^='extra_fields'], #tracker-summary, #tracker-description, [name='priority']").serialize(),
 			async: false,
 			dataType: 'json',
+			contentType:"application/json; charset=utf-8",
 			success: function(answer){
 				if(answer['message']) {
 					showMessage(answer['message'], 'error');
diff --git a/src/common/tracker/views/form-addextrafield.php b/src/common/tracker/views/form-addextrafield.php
index a9f454c..250a70a 100644
--- a/src/common/tracker/views/form-addextrafield.php
+++ b/src/common/tracker/views/form-addextrafield.php
@@ -221,7 +221,8 @@ $jsvariable ="
 	var typeDateTime = ".ARTIFACT_EXTRAFIELDTYPE_DATETIME.";
 	var typeUser = ".ARTIFACT_EXTRAFIELDTYPE_USER.";
 	var typeRelease = ".ARTIFACT_EXTRAFIELDTYPE_RELEASE.";
-	var typeEffort = ".ARTIFACT_EXTRAFIELDTYPE_EFFORT.";";
+	var typeEffort = ".ARTIFACT_EXTRAFIELDTYPE_EFFORT.";
+	var typeParent = ".ARTIFACT_EXTRAFIELDTYPE_PARENT.";";
 
 $javascript = <<<'EOS'
 	$("p[class^='for-']").hide();
@@ -294,6 +295,12 @@ $javascript = <<<'EOS'
 		$("p.for-effort").show();
 		$("p[class^='for-']:not(.for-effort)").hide();
 	});
+	$("input[value="+typeParent+"]").on('change', function(){
+		$("label[for='attribute1']").text(size);
+		$("label[for='attribute2']").text(maxLength);
+		$("p.for-parent").show();
+		$("p[class^='for-']:not(.for-parent)").hide();
+	});
 
 EOS;
 echo html_e('script', array( 'type'=>'text/javascript'), '//<![CDATA['."\n".'$(function(){'.$jsvariable."\n".$javascript.'});'."\n".'//]]>');
@@ -303,12 +310,17 @@ echo html_e('strong', array(), _('Type of custom field').utils_requiredField()._
 if ($ath->usesCustomStatuses()) {
 	unset($eftypes[ARTIFACT_EXTRAFIELDTYPE_STATUS]);
 }
+
+if (!forge_get_config('use_artefacts_dependencies')) {
+	unset($eftypes[ARTIFACT_EXTRAFIELDTYPE_PARENT]);
+}
+
 $vals = array_keys($eftypes);
 $texts = array_values($eftypes);
 echo html_build_radio_buttons_from_arrays($vals, $texts, 'field_type', '', false, '', false ,'', false, array('required'=>'required') );
 echo html_ac(html_ap() - 1);
 
-echo html_ao('p', array('class'=>'for-text for-textarea for-integer for-relation for-effort'));
+echo html_ao('p', array('class'=>'for-text for-textarea for-integer for-relation for-effort for-parent'));
 echo html_e('label', array('for'=>'attribute1'), _('Size')._(':'));
 echo html_e('input', array('type'=>'text', 'name'=>'attribute1', 'value'=>'20', 'size'=>'2', 'maxlength'=>'2')).html_e('br');
 echo html_e('label', array('for'=>'attribute2'), _('Maxlength')._(':'));
diff --git a/src/common/tracker/views/form-editformula.php b/src/common/tracker/views/form-editformula.php
index 38cd5ae..6001baf 100644
--- a/src/common/tracker/views/form-editformula.php
+++ b/src/common/tracker/views/form-editformula.php
@@ -27,9 +27,6 @@ global $HTML;
 
 html_use_tablesorter();
 
-$title = sprintf(_('Manage Custom Fields for %s'), $ath->getName());
-$ath->adminHeader(array('title'=>$title, 'modal'=>1));
-
 $boxid = getIntFromRequest('boxid');
 if ($boxid) {
 	$ef_id = $boxid;
@@ -46,6 +43,9 @@ if (!$ac || !is_object($ac)) {
 	exit_error($ac->getErrorMessage());
 }
 
+$title = sprintf(_('Edit formula for %s'), $ath->getName());
+$ath->adminHeader(array('title'=>$title, 'modal'=>1));
+
 if (!$efe_id) {
 	$formula = $ac->getFormula();
 } else {
@@ -57,7 +57,6 @@ if (!$efe_id) {
 	}
 	$formula = $ao->getFormula();
 }
-
 $efarr = $ath->getExtraFields(array(),false,true);
 $efarr [] = array('field_name'=>'Assigned to','alias'=>'assigned_to', 'field_type'=>ARTIFACT_EXTRAFIELDTYPE_USER,'extra_field_id'=>0);
 $efarr [] = array('field_name'=>'Priority','alias'=>'priority', 'field_type'=>ARTIFACT_EXTRAFIELDTYPE_SELECT, 'extra_field_id'=>0);
@@ -252,7 +251,7 @@ $("textarea#formula").keydown(function(e) {
 EOS;
 echo html_e('script', array('type'=>'text/javascript'), '//<![CDATA['."\n".'$(function(){'.$javascript.'});'."\n".'//]]>');
 
-echo html_e('h2', array(), _('Edit formula'));
+echo html_e('h2', array(), _('Formula'));
 
 if (!$efe_id) {
 	echo $HTML->openForm(array('action' => '/tracker/admin/?group_id='.$group_id.'&id='.$ef_id.'&atid='.$ath->getID(), 'method' => 'post'));
diff --git a/src/common/tracker/views/form-updateextrafield.php b/src/common/tracker/views/form-updateextrafield.php
index 2f2e05c..16e65ee 100644
--- a/src/common/tracker/views/form-updateextrafield.php
+++ b/src/common/tracker/views/form-updateextrafield.php
@@ -209,6 +209,21 @@ if (!$ac || !is_object($ac)) {
 		echo html_e('input', array('type'=>'hidden', 'name'=>'formula', 'value'=>''));
 	}
 
+	$aggregationRules = $ac->getAvailableAggregationRules();
+	if (!empty($aggregationRules)) {
+		echo html_ao('p');
+		echo html_e('label', array('for'=>'aggregation_rule'), _('Dependency of parents on children'));
+		echo html_build_select_box_from_arrays(array_keys($aggregationRules), array_values($aggregationRules), 'aggregation_rule', $ac->getAggregationRule(), false).html_e('br');
+		echo html_ac(html_ap() - 1);
+	}
+	$distributionRules = $ac->getAvailableDistributionRules();
+	if (!empty($distributionRules)) {
+		echo html_ao('p');
+		echo html_e('label', array('for'=>'distribution_rule'), _('Dependency of children on parents'));
+		echo html_build_select_box_from_arrays(array_keys($distributionRules), array_values($distributionRules), 'distribution_rule', $ac->getDistributionRule(), false).html_e('br');
+		echo html_ac(html_ap() - 1);
+	}
+
 	echo $HTML->warning_msg(_('It is not recommended that you change the custom field name because other things are dependent upon it. When you change the custom field name, all related items will be changed to the new name.'));
 
 	echo html_ao('p');
diff --git a/src/common/widget/Widget_TrackerComment.class.php b/src/common/widget/Widget_TrackerComment.class.php
index db51547..3aa56d5 100644
--- a/src/common/widget/Widget_TrackerComment.class.php
+++ b/src/common/widget/Widget_TrackerComment.class.php
@@ -67,7 +67,9 @@ class Widget_TrackerComment extends Widget {
 		if ($func == 'detail') {
 			$elementsLi[] = array('content' => util_make_link('#tabber-comments', _('Comments').$nb, false, true));
 			if ($group->usesPM()) {
-				$elementsLi[] = array('content' => util_make_link('#tabber-tasks', _('Related Tasks'), false, true));
+				$count= db_numrows($ah->getRelatedTasks());
+				$nbrt = $count? ' ('.$count.')' : '';
+				$elementsLi[] = array('content' => util_make_link('#tabber-tasks', _('Related Tasks').$nbrt, false, true));
 			}
 		}
 		$elementsLi[] = array('content' => util_make_link('#tabber-attachments', _('Attachments').$nbf, false, true));
@@ -85,9 +87,21 @@ class Widget_TrackerComment extends Widget {
 			if ($pluginfound) {
 				$elementsLi[] = array('content' => util_make_link('#tabber-commits', _('Commits'), false, true));
 			}
-			$elementsLi[] = array('content' => util_make_link('#tabber-changes', _('Changes'), false, true));
+			$count=db_numrows($ah->getHistory());
+			$nbh = $count? ' ('.$count.')' : '';
+			$elementsLi[] = array('content' => util_make_link('#tabber-changes', _('Changes').$nbh, false, true));
 			if ($ah->hasRelations()) {
-				$elementsLi[] = array('content' => util_make_link('#tabber-relations', _('Relations'), false, true));
+				$count=db_numrows($ah->getRelations());
+				$nbr = $count? ' ('.$count.')' : '';
+				$elementsLi[] = array('content' => util_make_link('#tabber-relations', _('Relations').$nbr, false, true));
+			}
+			if (forge_get_config('use_artefacts_dependencies')) {
+				$tabTitle = _('Children');
+				$nbChildren = $ah->hasChildren();
+				if ($nbChildren) {
+					$tabTitle .= ' ('.$nbChildren.')';
+				}
+				$elementsLi[] = array('content' => util_make_link('#tabber-children', $tabTitle, false, true));
 			}
 			if (forge_get_config('use_object_associations')) {
 				$tabTitle = _('Associations');
@@ -153,7 +167,12 @@ class Widget_TrackerComment extends Widget {
 		if ($func == 'detail') {
 			$tabberContent .= html_e('div', array('id' => 'tabber-changes', 'class' => 'tabbertab'),
 						$ah->showHistory());
-			$tabberContent .= $ah->showRelations();
+			$tabberContent .= html_e('div', array('id' => 'tabber-relations', 'class' => 'tabbertab'),
+						$ah->showRelations());
+			if (forge_get_config('use_artefacts_dependencies')) {
+				$tabberContent .= html_e('div', array('id' => 'tabber-children', 'class' => 'tabbertab'),
+						$ah->showChildren());
+			}
 			if (forge_get_config('use_object_associations')) {
 				$associationContent = $ah->showAssociations('/tracker/?func=removeassoc&aid='.$ah->getID().'&group_id='.$group_id.'&atid='.$ath->getID());
 				if (forge_check_perm('tracker', $atid, 'tech')) {
diff --git a/src/db/20170502-tracker-parent-artifact.sql b/src/db/20170502-tracker-parent-artifact.sql
new file mode 100644
index 0000000..96e327c
--- /dev/null
+++ b/src/db/20170502-tracker-parent-artifact.sql
@@ -0,0 +1,3 @@
+ALTER TABLE artifact_extra_field_list
+   ADD COLUMN aggregation_rule integer NOT NULL DEFAULT 0,
+   ADD COLUMN distribution_rule integer NOT NULL DEFAULT 0;
\ No newline at end of file
diff --git a/src/www/include/Layout.class.php b/src/www/include/Layout.class.php
index 694d86d..45b5e3d 100644
--- a/src/www/include/Layout.class.php
+++ b/src/www/include/Layout.class.php
@@ -1013,6 +1013,10 @@ abstract class Layout extends FFError {
 		return $this->getPicto('ic/edit-file.png', $title, $alt, 20, 20, $otherAttr);
 	}
 
+	function getEditFieldPic($title = '', $alt = '', $otherAttr = array()) {
+		return $this->getPicto('ic/forum_edit.png', $title, $alt, 20, 20, $otherAttr);
+	}
+
 	function getNewPic($title = '', $alt = '', $otherAttr = array()) {
 		return $this->getPicto('ic/add.png', $title, $alt, 20, 20, $otherAttr);
 	}
diff --git a/src/www/themes/funky-wOw/css/theme.css b/src/www/themes/funky-wOw/css/theme.css
index 48778d2..f1ae5ff 100644
--- a/src/www/themes/funky-wOw/css/theme.css
+++ b/src/www/themes/funky-wOw/css/theme.css
@@ -131,3 +131,6 @@ input, select {
 	vertical-align: middle;
 }
 
+.artifact_closed, .artifact_closed:hover {
+	text-decoration:line-through;
+}
\ No newline at end of file
diff --git a/src/www/themes/funky/css/theme.css b/src/www/themes/funky/css/theme.css
index a7de379..89bda99 100644
--- a/src/www/themes/funky/css/theme.css
+++ b/src/www/themes/funky/css/theme.css
@@ -800,3 +800,7 @@ footer img {
 input, select {
 	vertical-align: middle;
 }
+
+.artifact_closed, .artifact_closed:hover {
+	text-decoration:line-through;
+}
\ No newline at end of file

-----------------------------------------------------------------------

Summary of changes:
 src/common/tracker/Artifact.class.php              | 94 ++++++++++++++++++++--
 src/common/tracker/ArtifactExtraField.class.php    | 85 ++++++++++++++++---
 src/common/tracker/actions/admin-updates.php       |  4 +-
 src/common/tracker/actions/detail.php              | 33 ++++++--
 src/common/tracker/actions/effort_units.php        |  1 -
 src/common/tracker/actions/mod-limited.php         | 33 ++++++--
 src/common/tracker/actions/mod.php                 | 37 +++++++--
 src/common/tracker/include/ArtifactHtml.class.php  | 71 +++++++++-------
 .../tracker/include/ArtifactTypeHtml.class.php     | 38 ++++++++-
 src/common/tracker/views/form-addextrafield.php    | 16 +++-
 src/common/tracker/views/form-editformula.php      |  9 +--
 src/common/tracker/views/form-updateextrafield.php | 15 ++++
 src/common/widget/Widget_TrackerComment.class.php  | 27 ++++++-
 src/db/20170502-tracker-parent-artifact.sql        |  3 +
 src/www/include/Layout.class.php                   |  4 +
 src/www/themes/funky-wOw/css/theme.css             |  3 +
 src/www/themes/funky/css/theme.css                 |  4 +
 17 files changed, 397 insertions(+), 80 deletions(-)
 create mode 100644 src/db/20170502-tracker-parent-artifact.sql


hooks/post-receive
-- 
FusionForge



More information about the Fusionforge-commits mailing list