Skip to content

Feat/connect nc ai backend#58

Draft
chrip wants to merge 17 commits intomainfrom
feat/connect-nc-ai-backend
Draft

Feat/connect nc ai backend#58
chrip wants to merge 17 commits intomainfrom
feat/connect-nc-ai-backend

Conversation

@chrip
Copy link
Copy Markdown

@chrip chrip commented May 6, 2026

The web-app counter part for feat(smartpicker): wire NC Assistant Smart Picker bridge
Euro-Office/eurooffice-nextcloud#17

This PR is based on the preparation work for Smart Picker by @rikled

rikled and others added 14 commits May 8, 2026 12:08
Signed-off-by: Hendrik Leidinger <hendrik.leidinger@nextcloud.com>
Signed-off-by: Hendrik Leidinger <hendrik.leidinger@nextcloud.com>
Signed-off-by: Hendrik Leidinger <hendrik.leidinger@nextcloud.com>
Signed-off-by: Hendrik Leidinger <hendrik.leidinger@nextcloud.com>
Signed-off-by: Hendrik Leidinger <hendrik.leidinger@nextcloud.com>
…tation editors

api.PastePlainText only exists in cell/api.js (spreadsheet). Calling
it on the documenteditor / presentationeditor api throws and triggers
OnlyOffice's generic 'An error occurred during the work with the
document' dialog, leaving the document in an unrecoverable state.

Route the insertPlainText gateway command through asc_PasteData with
c_oAscClipboardDataFormat.Text instead. The spreadsheet handler keeps
calling PastePlainText since it is supported natively there.

Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
…to literal 1

Asc.c_oAscClipboardDataFormat is undefined in the documenteditor /
presentationeditor runtime — the constant lives on AscCommon. Read
it from AscCommon and fall back to the literal 1 (Text format from
clipboard_base.js) so insertPlainText keeps working even if the
namespace shifts again.

Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
OnlyOffice already ships an AI/sparkles SVG symbol (btn-general-ai)
in apps/common/main/resources/img/toolbar/icons.svg, used by the
Macros 'AI Assistant' dialog. Same MDI 'creation' shape that NC's
Assistant uses, so the Smart Picker toolbar entry now matches both
OO's existing AI surfaces and NC's iconography.

The icon lives in the small (24x24) common sprite, not the per-editor
big (28x28) sprite. SVG scaling makes that visually fine for the
x-huge button — it renders a touch thinner than the surrounding
big-sprite icons but reads as the right symbol. A dedicated
btn-big-general-ai variant can land later if needed.

Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
Closure Compiler advanced-mode renames any prototype property assigned
with dotted notation, so asc_docs_api.prototype.asc_PasteData = ... is
unreachable from outside the bundle (the runtime property name is
mangled). Only methods registered via window['asc_docs_api'].
prototype['<name>'] = ... survive minification.

In sdkjs/word/api.js the only such text-insertion entry is Add_Text
('cool api'), which calls TextBox_Put internally — that is the public
entry for typing characters at the current cursor regardless of
context (body / textbox / etc.).

Switch document and presentation editor insertPlainText handlers to
prefer Add_Text and only fall back to asc_PasteData if a build keeps
the dotted-notation method (it normally won't).

Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
…sertion

Previous attempts (Add_Text, asc_PasteData, PastePlainText) only worked
in the documenteditor — Add_Text is exposed only on word's asc_docs_api,
asc_PasteData is mangled by Closure Compiler advanced-mode in all three
editors, and PastePlainText was removed from the spreadsheet api.
Result: smart-picker silently no-op'd in slide and cell editors.

Switch all three editors' insertPlainText handlers to
this.api['pluginMethod_PasteText'], which is registered in
sdkjs/common/apiBase_plugins.js as
Api.prototype['pluginMethod_PasteText'] — bracket notation survives
minification, the JSDoc declares it valid for ["CDE", "CSE", "CPE"],
and internally it calls asc_PasteData with c_oAscClipboardDataFormat.Text
wrapped in executeGroupActions for clean undo. This is the same entry
point OnlyOffice's own AI plugin uses.

Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
Step (4) of the deeper Assistant integration plan: when the user has
text selected and clicks Smart Picker, the AI's reply should replace
the selected text in place rather than appending at the cursor.

Three changes:

1. Read the active selection via api['asc_GetSelectedText']() at click
   time and forward it through the postMessage payload so NC's
   Assistant can seed its input with it.

2. In documenteditor, drop a hidden bookmark on the selected range
   ('eurooffice_smartpicker_anchor') via the bracket-exposed
   asc_GetBookmarksManager / asc_AddBookmark. The toolbar click would
   otherwise collapse the selection (focus shifts to the button), so
   the range needs to be anchored to survive the modal round-trip.

3. In insertPlainText, restore the selection by SelectBookmark, drop
   the bookmark, then call pluginMethod_PasteText. With the selection
   re-established, asc_PasteData replaces it.

For presentationeditor and spreadsheeteditor we capture selection text
but cannot anchor (no bookmark manager). Inline replacement there is
best-effort: if the editor preserves selection across the toolbar
click, paste replaces; otherwise the AI reply lands at the cursor
(matching the previous behaviour).

Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
…isable

Rename the Smart Picker toolbar entry to 'Nextcloud Assistant' across
the document, spreadsheet and presentation editors (caption + tooltip)
and switch the icon to the bundled Material Design 'creation' sparkles
that NC's own Assistant uses (apps/settings/img/ai.svg, MIT-equivalent
license). The SVG is embedded as a new symbol id='btn-nc-assistant'
in apps/common/main/resources/img/toolbar/icons.svg, so the icon ships
with the bundle and does not depend on Nextcloud serving ai.svg.

Add a host->editor command setSmartPickerEnabled(boolean) so the
host (Nextcloud integration) can disable the toolbar entry at runtime
when the Assistant app isn't loaded. The command travels through the
existing api.js / Gateway.js plumbing and resolves to
btnSmartPicker.setDisabled in each editor controller.

Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
The previous commit edited the assembled apps/common/main/resources/img/toolbar/icons.svg
directly, but the grunt prebuild-svg-sprites task regenerates that file
from individual SVGs in apps/common/main/resources/img/toolbar/v2/2.5x/
on every build, dropping the new symbol on the floor. Add the icon as
a source file (btn-nc-assistant.svg) so the sprite picks it up by
filename — the symbol id matches the basename. Revert the manual edit
of icons.svg.

Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
The Smart Picker now opens the NC Assistant form seeded with the
editor selection and stops there — the user reads or copies the AI
result manually. We do not try to paste back into the document
because plain-text paste loses formatting on round-trip; until that
preserves at least basic styling the feature is intentionally
read-only.

Drop the bookmark anchor / select / remove dance from
onBtnSmartPickerClick (no replacement happens, so no anchor needed).
Simplify documenteditor's insertPlainText handler to plain
pluginMethod_PasteText — still useful for other host integrations
that paste plain text via the gateway.

Spreadsheet and presentation editors already only captured selection
and forwarded it; no change needed there. All three editors now
follow the same minimal flow.

Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
@chrip chrip force-pushed the feat/connect-nc-ai-backend branch from 4a1748a to f14296c Compare May 8, 2026 10:08
chrip added 3 commits May 8, 2026 12:53
…menu

The toolbar entry duplicated the global Nextcloud header Assistant icon
without adding meaningful value. Replace it with a context-menu entry
that only surfaces when the user has text selected (or right-clicks
in the canvas) and only when the Assistant app is loaded — a quiet
PoC integration that gets out of the way otherwise.

Web-apps changes:

- DocumentHolder views: add 'Ask Nextcloud Assistant' menu item +
  separator at the bottom of the text/cell context menu in all three
  editors (DE textMenu, SSE ssMenu, PE textMenu). Hidden by default.
- DocumentHolder controllers: subscribe to the new
  Common.Gateway.on('setassistantavailable') event; when the host
  announces the Assistant app is loaded, flip the menu item visible.
  When unavailable the entry is not rendered at all (no grayed-out
  ghost), matching the requirement to not disturb the GUI when the
  Assistant isn't installed.
- DocumentHolder controllers: onAskNcAssistant captures
  asc_GetSelectedText() and forwards it via
  Common.Gateway.requestSmartPicker — the existing
  editor->host postMessage bridge (no protocol change).

- Toolbar: drop btnSmartPicker definitions, slot injections, click
  handlers, lock-list entries, shortcut hints, locale strings
  (capBtnSmartPicker / tipSmartPicker / tipBtnSmartPicker),
  setSmartPickerEnabled handlers, and gateway 'setsmartpickerenabled'
  subscriptions across all three editors.
- api.js / Gateway.js: rename outbound facade method
  setSmartPickerEnabled -> setAssistantAvailable and gateway event
  setsmartpickerenabled -> setassistantavailable.

The icon (btn-nc-assistant) stays in the sprite — the context menu
item reuses it.

Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
Common.UI.MenuItem.setVisible only works reliably while the menu is in
the middle of rendering — outside that window the inherited
BaseView.setVisible calls this.show()/this.hide() which do not exist
on MenuItem and the call is silently no-op'd. Constructing items with
visible:false also breaks render: the constructor's own setVisible
call hits the same broken path and the item ends up unresponsive to
later setVisible.

Switch all three editors to the same pattern: construct items with
default visible:true, store the host-announced availability flag on
the view (ncAssistantAvailable), and toggle visibility from inside
the menu's open hook (initMenu for DE/PE textMenu, show:before for
SSE ssMenu). The controller's onSetAssistantAvailable just updates
the flag.

Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
…stener

The gateway 'setassistantavailable' listener was using
_.bind(this.onSetAssistantAvailable, this) and reading
this.documentHolder. In practice the bound this can pin to a stale
controller instance (or one whose .documentHolder isn't the live
view), so the listener fires but the flag never lands on the actual
documentHolder that the menu's initMenu / show:before reads. Move
the lookup inside the closure: each event re-resolves the live view
via DE/SSE/PE.getController('DocumentHolder').documentHolder.

Signed-off-by: Christoph Schaefer <christoph.schaefer@nextcloud.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants