* feat: add ability to move boards between workspaces
Implements the "Move to workspace" feature (#344) allowing users to
relocate a board and all its contents (lists, cards, labels, checklists,
comments, activity) to a different workspace.
Key design decisions:
- Card member assignments are cleared on move (they reference
workspace-scoped members that may not exist in the target workspace)
- Comments and activity history are preserved (they reference global
user IDs, not workspace members)
- Slug conflicts in the target workspace are auto-resolved by
appending a UID suffix
- Permission model: requires board:edit in source workspace and
board:create in target workspace
- Templates and archived boards cannot be moved
Co-Authored-By: Claude <noreply@anthropic.com>
* refactor: consolidate board queries in move mutation
Address review feedback:
- Consolidate 3 separate board queries into a single findFirst()
that fetches all needed fields (id, name, slug, type, isArchived,
workspaceId, createdBy)
- Fix slug fallback to use board.name instead of publicId for
human-readable URLs
Co-Authored-By: Claude <noreply@anthropic.com>
* fix: filter guest workspaces from move board destination list
Guests typically lack board:create permission in the target workspace,
so showing them as destinations leads to a confusing server rejection.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: extract getBoardForMove repo function
Moves the inline board query from the move mutation into the repo
layer, consistent with how every other board mutation fetches data.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* test: add unit tests for board.move mutation
10 test cases covering auth, validation, permissions, slug conflict
resolution, and the happy path. Follows webhook.test.ts patterns.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: mark locale files as linguist-generated
GitHub will now auto-collapse compiled translation files (messages.json,
messages.ts, messages.po) in PR diffs and exclude them from language
stats. This makes PRs that touch i18n strings much easier to review.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: remove locale file changes from PR
Reverts locale file diffs and .gitattributes to match main, per review
feedback. The locale changes were unrelated translation updates that
inflated the PR diff.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* chore: remove locale file changes from PR
Per @hjball's review: locale compilation/translations are handled
automatically on merge to main, so this PR shouldn't carry them.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* chore: align locale files with upstream/main
Previous removal commit used local main, which had drifted from
upstream. Re-syncing to upstream/main so the PR carries no locale diff.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
* fix(board-move): tighten deletedAt handling per review
Three changes addressing @hjball's review comments, all about the
schema treating deletedAt as optional metadata while the move-board
flow needs it as a load-bearing invariant.
1. getBoardForMove now filters isNull(deletedAt). Moving a tombstoned
board has no defensible semantics. Replaces the implicit
"the board exists in the table" check with an explicit
"the board is not soft-deleted" check.
2. Move-flow's clearing of cardToWorkspaceMembers now spans every
card under every list ever associated with this board, including
soft-deleted ones. If we leave member assignments on a deleted
card and that card is later restored, the assignments would
resurrect rogue references to workspace members from the OLD
workspace. Removed the isNull filters on both lists and cards in
that loop.
3. Move-flow now refuses to move into a soft-deleted target
workspace. workspaceRepo.getByPublicId did not previously project
deletedAt; extended its column selection so the call-site guard
in board.move can check it. (A wider fix to make the repo treat
deleted-as-not-found across all 14+ callers is left for a
separate PR — narrow scope here.)
Plus one regression test: throws NOT_FOUND when target workspace is
soft-deleted. All 11 board-move tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
* feat: add ticket numbers to cards with workspace prefix
- Add cardNumber to cards
- Add cardPrefix/cardCounter to workspace
- Populate initial prefixes and numbers via new migration
- Introduce generateWorkspacePrefix util and export it
- Include cardNumber in card-related API responses and search results
- Render and display tickets as PREFIX-NUMBER in UI
- Update Card component to accept ticketNumber
- Update CardModal and board cards to show number when available
- Add cardNumber to CommandPalette search results type
* feat: regen migration
* feat: enhance card and workspace schemas with cardNumber and indexing
- Updated the card repository to allocate card numbers atomically per workspace.
- Modified the card schema to include a cardNumber field and added an index on listId and cardNumber for improved query performance.
- Enhanced the workspace schema to include an index on cardPrefix for optimized lookups.
- Adjusted the migration journal to reflect the new schema changes and their timestamps.
- Updated the regex in workspace repository to allow alphanumeric prefixes in ticket IDs.
---------
Co-authored-by: Henry <henry_ball@hotmail.co.uk>
Previously, archiving or unarchiving a board left the user on the
(now archived/unarchived) board view with no clear navigation path.
This redirects to /boards after either action, matching the existing
behaviour of delete and move operations.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add card context menu and duplication functionality
* Implemented a context menu for cards allowing actions such as copying links, duplicating cards, and managing members, labels, and due dates
* Added modals for card duplication and context actions.
* Updated API with a new endpoint for duplicating cards, including options for copying labels, members, and checklists
* refactor: remove cardPublicId from context menu and related components
* Removed cardPublicId prop from CardContextMenu and CardContextMembersModal for cleaner context handling
* Updated scrollbar styling
* feat: add delete card functionality to context menu
* feat: workspace start of week column
* feat(l10n): add workspace setting for the first day of the week
Fixes#361
* feat: add Saturday as option
* chore: fix migration order
* chore: fix merge
---------
Co-authored-by: Henry <henry_ball@hotmail.co.uk>
* fix: add 404 not found page
Closes#320
- Add custom 404 page matching the app's design system
- Include PatternedBackground and proper dark mode support
- Provide navigation links to homepage and boards
- Add i18n support with @lingui/react
* fix: add 404 redirects for non-existent boards and cards
Add useEffect hooks to redirect to /404 page when:
- Board does not exist in board view
- Card does not exist in card view
This addresses the cases mentioned in maintainer feedback where
the static 404 page wasn't being used for dynamic routes.
Addresses review feedback on PR #349
* feat: redirect to 404 for non-existent public workspaces and cards
Per maintainer feedback:
- Add redirect logic to public boards view when workspace doesn't exist
- Add redirect logic to public card modal when card doesn't exist
- Uses error?.data?.code === 'NOT_FOUND' check as suggested
- Closes modal before redirecting for card modal
* init: schema migration, isArchived added to
board table. refactor: board repo for isArchived filtering
* init: archived, unarchived API procedures. refactor: all query
* fix: migration error
* feat: add tabbed navigation for boards view
* Implemented a Listbox for mobile and a tabbed navigation for desktop to switch between "Boards" and "Archived" views.
* Introduced state management for active tab selection.
* Updated UI components to reflect the new navigation structure.
* init: frontend/boards lists & tabs
* chore: fixed font styling and spacing
* init:boardDropdown / boardView.
* chore:added translations
* Remove .cursor plan file from repo
* fix:build erros
* revert: remove locales changes
* fix:reverted changes under locales, replaced the archive and unarchive endpoints. Reorder migrations
* fix:migration issue
* fix: update journal.json
---------
Co-authored-by: Henry <henry_ball@hotmail.co.uk>
- Use /boards/{id} for private board links so copied link works; keep pretty URL for public boards
- Show matching path in board header (pretty path for public, boards/id for private)
- Copy link button copies URL to clipboard instead of opening in new tab (opening a new tab seems redundant since we're already on it)
- Edit workspace URL button links to /settings/workspace instead of account settings
* feat: setup schema for workspace roles
* chore: regen migration
* feat: add publicId to workspace roles
* feat: setup default permissions
* feat: add repo funcs
* feat: setup basic router interactions
* feat: add card permissions
* feat: assert permissions for lists
* feat: assert board permissions
* feat: assert permission for remaining routes
* feat: add permissions page to settings
* feat: enable updating member roles
* feat: order members by role and createdAt
* feat: allow editing individual permissions
* feat: reset role defaults
* feat: clear all permission overrides
* feat: allow users to delete entities they have created
* feat: set roleId when inviting new members
* feat: disable UI elements if user does not have permissions
* feat: allow admins to assign the admin role to other users
* feat: allow delete:list as default
* refactor: centre permissions modal
* chore: translations
* feat: add YouTube video embed support for TipTap editor
- Paste YouTube URLs to auto-embed videos with metadata
- Edit video title and URL through dropdown menu
- Convert embed back to plain URL link
- Fetch video titles automatically via YouTube oEmbed API
* fix:
- reverted NewCardForm CSS properties back to max-h-48.
- Added boolean prop to TipTap Edtior for YouTube embed.
- Disabled YouTube embed feature for NewCardForm Editor
* chore: lint
* chore: translations
* chore: update translations
---------
Co-authored-by: Henry <henry_ball@hotmail.co.uk>
* feat: add card due dates to schema
* feat: update repo funcs
* feat: update card router to support due dates
* chore: update migration journal
* feat: add date selector
* feat: display date icon and label on cards
* feat: add due date filters
* feat: add due date to new card form
* feat: light mode tweaks
* feat: improve text eligibility on light mode
* feat: reduce selector font size
* feat: display date updates in card activity
* chore: gen translations
* feat: add list filter to board view
* feat: implement API-driven list filtering
* refactor: remove unnecessary list join from card filtering queries
* feat: enable list filter options for public boards
* refactor(perf): move to main query
---------
Co-authored-by: Henry <henry_ball@hotmail.co.uk>
* feat: card will indicate icons of comments and description
* fix: comments limit to one
* feat: fetch comments for public boards
---------
Co-authored-by: Henry <henry_ball@hotmail.co.uk>
* refactor: reorganize settings page with tabbed interface
* feat: revamp API key management with new list view and confirmation modals
* refactor: update tab styling
* refactor: tweak UI/UX for managing API keys
* refactor: only show update button when change has been made
* refactor: only show update button when content of display name has been updated
* feat: store tab state in params
* refactor: remove focus state from tabs
* refactor: tweak styling on mobile select
* refactor: simplify settings pages
* feat: open upgrade modal if upgrade=pro is in params
* feat: add scroll to api key list on mobile
* chore: add translations
---------
Co-authored-by: Henry <henry_ball@hotmail.co.uk>
* feat: add patterned background to boards
* feat: setup dashboard 2.0
* fix: prevent patterned background from overlaying buttons
* feat: set max width for main card view
* feat: adjust colour scheme for card view
* feat: adjust dashboard border colour scheme and radius
* fix: use correct colour for description placeholder
* fix: use getLayout to persist layout state across pages
* feat: reduce max width for settings and members pages
* feat: add feedback button and modal
* feat: adjust page max width
* feat: extend mobile layout support
* fix: hide pro badge when collapsed
* feat: tweak nav styling for light mode
* feat: tweak skeleton loaders for board list
* feat: extend list max height
* fix: hide side nav right border on desktop
* chore: update hero images
* chore: update hero images for docs
* chore: update translations
* feat: add mobile navigation with responsive layout and theme controls
* feat: prevent workspace owners from removing themselves and update workspace dropdown styling
* feat: add useClickOutside hook and event listener utilities for improved UI interactions
* chore: improve mobile UI styling
* refactor: improve UI layout and buttons in boards/members views
feat: adjust /members layout
* fix: standardize layout containers and improve mobile navigation styling
* feat: update card view layout
* feat: add responsive layout to board view
* feat: readjust boards page layout
* feat: enhance table view on mobile for members page
* feat: extend mobile support with sliding side panels
* fix: prevent two panels from being open at the same time
* feat: close panels when clicking outside
* fix: adjust font-sizing for import source
---------
Co-authored-by: Henry <henry_ball@hotmail.co.uk>
* feat: setup localisation with lingui
* Fix hydration and locale issues
* Add missing translations and tweak selector styling
* Extend language support
* Update lang support
* Extend lang support
* Fix build and add dyanmic imports
* feat: enhance board visibility controls with dropdown menu and success notifications
* feat: tweak design
---------
Co-authored-by: Henry <henry_ball@hotmail.co.uk>