At Public Board, drag resize list width and swimlane height. For logged in users, fix adding labels.

Thanks to xet7 !

Fixes #5922
This commit is contained in:
Lauri Ojansivu 2025-10-19 23:15:55 +03:00
parent 55bec31a3f
commit 3514335247
13 changed files with 279 additions and 103 deletions

View file

@ -34,7 +34,8 @@ This release fixes the following bugs:
- [Fix unable to see My Due Cards](https://github.com/wekan/wekan/commit/66b444e2b0c9b2ed5f98cd1ff0cd9222b2d0c624). - [Fix unable to see My Due Cards](https://github.com/wekan/wekan/commit/66b444e2b0c9b2ed5f98cd1ff0cd9222b2d0c624).
Thanks to xet7. Thanks to xet7.
- Fix drag drop lists. - Fix drag drop lists.
[Part 1](https://github.com/wekan/wekan/commit/324f3f7794aace800022a24deb5fd5fb36ebd384). [Part 1](https://github.com/wekan/wekan/commit/324f3f7794aace800022a24deb5fd5fb36ebd384),
[Part 2](https://github.com/wekan/wekan/commit/ff516ec696ef499f11b04b30053eeb9d3f96d8d1).
Thanks to xet7. Thanks to xet7.
- [Removed extra pipe characters](https://github.com/wekan/wekan/commit/caa6e615ff3c3681bf2b470a625eb39c6009b825). - [Removed extra pipe characters](https://github.com/wekan/wekan/commit/caa6e615ff3c3681bf2b470a625eb39c6009b825).
Thanks to xet7. Thanks to xet7.

View file

@ -168,7 +168,12 @@ CardCustomField.register('cardCustomField');
} }
showWeekOfYear() { showWeekOfYear() {
return ReactiveCache.getCurrentUser().isShowWeekOfYear(); const user = ReactiveCache.getCurrentUser();
if (!user) {
// For non-logged-in users, week of year is not shown
return false;
}
return user.isShowWeekOfYear();
} }
showDate() { showDate() {

View file

@ -131,7 +131,12 @@ const CardDate = BlazeComponent.extendComponent({
}, },
showWeekOfYear() { showWeekOfYear() {
return ReactiveCache.getCurrentUser().isShowWeekOfYear(); const user = ReactiveCache.getCurrentUser();
if (!user) {
// For non-logged-in users, week of year is not shown
return false;
}
return user.isShowWeekOfYear();
}, },
showDate() { showDate() {
@ -301,7 +306,12 @@ class CardCustomFieldDate extends CardDate {
} }
showWeekOfYear() { showWeekOfYear() {
return ReactiveCache.getCurrentUser().isShowWeekOfYear(); const user = ReactiveCache.getCurrentUser();
if (!user) {
// For non-logged-in users, week of year is not shown
return false;
}
return user.isShowWeekOfYear();
} }
showDate() { showDate() {

View file

@ -125,8 +125,19 @@ Template.createLabelPopup.events({
.$('#labelName') .$('#labelName')
.val() .val()
.trim(); .trim();
const color = Blaze.getData(templateInstance.find('.fa-check')).color;
board.addLabel(name, color); // Find the selected color by looking for the palette color that contains the checkmark
let selectedColor = null;
templateInstance.$('.js-palette-color').each(function() {
if ($(this).text().includes('✅')) {
selectedColor = Blaze.getData(this).color;
return false; // break out of loop
}
});
if (selectedColor) {
board.addLabel(name, selectedColor);
}
Popup.back(); Popup.back();
}, },
}); });
@ -144,8 +155,19 @@ Template.editLabelPopup.events({
.$('#labelName') .$('#labelName')
.val() .val()
.trim(); .trim();
const color = Blaze.getData(templateInstance.find('.fa-check')).color;
board.editLabel(this._id, name, color); // Find the selected color by looking for the palette color that contains the checkmark
let selectedColor = null;
templateInstance.$('.js-palette-color').each(function() {
if ($(this).text().includes('✅')) {
selectedColor = Blaze.getData(this).color;
return false; // break out of loop
}
});
if (selectedColor) {
board.editLabel(this._id, name, selectedColor);
}
Popup.back(); Popup.back();
}, },
}); });

View file

@ -197,20 +197,60 @@ BlazeComponent.extendComponent({
listWidth() { listWidth() {
const user = ReactiveCache.getCurrentUser(); const user = ReactiveCache.getCurrentUser();
const list = Template.currentData(); const list = Template.currentData();
if (!user || !list) return 270; // Return default width if user or list is not available if (!list) return 270; // Return default width if list is not available
if (user) {
// For logged-in users, get from user profile
return user.getListWidthFromStorage(list.boardId, list._id); return user.getListWidthFromStorage(list.boardId, list._id);
} else {
// For non-logged-in users, get from localStorage
try {
const stored = localStorage.getItem('wekan-list-widths');
if (stored) {
const widths = JSON.parse(stored);
if (widths[list.boardId] && widths[list.boardId][list._id]) {
return widths[list.boardId][list._id];
}
}
} catch (e) {
console.warn('Error reading list width from localStorage:', e);
}
return 270; // Return default width if not found
}
}, },
listConstraint() { listConstraint() {
const user = ReactiveCache.getCurrentUser(); const user = ReactiveCache.getCurrentUser();
const list = Template.currentData(); const list = Template.currentData();
if (!user || !list) return 550; // Return default constraint if user or list is not available if (!list) return 550; // Return default constraint if list is not available
if (user) {
// For logged-in users, get from user profile
return user.getListConstraintFromStorage(list.boardId, list._id); return user.getListConstraintFromStorage(list.boardId, list._id);
} else {
// For non-logged-in users, get from localStorage
try {
const stored = localStorage.getItem('wekan-list-constraints');
if (stored) {
const constraints = JSON.parse(stored);
if (constraints[list.boardId] && constraints[list.boardId][list._id]) {
return constraints[list.boardId][list._id];
}
}
} catch (e) {
console.warn('Error reading list constraint from localStorage:', e);
}
return 550; // Return default constraint if not found
}
}, },
autoWidth() { autoWidth() {
const user = ReactiveCache.getCurrentUser(); const user = ReactiveCache.getCurrentUser();
const list = Template.currentData(); const list = Template.currentData();
if (!user) {
// For non-logged-in users, auto-width is disabled
return false;
}
return user.isAutoWidth(list.boardId); return user.isAutoWidth(list.boardId);
}, },
@ -329,6 +369,10 @@ BlazeComponent.extendComponent({
// Use the new storage method that handles both logged-in and non-logged-in users // Use the new storage method that handles both logged-in and non-logged-in users
if (process.env.DEBUG === 'true') { if (process.env.DEBUG === 'true') {
} }
const currentUser = ReactiveCache.getCurrentUser();
if (currentUser) {
// For logged-in users, use server method
Meteor.call('applyListWidthToStorage', boardId, listId, finalWidth, listConstraint, (error, result) => { Meteor.call('applyListWidthToStorage', boardId, listId, finalWidth, listConstraint, (error, result) => {
if (error) { if (error) {
console.error('Error saving list width:', error); console.error('Error saving list width:', error);
@ -337,6 +381,37 @@ BlazeComponent.extendComponent({
} }
} }
}); });
} else {
// For non-logged-in users, save to localStorage directly
try {
// Save list width
const storedWidths = localStorage.getItem('wekan-list-widths');
let widths = storedWidths ? JSON.parse(storedWidths) : {};
if (!widths[boardId]) {
widths[boardId] = {};
}
widths[boardId][listId] = finalWidth;
localStorage.setItem('wekan-list-widths', JSON.stringify(widths));
// Save list constraint
const storedConstraints = localStorage.getItem('wekan-list-constraints');
let constraints = storedConstraints ? JSON.parse(storedConstraints) : {};
if (!constraints[boardId]) {
constraints[boardId] = {};
}
constraints[boardId][listId] = listConstraint;
localStorage.setItem('wekan-list-constraints', JSON.stringify(constraints));
if (process.env.DEBUG === 'true') {
}
} catch (e) {
console.warn('Error saving list width/constraint to localStorage:', e);
}
}
e.preventDefault(); e.preventDefault();
}; };

View file

@ -220,6 +220,7 @@
margin: 0; margin: 0;
margin-top: 1px; margin-top: 1px;
} }
#header-quick-access #header-user-bar .header-user-bar-name, #header-quick-access #header-user-bar .header-user-bar-name,
#header-quick-access #header-help { #header-quick-access #header-help {
margin: 4px 8px 0 0; margin: 4px 8px 0 0;

View file

@ -28,7 +28,6 @@ template(name="sidebar")
+Template.dynamic(template=getViewTemplate) +Template.dynamic(template=getViewTemplate)
template(name='homeSidebar') template(name='homeSidebar')
hr
+membersWidget +membersWidget
hr hr
+labelsWidget +labelsWidget
@ -38,6 +37,7 @@ template(name='homeSidebar')
span {{_ 'hide-minicard-label-text'}} span {{_ 'hide-minicard-label-text'}}
b   b  
.materialCheckBox(class="{{#if hiddenMinicardLabelText}}is-checked{{/if}}") .materialCheckBox(class="{{#if hiddenMinicardLabelText}}is-checked{{/if}}")
if currentUser
ul#cards.vertical-scrollbars-toggle ul#cards.vertical-scrollbars-toggle
a.flex.js-vertical-scrollbars-toggle(title="{{_ 'enable-vertical-scrollbars'}}") a.flex.js-vertical-scrollbars-toggle(title="{{_ 'enable-vertical-scrollbars'}}")
span {{_ 'enable-vertical-scrollbars'}} span {{_ 'enable-vertical-scrollbars'}}

View file

@ -203,6 +203,8 @@ BlazeComponent.extendComponent({
}, },
}).register('homeSidebar'); }).register('homeSidebar');
Template.boardInfoOnMyBoardsPopup.helpers({ Template.boardInfoOnMyBoardsPopup.helpers({
hideCardCounterList() { hideCardCounterList() {
return Utils.isMiniScreen() && Session.get('currentBoard'); return Utils.isMiniScreen() && Session.get('currentBoard');

View file

@ -23,6 +23,7 @@ template(name="swimlaneFixedHeader")
+viewer +viewer
| {{isTitleDefault title}} | {{isTitleDefault title}}
.swimlane-header-menu .swimlane-header-menu
if currentUser
unless currentUser.isCommentOnly unless currentUser.isCommentOnly
a.js-open-add-swimlane-menu.swimlane-header-plus-icon(title="{{_ 'add-swimlane'}}") a.js-open-add-swimlane-menu.swimlane-header-plus-icon(title="{{_ 'add-swimlane'}}")
| |
@ -53,6 +54,7 @@ template(name="editSwimlaneTitleForm")
| ❌ | ❌
template(name="swimlaneActionPopup") template(name="swimlaneActionPopup")
if currentUser
unless currentUser.isCommentOnly unless currentUser.isCommentOnly
ul.pop-over-list ul.pop-over-list
if currentUser.isBoardAdmin if currentUser.isBoardAdmin
@ -80,6 +82,7 @@ template(name="swimlaneActionPopup")
| {{_ 'move-swimlane'}} | {{_ 'move-swimlane'}}
template(name="swimlaneAddPopup") template(name="swimlaneAddPopup")
if currentUser
unless currentUser.isCommentOnly unless currentUser.isCommentOnly
form form
input.swimlane-name-input.full-line(type="text" placeholder="{{_ 'add-swimlane'}}" input.swimlane-name-input.full-line(type="text" placeholder="{{_ 'add-swimlane'}}"

View file

@ -72,6 +72,7 @@ template(name="addListForm")
| |
template(name="moveSwimlanePopup") template(name="moveSwimlanePopup")
if currentUser
unless currentUser.isWorker unless currentUser.isWorker
label {{_ 'boards'}}: label {{_ 'boards'}}:
select.js-select-boards(autofocus) select.js-select-boards(autofocus)
@ -82,6 +83,7 @@ template(name="moveSwimlanePopup")
button.primary.confirm.js-done {{_ 'done'}} button.primary.confirm.js-done {{_ 'done'}}
template(name="copySwimlanePopup") template(name="copySwimlanePopup")
if currentUser
unless currentUser.isWorker unless currentUser.isWorker
label {{_ 'boards'}}: label {{_ 'boards'}}:
select.js-select-boards(autofocus) select.js-select-boards(autofocus)

View file

@ -423,7 +423,31 @@ BlazeComponent.extendComponent({
swimlaneHeight() { swimlaneHeight() {
const user = ReactiveCache.getCurrentUser(); const user = ReactiveCache.getCurrentUser();
const swimlane = Template.currentData(); const swimlane = Template.currentData();
const height = user.getSwimlaneHeightFromStorage(swimlane.boardId, swimlane._id);
let height;
if (user) {
// For logged-in users, get from user profile
height = user.getSwimlaneHeightFromStorage(swimlane.boardId, swimlane._id);
} else {
// For non-logged-in users, get from localStorage
try {
const stored = localStorage.getItem('wekan-swimlane-heights');
if (stored) {
const heights = JSON.parse(stored);
if (heights[swimlane.boardId] && heights[swimlane.boardId][swimlane._id]) {
height = heights[swimlane.boardId][swimlane._id];
} else {
height = -1;
}
} else {
height = -1;
}
} catch (e) {
console.warn('Error reading swimlane height from localStorage:', e);
height = -1;
}
}
return height == -1 ? "auto" : (height + 5 + "px"); return height == -1 ? "auto" : (height + 5 + "px");
}, },
@ -537,7 +561,9 @@ BlazeComponent.extendComponent({
if (process.env.DEBUG === 'true') { if (process.env.DEBUG === 'true') {
} }
// Use the new storage method that handles both logged-in and non-logged-in users const currentUser = ReactiveCache.getCurrentUser();
if (currentUser) {
// For logged-in users, use server method
Meteor.call('applySwimlaneHeightToStorage', boardId, swimlaneId, finalHeight, (error, result) => { Meteor.call('applySwimlaneHeightToStorage', boardId, swimlaneId, finalHeight, (error, result) => {
if (error) { if (error) {
console.error('Error saving swimlane height:', error); console.error('Error saving swimlane height:', error);
@ -546,6 +572,25 @@ BlazeComponent.extendComponent({
} }
} }
}); });
} else {
// For non-logged-in users, save to localStorage directly
try {
const stored = localStorage.getItem('wekan-swimlane-heights');
let heights = stored ? JSON.parse(stored) : {};
if (!heights[boardId]) {
heights[boardId] = {};
}
heights[boardId][swimlaneId] = finalHeight;
localStorage.setItem('wekan-swimlane-heights', JSON.stringify(heights));
if (process.env.DEBUG === 'true') {
}
} catch (e) {
console.warn('Error saving swimlane height to localStorage:', e);
}
}
e.preventDefault(); e.preventDefault();
}; };

View file

@ -101,6 +101,10 @@ window.Popup = new (class {
// our internal dependency, and since we just changed the top element of // our internal dependency, and since we just changed the top element of
// our internal stack, the popup will be updated with the new data. // our internal stack, the popup will be updated with the new data.
if (!self.isOpen()) { if (!self.isOpen()) {
if (!Template[popupName]) {
console.error('Template not found:', popupName);
return;
}
self.current = Blaze.renderWithData( self.current = Blaze.renderWithData(
self.template, self.template,
() => { () => {

View file

@ -1619,7 +1619,10 @@ Meteor.methods({
check(swimlaneId, String); check(swimlaneId, String);
check(height, Number); check(height, Number);
const user = ReactiveCache.getCurrentUser(); const user = ReactiveCache.getCurrentUser();
if (user) {
user.setSwimlaneHeightToStorage(boardId, swimlaneId, height); user.setSwimlaneHeightToStorage(boardId, swimlaneId, height);
}
// For non-logged-in users, the client-side code will handle localStorage
}, },
applyListWidthToStorage(boardId, listId, width, constraint) { applyListWidthToStorage(boardId, listId, width, constraint) {
@ -1628,8 +1631,11 @@ Meteor.methods({
check(width, Number); check(width, Number);
check(constraint, Number); check(constraint, Number);
const user = ReactiveCache.getCurrentUser(); const user = ReactiveCache.getCurrentUser();
if (user) {
user.setListWidthToStorage(boardId, listId, width); user.setListWidthToStorage(boardId, listId, width);
user.setListConstraintToStorage(boardId, listId, constraint); user.setListConstraintToStorage(boardId, listId, constraint);
}
// For non-logged-in users, the client-side code will handle localStorage
}, },
setZoomLevel(level) { setZoomLevel(level) {
check(level, Number); check(level, Number);