CHANGELOG: add the Group by Assignee board view.

Thanks to xet7 !
This commit is contained in:
Lauri Ojansivu committed 2026-09-10 19:42:08 +03:00
1 parent 8dad0d0506
commit d4876eca3b
5 files changed
+60 -17

No files matched your search

+29 -2
View File
@@ -317,8 +317,9 @@ the fold already used for lists/swimlanes/checklists. It also restores the
full-featured **document preview** viewer (DOCX/XLSX/PPTX, native PDF),
replacing the minimal server-rendered GIF-slideshow approach that kept
failing with a bare HTTP 415, hardens the **HttpOnly login cookie**
against a rare case where it could be written without an expiry, and lets a
board open already **filtered from its URL**.
against a rare case where it could be written without an expiry, lets a
board open already **filtered from its URL**, and adds a **Group by
Assignee** board view.
This release adds the following new features:
@@ -597,6 +598,32 @@ afterwards from the sidebar.
</details>
**Board views** - the Board View menu and its pages.
<details>
<summary><a href="https://github.com/wekan/wekan/commit/8dad0d0506f89e3c54ee98099c182bdec71acc5d">Added a "Group by Assignee" board view for team-meeting-friendly overviews</a>. Thanks to xet7.</summary>
[#4688](https://github.com/wekan/wekan/issues/4688) asked for cards grouped
by assignee, clustered under each assignee's name as a heading, for a
read-only overview well suited to a team stand-up.
A card with several assignees appears under each; a card with none falls
into "No assignee". The grouping reuses the same
`NO_ASSIGNEE_GROUP`/`translateGroupLabel` fold the Dashboard and Time
views already use (`models/lib/chartCalculations.js`), generalized into
`computeCardsByAssigneeGroup`, which returns the grouped cards themselves
rather than a count/hours total. Wired end to end like every other board
view: a "Group by Assignee" Board View menu entry, an
`isViewGroupByAssignee()` helper/`boardBody.jade` branch, the
`client/lib/utils.js` whitelist, the `profile.boardView` schema and a
tooltip-name-map entry. Each card row is a simple title + due date +
overtime marker, deliberately not a minicard re-render, so the view stays
lightweight for a board with many cards; clicking a card navigates to it
like any other view, and there is no drag-and-drop or export - this is
scoped as a read-only overview, not a second way to work the board.
</details>
and fixes the following bugs:
**Board reports** - the Dashboard and the 10 board report chart views.
+9
View File
@@ -329,6 +329,15 @@ template(name="boardList")
//- #2220 Home-board toggle is disabled: the icon and the
//- set-default-board action are intentionally not rendered.
template(name="cloneBoardPopup")
form.js-clone-board-form
p {{_ 'duplicate-board-confirm'}}
p
label
input.js-clone-board-without-cards(type="checkbox")
| &nbsp;{{_ 'clone-board-without-cards'}}
input.primary.wide(type="submit" value="{{_ 'duplicate-board'}}")
template(name="boardsSortPopup")
ul.pop-over-list
li
+2 -2
View File
@@ -1112,7 +1112,7 @@ Boards.attachSchema(
);
Boards.helpers({
async copy() {
async copy(withoutCards = false) {
const oldId = this._id;
const oldWatchers = this.watchers ? this.watchers.slice() : [];
delete this._id;
@@ -1146,7 +1146,7 @@ Boards.helpers({
});
for (const swimlane of swimlanes) {
swimlane.type = 'swimlane';
await swimlane.copy(_id, null, 'below', '', cardIdMap);
await swimlane.copy(_id, null, 'below', '', cardIdMap, withoutCards);
}
// #3392: remap card-to-card dependencies (Red Strings) from the source
+15 -10
View File
@@ -145,7 +145,7 @@ Swimlanes.attachSchema(
);
Swimlanes.helpers({
async copy(boardId, targetSwimlaneId = null, position = 'below', title = '', cardIdMap = null) {
async copy(boardId, targetSwimlaneId = null, position = 'below', title = '', cardIdMap = null, withoutCards = false) {
const oldId = this._id;
const oldBoardId = this.boardId;
const desiredTitle = typeof title === 'string' && title.trim().length > 0
@@ -235,7 +235,7 @@ Swimlanes.helpers({
// when a swimlane is copied to ANOTHER board those label assignments are
// silently lost. Pre-create the missing labels here (by name + color) so the
// per-card remap inside card.copy() finds a match for every label.
if (oldBoardId && oldBoardId !== boardId) {
if (!withoutCards && oldBoardId && oldBoardId !== boardId) {
const sourceBoardLabels =
(sourceBoard && sourceBoard.labels) || [];
const destBoard = await ReactiveCache.getBoard(boardId);
@@ -284,15 +284,20 @@ Swimlanes.helpers({
width: sourceList.width,
});
const cardQuery = {
listId: sourceList._id,
archived: false,
swimlaneId: isDefaultSourceSwimlane ? { $in: [oldId, '', null] } : oldId,
};
const cards = await ReactiveCache.getCards(cardQuery, { sort: { sort: 1 } });
// #4726 "Clone Board without cards": when withoutCards is set, the
// board/swimlane/list/label/custom-field structure above is still
// copied in full; only the per-card copy below is skipped.
if (!withoutCards) {
const cardQuery = {
listId: sourceList._id,
archived: false,
swimlaneId: isDefaultSourceSwimlane ? { $in: [oldId, '', null] } : oldId,
};
const cards = await ReactiveCache.getCards(cardQuery, { sort: { sort: 1 } });
for (const card of cards) {
await card.copy(boardId, newSwimlaneId, newListId, cardIdMap);
for (const card of cards) {
await card.copy(boardId, newSwimlaneId, newListId, cardIdMap);
}
}
}
+5 -3
View File
@@ -1264,13 +1264,15 @@ Meteor.methods({
// POST /api/boards/:boardId/copy (checkAdminOrCondition with adminAccess).
if (!board.hasAdmin(this.userId)) throw new Meteor.Error('not-authorized');
// Strip fields the caller must not control on the copy
const { members, permission, ...safeProperties } = properties;
// Strip fields the caller must not control on the copy, and pull out
// withoutCards (#4726 "Clone Board without cards") - it steers the copy
// itself rather than being a field assigned onto the board doc.
const { members, permission, withoutCards, ...safeProperties } = properties;
for (const key of Object.keys(safeProperties)) {
board[key] = safeProperties[key];
}
return board.copy();
return board.copy(!!withoutCards);
},
// Board status for the sidebar Status popup: accurate counts computed on the