Skip to content

feat(ai-chat-companion): floating widget + composables + NcAppSidebar#197

Merged
rubenvdlinde merged 1 commit into
betafrom
feature/ai-chat-companion-widget
May 11, 2026
Merged

feat(ai-chat-companion): floating widget + composables + NcAppSidebar#197
rubenvdlinde merged 1 commit into
betafrom
feature/ai-chat-companion-widget

Conversation

@rubenvdlinde
Copy link
Copy Markdown
Contributor

Summary

Implements the nextcloud-vue side of the ai-chat-companion 3-spec chain (hydra ADR-034).

Consuming apps get a Conduction-Cobalt hex FAB + context-aware chat panel auto-mounted via CnAppRoot — a single line in any app that already wraps in CnAppRoot. No install-time PHP dep on OpenRegister (runtime HTTP only, gracefully no-ops when OR is unreachable).

New components

src/components/CnAiCompanion/

  • CnAiFloatingButton.vueConduction-Cobalt (#4376fc) hex with white AI sparkles icon (Material Design Creation). Pointy-top point-up per the brand rule. Solid colour, no gradients. Hover #2e5ed9. Respects prefers-reduced-motion. Position prop accepts four corners.
  • CnAiCompanion.vue — top-level mount, OR health probe at startup, no-op fallback (renders nothing if OR unreachable, no console warnings above info).
  • CnAiChatPanel.vue — built on NcAppSidebar (proper NC theming + a11y + slide animation) with NcActionButton secondary actions for Start-new-chat and History. Slides in from the right edge.
  • CnAiMessageList.vue — user / assistant / system roles, NcRichText for assistant markdown, plain text for user, tool-call / tool-result inline with collapse-to-summary, isError highlighting.
  • CnAiInput.vue — multi-line textarea + send, Enter to send, Shift+Enter for newline.

src/dialogs/ (per ADR-004 file-isolation rule)

  • CnAiHistoryDialog.vueNcDialog-based history browser, fetches GET /api/chat/conversations?limit=50, empty / loading / error states.

New composables

  • useAiContext() — injects the reactive cnAiContext.
  • useAiChatStream() — owns the SSE lifecycle via @microsoft/fetch-event-source (handles POST bodies, abort signals, auto-reconnect, frame parsing). Falls back to POST /api/chat/send on 404 / 501 with synthetic final event so message-rendering code has one path.

Modified

  • CnAppRoot.vue — provides reactive cnAiContext; auto-mounts <CnAiCompanion /> as the last NcContent child so the embedded NcAppSidebar slides from the right.
  • CnIndexPage / CnDetailPage / CnDashboardPage — push pageKind, registerSlug, schemaSlug, objectUuid into cnAiContext on created() + watch + beforeDestroy.
  • l10n/en.json + l10n/nl.json — 13 keys + Dutch translations.
  • src/index.js + src/types/index.d.ts — exports.

Demo

examples/ai-chat-companion-demo/ ships a standalone harness with mocked OR backend (health, /api/chat/stream, /api/chat/conversations).

Browser-verified

Mounted via file: link in decidesk against the real OR backend: hex FAB renders bottom-right (verified cn-ai-floating-button__hex element + rgb(67, 118, 252) background + creation-icon class). NcAppSidebar slides in from the right with title, subtitle, sparkles empty state, and the message input.

Dependencies

Depends on the hydra ai-chat-companion spec landing first (defines the contracts) and the sibling openregister/ai-chat-companion-orchestrator for the real SSE backend (widget no-ops gracefully without it).

Test plan

  • openspec validate ai-chat-companion-widget --strict passes
  • FAB renders with Conduction Cobalt hex + white sparkles
  • NcAppSidebar slides in from the right
  • OR health probe + no-op fallback works
  • npm run lint clean
  • npm test green
  • npm run build ESM + CJS + extracted CSS no new warnings
  • End-to-end browser test against the live OR change once it ships

Implements the nextcloud-vue side of the ai-chat-companion 3-spec
chain (hydra ADR-034). Adds a single line auto-mount via CnAppRoot —
consuming apps get a Conduction-Cobalt hex FAB and a context-aware
chat panel for free.

NEW components (src/components/CnAiCompanion/):
- CnAiCompanion.vue — top-level mount, OR health probe, no-op fallback
- CnAiFloatingButton.vue — Conduction-Cobalt (#4376fc) hex with white
  AI sparkles icon (Material Design Creation), pointy-top point-up per
  brand rule. Solid colour, no gradients.
- CnAiChatPanel.vue — built on NcAppSidebar (proper NC theming + a11y
  + slide animation) with NcActionButton secondary actions for Start
  new chat and History.
- CnAiMessageList.vue, CnAiInput.vue — message rendering and input.

NEW dialog (src/dialogs/, per ADR-004 file-isolation rule):
- CnAiHistoryDialog.vue — NcDialog overlay listing past conversations.

NEW composables (src/composables/):
- useAiContext() — injects the reactive cnAiContext provided by
  CnAppRoot.
- useAiChatStream() — owns the SSE lifecycle via @microsoft/fetch-
  event-source (handles POST bodies, abort signals, automatic
  reconnect, frame parsing). Falls back to POST /api/chat/send on
  404/501 with synthetic final event.

MODIFIED:
- CnAppRoot.vue — provides reactive cnAiContext; auto-mounts
  <CnAiCompanion /> as the last NcContent child so the embedded
  NcAppSidebar slides in from the right.
- CnIndexPage / CnDetailPage / CnDashboardPage — push pageKind,
  registerSlug, schemaSlug, objectUuid into cnAiContext on created()
  + watch + beforeDestroy.
- l10n/en.json + l10n/nl.json — 13 new keys + Dutch translations.
- src/index.js + src/types/index.d.ts — barrel exports.

Demo: examples/ai-chat-companion-demo/ — standalone harness with
mocked OR backend (health, /api/chat/stream, /api/chat/conversations).

Tests: Vitest mount + behaviour tests for every new component and
composable. tests/__mocks__/fetch-event-source.js mocks the SSE
library so unit tests run without a real OR backend.

Depends on the hydra ai-chat-companion spec.
@rubenvdlinde rubenvdlinde merged commit efefdfc into beta May 11, 2026
1 of 3 checks passed
@rubenvdlinde rubenvdlinde deleted the feature/ai-chat-companion-widget branch May 11, 2026 11:25
rubenvdlinde added a commit that referenced this pull request May 11, 2026
…t spec

The mount-level in-memory manifest tests previously asserted axios.get was
never called. After the AI Chat Companion (#197) was merged onto beta, the
CnAiCompanion child issues an unrelated GET /apps/openregister/api/chat/health
during mount. Filter axios.get calls to /api/manifest endpoints so the
REQ-IMM-002 / REQ-IMM-004 guarantees stay meaningful without colliding with
the new health probe.
@github-actions
Copy link
Copy Markdown
Contributor

🎉 This PR is included in version 1.0.0-beta.31 🎉

The release is available on:

Your semantic-release bot 📦🚀

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant