View Issue Details
ID | Project | Category | View Status | Date Submitted | Last Update |
---|---|---|---|---|---|
0007840 | mantisbt | customization | public | 2007-03-19 08:02 | 2020-07-28 03:21 |
Reporter | stefanvandenoord | Assigned To | |||
Priority | normal | Severity | feature | Reproducibility | N/A |
Status | acknowledged | Resolution | open | ||
Summary | 0007840: Customizable 'my view' page | ||||
Description | I think it would be great if the 'my view' page was customizable. For example, the user preferences could include a checkbox for each standard 'my view' block, as well as each filter available to the user. The user could then also have the results of certain filters available on the 'my view' page, and could hide standard blocks that she doesn't need. | ||||
Tags | No tags attached. | ||||
Attached Files | customMyView.diff (70,617 bytes)
? account_my_view_add.php ? account_my_view_delete.php ? account_my_view_page.php ? account_my_view_sequence.php Index: config_defaults_inc.php =================================================================== RCS file: /cvsroot/mantisbt/mantisbt/config_defaults_inc.php,v retrieving revision 1.365 diff -u -r1.365 config_defaults_inc.php --- config_defaults_inc.php 4 Oct 2007 05:59:04 -0000 1.365 +++ config_defaults_inc.php 23 Oct 2007 17:39:02 -0000 @@ -195,7 +195,7 @@ # the sender email, part of 'From: ' header in emails $g_from_email = 'noreply@example.com'; - + # the sender name, part of 'From: ' header in emails $g_from_name = 'Mantis Bug Tracker'; @@ -296,8 +296,8 @@ $g_phpMailer_method = 0; # This option allows you to use a remote SMTP host. Must use the phpMailer script - # One or more hosts, separated by a semicolon, can be listed. - # You can also specify a different port for each host by using this + # One or more hosts, separated by a semicolon, can be listed. + # You can also specify a different port for each host by using this # format: [hostname:port] (e.g. "smtp1.example.com:25;smtp2.example.com"). # Hosts will be tried in order. $g_smtp_host = 'localhost'; @@ -308,7 +308,7 @@ $g_smtp_username = ''; $g_smtp_password = ''; - # It is recommended to use a cronjob or a scheduler task to send emails. + # It is recommended to use a cronjob or a scheduler task to send emails. # The cronjob should typically run every 5 minutes. If no cronjob is used, # then user will have to wait for emails to be sent after performing an action # which triggers notifications. This slows user performance. @@ -477,7 +477,7 @@ # resolution, fixed_in_version, view_state, os, os_build, platform, version, date_submitted, attachment, # category, sponsorship_total, severity, status, last_updated, summary, bugnotes_count $g_view_issues_page_columns = array ( 'selection', 'edit', 'priority', 'id', 'sponsorship_total', 'bugnotes_count', 'attachment', 'category', 'severity', 'status', 'last_updated', 'summary' ); - + # A configuration option that identifies the columns to be show on the print issues page. # In Mantis 1.1, this option can be overriden using the Generic Configuration screen. # This configuration can be overriden dynamically by overriding the custom function "get_columns_to_view". @@ -519,12 +519,12 @@ # Show user avatar # the current implementation is based on http://www.gravatar.com - # users will need to register there the same address used in + # users will need to register there the same address used in # this mantis installation to have their avatar shown # Please note: upon registration or avatar change, it takes some time for # the updated gravatar images to show on sites $g_show_avatar = OFF; - + # Only users above this threshold will have their avatar shown $g_show_avatar_threshold = DEVELOPER; @@ -560,11 +560,11 @@ # how many graphs to put in each row in the advanced summary page $g_graph_summary_graphs_per_row = 2; - + # initial graph type selected on bug_graph_page (see that page for possible values) # 0 asks user to select $g_default_graph_type = 0; - + # graph colours, once the list is exhausted it will repeat $g_graph_colors = array('coral', 'red', 'blue', 'black', 'green', 'orange', 'pink', 'brown', 'gray', 'blueviolet','chartreuse','fuschia','indigo'); @@ -646,7 +646,7 @@ # Default bug priority when reporting a new bug $g_default_bug_priority = NORMAL; - + # Default bug reproducibility when reporting a new bug $g_default_bug_reproducibility = REPRODUCIBILITY_HAVENOTTRIED; @@ -793,7 +793,7 @@ # DISK, DATABASE, or FTP. $g_file_upload_method = DATABASE; - # When using FTP or DISK for storing uploaded files, this setting control + # When using FTP or DISK for storing uploaded files, this setting control # the access permissions they will have on the web server: with the default # value (0400) files will be read-only, and accessible only by the user # running the apache process (probably "apache" in Linux and "Administrator" @@ -877,7 +877,7 @@ $g_ldap_bind_dn = ''; $g_ldap_bind_passwd = ''; $g_use_ldap_email = OFF; # Should we send to the LDAP email address or what MySql tells us - + # The LDAP Protocol Version, if 0, then the protocol version is not set. $g_ldap_protocol_version = 0; @@ -1114,10 +1114,10 @@ # threshold for viewing roadmap $g_roadmap_view_threshold = VIEWER; - + # threshold for updating roadmap, target_version, etc $g_roadmap_update_threshold = DEVELOPER; - + # status change thresholds $g_update_bug_status_threshold = DEVELOPER; @@ -1126,7 +1126,7 @@ # access level needed to set a bug sticky $g_set_bug_sticky_threshold = MANAGER; - + # The minimum access level for someone to be a member of the development team # and appear on the project information page. $g_development_team_threshold = DEVELOPER; @@ -1314,7 +1314,7 @@ # Rather than launching a separate page, the filters are updated in-line in the # view_all_bugs_page. $g_dhtml_filters = ON; - + # The service to use to create a short URL. The %s will be replaced by the long URL. $g_create_short_url = 'http://tinyurl.com/create.php?url=%s'; @@ -1352,6 +1352,7 @@ $g_mantis_custom_field_string_table = '%db_table_prefix%_custom_field_string%db_table_suffix%'; $g_mantis_upgrade_table = '%db_table_prefix%_upgrade%db_table_suffix%'; $g_mantis_filters_table = '%db_table_prefix%_filters%db_table_suffix%'; + $g_mantis_filters_my_view_table = '%db_table_prefix%_filters_my_view%db_table_suffix%'; $g_mantis_sponsorship_table = '%db_table_prefix%_sponsorship%db_table_suffix%'; $g_mantis_tokens_table = '%db_table_prefix%_tokens%db_table_suffix%'; $g_mantis_project_hierarchy_table = '%db_table_prefix%_project_hierarchy%db_table_suffix%'; @@ -1493,7 +1494,7 @@ # WARNING: Potential security hazard. Only turn this on when you really # need it (for debugging/profiling) $g_show_queries_list = OFF; - + # --- detailed error messages ----- # Shows a list of variables and their values when an error is triggered # Only applies to error types configured to 'halt' in $g_display_errors, below @@ -1581,7 +1582,7 @@ # Note: # - Extensions must be in lower case # - All icons will be displayed as 16x16 pixels. - $g_file_type_icons = array( + $g_file_type_icons = array( '7z' => 'zip.gif', 'ace' => 'zip.gif', 'arj' => 'zip.gif', @@ -1675,19 +1676,37 @@ # Number of bugs shown in each box $g_my_view_bug_count = 10; - # Boxes to be shown and their order - # A box that is not to be shown can have its value set to 0 + # Boxes to be shown in "My View". Put them in the order you want them to appear $g_my_view_boxes = array ( - 'assigned' => '1', - 'unassigned' => '2', - 'reported' => '3', - 'resolved' => '4', - 'recent_mod' => '5', - 'monitored' => '6', - 'feedback' => '0', - 'verify' => '0' + FILTER_ASSIGNED, + FILTER_UNASSIGNED, + FILTER_REPORTED, + FILTER_RESOLVED, + FILTER_RECENT_MOD, + FILTER_MONITORED, + // FILTER_FEEDBACK, + // FILTER_VERIFY, + ); + + # Allows you to set a custom "My View" on an access level basis + # To do this, set the key of the first dimension to the access level, then + # make the value an array of filters. For example: + # $g_my_view_access_boxes = array ( + # ADMINISTRATOR => array( + # FILTER_UNASSIGNED, + # FILTER_ASSIGNED + # ), + # REPORTER => array( + # FILTER_REPORTED, + # FILTER_MONITORED + # ) + # ); + $g_my_view_access_boxes = array ( ); + # threshold needed to customize the 'My View' screen + $g_custom_my_view_threshold = ANYBODY; + # Toggle whether 'My View' boxes are shown in a fixed position (i.e. adjacent boxes start at the same vertical position) $g_my_view_boxes_fixed_position = ON; @@ -1703,7 +1722,7 @@ $g_rss_enabled = ON; # This seed is used as part of the inputs for calculating the authentication key for the RSS feeds. - # If this seed changes, all the existing keys for the RSS feeds will become invalid. This is + # If this seed changes, all the existing keys for the RSS feeds will become invalid. This is # defaulted to the database user name, but it is recommended to overwrite it with a specific value # on installation. $g_rss_key_seed = '%db_username%'; @@ -1782,7 +1801,7 @@ # Custom Group Actions # # This extensibility model allows developing new group custom actions. This - # can be implemented with a totally custom form and action pages or with a + # can be implemented with a totally custom form and action pages or with a # pre-implemented form and action page and call-outs to some functions. These # functions are to be implemented in a predefined file whose name is based on # the action name. For example, for an action to add a note, the action would @@ -1810,26 +1829,26 @@ ##################### # Wiki Integration ##################### - + # Wiki Integration Enabled? $g_wiki_enable = OFF; # Wiki Engine (supported engines: 'dokuwiki', 'mediawiki', 'xwiki') $g_wiki_engine = 'dokuwiki'; - + # Wiki namespace to be used as root for all pages relating to this mantis installation. $g_wiki_root_namespace = 'mantis'; - + # URL under which the wiki engine is hosted. Must be on the same server. $g_wiki_engine_url = $t_protocol . '://' . $t_host . '/%wiki_engine%/'; - + ##################### # Recently Visited ##################### # Whether to show the most recently visited issues or not. At the moment we always track them even if this flag is off. $g_recently_visited = ON; - + # The maximum number of issues to keep in the recently visited list. $g_recently_visited_count = 5; @@ -1893,7 +1912,7 @@ # Threshold needed to be able to create and modify global profiles $g_manage_global_profile_threshold = MANAGER; - # Allows the users to enter free text when reporting/updating issues + # Allows the users to enter free text when reporting/updating issues # for the profile related fields (i.e. platform, os, os build) $g_allow_freetext_in_profile_fields = ON; @@ -1907,7 +1926,7 @@ # The twitter account user name. $g_twitter_username = ''; - + # The twitter account password. $g_twitter_password = ''; ?> Index: my_view_page.php =================================================================== RCS file: /cvsroot/mantisbt/mantisbt/my_view_page.php,v retrieving revision 1.17 diff -u -r1.17 my_view_page.php --- my_view_page.php 28 Jul 2007 10:15:15 -0000 1.17 +++ my_view_page.php 23 Oct 2007 17:39:02 -0000 @@ -17,6 +17,7 @@ require_once( $t_core_path . 'compress_api.php' ); require_once( $t_core_path . 'filter_api.php' ); require_once( $t_core_path . 'last_visited_api.php' ); + require_once( $t_core_path . 'icon_api.php' ); auth_ensure_user_authenticated(); @@ -31,7 +32,7 @@ } html_page_top2(); - + print_recently_visited(); $f_page_number = gpc_get_int( 'page_number', 1 ); @@ -40,11 +41,6 @@ $t_bug_count = null; $t_page_count = null; - $t_boxes = config_get( 'my_view_boxes' ); - asort ($t_boxes); - reset ($t_boxes); - #print_r ($t_boxes); - $t_project_id = helper_get_current_project(); ?> @@ -61,91 +57,125 @@ echo '</td>'; echo '</tr>'; } -?> -<?php - $t_number_of_boxes = count ( $t_boxes ); $t_boxes_position = config_get( 'my_view_boxes_fixed_position' ); + + $t_custom_my_view_threshold = config_get('custom_my_view_threshold'); + + # Make sure they have access to define a custom 'my view' + if (access_has_global_level($t_custom_my_view_threshold)) { + + # Get the list of custom my_view filters + $t_filters = filter_db_get_my_view( $t_current_user_id, TRUE ); + + # If they set no custom filters, then get the default view + if (count($t_filters) <= 0) + $t_filters = filter_get_default_my_view( $t_project_id ); + + } + else { + $t_filters = filter_get_default_my_view( $t_project_id ); + } + + + $t_number_of_boxes = count($t_filters); + $t_counter = 0; - while (list ($t_box_title, $t_box_display) = each ($t_boxes)) { - # don't display bugs that are set as 0 - if ($t_box_display == 0) { - $t_number_of_boxes = $t_number_of_boxes - 1; - } + foreach ($t_filters AS $filter) { - # don't display "Assigned to Me" bugs to users that bugs can't be assigned to - else if ( $t_box_title == 'assigned' && ( current_user_is_anonymous() OR user_get_assigned_open_bug_count( $t_current_user_id, $t_project_id ) == 0 ) ) { - $t_number_of_boxes = $t_number_of_boxes - 1; - } + $t_counter++; - # don't display "Monitored by Me" bugs to users that can't monitor bugs - else if ( $t_box_title == 'monitored' && ( current_user_is_anonymous() OR !access_has_project_level( config_get( 'monitor_bug_threshold' ), $t_project_id, $t_current_user_id ) ) ) { - $t_number_of_boxes = $t_number_of_boxes - 1; - } + # If the filter is for a specific project, only use that project + if (array_key_exists('project_id', $filter) && $filter['project_id'] != 0) + $t_filter_project_id = $filter['project_id']; + else + $t_filter_project_id = $t_project_id; + + if ( ON == $t_boxes_position ) { + + # for even box number start new row and column + if ( 1 == $t_counter % 2 ) { + echo '<tr><td valign="top" width="50%">'; + + print_filter_my_view_box( + $filter['name'], + $f_page_number, + $t_per_page, + $filter['filter'], + $t_filter_project_id, + $t_current_user_id, + null, + array_key_exists('url', $filter)?"view_all_set.php?type=1&temporary=y&". $filter['url']:null + ); - # don't display "Reported by Me" bugs to users that can't report bugs - else if ( in_array( $t_box_title, array( 'reported', 'feedback', 'verify' ) ) && - ( current_user_is_anonymous() OR !access_has_project_level( config_get( 'report_bug_threshold' ), $t_project_id, $t_current_user_id ) ) ) { - $t_number_of_boxes = $t_number_of_boxes - 1; - } + echo '</td>'; + } - # display the box + # for odd box number only start new column + elseif ( 0 == $t_counter%2 ) { + echo '<td valign="top" width="50%">'; + + print_filter_my_view_box( + $filter['name'], + $f_page_number, + $t_per_page, + $filter['filter'], + $t_filter_project_id, + $t_current_user_id, + null, + array_key_exists('url', $filter)?"view_all_set.php?type=1&temporary=y&". $filter['url']:null + ); + + echo '</td></tr>'; + } + + # for odd number of box display one empty table cell in second column + if ( ( $t_counter == $t_number_of_boxes ) && 1 == $t_counter%2 ) { + echo '<td valign="top" width="50%"></td></tr>'; + } + + } else { - $t_counter++; - # check the style of displaying boxes - fixed (ie. each box in a separate table cell) or not - if ( ON == $t_boxes_position ) { - # for even box number start new row and column - if ( 1 == $t_counter%2 ) { - echo '<tr><td valign="top" width="50%">'; - include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'my_view_inc.php' ); - echo '</td>'; - } - - # for odd box number only start new column - elseif ( 0 == $t_counter%2 ) { - echo '<td valign="top" width="50%">'; - include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'my_view_inc.php' ); - echo '</td></tr>'; - } - - # for odd number of box display one empty table cell in second column - if ( ( $t_counter == $t_number_of_boxes ) && 1 == $t_counter%2 ) { - echo '<td valign="top" width="50%"></td></tr>'; - } - } - else if ( OFF == $t_boxes_position ) { - # start new table row and column for first box - if ( 1 == $t_counter ) { - echo '<tr><td valign="top" width="50%">'; - } - - # start new table column for the second half of boxes - if ( $t_counter == ceil ($t_number_of_boxes/2) + 1 ) { - echo '<td valign="top" width="50%">'; - } - - # display the required box - include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'my_view_inc.php' ); - echo '<br />'; - - # close the first column for first half of boxes - if ( $t_counter == ceil ($t_number_of_boxes/2) ) { - echo '</td>'; - } - - # close the table row after all of the boxes - if ( $t_counter == $t_number_of_boxes ) { - echo '</td></tr>'; - } + # start new table row and column for first box + if ( 1 == $t_counter ) { + echo '<tr><td valign="top" width="50%">'; + } + + # start new table column for the second half of boxes + if ( $t_counter == ceil ($t_number_of_boxes/2) + 1 ) { + echo '<td valign="top" width="50%">'; + } + + # display the required box + + print_filter_my_view_box( + $filter['name'], + $f_page_number, + $t_per_page, + $filter['filter'], + $t_filter_project_id, + $t_current_user_id, + null, + array_key_exists('url', $filter)?"view_all_set.php?type=1&temporary=y&". $filter['url']:null + ); + + echo '<br />'; + + # close the first column for first half of boxes + if ( $t_counter == ceil ($t_number_of_boxes/2) ) { + echo '</td>'; + } + + # close the table row after all of the boxes + if ( $t_counter == $t_number_of_boxes ) { + echo '</td></tr>'; } } - } -?> + } -<?php if ( $t_status_legend_position == STATUS_LEGEND_POSITION_BOTTOM || $t_status_legend_position == STATUS_LEGEND_POSITION_BOTH ) { echo '<tr>'; echo '<td colspan="2">'; @@ -160,4 +190,4 @@ <?php html_page_bottom1( __FILE__ ); -?> +?> \ No newline at end of file Index: core/constant_inc.php =================================================================== RCS file: /cvsroot/mantisbt/mantisbt/core/constant_inc.php,v retrieving revision 1.74 diff -u -r1.74 constant_inc.php --- core/constant_inc.php 24 Sep 2007 19:24:30 -0000 1.74 +++ core/constant_inc.php 23 Oct 2007 17:39:03 -0000 @@ -261,7 +261,7 @@ define( 'ERROR_LDAP_UPDATE_FAILED', 1402 ); define( 'ERROR_LDAP_USER_NOT_FOUND', 1403 ); define( 'ERROR_LDAP_EXTENSION_NOT_LOADED', 1404 ); - + # ERROR_CATEGORY_* define( 'ERROR_CATEGORY_DUPLICATE', 1500 ); define( 'ERROR_CATEGORY_NO_ACTION', 1501 ); @@ -296,7 +296,7 @@ # ERROR_FILTER_* define( 'ERROR_FILTER_NOT_FOUND', 2000 ); define( 'ERROR_FILTER_TOO_OLD', 2001 ); - + # ERROR_TWITTER_* define( 'ERROR_TWITTER_NO_CURL_EXT', 2100 ); @@ -321,6 +321,16 @@ define( 'FILTER_POSITION_BOTTOM', 2 ); define( 'FILTER_POSITION_BOTH', 3 ); // FILTER_POSITION_TOP | FILTER_POSITION_BOTTOM (bitwise OR) + # Default Filters + define( 'FILTER_ASSIGNED', -1 ); + define( 'FILTER_RECENT_MOD', -2 ); + define( 'FILTER_REPORTED', -3 ); + define( 'FILTER_RESOLVED', -4 ); + define( 'FILTER_UNASSIGNED', -5 ); + define( 'FILTER_MONITORED', -6 ); + define( 'FILTER_FEEDBACK', -7 ); + define( 'FILTER_VERIFY', -8 ); + # Flags for settings E-mail categories define( 'EMAIL_CATEGORY_PROJECT_CATEGORY', 1); Index: core/filter_api.php =================================================================== RCS file: /cvsroot/mantisbt/mantisbt/core/filter_api.php,v retrieving revision 1.164 diff -u -r1.164 filter_api.php --- core/filter_api.php 19 Oct 2007 06:13:00 -0000 1.164 +++ core/filter_api.php 23 Oct 2007 17:39:03 -0000 @@ -120,7 +120,7 @@ if ( is_string( $p_field_value ) && is_blank( $p_field_value ) ) { return true; } - + if ( is_bool( $p_field_value ) && !$p_field_value ) { return true; } @@ -138,7 +138,7 @@ # $p_field_name - The field name. # $p_field_value - The field value (can be an array) function filter_encode_field_and_value( $p_field_name, $p_field_value ) { - $t_query_array = array(); + $t_query_array = array(); if ( is_array( $p_field_value ) ) { $t_count = count( $p_field_value ); if ( $t_count > 1 ) { @@ -158,7 +158,7 @@ # Get a permalink for the current active filter. The results of using these fields by other users # can be inconsistent with the original results due to fields like "Myself", "Current Project", # and due to access level. - # Returns the search.php?xxxx or an empty string if no criteria applied. + # Returns the search.php?xxxx or an empty string if no criteria applied. function filter_get_url( $p_custom_filter ) { $t_query = array(); @@ -267,26 +267,26 @@ if ( !filter_str_field_is_any( $p_custom_filter[FILTER_PROPERTY_START_DAY] ) ) { $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_START_DAY, $p_custom_filter[FILTER_PROPERTY_START_DAY] ); } - + if ( !filter_str_field_is_any( $p_custom_filter[FILTER_PROPERTY_END_DAY] ) ) { $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_END_DAY, $p_custom_filter[FILTER_PROPERTY_END_DAY] ); } - + if ( !filter_str_field_is_any( $p_custom_filter[FILTER_PROPERTY_START_MONTH] ) ) { $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_START_MONTH, $p_custom_filter[FILTER_PROPERTY_START_MONTH] ); } - + if ( !filter_str_field_is_any( $p_custom_filter[FILTER_PROPERTY_END_MONTH] ) ) { $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_END_MONTH, $p_custom_filter[FILTER_PROPERTY_END_MONTH] ); } - + if ( !filter_str_field_is_any( $p_custom_filter[FILTER_PROPERTY_START_YEAR] ) ) { $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_START_YEAR, $p_custom_filter[FILTER_PROPERTY_START_YEAR] ); } - + if ( !filter_str_field_is_any( $p_custom_filter[FILTER_PROPERTY_END_YEAR] ) ) { $t_query[] = filter_encode_field_and_value( FILTER_SEARCH_END_YEAR, $p_custom_filter[FILTER_PROPERTY_END_YEAR] ); - } + } } if ( !filter_str_field_is_any( $p_custom_filter[FILTER_PROPERTY_RELATIONSHIP_TYPE] ) ) { @@ -426,6 +426,7 @@ $t_project_id = $p_project_id; } + if ( $p_custom_filter === null ) { # Prefer current_user_get_bug_filter() over user_get_filter() when applicable since it supports # cookies set by previous version of the code. @@ -476,7 +477,7 @@ $t_all_projects_found = false; $t_new_project_ids = array(); foreach ( $t_project_ids as $t_pid ) { - if ( $t_pid == META_FILTER_CURRENT ) { + if ( $t_pid == META_FILTER_CURRENT ) { $t_pid = $t_project_id; } @@ -505,7 +506,7 @@ } else { $t_project_ids = $t_new_project_ids; } - + if ( $t_projects_query_required ) { // expand project ids to include sub-projects if ( $t_include_sub_projects ) { @@ -566,7 +567,7 @@ } // both queries can't be null, so we either have one of them or both. - + if ( $t_private_and_public_query === null ) { $t_project_query = $t_public_only_query; } else if ( $t_public_only_query === null ) { @@ -617,7 +618,7 @@ } } } - + if ( 1 < count( $t_clauses ) ) { $t_reporter_query = "( $t_bug_table.reporter_id in (". implode( ', ', $t_clauses ) .") )"; } else { @@ -666,7 +667,7 @@ } } } - + if ( 1 < count( $t_clauses ) ) { $t_handler_query = "( $t_bug_table.handler_id in (". implode( ', ', $t_clauses ) .") )"; } else { @@ -1011,7 +1012,7 @@ array_push( $t_clauses, "'$c_target_version'" ); } } - + #echo var_dump( $t_clauses ); exit; if ( 1 < count( $t_clauses ) ) { array_push( $t_where_clauses, "( $t_bug_table.target_version in (". implode( ', ', $t_clauses ) .") )" ); @@ -1066,7 +1067,7 @@ array_push( $t_join_clauses, "LEFT JOIN $t_bug_relationship_table $t_table_name ON $t_table_name.destination_bug_id = $t_bug_table.id" ); array_push( $t_join_clauses, "LEFT JOIN $t_bug_relationship_table ${t_table_name}2 ON ${t_table_name}2.source_bug_id = $t_bug_table.id" ); // get reverse relationships - array_push( $t_clauses, "($t_table_name.relationship_type='$t_comp_type' AND $t_table_name.source_bug_id='$c_rel_bug')" ); + array_push( $t_clauses, "($t_table_name.relationship_type='$t_comp_type' AND $t_table_name.source_bug_id='$c_rel_bug')" ); array_push( $t_clauses, "($t_table_name"."2.relationship_type='$c_rel_type' AND $t_table_name"."2.destination_bug_id='$c_rel_bug')" ); array_push( $t_where_clauses, '('. implode( ' OR ', $t_clauses ) .')' ); } @@ -1081,7 +1082,7 @@ $t_tags_all = array(); $t_tags_any = array(); $t_tags_none = array(); - + foreach( $t_tags as $t_tag_row ) { switch ( $t_tag_row['filter'] ) { case 1: @@ -1095,13 +1096,13 @@ break; } } - + if ( 0 < $t_filter['tag_select'] && tag_exists( $t_filter['tag_select'] ) ) { $t_tags_any[] = tag_get( $t_filter['tag_select'] ); } - + $t_bug_tag_table = config_get( 'mantis_bug_tag_table' ); - + if ( count( $t_tags_all ) ) { $t_clauses = array(); foreach ( $t_tags_all as $t_tag_row ) { @@ -1109,7 +1110,7 @@ } array_push( $t_where_clauses, '('. implode( ' AND ', $t_clauses ) .')' ); } - + if ( count( $t_tags_any ) ) { $t_clauses = array(); foreach ( $t_tags_any as $t_tag_row ) { @@ -1117,16 +1118,16 @@ } array_push( $t_where_clauses, "$t_bug_table.id IN ( SELECT bug_id FROM $t_bug_tag_table WHERE ( ". implode( ' OR ', $t_clauses ) .') )' ); } - + if ( count( $t_tags_none ) ) { $t_clauses = array(); foreach ( $t_tags_none as $t_tag_row ) { array_push( $t_clauses, "$t_bug_tag_table.tag_id = $t_tag_row[id]" ); } array_push( $t_where_clauses, "$t_bug_table.id NOT IN ( SELECT bug_id FROM $t_bug_tag_table WHERE ( ". implode( ' OR ', $t_clauses ) .') )' ); - } + } - } + } } # custom field filters @@ -1152,10 +1153,10 @@ if ( !$t_any_found ) { $t_def = custom_field_get_definition( $t_cfid ); $t_table_name = $t_custom_field_string_table . '_' . $t_cfid; - # We need to filter each joined table or the result query will explode in dimensions - # Each custom field will result in a exponential growth like Number_of_Issues^Number_of_Custom_Fields - # and only after this process ends (if it is able to) the result query will be filtered - # by the WHERE clause and by the DISTINCT clause + # We need to filter each joined table or the result query will explode in dimensions + # Each custom field will result in a exponential growth like Number_of_Issues^Number_of_Custom_Fields + # and only after this process ends (if it is able to) the result query will be filtered + # by the WHERE clause and by the DISTINCT clause $t_cf_join_clause = "LEFT JOIN $t_custom_field_string_table $t_table_name ON $t_table_name.bug_id = $t_bug_table.id AND $t_table_name.field_id = $t_cfid "; if ($t_def['type'] == CUSTOM_FIELD_TYPE_DATE) { @@ -1186,7 +1187,7 @@ $t_filter_array = array(); foreach( $t_filter['custom_fields'][$t_cfid] as $t_filter_member ) { $t_filter_member = stripslashes( $t_filter_member ); - if ( META_FILTER_NONE == $t_filter_member ) { + if ( META_FILTER_NONE == $t_filter_member ) { # coerce filter value if selecting META_FILTER_NONE so it will match empty fields $t_filter_member = ''; # but also add those _not_ present in the custom field string table @@ -1218,7 +1219,7 @@ $c_search = db_prepare_string( $t_filter['search'] ); $c_search_int = db_prepare_int( $t_filter['search'] ); $t_textsearch_where_clause = '(' . db_helper_like( 'summary', "%$c_search%" ) . - ' OR ' . db_helper_like( "$t_bug_text_table.description", "%$c_search%" ) . + ' OR ' . db_helper_like( "$t_bug_text_table.description", "%$c_search%" ) . ' OR ' . db_helper_like( "$t_bug_text_table.steps_to_reproduce", "%$c_search%" ) . ' OR ' . db_helper_like( "$t_bug_text_table.additional_information", "%$c_search%" ) . " OR ( $t_bug_table.id = '$c_search_int' ) )"; @@ -1346,21 +1347,21 @@ if ( ( 'on' == $t_filter['sticky_issues'] ) && ( NULL !== $p_show_sticky ) ) { $t_order_array[] = "sticky DESC"; } - + $t_join = ''; for ( $i=0; $i < count( $t_sort_fields ); $i++ ) { $c_sort = db_prepare_string( $t_sort_fields[$i] ); if ( ! in_array( $t_sort_fields[$i], array_slice( $t_sort_fields, $i + 1) ) ) { - # if sorting by a custom field - if ( strpos( $c_sort, 'custom_' ) === 0 ) { - $t_custom_field = substr( $c_sort, strlen( 'custom_' ) ); - $t_custom_field_id = custom_field_get_id_from_name( $t_custom_field ); - $t_join .= " LEFT JOIN $t_custom_field_string_table ON ( ( $t_custom_field_string_table.bug_id = $t_bug_table.id ) AND ( $t_custom_field_string_table.field_id = $t_custom_field_id ) )"; - $c_sort = "$t_custom_field_string_table.value"; - $t_select_clauses[] = "$t_custom_field_string_table.value"; - } + # if sorting by a custom field + if ( strpos( $c_sort, 'custom_' ) === 0 ) { + $t_custom_field = substr( $c_sort, strlen( 'custom_' ) ); + $t_custom_field_id = custom_field_get_id_from_name( $t_custom_field ); + $t_join .= " LEFT JOIN $t_custom_field_string_table ON ( ( $t_custom_field_string_table.bug_id = $t_bug_table.id ) AND ( $t_custom_field_string_table.field_id = $t_custom_field_id ) )"; + $c_sort = "$t_custom_field_string_table.value"; + $t_select_clauses[] = "$t_custom_field_string_table.value"; + } if ( 'DESC' == $t_dir_fields[$i] ) { $c_dir = 'DESC'; @@ -1375,10 +1376,10 @@ # add basic sorting if necessary if ( ! in_array( 'last_updated', $t_sort_fields ) ) { $t_order_array[] = 'last_updated DESC'; - } + } if ( ! in_array( 'date_submitted', $t_sort_fields ) ) { $t_order_array[] = 'date_submitted DESC'; - } + } $t_order = " ORDER BY " . implode( ', ', $t_order_array ); $t_select = implode( ', ', array_unique( $t_select_clauses ) ); @@ -1405,24 +1406,24 @@ $row_count = db_num_rows( $result2 ); $t_id_array_lastmod = array(); - + for ( $i=0 ; $i < $row_count ; $i++ ) { $row = db_fetch_array( $result2 ); $t_id_array_lastmod[] = db_prepare_int ( $row['id'] ); - + $row['date_submitted'] = db_unixtimestamp ( $row['date_submitted'] ); $row['last_updated'] = db_unixtimestamp ( $row['last_updated'] ); - + array_push( $rows, $row ); } $t_id_array_lastmod = array_unique( $t_id_array_lastmod ); - + // paulr: it should be impossible for t_id_array_lastmod to be array(): // that would imply that $t_id_array is null which aborts this function early //if ( count( $t_id_array_lastmod ) > 0 ) { $t_where = "WHERE $t_bugnote_table.bug_id in (" . implode( ", ", $t_id_array_lastmod ) . ")"; - + $query3 = "SELECT DISTINCT bug_id,MAX(last_modified) as last_modified, COUNT(last_modified) as count FROM $t_bugnote_table $t_where GROUP BY bug_id"; # perform query @@ -1432,7 +1433,7 @@ for ( $i=0 ; $i < $row_count ; $i++ ) { $row = db_fetch_array( $result3 ); - + $t_stats[ $row['bug_id'] ] = $row; } @@ -1608,9 +1609,9 @@ || ( ( AUTO == config_get( 'show_product_version' ) ) && ( count( version_get_all_rows_with_subs( $t_project_id ) ) > 0 ) ); # overload handler_id setting if user isn't supposed to see them (ref #6189) - if ( ! access_has_project_level( config_get( 'view_handler_threshold' ), $t_project_id ) ) { - $t_filter['handler_id'] = array( META_FILTER_ANY ); - } + if ( ! access_has_project_level( config_get( 'view_handler_threshold' ), $t_project_id ) ) { + $t_filter['handler_id'] = array( META_FILTER_ANY ); + } ?> <tr <?php PRINT "class=\"" . $t_trclass . "\""; ?>> @@ -1776,7 +1777,7 @@ <input type="hidden" name="show_category[]" value="<?php echo string_display( $t_current );?>" /> <?php $t_this_string = ''; - if ( ( ( $t_current == META_FILTER_ANY ) && ( is_numeric( $t_current ) ) ) + if ( ( ( $t_current == META_FILTER_ANY ) && ( is_numeric( $t_current ) ) ) || ( is_blank( $t_current ) ) ) { $t_any_found = true; } else { @@ -2028,7 +2029,7 @@ <input type="hidden" name="show_build[]" value="<?php echo string_display( $t_current );?>" /> <?php $t_this_string = ''; - if ( ( ( $t_current == META_FILTER_ANY ) && ( is_numeric( $t_current ) ) ) + if ( ( ( $t_current == META_FILTER_ANY ) && ( is_numeric( $t_current ) ) ) || ( is_blank( $t_current ) ) ) { $t_any_found = true; } else if ( META_FILTER_NONE == $t_current ) { @@ -2066,7 +2067,7 @@ <input type="hidden" name="show_version[]" value="<?php echo string_display( $t_current );?>" /> <?php $t_this_string = ''; - if ( ( ( $t_current == META_FILTER_ANY ) && (is_numeric( $t_current ) ) ) + if ( ( ( $t_current == META_FILTER_ANY ) && (is_numeric( $t_current ) ) ) || ( is_blank( $t_current ) ) ) { $t_any_found = true; } else if ( META_FILTER_NONE == $t_current ) { @@ -2103,7 +2104,7 @@ <input type="hidden" name="fixed_in_version[]" value="<?php echo string_display( $t_current );?>" /> <?php $t_this_string = ''; - if ( ( ( $t_current == META_FILTER_ANY ) && ( is_numeric( $t_current ) ) ) + if ( ( ( $t_current == META_FILTER_ANY ) && ( is_numeric( $t_current ) ) ) || ( is_blank( $t_current ) ) ) { $t_any_found = true; } else if ( META_FILTER_NONE == $t_current ) { @@ -2135,38 +2136,38 @@ </td> <?php } ?> <td colspan="1" class="small-caption" valign="top" id="show_priority_filter_target"> - <?php + <?php $t_output = ''; - $t_any_found = false; - if ( count( $t_filter['show_priority'] ) == 0 ) { - PRINT lang_get( 'any' ); - } else { - $t_first_flag = true; - foreach( $t_filter['show_priority'] as $t_current ) { + $t_any_found = false; + if ( count( $t_filter['show_priority'] ) == 0 ) { + PRINT lang_get( 'any' ); + } else { + $t_first_flag = true; + foreach( $t_filter['show_priority'] as $t_current ) { ?> <input type="hidden" name="show_priority[]" value="<?php echo $t_current;?>" /> <?php - $t_this_string = ''; + $t_this_string = ''; if ( ( $t_current === META_FILTER_ANY ) || ( is_blank( $t_current ) ) || ( $t_current === 0 ) ) { - $t_any_found = true; - } else { - $t_this_string = get_enum_element( 'priority', $t_current ); - } - if ( $t_first_flag != true ) { - $t_output = $t_output . '<br />'; - } else { - $t_first_flag = false; - } - $t_output = $t_output . $t_this_string; - } - if ( true == $t_any_found ) { - PRINT lang_get( 'any' ); - } else { - PRINT $t_output; - } - } - ?> - </td> + $t_any_found = true; + } else { + $t_this_string = get_enum_element( 'priority', $t_current ); + } + if ( $t_first_flag != true ) { + $t_output = $t_output . '<br />'; + } else { + $t_first_flag = false; + } + $t_output = $t_output . $t_this_string; + } + if ( true == $t_any_found ) { + PRINT lang_get( 'any' ); + } else { + PRINT $t_output; + } + } + ?> + </td> <td colspan="1" class="small-caption" valign="top" id="show_target_version_filter_target"> <?php $t_output = ''; @@ -2181,7 +2182,7 @@ <input type="hidden" name="target_version[]" value="<?php echo string_display( $t_current );?>" /> <?php $t_this_string = ''; - if ( ( ( $t_current == META_FILTER_ANY ) && ( is_numeric( $t_current ) ) ) + if ( ( ( $t_current == META_FILTER_ANY ) && ( is_numeric( $t_current ) ) ) || ( is_blank( $t_current ) ) ) { $t_any_found = true; } else if ( META_FILTER_NONE == $t_current ) { @@ -2269,7 +2270,7 @@ <script type="text/javascript" language="JavaScript"> <!-- function SwitchDateFields() { - // All fields need to be enabled to go back to the script + // All fields need to be enabled to go back to the script document.filters_open.start_month.disabled = ! document.filters_open.do_filter_by_date.checked; document.filters_open.start_day.disabled = ! document.filters_open.do_filter_by_date.checked; document.filters_open.start_year.disabled = ! document.filters_open.do_filter_by_date.checked; @@ -2277,7 +2278,7 @@ document.filters_open.end_day.disabled = ! document.filters_open.do_filter_by_date.checked; document.filters_open.end_year.disabled = ! document.filters_open.do_filter_by_date.checked; - return true; + return true; } // --> </script> @@ -2342,7 +2343,7 @@ if ( -1 == $c_rel_type || 0 == $c_rel_bug ) { PRINT lang_get( 'any' ); } else { - PRINT relationship_get_description_for_history ($c_rel_type) . ' ' . $c_rel_bug; + PRINT relationship_get_description_for_history ($c_rel_type) . ' ' . $c_rel_bug; } ?> @@ -2385,13 +2386,13 @@ ?> </td> <td class="small-caption" valign="top" id="tag_string_filter_target" colspan="5"> - <?php + <?php $t_tag_string = $t_filter['tag_string']; if ( $t_filter['tag_select'] != 0 ) { $t_tag_string .= ( is_blank( $t_tag_string ) ? '' : config_get( 'tag_separator' ) ); $t_tag_string .= tag_get_field( $t_filter['tag_select'], 'name' ); } - PRINT $t_tag_string + PRINT $t_tag_string ?> <input type="hidden" name="tag_string" value="<?php echo $t_tag_string ?>"/> </td> @@ -2519,7 +2520,7 @@ foreach( $t_filter['custom_fields'][$t_accessible_custom_fields_ids[$i]] as $t_current ) { $t_current = stripslashes( $t_current ); $t_this_string = ''; - if ( ( ( $t_current == META_FILTER_ANY ) && ( is_numeric( $t_current ) ) ) + if ( ( ( $t_current == META_FILTER_ANY ) && ( is_numeric( $t_current ) ) ) || ( is_blank( $t_current ) ) ) { $t_any_found = true; } else if ( ( META_FILTER_NONE == $t_current ) && ( is_numeric( $t_current ) ) ) { @@ -2602,11 +2603,11 @@ echo ", "; } $t_sort = $t_sort_fields[$i]; - if ( strpos( $t_sort, 'custom_' ) === 0 ) { - $t_field_name = string_display( lang_get_defaulted( substr( $t_sort, strlen( 'custom_' ) ) ) ); - } else { - $t_field_name = string_get_field_name( $t_sort ); - } + if ( strpos( $t_sort, 'custom_' ) === 0 ) { + $t_field_name = string_display( lang_get_defaulted( substr( $t_sort, strlen( 'custom_' ) ) ) ); + } else { + $t_field_name = string_get_field_name( $t_sort ); + } echo $t_field_name . " " . lang_get( 'bugnote_order_' . strtolower( $t_dir_fields[$i] ) ); echo "<input type=\"hidden\" name=\"sort_$i\" value=\"$t_sort_fields[$i]\" />"; @@ -2652,7 +2653,7 @@ } ?> </td> - <?php + <?php if ( $t_filter_cols > 6 ) { echo '<td class="small-caption" valign="top" colspan="' . ( $t_filter_cols - 5 ) . '"> </td>'; } @@ -2660,7 +2661,7 @@ if ( $t_filter_cols > 3 ) { echo '<td class="small-caption" valign="top" colspan="' . ( $t_filter_cols - 2 ) . '"> </td>'; } - } + } ?> </tr> <?php @@ -2692,9 +2693,9 @@ print_bracket_link( $f_switch_view_link . 'advanced', lang_get( 'advanced_filters' ) ); } - print_bracket_link( - 'permalink_page.php?url=' . urlencode( filter_get_url( $t_filter ) ), - lang_get( 'create_filter_link' ), + print_bracket_link( + 'permalink_page.php?url=' . urlencode( filter_get_url( $t_filter ) ), + lang_get( 'create_filter_link' ), /* new window = */ true ); } ?> @@ -2769,7 +2770,7 @@ # check that the user can save non current filters (if required) if ( ( ALL_PROJECTS <= $c_project_id ) && ( !is_blank( $p_name ) ) && - ( !access_has_project_level( config_get( 'stored_query_create_threshold' ) ) ) ) { + ( !access_has_project_level( config_get( 'stored_query_create_threshold' ) ) ) ) { return -1; } @@ -2790,7 +2791,7 @@ $query = "UPDATE $t_filters_table SET is_public='$c_is_public', - filter_string='$c_filter_string' + filter_string='$c_filter_string' WHERE id='" . $row['id'] . "'"; db_query( $query ); @@ -2882,8 +2883,8 @@ $query = "SELECT * FROM $t_filters_table WHERE user_id='$c_user_id' - AND project_id='$c_project_id' - AND name=''"; + AND project_id='$c_project_id' + AND name=''"; $result = db_query( $query ); if ( db_num_rows( $result ) > 0 ) { @@ -3048,7 +3049,7 @@ if ( !isset( $p_filter_arr['dir'] ) ) { $p_filter_arr['dir'] = "DESC"; } - + if ( !isset( $p_filter_arr['platform'] ) ) { $p_filter_arr['platform'] = array( 0 => META_FILTER_ANY ); } @@ -3140,15 +3141,15 @@ if ( isset( $t_sort_fields[$i] ) ) { $t_drop = false; $t_sort = $t_sort_fields[$i]; - if ( strpos( $t_sort, 'custom_' ) === 0 ) { - if ( false === custom_field_get_id_from_name( substr( $t_sort, strlen( 'custom_' ) ) ) ) { - $t_drop = true; - } - } else { - if ( ! in_array( $t_sort, $t_fields ) ) { - $t_drop = true; - } - } + if ( strpos( $t_sort, 'custom_' ) === 0 ) { + if ( false === custom_field_get_id_from_name( substr( $t_sort, strlen( 'custom_' ) ) ) ) { + $t_drop = true; + } + } else { + if ( ! in_array( $t_sort, $t_fields ) ) { + $t_drop = true; + } + } if ( ! in_array( $t_dir_fields[$i], array( "ASC", "DESC" ) ) ) { $t_drop = true; } @@ -3240,6 +3241,612 @@ return $p_filter_arr; } + # Returns an array of the pre-defined filters + function filter_get_predefined ( $p_filter = false ) { + static $cache; + + if (!isset($cache)) { + + $t_bug_resolved_status_threshold = config_get( 'bug_resolved_status_threshold' ); + $t_hide_status_default = config_get( 'hide_status_default' ); + $t_default_show_changed = config_get( 'default_show_changed' ); + $t_current_user_id = auth_get_current_user_id(); + + $cache = array(); + + $cache[ FILTER_ASSIGNED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => $t_current_user_id ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_bug_resolved_status_threshold ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_assigned' ), + 'url' => 'handler_id=' . $t_current_user_id . '&hide_status=' . $t_bug_resolved_status_threshold, + 'id' => FILTER_ASSIGNED + ); + + $cache[ FILTER_RECENT_MOD ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => META_FILTER_NONE ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_recent_mod' ), + 'url' => 'hide_status=none', + 'id' => FILTER_RECENT_MOD + ); + + $cache[ FILTER_REPORTED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => $t_current_user_id ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'sort' => 'last_updated', + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_reported' ), + 'url' => 'reporter_id=' . $t_current_user_id . '&hide_status=' . $t_hide_status_default, + 'id' => FILTER_REPORTED + ); + + $cache[ FILTER_RESOLVED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => $t_bug_resolved_status_threshold ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_resolved' ), + 'url' => 'show_status=' . $t_bug_resolved_status_threshold . '&hide_status=' . $t_bug_resolved_status_threshold, + 'id' => FILTER_RESOLVED + ); + + $cache[ FILTER_UNASSIGNED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => META_FILTER_NONE ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_unassigned' ), + 'url' => 'handler_id=[none]' . '&hide_status=' . $t_hide_status_default, + 'id' => FILTER_UNASSIGNED + ); + + $cache[ FILTER_MONITORED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => $t_current_user_id ) + ), + 'name' => lang_get( 'my_view_title_monitored' ), + 'url' => 'user_monitor=' . $t_current_user_id . '&hide_status=' . $t_hide_status_default, + 'id' => FILTER_MONITORED + ); + + + $cache[ FILTER_FEEDBACK ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => FEEDBACK ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => $t_current_user_id ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_feedback' ), + 'url' => 'reporter_id=' . $t_current_user_id . '&show_status=' . FEEDBACK . '&hide_status=' . $t_hide_status_default, + 'id' => FILTER_FEEDBACK + ); + + $cache[ FILTER_VERIFY ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => $t_bug_resolved_status_threshold ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => $t_current_user_id ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_verify' ), + 'url' => 'reporter_id=' . $t_current_user_id . '&show_status=' . $t_bug_resolved_status_threshold, + 'id' => FILTER_VERIFY + ); + + } + + if (is_bool($p_filter) || empty($p_filter)) + return $cache; + else if (array_key_exists($p_filter, $cache)) + return $cache[ $p_filter ]; + else + return false; + + } + + # Returns an array of the default filters for my view + function filter_get_default_my_view ( $p_project_id = ALL_PROJECTS ) { + + $t_current_user_id = auth_get_current_user_id(); + + # Pull the list of My View boxes per access level + $t_access_boxes = config_get( 'my_view_access_boxes' ); + $t_user_level = access_get_project_level( $p_project_id ); + + # If they don't have a custom view by access level, give them the default + if (array_key_exists($t_user_level, $t_access_boxes)) + $t_config_boxes = $t_access_boxes[ $t_user_level ]; + else + $t_config_boxes = config_get( 'my_view_boxes' ); + + + $return = array(); + + foreach ($t_config_boxes AS $box) { + + # if box is less than 0, that means it's a predefined box + if ($box < 0) { + $return[ $box ] = filter_get_predefined( $box ); + } + + # otherwise, we need to get this filter from the database + else { + $return[ $box ] = filter_get_row( $box ); + if (!$return[ $box ]) + unset ($return[ $box ]); + else + $return[ $box ]['filter'] = filter_deserialize( $return[ $box ]['filter_string'] ); + } + } + + # don't display "Assigned to Me" bugs to users that bugs can't be assigned to + if ( current_user_is_anonymous() || user_get_assigned_open_bug_count( $t_current_user_id, $p_project_id ) == 0 ) + unset( $return[FILTER_ASSIGNED] ); + + # don't display "Monitored by Me" bugs to users that can't monitor bugs + if ( current_user_is_anonymous() OR !access_has_project_level( config_get( 'monitor_bug_threshold' ), $p_project_id, $t_current_user_id ) ) + unset( $return[FILTER_MONITORED] ); + + + # don't display "Reported by Me" bugs to users that can't report bugs + if ( current_user_is_anonymous() || !access_has_project_level( config_get( 'report_bug_threshold' ), $p_project_id, $t_current_user_id ) ) { + unset( $return[FILTER_REPORTED] ); + unset( $return[FILTER_FEEDBACK] ); + unset( $return[FILTER_VERIFY] ); + } + + return $return; + } + + # Returns a list of filters specific to a user for their my_view page + function filter_db_get_my_view ( $p_user_id = false ) { + + if (is_bool($p_user_id) || empty($p_user_id)) + $p_user_id = auth_get_current_user_id(); + + $t_filters_my_view_table = config_get( 'mantis_filters_my_view_table' ); + $t_filters_table = config_get( 'mantis_filters_table' ); + + $t_user_id = db_prepare_int( $p_user_id ); + + $query = "SELECT * + + FROM $t_filters_my_view_table + AS FMV + + LEFT JOIN $t_filters_table + AS FM + ON FMV.filter_id = FM.id + + WHERE FMV.user_id = $t_user_id + AND ( " + + # If the user doesn't have access rights to stored queries, return only predefined filters + .(access_has_project_level( config_get( 'stored_query_use_threshold' ) )?"FM.id IS NOT NULL OR ":"") + + ." FMV.filter_id < 0 ) + ORDER BY FMV.sequence ASC"; + + $result = db_query( $query ); + $query_count = db_num_rows( $result ); + + if ($query_count <= 0) + return array(); + + $t_filter_arr = array(); + + for ( $i = 0; $i < $query_count; $i++ ) { + $row = db_fetch_array( $result ); + + # if it is less than 0, that means it is a predefined filter + if (intval($row['filter_id']) < 0) { + $t_filter_arr[ intval($row['filter_id']) ] = filter_get_predefined( intval($row['filter_id']) ); + } + else { + $t_filter_arr[ intval($row['filter_id']) ] = $row; + $t_filter_arr[ intval($row['filter_id']) ]['filter'] = filter_deserialize( $row['filter_string'] ); + } + + // Perform some sequence cleanup + if ($row['sequence'] != $i + 1) + filter_set_filter_sequence( $i + 1, $row['filter_id'], $t_user_id ); + + $t_filter_arr[ intval($row['filter_id']) ]['sequence'] = $i + 1; + } + + return $t_filter_arr; + } + + # Returns the next sequence value for a user + function filter_get_next_sequence ( $p_user_id ) { + + $t_filters_my_view_table = config_get( 'mantis_filters_my_view_table' ); + $t_user_id = db_prepare_int( $p_user_id ); + + $query = "SELECT MAX(sequence) AS max + FROM $t_filters_my_view_table + WHERE user_id = ". $t_user_id; + + $result = db_query($query); + $row = db_fetch_array( $result ); + + return intval($row['max']) + 1; + } + + # Returns boolean whether a filter exists + # $p_predefined allows you to set whether or not a predefined filter ID will return true or not + function filter_exists ( $p_filter_id, $p_user_id = null, $p_project_id = null, $p_predefined = true) { + + # If less than zero, it must be a predefined filter ID + if ($p_filter_id < 0) { + if ($p_predefined && filter_get_predefined($p_filter_id)) + return true; + else + return false; + } + + # I used filter_cache_row instead of filter_get_row so I can control the errors + $filter = filter_cache_row( $p_filter_id, false ); + + if (!$filter) + return false; + + else if (!is_null($p_user_id) && $p_user_id != $filter['user_id']) + return false; + + else if (!is_null($p_project_id) && $p_project_id != $filter['project_id']) + return false; + + return true; + } + + # Removes a filter from a users 'My View' + function filter_remove_from_my_view ( $p_filter_id, $p_user_id = null ) { + + if ( empty($p_user_id) || is_bool($p_user_id) ) + $p_user_id = auth_get_current_user_id(); + + $t_filters_my_view_table = config_get( 'mantis_filters_my_view_table' ); + + $c_user_id = db_prepare_int( $p_user_id ); + $c_filter_id = db_prepare_int( $p_filter_id ); + + # First, we need to get the sequence of this filter so we can adjust order + $query = "SELECT sequence + FROM $t_filters_my_view_table + WHERE filter_id = $c_filter_id + AND user_id = $c_user_id + LIMIT 1"; + + $result = db_query($query); + + if (db_num_rows( $result ) <= 0) + return true; + + $t_sequence = db_fetch_array( $result ); + $t_sequence = db_prepare_int($t_sequence['sequence']); + + $query = "DELETE FROM $t_filters_my_view_table + WHERE filter_id = $c_filter_id + AND user_id = $c_user_id + LIMIT 1"; + + db_query($query); + + $query = "UPDATE $t_filters_my_view_table + SET sequence = sequence - 1 + WHERE sequence > $t_sequence + AND user_id = $c_user_id"; + + db_query( $query ); + + return true; + } + + # adds a new filter to a users 'My View' + function filter_add_to_my_view ($p_filter_id, $p_user_id = null) { + + if ( empty($p_user_id) || is_bool($p_user_id) ) + $p_user_id = auth_get_current_user_id(); + + $c_filter_id = db_prepare_int( $p_filter_id ); + $c_user_id = db_prepare_int( $p_user_id ); + + # We can't add a non-existent filter + if ( !filter_exists( $c_filter_id, $c_user_id ) ) + return false; + + $t_filters_my_view_table = config_get( 'mantis_filters_my_view_table' ); + + $query = "INSERT INTO $t_filters_my_view_table + SET filter_id = $c_filter_id, + user_id = $c_user_id, + sequence = ". filter_get_next_sequence( $c_user_id ); + + db_query( $query ); + + return true; + + } + + # updates the sequence for a filter + function filter_set_filter_sequence ($p_sequence, $p_filter_id, $p_user_id = null) { + + if ( empty($p_user_id) || is_bool($p_user_id) ) + $p_user_id = auth_get_current_user_id(); + + $c_filter_id = db_prepare_int( $p_filter_id ); + $c_user_id = db_prepare_int( $p_user_id ); + $c_sequence = db_prepare_int( $p_sequence ); + + $t_filters_my_view_table = config_get( 'mantis_filters_my_view_table' ); + + $query = "UPDATE $t_filters_my_view_table + SET sequence = $c_sequence + WHERE filter_id = $c_filter_id + AND user_id = $c_user_id + LIMIT 1"; + + db_query( $query ); + + } + + # Prints a select box for adding filters + function print_filter_my_view_inactive ( $p_show_empty = true ) { + + $p_user_id = auth_get_current_user_id(); + + # Get the filters the user currently displays on their My View + $t_active = array_keys( filter_db_get_my_view() ); + + # Get all the predefined filters, then weed out the ones they have already set + $t_predefined = filter_get_predefined(); + foreach ($t_predefined AS $key => $filter) { + if (in_array($key, $t_active)) + unset($t_predefined[$key]); + else + $t_predefined[ $key ] = $filter['name']; + } + + if ( access_has_project_level( config_get( 'stored_query_use_threshold' ) ) ) { + + # Get all the available filters, then weed out the ones already in use + $t_available = filter_db_get_available_queries( ALL_PROJECTS, $p_user_id ); + foreach ($t_available AS $key => $filter) { + if (in_array($key, $t_active)) + unset($t_available[$key]); + } + + } else { + $t_available = array(); + } + + # If both lists are empty, don't show the form unless they want us to + if (count($t_predefined) <= 0 && count($t_available) <= 0 && !$p_show_empty) + return; + + ?> + <form action="account_my_view_add.php" method="post"> + <select name="filter_id"> + <?php + + if (count($t_available) > 0) { + echo "<optgroup label='". lang_get('custom_filters') ."'>"; + + foreach ($t_available AS $f_key => $f_title) { + echo "<option value='". $f_key ."'>" . string_display_line($f_title) . "</option>"; + } + echo "</optgroup>"; + } + + if (count($t_predefined) > 0) { + echo "<optgroup label='". lang_get('predefined_filters') ."'>"; + + foreach ($t_predefined AS $f_key => $f_title) { + echo "<option value='". $f_key ."'>". string_display_line($f_title) ."</option>"; + } + echo "</optgroup>"; + } + + ?> + </select> + <input type="submit" class="button" value="<?php echo lang_get('add_my_view_filter'); ?>" /> + </form> + <?php + } + + # Prints a my view box from a set of query results + function print_filter_my_view_box ( $p_title, $p_page_number, $p_per_page, $p_custom_filter, + $p_project_id, $p_user_id, $p_show_sticky = null, $p_url = null, $p_show_empty = TRUE ) { + + $t_page_count = 0; + $t_bug_count = 0; + + # Run the filter query + $result = filter_get_bug_rows( $p_page_number, $p_per_page, $t_page_count, $t_bug_count, + $p_custom_filter, $p_project_id, $p_user_id, $p_show_sticky ); + + if (count($result) == 0 && !$p_show_empty) + return; + + if (is_null($p_url)) + $p_url = filter_get_url( $p_custom_filter ); + + $t_icon_path = config_get( 'icon_path' ); + $t_update_bug_threshold = config_get( 'update_bug_threshold' ); + + ?> + <table class="width100" cellspacing="1"> + <tr> + <td class="form-title" colspan="2"> + <a class="subtle" href="<?php echo $p_url; ?>"><?php echo string_display_line($p_title); ?></a> + [<a class="subtle" href="<?php echo $p_url; ?>" target="_blank">^</a>] + ( <?php echo string_display_line(project_get_name( $p_project_id )); ?> ) + <?php + if ( count( $result ) > 0 ) { + $v_start = $p_per_page * ($p_page_number - 1) + 1; + $v_end = $v_start + count( $result ) - 1; + } else { + $v_start = 0; + $v_end = 0; + } + echo "($v_start - $v_end / $t_bug_count)"; + ?> + </td> + </tr> + <?php + foreach ($result AS $row) { + + ?> + <tr bgcolor="<?php echo get_status_color($row['status']) ?>"> + + <td class="center"> + <span class="small"> + <?php + print_bug_link( $row['id'] ); + + echo '<br />'; + + if ( !bug_is_readonly( $row['id'] ) && access_has_bug_level( $t_update_bug_threshold, $row['id'] ) ) { + echo '<a href="' . string_get_bug_update_url( $row['id'] ) . '"><img border="0" src="' . $t_icon_path . 'update.png' . '" alt="' . lang_get( 'update_bug_button' ) . '" /></a>'; + } + + if ( ON == config_get( 'show_priority_text' ) ) { + print_formatted_priority_string( $row['status'], $row['priority'] ); + } else { + print_status_icon( $row['priority'] ); + } + + $t_attachment_count = 0; + if ( ( file_can_view_bug_attachments( $row['id'] ) ) ) { + $t_attachment_count = file_bug_attachment_count( $row['id'] ); + } + + if ( 0 < $t_attachment_count ) { + echo '<a href="' . string_get_bug_view_url( $row['id'] ) . '#attachments">'; + echo '<img border="0" src="' . $t_icon_path . 'attachment.png' . '"'; + echo ' alt="' . lang_get( 'attachment_alt' ) . '"'; + echo ' title="' . $t_attachment_count . ' ' . lang_get( 'attachments' ) . '"'; + echo ' />'; + echo '</a>'; + } + if ( VS_PRIVATE == $row['view_state'] ) { + echo '<img src="' . $t_icon_path . 'protected.gif" width="8" height="15" alt="' . lang_get( 'private' ) . '" />'; + } + ?> + </span> + </td> + <td class="left" valign="top" width="100%"> + <span class="small"> + <?php + + echo string_attribute( $row['summary'] ) + .'<br />'; + # show project name if viewing 'all projects' or bug is in subproject + if ( ON == config_get( 'show_bug_project_links' ) && + helper_get_current_project() != $row['project_id'] ) { + echo '['. project_get_name($row['project_id']) .'] '; + } + + echo string_display( $row['category'] ); + + $t_last_updated = date( config_get( 'normal_date_format' ), $row['last_updated'] ); + + if ( $row['last_updated'] > strtotime( '-'. $p_custom_filter['highlight_changed'] .' hours' ) ) { + echo ' - <b>' . $t_last_updated . '</b>'; + } else { + echo ' - ' . $t_last_updated; + } + + ?> + </span> + </td> + </tr> + <?php + } + ?> + </table> + + <? + + } + + /** * The following functions each print out an individual filter field. @@ -3345,7 +3952,7 @@ </select> <?php } - + function print_filter_platform() { global $t_select_modifier, $t_filter; @@ -3353,7 +3960,7 @@ <!-- Platform --> <select <?php echo $t_select_modifier;?> name="platform[]"> <option value="<?php echo META_FILTER_ANY ?>" <?php check_selected( $t_filter['platform'], META_FILTER_ANY ); ?>>[<?php echo lang_get( 'any' ) ?>]</option> - <?php + <?php log_event( LOG_FILTERING, 'Platform = ' . var_export( $t_filter['platform'], true ) ); print_platform_option_list( $t_filter['platform'] ); ?> @@ -3472,10 +4079,10 @@ function print_filter_show_priority(){ global $t_select_modifier, $t_filter; ?><!-- Priority --> - <select <?php PRINT $t_select_modifier;?> name="show_priority[]"> + <select <?php PRINT $t_select_modifier;?> name="show_priority[]"> <option value="<?php echo META_FILTER_ANY ?>" <?php check_selected( $t_filter['show_priority'], META_FILTER_ANY ); ?>>[<?php echo lang_get( 'any' ) ?>]</option> <?php print_enum_string_option_list( 'priority', $t_filter['show_priority'] ) ?> - </select> + </select> <?php } @@ -3684,11 +4291,11 @@ $t_shown_fields[""] = ""; for ( $i=0; $i < $t_n_fields; $i++ ) { if ( !in_array( $t_fields[$i], array( 'selection', 'edit', 'bugnotes_count', 'attachment' ) ) ) { - if ( strpos( $t_fields[$i], 'custom_' ) === 0 ) { - $t_field_name = string_display( lang_get_defaulted( substr( $t_fields[$i], strlen( 'custom_' ) ) ) ); - } else { - $t_field_name = string_get_field_name( $t_fields[$i] ); - } + if ( strpos( $t_fields[$i], 'custom_' ) === 0 ) { + $t_field_name = string_display( lang_get_defaulted( substr( $t_fields[$i], strlen( 'custom_' ) ) ) ); + } else { + $t_field_name = string_get_field_name( $t_fields[$i] ); + } $t_shown_fields[$t_fields[$i]] = $t_field_name; } } @@ -3867,7 +4474,7 @@ </select> <?php } - + # Prints a multi-value filter field. For example, platform, etc. # $p_field_name - The name of the field, e.g. "platform" # $p_field_value - an array of values. @@ -3879,7 +4486,7 @@ echo lang_get( 'any' ); } else { $t_first_flag = true; - + $t_field_value = is_array( $p_field_value ) ? $p_field_value : array( $p_field_value ); foreach( $t_field_value as $t_current ) { @@ -3889,7 +4496,7 @@ <?php $t_this_string = ''; - if ( ( ( $t_current == META_FILTER_ANY ) && ( is_numeric( $t_current ) ) ) + if ( ( ( $t_current == META_FILTER_ANY ) && ( is_numeric( $t_current ) ) ) || ( is_blank( $t_current ) ) ) { $t_any_found = true; } else { @@ -3993,7 +4600,7 @@ return ''; } } - + # -------------------- # Checks if a filter value is "any". Supports both single value as well as multiple value # fields (array). Index: core/html_api.php =================================================================== RCS file: /cvsroot/mantisbt/mantisbt/core/html_api.php,v retrieving revision 1.219 diff -u -r1.219 html_api.php --- core/html_api.php 22 Oct 2007 07:05:45 -0000 1.219 +++ core/html_api.php 23 Oct 2007 17:39:03 -0000 @@ -63,7 +63,7 @@ # flag for error handler to skip header menus $g_error_send_page_header = true; - + # Projax library disabled by default. It will be enabled if projax_api.php # is included. But it must be included after html_api.php $g_enable_projax = false; @@ -750,18 +750,25 @@ function print_account_menu( $p_page='' ) { $t_account_page = 'account_page.php'; $t_account_prefs_page = 'account_prefs_page.php'; + $t_account_my_view_page = 'account_my_view_page.php'; $t_account_profile_menu_page = 'account_prof_menu_page.php'; $t_account_sponsor_page = 'account_sponsor_page.php'; switch ( $p_page ) { case $t_account_page : $t_account_page = ''; break; case $t_account_prefs_page : $t_account_prefs_page = ''; break; + case $t_account_my_view_page : $t_account_my_view_page = ''; break; case $t_account_profile_menu_page : $t_account_profile_menu_page = ''; break; case $t_account_sponsor_page : $t_account_sponsor_page = ''; break; } print_bracket_link( $t_account_page, lang_get( 'account_link' ) ); print_bracket_link( $t_account_prefs_page, lang_get( 'change_preferences_link' ) ); + + + if (access_has_global_level(config_get('custom_my_view_threshold'))) + print_bracket_link( $t_account_my_view_page, lang_get( 'my_view_link' ) ); + if ( access_has_project_level( config_get( 'add_profile_threshold' ) ) ) { print_bracket_link( $t_account_profile_menu_page, lang_get( 'manage_profiles_link' ) ); } @@ -911,22 +918,22 @@ if ( null === $p_fields ) { $p_fields = array(); } - + if ( strtolower( $p_method ) == 'get' ) { $t_method = 'get'; } else { $t_method = 'post'; } - + PRINT "<form method=\"$t_method\" action=\"$p_action\">\n"; - + foreach ( $p_fields as $key => $val ) { $key = string_attribute( $key ); $val = string_attribute( $val ); - + PRINT " <input type=\"hidden\" name=\"$key\" value=\"$val\" />\n"; } - + PRINT " <input type=\"submit\" class=\"button\" value=\"$p_button_text\" />\n"; PRINT "</form>\n"; } @@ -1222,7 +1229,7 @@ * @param integer Tag ID */ function html_button_tag_update( $p_tag_id ) { - if ( access_has_global_level( config_get( 'tag_edit_threshold' ) ) + if ( access_has_global_level( config_get( 'tag_edit_threshold' ) ) || ( auth_get_current_user_id() == tag_get_field( $p_tag_id, 'user_id' ) && access_has_global_level( config_get( 'tag_edit_own_threshold' ) ) ) ) { Index: lang/strings_english.txt =================================================================== RCS file: /cvsroot/mantisbt/mantisbt/lang/strings_english.txt,v retrieving revision 1.316 diff -u -r1.316 strings_english.txt --- lang/strings_english.txt 22 Sep 2007 22:51:15 -0000 1.316 +++ lang/strings_english.txt 23 Oct 2007 17:39:04 -0000 @@ -1432,4 +1432,10 @@ $s_graph_page = 'Graph Bug History'; $s_graph_bug_page_link = 'Graph'; -?> +# Custom Filtering +$s_add_my_view_filter = 'Add Filter to My View'; +$s_my_view_filters = 'My View Filters'; +$s_predefined_filters = 'Predefined Filters'; +$s_custom_filters = 'Custom Filters'; + +?> \ No newline at end of file customMyView_v2.diff (33,697 bytes)
? account_my_view_add.php ? account_my_view_delete.php ? account_my_view_page.php ? account_my_view_sequence.php Index: config_defaults_inc.php =================================================================== RCS file: /cvsroot/mantisbt/mantisbt/config_defaults_inc.php,v retrieving revision 1.365 diff -u -b -r1.365 config_defaults_inc.php --- config_defaults_inc.php 4 Oct 2007 05:59:04 -0000 1.365 +++ config_defaults_inc.php 23 Oct 2007 19:23:21 -0000 @@ -1352,6 +1352,7 @@ $g_mantis_custom_field_string_table = '%db_table_prefix%_custom_field_string%db_table_suffix%'; $g_mantis_upgrade_table = '%db_table_prefix%_upgrade%db_table_suffix%'; $g_mantis_filters_table = '%db_table_prefix%_filters%db_table_suffix%'; + $g_mantis_filters_my_view_table = '%db_table_prefix%_filters_my_view%db_table_suffix%'; $g_mantis_sponsorship_table = '%db_table_prefix%_sponsorship%db_table_suffix%'; $g_mantis_tokens_table = '%db_table_prefix%_tokens%db_table_suffix%'; $g_mantis_project_hierarchy_table = '%db_table_prefix%_project_hierarchy%db_table_suffix%'; @@ -1675,19 +1676,37 @@ # Number of bugs shown in each box $g_my_view_bug_count = 10; - # Boxes to be shown and their order - # A box that is not to be shown can have its value set to 0 + # Boxes to be shown in "My View". Put them in the order you want them to appear $g_my_view_boxes = array ( - 'assigned' => '1', - 'unassigned' => '2', - 'reported' => '3', - 'resolved' => '4', - 'recent_mod' => '5', - 'monitored' => '6', - 'feedback' => '0', - 'verify' => '0' + FILTER_ASSIGNED, + FILTER_UNASSIGNED, + FILTER_REPORTED, + FILTER_RESOLVED, + FILTER_RECENT_MOD, + FILTER_MONITORED, + // FILTER_FEEDBACK, + // FILTER_VERIFY, ); + # Allows you to set a custom "My View" on an access level basis + # To do this, set the key of the first dimension to the access level, then + # make the value an array of filters. For example: + # $g_my_view_access_boxes = array ( + # ADMINISTRATOR => array( + # FILTER_UNASSIGNED, + # FILTER_ASSIGNED + # ), + # REPORTER => array( + # FILTER_REPORTED, + # FILTER_MONITORED + # ) + # ); + $g_my_view_access_boxes = array ( + ); + + # threshold needed to customize the 'My View' screen + $g_custom_my_view_threshold = ANYBODY; + # Toggle whether 'My View' boxes are shown in a fixed position (i.e. adjacent boxes start at the same vertical position) $g_my_view_boxes_fixed_position = ON; Index: my_view_page.php =================================================================== RCS file: /cvsroot/mantisbt/mantisbt/my_view_page.php,v retrieving revision 1.17 diff -u -b -r1.17 my_view_page.php --- my_view_page.php 28 Jul 2007 10:15:15 -0000 1.17 +++ my_view_page.php 23 Oct 2007 19:23:21 -0000 @@ -17,6 +17,7 @@ require_once( $t_core_path . 'compress_api.php' ); require_once( $t_core_path . 'filter_api.php' ); require_once( $t_core_path . 'last_visited_api.php' ); + require_once( $t_core_path . 'icon_api.php' ); auth_ensure_user_authenticated(); @@ -40,11 +41,6 @@ $t_bug_count = null; $t_page_count = null; - $t_boxes = config_get( 'my_view_boxes' ); - asort ($t_boxes); - reset ($t_boxes); - #print_r ($t_boxes); - $t_project_id = helper_get_current_project(); ?> @@ -61,52 +57,76 @@ echo '</td>'; echo '</tr>'; } -?> -<?php - $t_number_of_boxes = count ( $t_boxes ); $t_boxes_position = config_get( 'my_view_boxes_fixed_position' ); - $t_counter = 0; - while (list ($t_box_title, $t_box_display) = each ($t_boxes)) { - # don't display bugs that are set as 0 - if ($t_box_display == 0) { - $t_number_of_boxes = $t_number_of_boxes - 1; - } + $t_custom_my_view_threshold = config_get('custom_my_view_threshold'); - # don't display "Assigned to Me" bugs to users that bugs can't be assigned to - else if ( $t_box_title == 'assigned' && ( current_user_is_anonymous() OR user_get_assigned_open_bug_count( $t_current_user_id, $t_project_id ) == 0 ) ) { - $t_number_of_boxes = $t_number_of_boxes - 1; - } + # Make sure they have access to define a custom 'my view' + if (access_has_global_level($t_custom_my_view_threshold)) { - # don't display "Monitored by Me" bugs to users that can't monitor bugs - else if ( $t_box_title == 'monitored' && ( current_user_is_anonymous() OR !access_has_project_level( config_get( 'monitor_bug_threshold' ), $t_project_id, $t_current_user_id ) ) ) { - $t_number_of_boxes = $t_number_of_boxes - 1; - } + # Get the list of custom my_view filters + $t_filters = filter_db_get_my_view( $t_current_user_id, TRUE ); - # don't display "Reported by Me" bugs to users that can't report bugs - else if ( in_array( $t_box_title, array( 'reported', 'feedback', 'verify' ) ) && - ( current_user_is_anonymous() OR !access_has_project_level( config_get( 'report_bug_threshold' ), $t_project_id, $t_current_user_id ) ) ) { - $t_number_of_boxes = $t_number_of_boxes - 1; - } + # If they set no custom filters, then get the default view + if (count($t_filters) <= 0) + $t_filters = filter_get_default_my_view( $t_project_id ); - # display the box + } else { + $t_filters = filter_get_default_my_view( $t_project_id ); + } + + + $t_number_of_boxes = count($t_filters); + + $t_counter = 0; + + foreach ($t_filters AS $filter) { + $t_counter++; - # check the style of displaying boxes - fixed (ie. each box in a separate table cell) or not + # If the filter is for a specific project, only use that project + if (array_key_exists('project_id', $filter) && $filter['project_id'] != 0) + $t_filter_project_id = $filter['project_id']; + else + $t_filter_project_id = $t_project_id; + if ( ON == $t_boxes_position ) { + # for even box number start new row and column - if ( 1 == $t_counter%2 ) { + if ( 1 == $t_counter % 2 ) { echo '<tr><td valign="top" width="50%">'; - include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'my_view_inc.php' ); + + print_filter_my_view_box( + $filter['name'], + $f_page_number, + $t_per_page, + $filter['filter'], + $t_filter_project_id, + $t_current_user_id, + null, + array_key_exists('url', $filter)?"view_all_set.php?type=1&temporary=y&". $filter['url']:null + ); + echo '</td>'; } # for odd box number only start new column elseif ( 0 == $t_counter%2 ) { echo '<td valign="top" width="50%">'; - include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'my_view_inc.php' ); + + print_filter_my_view_box( + $filter['name'], + $f_page_number, + $t_per_page, + $filter['filter'], + $t_filter_project_id, + $t_current_user_id, + null, + array_key_exists('url', $filter)?"view_all_set.php?type=1&temporary=y&". $filter['url']:null + ); + echo '</td></tr>'; } @@ -114,8 +134,10 @@ if ( ( $t_counter == $t_number_of_boxes ) && 1 == $t_counter%2 ) { echo '<td valign="top" width="50%"></td></tr>'; } + } - else if ( OFF == $t_boxes_position ) { + else { + # start new table row and column for first box if ( 1 == $t_counter ) { echo '<tr><td valign="top" width="50%">'; @@ -127,7 +149,18 @@ } # display the required box - include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'my_view_inc.php' ); + + print_filter_my_view_box( + $filter['name'], + $f_page_number, + $t_per_page, + $filter['filter'], + $t_filter_project_id, + $t_current_user_id, + null, + array_key_exists('url', $filter)?"view_all_set.php?type=1&temporary=y&". $filter['url']:null + ); + echo '<br />'; # close the first column for first half of boxes @@ -140,12 +173,9 @@ echo '</td></tr>'; } } - } - } -?> + } -<?php if ( $t_status_legend_position == STATUS_LEGEND_POSITION_BOTTOM || $t_status_legend_position == STATUS_LEGEND_POSITION_BOTH ) { echo '<tr>'; echo '<td colspan="2">'; Index: core/constant_inc.php =================================================================== RCS file: /cvsroot/mantisbt/mantisbt/core/constant_inc.php,v retrieving revision 1.74 diff -u -b -r1.74 constant_inc.php --- core/constant_inc.php 24 Sep 2007 19:24:30 -0000 1.74 +++ core/constant_inc.php 23 Oct 2007 19:23:21 -0000 @@ -321,6 +321,16 @@ define( 'FILTER_POSITION_BOTTOM', 2 ); define( 'FILTER_POSITION_BOTH', 3 ); // FILTER_POSITION_TOP | FILTER_POSITION_BOTTOM (bitwise OR) + # Default Filters + define( 'FILTER_ASSIGNED', -1 ); + define( 'FILTER_RECENT_MOD', -2 ); + define( 'FILTER_REPORTED', -3 ); + define( 'FILTER_RESOLVED', -4 ); + define( 'FILTER_UNASSIGNED', -5 ); + define( 'FILTER_MONITORED', -6 ); + define( 'FILTER_FEEDBACK', -7 ); + define( 'FILTER_VERIFY', -8 ); + # Flags for settings E-mail categories define( 'EMAIL_CATEGORY_PROJECT_CATEGORY', 1); Index: core/filter_api.php =================================================================== RCS file: /cvsroot/mantisbt/mantisbt/core/filter_api.php,v retrieving revision 1.164 diff -u -b -r1.164 filter_api.php --- core/filter_api.php 19 Oct 2007 06:13:00 -0000 1.164 +++ core/filter_api.php 23 Oct 2007 19:23:21 -0000 @@ -426,6 +426,7 @@ $t_project_id = $p_project_id; } + if ( $p_custom_filter === null ) { # Prefer current_user_get_bug_filter() over user_get_filter() when applicable since it supports # cookies set by previous version of the code. @@ -3240,6 +3241,612 @@ return $p_filter_arr; } + # Returns an array of the pre-defined filters + function filter_get_predefined ( $p_filter = false ) { + static $cache; + + if (!isset($cache)) { + + $t_bug_resolved_status_threshold = config_get( 'bug_resolved_status_threshold' ); + $t_hide_status_default = config_get( 'hide_status_default' ); + $t_default_show_changed = config_get( 'default_show_changed' ); + $t_current_user_id = auth_get_current_user_id(); + + $cache = array(); + + $cache[ FILTER_ASSIGNED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => $t_current_user_id ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_bug_resolved_status_threshold ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_assigned' ), + 'url' => 'handler_id=' . $t_current_user_id . '&hide_status=' . $t_bug_resolved_status_threshold, + 'id' => FILTER_ASSIGNED + ); + + $cache[ FILTER_RECENT_MOD ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => META_FILTER_NONE ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_recent_mod' ), + 'url' => 'hide_status=none', + 'id' => FILTER_RECENT_MOD + ); + + $cache[ FILTER_REPORTED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => $t_current_user_id ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'sort' => 'last_updated', + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_reported' ), + 'url' => 'reporter_id=' . $t_current_user_id . '&hide_status=' . $t_hide_status_default, + 'id' => FILTER_REPORTED + ); + + $cache[ FILTER_RESOLVED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => $t_bug_resolved_status_threshold ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_resolved' ), + 'url' => 'show_status=' . $t_bug_resolved_status_threshold . '&hide_status=' . $t_bug_resolved_status_threshold, + 'id' => FILTER_RESOLVED + ); + + $cache[ FILTER_UNASSIGNED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => META_FILTER_NONE ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_unassigned' ), + 'url' => 'handler_id=[none]' . '&hide_status=' . $t_hide_status_default, + 'id' => FILTER_UNASSIGNED + ); + + $cache[ FILTER_MONITORED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => $t_current_user_id ) + ), + 'name' => lang_get( 'my_view_title_monitored' ), + 'url' => 'user_monitor=' . $t_current_user_id . '&hide_status=' . $t_hide_status_default, + 'id' => FILTER_MONITORED + ); + + + $cache[ FILTER_FEEDBACK ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => FEEDBACK ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => $t_current_user_id ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_feedback' ), + 'url' => 'reporter_id=' . $t_current_user_id . '&show_status=' . FEEDBACK . '&hide_status=' . $t_hide_status_default, + 'id' => FILTER_FEEDBACK + ); + + $cache[ FILTER_VERIFY ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => $t_bug_resolved_status_threshold ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => $t_current_user_id ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_verify' ), + 'url' => 'reporter_id=' . $t_current_user_id . '&show_status=' . $t_bug_resolved_status_threshold, + 'id' => FILTER_VERIFY + ); + + } + + if (is_bool($p_filter) || empty($p_filter)) + return $cache; + else if (array_key_exists($p_filter, $cache)) + return $cache[ $p_filter ]; + else + return false; + + } + + # Returns an array of the default filters for my view + function filter_get_default_my_view ( $p_project_id = ALL_PROJECTS ) { + + $t_current_user_id = auth_get_current_user_id(); + + # Pull the list of My View boxes per access level + $t_access_boxes = config_get( 'my_view_access_boxes' ); + $t_user_level = access_get_project_level( $p_project_id ); + + # If they don't have a custom view by access level, give them the default + if (array_key_exists($t_user_level, $t_access_boxes)) + $t_config_boxes = $t_access_boxes[ $t_user_level ]; + else + $t_config_boxes = config_get( 'my_view_boxes' ); + + + $return = array(); + + foreach ($t_config_boxes AS $box) { + + # if box is less than 0, that means it's a predefined box + if ($box < 0) { + $return[ $box ] = filter_get_predefined( $box ); + } + + # otherwise, we need to get this filter from the database + else { + $return[ $box ] = filter_get_row( $box ); + if (!$return[ $box ]) + unset ($return[ $box ]); + else + $return[ $box ]['filter'] = filter_deserialize( $return[ $box ]['filter_string'] ); + } + } + + # don't display "Assigned to Me" bugs to users that bugs can't be assigned to + if ( current_user_is_anonymous() || user_get_assigned_open_bug_count( $t_current_user_id, $p_project_id ) == 0 ) + unset( $return[FILTER_ASSIGNED] ); + + # don't display "Monitored by Me" bugs to users that can't monitor bugs + if ( current_user_is_anonymous() OR !access_has_project_level( config_get( 'monitor_bug_threshold' ), $p_project_id, $t_current_user_id ) ) + unset( $return[FILTER_MONITORED] ); + + + # don't display "Reported by Me" bugs to users that can't report bugs + if ( current_user_is_anonymous() || !access_has_project_level( config_get( 'report_bug_threshold' ), $p_project_id, $t_current_user_id ) ) { + unset( $return[FILTER_REPORTED] ); + unset( $return[FILTER_FEEDBACK] ); + unset( $return[FILTER_VERIFY] ); + } + + return $return; + } + + # Returns a list of filters specific to a user for their my_view page + function filter_db_get_my_view ( $p_user_id = false ) { + + if (is_bool($p_user_id) || empty($p_user_id)) + $p_user_id = auth_get_current_user_id(); + + $t_filters_my_view_table = config_get( 'mantis_filters_my_view_table' ); + $t_filters_table = config_get( 'mantis_filters_table' ); + + $t_user_id = db_prepare_int( $p_user_id ); + + $query = "SELECT * + + FROM $t_filters_my_view_table + AS FMV + + LEFT JOIN $t_filters_table + AS FM + ON FMV.filter_id = FM.id + + WHERE FMV.user_id = $t_user_id + AND ( " + + # If the user doesn't have access rights to stored queries, return only predefined filters + .(access_has_project_level( config_get( 'stored_query_use_threshold' ) )?"FM.id IS NOT NULL OR ":"") + + ." FMV.filter_id < 0 ) + ORDER BY FMV.sequence ASC"; + + $result = db_query( $query ); + $query_count = db_num_rows( $result ); + + if ($query_count <= 0) + return array(); + + $t_filter_arr = array(); + + for ( $i = 0; $i < $query_count; $i++ ) { + $row = db_fetch_array( $result ); + + # if it is less than 0, that means it is a predefined filter + if (intval($row['filter_id']) < 0) { + $t_filter_arr[ intval($row['filter_id']) ] = filter_get_predefined( intval($row['filter_id']) ); + } + else { + $t_filter_arr[ intval($row['filter_id']) ] = $row; + $t_filter_arr[ intval($row['filter_id']) ]['filter'] = filter_deserialize( $row['filter_string'] ); + } + + // Perform some sequence cleanup + if ($row['sequence'] != $i + 1) + filter_set_filter_sequence( $i + 1, $row['filter_id'], $t_user_id ); + + $t_filter_arr[ intval($row['filter_id']) ]['sequence'] = $i + 1; + } + + return $t_filter_arr; + } + + # Returns the next sequence value for a user + function filter_get_next_sequence ( $p_user_id ) { + + $t_filters_my_view_table = config_get( 'mantis_filters_my_view_table' ); + $t_user_id = db_prepare_int( $p_user_id ); + + $query = "SELECT MAX(sequence) AS max + FROM $t_filters_my_view_table + WHERE user_id = ". $t_user_id; + + $result = db_query($query); + $row = db_fetch_array( $result ); + + return intval($row['max']) + 1; + } + + # Returns boolean whether a filter exists + # $p_predefined allows you to set whether or not a predefined filter ID will return true or not + function filter_exists ( $p_filter_id, $p_user_id = null, $p_project_id = null, $p_predefined = true) { + + # If less than zero, it must be a predefined filter ID + if ($p_filter_id < 0) { + if ($p_predefined && filter_get_predefined($p_filter_id)) + return true; + else + return false; + } + + # I used filter_cache_row instead of filter_get_row so I can control the errors + $filter = filter_cache_row( $p_filter_id, false ); + + if (!$filter) + return false; + + else if (!is_null($p_user_id) && $p_user_id != $filter['user_id']) + return false; + + else if (!is_null($p_project_id) && $p_project_id != $filter['project_id']) + return false; + + return true; + } + + # Removes a filter from a users 'My View' + function filter_remove_from_my_view ( $p_filter_id, $p_user_id = null ) { + + if ( empty($p_user_id) || is_bool($p_user_id) ) + $p_user_id = auth_get_current_user_id(); + + $t_filters_my_view_table = config_get( 'mantis_filters_my_view_table' ); + + $c_user_id = db_prepare_int( $p_user_id ); + $c_filter_id = db_prepare_int( $p_filter_id ); + + # First, we need to get the sequence of this filter so we can adjust order + $query = "SELECT sequence + FROM $t_filters_my_view_table + WHERE filter_id = $c_filter_id + AND user_id = $c_user_id + LIMIT 1"; + + $result = db_query($query); + + if (db_num_rows( $result ) <= 0) + return true; + + $t_sequence = db_fetch_array( $result ); + $t_sequence = db_prepare_int($t_sequence['sequence']); + + $query = "DELETE FROM $t_filters_my_view_table + WHERE filter_id = $c_filter_id + AND user_id = $c_user_id + LIMIT 1"; + + db_query($query); + + $query = "UPDATE $t_filters_my_view_table + SET sequence = sequence - 1 + WHERE sequence > $t_sequence + AND user_id = $c_user_id"; + + db_query( $query ); + + return true; + } + + # adds a new filter to a users 'My View' + function filter_add_to_my_view ($p_filter_id, $p_user_id = null) { + + if ( empty($p_user_id) || is_bool($p_user_id) ) + $p_user_id = auth_get_current_user_id(); + + $c_filter_id = db_prepare_int( $p_filter_id ); + $c_user_id = db_prepare_int( $p_user_id ); + + # We can't add a non-existent filter + if ( !filter_exists( $c_filter_id, $c_user_id ) ) + return false; + + $t_filters_my_view_table = config_get( 'mantis_filters_my_view_table' ); + + $query = "INSERT INTO $t_filters_my_view_table + SET filter_id = $c_filter_id, + user_id = $c_user_id, + sequence = ". filter_get_next_sequence( $c_user_id ); + + db_query( $query ); + + return true; + + } + + # updates the sequence for a filter + function filter_set_filter_sequence ($p_sequence, $p_filter_id, $p_user_id = null) { + + if ( empty($p_user_id) || is_bool($p_user_id) ) + $p_user_id = auth_get_current_user_id(); + + $c_filter_id = db_prepare_int( $p_filter_id ); + $c_user_id = db_prepare_int( $p_user_id ); + $c_sequence = db_prepare_int( $p_sequence ); + + $t_filters_my_view_table = config_get( 'mantis_filters_my_view_table' ); + + $query = "UPDATE $t_filters_my_view_table + SET sequence = $c_sequence + WHERE filter_id = $c_filter_id + AND user_id = $c_user_id + LIMIT 1"; + + db_query( $query ); + + } + + # Prints a select box for adding filters + function print_filter_my_view_inactive ( $p_show_empty = true ) { + + $p_user_id = auth_get_current_user_id(); + + # Get the filters the user currently displays on their My View + $t_active = array_keys( filter_db_get_my_view() ); + + # Get all the predefined filters, then weed out the ones they have already set + $t_predefined = filter_get_predefined(); + foreach ($t_predefined AS $key => $filter) { + if (in_array($key, $t_active)) + unset($t_predefined[$key]); + else + $t_predefined[ $key ] = $filter['name']; + } + + if ( access_has_project_level( config_get( 'stored_query_use_threshold' ) ) ) { + + # Get all the available filters, then weed out the ones already in use + $t_available = filter_db_get_available_queries( ALL_PROJECTS, $p_user_id ); + foreach ($t_available AS $key => $filter) { + if (in_array($key, $t_active)) + unset($t_available[$key]); + } + + } else { + $t_available = array(); + } + + # If both lists are empty, don't show the form unless they want us to + if (count($t_predefined) <= 0 && count($t_available) <= 0 && !$p_show_empty) + return; + + ?> + <form action="account_my_view_add.php" method="post"> + <select name="filter_id"> + <?php + + if (count($t_available) > 0) { + echo "<optgroup label='". lang_get('custom_filters') ."'>"; + + foreach ($t_available AS $f_key => $f_title) { + echo "<option value='". $f_key ."'>" . string_display_line($f_title) . "</option>"; + } + echo "</optgroup>"; + } + + if (count($t_predefined) > 0) { + echo "<optgroup label='". lang_get('predefined_filters') ."'>"; + + foreach ($t_predefined AS $f_key => $f_title) { + echo "<option value='". $f_key ."'>". string_display_line($f_title) ."</option>"; + } + echo "</optgroup>"; + } + + ?> + </select> + <input type="submit" class="button" value="<?php echo lang_get('add_my_view_filter'); ?>" /> + </form> + <?php + } + + # Prints a my view box from a set of query results + function print_filter_my_view_box ( $p_title, $p_page_number, $p_per_page, $p_custom_filter, + $p_project_id, $p_user_id, $p_show_sticky = null, $p_url = null, $p_show_empty = TRUE ) { + + $t_page_count = 0; + $t_bug_count = 0; + + # Run the filter query + $result = filter_get_bug_rows( $p_page_number, $p_per_page, $t_page_count, $t_bug_count, + $p_custom_filter, $p_project_id, $p_user_id, $p_show_sticky ); + + if (count($result) == 0 && !$p_show_empty) + return; + + if (is_null($p_url)) + $p_url = filter_get_url( $p_custom_filter ); + + $t_icon_path = config_get( 'icon_path' ); + $t_update_bug_threshold = config_get( 'update_bug_threshold' ); + + ?> + <table class="width100" cellspacing="1"> + <tr> + <td class="form-title" colspan="2"> + <a class="subtle" href="<?php echo $p_url; ?>"><?php echo string_display_line($p_title); ?></a> + [<a class="subtle" href="<?php echo $p_url; ?>" target="_blank">^</a>] + ( <?php echo string_display_line(project_get_name( $p_project_id )); ?> ) + <?php + if ( count( $result ) > 0 ) { + $v_start = $p_per_page * ($p_page_number - 1) + 1; + $v_end = $v_start + count( $result ) - 1; + } else { + $v_start = 0; + $v_end = 0; + } + echo "($v_start - $v_end / $t_bug_count)"; + ?> + </td> + </tr> + <?php + foreach ($result AS $row) { + + ?> + <tr bgcolor="<?php echo get_status_color($row['status']) ?>"> + + <td class="center"> + <span class="small"> + <?php + print_bug_link( $row['id'] ); + + echo '<br />'; + + if ( !bug_is_readonly( $row['id'] ) && access_has_bug_level( $t_update_bug_threshold, $row['id'] ) ) { + echo '<a href="' . string_get_bug_update_url( $row['id'] ) . '"><img border="0" src="' . $t_icon_path . 'update.png' . '" alt="' . lang_get( 'update_bug_button' ) . '" /></a>'; + } + + if ( ON == config_get( 'show_priority_text' ) ) { + print_formatted_priority_string( $row['status'], $row['priority'] ); + } else { + print_status_icon( $row['priority'] ); + } + + $t_attachment_count = 0; + if ( ( file_can_view_bug_attachments( $row['id'] ) ) ) { + $t_attachment_count = file_bug_attachment_count( $row['id'] ); + } + + if ( 0 < $t_attachment_count ) { + echo '<a href="' . string_get_bug_view_url( $row['id'] ) . '#attachments">'; + echo '<img border="0" src="' . $t_icon_path . 'attachment.png' . '"'; + echo ' alt="' . lang_get( 'attachment_alt' ) . '"'; + echo ' title="' . $t_attachment_count . ' ' . lang_get( 'attachments' ) . '"'; + echo ' />'; + echo '</a>'; + } + if ( VS_PRIVATE == $row['view_state'] ) { + echo '<img src="' . $t_icon_path . 'protected.gif" width="8" height="15" alt="' . lang_get( 'private' ) . '" />'; + } + ?> + </span> + </td> + <td class="left" valign="top" width="100%"> + <span class="small"> + <?php + + echo string_attribute( $row['summary'] ) + .'<br />'; + # show project name if viewing 'all projects' or bug is in subproject + if ( ON == config_get( 'show_bug_project_links' ) && + helper_get_current_project() != $row['project_id'] ) { + echo '['. project_get_name($row['project_id']) .'] '; + } + + echo string_display( $row['category'] ); + + $t_last_updated = date( config_get( 'normal_date_format' ), $row['last_updated'] ); + + if ( $row['last_updated'] > strtotime( '-'. $p_custom_filter['highlight_changed'] .' hours' ) ) { + echo ' - <b>' . $t_last_updated . '</b>'; + } else { + echo ' - ' . $t_last_updated; + } + + ?> + </span> + </td> + </tr> + <?php + } + ?> + </table> + + <? + + } + + /** * The following functions each print out an individual filter field. Index: core/html_api.php =================================================================== RCS file: /cvsroot/mantisbt/mantisbt/core/html_api.php,v retrieving revision 1.219 diff -u -b -r1.219 html_api.php --- core/html_api.php 22 Oct 2007 07:05:45 -0000 1.219 +++ core/html_api.php 23 Oct 2007 19:23:21 -0000 @@ -750,18 +750,25 @@ function print_account_menu( $p_page='' ) { $t_account_page = 'account_page.php'; $t_account_prefs_page = 'account_prefs_page.php'; + $t_account_my_view_page = 'account_my_view_page.php'; $t_account_profile_menu_page = 'account_prof_menu_page.php'; $t_account_sponsor_page = 'account_sponsor_page.php'; switch ( $p_page ) { case $t_account_page : $t_account_page = ''; break; case $t_account_prefs_page : $t_account_prefs_page = ''; break; + case $t_account_my_view_page : $t_account_my_view_page = ''; break; case $t_account_profile_menu_page : $t_account_profile_menu_page = ''; break; case $t_account_sponsor_page : $t_account_sponsor_page = ''; break; } print_bracket_link( $t_account_page, lang_get( 'account_link' ) ); print_bracket_link( $t_account_prefs_page, lang_get( 'change_preferences_link' ) ); + + + if (access_has_global_level(config_get('custom_my_view_threshold'))) + print_bracket_link( $t_account_my_view_page, lang_get( 'my_view_link' ) ); + if ( access_has_project_level( config_get( 'add_profile_threshold' ) ) ) { print_bracket_link( $t_account_profile_menu_page, lang_get( 'manage_profiles_link' ) ); } Index: lang/strings_english.txt =================================================================== RCS file: /cvsroot/mantisbt/mantisbt/lang/strings_english.txt,v retrieving revision 1.316 diff -u -b -r1.316 strings_english.txt --- lang/strings_english.txt 22 Sep 2007 22:51:15 -0000 1.316 +++ lang/strings_english.txt 23 Oct 2007 19:23:21 -0000 @@ -1432,4 +1432,10 @@ $s_graph_page = 'Graph Bug History'; $s_graph_bug_page_link = 'Graph'; +# Custom Filtering +$s_add_my_view_filter = 'Add Filter to My View'; +$s_my_view_filters = 'My View Filters'; +$s_predefined_filters = 'Predefined Filters'; +$s_custom_filters = 'Custom Filters'; + ?> configurable_my_view.patch (34,142 bytes)
Index: config_defaults_inc.php =================================================================== --- config_defaults_inc.php (revision 5305) +++ config_defaults_inc.php (working copy) @@ -1427,6 +1427,7 @@ $g_db_table['mantis_custom_field_string_table'] = '%db_table_prefix%_custom_field_string%db_table_suffix%'; $g_db_table['mantis_upgrade_table'] = '%db_table_prefix%_upgrade%db_table_suffix%'; $g_db_table['mantis_filters_table'] = '%db_table_prefix%_filters%db_table_suffix%'; + $g_db_table['mantis_filters_my_view_table'] = '%db_table_prefix%_filters_my_view%db_table_suffix%'; $g_db_table['mantis_sponsorship_table'] = '%db_table_prefix%_sponsorship%db_table_suffix%'; $g_db_table['mantis_tokens_table'] = '%db_table_prefix%_tokens%db_table_suffix%'; $g_db_table['mantis_project_hierarchy_table'] = '%db_table_prefix%_project_hierarchy%db_table_suffix%'; @@ -1756,20 +1757,42 @@ # Boxes to be shown and their order # A box that is not to be shown can have its value set to 0 $g_my_view_boxes = array ( - 'assigned' => '1', - 'unassigned' => '2', - 'reported' => '3', - 'resolved' => '4', - 'recent_mod' => '5', - 'monitored' => '6', - 'feedback' => '0', - 'verify' => '0' + FILTER_ASSIGNED, + FILTER_UNASSIGNED, + FILTER_REPORTED, + FILTER_RESOLVED, + FILTER_RECENT_MOD, + FILTER_MONITORED, + // FILTER_FEEDBACK, + // FILTER_VERIFY, ); + # Allows you to set a custom "My View" on an access level basis + # To do this, set the key of the first dimension to the access level, then + # make the value an array of filters. For example: + # $g_my_view_access_boxes = array ( + # ADMINISTRATOR => array( + # FILTER_UNASSIGNED, + # FILTER_ASSIGNED + # ), + # REPORTER => array( + # FILTER_REPORTED, + # FILTER_MONITORED + # ) + # ); + $g_my_view_access_boxes = array ( + ); + + # threshold needed to customize the 'My View' screen + $g_custom_my_view_threshold = ANYBODY; + # Toggle whether 'My View' boxes are shown in a fixed position (i.e. adjacent boxes start at the same vertical position) $g_my_view_boxes_fixed_position = ON; + # Toggle whether 'My View' boxes are shown in a fixed position (i.e. adjacent boxes start at the same vertical position) + $g_my_view_boxes_fixed_position = ON; + ###################### # RSS Feeds ###################### Index: core/constant_inc.php =================================================================== --- core/constant_inc.php (revision 5305) +++ core/constant_inc.php (working copy) @@ -354,6 +354,16 @@ define( 'FILTER_POSITION_BOTTOM', 2 ); define( 'FILTER_POSITION_BOTH', 3 ); // FILTER_POSITION_TOP | FILTER_POSITION_BOTTOM (bitwise OR) + # Default Filters + define( 'FILTER_ASSIGNED', -1 ); + define( 'FILTER_RECENT_MOD', -2 ); + define( 'FILTER_REPORTED', -3 ); + define( 'FILTER_RESOLVED', -4 ); + define( 'FILTER_UNASSIGNED', -5 ); + define( 'FILTER_MONITORED', -6 ); + define( 'FILTER_FEEDBACK', -7 ); + define( 'FILTER_VERIFY', -8 ); + # Flags for settings E-mail categories define( 'EMAIL_CATEGORY_PROJECT_CATEGORY', 1); Index: core/filter_api.php =================================================================== --- core/filter_api.php (revision 5305) +++ core/filter_api.php (working copy) @@ -3371,8 +3371,612 @@ # all of our filter values are now guaranteed to be there, and correct. return $p_filter_arr; } + + # Returns an array of the pre-defined filters + function filter_get_predefined ( $p_filter = false ) { + static $cache; + if (!isset($cache)) { + $t_bug_resolved_status_threshold = config_get( 'bug_resolved_status_threshold' ); + $t_hide_status_default = config_get( 'hide_status_default' ); + $t_default_show_changed = config_get( 'default_show_changed' ); + $t_current_user_id = auth_get_current_user_id(); + + $cache = array(); + + $cache[ FILTER_ASSIGNED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => $t_current_user_id ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_bug_resolved_status_threshold ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_assigned' ), + 'url' => 'handler_id=' . $t_current_user_id . '&hide_status=' . $t_bug_resolved_status_threshold, + 'id' => FILTER_ASSIGNED + ); + + $cache[ FILTER_RECENT_MOD ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => META_FILTER_NONE ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_recent_mod' ), + 'url' => 'hide_status=none', + 'id' => FILTER_RECENT_MOD + ); + + $cache[ FILTER_REPORTED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => $t_current_user_id ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'sort' => 'last_updated', + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_reported' ), + 'url' => 'reporter_id=' . $t_current_user_id . '&hide_status=' . $t_hide_status_default, + 'id' => FILTER_REPORTED + ); + + $cache[ FILTER_RESOLVED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => $t_bug_resolved_status_threshold ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_resolved' ), + 'url' => 'show_status=' . $t_bug_resolved_status_threshold . '&hide_status=' . $t_bug_resolved_status_threshold, + 'id' => FILTER_RESOLVED + ); + + $cache[ FILTER_UNASSIGNED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => META_FILTER_NONE ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_unassigned' ), + 'url' => 'handler_id=[none]' . '&hide_status=' . $t_hide_status_default, + 'id' => FILTER_UNASSIGNED + ); + + $cache[ FILTER_MONITORED ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => META_FILTER_ANY ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => META_FILTER_ANY ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => $t_current_user_id ) + ), + 'name' => lang_get( 'my_view_title_monitored' ), + 'url' => 'user_monitor=' . $t_current_user_id . '&hide_status=' . $t_hide_status_default, + 'id' => FILTER_MONITORED + ); + + + $cache[ FILTER_FEEDBACK ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => FEEDBACK ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => $t_current_user_id ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_feedback' ), + 'url' => 'reporter_id=' . $t_current_user_id . '&show_status=' . FEEDBACK . '&hide_status=' . $t_hide_status_default, + 'id' => FILTER_FEEDBACK + ); + + $cache[ FILTER_VERIFY ] = array( + 'filter' => array( + 'show_category' => Array ( '0' => META_FILTER_ANY ), + 'show_severity' => Array ( '0' => META_FILTER_ANY ), + 'show_status' => Array ( '0' => $t_bug_resolved_status_threshold ), + 'highlight_changed' => $t_default_show_changed, + 'reporter_id' => Array ( '0' => $t_current_user_id ), + 'handler_id' => Array ( '0' => META_FILTER_ANY ), + 'show_resolution' => Array ( '0' => META_FILTER_ANY ), + 'show_build' => Array ( '0' => META_FILTER_ANY ), + 'show_version' => Array ( '0' => META_FILTER_ANY ), + 'hide_status' => Array ( '0' => $t_hide_status_default ), + 'user_monitor' => Array ( '0' => META_FILTER_ANY ) + ), + 'name' => lang_get( 'my_view_title_verify' ), + 'url' => 'reporter_id=' . $t_current_user_id . '&show_status=' . $t_bug_resolved_status_threshold, + 'id' => FILTER_VERIFY + ); + + } + + if (is_bool($p_filter) || empty($p_filter)) + return $cache; + else if (array_key_exists($p_filter, $cache)) + return $cache[ $p_filter ]; + else + return false; + + } + + # Returns an array of the default filters for my view + function filter_get_default_my_view ( $p_project_id = ALL_PROJECTS ) { + + $t_current_user_id = auth_get_current_user_id(); + + # Pull the list of My View boxes per access level + $t_access_boxes = config_get( 'my_view_access_boxes' ); + $t_user_level = access_get_project_level( $p_project_id ); + + # If they don't have a custom view by access level, give them the default + if (array_key_exists($t_user_level, $t_access_boxes)) + $t_config_boxes = $t_access_boxes[ $t_user_level ]; + else + $t_config_boxes = config_get( 'my_view_boxes' ); + + + $return = array(); + + foreach ($t_config_boxes AS $box) { + + # if box is less than 0, that means it's a predefined box + if ($box < 0) { + $return[ $box ] = filter_get_predefined( $box ); + } + + # otherwise, we need to get this filter from the database + else { + $return[ $box ] = filter_get_row( $box ); + if (!$return[ $box ]) + unset ($return[ $box ]); + else + $return[ $box ]['filter'] = filter_deserialize( $return[ $box ]['filter_string'] ); + } + } + + # don't display "Assigned to Me" bugs to users that bugs can't be assigned to + if ( current_user_is_anonymous() || user_get_assigned_open_bug_count( $t_current_user_id, $p_project_id ) == 0 ) + unset( $return[FILTER_ASSIGNED] ); + + # don't display "Monitored by Me" bugs to users that can't monitor bugs + if ( current_user_is_anonymous() OR !access_has_project_level( config_get( 'monitor_bug_threshold' ), $p_project_id, $t_current_user_id ) ) + unset( $return[FILTER_MONITORED] ); + + + # don't display "Reported by Me" bugs to users that can't report bugs + if ( current_user_is_anonymous() || !access_has_project_level( config_get( 'report_bug_threshold' ), $p_project_id, $t_current_user_id ) ) { + unset( $return[FILTER_REPORTED] ); + unset( $return[FILTER_FEEDBACK] ); + unset( $return[FILTER_VERIFY] ); + } + + return $return; + } + + # Returns a list of filters specific to a user for their my_view page + function filter_db_get_my_view ( $p_user_id = false ) { + + if (is_bool($p_user_id) || empty($p_user_id)) + $p_user_id = auth_get_current_user_id(); + + $t_filters_my_view_table = db_get_table( 'mantis_filters_my_view_table' ); + $t_filters_table = db_get_table( 'mantis_filters_table' ); + + $t_user_id = db_prepare_int( $p_user_id ); + + $query = "SELECT * + + FROM $t_filters_my_view_table + AS FMV + + LEFT JOIN $t_filters_table + AS FM + ON FMV.filter_id = FM.id + + WHERE FMV.user_id = $t_user_id + AND ( " + + # If the user doesn't have access rights to stored queries, return only predefined filters + .(access_has_project_level( config_get( 'stored_query_use_threshold' ) )?"FM.id IS NOT NULL OR ":"") + + ." FMV.filter_id < 0 ) + ORDER BY FMV.sequence ASC"; + + $result = db_query( $query ); + $query_count = db_num_rows( $result ); + + if ($query_count <= 0) + return array(); + + $t_filter_arr = array(); + + for ( $i = 0; $i < $query_count; $i++ ) { + $row = db_fetch_array( $result ); + + # if it is less than 0, that means it is a predefined filter + if (intval($row['filter_id']) < 0) { + $t_filter_arr[ intval($row['filter_id']) ] = filter_get_predefined( intval($row['filter_id']) ); + } + else { + $t_filter_arr[ intval($row['filter_id']) ] = $row; + $t_filter_arr[ intval($row['filter_id']) ]['filter'] = filter_deserialize( $row['filter_string'] ); + } + + // Perform some sequence cleanup + if ($row['sequence'] != $i + 1) + filter_set_filter_sequence( $i + 1, $row['filter_id'], $t_user_id ); + + $t_filter_arr[ intval($row['filter_id']) ]['sequence'] = $i + 1; + } + + return $t_filter_arr; + } + + # Returns the next sequence value for a user + function filter_get_next_sequence ( $p_user_id ) { + + $t_filters_my_view_table = db_get_table( 'mantis_filters_my_view_table' ); + $t_user_id = db_prepare_int( $p_user_id ); + + $query = "SELECT MAX(sequence) AS max + FROM $t_filters_my_view_table + WHERE user_id = ". $t_user_id; + + $result = db_query($query); + $row = db_fetch_array( $result ); + + return intval($row['max']) + 1; + } + + # Returns boolean whether a filter exists + # $p_predefined allows you to set whether or not a predefined filter ID will return true or not + function filter_exists ( $p_filter_id, $p_user_id = null, $p_project_id = null, $p_predefined = true) { + + # If less than zero, it must be a predefined filter ID + if ($p_filter_id < 0) { + if ($p_predefined && filter_get_predefined($p_filter_id)) + return true; + else + return false; + } + + # I used filter_cache_row instead of filter_get_row so I can control the errors + $filter = filter_cache_row( $p_filter_id, false ); + + if (!$filter) + return false; + + else if (!is_null($p_user_id) && $p_user_id != $filter['user_id']) + return false; + + else if (!is_null($p_project_id) && $p_project_id != $filter['project_id']) + return false; + + return true; + } + + # Removes a filter from a users 'My View' + function filter_remove_from_my_view ( $p_filter_id, $p_user_id = null ) { + + if ( empty($p_user_id) || is_bool($p_user_id) ) + $p_user_id = auth_get_current_user_id(); + + $t_filters_my_view_table = db_get_table( 'mantis_filters_my_view_table' ); + + $c_user_id = db_prepare_int( $p_user_id ); + $c_filter_id = db_prepare_int( $p_filter_id ); + + # First, we need to get the sequence of this filter so we can adjust order + $query = "SELECT sequence + FROM $t_filters_my_view_table + WHERE filter_id = $c_filter_id + AND user_id = $c_user_id + LIMIT 1"; + + $result = db_query($query); + + if (db_num_rows( $result ) <= 0) + return true; + + $t_sequence = db_fetch_array( $result ); + $t_sequence = db_prepare_int($t_sequence['sequence']); + + $query = "DELETE FROM $t_filters_my_view_table + WHERE filter_id = $c_filter_id + AND user_id = $c_user_id + LIMIT 1"; + + db_query($query); + + $query = "UPDATE $t_filters_my_view_table + SET sequence = sequence - 1 + WHERE sequence > $t_sequence + AND user_id = $c_user_id"; + + db_query( $query ); + + return true; + } + + # adds a new filter to a users 'My View' + function filter_add_to_my_view ($p_filter_id, $p_user_id = null) { + + if ( empty($p_user_id) || is_bool($p_user_id) ) + $p_user_id = auth_get_current_user_id(); + + $c_filter_id = db_prepare_int( $p_filter_id ); + $c_user_id = db_prepare_int( $p_user_id ); + + # We can't add a non-existent filter + if ( !filter_exists( $c_filter_id, $c_user_id ) ) + return false; + + $t_filters_my_view_table = db_get_table( 'mantis_filters_my_view_table' ); + + $query = "INSERT INTO $t_filters_my_view_table + SET filter_id = $c_filter_id, + user_id = $c_user_id, + sequence = ". filter_get_next_sequence( $c_user_id ); + + db_query( $query ); + + return true; + + } + + # updates the sequence for a filter + function filter_set_filter_sequence ($p_sequence, $p_filter_id, $p_user_id = null) { + + if ( empty($p_user_id) || is_bool($p_user_id) ) + $p_user_id = auth_get_current_user_id(); + + $c_filter_id = db_prepare_int( $p_filter_id ); + $c_user_id = db_prepare_int( $p_user_id ); + $c_sequence = db_prepare_int( $p_sequence ); + + $t_filters_my_view_table = db_get_table( 'mantis_filters_my_view_table' ); + + $query = "UPDATE $t_filters_my_view_table + SET sequence = $c_sequence + WHERE filter_id = $c_filter_id + AND user_id = $c_user_id + LIMIT 1"; + + db_query( $query ); + + } + + # Prints a select box for adding filters + function print_filter_my_view_inactive ( $p_show_empty = true ) { + + $p_user_id = auth_get_current_user_id(); + + # Get the filters the user currently displays on their My View + $t_active = array_keys( filter_db_get_my_view() ); + + # Get all the predefined filters, then weed out the ones they have already set + $t_predefined = filter_get_predefined(); + foreach ($t_predefined AS $key => $filter) { + if (in_array($key, $t_active)) + unset($t_predefined[$key]); + else + $t_predefined[ $key ] = $filter['name']; + } + + if ( access_has_project_level( config_get( 'stored_query_use_threshold' ) ) ) { + + # Get all the available filters, then weed out the ones already in use + $t_available = filter_db_get_available_queries( ALL_PROJECTS, $p_user_id ); + foreach ($t_available AS $key => $filter) { + if (in_array($key, $t_active)) + unset($t_available[$key]); + } + + } else { + $t_available = array(); + } + + # If both lists are empty, don't show the form unless they want us to + if (count($t_predefined) <= 0 && count($t_available) <= 0 && !$p_show_empty) + return; + + ?> + <form action="account_my_view_add.php" method="post"> + <select name="filter_id"> + <?php + + if (count($t_available) > 0) { + echo "<optgroup label='". lang_get('custom_filters') ."'>"; + + foreach ($t_available AS $f_key => $f_title) { + echo "<option value='". $f_key ."'>" . string_display_line($f_title) . "</option>"; + } + echo "</optgroup>"; + } + + if (count($t_predefined) > 0) { + echo "<optgroup label='". lang_get('predefined_filters') ."'>"; + + foreach ($t_predefined AS $f_key => $f_title) { + echo "<option value='". $f_key ."'>". string_display_line($f_title) ."</option>"; + } + echo "</optgroup>"; + } + + ?> + </select> + <input type="submit" class="button" value="<?php echo lang_get('add_my_view_filter'); ?>" /> + </form> + <?php + } + + # Prints a my view box from a set of query results + function print_filter_my_view_box ( $p_title, $p_page_number, $p_per_page, $p_custom_filter, + $p_project_id, $p_user_id, $p_show_sticky = null, $p_url = null, $p_show_empty = TRUE ) { + + $t_page_count = 0; + $t_bug_count = 0; + + # Run the filter query + $result = filter_get_bug_rows( $p_page_number, $p_per_page, $t_page_count, $t_bug_count, + $p_custom_filter, $p_project_id, $p_user_id, $p_show_sticky ); + + if (count($result) == 0 && !$p_show_empty) + return; + + if (is_null($p_url)) + $p_url = filter_get_url( $p_custom_filter ); + + $t_icon_path = config_get( 'icon_path' ); + $t_update_bug_threshold = config_get( 'update_bug_threshold' ); + + ?> + <table class="width100" cellspacing="1"> + <tr> + <td class="form-title" colspan="2"> + <a class="subtle" href="<?php echo $p_url; ?>"><?php echo string_display_line($p_title); ?></a> + [<a class="subtle" href="<?php echo $p_url; ?>" target="_blank">^</a>] + ( <?php echo string_display_line(project_get_name( $p_project_id )); ?> ) + <?php + if ( count( $result ) > 0 ) { + $v_start = $p_per_page * ($p_page_number - 1) + 1; + $v_end = $v_start + count( $result ) - 1; + } else { + $v_start = 0; + $v_end = 0; + } + echo "($v_start - $v_end / $t_bug_count)"; + ?> + </td> + </tr> + <?php + foreach ($result AS $row) { + + ?> + <tr bgcolor="<?php echo get_status_color($row['status']) ?>"> + + <td class="center"> + <span class="small"> + <?php + print_bug_link( $row['id'] ); + + echo '<br />'; + + if ( !bug_is_readonly( $row['id'] ) && access_has_bug_level( $t_update_bug_threshold, $row['id'] ) ) { + echo '<a href="' . string_get_bug_update_url( $row['id'] ) . '"><img border="0" src="' . $t_icon_path . 'update.png' . '" alt="' . lang_get( 'update_bug_button' ) . '" /></a>'; + } + + if ( ON == config_get( 'show_priority_text' ) ) { + print_formatted_priority_string( $row['status'], $row['priority'] ); + } else { + print_status_icon( $row['priority'] ); + } + + $t_attachment_count = 0; + if ( ( file_can_view_bug_attachments( $row['id'] ) ) ) { + $t_attachment_count = file_bug_attachment_count( $row['id'] ); + } + + if ( 0 < $t_attachment_count ) { + echo '<a href="' . string_get_bug_view_url( $row['id'] ) . '#attachments">'; + echo '<img border="0" src="' . $t_icon_path . 'attachment.png' . '"'; + echo ' alt="' . lang_get( 'attachment_alt' ) . '"'; + echo ' title="' . $t_attachment_count . ' ' . lang_get( 'attachments' ) . '"'; + echo ' />'; + echo '</a>'; + } + if ( VS_PRIVATE == $row['view_state'] ) { + echo '<img src="' . $t_icon_path . 'protected.gif" width="8" height="15" alt="' . lang_get( 'private' ) . '" />'; + } + ?> + </span> + </td> + <td class="left" valign="top" width="100%"> + <span class="small"> + <?php + + echo string_attribute( $row['summary'] ) + .'<br />'; + # show project name if viewing 'all projects' or bug is in subproject + if ( ON == config_get( 'show_bug_project_links' ) && + helper_get_current_project() != $row['project_id'] ) { + echo '['. project_get_name($row['project_id']) .'] '; + } + + echo string_display( $row['category'] ); + + $t_last_updated = date( config_get( 'normal_date_format' ), $row['last_updated'] ); + + if ( $row['last_updated'] > strtotime( '-'. $p_custom_filter['highlight_changed'] .' hours' ) ) { + echo ' - <b>' . $t_last_updated . '</b>'; + } else { + echo ' - ' . $t_last_updated; + } + + ?> + </span> + </td> + </tr> + <?php + } + ?> + </table> + + <? + + } + /** * The following functions each print out an individual filter field. * They are derived from view_filters_page.php Index: core/html_api.php =================================================================== --- core/html_api.php (revision 5305) +++ core/html_api.php (working copy) @@ -841,6 +841,7 @@ function print_account_menu( $p_page='' ) { $t_account_page = 'account_page.php'; $t_account_prefs_page = 'account_prefs_page.php'; + $t_account_my_view_page = 'account_my_view_page.php'; $t_account_profile_menu_page = 'account_prof_menu_page.php'; $t_account_sponsor_page = 'account_sponsor_page.php'; $t_account_manage_columns_page = 'account_manage_columns_page.php'; @@ -852,6 +853,9 @@ case $t_account_prefs_page: $t_account_prefs_page = ''; break; + case $t_account_my_view_page: + $t_account_my_view_page = ''; + break; case $t_account_profile_menu_page: $t_account_profile_menu_page = ''; break; @@ -865,6 +869,8 @@ print_bracket_link( $t_account_page, lang_get( 'account_link' ) ); print_bracket_link( $t_account_prefs_page, lang_get( 'change_preferences_link' ) ); + if (access_has_global_level(config_get('custom_my_view_threshold'))) + print_bracket_link( $t_account_my_view_page, lang_get( 'my_view_link' ) ); print_bracket_link( $t_account_manage_columns_page, lang_get( 'manage_columns_config' ) ); if ( access_has_project_level( config_get( 'add_profile_threshold' ) ) ) { Index: lang/strings_english.txt =================================================================== --- lang/strings_english.txt (revision 5305) +++ lang/strings_english.txt (working copy) @@ -1528,4 +1528,9 @@ #account_view_page.php $s_view_account_title = 'User Information'; +# Custom Filtering +$s_add_my_view_filter = 'Add Filter to My View'; +$s_my_view_filters = 'My View Filters'; +$s_predefined_filters = 'Predefined Filters'; +$s_custom_filters = 'Custom Filters'; ?> Index: my_view_page.php =================================================================== --- my_view_page.php (revision 5305) +++ my_view_page.php (working copy) @@ -29,6 +29,7 @@ require_once( $t_core_path . 'compress_api.php' ); require_once( $t_core_path . 'filter_api.php' ); require_once( $t_core_path . 'last_visited_api.php' ); + require_once( $t_core_path . 'icon_api.php' ); auth_ensure_user_authenticated(); @@ -55,11 +56,6 @@ $t_bug_count = null; $t_page_count = null; - $t_boxes = config_get( 'my_view_boxes' ); - asort ($t_boxes); - reset ($t_boxes); - #print_r ($t_boxes); - $t_project_id = helper_get_current_project(); ?> @@ -79,88 +75,115 @@ ?> <?php - $t_number_of_boxes = count ( $t_boxes ); $t_boxes_position = config_get( 'my_view_boxes_fixed_position' ); + $t_custom_my_view_threshold = config_get('custom_my_view_threshold'); + + # Make sure they have access to define a custom 'my view' + if (access_has_global_level($t_custom_my_view_threshold)) { + # Get the list of custom my_view filters + $t_filters = filter_db_get_my_view( $t_current_user_id, TRUE ); + + # If they set no custom filters, then get the default view + if (count($t_filters) <= 0) + $t_filters = filter_get_default_my_view( $t_project_id ); + + } else { + $t_filters = filter_get_default_my_view( $t_project_id ); + } + + $t_number_of_boxes = count($t_filters); + $t_counter = 0; - while (list ($t_box_title, $t_box_display) = each ($t_boxes)) { - # don't display bugs that are set as 0 - if ($t_box_display == 0) { - $t_number_of_boxes = $t_number_of_boxes - 1; - } + foreach ($t_filters AS $filter) { + $t_counter++; - # don't display "Assigned to Me" bugs to users that bugs can't be assigned to - else if ( $t_box_title == 'assigned' && ( current_user_is_anonymous() OR user_get_assigned_open_bug_count( $t_current_user_id, $t_project_id ) == 0 ) ) { - $t_number_of_boxes = $t_number_of_boxes - 1; - } + # If the filter is for a specific project, only use that project + if (array_key_exists('project_id', $filter) && $filter['project_id'] != 0) + $t_filter_project_id = $filter['project_id']; + else + $t_filter_project_id = $t_project_id; - # don't display "Monitored by Me" bugs to users that can't monitor bugs - else if ( $t_box_title == 'monitored' && ( current_user_is_anonymous() OR !access_has_project_level( config_get( 'monitor_bug_threshold' ), $t_project_id, $t_current_user_id ) ) ) { - $t_number_of_boxes = $t_number_of_boxes - 1; - } + if ( ON == $t_boxes_position ) { + # for even box number start new row and column + if ( 1 == $t_counter %2 ) { + echo '<tr><td valign="top" width="50%">'; - # don't display "Reported by Me" bugs to users that can't report bugs - else if ( in_array( $t_box_title, array( 'reported', 'feedback', 'verify' ) ) && - ( current_user_is_anonymous() OR !access_has_project_level( config_get( 'report_bug_threshold' ), $t_project_id, $t_current_user_id ) ) ) { - $t_number_of_boxes = $t_number_of_boxes - 1; - } + print_filter_my_view_box( + $filter['name'], + $f_page_number, + $t_per_page, + $filter['filter'], + $t_filter_project_id, + $t_current_user_id, + null, + array_key_exists('url', $filter)?"view_all_set.php?type=1&temporary=y&". $filter['url']:null + ); + echo '</td>'; + } - # display the box - else { - $t_counter++; + # for odd box number only start new column + elseif ( 0 == $t_counter %2 ) { + echo '<td valign="top" width="50%">'; - # check the style of displaying boxes - fixed (ie. each box in a separate table cell) or not - if ( ON == $t_boxes_position ) { - # for even box number start new row and column - if ( 1 == $t_counter%2 ) { - echo '<tr><td valign="top" width="50%">'; - include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'my_view_inc.php' ); - echo '</td>'; - } + print_filter_my_view_box( + $filter['name'], + $f_page_number, + $t_per_page, + $filter['filter'], + $t_filter_project_id, + $t_current_user_id, + null, + array_key_exists('url', $filter)?"view_all_set.php?type=1&temporary=y&". $filter['url']:null + ); - # for odd box number only start new column - elseif ( 0 == $t_counter%2 ) { - echo '<td valign="top" width="50%">'; - include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'my_view_inc.php' ); - echo '</td></tr>'; - } + echo '</td></tr>'; + } - # for odd number of box display one empty table cell in second column - if ( ( $t_counter == $t_number_of_boxes ) && 1 == $t_counter%2 ) { - echo '<td valign="top" width="50%"></td></tr>'; - } + # for odd number of box display one empty table cell in second column + if ( ( $t_counter == $t_number_of_boxes ) && 1 == $t_counter ) { + echo '<td valign="top" width="50%"></td></tr>'; } - else if ( OFF == $t_boxes_position ) { - # start new table row and column for first box - if ( 1 == $t_counter ) { - echo '<tr><td valign="top" width="50%">'; - } - # start new table column for the second half of boxes - if ( $t_counter == ceil ($t_number_of_boxes/2) + 1 ) { - echo '<td valign="top" width="50%">'; - } + } + else { + # start new table row and column for first box + if ( 1 == $t_counter ) { + echo '<tr><td valign="top" width="50%">'; + } - # display the required box - include( dirname( __FILE__ ) . DIRECTORY_SEPARATOR . 'core' . DIRECTORY_SEPARATOR . 'my_view_inc.php' ); - echo '<br />'; + # start new table column for the second half of boxes + if ( $t_counter == ceil ($t_number_of_boxes/2) + 1 ) { + echo '<td valign="top" width="50%">'; + } - # close the first column for first half of boxes - if ( $t_counter == ceil ($t_number_of_boxes/2) ) { - echo '</td>'; - } + # display the required box - # close the table row after all of the boxes - if ( $t_counter == $t_number_of_boxes ) { - echo '</td></tr>'; - } + print_filter_my_view_box( + $filter['name'], + $f_page_number, + $t_per_page, + $filter['filter'], + $t_filter_project_id, + $t_current_user_id, + null, + array_key_exists('url', $filter)?"view_all_set.php?type=1&temporary=y&". $filter['url']:null + ); + + echo '<br />'; + + # close the first column for first half of boxes + if ( $t_counter == ceil ($t_number_of_boxes/2) ) { + echo '</td>'; } + + # close the table row after all of the boxes + if ( $t_counter == $t_number_of_boxes ) { + echo '</td></tr>'; + } } } -?> - -<?php if ( $t_status_legend_position == STATUS_LEGEND_POSITION_BOTTOM || $t_status_legend_position == STATUS_LEGEND_POSITION_BOTH ) { echo '<tr>'; echo '<td colspan="2">'; | ||||
has duplicate | 0007065 | closed | dregad | Customize box layout on My View page |
has duplicate | 0007025 | closed | giallu | Would like to create filters and have them visible from the My View page |
has duplicate | 0013348 | closed | atrol | Change the directory of closed bugs |
has duplicate | 0013358 | closed | atrol | Resolved items showing up in the Unassigned view |
has duplicate | 0005048 | closed | dregad | Sort My View by _____ |
has duplicate | 0005832 | closed | dregad | My View settings on a per-user basis |
has duplicate | 0006412 | closed | dregad | My View be created by custom filters. |
has duplicate | 0014007 | closed | atrol | Custom fileds in my_view_page |
has duplicate | 0006480 | closed | dregad | custom "My View" page for each user or access level |
has duplicate | 0015741 | closed | atrol | my_view_page.php cannot be customized |
has duplicate | 0025716 | closed | atrol | Feature request: Option to customize My View page |
has duplicate | 0026729 | closed | atrol | Change issue display order on "My vision" |
has duplicate | 0004945 | closed | dregad | Customisation for My-View Page |
has duplicate | 0027111 | closed | dregad | Change the status displayed in [My View] |
has duplicate | 0008008 | closed | dregad | extending "my_view_page.php" with self defined filters (including custom filter fields) |
related to | 0021895 | new | Support saved filters in My View page |
I think it would be a good idea for users to add My View boxes based on filters that they have access to. Also to remove such boxes using some configuration page or using AJAX to close the windows. We may consider support for minimizing such windows. |
|
While implementing Mantis for my company I set-up this feature. I have attached an archive to this note with a diff file, 4 new files and a readme that describes installation and use. |
|
Can you resubmit a diff that does not contain useless add/remove blocks? Perhaps your file editor needs to be set to use Unix-style line feed like the rest of the Mantis codebase, rather than windows style carriage returns. |
|
re-uploaded |
|
I am interested in this feature, so If no one beats me on that, I will happily review/commit your code. |
|
Do you think this customization work with the last version 1.1.1? If, yes, why didn't you add this very useful feature in the last Mantis' version? Gôm |
|
I install this improve but account_my_view_page.php and my_view_page.php are empty.I don't know how I can complete data, any idea? thanks |
|
Someone know how can I execute this command (see "readme")? 3) Apply the diff file with the following command: Yes ... My Mantis is working on Windows! |
|
this feature is great. there is only one error. If a user wants to add a custom filter add by another one the page refreshes but the filter didn't append. you can fix this if you edit the function filter_add_to_my_view in filter api as follows: change if ( !filter_exists( $c_filter_id, $c_user_id ) ) |
|
I change but in "My View" the custom filters don't appear. Another idea..... |
|
i really like this feature. i made a patch (configurable_my_view.patch) against the actual trunk. You have to download the archive customMyView_v2.tar.gz and follow the readme. instead of using the diff-file of the archive use the new patch. |
|
hi all, i am running Mantis in our company 6 months ago over iSeries using Mysql, i am trying now to apply this patch but i had this error: Hmm... I can't seem to find a patch in there anywhere. could you please advice? thanks |
|
I have fixed the problem about filters of another user replacing the line: in the filter_exists function off filter_api.php This allow the public filters be added by all users |
|
This seems like an important thing to do in order to really make the my view page useful. Was there a problem with the submitted change that the development team didn't like? I applied it to 1.2.0 and with a little bit of playing around had it working. I need to do a full code review and more testing, and I'm not sure if something needs to be done to automate the addition of a database table, but I'll attach a git patch shortly if that's all this is waiting on. |
|
@cmfitch1: do you by chance have a patch that works with 1.2.2 or were you ever abel to get around to making one for 1.2.0? As an addition to this feature, it'd be great if one could also change the display order of the view boxes view user preference would be great as well. |
|
See http://github.com/daryn/mantisbt/tree/save-filter for a similar feature branch against current trunk. This feature is nearly ready to commit and could use some additional testers. |
|
Souldn't it be integrated as a plugin instead of a patch ? |
|
daryn, I had a quick look at your branch, but unfortunately it does not apply cleanly on the latest trunk... Some conflicts are trivial, but others I'm not sure what to do. Any chance you can merge it ? both modified: css/default.css |
|
A possible custom workaround for allowing access level based customization of the my view page was described in 0006480:0033235 |
|
Removed assignment. giallu will not contribute to this issue in near future. |
|
This would be a welcomed feature. In addition, I would add that the boxes on the My View page should be in a drag and droppable grid layout so users can easily reposition them. |
|