Commit Graph

7 Commits

Author SHA1 Message Date
Naiyuan Qing
0399e387f8 fix(views): resolve stale status in cmd+k recent issues list
Recent issues store was duplicating server data (title, status, identifier)
in Zustand, violating the single-source-of-truth architecture. Now the store
only tracks visit records (id + visitedAt), and the search command joins
fresh data from the TanStack Query issue list cache at render time.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-14 18:23:27 +08:00
Jiayuan Zhang
faee939312 feat(issues): add project filter to Issues tab (#671)
Support filtering issues by project in the Issues tab filter dropdown,
including a "No project" option for issues without a project assigned.

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 23:23:45 +08:00
Jiayuan Zhang
54d452e20d feat(search): show recent issues in cmd+k dialog (#656)
* feat(search): show recent issues list when cmd+k opens

When opening the cmd+k search dialog, display a list of recently visited
issues instead of the empty placeholder. Visits are tracked via a
workspace-scoped persisted Zustand store (max 20 items).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(search): close cmd+k dialog on single ESC press

cmdk was consuming the first ESC to clear internal state, requiring a
second press to close the dialog. Intercept ESC on the CommandPrimitive
and close the dialog directly.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(search): move ESC handler to input to prevent double-ESC

The previous handler on CommandPrimitive didn't fire because cmdk
intercepts ESC at the input level. Moving the onKeyDown to
CommandPrimitive.Input ensures it fires before cmdk processes it.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* fix(search): use capture-phase ESC listener to close dialog reliably

The previous onKeyDown approach on the Input didn't work because
base-ui Dialog's internal focus management handled ESC before the
React synthetic event. Use a document-level capture-phase listener
that fires before all other handlers and stops propagation.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

* test(search): cover single-escape command palette close

---------

Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 20:48:43 +08:00
Naiyuan Qing
85cff15427 feat(core): standardize storage + workspace isolation for persist stores
Unify all client-side persistence through StorageAdapter and add
workspace-scoped key namespacing (${key}:${wsId}).

- createPersistStorage: bridge for Zustand persist → StorageAdapter DI
- createWorkspaceAwareStorage: dynamic namespace by current workspace
- Migrate 6 persist stores (navigation, draft, view, scope, my-issues-view, chat)
- Rehydration registry: stores auto-rehydrate on workspace switch
- clearWorkspaceStorage: cleanup on workspace delete / member removal
- Chat store: namespace keys + rehydrate on workspace switch
- Factory view stores (createIssueViewStore): auto-register for rehydration

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:59:53 +08:00
Naiyuan Qing
4268b7891a feat(core): add workspace-aware storage for scoped persist stores
Create createWorkspaceAwareStorage that dynamically namespaces
localStorage keys by workspace ID (e.g. "multica_issue_draft:ws_abc").
Wire setCurrentWorkspaceId into workspace store lifecycle methods and
migrate all workspace-scoped stores (draft, view, scope) to use it.
Navigation store intentionally left user-scoped without namespace.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 15:27:18 +08:00
Naiyuan Qing
5878bddd6b refactor(core): move my-issues view store to packages/core/issues/stores
The my-issues view store is shared client state that doesn't depend on
any UI library. Move it from packages/views/my-issues/stores/ to
packages/core/issues/stores/ to follow the no-duplication rule and keep
state factories together with related issue stores.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-10 11:33:37 +08:00
Naiyuan Qing
e1e7f68330 feat: extract packages/core — Turborepo infrastructure + headless business logic
Phase 1: Monorepo infrastructure
- Add Turborepo with turbo.json pipeline (build, dev, typecheck, test)
- Update pnpm-workspace.yaml to include packages/*
- Create shared TypeScript config (packages/tsconfig)

Phase 2: Extract packages/core (zero react-dom, all-platform reuse)
- Move domain types, API client, logger, utils → packages/core/
- Move TanStack Query modules (issues, inbox, workspace, runtimes)
- Move Zustand stores (auth, workspace, issues, navigation, modals)
- Move realtime sync (WSProvider, hooks, ws-updaters)
- Refactor auth/workspace stores to factory pattern for DI
- Refactor ApiClient with onUnauthorized callback
- Refactor useWorkspaceId to React Context (WorkspaceIdProvider)
- Refactor WSProvider to accept wsUrl + store props
- Create apps/web/platform/ bridge layer (api singleton, store instances)
- Update 91 import paths across apps/web/
- Fix 3 test files for new import paths

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 10:20:00 +08:00