feat(web-app-ai-quick-draft-creator): add AI quick draft creator action#465
Open
LukasHirt wants to merge 9 commits into
Open
feat(web-app-ai-quick-draft-creator): add AI quick draft creator action#465LukasHirt wants to merge 9 commits into
LukasHirt wants to merge 9 commits into
Conversation
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
dj4oC
reviewed
Jun 25, 2026
dj4oC
left a comment
Contributor
There was a problem hiding this comment.
Thanks for getting this up. Concept fits the repo well (an upload-menu action that drafts a doc via the LLM). Flagging issues found in review — marking as a comment since it's a draft. The security items are the important ones.
Blockers
- [security] LLM is called directly from the browser with no origin guard.
useLLM.tsdoesfetch(\${cfg.endpoint}/chat/completions`)(and/models) directly. The house pattern (seeweb-app-chat-with-file/src/composables/useChat.ts) routes everything through the same-originai-llm-proxyand refuses any endpoint whose origin ≠window.location.origin`. Please route all LLM traffic through the proxy. - [security] Admin API key is shipped to every client.
index.tsreadsapplicationConfig.llm.apiKeyanduseLLM.tssends it asAuthorization: Bearer <apiKey>.applicationConfigis public, so this leaks the provider key to all users. Siblings forward the user's oCIS token (authStore.accessToken) and keepLLM_API_KEYserver-side in the proxy. Please dropapiKeyfrom client config entirely.
Major
- Package lives under
extensions/…, butpnpm-workspace.yamlonly globspackages/*— so it isn't installed/built/linted/mounted. Move topackages/web-app-ai-quick-draft-creator/. - No
dist/mount indocker-compose.ymland no entry indev/docker/ocis.apps.yaml/support/actions/ocis.apps.yaml, soapplicationConfig.llmis always undefined → the action never appears. Add the mount + an apps-config key matching the mount-target dir. - No
l10n/directory anddefineWebApplicationreturns notranslationskey, so strings can't be extracted/localized (they are correctly wrapped in$gettext, good). useLLM.tsships ~200 lines of unused code (stream,completeJSON,summariseMessages) and fires up to 4 capability-probe round-trips on every modal open; the feature only usescomplete()once.
Minor
src/App.vueis an unused generated stub — remove.useDraftCreator.tswritesslug-YYYY-MM-DD.mdwith no collision check → two same-day drafts silently overwrite.- E2E asserts are no-ops (
toBeGreaterThanOrEqual(0),expect(true).toBe(true)early-returns), and the mock targets**/ai-llm-proxy/**while the code callscfg.endpointdirectly — the happy path is never exercised. - PR title isn't Conventional Commits — CI enforces it (e.g.
feat(web-app-ai-quick-draft-creator): …).
Happy to pair on the proxy wiring if useful — chat-with-file is the closest reference.
6 tasks
Collaborator
Author
Review feedback addressedAll review items have been resolved. Here is a summary of every change made: Blockers fixedDirect browser LLM calls → proxy routing
API key removed from the browser
Major fixesWrong directory → moved
Docker / YAML config added
l10n added
Unused code removed
Minor fixes
All 11 unit tests pass. TypeScript type check passes. |
1af9eef to
b68fab6
Compare
b68fab6 to
f50365d
Compare
Signed-off-by: Lukas Hirt <info@hirt.cz>
Signed-off-by: Lukas Hirt <info@hirt.cz>
…/ to packages/ Relocate ai-quick-draft-creator from the non-standard extensions/ directory to packages/web-app-ai-quick-draft-creator/ so it is picked up by the pnpm-workspace.yaml glob (packages/*) and follows the repo convention. Rename the package to web-app-ai-quick-draft-creator. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Lukas Hirt <info@hirt.cz>
Security (blockers): - Route all LLM requests through the same-origin ai-llm-proxy; the browser now sends Authorization: Bearer <oCIS OIDC token> to the proxy rather than calling the LLM endpoint directly. - Remove apiKey from LLMConfig and from applicationConfig entirely; the provider API key is held server-side by the proxy only. - useLLM.ts enforces a same-origin check at call time and throws a user-visible error if the endpoint is cross-origin. Structural: - Delete unused generated App.vue stub. - Add l10n/translations.json (initially empty) and l10n/template.pot; wire translations into defineWebApplication return value. - Update docker-compose.yml with dist volume mount for the extension. - Add ai-quick-draft-creator entry to dev/docker/ocis.apps.yaml. - Add web-app-ai-quick-draft-creator entry to support/actions/ocis.apps.yaml. - Add web-app-ai-quick-draft-creator to the CI test matrix in test.yml. Code quality: - Remove ~190 lines of unused code from useLLM.ts: capability probe (4 network requests on every modal open), stream(), completeJSON(), and summariseMessages(). - Remove capability-based tier logic from useDraftCreator.ts; always generate a well-structured draft prompt. - Add HH-mm-ss timestamp suffix to derived filenames so two same-day drafts never silently overwrite each other. - Replace raw <button> elements in DraftCreatorModal.vue with <oc-button> and add an <oc-spinner> during creation. Tests: - Unit tests updated to match the slimmed UseLLMReturn interface (no stream/completeJSON/capabilities); add a collision-suffix test. - E2E tests rewritten: all no-op assertions replaced with real behavioral checks; proxy mock now targets **/ai-llm-proxy/v1/** (matching the same-origin path enforced by useLLM.ts); happy-path test verifies proxy is called and modal closes on success. Docs: - Update README to document the proxy security model, configuration, and environment variables. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Signed-off-by: Lukas Hirt <info@hirt.cz>
Signed-off-by: Lukas Hirt <info@hirt.cz>
…sible Signed-off-by: Lukas Hirt <info@hirt.cz>
…pe errors Signed-off-by: Lukas Hirt <info@hirt.cz>
f50365d to
e9c3e1d
Compare
… instead of upload menu Use appInfo.extensions with newFileMenu + customHandler to place the 'Draft from description' action in the correct #new-file-menu-drop dropdown (the + New button), not the upload dropdown. The newFileMenu.isVisible callback receives currentFolder directly as a parameter, so the canUpload check is accurate and race-condition-free. Update E2E tests to open #new-file-menu-btn and locate the item by its menu title text. Signed-off-by: Lukas Hirt <info@hirt.cz>
…tomatically
After a draft is created, trigger the default file action so the new
file opens immediately without requiring manual navigation.
Return `{ resource, space }` from `createDraft` instead of the filename
string so the modal can pass the created resource to `triggerDefaultAction`.
Also adds `oc-modal-body-actions-cancel` class to the cancel button for
reliable E2E targeting, dismisses open modals before logout in `LoginPage`,
drops the WebDAV PUT stub from E2E setup now that tests run against real
oCIS, and adds `public/manifest.json`.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Signed-off-by: Lukas Hirt <info@hirt.cz>
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
Adds a new AI Quick Draft Creator extension that lets users generate AI-written documents directly from the ownCloud Web file manager.
How it works
ai-llm-proxy, receives the generated content, and saves the file to the current folder via WebDAVWhat is included
packages/web-app-ai-quick-draft-creator/— the full Vue 3 + TypeScript extensionactionextension in the new-file menuDraftCreatorModal.vue— description input, format selector, create/cancel buttonsuseDraftCreatorcomposable — LLM prompt building, WebDAV upload, returns{ resource, space }so the modal can trigger the default file action on the resultl10n/translation scaffoldsupport/pages/loginPage.ts— extended with modal locators and pre-logout modal dismissal for reliable E2E teardowndev/docker/andsupport/actions/— updatedocis.apps.yamlanddocker-compose.ymlto mount the new extension and wire up its LLM configConfiguration
The extension reads its LLM endpoint from the oCIS app config key
web-app-ai-quick-draft-creator(orai-quick-draft-creatorin local dev mounts), following the same pattern as the other AI extensions in this repo.Test plan
pnpm --filter web-app-ai-quick-draft-creator test:unit— all unit tests passpnpm --filter web-app-ai-quick-draft-creator test:e2e— E2E acceptance tests pass against a running oCIS stackisVisiblereturns false)