diff --git a/modules/issue_tracker/css/issue_card.css b/modules/issue_tracker/css/issue_card.css index e059ff246e..388f0f4b1f 100644 --- a/modules/issue_tracker/css/issue_card.css +++ b/modules/issue_tracker/css/issue_card.css @@ -33,6 +33,7 @@ display: flex; gap: 8px; margin-bottom: 16px; + flex-wrap: wrap; } .issue-content { diff --git a/modules/issue_tracker/css/issue_tracker_batchmode.css b/modules/issue_tracker/css/issue_tracker_batchmode.css index 727795e7b2..3d42012731 100644 --- a/modules/issue_tracker/css/issue_tracker_batchmode.css +++ b/modules/issue_tracker/css/issue_tracker_batchmode.css @@ -30,20 +30,28 @@ } .filter-list { - display: flex; - flex-wrap: wrap; - gap: 10px; + display: grid; + grid-template-columns: auto auto auto; + padding: 10px; + overflow-y: scroll; + max-height: 300px; } .filter-list label { display: flex; - align-items: center; - margin-bottom: 0; - font-weight: normal; + padding-right: 10px; +} + +.filter-list label input { + margin: 0; + margin-right: 4px; + margin-bottom: 4px; } .filter-list label span { - margin-left: 3px; + margin-left: 5px; + margin-top: auto; + margin-bottom: auto; } .issues-list { diff --git a/modules/issue_tracker/jsx/IssueCard.js b/modules/issue_tracker/jsx/IssueCard.js index 4fdc6d1538..9bf8ae50fc 100644 --- a/modules/issue_tracker/jsx/IssueCard.js +++ b/modules/issue_tracker/jsx/IssueCard.js @@ -4,6 +4,7 @@ import swal from 'sweetalert2'; import Modal from 'jsx/Modal'; import {withTranslation, Trans} from 'react-i18next'; import '../css/issue_card.css'; +import Markdown from 'jsx/Markdown'; const IssueCard = React.memo(function IssueCard(props) { const {t} = props; @@ -457,7 +458,8 @@ const IssueCard = React.memo(function IssueCard(props) { ) : (

- {description}

+ +

)} @@ -469,7 +471,8 @@ const IssueCard = React.memo(function IssueCard(props) { issue.topComments.map((comment, index) => (

- {comment.issueComment}

+ +

), }, + { + id: 'assignee', // Added assignee tab + label: ( + + Assignee{' '} + {selectedAssignees.length} + + ), + }, ]; const panelTitle = ( @@ -316,6 +330,27 @@ function IssueTrackerBatchMode({options = {}, t}) { ))}
+ +
+ {Object.entries(assignees).map(([value, label]) => ( + + ))} +
+

@@ -415,6 +450,7 @@ IssueTrackerBatchMode.propTypes = { statuses: PropTypes.object, categories: PropTypes.object, sites: PropTypes.object, + assignees: PropTypes.object, }).isRequired, t: PropTypes.func.isRequired, }; diff --git a/modules/issue_tracker/jsx/issueTrackerIndex.js b/modules/issue_tracker/jsx/issueTrackerIndex.js index 5038f3db92..5bb02a534b 100644 --- a/modules/issue_tracker/jsx/issueTrackerIndex.js +++ b/modules/issue_tracker/jsx/issueTrackerIndex.js @@ -379,6 +379,7 @@ class IssueTrackerIndex extends Component { statuses: this.state.data.fieldOptions.statuses, categories: this.state.data.fieldOptions.categories, sites: this.state.data.fieldOptions.sites, + assignees: this.state.data.fieldOptions.assignees, }} /> diff --git a/modules/issue_tracker/php/edit.class.inc b/modules/issue_tracker/php/edit.class.inc index 0ca171cf33..d13890d98b 100644 --- a/modules/issue_tracker/php/edit.class.inc +++ b/modules/issue_tracker/php/edit.class.inc @@ -1258,20 +1258,35 @@ class Edit extends \NDB_Page implements ETagCalculator /** * Get a formatted string from user information. * - * @param string $userid a username/userid + * @param string|null $userid a username/userid, or null * * @return string a formatted string "fullname (userid)" */ - function formatUserInformation(string $userid) + function formatUserInformation(?string $userid) { - $user = \User::factory($userid); - $un = $user->getUsername(); - if (empty($un)) { - // e.g. in case of anonymous user - return $user->getFullname(); - } else { - return $user->getFullname() . " (" . $un . ")"; + if ($userid === null) { + // same as the real name for AnonymousUser object + return "AnonymousUser"; } + + // get real name + $db = $this->loris->getdatabaseConnection(); + $realName = $db->pselectOne( + "SELECT Real_name + FROM users + WHERE userid = :uid + ", + ["uid" => $userid] + ); + + // not found => Anonymous + if ($realName === null) { + // same as the real name for AnonymousUser object + return "AnonymousUser"; + } + + // else full name + username + return "{$realName} ({$userid})"; } /**