feat(collab): shared links, chat images, and plugin fullscreen - #2274
Merged
Conversation
mauriceboe
force-pushed
the
feat/collab-links-chat-images
branch
from
September 8, 2026 20:42
13f6697 to
0fe614f
Compare
Adds a Collab Links panel (add/pin/delete) with translations in every locale so tab and button labels are not raw i18n keys, chat image attachments (up to 4), and native fullscreen on plugin iframes. Includes Zod request DTOs and CollabPanel coverage for the Links tab.
The chat image filter believed the Content-Type the client put on the part. The stored name keeps the extension of the name the client sent, and the download route derives what it serves from that extension and sends it inline, so pwn.html declared as image/png came back as HTML on our own origin. The filter now checks the extension as well, against the blocked list and against the types it claims to accept, because a per-route filter fully replaces the module-level one it looked like it was adding to. The multipart message route also kept its guard decorators. Guards run before the interceptor, so a refusal went out while the client was still streaming up to four images and the socket died as ECONNRESET rather than carrying the error. The checks moved into the handler, where the other upload route in this file already does them, and a test pins both refusals. The three collab:link events were missing from the shared registry, which the server typecheck refuses, and the admin Links switch could never be saved because the Zod contract had no key for it. Both are in now. Migrations moved to the end of the list and the column add uses the pragma guard rather than a caught duplicate-column error. The message-required string keeps its old wording for a request without a file part, so a client from before this route took images sees what it always saw.
…inks The desktop layout rendered notes and links as a pair and dropped whichever of the two was on its own, so turning the new Links feature off on an otherwise default install made the Notes panel disappear. Both rows are now split by kind and rendered only when they hold something, and one function decides what a panel id renders, because the branch that lost a panel did so by not listing it. The message and its attachment rows are written in one transaction. The caller has already committed the image bytes by then, so a message that landed without them left those bytes with nothing pointing at them and nothing to sweep them. Deleting one now drops the blobs after the rows are gone rather than before. A body the Zod pipe rejects used to leave up to four spooled images on disk: pipes run after interceptors, so multer had already written them and the handler's own cleanup was never reached. An interceptor removes them on any failure before the handler, which also covers every other schema mismatch, and the length check that could never fire is gone. Adding, pinning and deleting a link now says something when it fails instead of raising an unhandled rejection, the list has real types, and the rejected-image toast is translated in all 23 locales rather than shipping English everywhere. The picking, previewing and clearing of chat images moved into one hook both shells use: it was copied into two, and both rebuilt every preview on each change and leaked an object URL per image per pick. Tests: the four link routes end to end with the validation pipe the harness was missing, the image filter against the disguised-extension case, and the layout combinations that drop a panel.
The URL check used `new URL(...)`, and this package compiles against lib ES2022 alone so that it carries neither DOM nor Node globals, which is why the shared typecheck refused it. `z.url()` plus a protocol test does the same job with names the package actually has; z.url() on its own would take mailto: and javascript:. The three collab:link events also needed their fixtures and their place in the pinned inventory count, the guard that stops the fixture map drifting from the registry.
…columns The three collab:link events were broadcast and landed nowhere: the links panel held its own list and never listened, so a link somebody else added showed up on the next reload. It listens now, the same shape the notes panel uses, and the events are classified in the client's WS policy, which is the ratchet that caught this. Four e2e harnesses build their own trip_files and one asserts the collab feature set, so the new message_id column and the new links flag had to reach them too. Two MCP unit tests pinned the old four-key feature object.
mauriceboe
force-pushed
the
feat/collab-links-chat-images
branch
from
September 8, 2026 21:25
126305a to
e624c6f
Compare
The chat images never reached a test: committing them to storage, taking them back out when a later one fails, and dropping them again when the reply target turns out to be gone. The interceptor that removes the spool when a request dies before the handler had none either, and it sits in a domain pinned at 99% function coverage. Both filters are pinned too, including the disguised extensions that were the point of changing them.
Open
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
collab.tabs.linksandcollab.links.*added in every locale so the UI shows "Links" / "Add link" instead of raw keys.allowFullScreenandallow="fullscreen"so Kanban and other plugins can go native fullscreen.These are the host patches we have been running on a custom 4.2.1 image (previously
trek-collab:3.5.5).Test plan
node shared/scripts/i18n-parity.mjs— file + key parity OKlinks: falsein feature-off combinationsNotes
TREK contributing guidelines ask for a Discord
#github-prpitch first. Happy to discuss there if this needs to be split (links vs chat images vs fullscreen) or adjusted before review.