Skip to content

Commit

Permalink
Allow multiple, customizable due date levels
Browse files Browse the repository at this point in the history
New config option defining due date levels allowing administrators to
customize both the number of levels, and the cutover deadlines. CSS can
be used to define the colors.

Fixes #26438, #9155, #16869
PR #1589
  • Loading branch information
dregad committed Feb 2, 2020
2 parents a91e7e1 + a143f38 commit 1aa2adf
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 30 deletions.
7 changes: 4 additions & 3 deletions bug_update_page.php
Expand Up @@ -319,10 +319,11 @@
# Due Date
echo '<th class="category"><label for="due_date">' . lang_get( 'due_date' ) . '</label></th>';

if( bug_is_overdue( $t_bug_id ) ) {
echo '<td class="overdue">';
} else {
$t_level = bug_overdue_level( $t_bug_id );
if( $t_level === false ) {
echo '<td>';
} else {
echo '<td class="due-', $t_level, '">';
}

if( access_has_bug_level( config_get( 'due_date_update_threshold' ), $t_bug_id ) ) {
Expand Down
8 changes: 4 additions & 4 deletions bug_view_inc.php
Expand Up @@ -292,11 +292,11 @@
if( $t_flags['due_date_show'] ) {
echo '<th class="bug-due-date category">', lang_get( 'due_date' ), '</th>';

if( $t_issue_view['overdue'] ) {
echo '<td class="bug-due-date overdue">', $t_issue_view['due_date'], '</td>';
} else {
echo '<td class="bug-due-date">', $t_issue_view['due_date'], '</td>';
$t_css = 'bug-due-date';
if( $t_issue_view['overdue'] !== false ) {
$t_css .= ' due-' . $t_issue_view['overdue'];
}
echo '<td class="' . $t_css . '">', $t_issue_view['due_date'], '</td>';
} else {
$t_spacer += 2;
}
Expand Down
28 changes: 28 additions & 0 deletions config_defaults_inc.php
Expand Up @@ -4165,6 +4165,33 @@
*/
$g_due_date_default = '';

/**
* Due date warning levels.
*
* A variable number of Levels (defined as a number of seconds going backwards
* from the current timestamp, compared to an issue's due date) can be defined.
* Levels must be defined in ascending order.
*
* - The first entry (array key 0) defines "Overdue". Normally and by default,
* its value is `0` meaning that issues will be marked overdue as soon as
* their due date has passed. However, it is also possible to set it to a
* higher value to flag overdue issues earlier, or even use a negative value
* to allow a "grace period" after due date.
* - Array keys 1 and 2 offer two levels of "Due soon": orange and green.
* By default, only the first one is set, to 7 days.
*
* Out of the box, MantisBT allows for 3 warning levels. Additional ones may
* be defined, but in that case new `due-N` CSS rules (where N is the
* array's index) must be created otherwise the extra levels will not be
* highlighted in the UI.
*
* @global array $g_due_date_warning_levels
*/
$g_due_date_warning_levels = array(
0,
7 * SECONDS_PER_DAY,
);

################
# Sub-projects #
################
Expand Down Expand Up @@ -4504,6 +4531,7 @@
'due_date_default',
'due_date_update_threshold',
'due_date_view_threshold',
'due_date_warning_levels',
'email_ensure_unique',
'email_dkim_domain',
'email_dkim_enable',
Expand Down
47 changes: 37 additions & 10 deletions core/bug_api.php
Expand Up @@ -1129,6 +1129,42 @@ function bug_is_closed( $p_bug_id ) {
return( $t_bug->status >= config_get( 'bug_closed_status_threshold', null, null, $t_bug->project_id ) );
}

/**
* Return a bug's overdue warning level.
* Determines the level based on the difference between the bug's due date
* and the current date/time, based on the defined delays
* @see $g_due_date_warning_levels
*
* @param $p_bug_id
*
* @return int|false Warning level (0 = overdue), false if N/A.
*/
function bug_overdue_level( $p_bug_id ) {
if( bug_is_resolved( $p_bug_id ) ) {
return false;
}

$t_bug = bug_get( $p_bug_id );
$t_due_date = $t_bug->due_date;

if( date_is_null( $t_due_date ) ) {
return false;
}

$t_warning_levels = config_get( 'due_date_warning_levels', null, null, $t_bug->project_id );
if( !empty( $t_warning_levels ) && !is_array( $t_warning_levels ) ) {
trigger_error( ERROR_GENERIC );
}

$t_now = db_now();
foreach( $t_warning_levels as $t_level => $t_delay ) {
if( $t_now > $t_due_date - $t_delay ) {
return $t_level;
}
}
return false;
}

/**
* Check if a given bug is overdue
* @param integer $p_bug_id Integer representing bug identifier.
Expand All @@ -1137,16 +1173,7 @@ function bug_is_closed( $p_bug_id ) {
* @uses database_api.php
*/
function bug_is_overdue( $p_bug_id ) {
$t_due_date = bug_get_field( $p_bug_id, 'due_date' );
if( !date_is_null( $t_due_date ) ) {
$t_now = db_now();
if( $t_now > $t_due_date ) {
if( !bug_is_resolved( $p_bug_id ) ) {
return true;
}
}
}
return false;
return bug_overdue_level( $p_bug_id ) === 0;
}

/**
Expand Down
36 changes: 26 additions & 10 deletions core/columns_api.php
Expand Up @@ -1634,20 +1634,17 @@ function print_column_tags( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_V
* @access public
*/
function print_column_due_date( BugData $p_bug, $p_columns_target = COLUMNS_TARGET_VIEW_PAGE ) {
$t_overdue = '';

if( !access_has_bug_level( config_get( 'due_date_view_threshold' ), $p_bug->id ) ||
date_is_null( $p_bug->due_date )
) {
$t_css = '';
$t_value = '&#160;';
} else {
if( bug_is_overdue( $p_bug->id ) ) {
$t_overdue = ' overdue';
}
$t_css = " due-" . bug_overdue_level( $p_bug->id );
$t_value = string_display_line( date( config_get( 'short_date_format' ), $p_bug->due_date ) );
}

printf( '<td class="column-due-date%s">%s</td>', $t_overdue, $t_value );
printf( '<td class="column-due-date%s">%s</td>', $t_css, $t_value );
}

/**
Expand All @@ -1663,10 +1660,29 @@ function print_column_overdue( BugData $p_bug, $p_columns_target = COLUMNS_TARGE
echo '<td class="column-overdue">';

if( access_has_bug_level( config_get( 'due_date_view_threshold' ), $p_bug->id ) &&
!date_is_null( $p_bug->due_date ) &&
bug_is_overdue( $p_bug->id ) ) {
$t_overdue_text_hover = sprintf( lang_get( 'overdue_since' ), date( config_get( 'short_date_format' ), $p_bug->due_date ) );
echo '<i class="fa fa-times-circle-o" title="' . string_display_line( $t_overdue_text_hover ) . '"></i>';
!date_is_null( $p_bug->due_date )
) {
$t_level = bug_overdue_level( $p_bug->id );
if( $t_level === 0 ) {
$t_icon = 'fa-times-circle-o';
$t_overdue_text_hover = sprintf(
lang_get( 'overdue_since' ),
date( config_get( 'short_date_format' ), $p_bug->due_date )
);
} else {
$t_icon = $t_level === false ? 'fa-info-circle' : 'fa-warning';

$t_duration = $p_bug->due_date - db_now();
if( $t_duration <= SECONDS_PER_DAY ) {
$t_overdue_text_hover = lang_get( 'overdue_one_day' );
} else {
$t_overdue_text_hover = sprintf(
lang_get( 'overdue_days' ),
ceil( $t_duration / SECONDS_PER_DAY )
);
}
}
echo '<i class="fa ' . $t_icon . '" title="' . string_display_line( $t_overdue_text_hover ) . '"></i>';
} else {
echo '&#160;';
}
Expand Down
2 changes: 1 addition & 1 deletion core/commands/IssueViewPageCommand.php
Expand Up @@ -182,7 +182,7 @@ protected function process() {
# Due date
$t_flags['due_date_show'] = in_array( 'due_date', $t_fields ) && access_has_bug_level( config_get( 'due_date_view_threshold' ), $t_issue_id );
if( $t_flags['due_date_show'] ) {
$t_issue_view['overdue'] = bug_is_overdue( $t_issue_id );
$t_issue_view['overdue'] = bug_overdue_level( $t_issue_id );

if( isset( $t_issue['due_date'] ) ) {
$t_issue_view['due_date'] = date( config_get( 'normal_date_format' ), strtotime( $t_issue['due_date'] ) );
Expand Down
6 changes: 4 additions & 2 deletions css/default.css
Expand Up @@ -92,8 +92,10 @@ tr.bugnote .bugnote-note { background-color: #e8e8e8; color: #000000; width: 75%
.color-global { background-color: LightBlue; }
.color-project { background-color: LightGreen; }

td.overdue { background-color: #d15b47; color: #ffffff; font-weight: bold; }
td.print-overdue { font-weight: bold; }
td.due-0, td.overdue { background-color: red; color: #ffffff; font-weight: bold; }
td.due-1 { background-color: darkorange; color: #ffffff; font-weight: bold; }
td.due-2 { background-color: green; color: #ffffff; font-weight: bold; }
td.print-overdue { font-weight: bold; }

.collapse-link { cursor: pointer; }

Expand Down
34 changes: 34 additions & 0 deletions docbook/Admin_Guide/en-US/config/duedate.xml
Expand Up @@ -13,13 +13,15 @@
</para>
</listitem>
</varlistentry>

<varlistentry>
<term>$g_due_date_view_threshold</term>
<listitem>
<para>Threshold to see due date. Default is NOBODY.
</para>
</listitem>
</varlistentry>

<varlistentry>
<term>$g_due_date_default</term>
<listitem>
Expand All @@ -30,5 +32,37 @@
</para>
</listitem>
</varlistentry>

<varlistentry>
<term>$g_due_date_warning_levels</term>
<listitem>
<para>Due date warning levels. A variable number of Levels
(defined as a number of seconds going backwards
from the current timestamp, compared to an issue's due date) can be defined.
Levels must be defined in ascending order.
<itemizedlist>
<listitem>
<para>The first entry (array key 0) defines <emphasis>Overdue</emphasis>.
Normally and by default, its value is <literal>0</literal>, meaning
that issues will be marked overdue as soon as
their due date has passed. However, it is also possible to set it to a
higher value to flag overdue issues earlier, or even use a negative value
to allow a "grace period" after due date.
</para>
</listitem>
<listitem>
<para>Array keys 1 and 2 offer two levels of <emphasis>Due soon</emphasis>:
orange and green.
By default, only the first one is set, to 7 days.
</para>
</listitem>
</itemizedlist>
Out of the box, MantisBT allows for 3 warning levels. Additional ones may
be defined, but in that case new <literal>due-N</literal> CSS rules
(where N is the array's index) must be created otherwise the extra levels
will not be highlighted in the UI.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
2 changes: 2 additions & 0 deletions lang/strings_english.txt
Expand Up @@ -1585,6 +1585,8 @@ $s_copy_columns_to = 'Copy Columns To';
$s_due_date = 'Due Date';
$s_overdue = 'Overdue';
$s_overdue_since = 'Overdue since %1$s';
$s_overdue_one_day = 'Overdue in less than a day';
$s_overdue_days = 'Overdue in %1$d days';

#account_view_page.php
$s_view_account_title = 'User Information';
Expand Down

0 comments on commit 1aa2adf

Please sign in to comment.