feat(ai-smart-file-tagger-qa): add AI Smart File Tagger#490
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. |
8c0104a to
6d1c358
Compare
dj4oC
left a comment
There was a problem hiding this comment.
Adds a context-menu "Suggest tags" action for single files that calls a same-origin ai-llm-proxy, renders chip selection in a modal, and applies confirmed tags via assignTags (Graph API).
- Security: no findings — same-origin enforcement correct (CWE-918 gated), bearer token protected, tag normalization (lowercase, 30-char cap) appropriate ✅
- Stability: no findings —
assignTagsmerge into local store rather than overwrite is correct ✅ - Performance: PDF.js client-side extraction is scoped and capped (12,000 chars); no unbounded allocation ✅
- Test coverage: unit + e2e tests present ✅
- TODOs found: 1 —
"description": "CANDIDATE"inpackage.json(tracking issue to follow) - Dependency:
pdfjs-dist@^6.1.200(Apache-2.0) added — covered by existingdependabot.ymlnpm config ✅ - CI status: all green per Snyk ✅ (build verification not possible in cloud review environment)
- Stale review:
⚠️ This PR has been awaiting review since 2026-06-30 — exceeded 48h threshold by 8 days
No blocking findings. This can proceed to human sign-off once the package.json description placeholder is resolved (see tracking issue).
🤖 Automated review by Claude Code (security · stability · performance · coverage)
|
TODO tracking: issue #501 opened to replace the |
|
@copilot resolve the merge conflicts on this branch. |
Signed-off-by: Lukas Hirt <info@hirt.cz>
…mposables/useTagSuggestions.ts` (prompt construction, LLM fetch, JSON parse with confidence scores, plain-text fallback, WebDAV tag write via `useClientService`), `src/utils/file-support.ts` (content-extraction eligibility check, MIME helper), and wire `src/index.ts` to read `applicationConfig.llm`, build `llmConfig`, and register the `ActionExtension` on `app.files.quick-actions` (with fallback to `global.files.context-actions` if the extension point is absent). Verify the quick-actions extension point exists in `node_modules/@ownclouders/web-pkg` and confirm an unused dev-server port in the `97XX` range. Signed-off-by: Lukas Hirt <info@hirt.cz>
Signed-off-by: Lukas Hirt <info@hirt.cz>
Signed-off-by: Lukas Hirt <info@hirt.cz>
…ts/TagSuggestionModal.vue`: loading spinner, selectable tag chips (OcTag or OcButton toggle fallback), confidence badges, error banner, confirm/dismiss buttons, and unconfigured-state info message. Wire the modal into the action handler via `useModals().dispatchModal`. Use only ODS components and ownCloud CSS custom properties; wrap all strings in `$pgettext`. Signed-off-by: Lukas Hirt <info@hirt.cz>
…/composables/useTagSuggestions.spec.ts` covering prompt construction (content mode vs name-only mode), structured JSON parse, plain-text fallback, tag application via mocked WebDAV, and error branches (401, 429, network failure). Write `tests/unit/components/TagSuggestionModal.spec.ts` covering loading state, chip rendering, chip toggle, confirm calls `applyTags`, dismiss closes, error banner, and unconfigured tooltip. Signed-off-by: Lukas Hirt <info@hirt.cz>
Signed-off-by: Lukas Hirt <info@hirt.cz>
Signed-off-by: Lukas Hirt <info@hirt.cz>
…on in `tests/e2e/acceptance.spec.ts` with a Playwright smoke test: upload a `.txt` file, click the sparkle quick-action, assert the `TagSuggestionModal` appears with at least one chip, toggle a chip off, confirm, and assert the modal closes. Signed-off-by: Lukas Hirt <info@hirt.cz>
Signed-off-by: Lukas Hirt <info@hirt.cz>
Signed-off-by: Lukas Hirt <info@hirt.cz>
Signed-off-by: Lukas Hirt <info@hirt.cz>
… state sync issues - Fix tag chips rendering as raw JSON/numbered-list text when the LLM ignores the requested response format - Fix selected/unselected chip colors having inverted contrast; tags now default to unselected (opt-in) instead of pre-selected - Replace the modal's custom Dismiss/Apply tags button row with the framework's own modal actions (confirmText + exposed onConfirm) - Add a hint above the chip list explaining the tags must be selected - Sync the resources store after applying tags so the file list/sidebar reflect the new tags without a page refresh - Fix a race in the e2e test that read the chip count before the async suggestion fetch resolved Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Signed-off-by: Lukas Hirt <info@hirt.cz>
Signed-off-by: Lukas Hirt <info@hirt.cz>
…I matrix, and oCIS apps config Signed-off-by: Lukas Hirt <info@hirt.cz>
…laceholder description Bumps @ownclouders/web-client, @ownclouders/web-pkg, and @ownclouders/extension-sdk to 12.5.0 to match the rest of the monorepo, and replaces the "CANDIDATE" package.json description with a real one. Closes #501 Signed-off-by: Lukas Hirt <info@hirt.cz>
45e96c7 to
c35f7da
Compare
|
Branch was stale — rebased onto Also addressed the review's open item:
Verified post-rebase: |
Problem
Files accumulate without tags, making search and filter ineffective.
Manual tagging at scale doesn't happen — it requires opening every file individually.
Solution
A sparkle icon appears inline in each file row. Clicking it sends the file's
content (txt/md/pdf) or just its name and type (all others) to the configured
LLM, which returns 3–5 suggested tags shown in a lightweight confirmation
popover. The user accepts, deselects, or dismisses. With structured-output
models, tags include a confidence score; with basic text models, a flat list.
Without a configured LLM, the button shows a tooltip describing the required
admin setup.
Extension points
app.files.quick-actionsWhy ship this now
As oCIS deployments scale, findability suffers first. This is the lowest-friction
path to enriched metadata, meeting users exactly where they already are.
What was built
packages/web-app-ai-smart-file-tagger-qa adds an inline "suggest tags" action to the files app, sending a file's content or name/MIME type to a configured LLM and returning suggested tags for the user to accept or dismiss. Because
app.files.quick-actionsdoesn't exist in the installed@ownclouders/web-pkg(v12.3.2), the action is registered onglobal.files.context-actionsinstead — accessible from the file's context menu rather than as an inline row icon.src/index.tsreadsapplicationConfig.llm, builds the LLM config, and wires theActionExtensionregistration.The core logic lives in
src/composables/useTagSuggestions.ts, which pulls file content over WebDAV for.txt/.md/.pdf(PDF text extraction via pdfjs-dist with a fake worker) and falls back to filename + MIME type for everything else, gated bysrc/utils/file-support.ts. It calls the existinguseLLM.complete()composable with a structured JSON prompt and parses a{ tags: [{ name, confidence }] }response, with a plain-text comma/newline fallback for models that don't support structured output — matching the two-tier degradation already established byweb-app-ai-doc-summary. Accepted tags are applied viaclientService.graphAuthenticated.tags.assignTags().src/components/TagSuggestionModal.vuerenders the suggestion UI: a loading spinner, an unconfigured-LLM notice, toggleableOcTagchips with confidence badges (selection state is tracked via a CSS class since thisOcTagversion has no nativeselectedprop), an error banner, and its own Apply/Dismiss controls since the modal is launched withhideConfirmButton: true.Test coverage includes 36 unit tests across the composable (prompt construction, structured/plain-text parsing, confidence normalization, tag application, and 401/429/network error handling) and the modal component (state rendering, chip toggling, confirm/dismiss behavior), plus a Playwright acceptance spec that mocks the LLM proxy, uploads a test file, triggers the action from the context menu, and verifies the modal's chip rendering, toggle, and confirm-close flow. The acceptance spec and its page object live inside the package rather than shared
support/pages/, per the per-extension page-object convention. A known limitation, documented in the package README, is that tag suggestions surface from the file context menu rather than as an inline quick-action icon, since the originally spec'd extension point isn't available in this web-pkg version.Gate
Effort: S · 🤖 Generated by extctl