-
Admin Panel → Problems no longer shows a finished board-repair as still running,
nor counts informational CPU rows as "new problems". On an idle server with far
fewer than 146 boards the Status page showed "Board data-repair — 146/146 boards"
running forever (with a matching "Migration or repair" login warning), and the CPU
area showed dozens of "new problems". The repair actually finishes and writes
running:false, but the startup pass ALSO fired a non-awaited running:true
progress write at the last board (boardsDone === boardsTotal); being
fire-and-forget it could land after the awaited completion write and pin the doc at
"running, 146/146" — and a process killed mid-repair leaves running:true too. The
startup pass now persists only intermediate progress (the completion write owns the
final state), and the Status page asks a pure isStatusActive() instead of reading
the raw flag: a migration/repair counts as in progress only while it is running AND
not in a terminal phase AND not already finished by count (done >= total) AND
updated recently (a running flag with no recent progress write is a crashed run), so
a doc already stuck on an instance heals itself and the "Migration or repair" warning
clears with it. The CPU "new problems" count excluded nothing: the monitor writes one
detected row when a high-CPU period starts and several severity:'info' rows
(remediated when it ends, mitigation and FerretDB-governor rows), so each brief,
already-over spike looked like several problems; the count now excludes
severity:'info' rows — notices that a problem was handled or cleared are not
problems — while rows with no severity still count, so nothing unclassified is
dropped.
Thanks to Alishara and xet7.
-
"Map to existing user" for an imported (virtual) member now searches every user
instead of listing only board members. After importing a Trello board and choosing to
map users later, the picker offered nothing but the admin: it listed only the ACTIVE
REAL MEMBERS of the board, and right after an import the real people have no membership
at all — the placeholders do — so on a board whose only real member is the importing
admin there was literally nobody to pick, and no search box either. The picker now has a
search box that goes through the same permission-checked searchUsers method the normal
add-member typeahead uses, so the same board-membership check and the same #6116
same-org/team restriction apply; with the box empty it still lists the board's real
members (which changes no roles at all), and typing searches every real user and labels
the ones who are not on this board yet. Mapping onto a user who is not a board member
adds them with the PLACEHOLDER's own role — the role the import recorded for that
person, never a higher one — and only after passing exactly the checks inviting them
would: the Admin Panel "roles allowed to invite" setting, the same-org/team restriction,
and the refusal to add a deactivated account. This also fixes sanitizeUserForSearch
dropping profile from every search result — it read the Mongo-style paths in its
allowlist (profile.fullname) as FLAT keys, so both this picker and the add-member
typeahead showed a blank name with only the username in
brackets.
Thanks to AmigaAbattoir and xet7.
-
Admin Panel report styles were never loaded, so every report's prev/next pagination
button rendered with a black background. client/components/settings/adminReports.css
was not imported anywhere, and package.json sets meteor.mainModule, which disables
Meteor's eager loading — a CSS file that nothing imports is simply not in the bundle. The
buttons fell through to the global button { background: var(--theme-accent, #000) } in
forms.css, which is BLACK when no custom theme colour is set. All prev/next controls in
WeKan (admin reports, People/Org/Team/Domain, All Boards, board Table view, cron tables)
now share one themed stylesheet that also covers :focus and :active — forms.css
styles those at a specificity equal to or higher than a plain .some-pagination button
rule, so even a loaded stylesheet lost as soon as the button was clicked and pressing
"next" left it dark grey until it lost focus. Disabled is now the same themed outline
faded rather than a grey block, and the "3 / 42" page info inherits the surrounding text
colour instead of a hard-coded #333 that vanishes on dark
backgrounds.
Thanks to xet7.
-
Admin Panel → Problems → Cards report loads and pages faster. The report already
paginated server-side (25 rows per page via limit/skip), so it never loaded all cards
into the browser, but the cardsReport publication sent WHOLE card documents —
description, customFields, vote/poker sub-documents, every date field — when the table
renders only six columns, so a 25-row page could be hundreds of kilobytes on boards with
long descriptions; it now projects only the six columns shown. And every prev/next click
re-ran the report's count method as well as re-subscribing, paying for a full collection
count plus a second server round trip even though the total cannot change just because
you moved to the next page; opening a report and searching in it now recount, plain
paging does not. Both changes also apply to the files, rules, boards, impersonation and
recovery reports, which share the same loader.
Thanks to xet7.
-
Six Meteor methods threw Did not check() all arguments during call to '<method>',
because this app runs with the audit-argument-checks package: a method that RECEIVES
an argument it never check()s fails the call outright. problemDetailReport(area) had
the defect but nothing had ever passed it an argument, so it surfaced only when the new
Admin Panel → Problems → CPU usage header started polling problemDetailReport('cpu')
every 5 seconds and filled the server log with the exception. Auditing every server
method for the same defect found five more that ARE called with arguments from the
client, so those features were failing outright: unlockUser (Admin Panel → People,
unlocking a locked-out user), runBackup, restoreBackup and saveBackupSchedule
(Admin Panel → Attachments) and migrateTextDatabase (the MongoDB ↔ FerretDB text
migration), plus getServiceConfiguration, which has no current client caller. Each now
checks its arguments against the types its call sites actually pass
.
Thanks to xet7.
-
Every bundled binary now runs through cpu-exec on Sandstorm and in the snap, so a CPU
missing an instruction-set feature falls back to qemu-user instead of killing the app
with SIGILL. cpu-exec (#6458) exists for exactly that — AVX masked by a hypervisor
(QEMU/KVM/Proxmox), an old CPU, ARMv8.0 on a Raspberry Pi — and with no features
declared it is a plain exec, which is why the design is to route everything through it.
Sandstorm SHIPPED cpu-exec and qemu-x86_64 but its grain launcher spawned all eight
bundled binaries directly (ferretdb, mongod 3.0 twice, niscud, the legacy mongo CLI
twice, and node for the bridge and the importer), so the safety net sat in the package
unreachable — on the platform with the least control over its hardware, since a grain
runs on whatever CPU the host has. The snap routed mongod but not FerretDB
(ferretdb-control, both the external-DB and SQLite launches) and not node
(wekan-control, the main application start and both maintenance-page starts). Both are
routed now, each with a direct-exec fallback so an older deps image or snap revision
still works; on Sandstorm the guard also requires /bin/bash, since cpu-exec is a bash
script, and the snap's main start keeps its ulimit -s 65500. Docker and the bundle
launcher already routed their binaries and were rechecked for other unrouted launches.
The wiring guard previously asserted only that the Sandstorm build SHIPS cpu-exec —
exactly how the gap survived — and now asserts that each launcher actually uses
it.
Thanks to xet7.
-
rebuild-wekan.sh now raises the inotify watch limit when it is too low, and
.meteorignore stops Meteor watching .tools/ and FerretDB/. Meteor's file watcher
takes ONE inotify watch per DIRECTORY, and fs.inotify.max_user_watches is per USER,
shared with every other watcher — an editor is usually the other big consumer. When it
runs out, Meteor fails with a message that blames the disk and sends people looking in
the wrong place: inotify_add_watch on '<path>' failed: No space left on device. ENOSPC
from inotify_add_watch means the WATCH LIMIT is exhausted, not that the disk is full.
Two non-app trees were 72% of this repo's 41,040 watched directories — .tools/ (20,535
dirs, 4.1 GB: a full Node install with headers for every openssl arch, a Go toolchain
with its caches, build logs) and FerretDB/ (9,148 dirs, 3.4 GB: the Go fork checkout).
Both were already in .gitignore, but the watcher only honours .meteorignore, so
Meteor kept walking them; excluding them takes the count to 11,213. And
rebuild-wekan.sh now checks the limit on every run and raises it to 524288 (plus
max_user_instances to 1024) with sysctl, persisting it to
/etc/sysctl.d/60-wekan-inotify.conf. It never aborts a build: it is a silent no-op
when the limit is already high, uses sudo only when it can, prints the exact commands to
run by hand when it cannot, honours WEKAN_INOTIFY_WATCHES=0 to skip, and returns
immediately on macOS/BSD, which have no
inotify.
Thanks to xet7.
-
Drag handles: the "Show desktop drag handles" toggle now works on touch screens, the card
body pans the board when handles are on, the handle is finger-sized on touch, and tab
order no longer jumps to invisible controls. The rule was
isTouchScreen() || preference, so on a touch screen the OR was already true and the
toggle could never hide the handles — and every handle in the app plus every sortable
handle selector goes through that one helper. The setting is now three states (on, off,
never-chosen): an explicit choice always wins, including OFF on touch, and only
never-chosen lets the device decide, where a touch screen still gets handles by default.
Handles also decide what a DRAG MEANS, and that half was broken too: .minicard and
.list-header carried nodragscroll unconditionally, so with handles ON a finger
dragging across a card neither moved the card (only the handle does) nor panned the board
— it did nothing; they now opt out only when handles are OFF, i.e. only when the element
IS the drag source. The handle itself was a 20–28px icon in the bottom-right corner, a
mouse-sized target that is close to unusable on a wall-mounted infoscreen; on a coarse
pointer it becomes a 48px full-height strip down the leading edge with the card content
padded to match, while a mouse keeps the compact corner handle. And the keyboard
card/list move buttons are focusable but opacity: 0 at the START of the card content,
so tabbing went card → invisible → invisible → next card; they are now revealed while
focused.
Thanks to xet7.
-
The quick-access top bar now fits on ONE row on phones. On an iPhone 12 mini (375px) it
wrapped to two rows — home + logo + mobile/desktop toggle on the first, drag-handle
toggle + zoom + notifications + user menu on the second. The mobile CSS chose that
deliberately (a nowrap row overflowed and was clipped), but that treated the symptom: the
row did not fit because the home link kept its full "All Boards" label — the widest item
in the bar, and longer still in most languages — the logo was allowed 120px of a 375px
bar, TWO items had margin-inline-start: auto (an auto margin absorbs all remaining
space on its line, so the first one filled row 1 and pushed the rest onto row 2), and
items carried 8px gaps plus 0.5rem margins on both sides on the iPhone path. The row now
fits: icon-only home link, an 84×20 logo cap, exactly one auto margin, 6px gaps and 3px
margins — 342px of 375px by the declared sizes. The home label is a bare text node so it
cannot be selected directly; font-size: 0 on the link collapses it and the icon's own
size brings the icon back, with the text still in the DOM for screen readers. Both the
@media path and the .iphone-device path (added by boardBody.js, so present on a board
page and absent on All Boards) were changed together, or the bar would have changed
height when navigating between those two
screens. The "All Boards" label is also
hidden whenever mobile MODE is on, which is a different thing from a narrow viewport:
body.mobile-mode comes from the phone/desktop toggle in that same bar, is a deliberate
user choice and applies at any width, so on a wide screen in mobile mode the label was
still showing](https://github.com/wekan/wekan/commit/b9f178ef5). Hiding the label needed
!important and the last word in the file: ELEVEN rules in header.css set a font-size
on that same link, most of them !important, including three scoped to the All Boards
page itself (body:not(.board-view) / .wrapper ~) and one setting 16px !important
— so the first attempt lost to all of them and the label kept showing on exactly the page
it was reported on. The notification bell also sat in 36px of margin around a 28px icon
(10px each side of the button plus 0.5rem each side of its wrapper); both layers now give
2px a side, taking the measured one-row budget from 342px to 320px of
375px](https://github.com/wekan/wekan/commit/76516a1a2). Finally, the avatar still
dropped to a second line with space left beside the bell, because a width-based rule
forced flex-wrap: wrap !important on that bar — added deliberately, "so ~7 items fit in
two wrapped rows". An !important wrap beats any nowrap, so none of the one-row work
took effect at small width, and a wrapping flex row breaks BEFORE the last item rather
than shrinking anything. All eight flex-wrap rules on the bar are now nowrap, and the
username/full name beside the avatar is hidden at small width too (the template hides it
unless isMiniScreen, but that also weighs mobile mode and the device, so it can be true
while the bar is narrow, and a full name is easily 100px+ of a 375px bar). Measured
budget: 328px of 375px](https://github.com/wekan/wekan/commit/fff495127).
Thanks to xet7.
-
Board tiles and the "+ Add Board" / "+ Add Template Container" tile are now the same,
shorter height on mobile. A board tile was 8rem (128px) on a phone while the add tile had
no mobile height at all — it fell back to the desktop min-height: 72px plus 42px of
padding and then grew further around its wrapped label — so the two were never the same
height and both wasted vertical space. Both are now a flat 4rem (64px) with
box-sizing: border-box, so the number is the rendered height rather than a floor that
padding is added to, and the board tile's 24px/18px vertical padding (what made it tall)
is cut to 6px. One rule covers every All Boards tab — Starred, Templates, Remaining and
Workspaces all render the same .board-list
tiles. Only the add tile actually shrank
at first, leaving a board icon towering over "+ Add Board" on the Remaining tab: two
selectors set that height and they are not equally specific —
.board-list.mobile-view .board-list-item (0,3,0) beat .board-list .board-list-item
(0,2,0), while the add tile escaped because its own selector is also (0,3,0) and came
later. Both .mobile-view shapes are now spelled out, and because that 8rem rule sits
outside any media query — .mobile-view comes from Utils.isMiniScreen(), which weighs
mobile mode and the device as well as width — the override is repeated outside the media
query too](https://github.com/wekan/wekan/commit/000a29129). The tiles STILL differed for
a reason unrelated to either height: the mobile board list is a grid with a fixed height
and no align-content, so it defaulted to stretch and its single row filled the whole
column — "+ Add Board" showed a 4rem grey label at the top of a stretched cell, while a
board's li carries the board colour itself and painted the entire cell. align-content: start plus align-items: start keeps rows at their content height, and the list still
scrolls because that comes from the fixed height plus overflow-y: auto. The two mobile
columns are also rebalanced from minmax(84px, 30%) to minmax(140px, 42%): at 30% of a
375px phone the left menu was ~112px so "Workspaces" and the counts wrapped, while the
board column had more width than two 4rem tiles need — it is now ~158px of menu and
~209px of boards, still fitting two ~96px tiles side by
side](https://github.com/wekan/wekan/commit/534b80f92).
Thanks to xet7.
-
All Boards on a phone now matches what a wide screen already does: board titles read
left to right instead of breaking one letter per line, "+ Add Board" spans both columns,
the folder name and the search box share one row, and the search placeholder is gone. The
titles broke because space for the single ~26px absolutely-positioned drag handle was
reserved THREE times on the way down — 32px on the li, 30px in the tile padding and
30px again on .details — which on a ~96px tile left about nothing for text; it is now
reserved once, on the innermost container, leaving ~52px. The header wrapped because the
search box would not shrink (a flex item's default min-width: auto refuses to go below
its content width), so min-width: 0 plus flex: 1 1 auto lets it take what is left
beside the title. The "Search boards" placeholder filled the whole box on a phone and is
replaced by an aria-label, which is what a placeholder should never have been standing
in for. "+ Add Board" and a board tile
are then made identical in size: the add tile is one grid cell again rather than spanning
both columns, and — since .js-add-board carries margin: 8px !important while
.js-board carries margin: 8px — both are zeroed at small width rather than only one,
which would have made the add tile the odd one out instead. The grid's own 8px gap
already separates the cells, so every tile is one 96×64px cell at 375px, add and board
alike](https://github.com/wekan/wekan/commit/8fd2982ec). The menu title also goes ABOVE
the search box on a phone rather than beside it: squeezed onto one row, "Remaining" was
ellipsised to "R.." and the search still had barely any width. They stack again, but
without the tall empty band that made stacking look wrong before — each part takes
exactly one full-width row with a fixed 6px row-gap, so the search sits directly under
the title](https://github.com/wekan/wekan/commit/9d0908e4b).
Thanks to xet7.
-
"Show desktop drag handles" now works on the All Boards page too. It governed swimlanes,
lists and cards on a board, but board TILES always showed their handle and were always
draggable from anywhere, so turning handles off did nothing there. The handle markup is
now behind the same helper in both places it appears, and — the half that matters — so is
the drag source: with handles ON the handle is the only place a board drag may start, so
a finger dragging across the rest of the tile scrolls the list instead of picking the
board up, the same contract cards and lists follow. Boards use HTML5 drag-and-drop rather
than jQuery sortable, so this could not be done by swapping a handle option: the li
keeps draggable="true" (a drag can only start from a draggable element, and moving the
attribute onto the handle would drag the handle rather than the board) and dragstart
cancels the drag unless it began inside .board-handle. With no handle rendered, the
title reclaims the 28px reserved for
it.
Thanks to xet7.
-
Adding a workspace now shows a real input field. The "+" beside Workspaces called
window.prompt(), which a browser is free to refuse — iOS Safari offers "don't allow
further prompts" for a page and then suppresses every later one, so the button did
nothing at all and no input field ever appeared. It now opens a normal WeKan popup with a
text input and a submit button, the same pattern every other create flow uses; submitting
it empty keeps the popup open and refocuses the field rather than closing silently, which
is what a cancelled prompt looked like. This was the only window.prompt() left in the
client.
Thanks to xet7.
-
Admin Panel tables fit the screen and wrap their text on a phone. Admin Panel / Version
needed a horizontal scroll to read a value that easily fits on screen — "WeKan Version"
at the left edge and its version number about a thousand pixels away — because every
admin table is forced to min-width: 1200px !important with white-space: nowrap cells,
to guarantee a scrollbar for the wide data tables. Reasonable for those, but a two-column
table is pushed to 1200px for nothing and nowrap cells can never use a second line. At
small width the table is now at most as wide as the screen and cells may use as many
lines as they need, with long unbroken values (version strings, paths, URLs) breaking
rather than pushing it wide again; the label column keeps a 45% share so it does not
collapse beside a long value. Horizontal scrolling still works where a table genuinely
cannot fit.
Thanks to xet7.
-
Search All Boards on a phone now fits the width, scrolls down, and drags with a finger.
Label Colors ran off the right edge because .global-search-page is
width: 40%; min-width: 400px — sized for a desktop column — so on a 375px phone the
block was already wider than the screen and the palette's flex-wrap: wrap had nothing
to wrap into. The page could not be scrolled down AT ALL because .wrapper, the GLOBAL
layout element, is given height: 100vh; overflow: hidden by the All Boards stylesheet at
this width: fine for the boards page, which has its own scroll container, but it applies
to every page and this one had none, so everything below the fold was unreachable. And
dragscroll did nothing because dragscrollTouch.js scrolls the nearest .dragscroll
ancestor that can actually scroll, and no element here carried the class. The help panel
and the results list are now width-constrained, bounded scroll containers carrying
.dragscroll; the query form shares the class but is a short fixed header, so it is
explicitly excluded from becoming a scroll box of its
own. Giving each panel its own scroll
box turned out not to work — the panels start BELOW the search form, so their bottoms and
their scrollbars ended up past the bottom of the clipped wrapper, leaving text cut
mid-character after "Notes" on iPhone and the list ending at "Differing operators … red
label." on Fairphone 4. The page now has exactly ONE scroll container: its wrapper is
tagged global-search-wrapper and is height: auto; min-height: 100vh; overflow-y: auto
at phone widths, with the panels back to plain content. .dragscroll moved to that
wrapper and was REMOVED from the panels, which is required rather than tidying —
dragscrollTouch.js takes the nearest .dragscroll ancestor and gives up if it cannot
scroll, so leaving the class on a now-static panel would have disabled finger dragging on
the whole page](https://github.com/wekan/wekan/commit/be07356cc). That single-inner-scroller
still fought the ancestor: the wrapper box (min-height: 100vh) is taller than its parent
#content, which is itself a scroller in mobile mode, so both scrolled — on iOS Safari
the page rubber-banded back to "Differing operators" at the bottom, while Fairphone
Firefox merely reached the end. The clip is now released WITHOUT adding any scroller
(.wrapper for this page is height: auto; overflow: visible), leaving #content — the
page's existing scroller, and what a finger scrolls natively on touch — as the single
scroller, which cannot fight itself. The .dragscroll class is dropped from the wrapper
since native scrolling now handles it. A last touch clears iOS Safari's bottom toolbar,
which was still covering the final line: the scroller #content is calc(100vh - 48px)
and on iOS 100vh is the large viewport (toolbar hidden), so its bottom edge sits behind
the toolbar — the wrapper now has calc(120px + env(safe-area-inset-bottom, 0px)) of
trailing space so the last line scrolls clear of
it. The bottom stayed unreachable through several attempts because the cause was
#content, not the wrapper: #content is a flex child, and a flex child defaults to
min-height: auto — it grows to fit its content and never scrolls, so anything past the
fold overflowed out of reach. On this page (min-height: 0 on #content, scoped with
body:has(.wrapper.global-search-wrapper) so no other page is affected) it becomes a
real scroller, inside a 100dvh body so the bottom tracks Safari's toolbar instead of
hiding behind the large-viewport 100vh, with overscroll-behavior: contain to stop the
landscape pull-to-refresh. A finger drag over the grey content area still did nothing
while the header bars scrolled — because the header sits outside #content, that proved
the body is the real scroller and #content's own overflow-y: auto was trapping the
touch; #content is now a pass-through (overflow: visible; flex: 0 0 auto) so the body
is the single scroller, draggable by a finger
anywhere](https://github.com/wekan/wekan/commit/762547b92).
Thanks to xet7.
-
All Boards in iPhone landscape: the left menu no longer balloons and the folder header no
longer collides. Landscape is ~844px CSS-wide — above the 800px breakpoint but still an
iPhone, so the device-width media query applies while the max-width: 800px rules do not.
That split made the left menu 42% of 844px (~354px), flinging each count chip ~250px
from its label, and left the folder header ("Remaining" + multi-selection buttons +
search) on a single row where the buttons overlapped the title. The menu is now
minmax(140px, min(42%, 210px)) (portrait unchanged at 158px, landscape capped at 210px)
with the count packed next to its label, and the header's stacking media query carries the
same device-width branch as the grid so it stacks in landscape
too.
Thanks to xet7.
-
Board tiles no longer merge on a laptop. The phone equal-tile work had six rule groups
whose selector lists carried a bare .board-list ... variant next to the intended
.board-list.mobile-view ... one, so they also hit the desktop float layout where
.mobile-view is absent — margin: 0 !important on .board-list li.js-board killed the
8px gap that .board-list li { width: 20%; margin: 8px } relies on, so adjacent coloured
tiles touched and read as one block. All six are now .mobile-view-only, restoring the
desktop layout while leaving the phone layout
unchanged.
Thanks to xet7.
-
The top-bar zoom %, notification bell and user/avatar menu now stay at the END of the
quick-access bar — the right edge in LTR, the left edge in RTL. They are the last items
in the bar and the middle starred-boards list normally pushes them there with flex: 1,
but that list is display: none on a phone, so with nothing filling the middle the group
bunched at the start with empty bar beside it. A single margin-inline-start: auto
(logical, so it flips for RTL automatically) on the first item of the group pushes the
whole group to the end, with the row's other auto margin cleared so they do not split
apart.
Thanks to xet7.
-
Board tiles on All Boards are now a responsive grid, so widening the window adds more
boards per row instead of stretching the tiles. Both layouts were fixed-column — desktop
float: width 20% (5, wrapping to 4) and the mobile grid repeat(2, 1fr) (always 2) — so
more width just made the tiles wider. They are now
repeat(auto-fill, minmax(…, 1fr)): desktop minmax(200px, 1fr) (~3 columns at 1000px up
to ~11 at 2500px) and mobile-view minmax(min(46%, 200px), 1fr) (keeps ~2 columns on a
narrow phone but scales up on a wider one), with the 8px grid gap replacing the per-tile
margins. Phones still pin two columns via the small-width media
queries.
Thanks to xet7.
-
All Boards drag-and-drop and touch targets. A mouse drag can reorder boards again: the
board list <ul> is a .dragscroll element so the mouse dragscroll library was panning
it instead of starting the tile's HTML5 drag, and a.js-open-board being a link meant
grabbing the title dragged the URL — the tile is now .nodragscroll and the link
draggable="false". With drag handles ON, dragging the handle did nothing because the
gate checked dragstart.target, which in Chrome/Firefox is the whole draggable li, not
the handle; the press location is now recorded on mousedown and read in dragstart.
And "+ Add workspace" is now a 44px touch target instead of a ~20px "+" a finger kept
missing. Reordering by FINGER did not work yet at this point — board reorder uses HTML5
drag-and-drop, which browsers do not fire from touch; that is fixed by the touch
drag-and-drop bridge in a later entry below (a separate, tested change, without discarding
any of the mouse fixes here).
Thanks to xet7.
-
All Boards drag-reorder now persists and can move a board to the end, and the header is
decluttered. Dropping one board onto another threw INVALID [400] because
profile.boardSortIndex (written on reorder) had no schema entry while the user
profile enumerates its subfields — a schema field is added. Dropping on a board can
only place it BEFORE that board, so a dashed "drop here to move to the end" placeholder
follows the drag: while a board is dragged, an empty gap opens up before or after the tile
under the cursor — anywhere in the current view (Starred / Templates / Remaining / a
workspace), the end included — showing where it will land, backed by a pure
computeReorderedIds(..., after) that inserts on either side and no-ops a drop into the
board's own slot; the drop reads the gap's real DOM position (so releasing OVER the gap
works — the placeholder is not a board tile, which had made the board snap back to its
original position). Hovering anywhere on a board icon opens the gap at THAT icon's slot
(drop to take its place), rather than needing to aim the icon's left half; only the last
icon's trailing half inserts after, to keep the end reachable. The dragged icon is taken
out of the grid flow while dragging (the other icons reflow as if it were gone), so the
gap lands exactly where the icon will go rather than one slot to the left, and the drag
ghost is centred on the cursor (setDragImage) so the gap opens for the icon the ghost is
over rather than needing to aim the target's left edge. And the
current folder's NAME beside its icon in the header ("Starred"/"Remaining"/a workspace
name) is hidden — redundant with the icon, the highlighted menu row and the "My Boards"
title, and it crowded the Multi-Selection / Sort / search controls — kept for screen
readers only. The section icon left of the Multi-Selection button is now the same Font
Awesome glyph and colour as the matching left-menu item (fa-star / fa-clipboard /
fa-folder / fa-folder-open, #4d4d4d) instead of a Unicode
emoji.
Thanks to xet7.
-
Board icons can now be reordered by FINGER, not just with a mouse — and the same fix
makes every other HTML5 drag-and-drop in WeKan work from touch. HTML5 drag-and-drop
(draggable="true" + dragstart/dragover/drop) is never fired from touch by any browser,
so on a touchscreen the board-icon reorder above, the workspace drag-to-share and the
card/rule drags could only be driven with a mouse. Rather than rewrite reorder onto
jQuery-UI-sortable (which would have discarded every mouse fix in the two entries above), a
small bridge, client/lib/dragDropTouch.js, makes a finger drive the SAME handlers: a
long press (250 ms) on a draggable element starts a synthetic drag that dispatches real,
bubbling dragstart/dragenter/dragover/dragleave/drop/dragend events with a dataTransfer
shim, so the delegated handlers run unchanged. It is deliberately safe beside the existing
touch scrolling — a quick swipe on a draggable tile still scrolls, and it only calls
preventDefault once a drag is actually under way; it fires a mousedown on the pressed
element first so the reorder's handle gate (which records the press location) works from
touch too; it honours setDragImage so the ghost is centred on the finger as it is on the
cursor; and it leaves form fields and jQuery-UI sortables (lists / swimlanes / cards,
already covered by touch-punch) alone. Loaded globally, with source-guard tests pinning the
scroll-coexistence and handle-gate properties.
Thanks to xet7.
-
All Boards header on a phone: the section icon and the Multi-Selection / Sort buttons now
share ONE row with the Search box on its own row below, instead of the section icon
sitting alone on a wasted first line; the blue Sort button always shows a sort icon (the
plain fa-sort glyph, as a direct i.fa child like the Multi-Selection button beside it,
rather than the wrapped fa-sort-alpha-asc that showed as a blank blue square); and on the
narrow left menu each workspace NAME keeps a small floor of width so at least the first few
characters stay visible (with the trailing menu button and count shrinking first), so a
workspace can be told apart while it is dragged — an unnamed workspace still shows just its
icon.
Thanks to xet7.
Thanks to above GitHub users for their contributions and translators for their translations.