diff --git a/web/api/js/codechecker-api-node/dist/codechecker-api-6.57.0.tgz b/web/api/js/codechecker-api-node/dist/codechecker-api-6.57.0.tgz deleted file mode 100644 index aa78200261..0000000000 Binary files a/web/api/js/codechecker-api-node/dist/codechecker-api-6.57.0.tgz and /dev/null differ diff --git a/web/api/js/codechecker-api-node/dist/codechecker-api-6.58.0.tgz b/web/api/js/codechecker-api-node/dist/codechecker-api-6.58.0.tgz new file mode 100644 index 0000000000..a8cf8ab10b Binary files /dev/null and b/web/api/js/codechecker-api-node/dist/codechecker-api-6.58.0.tgz differ diff --git a/web/api/js/codechecker-api-node/package.json b/web/api/js/codechecker-api-node/package.json index 16a8225ce5..0bfd792add 100644 --- a/web/api/js/codechecker-api-node/package.json +++ b/web/api/js/codechecker-api-node/package.json @@ -1,6 +1,6 @@ { "name": "codechecker-api", - "version": "6.57.0", + "version": "6.58.0", "description": "Generated node.js compatible API stubs for CodeChecker server.", "main": "lib", "homepage": "https://github.com/Ericsson/codechecker", diff --git a/web/api/py/codechecker_api/dist/codechecker_api.tar.gz b/web/api/py/codechecker_api/dist/codechecker_api.tar.gz index 961798f1ce..3875d3ef7f 100644 Binary files a/web/api/py/codechecker_api/dist/codechecker_api.tar.gz and b/web/api/py/codechecker_api/dist/codechecker_api.tar.gz differ diff --git a/web/api/py/codechecker_api/setup.py b/web/api/py/codechecker_api/setup.py index 41326569c1..b369453448 100644 --- a/web/api/py/codechecker_api/setup.py +++ b/web/api/py/codechecker_api/setup.py @@ -8,7 +8,7 @@ with open('README.md', encoding='utf-8', errors="ignore") as f: long_description = f.read() -api_version = '6.57.0' +api_version = '6.58.0' setup( name='codechecker_api', diff --git a/web/api/py/codechecker_api_shared/dist/codechecker_api_shared.tar.gz b/web/api/py/codechecker_api_shared/dist/codechecker_api_shared.tar.gz index b5e79342e2..4d607e2b2f 100644 Binary files a/web/api/py/codechecker_api_shared/dist/codechecker_api_shared.tar.gz and b/web/api/py/codechecker_api_shared/dist/codechecker_api_shared.tar.gz differ diff --git a/web/api/py/codechecker_api_shared/setup.py b/web/api/py/codechecker_api_shared/setup.py index 3e4566e7f5..a4c2e70d02 100644 --- a/web/api/py/codechecker_api_shared/setup.py +++ b/web/api/py/codechecker_api_shared/setup.py @@ -8,7 +8,7 @@ with open('README.md', encoding='utf-8', errors="ignore") as f: long_description = f.read() -api_version = '6.57.0' +api_version = '6.58.0' setup( name='codechecker_api_shared', diff --git a/web/api/report_server.thrift b/web/api/report_server.thrift index 92d4f9a4db..359372e28a 100644 --- a/web/api/report_server.thrift +++ b/web/api/report_server.thrift @@ -41,6 +41,15 @@ enum Order { DESC } +/** + * Report status can show the current status of the report + * that depends on the review and thedetection status. + */ +enum ReportStatus { + OUTSTANDING, // The report is outstanding according to the review- and the detection status. + CLOSED // The report is not a valid bug according to the review- and the detection status. +} + /** * Review status is a feature which allows a user to assign one of these * statuses to a particular Report. @@ -381,6 +390,7 @@ struct ReportFilter { // [(key1, value1), (key1, value2), (key2, value3)] returns reports which // have "value1" OR "value2" for "key1" AND have "value3" for "key2". 22: optional list annotations, + 23: optional list reportStatus, // Specifying the status of the filtered reports. } struct RunReportCount { @@ -826,6 +836,16 @@ service codeCheckerDBAccess { 5: i64 offset) throws (1: codechecker_api_shared.RequestFailed requestError), + // getReportStatusCounts returns ReportStatus-count pairs + // to show the number of outstanding and closed reports. + // If the run id list is empty the metrics will be + // counted for all of the runs. + // PERMISSION: PRODUCT_VIEW + map getReportStatusCounts(1: list runIds, + 2: ReportFilter reportFilter, + 3: CompareData cmpData) + throws (1: codechecker_api_shared.RequestFailed requestError), + // If the run id list is empty the metrics will be counted // for all of the runs and in compare mode all of the runs // will be used as a baseline excluding the runs in compare data. diff --git a/web/codechecker_web/shared/version.py b/web/codechecker_web/shared/version.py index 35c50e887d..34d8826c36 100644 --- a/web/codechecker_web/shared/version.py +++ b/web/codechecker_web/shared/version.py @@ -18,7 +18,7 @@ # The newest supported minor version (value) for each supported major version # (key) in this particular build. SUPPORTED_VERSIONS = { - 6: 57 + 6: 58 } # Used by the client to automatically identify the latest major and minor diff --git a/web/server/codechecker_server/api/report_server.py b/web/server/codechecker_server/api/report_server.py index cbace677a1..5b34a6b75b 100644 --- a/web/server/codechecker_server/api/report_server.py +++ b/web/server/codechecker_server/api/report_server.py @@ -39,7 +39,7 @@ DetectionStatus, DiffType, \ Encoding, ExportData, \ Order, \ - ReportData, ReportDetails, ReviewData, ReviewStatusRule, \ + ReportData, ReportDetails, ReportStatus, ReviewData, ReviewStatusRule, \ ReviewStatusRuleFilter, ReviewStatusRuleSortMode, \ ReviewStatusRuleSortType, RunData, RunFilter, RunHistoryData, \ RunReportCount, RunSortType, RunTagCount, \ @@ -70,8 +70,8 @@ SourceComponent from .thrift_enum_helper import detection_status_enum, \ - detection_status_str, review_status_enum, review_status_str, \ - report_extended_data_type_enum + detection_status_str, report_status_enum, \ + review_status_enum, review_status_str, report_extended_data_type_enum LOG = get_logger('server') @@ -301,6 +301,28 @@ def process_report_filter( AND.append(or_(*OR)) + if report_filter.reportStatus: + dst = list(map(detection_status_str, + (DetectionStatus.NEW, + DetectionStatus.UNRESOLVED, + DetectionStatus.REOPENED))) + rst = list(map(review_status_str, + (API_ReviewStatus.UNREVIEWED, + API_ReviewStatus.CONFIRMED))) + + OR = [] + filter_query = and_( + Report.review_status.in_(rst), + Report.detection_status.in_(dst) + ) + if ReportStatus.OUTSTANDING in report_filter.reportStatus: + OR.append(filter_query) + + if ReportStatus.CLOSED in report_filter.reportStatus: + OR.append(not_(filter_query)) + + AND.append(or_(*OR)) + if report_filter.detectionStatus: dst = list(map(detection_status_str, report_filter.detectionStatus)) @@ -3255,6 +3277,60 @@ def getCheckerMsgCounts(self, run_ids, report_filter, cmp_data, limit, results = dict(checker_messages.all()) return results + @exc_to_thrift_reqfail + @timeit + def getReportStatusCounts(self, run_ids, report_filter, cmp_data): + """ + If the run id list is empty the metrics will be counted + for all of the runs and in compare mode all of the runs + will be used as a baseline excluding the runs in compare data. + """ + self.__require_view() + with DBSession(self._Session) as session: + filter_expression, join_tables = process_report_filter( + session, run_ids, report_filter, cmp_data) + + extended_table = session.query( + Report.review_status, + Report.detection_status, + Report.bug_id + ) + + if report_filter.annotations is not None: + extended_table = extended_table.outerjoin( + ReportAnnotations, + ReportAnnotations.report_id == Report.id + ) + extended_table = extended_table.group_by(Report.id) + + extended_table = apply_report_filter( + extended_table, filter_expression, join_tables) + + extended_table = extended_table.subquery() + + is_outstanding_case = get_is_opened_case(extended_table) + case_label = "isOutstanding" + + if report_filter.isUnique: + q = session.query( + is_outstanding_case.label(case_label), + func.count(extended_table.c.bug_id.distinct())) \ + .group_by(is_outstanding_case) + else: + q = session.query( + is_outstanding_case.label(case_label), + func.count(extended_table.c.bug_id)) \ + .group_by(is_outstanding_case) + + results = { + report_status_enum( + "outstanding" if isOutstanding + else "closed" + ): count for isOutstanding, count in q + } + + return results + @exc_to_thrift_reqfail @timeit def getReviewStatusCounts(self, run_ids, report_filter, cmp_data): diff --git a/web/server/codechecker_server/api/thrift_enum_helper.py b/web/server/codechecker_server/api/thrift_enum_helper.py index b635184890..868e1e2f40 100644 --- a/web/server/codechecker_server/api/thrift_enum_helper.py +++ b/web/server/codechecker_server/api/thrift_enum_helper.py @@ -11,7 +11,7 @@ from codechecker_api.codeCheckerDBAccess_v6.ttypes import DetectionStatus, \ - ExtendedReportDataType, ReviewStatus + ExtendedReportDataType, ReportStatus, ReviewStatus from codechecker_api.ProductManagement_v6.ttypes import Confidentiality @@ -119,3 +119,23 @@ def report_extended_data_type_enum(status): return ExtendedReportDataType.MACRO elif status == 'fixit': return ExtendedReportDataType.FIXIT + + +def report_status_str(status): + """ + Returns the given report status Thrift enum value. + """ + if status == ReportStatus.OUTSTANDING: + return 'outstanding' + elif status == ReportStatus.CLOSED: + return 'closed' + + +def report_status_enum(status): + """ + Converts the given report status to string. + """ + if status == 'outstanding': + return ReportStatus.OUTSTANDING + elif status == 'closed': + return ReportStatus.CLOSED diff --git a/web/server/vue-cli/package-lock.json b/web/server/vue-cli/package-lock.json index d13e5ac71f..d908b8c278 100644 --- a/web/server/vue-cli/package-lock.json +++ b/web/server/vue-cli/package-lock.json @@ -11,7 +11,7 @@ "@mdi/font": "^6.5.95", "chart.js": "^2.9.4", "chartjs-plugin-datalabels": "^0.7.0", - "codechecker-api": "file:../../api/js/codechecker-api-node/dist/codechecker-api-6.57.0.tgz", + "codechecker-api": "file:../../api/js/codechecker-api-node/dist/codechecker-api-6.58.0.tgz", "codemirror": "^5.65.0", "date-fns": "^2.28.0", "js-cookie": "^3.0.1", @@ -5113,9 +5113,9 @@ } }, "node_modules/codechecker-api": { - "version": "6.57.0", - "resolved": "file:../../api/js/codechecker-api-node/dist/codechecker-api-6.57.0.tgz", - "integrity": "sha512-cD3FgORIPnPeeuSu4xqtQjpWpoa58eaP+6XCl0WJ/C9YIyXY+j8aPwvIgtPivlUPRQWcXm+dCgr1tOxZzZ2G4A==", + "version": "6.58.0", + "resolved": "file:../../api/js/codechecker-api-node/dist/codechecker-api-6.58.0.tgz", + "integrity": "sha512-N6qK5cnLt32jnJlSyyGMmW6FCzybDljyH1RrGOZ1Gk9n1vV7WluJbC9InYWsZ5lbK7xVyIrphTKXhqC4ARKF6g==", "license": "SEE LICENSE IN LICENSE", "dependencies": { "thrift": "0.13.0-hotfix.1" @@ -21145,8 +21145,8 @@ "dev": true }, "codechecker-api": { - "version": "file:../../api/js/codechecker-api-node/dist/codechecker-api-6.57.0.tgz", - "integrity": "sha512-cD3FgORIPnPeeuSu4xqtQjpWpoa58eaP+6XCl0WJ/C9YIyXY+j8aPwvIgtPivlUPRQWcXm+dCgr1tOxZzZ2G4A==", + "version": "file:../../api/js/codechecker-api-node/dist/codechecker-api-6.58.0.tgz", + "integrity": "sha512-N6qK5cnLt32jnJlSyyGMmW6FCzybDljyH1RrGOZ1Gk9n1vV7WluJbC9InYWsZ5lbK7xVyIrphTKXhqC4ARKF6g==", "requires": { "thrift": "0.13.0-hotfix.1" } diff --git a/web/server/vue-cli/package.json b/web/server/vue-cli/package.json index dc0f834824..2239777668 100644 --- a/web/server/vue-cli/package.json +++ b/web/server/vue-cli/package.json @@ -27,7 +27,7 @@ }, "dependencies": { "@mdi/font": "^6.5.95", - "codechecker-api": "file:../../api/js/codechecker-api-node/dist/codechecker-api-6.57.0.tgz", + "codechecker-api": "file:../../api/js/codechecker-api-node/dist/codechecker-api-6.58.0.tgz", "chart.js": "^2.9.4", "chartjs-plugin-datalabels": "^0.7.0", "codemirror": "^5.65.0", diff --git a/web/server/vue-cli/src/components/Icons/ReportStatusIcon.vue b/web/server/vue-cli/src/components/Icons/ReportStatusIcon.vue new file mode 100644 index 0000000000..c549e8c586 --- /dev/null +++ b/web/server/vue-cli/src/components/Icons/ReportStatusIcon.vue @@ -0,0 +1,36 @@ + + + diff --git a/web/server/vue-cli/src/components/Icons/index.js b/web/server/vue-cli/src/components/Icons/index.js index af58ec89e0..84ab21070b 100644 --- a/web/server/vue-cli/src/components/Icons/index.js +++ b/web/server/vue-cli/src/components/Icons/index.js @@ -1,6 +1,7 @@ import AnalyzerStatisticsIcon from "./AnalyzerStatisticsIcon"; import ConfidentialityIcon from "./ConfidentialityIcon"; import DetectionStatusIcon from "./DetectionStatusIcon"; +import ReportStatusIcon from "./ReportStatusIcon"; import ReportStepEnumIcon from "./ReportStepEnumIcon"; import ReviewStatusIcon from "./ReviewStatusIcon"; import SeverityIcon from "./SeverityIcon"; @@ -10,6 +11,7 @@ export { AnalyzerStatisticsIcon, ConfidentialityIcon, DetectionStatusIcon, + ReportStatusIcon, ReportStepEnumIcon, ReviewStatusIcon, SeverityIcon, diff --git a/web/server/vue-cli/src/components/Report/ReportFilter/Filters/ReportStatusFilter.vue b/web/server/vue-cli/src/components/Report/ReportFilter/Filters/ReportStatusFilter.vue new file mode 100644 index 0000000000..bca96f6196 --- /dev/null +++ b/web/server/vue-cli/src/components/Report/ReportFilter/Filters/ReportStatusFilter.vue @@ -0,0 +1,129 @@ + + + + \ No newline at end of file diff --git a/web/server/vue-cli/src/components/Report/ReportFilter/Filters/SelectOption/SelectOption.vue b/web/server/vue-cli/src/components/Report/ReportFilter/Filters/SelectOption/SelectOption.vue index c2d9da404e..a7deb9c858 100644 --- a/web/server/vue-cli/src/components/Report/ReportFilter/Filters/SelectOption/SelectOption.vue +++ b/web/server/vue-cli/src/components/Report/ReportFilter/Filters/SelectOption/SelectOption.vue @@ -50,9 +50,9 @@ @@ -84,7 +84,7 @@ - + + + + + + + + + @@ -305,17 +316,11 @@ {{ item.outstanding }} @@ -351,7 +356,11 @@