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) {
) : (
)}
@@ -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})";
}
/**