mirror of
https://github.com/multica-ai/multica.git
synced 2026-08-03 11:10:23 +02:00
fix/transcript-virtual-scroll
9 Commits
| Author | SHA1 | Message | Date | |
|---|---|---|---|---|
|
|
17ee59ccc5 |
feat(editor): standard Mermaid viewer with pan/zoom, exports and a real dialog (MUL-4908) (#5564)
* feat(editor): standard Mermaid viewer with pan/zoom, exports and a real dialog (MUL-4908) Mermaid's fullscreen view was a bespoke lightbox: no visible close button, no canvas interaction, and a toolbar that scrolled away with wide diagrams. Escape also stopped working once the iframe took focus, which is why it read as "impossible to close". Replace it with a viewer built on the shared Dialog, so it inherits the backdrop, focus trap, scroll lock, focus restore and Escape handling that HTML preview already had. The diagram stays in an `sandbox=""` iframe — isolation is not relaxed to buy interactivity. Instead the iframe is `pointer-events: none` and pan/zoom is applied from the host document as a transform on its wrapper. That inversion is also what keeps Escape working: the iframe can never take focus. - Viewer: fit-on-open, drag pan, wheel/pinch/keyboard zoom (25%-400%) anchored at the pointer, Fit / 100% / Reset, and a header toolbar that cannot scroll away. Panning is clamped so the canvas can never be lost. - Export: `.mmd`, `.svg` and `.png`. Requires `htmlLabels: false` — browsers do not rasterize Mermaid's default HTML-in-foreignObject labels through an `<img>`; verified in Chromium that they paint zero pixels AND taint the canvas, so PNG export silently produced nothing. - Inline: toolbar lifted out of the scroll container, natural-size rendering (small diagrams centered, wide ones scroll at a readable size with edge fades), copy source, and a parser message on the error fallback. - Theme switches no longer close the viewer or discard zoom/position; the previous diagram stays on screen until its replacement is ready. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> * fix(editor): stop Mermaid drags selecting text and misfiring the viewer (MUL-4908) Two gesture defects on the inline diagram, reported by Naiyuan. 1. Dragging a diagram started a native text selection. The iframe is a replaced element, so the whole diagram box got painted with the selection highlight and the drag ran on into the surrounding comment text. Fixed with `user-select: none` on the inline scroller and the viewer canvas. Deliberately NOT by preventDefault-ing pointerdown: verified in Chromium that it also drops the default focus, which silently kills the viewer's keyboard controls (+/-, 0, arrows). 2. Any drag ended in a `click`, so trying to look along a wide diagram opened the viewer on top of the user. The inline diagram had no drag handling at all — only `onClick`. Suppressing the selection alone would have made this fire more reliably, not less, so both had to land together. Past a 5px threshold the gesture is a drag for good: releasing no longer taps, and a horizontal drag pans the scroller instead. This holds even when the diagram has no room to scroll, so an unscrollable diagram cannot open on release either. A still click, a sub-threshold jitter, and the expand button all still open the viewer. Touch is left alone — it already pans natively and its vertical drags belong to the page; the browser announces its takeover with pointercancel. Mouse and pen have no native drag-to-scroll and are panned here. Verified in Chromium: still click opens; a 150px drag pans and does not open; a drag on an unscrollable diagram does not open; 3px jitter still opens; and no gesture selects text. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: Walt <walt@multica.ai> Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> |
||
|
|
3b08456264 |
feat(views): block draft-fixing actions while attachments upload (#5465)
Submitting a composer mid-upload silently lost the file: the editor holds a `blob:` placeholder that gets stripped during serialization, and the attachment id does not exist yet, so the send succeeded without the file. Chat and Quick Create gated this; manual issue create, Feedback's button, comments, replies and comment edit did not. Gate every action that FIXES a draft — Send/Create/Save, Cmd/Ctrl+Enter, Enter on the title, and the manual/agent mode switches — behind one source of truth: the editor document, which IS the upload queue. ContentEditor publishes queue transitions via `onUploadingChange` (a transaction listener, not `onUpdate` — that path is debounced and skips no-change emissions, and a failed upload leaves byte-identical markdown, so the un-gate would never fire). `useUploadGate` pairs that render state with an `isBlocked()` re-read at submit time, since the shortcut paths never consult the button. The publisher emits its current answer on subscribe rather than only on flips: hosts outlive editor instances (comment edit remounts on cancel, chat swaps by key on agent switch), and an editor torn down mid-upload would otherwise leave submit wedged shut with no pending node left to reopen it. Also fixes the failure toast that never fired: `uploadWithToast` only reported errors if a caller passed `onError`, and none did, so failed uploads removed their placeholder and vanished unexplained. `useEditorUpload` now supplies it once for every composer. Per MUL-4808: drops Quick Create's upload-time lock on the attach button (files can queue), and leaves description autosave ungated by design. Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com> Co-authored-by: multica-agent <github@multica.ai> |
||
|
|
343ace89a7 |
feat(editor): MUL-3557 add one-click task-list toggle to bubble menu (#4538)
Add a dedicated checkbox/task-list toggle button to the editor bubble menu, between the List dropdown and Quote. It turns the current line(s) into a `- [ ]` task item or back to a paragraph in one tap, reusing the existing toggleTaskList() command and the same Toggle/Tooltip pattern as the neighboring controls. Adds bubble_menu.task_list locale keys for en/zh-Hans/ja/ko. Co-authored-by: Lambda <lambda@multica.ai> Co-authored-by: multica-agent <github@multica.ai> |
||
|
|
dfc159e1aa |
feat: skip agent triggering on /note-prefixed comments (MUL-3115, #3649) (#3885)
* feat(comments): skip agent triggering on /note-prefixed comments A comment whose first token is the reserved /note prefix (case-insensitive) is stored like any other comment but never wakes an agent. The guard sits at the top of triggerTasksForComment, the single chokepoint, so it covers all three trigger paths — assignee, squad leader, and @mentioned agents. Gating only shouldEnqueueOnComment (as originally proposed) would still let "/note @agent ..." through the mention path. Lets members leave human-only tips/notes on agent-assigned issues without burning an agent run. MUL-3115, closes #3649. Co-authored-by: multica-agent <github@multica.ai> * feat(editor): add /note built-in slash command to comment composer Enable the `/` menu in the issue comment and reply composers in a new "command" mode that lists fixed built-in commands instead of the chat skill picker. Currently one command, /note, which marks a comment as a human-only note that won't trigger the assigned agent. Selecting it inserts the plain-text "/note " prefix (not a rich node), so a menu pick and a hand-typed command are byte-identical and the backend detects either with a simple prefix match. The command menu renders nothing on a non-matching `/` (hideOnEmpty) so typing a date like 6/8 isn't noisy. The chat skill picker is unchanged. MUL-3115. Co-authored-by: multica-agent <github@multica.ai> * refactor(editor): match /note by label prefix and localize its description Address PR review feedback: - buildBuiltinCommandItems now matches the command label as a prefix only, dropping the description substring match copied from the skill picker. With one command this keeps the menu predictable (/no surfaces note; /deploy or a description word like /agent shows nothing) and avoids Enter selecting note unexpectedly. - The command description is now a localized UI string: added slash_command.commands.note to all four editor locales (en/ja/ko/zh-Hans) and the menu renders it via the typed translator. The /label itself stays literal since it's the typed token the backend matches. MUL-3115. Co-authored-by: multica-agent <github@multica.ai> * fix(editor): shorten /note command description to avoid truncation The slash menu item is single-line (truncate, w-72), so the longer copy was cut off. Shorten to "won't trigger any agents" across all four locales — also more accurate, since /note skips assignee, squad leader, and @mentioned agents, not just the assigned one. MUL-3115. Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: J <j@multica.ai> Co-authored-by: multica-agent <github@multica.ai> |
||
|
|
b0d479c6e7 | fix: use mentions for chat context (#3755) | ||
|
|
0d38288dbd |
MUL-2926 feat(editor): support markdown checkbox task lists (#3593) (#3657)
* feat(editor): support markdown checkbox task lists (#3593) Render `- [ ]` / `- [x]` as interactive checkboxes in the issue content editor, matching GitHub / Notion. - Register TaskList + a patched TaskItem in the shared extension factory. Both ship their own markdown tokenizer / renderMarkdown, input rules, and a checkbox NodeView; the taskList tokenizer is consulted before marked's built-in list tokenizer, so `- [ ]` becomes a task while a plain `- ` still falls through to the bullet list. - Patch TaskItem's keymap to share PatchedListItem's split -> lift Enter chain (double-Enter on an empty item exits the list); nested: true enables sub-tasks and nested round-trips. - Add a "Task list" entry to the bubble-menu list dropdown (+ i18n for en / zh-Hans / ja / ko). - Style task lists in prose.css for both the editor ([data-type="taskList"]) and the readonly remark-gfm output (.contains-task-list); completed items render muted. Readonly already rendered task lists via remark-gfm; this brings the editable view to parity. Adds markdown round-trip and readonly checked-state tests. MUL-2926 Co-authored-by: multica-agent <github@multica.ai> * fix(editor): keep readonly nested task lists block-laid-out (#3593) The shared `display: flex` rule on task-list items broke nested task lists in the readonly view. remark-gfm renders a task item as `<li><input> text <ul>…</ul></li>` — no body wrapper — so a nested list is a direct sibling of the checkbox and text, and flex pulled it onto the same row. The editor's Tiptap NodeView wraps the body in a `<div>`, so it was unaffected. Split the task-list CSS into separate editor and readonly blocks: the editor keeps the flex row; readonly stays a block list item with an inline checkbox so a nested `<ul>` drops below and indents under its parent. Adds a readonly test that pins the nested DOM shape (nested `<ul>` inside the parent `<li>`), so a future remark-gfm change that wraps the body fails loudly. MUL-2926 Co-authored-by: multica-agent <github@multica.ai> * feat(editor): convert `- [ ] ` typing into a task list (#3593) TaskItem's built-in input rule only converts `[ ] ` / `[x] ` typed at the start of a plain paragraph. When the user types the GitHub-style `- [ ] ` the leading `- ` first turns the line into a bullet, and the built-in rule no longer fires — so `[ ]` stayed as literal text and nothing became a checkbox. Add an input rule on PatchedTaskItem that catches the checkbox token when it is the entire content of a freshly-typed list item (bullet or ordered) and converts just that item into a task item (deleteRange → liftListItem → toggleList). The anchored regex means it only fires on an item whose whole content is `[ ] ` / `[x] `, so sibling items in the same list are left untouched. Adds typing-level tests (real input-rule simulation) covering `[ ] `, `[x] `, `- [ ] `, `- [x] `, the mixed-list split case, and the plain-bullet no-op. MUL-2926 Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: J <j@multica.ai> Co-authored-by: multica-agent <github@multica.ai> |
||
|
|
0d51614c9c |
feat(editor): text highlight (==text==) in description & comments [MUL-2934] (#3661)
* feat(editor): support text highlight (==text==) in description & comments Adds a single-color (yellow) text highlight mark to the shared rich-text editor, round-tripped through stored Markdown as ==text==. - HighlightExtension: @tiptap/extension-highlight + @tiptap/markdown hooks (markdownTokenizer/parseMarkdown/renderMarkdown) so ==text== <-> <mark> round-trips; inner inline formatting preserved via inlineTokens. - Bubble menu: highlight toggle button (Mod-Shift-H), i18n in 4 locales. - Read-only renderer: highlightToHtml lowers ==text== -> <mark> (skips code and math); rehype-sanitize schema whitelists <mark>. Nested Markdown inside a highlight still parses via the existing rehype-raw step. - prose.css: single yellow <mark> style, legible in light/dark. Pinned @tiptap/extension-highlight to exact 3.22.1 to match @tiptap/core (>=3.23 expects a getStyleProperty export core 3.22.1 doesn't have). Web/desktop only. Mobile (native md4c, no == syntax, no custom renderers) is tracked as a follow-up. MUL-2934. Tests: editor round-trip (cross-process serialization protocol), readonly <mark> rendering + sanitize, and the ==->mark transform incl. code-skip. Co-authored-by: multica-agent <github@multica.ai> * fix(editor): align highlight boundary rules across editor & readonly Addresses two boundary bugs from review (PR #3661): 1. A == inside inline code/math could close a highlight when the opening == was outside the literal span (e.g. ==a `b==c` d== wrongly became <mark>a `b</mark>c` d==). Both the editor tokenizer's lazy regex and the readonly transform only guarded the opening fence, not the closing one. 2. The readonly transform matched across blank lines (==a\n\nb==) while the editor lexes those as two literal paragraphs — a storage↔editor↔readonly mismatch. Fix: extract one shared matcher (utils/highlight-match.ts) used by BOTH the editor tokenizer and the readonly lowering, so the rules can't drift. It skips fences that fall inside code/math literal ranges (open or close) and caps the inner span at the first blank line. Tests: shared-matcher unit tests + both repros covered on the editor (round-trip/HTML) and readonly (transform + rendered DOM) sides. Co-authored-by: multica-agent <github@multica.ai> * fix(editor): handle CRLF in highlight blank-line boundary BLANK_LINE_RE only matched LF, so a CRLF blank line (==a\r\n\r\nb==) was not recognized as a block boundary and got highlighted. Widen to \r?\n[ \t]*\r?\n. Tests: CRLF blank-line (no highlight) + CRLF soft-break (still highlights) on the matcher, readonly transform, and editor sides. Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: Lambda <lambda@multica.ai> Co-authored-by: multica-agent <github@multica.ai> |
||
|
|
91c1e51411 |
feat(editor): add / slash-command palette for invoking agent skills (#3159)
* feat(editor): add / slash-command palette for invoking agent skills Adds a `/` trigger in the chat box that opens a popover listing the active agent's skills. Selecting an item inserts a `[/label](slash://skill/<id>)` token; the daemon extracts those IDs in `buildChatPrompt` and emits an "Explicitly selected skills:" block using the canonical names from the agent's skill registry — labels are display-only and never trusted. Built on Tiptap's `Mention` extension so the suggestion lifecycle, keyboard routing, and IME handling mirror the existing `@` mention UX. Item list is sourced from the React Query workspace cache (no per-keystroke fetch). Gated behind a new `enableSlashCommands` prop so only `chat-input` opts in; other `ContentEditor` consumers (issue editor, comments) are unaffected. Read-only markdown surfaces render the token as a `.slash-command` pill via a custom link renderer + sanitize-schema/url-transform allowlists. Closes #3108 * fix(i18n): add slash_command editor copy for ko/ja The PR added slash_command popover empty-state keys to en + zh-Hans only; locales/parity.test.ts requires every locale to cover every EN key, so ko and ja failed CI. Add the two keys (no_skills_configured, no_results) matching existing skill terminology (스킬 / スキル). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> --------- Co-authored-by: Naiyuan Qing <145280634+NevilleQingNY@users.noreply.github.com> Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com> |
||
|
|
1aa742053b |
i18n: add japanese locale (MUL-2893) (#3538)
* i18n: add japanese locale * fix: spacing issues * refactor * fix(desktop): set <html lang> before paint to avoid JA Kanji font flash Switch the documentElement.lang sync from useEffect to useLayoutEffect so lang is committed before the first paint. Otherwise Japanese desktop users saw one frame of Kanji rendered with the Chinese-first fallback stack before the html[lang|="ja"] CJK override applied. Also fix the stale selector in the HTML_LANG comment (html[lang^="ja"] -> html[lang|="ja"]). Addresses review nits on MUL-2893. Co-authored-by: multica-agent <github@multica.ai> * fix(docs): tokenize the ideographic iteration mark in JA search Add U+3005 (々) to the Japanese search tokenizer character class. It sits just below the kana blocks, so words like 様々 / 日々 / 個々 previously dropped the mark and split awkwardly, hurting recall. Addresses a review nit on MUL-2893. Co-authored-by: multica-agent <github@multica.ai> * fix(i18n): restore ja locale parity after merging main Merging main brought new EN strings into agents/chat/onboarding/settings/ squads that the ja bundle (authored against an older snapshot) lacked, breaking the locales parity test. Add the Japanese translations for the new keys (workspace logo upload, agents runtime filter, chat session-history stop dialog, onboarding social_github, squad archived status) and drop the two renamed chat window keys (active_group / archived_group) that EN removed in favour of history_group. Fixes the failing @multica/views parity.test.ts on the FE CI for MUL-2893. Co-authored-by: multica-agent <github@multica.ai> --------- Co-authored-by: J <j@multica.ai> Co-authored-by: multica-agent <github@multica.ai> |