mirror of
https://github.com/wekan/wekan.git
synced 2025-12-16 07:20:12 +01:00
Fixed Error in migrate-lists-to-per-swimlane migration.
Thanks to xet7 ! Fixes #5918
This commit is contained in:
parent
9bd21e1d1b
commit
cc99da5357
9 changed files with 157 additions and 135 deletions
|
|
@ -21,6 +21,10 @@ template(name="boardBody")
|
|||
if notDisplayThisBoard
|
||||
| {{_ 'tableVisibilityMode-allowPrivateOnly'}}
|
||||
else
|
||||
// Debug information (remove in production)
|
||||
if debugBoardState
|
||||
.debug-info(style="position: fixed; top: 0; left: 0; background: rgba(0,0,0,0.8); color: white; padding: 10px; z-index: 9999; font-size: 12px;")
|
||||
| Board: {{currentBoard.title}} | View: {{boardView}} | HasSwimlanes: {{hasSwimlanes}} | Swimlanes: {{currentBoard.swimlanes.length}}
|
||||
.board-wrapper(class=currentBoard.colorClass class="{{#if isMiniScreen}}mobile-view{{/if}}")
|
||||
.board-canvas.js-swimlanes(
|
||||
class="{{#if hasSwimlanes}}dragscroll{{/if}}"
|
||||
|
|
@ -39,9 +43,8 @@ template(name="boardBody")
|
|||
each currentBoard.swimlanes
|
||||
+swimlane(this)
|
||||
else
|
||||
a.js-empty-board-add-swimlane(title="{{_ 'add-swimlane'}}")
|
||||
h1.big-message.quiet
|
||||
| {{_ 'add-swimlane'}} +
|
||||
// Fallback: If no swimlanes exist, show lists instead of empty message
|
||||
+listsGroup(currentBoard)
|
||||
else if isViewLists
|
||||
+listsGroup(currentBoard)
|
||||
else if isViewCalendar
|
||||
|
|
|
|||
|
|
@ -238,11 +238,16 @@ BlazeComponent.extendComponent({
|
|||
}
|
||||
}
|
||||
|
||||
// Observe for new popups/menus and set focus
|
||||
// Observe for new popups/menus and set focus (but exclude swimlane content)
|
||||
const popupObserver = new MutationObserver(function(mutations) {
|
||||
mutations.forEach(function(mutation) {
|
||||
mutation.addedNodes.forEach(function(node) {
|
||||
if (node.nodeType === 1 && (node.classList.contains('popup') || node.classList.contains('modal') || node.classList.contains('menu'))) {
|
||||
if (node.nodeType === 1 &&
|
||||
(node.classList.contains('popup') || node.classList.contains('modal') || node.classList.contains('menu')) &&
|
||||
!node.closest('.js-swimlanes') &&
|
||||
!node.closest('.swimlane') &&
|
||||
!node.closest('.list') &&
|
||||
!node.closest('.minicard')) {
|
||||
setTimeout(function() { focusFirstInteractive(node); }, 10);
|
||||
}
|
||||
});
|
||||
|
|
@ -601,10 +606,20 @@ BlazeComponent.extendComponent({
|
|||
|
||||
hasSwimlanes() {
|
||||
const currentBoard = Utils.getCurrentBoard();
|
||||
if (!currentBoard) return false;
|
||||
if (!currentBoard) {
|
||||
console.log('hasSwimlanes: No current board');
|
||||
return false;
|
||||
}
|
||||
|
||||
const swimlanes = currentBoard.swimlanes();
|
||||
return swimlanes.length > 0;
|
||||
try {
|
||||
const swimlanes = currentBoard.swimlanes();
|
||||
const hasSwimlanes = swimlanes && swimlanes.length > 0;
|
||||
console.log('hasSwimlanes: Board has', swimlanes ? swimlanes.length : 0, 'swimlanes');
|
||||
return hasSwimlanes;
|
||||
} catch (error) {
|
||||
console.error('hasSwimlanes: Error getting swimlanes:', error);
|
||||
return false;
|
||||
}
|
||||
},
|
||||
|
||||
|
||||
|
|
@ -618,6 +633,12 @@ BlazeComponent.extendComponent({
|
|||
},
|
||||
|
||||
debugBoardState() {
|
||||
// Enable debug mode by setting ?debug=1 in URL
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
return urlParams.get('debug') === '1';
|
||||
},
|
||||
|
||||
debugBoardStateData() {
|
||||
const currentBoard = Utils.getCurrentBoard();
|
||||
const currentBoardId = Session.get('currentBoard');
|
||||
const isBoardReady = this.isBoardReady.get();
|
||||
|
|
|
|||
|
|
@ -1,37 +1,6 @@
|
|||
import { ReactiveCache } from '/imports/reactiveCache';
|
||||
import { TAPi18n } from '/imports/i18n';
|
||||
|
||||
// Template helpers for attachmentSettings
|
||||
Template.attachmentSettings.helpers({
|
||||
loading() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.loading) {
|
||||
return instance.loading.get();
|
||||
}
|
||||
return attachmentSettings.loading.get();
|
||||
},
|
||||
showStorageSettings() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.showStorageSettings) {
|
||||
return instance.showStorageSettings.get();
|
||||
}
|
||||
return attachmentSettings.showStorageSettings.get();
|
||||
},
|
||||
showMigration() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.showMigration) {
|
||||
return instance.showMigration.get();
|
||||
}
|
||||
return attachmentSettings.showMigration.get();
|
||||
},
|
||||
showMonitoring() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.showMonitoring) {
|
||||
return instance.showMonitoring.get();
|
||||
}
|
||||
return attachmentSettings.showMonitoring.get();
|
||||
}
|
||||
});
|
||||
import { Meteor } from 'meteor/meteor';
|
||||
import { Session } from 'meteor/session';
|
||||
import { Tracker } from 'meteor/tracker';
|
||||
|
|
@ -102,6 +71,20 @@ BlazeComponent.extendComponent({
|
|||
this.loadMonitoringData();
|
||||
},
|
||||
|
||||
// Template helpers for this component
|
||||
loading() {
|
||||
return this.loading.get();
|
||||
},
|
||||
showStorageSettings() {
|
||||
return this.showStorageSettings.get();
|
||||
},
|
||||
showMigration() {
|
||||
return this.showMigration.get();
|
||||
},
|
||||
showMonitoring() {
|
||||
return this.showMonitoring.get();
|
||||
},
|
||||
|
||||
events() {
|
||||
return [
|
||||
{
|
||||
|
|
@ -497,5 +480,25 @@ BlazeComponent.extendComponent({
|
|||
}
|
||||
}).register('attachmentMonitoring');
|
||||
|
||||
// Template helpers for attachmentSettings
|
||||
Template.attachmentSettings.helpers({
|
||||
loading() {
|
||||
const instance = Template.instance();
|
||||
return instance.loading && instance.loading.get();
|
||||
},
|
||||
showStorageSettings() {
|
||||
const instance = Template.instance();
|
||||
return instance.showStorageSettings && instance.showStorageSettings.get();
|
||||
},
|
||||
showMigration() {
|
||||
const instance = Template.instance();
|
||||
return instance.showMigration && instance.showMigration.get();
|
||||
},
|
||||
showMonitoring() {
|
||||
const instance = Template.instance();
|
||||
return instance.showMonitoring && instance.showMonitoring.get();
|
||||
},
|
||||
});
|
||||
|
||||
// Export the attachment settings for use in other components
|
||||
export { attachmentSettings };
|
||||
|
|
|
|||
|
|
@ -526,3 +526,27 @@ function pollMigrationProgress(instance) {
|
|||
});
|
||||
}, 1000);
|
||||
}
|
||||
|
||||
// Template helpers for cronSettings
|
||||
Template.cronSettings.helpers({
|
||||
loading() {
|
||||
const instance = Template.instance();
|
||||
return instance.loading && instance.loading.get();
|
||||
},
|
||||
showMigrations() {
|
||||
const instance = Template.instance();
|
||||
return instance.showMigrations && instance.showMigrations.get();
|
||||
},
|
||||
showBoardOperations() {
|
||||
const instance = Template.instance();
|
||||
return instance.showBoardOperations && instance.showBoardOperations.get();
|
||||
},
|
||||
showJobs() {
|
||||
const instance = Template.instance();
|
||||
return instance.showJobs && instance.showJobs.get();
|
||||
},
|
||||
showAddJob() {
|
||||
const instance = Template.instance();
|
||||
return instance.showAddJob && instance.showAddJob.get();
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -3,86 +3,6 @@ import { TAPi18n } from '/imports/i18n';
|
|||
import { ALLOWED_WAIT_SPINNERS } from '/config/const';
|
||||
import LockoutSettings from '/models/lockoutSettings';
|
||||
|
||||
// Template helpers for settingBody
|
||||
Template.setting.helpers({
|
||||
generalSetting() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.generalSetting) {
|
||||
return instance.generalSetting.get();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
emailSetting() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.emailSetting) {
|
||||
return instance.emailSetting.get();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
accountSetting() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.accountSetting) {
|
||||
return instance.accountSetting.get();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
tableVisibilityModeSetting() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.tableVisibilityModeSetting) {
|
||||
return instance.tableVisibilityModeSetting.get();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
announcementSetting() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.announcementSetting) {
|
||||
return instance.announcementSetting.get();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
accessibilitySetting() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.accessibilitySetting) {
|
||||
return instance.accessibilitySetting.get();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
layoutSetting() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.layoutSetting) {
|
||||
return instance.layoutSetting.get();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
webhookSetting() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.webhookSetting) {
|
||||
return instance.webhookSetting.get();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
attachmentSettings() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.attachmentSettings) {
|
||||
return instance.attachmentSettings.get();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
cronSettings() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.cronSettings) {
|
||||
return instance.cronSettings.get();
|
||||
}
|
||||
return false;
|
||||
},
|
||||
loading() {
|
||||
const instance = Template.instance();
|
||||
if (instance && instance.loading) {
|
||||
return instance.loading.get();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
BlazeComponent.extendComponent({
|
||||
onCreated() {
|
||||
|
|
@ -110,6 +30,7 @@ BlazeComponent.extendComponent({
|
|||
Meteor.subscribe('lockoutSettings');
|
||||
},
|
||||
|
||||
|
||||
setError(error) {
|
||||
this.error.set(error);
|
||||
},
|
||||
|
|
@ -667,3 +588,51 @@ Template.selectSpinnerName.helpers({
|
|||
return Template.instance().data.spinnerName === match;
|
||||
},
|
||||
});
|
||||
|
||||
// Template helpers for the setting template
|
||||
Template.setting.helpers({
|
||||
generalSetting() {
|
||||
const instance = Template.instance();
|
||||
return instance.generalSetting && instance.generalSetting.get();
|
||||
},
|
||||
emailSetting() {
|
||||
const instance = Template.instance();
|
||||
return instance.emailSetting && instance.emailSetting.get();
|
||||
},
|
||||
accountSetting() {
|
||||
const instance = Template.instance();
|
||||
return instance.accountSetting && instance.accountSetting.get();
|
||||
},
|
||||
tableVisibilityModeSetting() {
|
||||
const instance = Template.instance();
|
||||
return instance.tableVisibilityModeSetting && instance.tableVisibilityModeSetting.get();
|
||||
},
|
||||
announcementSetting() {
|
||||
const instance = Template.instance();
|
||||
return instance.announcementSetting && instance.announcementSetting.get();
|
||||
},
|
||||
accessibilitySetting() {
|
||||
const instance = Template.instance();
|
||||
return instance.accessibilitySetting && instance.accessibilitySetting.get();
|
||||
},
|
||||
layoutSetting() {
|
||||
const instance = Template.instance();
|
||||
return instance.layoutSetting && instance.layoutSetting.get();
|
||||
},
|
||||
webhookSetting() {
|
||||
const instance = Template.instance();
|
||||
return instance.webhookSetting && instance.webhookSetting.get();
|
||||
},
|
||||
attachmentSettings() {
|
||||
const instance = Template.instance();
|
||||
return instance.attachmentSettings && instance.attachmentSettings.get();
|
||||
},
|
||||
cronSettings() {
|
||||
const instance = Template.instance();
|
||||
return instance.cronSettings && instance.cronSettings.get();
|
||||
},
|
||||
loading() {
|
||||
const instance = Template.instance();
|
||||
return instance.loading && instance.loading.get();
|
||||
},
|
||||
});
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ if (Meteor.isServer) {
|
|||
}
|
||||
}
|
||||
|
||||
storagePath = path.join(process.env.WRITABLE_PATH, 'attachments');
|
||||
storagePath = path.join(process.env.WRITABLE_PATH || process.cwd(), 'attachments');
|
||||
}
|
||||
|
||||
export const fileStoreStrategyFactory = new FileStoreStrategyFactory(AttachmentStoreStrategyFilesystem, storagePath, AttachmentStoreStrategyGridFs, attachmentBucket);
|
||||
|
|
|
|||
|
|
@ -40,7 +40,7 @@ if (Meteor.isServer) {
|
|||
}
|
||||
|
||||
avatarsBucket = createBucket('avatars');
|
||||
storagePath = path.join(process.env.WRITABLE_PATH, 'avatars');
|
||||
storagePath = path.join(process.env.WRITABLE_PATH || process.cwd(), 'avatars');
|
||||
}
|
||||
|
||||
const fileStoreStrategyFactory = new FileStoreStrategyFactory(FileStoreStrategyFilesystem, storagePath, FileStoreStrategyGridFs, avatarsBucket);
|
||||
|
|
|
|||
|
|
@ -1148,13 +1148,13 @@ Boards.helpers({
|
|||
permission: this.permission,
|
||||
members: this.members,
|
||||
color: this.color,
|
||||
description: TAPi18n.__('default-subtasks-board', {
|
||||
description: TAPi18n && TAPi18n.i18n ? TAPi18n.__('default-subtasks-board', {
|
||||
board: this.title,
|
||||
}),
|
||||
}) : `Default subtasks board for ${this.title}`,
|
||||
});
|
||||
|
||||
Swimlanes.insert({
|
||||
title: TAPi18n.__('default'),
|
||||
title: TAPi18n && TAPi18n.i18n ? TAPi18n.__('default') : 'Default',
|
||||
boardId: this.subtasksDefaultBoardId,
|
||||
});
|
||||
Boards.update(this._id, {
|
||||
|
|
@ -1181,13 +1181,13 @@ Boards.helpers({
|
|||
permission: this.permission,
|
||||
members: this.members,
|
||||
color: this.color,
|
||||
description: TAPi18n.__('default-dates-board', {
|
||||
description: TAPi18n && TAPi18n.i18n ? TAPi18n.__('default-dates-board', {
|
||||
board: this.title,
|
||||
}),
|
||||
}) : `Default dates board for ${this.title}`,
|
||||
});
|
||||
|
||||
Swimlanes.insert({
|
||||
title: TAPi18n.__('default'),
|
||||
title: TAPi18n && TAPi18n.i18n ? TAPi18n.__('default') : 'Default',
|
||||
boardId: this.dateSettingsDefaultBoardId,
|
||||
});
|
||||
Boards.update(this._id, {
|
||||
|
|
@ -1209,7 +1209,7 @@ Boards.helpers({
|
|||
this.subtasksDefaultListId === undefined
|
||||
) {
|
||||
this.subtasksDefaultListId = Lists.insert({
|
||||
title: TAPi18n.__('queue'),
|
||||
title: TAPi18n && TAPi18n.i18n ? TAPi18n.__('queue') : 'Queue',
|
||||
boardId: this._id,
|
||||
swimlaneId: this.getDefaultSwimline()._id, // Set default swimlane for subtasks list
|
||||
});
|
||||
|
|
@ -1228,7 +1228,7 @@ Boards.helpers({
|
|||
this.dateSettingsDefaultListId === undefined
|
||||
) {
|
||||
this.dateSettingsDefaultListId = Lists.insert({
|
||||
title: TAPi18n.__('queue'),
|
||||
title: TAPi18n && TAPi18n.i18n ? TAPi18n.__('queue') : 'Queue',
|
||||
boardId: this._id,
|
||||
swimlaneId: this.getDefaultSwimline()._id, // Set default swimlane for date settings list
|
||||
});
|
||||
|
|
@ -1244,8 +1244,10 @@ Boards.helpers({
|
|||
getDefaultSwimline() {
|
||||
let result = ReactiveCache.getSwimlane({ boardId: this._id });
|
||||
if (result === undefined) {
|
||||
// Use fallback title if i18n is not available (e.g., during migration)
|
||||
const title = TAPi18n && TAPi18n.i18n ? TAPi18n.__('default') : 'Default';
|
||||
Swimlanes.insert({
|
||||
title: TAPi18n.__('default'),
|
||||
title: title,
|
||||
boardId: this._id,
|
||||
});
|
||||
result = ReactiveCache.getSwimlane({ boardId: this._id });
|
||||
|
|
@ -2212,7 +2214,7 @@ if (Meteor.isServer) {
|
|||
migrationVersion: 1, // Latest version - no migration needed
|
||||
});
|
||||
const swimlaneId = Swimlanes.insert({
|
||||
title: TAPi18n.__('default'),
|
||||
title: TAPi18n && TAPi18n.i18n ? TAPi18n.__('default') : 'Default',
|
||||
boardId: id,
|
||||
});
|
||||
JsonRoutes.sendResult(res, {
|
||||
|
|
|
|||
|
|
@ -2138,7 +2138,7 @@ if (Meteor.isServer) {
|
|||
const future3 = new Future();
|
||||
Boards.insert(
|
||||
{
|
||||
title: TAPi18n.__('templates'),
|
||||
title: TAPi18n && TAPi18n.i18n ? TAPi18n.__('templates') : 'Templates',
|
||||
permission: 'private',
|
||||
type: 'template-container',
|
||||
},
|
||||
|
|
@ -2154,7 +2154,7 @@ if (Meteor.isServer) {
|
|||
// Insert the card templates swimlane
|
||||
Swimlanes.insert(
|
||||
{
|
||||
title: TAPi18n.__('card-templates-swimlane'),
|
||||
title: TAPi18n && TAPi18n.i18n ? TAPi18n.__('card-templates-swimlane') : 'Card Templates',
|
||||
boardId,
|
||||
sort: 1,
|
||||
type: 'template-container',
|
||||
|
|
@ -2174,7 +2174,7 @@ if (Meteor.isServer) {
|
|||
// Insert the list templates swimlane
|
||||
Swimlanes.insert(
|
||||
{
|
||||
title: TAPi18n.__('list-templates-swimlane'),
|
||||
title: TAPi18n && TAPi18n.i18n ? TAPi18n.__('list-templates-swimlane') : 'List Templates',
|
||||
boardId,
|
||||
sort: 2,
|
||||
type: 'template-container',
|
||||
|
|
@ -2194,7 +2194,7 @@ if (Meteor.isServer) {
|
|||
// Insert the board templates swimlane
|
||||
Swimlanes.insert(
|
||||
{
|
||||
title: TAPi18n.__('board-templates-swimlane'),
|
||||
title: TAPi18n && TAPi18n.i18n ? TAPi18n.__('board-templates-swimlane') : 'Board Templates',
|
||||
boardId,
|
||||
sort: 3,
|
||||
type: 'template-container',
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue