def testExtractUniqueValues_CombinedColumns(self): cols = ['priority/pri', 'owner', 'status', 'stars', 'mstone/milestone'] users_by_id = { 111: framework_views.StuffUserView(111, '*****@*****.**', True), } issue = fake.MakeTestIssue( 789, 5, 'sum 5', 'New', 111, merged_into=200001, labels='Priority-High Pri-0 Milestone-1.0 mstone-1', star_count=15) column_values = table_view_helpers.ExtractUniqueValues( cols, SEARCH_RESULTS_WITH_LABELS + [issue], users_by_id, self.config, {}) self.assertEquals(5, len(column_values)) self.assertEquals('priority/pri', column_values[0].column_name) self.assertEquals(['0', 'High', 'Low'], column_values[0].filter_values) self.assertEquals('owner', column_values[1].column_name) self.assertEquals(['*****@*****.**'], column_values[1].filter_values) self.assertEquals('status', column_values[2].column_name) self.assertEquals(['New'], column_values[2].filter_values) self.assertEquals('stars', column_values[3].column_name) self.assertEquals([1, 15], column_values[3].filter_values) self.assertEquals('mstone/milestone', column_values[4].column_name) self.assertEquals(['1', '1.0', '1.1'], column_values[4].filter_values)
def testExtractUniqueValues_ExplicitResults(self): cols = ['priority', 'owner', 'status', 'stars', 'mstone', 'foo'] users_by_id = { 111: framework_views.StuffUserView(111, '*****@*****.**', True), } column_values = table_view_helpers.ExtractUniqueValues( cols, SEARCH_RESULTS_WITH_LABELS, users_by_id, self.config, {}) self.assertEquals(len(cols), len(column_values)) self.assertEquals('priority', column_values[0].column_name) self.assertEquals(['High', 'Low'], column_values[0].filter_values) self.assertEquals('owner', column_values[1].column_name) self.assertEquals(['*****@*****.**'], column_values[1].filter_values) self.assertEquals('status', column_values[2].column_name) self.assertEquals(['New'], column_values[2].filter_values) self.assertEquals('stars', column_values[3].column_name) self.assertEquals([1], column_values[3].filter_values) self.assertEquals('mstone', column_values[4].column_name) self.assertEquals(['1', '1.1'], column_values[4].filter_values) self.assertEquals('foo', column_values[5].column_name) self.assertEquals([], column_values[5].filter_values)
def testExtractUniqueValues_NoResults(self): cols = ['type', 'priority', 'owner', 'status', 'stars', 'attachments'] column_values = table_view_helpers.ExtractUniqueValues( cols, EMPTY_SEARCH_RESULTS, {}, self.config, {}) self.assertEquals(6, len(column_values)) for index, col in enumerate(cols): self.assertEquals(index, column_values[index].col_index) self.assertEquals(col, column_values[index].column_name) self.assertEquals([], column_values[index].filter_values)
def GetTableViewData( self, mr, results, config, users_by_id, starred_iid_set, related_issues, viewable_iids_set): """EZT template values to render a Table View of issues. Args: mr: commonly used info parsed from the request. results: list of Issue PBs for the search results to be displayed. config: The ProjectIssueConfig PB for the current project. users_by_id: A dictionary {user_id: UserView} for all the users involved in results. starred_iid_set: Set of issues that the user has starred. related_issues: dict {issue_id: issue} of pre-fetched related issues. viewable_iids_set: set of issue ids that are viewable by the user. Returns: Dictionary of page data for rendering of the Table View. """ # We need ordered_columns because EZT loops have no loop-counter available. # And, we use column number in the Javascript to hide/show columns. columns = mr.col_spec.split() ordered_columns = [template_helpers.EZTItem(col_index=i, name=col) for i, col in enumerate(columns)] unshown_columns = table_view_helpers.ComputeUnshownColumns( results, columns, config, tracker_constants.OTHER_BUILT_IN_COLS) lower_columns = mr.col_spec.lower().split() lower_group_by = mr.group_by_spec.lower().split() table_data = _MakeTableData( results, starred_iid_set, lower_columns, lower_group_by, users_by_id, self.GetCellFactories(), related_issues, viewable_iids_set, config) # Used to offer easy filtering of each unique value in each column. column_values = table_view_helpers.ExtractUniqueValues( lower_columns, results, users_by_id, config, related_issues) table_view_data = { 'table_data': table_data, 'column_values': column_values, # Put ordered_columns inside a list of exactly 1 panel so that # it can work the same as the dashboard initial panel list headers. 'panels': [template_helpers.EZTItem(ordered_columns=ordered_columns)], 'unshown_columns': unshown_columns, 'cursor': mr.cursor or mr.preview, 'preview': mr.preview, 'default_colspec': tracker_constants.DEFAULT_COL_SPEC, 'default_results_per_page': tracker_constants.DEFAULT_RESULTS_PER_PAGE, 'csv_link': framework_helpers.FormatURL( [(name, mr.GetParam(name)) for name in framework_helpers.RECOGNIZED_PARAMS], 'csv', num=settings.max_artifact_search_results_per_page), 'preview_on_hover': ezt.boolean( _ShouldPreviewOnHover(mr.auth.user_pb)), } return table_view_data
def testExtractUniqueValues_ColumnsRobustness(self): cols = ['reporter', 'cc', 'owner', 'status', 'attachments'] search_results = [ tracker_pb2.Issue(), ] column_values = table_view_helpers.ExtractUniqueValues( cols, search_results, {}, self.config, {}) self.assertEquals(5, len(column_values)) for col_val in column_values: if col_val.column_name == 'attachments': self.assertEquals([0], col_val.filter_values) else: self.assertEquals([], col_val.filter_values)
def testExtractUniqueValues_DerivedValues(self): cols = ['priority', 'milestone', 'owner', 'status'] users_by_id = { 111: framework_views.StuffUserView(111, '*****@*****.**', True), 222: framework_views.StuffUserView(222, '*****@*****.**', True), 333: framework_views.StuffUserView(333, '*****@*****.**', True), } search_results = [ fake.MakeTestIssue(789, 1, 'sum 1', '', 111, labels='Priority-High Milestone-1.0', derived_labels='Milestone-2.0 Foo', derived_status='Started'), fake.MakeTestIssue( 789, 2, 'sum 2', 'New', 111, labels='Priority-High Milestone-1.0', derived_owner_id=333), # Not seen because of owner_id fake.MakeTestIssue(789, 3, 'sum 3', 'New', 0, labels='Priority-Low Milestone-1.1', derived_owner_id=222), ] column_values = table_view_helpers.ExtractUniqueValues( cols, search_results, users_by_id, self.config, {}) self.assertEquals(4, len(column_values)) self.assertEquals('priority', column_values[0].column_name) self.assertEquals(['High', 'Low'], column_values[0].filter_values) self.assertEquals('milestone', column_values[1].column_name) self.assertEquals(['1.0', '1.1', '2.0'], column_values[1].filter_values) self.assertEquals('owner', column_values[2].column_name) self.assertEquals(['*****@*****.**', '*****@*****.**'], column_values[2].filter_values) self.assertEquals('status', column_values[3].column_name) self.assertEquals(['New', 'Started'], column_values[3].filter_values)
def GetGridViewData(mr, results, config, users_by_id, starred_iid_set, grid_limited, related_issues, hotlist_context_dict=None): """EZT template values to render a Grid View of issues. Args: mr: commonly used info parsed from the request. results: The Issue PBs that are the search results to be displayed. config: The ProjectConfig PB for the project this view is in. users_by_id: A dictionary {user_id: user_view,...} for all the users involved in results. starred_iid_set: Set of issues that the user has starred. grid_limited: True if the results were limited to fit within the grid. related_issues: dict {issue_id: issue} of pre-fetched related issues. hotlist_context_dict: dict for building a hotlist grid table Returns: Dictionary for EZT template rendering of the Grid View. """ # We need ordered_columns because EZT loops have no loop-counter available. # And, we use column number in the Javascript to hide/show columns. columns = mr.col_spec.split() ordered_columns = [ template_helpers.EZTItem(col_index=i, name=col) for i, col in enumerate(columns) ] other_built_in_cols = (features_constants.OTHER_BUILT_IN_COLS if hotlist_context_dict else tracker_constants.OTHER_BUILT_IN_COLS) unshown_columns = table_view_helpers.ComputeUnshownColumns( results, columns, config, other_built_in_cols) grid_x_attr = (mr.x or config.default_x_attr or '--').lower() grid_y_attr = (mr.y or config.default_y_attr or '--').lower() all_label_values = {} for art in results: all_label_values[art.local_id] = (MakeLabelValuesDict(art)) if grid_x_attr == '--': grid_x_headings = ['All'] else: grid_x_items = table_view_helpers.ExtractUniqueValues( [grid_x_attr], results, users_by_id, config, related_issues, hotlist_context_dict=hotlist_context_dict) grid_x_headings = grid_x_items[0].filter_values if AnyArtifactHasNoAttr(results, grid_x_attr, users_by_id, all_label_values, config, related_issues, hotlist_context_dict=hotlist_context_dict): grid_x_headings.append(framework_constants.NO_VALUES) grid_x_headings = SortGridHeadings(grid_x_attr, grid_x_headings, users_by_id, config, tracker_helpers.SORTABLE_FIELDS) if grid_y_attr == '--': grid_y_headings = ['All'] else: grid_y_items = table_view_helpers.ExtractUniqueValues( [grid_y_attr], results, users_by_id, config, related_issues, hotlist_context_dict=hotlist_context_dict) grid_y_headings = grid_y_items[0].filter_values if AnyArtifactHasNoAttr(results, grid_y_attr, users_by_id, all_label_values, config, related_issues, hotlist_context_dict=hotlist_context_dict): grid_y_headings.append(framework_constants.NO_VALUES) grid_y_headings = SortGridHeadings(grid_y_attr, grid_y_headings, users_by_id, config, tracker_helpers.SORTABLE_FIELDS) logging.info('grid_x_headings = %s', grid_x_headings) logging.info('grid_y_headings = %s', grid_y_headings) grid_data = PrepareForMakeGridData( results, starred_iid_set, grid_x_attr, grid_x_headings, grid_y_attr, grid_y_headings, users_by_id, all_label_values, config, related_issues, hotlist_context_dict=hotlist_context_dict) grid_axis_choice_dict = {} for oc in ordered_columns: grid_axis_choice_dict[oc.name] = True for uc in unshown_columns: grid_axis_choice_dict[uc] = True for bad_axis in tracker_constants.NOT_USED_IN_GRID_AXES: if bad_axis in grid_axis_choice_dict: del grid_axis_choice_dict[bad_axis] grid_axis_choices = grid_axis_choice_dict.keys() grid_axis_choices.sort() grid_cell_mode = mr.cells if len(results) > settings.max_tiles_in_grid and mr.cells == 'tiles': grid_cell_mode = 'ids' grid_view_data = { 'grid_limited': ezt.boolean(grid_limited), 'grid_shown': len(results), 'grid_x_headings': grid_x_headings, 'grid_y_headings': grid_y_headings, 'grid_data': grid_data, 'grid_axis_choices': grid_axis_choices, 'grid_cell_mode': grid_cell_mode, 'results': results, # Really only useful in if-any. } return grid_view_data
def CreateHotlistTableData(mr, hotlist_issues, profiler, services): """Creates the table data for the hotlistissues table.""" with profiler.Phase('getting stars'): starred_iid_set = set( services.issue_star.LookupStarredItemIDs(mr.cnxn, mr.auth.user_id)) with profiler.Phase('Computing col_spec'): mr.ComputeColSpec(mr.hotlist) issues_list = services.issue.GetIssues( mr.cnxn, [hotlist_issue.issue_id for hotlist_issue in hotlist_issues]) with profiler.Phase('Getting config'): hotlist_issues_project_ids = GetAllProjectsOfIssues( [issue for issue in issues_list]) is_cross_project = len(hotlist_issues_project_ids) > 1 config_list = GetAllConfigsOfProjects(mr.cnxn, hotlist_issues_project_ids, services) harmonized_config = tracker_bizobj.HarmonizeConfigs(config_list) (sorted_issues, hotlist_issues_context, issues_users_by_id) = GetSortedHotlistIssues(mr, hotlist_issues, issues_list, harmonized_config, profiler, services) with profiler.Phase("getting related issues"): related_iids = set() results_needing_related = sorted_issues lower_cols = mr.col_spec.lower().split() for issue in results_needing_related: if 'blockedon' in lower_cols: related_iids.update(issue.blocked_on_iids) if 'blocking' in lower_cols: related_iids.update(issue.blocking_iids) if 'mergedinto' in lower_cols: related_iids.add(issue.merged_into) related_issues_list = services.issue.GetIssues(mr.cnxn, list(related_iids)) related_issues = { issue.issue_id: issue for issue in related_issues_list } with profiler.Phase('building table'): context_for_all_issues = { issue.issue_id: hotlist_issues_context[issue.issue_id] for issue in sorted_issues } column_values = table_view_helpers.ExtractUniqueValues( mr.col_spec.lower().split(), sorted_issues, issues_users_by_id, harmonized_config, related_issues, hotlist_context_dict=context_for_all_issues) unshown_columns = table_view_helpers.ComputeUnshownColumns( sorted_issues, mr.col_spec.split(), harmonized_config, features_constants.OTHER_BUILT_IN_COLS) pagination = paginate.ArtifactPagination( mr, sorted_issues, mr.num, GetURLOfHotlist(mr.cnxn, mr.hotlist, services.user), len(sorted_issues)) sort_spec = '%s %s %s' % (mr.group_by_spec, mr.sort_spec, harmonized_config.default_sort_spec) table_data = _MakeTableData(pagination.visible_results, starred_iid_set, mr.col_spec.lower().split(), mr.group_by_spec.lower().split(), issues_users_by_id, tablecell.CELL_FACTORIES, related_issues, harmonized_config, context_for_all_issues, mr.hotlist_id, sort_spec) table_related_dict = { 'column_values': column_values, 'unshown_columns': unshown_columns, 'pagination': pagination, 'is_cross_project': is_cross_project } return table_data, table_related_dict
def testExtractUniqueValues_NoColumns(self): column_values = table_view_helpers.ExtractUniqueValues( [], SEARCH_RESULTS_WITH_LABELS, {}, self.config, {}) self.assertEquals([], column_values)
def testExtractUniqueValues_NoResults(self): cols = ['type', 'priority', 'owner', 'status', 'stars', 'attachments'] column_values = table_view_helpers.ExtractUniqueValues( cols, EMPTY_SEARCH_RESULTS, {}, self.config, {}) self.assertEquals(6, len(column_values)) for index, col in enumerate(cols): self.assertEquals(index, column_values[index].col_index) self.assertEquals(col, column_values[index].column_name) self.assertEquals([], column_values[index].filter_values) def testExtractUniqueValues_ExplicitResults(self): cols = ['priority', 'owner', 'status', 'stars', 'mstone', 'foo'] users_by_id = { 111L: framework_views.StuffUserView(111, '*****@*****.**', True), } column_values = table_view_helpers.ExtractUniqueValues( cols, SEARCH_RESULTS_WITH_LABELS, users_by_id, self.config, {}) self.assertEquals(len(cols), len(column_values)) self.assertEquals('priority', column_values[0].column_name) self.assertEquals(['High', 'Low'], column_values[0].filter_values) self.assertEquals('owner', column_values[1].column_name) self.assertEquals(['*****@*****.**'], column_values[1].filter_values) self.assertEquals('status', column_values[2].column_name) self.assertEquals(['New'], column_values[2].filter_values) self.assertEquals('stars', column_values[3].column_name) self.assertEquals([1], column_values[3].filter_values) self.assertEquals('mstone', column_values[4].column_name)
def CreateHotlistTableData(mr, hotlist_issues, services): """Creates the table data for the hotlistissues table.""" with mr.profiler.Phase('getting stars'): starred_iid_set = set( services.issue_star.LookupStarredItemIDs(mr.cnxn, mr.auth.user_id)) with mr.profiler.Phase('Computing col_spec'): mr.ComputeColSpec(mr.hotlist) issues_list = services.issue.GetIssues( mr.cnxn, [hotlist_issue.issue_id for hotlist_issue in hotlist_issues]) with mr.profiler.Phase('Getting config'): hotlist_issues_project_ids = GetAllProjectsOfIssues( [issue for issue in issues_list]) is_cross_project = len(hotlist_issues_project_ids) > 1 config_list = GetAllConfigsOfProjects(mr.cnxn, hotlist_issues_project_ids, services) harmonized_config = tracker_bizobj.HarmonizeConfigs(config_list) (sorted_issues, hotlist_issues_context, issues_users_by_id) = GetSortedHotlistIssues(mr, hotlist_issues, issues_list, harmonized_config, services) with mr.profiler.Phase("getting related issues"): related_iids = set() results_needing_related = sorted_issues lower_cols = mr.col_spec.lower().split() for issue in results_needing_related: if 'blockedon' in lower_cols: related_iids.update(issue.blocked_on_iids) if 'blocking' in lower_cols: related_iids.update(issue.blocking_iids) if 'mergedinto' in lower_cols: related_iids.add(issue.merged_into) related_issues_list = services.issue.GetIssues(mr.cnxn, list(related_iids)) related_issues = { issue.issue_id: issue for issue in related_issues_list } with mr.profiler.Phase('filtering unviewable issues'): viewable_iids_set = { issue.issue_id for issue in tracker_helpers.GetAllowedIssues( mr, [related_issues.values()], services)[0] } with mr.profiler.Phase('building table'): context_for_all_issues = { issue.issue_id: hotlist_issues_context[issue.issue_id] for issue in sorted_issues } column_values = table_view_helpers.ExtractUniqueValues( mr.col_spec.lower().split(), sorted_issues, issues_users_by_id, harmonized_config, related_issues, hotlist_context_dict=context_for_all_issues) unshown_columns = table_view_helpers.ComputeUnshownColumns( sorted_issues, mr.col_spec.split(), harmonized_config, features_constants.OTHER_BUILT_IN_COLS) url_params = [(name, mr.GetParam(name)) for name in framework_helpers.RECOGNIZED_PARAMS] # We are passing in None for the project_name because we are not operating # under any project. pagination = paginate.ArtifactPagination( sorted_issues, mr.num, mr.GetPositiveIntParam('start'), None, GetURLOfHotlist(mr.cnxn, mr.hotlist, services.user), total_count=len(sorted_issues), url_params=url_params) sort_spec = '%s %s %s' % (mr.group_by_spec, mr.sort_spec, harmonized_config.default_sort_spec) table_data = _MakeTableData( pagination.visible_results, starred_iid_set, mr.col_spec.lower().split(), mr.group_by_spec.lower().split(), issues_users_by_id, tablecell.CELL_FACTORIES, related_issues, viewable_iids_set, harmonized_config, context_for_all_issues, mr.hotlist_id, sort_spec) table_related_dict = { 'column_values': column_values, 'unshown_columns': unshown_columns, 'pagination': pagination, 'is_cross_project': is_cross_project } return table_data, table_related_dict