- panelHotkeysController: move V key handler before isPanelHotkeyContext guard
so it fires after subfolder navigation when hover/focus state has reset;
only blocked when focus is on an input/textarea outside the panel
- browserNavigationController: add clearSelection param, call it before
reloadGrid() in navigateFolder, resetToBrowserRoot, onOpenFolderAsset,
onCustomSubfolderChanged so stale selection is cleared immediately
- panelRuntime: pass clearSelection via gridContainer._mjrSetSelection([])
- floatingViewerManager: filter folder-kind assets from selectedIds in
_onSelectionChanged to avoid trying to load a folder as media
Root cause: prepareGridForScopeSwitch set state.loading=false without resetting
state.offset/state.done. This triggered the Vue watch -> maybeFillViewport ->
loadNextPage with stale offset from the previous scope. The debounced reloadGrid
(30ms later) then found state.loading=true and skipped, leaving the grid showing
data from the wrong offset.
Two fixes in useGridLoader.js:
1. prepareGridForScopeSwitch: add setLegacyPageState({offset:0, cursor:null,
total:null, done:false}) so any premature maybeFillViewport call loads from
offset 0 (correct) rather than the previous scope cursor position.
2. loadNextPage: capture _loadReqId = state.requestId after syncPagedStateFromLegacy,
check it in beforeApplyPage. If a scope switch incremented requestId while
the fetch was in flight return {ok:false, stale:true} to discard the page
before applyPage runs - preventing stale scope data from corrupting state.assets.
- Add AI.VectorCaptionOnIndex UI setting with rollback on API error
- Backend: persist/read vector_caption_on_index via AppSettings
- Expose set_vector_caption_on_index via health route and clientOps API
- Wire is_vector_caption_on_index_enabled() into config + env vars
- Update vector_indexer to honour the caption-on-index flag
- Add tests: settings backend, health routes, vector indexer video alignment
- Extend grid_scope_switch_cache test coverage
- Replace direct comfyApiBridge import in WorkflowNodesTab with getRawHostApp (ADR 0007).
- Reset security prefs snapshot in _reset_security_state_for_tests so tests that toggle MAJOOR_REQUIRE_AUTH are not influenced by an earlier ensure_security_bootstrap publishing require_auth=False.
- Call _reset_security_state_for_tests from _clear_write_auth_env helper for proper isolation.
- Rebuild frontend bundle.
- ImageOps preview bridge: stream cropped contain-fit rect of __imageops_state.canvas (removes square scope/letterbox); fall back to full canvas when user pan/zoom is active. Signature-cached encode (WeakMap) avoids re-encoding on every poll tick.
- Floating viewer: skip metadata enrichment for imageops-live-preview source; preserve user pan/zoom across stream frames of the same node; remove inline CSS overrides that blocked the MFV transform.
- Workflow Nodes panel: graph-selected node is auto-expanded, promoted to first position in its container, scrolled into view, and gets a subtle blue highlight (is-selected-from-graph).
The Settings -> Security toggles (Allow Remote Full Access, Allow HTTP Token Transport, Require Token For All Writes) were persisted in the DB but ignored by _check_write_access() and the bootstrap-token endpoint, which only read MAJOOR_* env vars. Remote LAN clients hit 'Write access is blocked' even with all toggles enabled.
- New security_prefs_snapshot module: thread-safe in-memory snapshot of persisted prefs, hydrated at ensure_security_bootstrap() and republished on every set_security_prefs(). Read synchronously by guards.
- security.py::_resolve_security_flag(pref_key, env_var, default): single read site, snapshot-first / env-fallback. Used for allow_remote_write, require_auth, allow_insecure_token_transport.
- _bootstrap_enabled() also returns True when allow_remote_write is set in the snapshot (UI consent for remote bootstrap).
- bootstrap-token / rotate-token accept plain HTTP transport when allow_insecure_token_transport is on.
- Friendlier defaults so first install works zero-config on LAN: allow_remote_write=True, allow_insecure_token_transport=True. Auto-generated API token still gates writes.
- Error messages updated to point users to Settings -> Security instead of only env vars.
- README rewritten to put the UI flow first; env vars as headless fallback.
- pyproject.toml: per-file ignore F401 for routes/core/security.py since it is the single import point that re-exports from sub-modules.
- Early-fetch immediate (no setTimeout 800ms), persisted scope/sort key, includeTotal=false.
- Snapshot persisted in localStorage (was sessionStorage), with legacy migration.
- MIN_LOADING_SKELETON_MS=0; skeleton hides as soon as assets are present.
- New scheduleSnapshotHeadRefresh: re-fetch page 0 after fast-path cached:true and upsert new items at correct sort position. Fixes recent assets disappearing on scope switch (custom->output).
- offset=max(offset, assets.length) in didHydrate branch so prefetch loads next page, not page 0 again.
- refreshDuplicateAlerts non-blocking (fire-and-forget).
- Race guards: scheduleDeferredExecutionReload skips reload if scope/filter changed during prompt execution; scheduleSnapshotHeadRefresh aborts if context changes mid-fetch.
- Includes other staged misc edits (config, scanner, watcher, components).
The toolbar was redesigned from inline <select> to icon buttons + popovers.
Update the test to match the new structure:
- check for .mjr-mfv-guides-trigger and .mjr-mfv-ch-trigger in bar
- expect formatSelect.value to be 'off' when _overlayMaskEnabled is false
- add viewer.element to the mock so the popover appendChilds don't throw
- sidebarRunButton: add _walkAllNodes() to mirror ComfyUI's native
beforeQueued/afterQueued widget cycle on all nodes incl. inner subgraph
nodes so control_after_generate (randomize/increment/decrement) is
applied correctly on each MFV run
- widgetAdapters: _syncWidgetDomElement falls back to
cachedDeepestByFrame.widget.inputEl for PromotedWidgetView so typing
in the sidebar updates the canvas textarea of subgraph outer widgets
in real time
- widgetAdapters: spinner step forced to 1 for integer widgets;
widget.value restored after callback to bypass step2 snapping
- Remove stale storage event listener in SettingsPanel.js
- Add checks for window object in LiveStreamTracker.js, floatingViewerManager.js
- Implement onScopeDispose for storage event listener in usePanelStore.js
- Add check for window object in MajoorPanel.svelte
- Adjusting the infinite scroll loading point to 4 card rows from the bottom
- Improving grid state restoration after reloads
- Enhancing the early fetch mechanism for faster initial loads
- Optimizing execution runtime to handle large numbers of assets efficiently
- Updating viewer and run button behavior for better integration with ComfyUI
- Fix various bugs and edge cases