logancyang_obsidian-copilot/jest.setup.js
Emt-lin 2afc0949f3
feat(settings): redesign settings UI (v4, part 1) (#2692)
* feat(settings): redesign settings UI (v4, part 1)

First PR of the Settings v4 redesign: restructures the settings shell and
lands the Self-Host, Miyo, and Plus surfaces.

- Shell: new tab layout (drop Search; split Miyo / Self-Host), section
  cards, alignment and a11y passes.
- Self-Host Mode: provider/backend gating, BYOK cloud hiding, cloud options
  surfaced with a warning marker instead of hidden, @-mention cloud warnings.
- Miyo tab: data-driven status store, Connect/Disconnect via status pill,
  one-click vault registration with remote-deeplink fallback, Relay tag,
  capability toggles.
- Miyo semantic-search skill: user-facing enable toggle (flag + migration +
  gating) with disconnected-state handling.
- Document-processor backend flip + PDF fallback; searchEngine/docProcessor
  settings fields with v5->v6 migration routed through accessors.
- Plus block: value-first copy surfacing Agent Mode + Miyo, free-user upsell,
  usage line placeholder (hidden until the usage API lands).

Granular history preserved in backup/settings-v4-pre-rebase.

* fix(settings): address review — doc-processor fail-closed, PDF+EPUB local, self-host controls, skill reconcile

Responds to the maintainer review on the Settings v4 PR (F1/F2/F4/F5;
F3 auto-registration pending product direction, exclusion-drift re-sync
tracked as a fast-follow).

- Doc processor fails closed: resolveDocProcessorBackend now returns
  "miyo-unavailable" (never a silent cloud upload) when an explicit "miyo"
  choice can't be used — after Disconnect or on mobile without a remote URL.
  Delete the dead synchronous getDocProcessorBackend, and move the Document
  Processor picker out of the connection-gated wrapper so Plus stays
  selectable to recover from a fail-closed parse error.
- Process PDF and EPUB locally through Miyo (shared MIYO_LOCAL_EXTENSIONS),
  keep other formats on Plus, and state the split in the setting copy;
  generalize SelfHostPdfParser -> SelfHostDocParser.
- Restore the self-host controls to editable while self-host mode is on
  (disabled={!selfHostOn}), re-adding the Perplexity provider option and key.
- Reconcile the search-skill flag with the completed disk result even when
  the tab unmounts mid-op: the unmount cleanup no longer advances the skill
  token, and the toggle handler separates "superseded by a newer toggle"
  (skip persist) from "unmounted" (persist, suppress only UI).

* fix(settings): parse EPUB via Miyo in normal chat (re-review P1)

Docs4LLMParser threw "No project context" before reaching the Miyo route,
so an EPUB added in ordinary (non-project) chat failed even though Settings
promises local PDF/EPUB. Route the Miyo path before the project requirement;
keep project-scoped caching and the cloud path project-gated.
2026-07-18 22:19:22 -07:00

47 lines
1.8 KiB
JavaScript

import "web-streams-polyfill/dist/polyfill.min.js";
import { TextEncoder, TextDecoder } from "util";
window.TextEncoder = TextEncoder;
window.TextDecoder = TextDecoder;
// Polyfill Obsidian's Node.doc / Node.win augmentation so plugin code that
// reads `element.doc` / `element.win` works under jsdom.
if (typeof Node !== "undefined" && !Object.prototype.hasOwnProperty.call(Node.prototype, "doc")) {
Object.defineProperty(Node.prototype, "doc", {
get() {
return this.ownerDocument ?? window.document;
},
configurable: true,
});
}
if (typeof Node !== "undefined" && !Object.prototype.hasOwnProperty.call(Node.prototype, "win")) {
Object.defineProperty(Node.prototype, "win", {
get() {
return this.ownerDocument?.defaultView ?? window;
},
configurable: true,
});
}
// Polyfill Obsidian's `HTMLElement.setCssProps` augmentation (sets one or more
// CSS custom properties) so plugin code that calls it — e.g. the autosizing
// `Textarea` — works under jsdom.
if (typeof HTMLElement !== "undefined" && typeof HTMLElement.prototype.setCssProps !== "function") {
HTMLElement.prototype.setCssProps = function (props) {
for (const [name, value] of Object.entries(props)) {
this.style.setProperty(name, value);
}
};
}
// Obsidian exposes `activeDocument` / `activeWindow` globals pointing at the
// focused popout's document/window. Under jsdom there's only one document, so
// alias them onto `window` (the jsdom global object) — plugin code that portals
// into `activeDocument.body` (e.g. the Radix tooltip) would otherwise throw
// `activeDocument is not defined`.
if (typeof window.activeDocument === "undefined") {
window.activeDocument = window.document;
}
if (typeof window.activeWindow === "undefined") {
window.activeWindow = window;
}