ui-syncup 0.3.13 → 0.4.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/skills/ai-spec-workflow/SKILL.md +58 -0
- package/.agents/skills/ai-spec-workflow/references/AI_SPECIFICATION_WORKFLOW.md +1434 -0
- package/.agents/skills/ai-spec-workflow/references/templates/design-template.md +729 -0
- package/.agents/skills/ai-spec-workflow/references/templates/requirements-template.md +179 -0
- package/.agents/skills/ai-spec-workflow/references/templates/tasks-template.md +501 -0
- package/.agents/skills/animation-designer/SKILL.md +688 -0
- package/.agents/skills/animation-designer/manifest.yaml +44 -0
- package/.agents/skills/brainstorming/SKILL.md +54 -0
- package/.agents/skills/contract-driven-ui/SKILL.md +270 -0
- package/.agents/skills/dispatching-parallel-agents/SKILL.md +180 -0
- package/.agents/skills/executing-plans/SKILL.md +76 -0
- package/.agents/skills/executing-specs/SKILL.md +53 -0
- package/.agents/skills/finishing-a-development-branch/SKILL.md +200 -0
- package/.agents/skills/github-workflow-automation/SKILL.md +846 -0
- package/.agents/skills/react-best-practices/AGENTS.md +2249 -0
- package/.agents/skills/react-best-practices/README.md +123 -0
- package/.agents/skills/react-best-practices/SKILL.md +121 -0
- package/.agents/skills/react-best-practices/metadata.json +15 -0
- package/.agents/skills/react-best-practices/rules/_sections.md +46 -0
- package/.agents/skills/react-best-practices/rules/_template.md +28 -0
- package/.agents/skills/react-best-practices/rules/advanced-event-handler-refs.md +55 -0
- package/.agents/skills/react-best-practices/rules/advanced-use-latest.md +49 -0
- package/.agents/skills/react-best-practices/rules/async-api-routes.md +38 -0
- package/.agents/skills/react-best-practices/rules/async-defer-await.md +80 -0
- package/.agents/skills/react-best-practices/rules/async-dependencies.md +36 -0
- package/.agents/skills/react-best-practices/rules/async-parallel.md +28 -0
- package/.agents/skills/react-best-practices/rules/async-suspense-boundaries.md +99 -0
- package/.agents/skills/react-best-practices/rules/bundle-barrel-imports.md +59 -0
- package/.agents/skills/react-best-practices/rules/bundle-conditional.md +31 -0
- package/.agents/skills/react-best-practices/rules/bundle-defer-third-party.md +49 -0
- package/.agents/skills/react-best-practices/rules/bundle-dynamic-imports.md +35 -0
- package/.agents/skills/react-best-practices/rules/bundle-preload.md +50 -0
- package/.agents/skills/react-best-practices/rules/client-event-listeners.md +74 -0
- package/.agents/skills/react-best-practices/rules/client-swr-dedup.md +56 -0
- package/.agents/skills/react-best-practices/rules/js-batch-dom-css.md +82 -0
- package/.agents/skills/react-best-practices/rules/js-cache-function-results.md +80 -0
- package/.agents/skills/react-best-practices/rules/js-cache-property-access.md +28 -0
- package/.agents/skills/react-best-practices/rules/js-cache-storage.md +70 -0
- package/.agents/skills/react-best-practices/rules/js-combine-iterations.md +32 -0
- package/.agents/skills/react-best-practices/rules/js-early-exit.md +50 -0
- package/.agents/skills/react-best-practices/rules/js-hoist-regexp.md +45 -0
- package/.agents/skills/react-best-practices/rules/js-index-maps.md +37 -0
- package/.agents/skills/react-best-practices/rules/js-length-check-first.md +49 -0
- package/.agents/skills/react-best-practices/rules/js-min-max-loop.md +82 -0
- package/.agents/skills/react-best-practices/rules/js-set-map-lookups.md +24 -0
- package/.agents/skills/react-best-practices/rules/js-tosorted-immutable.md +57 -0
- package/.agents/skills/react-best-practices/rules/rendering-activity.md +26 -0
- package/.agents/skills/react-best-practices/rules/rendering-animate-svg-wrapper.md +47 -0
- package/.agents/skills/react-best-practices/rules/rendering-conditional-render.md +40 -0
- package/.agents/skills/react-best-practices/rules/rendering-content-visibility.md +38 -0
- package/.agents/skills/react-best-practices/rules/rendering-hoist-jsx.md +46 -0
- package/.agents/skills/react-best-practices/rules/rendering-hydration-no-flicker.md +82 -0
- package/.agents/skills/react-best-practices/rules/rendering-svg-precision.md +28 -0
- package/.agents/skills/react-best-practices/rules/rerender-defer-reads.md +39 -0
- package/.agents/skills/react-best-practices/rules/rerender-dependencies.md +45 -0
- package/.agents/skills/react-best-practices/rules/rerender-derived-state.md +29 -0
- package/.agents/skills/react-best-practices/rules/rerender-functional-setstate.md +74 -0
- package/.agents/skills/react-best-practices/rules/rerender-lazy-state-init.md +58 -0
- package/.agents/skills/react-best-practices/rules/rerender-memo.md +44 -0
- package/.agents/skills/react-best-practices/rules/rerender-transitions.md +40 -0
- package/.agents/skills/react-best-practices/rules/server-after-nonblocking.md +73 -0
- package/.agents/skills/react-best-practices/rules/server-cache-lru.md +41 -0
- package/.agents/skills/react-best-practices/rules/server-cache-react.md +26 -0
- package/.agents/skills/react-best-practices/rules/server-parallel-fetching.md +79 -0
- package/.agents/skills/react-best-practices/rules/server-serialization.md +38 -0
- package/.agents/skills/react-ui-patterns/SKILL.md +289 -0
- package/.agents/skills/receiving-code-review/SKILL.md +213 -0
- package/.agents/skills/requesting-code-review/SKILL.md +105 -0
- package/.agents/skills/requesting-code-review/code-reviewer.md +146 -0
- package/.agents/skills/reviewing-code/SKILL.md +28 -0
- package/.agents/skills/shadcn/SKILL.md +240 -0
- package/.agents/skills/shadcn/agents/openai.yml +5 -0
- package/.agents/skills/shadcn/assets/shadcn-small.png +0 -0
- package/.agents/skills/shadcn/assets/shadcn.png +0 -0
- package/.agents/skills/shadcn/cli.md +255 -0
- package/.agents/skills/shadcn/customization.md +202 -0
- package/.agents/skills/shadcn/evals/evals.json +47 -0
- package/.agents/skills/shadcn/mcp.md +94 -0
- package/.agents/skills/shadcn/rules/base-vs-radix.md +306 -0
- package/.agents/skills/shadcn/rules/composition.md +195 -0
- package/.agents/skills/shadcn/rules/forms.md +192 -0
- package/.agents/skills/shadcn/rules/icons.md +101 -0
- package/.agents/skills/shadcn/rules/styling.md +162 -0
- package/.agents/skills/steering-creation/SKILL.md +221 -0
- package/.agents/skills/steering-creation/references/STEERING_CREATION_INSTRUCTION.md +850 -0
- package/.agents/skills/subagent-driven-development/SKILL.md +240 -0
- package/.agents/skills/subagent-driven-development/code-quality-reviewer-prompt.md +20 -0
- package/.agents/skills/subagent-driven-development/implementer-prompt.md +78 -0
- package/.agents/skills/subagent-driven-development/spec-reviewer-prompt.md +61 -0
- package/.agents/skills/systematic-debugging/CREATION-LOG.md +119 -0
- package/.agents/skills/systematic-debugging/SKILL.md +296 -0
- package/.agents/skills/systematic-debugging/condition-based-waiting-example.ts +158 -0
- package/.agents/skills/systematic-debugging/condition-based-waiting.md +115 -0
- package/.agents/skills/systematic-debugging/defense-in-depth.md +122 -0
- package/.agents/skills/systematic-debugging/find-polluter.sh +63 -0
- package/.agents/skills/systematic-debugging/root-cause-tracing.md +169 -0
- package/.agents/skills/systematic-debugging/test-academic.md +14 -0
- package/.agents/skills/systematic-debugging/test-pressure-1.md +58 -0
- package/.agents/skills/systematic-debugging/test-pressure-2.md +68 -0
- package/.agents/skills/systematic-debugging/test-pressure-3.md +69 -0
- package/.agents/skills/test-driven-development/SKILL.md +371 -0
- package/.agents/skills/test-driven-development/testing-anti-patterns.md +299 -0
- package/.agents/skills/using-git-worktrees/SKILL.md +217 -0
- package/.agents/skills/using-superpowers/SKILL.md +87 -0
- package/.agents/skills/verification-before-completion/SKILL.md +139 -0
- package/.agents/skills/web-design-guidelines/SKILL.md +36 -0
- package/.agents/skills/writing-plans/SKILL.md +116 -0
- package/.agents/skills/writing-skills/SKILL.md +655 -0
- package/.agents/skills/writing-skills/anthropic-best-practices.md +1150 -0
- package/.agents/skills/writing-skills/examples/CLAUDE_MD_TESTING.md +189 -0
- package/.agents/skills/writing-skills/graphviz-conventions.dot +172 -0
- package/.agents/skills/writing-skills/persuasion-principles.md +187 -0
- package/.agents/skills/writing-skills/render-graphs.js +168 -0
- package/.agents/skills/writing-skills/testing-skills-with-subagents.md +384 -0
- package/.ai/steering/product.md +51 -0
- package/.ai/steering/structure.md +275 -0
- package/.ai/steering/tech.md +188 -0
- package/.claude/agents/database-architect.md +96 -0
- package/.claude/agents/deployment-pipeline-architect.md +122 -0
- package/.claude/agents/nextjs-expert.md +69 -0
- package/.claude/agents/ui-design-expert.md +106 -0
- package/.claudeignore +69 -0
- package/.dockerignore +8 -0
- package/.env.development +86 -0
- package/.env.example +171 -0
- package/.env.production +139 -0
- package/.env.test +58 -0
- package/.gitattributes +2 -0
- package/.github/ISSUE_TEMPLATE/bug_report.yml +33 -0
- package/.github/ISSUE_TEMPLATE/feature_request.yml +20 -0
- package/.github/PULL_REQUEST_TEMPLATE.md +23 -0
- package/.github/workflows/ci.yml +64 -0
- package/.github/workflows/release.yml +131 -0
- package/.nvmrc +1 -0
- package/.releaserc.json +18 -0
- package/.vercelignore +73 -0
- package/AGENTS.md +544 -0
- package/CHANGELOG.md +37 -0
- package/CODE_OF_CONDUCT.md +21 -0
- package/CONTRIBUTING.md +32 -0
- package/Dockerfile +84 -0
- package/LICENSE +21 -0
- package/README.md +328 -59
- package/SECURITY.md +16 -0
- package/bun.lock +3853 -0
- package/cli/README.md +94 -0
- package/cli/bun.lock +306 -0
- package/cli/index.ts +96 -0
- package/cli/package-lock.json +2157 -0
- package/cli/package.json +30 -0
- package/cli/src/commands/backup.ts +78 -0
- package/cli/src/commands/doctor.ts +82 -0
- package/cli/src/commands/init.ts +234 -0
- package/cli/src/commands/logs.ts +26 -0
- package/cli/src/commands/open.ts +23 -0
- package/cli/src/commands/remove.ts +44 -0
- package/cli/src/commands/restart.ts +21 -0
- package/cli/src/commands/restore.ts +90 -0
- package/cli/src/commands/start.ts +26 -0
- package/cli/src/commands/status.ts +25 -0
- package/cli/src/commands/stop.ts +20 -0
- package/cli/src/commands/upgrade.ts +28 -0
- package/cli/src/lib/docker.ts +40 -0
- package/cli/src/lib/env.ts +42 -0
- package/cli/src/lib/ui.ts +43 -0
- package/cli/tsconfig.json +13 -0
- package/cli/tsup.config.ts +12 -0
- package/components.json +24 -0
- package/docker/README.md +430 -0
- package/docker/compose.dev-minio.yml +30 -0
- package/docker/compose.dev.yml +39 -0
- package/docker/compose.local.yml +84 -0
- package/docker/compose.yml +153 -0
- package/docs/VERSIONING.md +117 -0
- package/docs/database/DRIZZLE_COMMANDS_EXPLAINED.md +1779 -0
- package/docs/database/DRIZZLE_ZOD_POSTGRESQL_INSTRUCTION.md +646 -0
- package/docs/database/MIGRATION_BEST_PRACTICES.md +601 -0
- package/docs/database/MIGRATION_ROLLBACK.md +1080 -0
- package/docs/database/MIGRATION_SYSTEM.md +165 -0
- package/docs/database/MIGRATION_TROUBLESHOOTING.md +881 -0
- package/docs/development/ENVIRONMENT_CONFIG.md +896 -0
- package/docs/development/LOCAL_DEVELOPMENT.md +456 -0
- package/docs/development/REMOTE_DATABASE_SETUP.md +786 -0
- package/docs/development/STORAGE_SETUP.md +207 -0
- package/docs/development/SUPABASE_LOCAL_SETUP.md +178 -0
- package/docs/development/TESTING.md +714 -0
- package/docs/feature-architectures/LOADING_ARCHITECTURE.md +343 -0
- package/docs/feature-architectures/NOTIFICATION_ARCHITECTURE.md +858 -0
- package/docs/feature-architectures/RATE_LIMIT_RESET.md +147 -0
- package/docs/feature-architectures/RBAC.md +1132 -0
- package/docs/feature-architectures/RESOURCE_LIMITS.md +69 -0
- package/docs/feature-architectures/SECURITY.md +284 -0
- package/docs/feature-architectures/WORKSPACES.md +278 -0
- package/docs/plans/admin-setup-wizard-routing-plan.md +623 -0
- package/drizzle/0000_purple_wilson_fisk.sql +360 -0
- package/drizzle/0001_drop_instance_public_url.sql +1 -0
- package/drizzle/meta/0000_snapshot.json +3118 -0
- package/drizzle/meta/_journal.json +20 -0
- package/drizzle.config.ts +13 -0
- package/eslint.config.mjs +44 -0
- package/install.sh +180 -0
- package/next.config.ts +91 -0
- package/package.json +128 -22
- package/playwright.config.ts +70 -0
- package/postcss.config.mjs +7 -0
- package/public/file.svg +1 -0
- package/public/globe.svg +1 -0
- package/public/logo.svg +11 -0
- package/public/next.svg +1 -0
- package/public/playground/CPM-101/as-is-image.jpg +0 -0
- package/public/playground/CPM-101/to-be-image.jpg +0 -0
- package/public/playground/TEST-1/LinkedIn-skeleton-screen.png +0 -0
- package/public/playground/TEST-1/https___dev-to-uploads.s3.amazonaws.com_uploads_articles_vuahe90ka1mkx9aepmea.webp +0 -0
- package/public/playground/TEST-1/linkedin_skeletonscreen.jpg +0 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/scripts/__tests__/migrate.integration.test.ts +642 -0
- package/scripts/__tests__/migrate.property.test.ts +1714 -0
- package/scripts/__tests__/migrate.test.ts +536 -0
- package/scripts/admin-reset-password.ts +114 -0
- package/scripts/check-email-queue.ts +99 -0
- package/scripts/check-sessions.ts +50 -0
- package/scripts/db-pull-data.sh +73 -0
- package/scripts/force-verify-email.sh +13 -0
- package/scripts/migrate.ts +693 -0
- package/scripts/process-email-queue.ts +26 -0
- package/scripts/reset-db.ts +47 -0
- package/scripts/reset-rate-limit.sh +26 -0
- package/scripts/reset-remote-db.sql +31 -0
- package/scripts/retry-failed-emails.ts +67 -0
- package/scripts/seed.ts +605 -0
- package/scripts/setup-monitoring.sh +440 -0
- package/scripts/sync-migration-tracking.ts +113 -0
- package/scripts/test-ci-error-handling.sh +237 -0
- package/scripts/test-ci-workflow.sh +200 -0
- package/scripts/test-migration.sh +151 -0
- package/scripts/validate-env.ts +25 -0
- package/scripts/validate-migration-system.ts +566 -0
- package/scripts/verify-ci-status-reporting.sh +206 -0
- package/scripts/verify-user-email.sql +22 -0
- package/scripts/verify-vercel-integration.ts +292 -0
- package/seed_data.md +54 -0
- package/src/app/(protected)/(team)/(routes)/[projectSlug]/error.tsx +89 -0
- package/src/app/(protected)/(team)/(routes)/[projectSlug]/loading.tsx +101 -0
- package/src/app/(protected)/(team)/(routes)/[projectSlug]/page.tsx +91 -0
- package/src/app/(protected)/(team)/(routes)/issue/[issueKey]/README.md +192 -0
- package/src/app/(protected)/(team)/(routes)/issue/[issueKey]/error.tsx +58 -0
- package/src/app/(protected)/(team)/(routes)/issue/[issueKey]/loading.tsx +14 -0
- package/src/app/(protected)/(team)/(routes)/issue/[issueKey]/not-found.tsx +47 -0
- package/src/app/(protected)/(team)/(routes)/issue/[issueKey]/page.tsx +91 -0
- package/src/app/(protected)/(team)/projects/page.tsx +16 -0
- package/src/app/(protected)/(team)/team/settings/(section)/instance/page.tsx +52 -0
- package/src/app/(protected)/(team)/team/settings/(section)/integrations/loading.tsx +5 -0
- package/src/app/(protected)/(team)/team/settings/(section)/integrations/page.tsx +23 -0
- package/src/app/(protected)/(team)/team/settings/(section)/members/loading.tsx +5 -0
- package/src/app/(protected)/(team)/team/settings/(section)/members/page.tsx +35 -0
- package/src/app/(protected)/(team)/team/settings/layout.tsx +72 -0
- package/src/app/(protected)/(team)/team/settings/loading.tsx +5 -0
- package/src/app/(protected)/(team)/team/settings/page.tsx +71 -0
- package/src/app/(protected)/dev/auth/README.md +151 -0
- package/src/app/(protected)/dev/auth/page.tsx +590 -0
- package/src/app/(protected)/layout.test.tsx +209 -0
- package/src/app/(protected)/layout.tsx +28 -0
- package/src/app/(protected)/onboarding/page.tsx +27 -0
- package/src/app/(protected)/settings/integrations/page.tsx +23 -0
- package/src/app/(protected)/settings/layout.tsx +26 -0
- package/src/app/(protected)/settings/notifications/page.tsx +26 -0
- package/src/app/(protected)/settings/other/page.tsx +23 -0
- package/src/app/(protected)/settings/page.tsx +23 -0
- package/src/app/(protected)/settings/preferences/page.tsx +23 -0
- package/src/app/(protected)/settings/security/page.tsx +37 -0
- package/src/app/(public)/forgot-password/page.tsx +20 -0
- package/src/app/(public)/invite/project/[token]/error.tsx +50 -0
- package/src/app/(public)/invite/project/[token]/loading.tsx +39 -0
- package/src/app/(public)/invite/project/[token]/page.tsx +156 -0
- package/src/app/(public)/layout.tsx +9 -0
- package/src/app/(public)/privacy-policy/page.tsx +12 -0
- package/src/app/(public)/reset-password/page.tsx +37 -0
- package/src/app/(public)/setup/__tests__/page.test.tsx +30 -0
- package/src/app/(public)/setup/page.tsx +17 -0
- package/src/app/(public)/share/issue/[token]/page.tsx +51 -0
- package/src/app/(public)/sign-in/page.tsx +55 -0
- package/src/app/(public)/sign-up/page.tsx +23 -0
- package/src/app/(public)/verify-email/page.tsx +22 -0
- package/src/app/(public)/verify-email-confirm/page.tsx +40 -0
- package/src/app/api/auth/[...all]/route.ts +6 -0
- package/src/app/api/auth/delete-account/route.ts +134 -0
- package/src/app/api/auth/dev/force-verify/route.ts +180 -0
- package/src/app/api/auth/dev/reset-rate-limit/route.ts +144 -0
- package/src/app/api/auth/dev/sessions/route.ts +172 -0
- package/src/app/api/auth/forgot-password/__tests__/forgot-password.property.test.ts +397 -0
- package/src/app/api/auth/forgot-password/route.ts +277 -0
- package/src/app/api/auth/logout/route.ts +115 -0
- package/src/app/api/auth/me/route.ts +123 -0
- package/src/app/api/auth/providers/__tests__/route.test.ts +236 -0
- package/src/app/api/auth/providers/route.ts +119 -0
- package/src/app/api/auth/resend-verification/route.ts +262 -0
- package/src/app/api/auth/reset-password/__tests__/reset-password.property.test.ts +493 -0
- package/src/app/api/auth/reset-password/__tests__/route.test.ts +284 -0
- package/src/app/api/auth/reset-password/route.ts +251 -0
- package/src/app/api/auth/verify-email/route.ts +232 -0
- package/src/app/api/example-cors/route.ts +61 -0
- package/src/app/api/health/route.ts +14 -0
- package/src/app/api/invite/project/[token]/__tests__/accept-invitation.integration.test.ts +348 -0
- package/src/app/api/invite/project/[token]/decline/route.ts +99 -0
- package/src/app/api/invite/project/[token]/route.ts +269 -0
- package/src/app/api/issues/[issueId]/activities/route.ts +213 -0
- package/src/app/api/issues/[issueId]/attachments/[attachmentId]/annotations/[annotationId]/comments/[commentId]/route.ts +486 -0
- package/src/app/api/issues/[issueId]/attachments/[attachmentId]/annotations/[annotationId]/comments/route.ts +283 -0
- package/src/app/api/issues/[issueId]/attachments/[attachmentId]/annotations/[annotationId]/read/route.ts +242 -0
- package/src/app/api/issues/[issueId]/attachments/[attachmentId]/annotations/[annotationId]/route.ts +534 -0
- package/src/app/api/issues/[issueId]/attachments/[attachmentId]/annotations/route.ts +514 -0
- package/src/app/api/issues/[issueId]/attachments/[attachmentId]/route.ts +161 -0
- package/src/app/api/issues/[issueId]/attachments/route.ts +376 -0
- package/src/app/api/issues/[issueId]/route.ts +516 -0
- package/src/app/api/notifications/[id]/read/route.ts +131 -0
- package/src/app/api/notifications/__tests__/notifications.integration.test.ts +350 -0
- package/src/app/api/notifications/read-all/route.ts +72 -0
- package/src/app/api/notifications/route.ts +148 -0
- package/src/app/api/notifications/unread-count/route.ts +77 -0
- package/src/app/api/projects/[id]/activities/route.ts +174 -0
- package/src/app/api/projects/[id]/invitations/[invitationId]/resend/route.ts +99 -0
- package/src/app/api/projects/[id]/invitations/[invitationId]/route.ts +96 -0
- package/src/app/api/projects/[id]/invitations/route.ts +254 -0
- package/src/app/api/projects/[id]/issues/route.ts +452 -0
- package/src/app/api/projects/[id]/join/route.ts +207 -0
- package/src/app/api/projects/[id]/members/[memberId]/route.ts +364 -0
- package/src/app/api/projects/[id]/members/me/route.ts +121 -0
- package/src/app/api/projects/[id]/members/route.ts +129 -0
- package/src/app/api/projects/[id]/route.ts +476 -0
- package/src/app/api/projects/route.ts +394 -0
- package/src/app/api/setup/admin/route.ts +255 -0
- package/src/app/api/setup/complete/__tests__/route.test.ts +60 -0
- package/src/app/api/setup/complete/route.ts +244 -0
- package/src/app/api/setup/config/route.ts +195 -0
- package/src/app/api/setup/export/route.ts +111 -0
- package/src/app/api/setup/health/route.ts +74 -0
- package/src/app/api/setup/import/route.ts +154 -0
- package/src/app/api/setup/status/route.ts +82 -0
- package/src/app/api/setup/workspace/route.ts +252 -0
- package/src/app/api/teams/[teamId]/export/route.ts +115 -0
- package/src/app/api/teams/[teamId]/invitations/[invitationId]/resend/route.ts +132 -0
- package/src/app/api/teams/[teamId]/invitations/[invitationId]/route.ts +117 -0
- package/src/app/api/teams/[teamId]/invitations/route.ts +363 -0
- package/src/app/api/teams/[teamId]/members/[userId]/route.ts +335 -0
- package/src/app/api/teams/[teamId]/members/route.ts +184 -0
- package/src/app/api/teams/[teamId]/members/search/route.ts +202 -0
- package/src/app/api/teams/[teamId]/route.ts +423 -0
- package/src/app/api/teams/[teamId]/switch/route.ts +140 -0
- package/src/app/api/teams/[teamId]/transfer-ownership/route.ts +212 -0
- package/src/app/api/teams/invitations/[token]/accept/route.ts +140 -0
- package/src/app/api/teams/invitations/by-id/[id]/accept/route.ts +98 -0
- package/src/app/api/teams/invitations/by-id/[id]/decline/route.ts +90 -0
- package/src/app/api/teams/route.ts +278 -0
- package/src/app/api/uploads/media/route.ts +118 -0
- package/src/app/api/uploads/presigned/route.ts +49 -0
- package/src/app/api/user/linked-accounts/route.ts +35 -0
- package/src/app/email-preview/page.tsx +11 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/global-error.tsx +21 -0
- package/src/app/layout.tsx +50 -0
- package/src/app/page.tsx +5 -0
- package/src/components/icons/atlassian-icon.tsx +22 -0
- package/src/components/icons/index.ts +1 -0
- package/src/components/layout/SIDEBAR_LAYOUT_BEST_PRACTICES.md +240 -0
- package/src/components/layout/app-shell-header-store.tsx +20 -0
- package/src/components/layout/app-shell-skeleton.tsx +89 -0
- package/src/components/layout/app-shell-wrapper.tsx +32 -0
- package/src/components/layout/app-shell.test.tsx +155 -0
- package/src/components/layout/app-shell.tsx +100 -0
- package/src/components/shared/headers/app-header-configurator.tsx +42 -0
- package/src/components/shared/headers/app-header.tsx +103 -0
- package/src/components/shared/headers/header-user-menu.tsx +247 -0
- package/src/components/shared/headers/index.ts +44 -0
- package/src/components/shared/headers/page-header.tsx +25 -0
- package/src/components/shared/notifications/__tests__/notification-bell.test.tsx +159 -0
- package/src/components/shared/notifications/__tests__/notification-dropdown.test.tsx +296 -0
- package/src/components/shared/notifications/__tests__/notification-item.test.tsx +328 -0
- package/src/components/shared/notifications/index.ts +45 -0
- package/src/components/shared/notifications/notification-actions.tsx +295 -0
- package/src/components/shared/notifications/notification-bell-button.tsx +77 -0
- package/src/components/shared/notifications/notification-dropdown.tsx +160 -0
- package/src/components/shared/notifications/notification-group-item.tsx +268 -0
- package/src/components/shared/notifications/notification-item.tsx +193 -0
- package/src/components/shared/notifications/notification-load-more.tsx +50 -0
- package/src/components/shared/notifications/notification-panel.tsx +49 -0
- package/src/components/shared/notifications/utils.tsx +127 -0
- package/src/components/shared/permission-guard/index.ts +1 -0
- package/src/components/shared/permission-guard/permission-tooltip.tsx +45 -0
- package/src/components/shared/relative-time.tsx +53 -0
- package/src/components/shared/section-container.tsx +32 -0
- package/src/components/shared/service-status-banner.tsx +121 -0
- package/src/components/shared/settings-sidebar/index.ts +2 -0
- package/src/components/shared/settings-sidebar/team-setting-aside.tsx +97 -0
- package/src/components/shared/settings-sidebar/user-settings-aside.tsx +66 -0
- package/src/components/shared/sidebar/app-sidebar.tsx +146 -0
- package/src/components/shared/sidebar/index.ts +36 -0
- package/src/components/shared/sidebar/sidebar-main.tsx +81 -0
- package/src/components/shared/sidebar/sidebar-project.tsx +61 -0
- package/src/components/shared/sidebar/sidebar-team-avatar.tsx +126 -0
- package/src/components/shared/sidebar/sidebar-team-switcher.tsx +185 -0
- package/src/components/shared/sidebar/type.ts +97 -0
- package/src/components/ui/alert-dialog.tsx +157 -0
- package/src/components/ui/alert.tsx +66 -0
- package/src/components/ui/avatar-upload.tsx +147 -0
- package/src/components/ui/avatar.tsx +53 -0
- package/src/components/ui/badge.tsx +46 -0
- package/src/components/ui/breadcrumb.tsx +109 -0
- package/src/components/ui/button.tsx +60 -0
- package/src/components/ui/card.tsx +92 -0
- package/src/components/ui/checkbox.tsx +32 -0
- package/src/components/ui/collapsible.tsx +33 -0
- package/src/components/ui/command.tsx +184 -0
- package/src/components/ui/dialog.tsx +143 -0
- package/src/components/ui/dropdown-menu.tsx +257 -0
- package/src/components/ui/empty.tsx +104 -0
- package/src/components/ui/field.tsx +244 -0
- package/src/components/ui/image-cropper-dialog.tsx +167 -0
- package/src/components/ui/input.tsx +21 -0
- package/src/components/ui/label.tsx +24 -0
- package/src/components/ui/optimized-image.tsx +220 -0
- package/src/components/ui/pagination.tsx +127 -0
- package/src/components/ui/popover.tsx +48 -0
- package/src/components/ui/progress.tsx +31 -0
- package/src/components/ui/radio-group.tsx +45 -0
- package/src/components/ui/scroll-area.tsx +58 -0
- package/src/components/ui/select.tsx +187 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/sheet.tsx +139 -0
- package/src/components/ui/sidebar.tsx +733 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/sonner.tsx +40 -0
- package/src/components/ui/spinner.tsx +16 -0
- package/src/components/ui/switch.tsx +31 -0
- package/src/components/ui/table.tsx +116 -0
- package/src/components/ui/tabs.tsx +66 -0
- package/src/components/ui/textarea.tsx +23 -0
- package/src/components/ui/tooltip.tsx +61 -0
- package/src/config/__tests__/workspace.property.test.ts +40 -0
- package/src/config/auth.ts +62 -0
- package/src/config/integrations.ts +126 -0
- package/src/config/quotas.ts +20 -0
- package/src/config/roles.ts +463 -0
- package/src/config/settings-nav.ts +39 -0
- package/src/config/team-settings-nav.ts +37 -0
- package/src/config/user-settings-nav.ts +42 -0
- package/src/config/version.ts +1 -0
- package/src/config/workspace.ts +64 -0
- package/src/features/annotations/README.md +283 -0
- package/src/features/annotations/api/annotations-api.ts +194 -0
- package/src/features/annotations/api/comments-api.ts +147 -0
- package/src/features/annotations/api/index.ts +71 -0
- package/src/features/annotations/api/save-annotation.ts +150 -0
- package/src/features/annotations/api/schemas.ts +142 -0
- package/src/features/annotations/components/annotated-attachment-view.tsx +576 -0
- package/src/features/annotations/components/annotation-action-sheet.tsx +140 -0
- package/src/features/annotations/components/annotation-annotations-panel.tsx +213 -0
- package/src/features/annotations/components/annotation-box.tsx +539 -0
- package/src/features/annotations/components/annotation-canvas.tsx +534 -0
- package/src/features/annotations/components/annotation-comment-input.tsx +145 -0
- package/src/features/annotations/components/annotation-context-menu.tsx +164 -0
- package/src/features/annotations/components/annotation-drawer.tsx +231 -0
- package/src/features/annotations/components/annotation-layer.tsx +271 -0
- package/src/features/annotations/components/annotation-pin.tsx +318 -0
- package/src/features/annotations/components/annotation-popover.tsx +562 -0
- package/src/features/annotations/components/annotation-thread-panel.tsx +485 -0
- package/src/features/annotations/components/annotation-thread-preview.tsx +195 -0
- package/src/features/annotations/components/annotation-toolbar.tsx +244 -0
- package/src/features/annotations/components/keyboard-shortcuts-modal.tsx +79 -0
- package/src/features/annotations/docs/ANNOTATIONS_ARCHITECTURE.md +67 -0
- package/src/features/annotations/docs/ANNOTATION_SAVE_ARCHITECTURE.md +422 -0
- package/src/features/annotations/docs/ANNOTATION_SAVE_FEATURE.md +408 -0
- package/src/features/annotations/docs/BOX_ANNOTATION_GUIDE.md +542 -0
- package/src/features/annotations/docs/NEXTSTEP.md +28 -0
- package/src/features/annotations/docs/STALE_CLOSURE_FIX.md +344 -0
- package/src/features/annotations/docs/UNDO_REDO_QUICK_START.md +545 -0
- package/src/features/annotations/docs/local_first_canvas_autosave_architecture.md +674 -0
- package/src/features/annotations/examples/complete-example.tsx +266 -0
- package/src/features/annotations/examples/save-annotation-example.tsx +309 -0
- package/src/features/annotations/hooks/__tests__/use-annotation-permissions.property.test.tsx +493 -0
- package/src/features/annotations/hooks/index.ts +36 -0
- package/src/features/annotations/hooks/use-annotation-batch-save.ts +109 -0
- package/src/features/annotations/hooks/use-annotation-comments.ts +353 -0
- package/src/features/annotations/hooks/use-annotation-drafts.ts +137 -0
- package/src/features/annotations/hooks/use-annotation-edit-state.ts +99 -0
- package/src/features/annotations/hooks/use-annotation-history-tracker.ts +159 -0
- package/src/features/annotations/hooks/use-annotation-integration.ts +916 -0
- package/src/features/annotations/hooks/use-annotation-permissions.ts +210 -0
- package/src/features/annotations/hooks/use-annotation-popover.ts +175 -0
- package/src/features/annotations/hooks/use-annotation-save.ts +208 -0
- package/src/features/annotations/hooks/use-annotation-tools.ts +237 -0
- package/src/features/annotations/hooks/use-annotations-with-history.ts +332 -0
- package/src/features/annotations/hooks/use-auto-save.ts +94 -0
- package/src/features/annotations/index.ts +111 -0
- package/src/features/annotations/types/annotation.ts +201 -0
- package/src/features/annotations/types/index.ts +28 -0
- package/src/features/annotations/utils/history-manager.ts +73 -0
- package/src/features/annotations/utils/index.ts +2 -0
- package/src/features/annotations/utils/map-attachments-to-threads.ts +28 -0
- package/src/features/annotations/utils/position-comment-input.ts +136 -0
- package/src/features/annotations/utils/re-sequence-labels.ts +92 -0
- package/src/features/annotations/utils/validate-annotation-label.ts +120 -0
- package/src/features/auth/api/types.ts +101 -0
- package/src/features/auth/components/__tests__/role-gate.test.tsx +448 -0
- package/src/features/auth/components/__tests__/social-login-buttons.test.tsx +313 -0
- package/src/features/auth/components/auth-card.tsx +36 -0
- package/src/features/auth/components/forgot-password-form.tsx +115 -0
- package/src/features/auth/components/index.ts +14 -0
- package/src/features/auth/components/invite-code-input.tsx +155 -0
- package/src/features/auth/components/invited-user-form.tsx +309 -0
- package/src/features/auth/components/onboarding-form.tsx +195 -0
- package/src/features/auth/components/password-strength-indicator.tsx +113 -0
- package/src/features/auth/components/reset-password-form.tsx +138 -0
- package/src/features/auth/components/role-gate.tsx +124 -0
- package/src/features/auth/components/self-registration-choice.tsx +153 -0
- package/src/features/auth/components/sign-in-form.tsx +159 -0
- package/src/features/auth/components/sign-up-form.tsx +158 -0
- package/src/features/auth/components/social-login-buttons.tsx +219 -0
- package/src/features/auth/hooks/__tests__/use-onboarding.test.tsx +109 -0
- package/src/features/auth/hooks/__tests__/use-session.test.tsx +160 -0
- package/src/features/auth/hooks/index.ts +15 -0
- package/src/features/auth/hooks/use-accept-invitation.ts +194 -0
- package/src/features/auth/hooks/use-delete-account.ts +86 -0
- package/src/features/auth/hooks/use-force-verify.ts +89 -0
- package/src/features/auth/hooks/use-forgot-password.ts +144 -0
- package/src/features/auth/hooks/use-link-account.ts +78 -0
- package/src/features/auth/hooks/use-linked-accounts.ts +88 -0
- package/src/features/auth/hooks/use-onboarding.ts +159 -0
- package/src/features/auth/hooks/use-resend-verification.ts +139 -0
- package/src/features/auth/hooks/use-reset-password.ts +151 -0
- package/src/features/auth/hooks/use-reset-rate-limit.ts +56 -0
- package/src/features/auth/hooks/use-self-registration.ts +202 -0
- package/src/features/auth/hooks/use-session.ts +81 -0
- package/src/features/auth/hooks/use-sessions.ts +59 -0
- package/src/features/auth/hooks/use-sign-in.ts +234 -0
- package/src/features/auth/hooks/use-sign-out.ts +88 -0
- package/src/features/auth/hooks/use-sign-up.ts +194 -0
- package/src/features/auth/hooks/use-unlink-account.ts +100 -0
- package/src/features/auth/hooks/use-verify-email-token.ts +125 -0
- package/src/features/auth/index.ts +75 -0
- package/src/features/auth/screens/forgot-password-screen.tsx +33 -0
- package/src/features/auth/screens/index.ts +7 -0
- package/src/features/auth/screens/onboarding-screen.tsx +49 -0
- package/src/features/auth/screens/reset-password-screen.tsx +33 -0
- package/src/features/auth/screens/sign-in-screen.tsx +61 -0
- package/src/features/auth/screens/sign-up-screen.tsx +37 -0
- package/src/features/auth/screens/verify-email-confirm-screen.tsx +286 -0
- package/src/features/auth/screens/verify-email-screen.tsx +146 -0
- package/src/features/auth/types/index.ts +14 -0
- package/src/features/auth/utils/__tests__/validators.test.ts +331 -0
- package/src/features/auth/utils/password-strength.ts +129 -0
- package/src/features/auth/utils/validators.ts +124 -0
- package/src/features/email-preview/actions/render-email.ts +21 -0
- package/src/features/email-preview/screens/email-preview-screen.tsx +81 -0
- package/src/features/folder-scaffold-template/index.ts +0 -0
- package/src/features/instance-settings/components/index.ts +6 -0
- package/src/features/instance-settings/components/instance-settings-form.tsx +180 -0
- package/src/features/instance-settings/components/instance-status-display.tsx +158 -0
- package/src/features/instance-settings/index.ts +7 -0
- package/src/features/instance-settings/screens/index.ts +5 -0
- package/src/features/instance-settings/screens/instance-settings-screen.tsx +59 -0
- package/src/features/issues/README.md +330 -0
- package/src/features/issues/api/create-issue.ts +19 -0
- package/src/features/issues/api/delete-issue.ts +27 -0
- package/src/features/issues/api/get-issue-activities.ts +58 -0
- package/src/features/issues/api/get-issue-details.ts +25 -0
- package/src/features/issues/api/get-project-issues-server.ts +44 -0
- package/src/features/issues/api/get-project-issues.ts +21 -0
- package/src/features/issues/api/index.ts +44 -0
- package/src/features/issues/api/update-issue.ts +31 -0
- package/src/features/issues/api/upload-attachment.ts +81 -0
- package/src/features/issues/components/activity-timeline.tsx +440 -0
- package/src/features/issues/components/canvas-state-indicator.tsx +90 -0
- package/src/features/issues/components/centered-canvas-view.tsx +739 -0
- package/src/features/issues/components/image-selector.tsx +123 -0
- package/src/features/issues/components/image-upload-zone.tsx +262 -0
- package/src/features/issues/components/infinite-canvas-background.tsx +163 -0
- package/src/features/issues/components/inline-editable-select.tsx +173 -0
- package/src/features/issues/components/inline-editable-text.tsx +225 -0
- package/src/features/issues/components/inline-editable-textarea.tsx +219 -0
- package/src/features/issues/components/inline-editable-user-select.tsx +202 -0
- package/src/features/issues/components/issue-deletion-dialog.tsx +142 -0
- package/src/features/issues/components/issue-details-panel.tsx +101 -0
- package/src/features/issues/components/issues-create-dialog.tsx +578 -0
- package/src/features/issues/components/issues-list-filter.tsx +312 -0
- package/src/features/issues/components/issues-list.tsx +151 -0
- package/src/features/issues/components/issues-priority-badge.tsx +77 -0
- package/src/features/issues/components/issues-status-badge.tsx +100 -0
- package/src/features/issues/components/metadata-section.tsx +389 -0
- package/src/features/issues/components/optimized-attachment-view.tsx +528 -0
- package/src/features/issues/components/optimized-image.tsx +257 -0
- package/src/features/issues/components/panel-header.tsx +186 -0
- package/src/features/issues/components/preload.ts +31 -0
- package/src/features/issues/components/priority-selector.tsx +101 -0
- package/src/features/issues/components/responsive-issue-layout-skeleton.tsx +139 -0
- package/src/features/issues/components/responsive-issue-layout.tsx +617 -0
- package/src/features/issues/components/status-selector.tsx +320 -0
- package/src/features/issues/components/type-selector.tsx +102 -0
- package/src/features/issues/components/upload-progress-overlay.tsx +35 -0
- package/src/features/issues/components/uploaded-image-preview.tsx +173 -0
- package/src/features/issues/components/workflow-control.tsx +318 -0
- package/src/features/issues/components/zoom-controls.tsx +150 -0
- package/src/features/issues/config/index.ts +47 -0
- package/src/features/issues/config/options.ts +323 -0
- package/src/features/issues/config/workflow.ts +102 -0
- package/src/features/issues/docs/ARCHITECTURE_DIAGRAM.md +321 -0
- package/src/features/issues/docs/BACKEND_ARCHITECTURE.md +194 -0
- package/src/features/issues/docs/IMAGE_COMPONENTS_ARCHITECTURE.md +363 -0
- package/src/features/issues/docs/IMAGE_COMPONENTS_IMPORTS.md +412 -0
- package/src/features/issues/docs/IMPLEMENTATION_CHECKLIST.md +210 -0
- package/src/features/issues/docs/ROUTE_SETUP_COMPLETE.md +242 -0
- package/src/features/issues/hooks/index.ts +78 -0
- package/src/features/issues/hooks/use-canvas-transform.ts +255 -0
- package/src/features/issues/hooks/use-create-issue.ts +28 -0
- package/src/features/issues/hooks/use-elastic-scroll.ts +296 -0
- package/src/features/issues/hooks/use-issue-activities.ts +71 -0
- package/src/features/issues/hooks/use-issue-delete.ts +84 -0
- package/src/features/issues/hooks/use-issue-details.ts +70 -0
- package/src/features/issues/hooks/use-issue-filters.ts +50 -0
- package/src/features/issues/hooks/use-issue-update.ts +93 -0
- package/src/features/issues/hooks/use-keyboard-shortcuts.ts +104 -0
- package/src/features/issues/hooks/use-optimized-image.ts +228 -0
- package/src/features/issues/hooks/use-project-issues.ts +14 -0
- package/src/features/issues/index.ts +65 -0
- package/src/features/issues/screens/issue-details-screen.tsx +207 -0
- package/src/features/issues/screens/issue-details-skeletons.tsx +295 -0
- package/src/features/issues/screens/issue-share-screen.tsx +56 -0
- package/src/features/issues/types/index.ts +48 -0
- package/src/features/issues/types/issue.ts +291 -0
- package/src/features/issues/utils/filter-issues.ts +141 -0
- package/src/features/issues/utils/index.ts +14 -0
- package/src/features/legal/index.ts +1 -0
- package/src/features/legal/screens/privacy-policy-screen.tsx +307 -0
- package/src/features/notifications/api/get-notifications.ts +58 -0
- package/src/features/notifications/api/get-unread-count.ts +37 -0
- package/src/features/notifications/api/index.ts +35 -0
- package/src/features/notifications/api/mark-all-as-read.ts +37 -0
- package/src/features/notifications/api/mark-as-read.ts +41 -0
- package/src/features/notifications/api/types.ts +109 -0
- package/src/features/notifications/hooks/__tests__/use-notification-subscription.test.ts +206 -0
- package/src/features/notifications/hooks/index.ts +28 -0
- package/src/features/notifications/hooks/use-mark-all-as-read.ts +106 -0
- package/src/features/notifications/hooks/use-mark-as-read.ts +106 -0
- package/src/features/notifications/hooks/use-notification-subscription.ts +244 -0
- package/src/features/notifications/hooks/use-notification-toast.ts +161 -0
- package/src/features/notifications/hooks/use-notifications.ts +80 -0
- package/src/features/notifications/hooks/use-unread-count.ts +60 -0
- package/src/features/notifications/index.ts +48 -0
- package/src/features/notifications/utils/group-notifications.ts +152 -0
- package/src/features/notifications/utils/index.ts +9 -0
- package/src/features/projects/api/create-invitation.ts +45 -0
- package/src/features/projects/api/create-project.ts +64 -0
- package/src/features/projects/api/delete-project.ts +50 -0
- package/src/features/projects/api/get-project-activities.ts +43 -0
- package/src/features/projects/api/get-project-members.ts +53 -0
- package/src/features/projects/api/get-project.ts +49 -0
- package/src/features/projects/api/get-projects.ts +61 -0
- package/src/features/projects/api/index.ts +27 -0
- package/src/features/projects/api/join-project.ts +52 -0
- package/src/features/projects/api/leave-project.ts +51 -0
- package/src/features/projects/api/list-invitations.ts +36 -0
- package/src/features/projects/api/remove-member.ts +60 -0
- package/src/features/projects/api/resend-invitation.ts +36 -0
- package/src/features/projects/api/revoke-invitation.ts +36 -0
- package/src/features/projects/api/types.ts +286 -0
- package/src/features/projects/api/update-member-role.ts +70 -0
- package/src/features/projects/api/update-project.ts +69 -0
- package/src/features/projects/components/__tests__/project-detail-activity-feed.test.tsx +106 -0
- package/src/features/projects/components/__tests__/project-invitation-dialog.test.tsx +211 -0
- package/src/features/projects/components/__tests__/project-member-manager-dialog.test.tsx +254 -0
- package/src/features/projects/components/index.ts +21 -0
- package/src/features/projects/components/project-actions.tsx +248 -0
- package/src/features/projects/components/project-create-dialog.tsx +410 -0
- package/src/features/projects/components/project-detail-activity-feed.tsx +206 -0
- package/src/features/projects/components/project-detail-header.tsx +103 -0
- package/src/features/projects/components/project-detail-overview.tsx +128 -0
- package/src/features/projects/components/project-icon-selector.test.tsx +49 -0
- package/src/features/projects/components/project-icon-selector.tsx +76 -0
- package/src/features/projects/components/project-invitation-dialog.tsx +368 -0
- package/src/features/projects/components/project-issues.tsx +128 -0
- package/src/features/projects/components/project-leave-button.tsx +69 -0
- package/src/features/projects/components/project-list-card.tsx +246 -0
- package/src/features/projects/components/project-list-filters.tsx +320 -0
- package/src/features/projects/components/project-member-manager-dialog.tsx +419 -0
- package/src/features/projects/components/project-settings-dialog.tsx +204 -0
- package/src/features/projects/components/project-stats.tsx +46 -0
- package/src/features/projects/components/project-title-section.tsx +78 -0
- package/src/features/projects/config/icons.ts +91 -0
- package/src/features/projects/hooks/index.ts +28 -0
- package/src/features/projects/hooks/use-create-invitation.ts +83 -0
- package/src/features/projects/hooks/use-create-project.ts +77 -0
- package/src/features/projects/hooks/use-delete-project.ts +84 -0
- package/src/features/projects/hooks/use-join-project.ts +43 -0
- package/src/features/projects/hooks/use-leave-project.ts +84 -0
- package/src/features/projects/hooks/use-project-activities.ts +39 -0
- package/src/features/projects/hooks/use-project-filters.ts +86 -0
- package/src/features/projects/hooks/use-project-invitations.ts +66 -0
- package/src/features/projects/hooks/use-project-members.ts +57 -0
- package/src/features/projects/hooks/use-project.ts +67 -0
- package/src/features/projects/hooks/use-projects.ts +49 -0
- package/src/features/projects/hooks/use-recent-projects.ts +58 -0
- package/src/features/projects/hooks/use-remove-member.ts +89 -0
- package/src/features/projects/hooks/use-resend-invitation.ts +68 -0
- package/src/features/projects/hooks/use-revoke-invitation.ts +71 -0
- package/src/features/projects/hooks/use-team-member-suggestions.ts +133 -0
- package/src/features/projects/hooks/use-update-member-role.ts +92 -0
- package/src/features/projects/hooks/use-update-project.ts +88 -0
- package/src/features/projects/index.ts +91 -0
- package/src/features/projects/screens/index.ts +3 -0
- package/src/features/projects/screens/invitation-acceptance-screen.tsx +320 -0
- package/src/features/projects/screens/project-detail-screen-wrapper.tsx +47 -0
- package/src/features/projects/screens/project-detail-screen.tsx +661 -0
- package/src/features/projects/screens/projects-list-screen.tsx +161 -0
- package/src/features/projects/types/index.ts +59 -0
- package/src/features/projects/utils/format-helpers.ts +16 -0
- package/src/features/projects/utils/index.ts +2 -0
- package/src/features/projects/utils/role-helpers.ts +25 -0
- package/src/features/setup/api/complete-setup.ts +21 -0
- package/src/features/setup/api/create-admin.ts +21 -0
- package/src/features/setup/api/create-first-workspace.ts +21 -0
- package/src/features/setup/api/get-instance-status.ts +12 -0
- package/src/features/setup/api/get-service-health.ts +12 -0
- package/src/features/setup/api/index.ts +44 -0
- package/src/features/setup/api/save-instance-config.ts +21 -0
- package/src/features/setup/api/types.ts +122 -0
- package/src/features/setup/components/__tests__/setup-wizard-ui.test.tsx +362 -0
- package/src/features/setup/components/admin-account-step.tsx +205 -0
- package/src/features/setup/components/first-workspace-step.tsx +120 -0
- package/src/features/setup/components/index.ts +9 -0
- package/src/features/setup/components/instance-config-step.tsx +107 -0
- package/src/features/setup/components/mail-config-step.tsx +205 -0
- package/src/features/setup/components/sample-data-step.tsx +131 -0
- package/src/features/setup/components/service-health-step.tsx +180 -0
- package/src/features/setup/components/service-status-badge.tsx +50 -0
- package/src/features/setup/components/setup-progress.tsx +103 -0
- package/src/features/setup/components/setup-wizard.tsx +169 -0
- package/src/features/setup/hooks/index.ts +12 -0
- package/src/features/setup/hooks/use-complete-setup.ts +23 -0
- package/src/features/setup/hooks/use-create-admin.ts +25 -0
- package/src/features/setup/hooks/use-create-first-workspace.ts +24 -0
- package/src/features/setup/hooks/use-instance-status.ts +21 -0
- package/src/features/setup/hooks/use-save-instance-config.ts +23 -0
- package/src/features/setup/hooks/use-service-health.ts +21 -0
- package/src/features/setup/hooks/use-setup-wizard.ts +152 -0
- package/src/features/setup/hooks/use-workspace-mode.ts +19 -0
- package/src/features/setup/index.ts +30 -0
- package/src/features/setup/screens/index.ts +1 -0
- package/src/features/setup/screens/setup-screen.tsx +40 -0
- package/src/features/setup/types/index.ts +69 -0
- package/src/features/setup/utils/index.ts +78 -0
- package/src/features/team-settings/components/index.ts +39 -0
- package/src/features/team-settings/components/loading-states.tsx +296 -0
- package/src/features/team-settings/components/permission-guard.tsx +23 -0
- package/src/features/team-settings/components/settings-card.tsx +22 -0
- package/src/features/team-settings/components/settings-context-provider.tsx +51 -0
- package/src/features/team-settings/components/settings-error-boundary.tsx +366 -0
- package/src/features/team-settings/components/settings-navigation.tsx +87 -0
- package/src/features/team-settings/components/settings-section.tsx +23 -0
- package/src/features/team-settings/components/team-danger-zone.tsx +275 -0
- package/src/features/team-settings/components/team-information-form.tsx +116 -0
- package/src/features/team-settings/components/team-invitations-list.tsx +463 -0
- package/src/features/team-settings/components/team-members-list.tsx +342 -0
- package/src/features/team-settings/components/team-permission-guard.tsx +56 -0
- package/src/features/team-settings/components/team-setting-integrations.tsx +27 -0
- package/src/features/team-settings/components/team-setting-member.tsx +28 -0
- package/src/features/team-settings/components/team-settings-general.tsx +131 -0
- package/src/features/team-settings/components/transfer-ownership-modal.tsx +164 -0
- package/src/features/team-settings/components/unauthorized-access.tsx +52 -0
- package/src/features/team-settings/hooks/__tests__/use-team-settings.test.tsx +139 -0
- package/src/features/team-settings/hooks/index.ts +1 -0
- package/src/features/team-settings/hooks/use-team-settings.ts +148 -0
- package/src/features/team-settings/hooks/use-transfer-ownership.ts +45 -0
- package/src/features/team-settings/index.ts +25 -0
- package/src/features/team-settings/screens/index.ts +1 -0
- package/src/features/team-settings/screens/team-settings-screen.tsx +33 -0
- package/src/features/team-settings/types/index.ts +78 -0
- package/src/features/team-settings/utils/index.ts +6 -0
- package/src/features/team-settings/utils/mock-data.ts +40 -0
- package/src/features/teams/api/cancel-invitation.ts +25 -0
- package/src/features/teams/api/create-invitation.ts +28 -0
- package/src/features/teams/api/create-team.ts +14 -0
- package/src/features/teams/api/delete-team.ts +19 -0
- package/src/features/teams/api/get-invitations.ts +25 -0
- package/src/features/teams/api/get-team-members.ts +25 -0
- package/src/features/teams/api/get-team.ts +13 -0
- package/src/features/teams/api/get-teams.ts +19 -0
- package/src/features/teams/api/index.ts +49 -0
- package/src/features/teams/api/leave-team.ts +22 -0
- package/src/features/teams/api/remove-member.ts +25 -0
- package/src/features/teams/api/resend-invitation.ts +26 -0
- package/src/features/teams/api/switch-team.ts +13 -0
- package/src/features/teams/api/types.ts +122 -0
- package/src/features/teams/api/update-member-roles.ts +28 -0
- package/src/features/teams/api/update-team.ts +17 -0
- package/src/features/teams/components/create-team-dialog.tsx +105 -0
- package/src/features/teams/hooks/__tests__/cache-invalidation.property.test.tsx +268 -0
- package/src/features/teams/hooks/index.ts +35 -0
- package/src/features/teams/hooks/use-can-manage-members.ts +21 -0
- package/src/features/teams/hooks/use-can-manage-team.ts +21 -0
- package/src/features/teams/hooks/use-cancel-invitation.ts +52 -0
- package/src/features/teams/hooks/use-create-invitation.ts +59 -0
- package/src/features/teams/hooks/use-create-team.ts +38 -0
- package/src/features/teams/hooks/use-delete-team.ts +43 -0
- package/src/features/teams/hooks/use-invitations.ts +31 -0
- package/src/features/teams/hooks/use-leave-team.ts +43 -0
- package/src/features/teams/hooks/use-remove-member.ts +58 -0
- package/src/features/teams/hooks/use-resend-invitation.ts +52 -0
- package/src/features/teams/hooks/use-switch-team.ts +41 -0
- package/src/features/teams/hooks/use-team-members.ts +31 -0
- package/src/features/teams/hooks/use-team-permissions.ts +102 -0
- package/src/features/teams/hooks/use-team.ts +30 -0
- package/src/features/teams/hooks/use-teams.ts +26 -0
- package/src/features/teams/hooks/use-update-member-roles.ts +64 -0
- package/src/features/teams/hooks/use-update-team.ts +47 -0
- package/src/features/teams/index.ts +111 -0
- package/src/features/user-settings/actions/set-password.ts +63 -0
- package/src/features/user-settings/api/index.ts +16 -0
- package/src/features/user-settings/components/__tests__/security-settings.test.tsx +125 -0
- package/src/features/user-settings/components/delete-account-dialog.tsx +185 -0
- package/src/features/user-settings/components/index.ts +13 -0
- package/src/features/user-settings/components/integrations-list.tsx +152 -0
- package/src/features/user-settings/components/notification-preferences.tsx +112 -0
- package/src/features/user-settings/components/other-settings.tsx +126 -0
- package/src/features/user-settings/components/password-section.tsx +297 -0
- package/src/features/user-settings/components/security-settings.tsx +184 -0
- package/src/features/user-settings/components/user-preferences.tsx +146 -0
- package/src/features/user-settings/hooks/index.ts +8 -0
- package/src/features/user-settings/hooks/use-notification-preferences.ts +65 -0
- package/src/features/user-settings/hooks/use-user-preferences.ts +52 -0
- package/src/features/user-settings/index.ts +22 -0
- package/src/features/user-settings/screens/index.ts +11 -0
- package/src/features/user-settings/screens/integrations-screen.tsx +24 -0
- package/src/features/user-settings/screens/notifications-screen.tsx +29 -0
- package/src/features/user-settings/screens/other-settings-screen.tsx +24 -0
- package/src/features/user-settings/screens/setting-preferences-screen.tsx +24 -0
- package/src/features/user-settings/screens/user-settings-screen.tsx +23 -0
- package/src/features/user-settings/types/index.ts +42 -0
- package/src/features/user-settings/utils/index.ts +8 -0
- package/src/hooks/use-long-press.ts +196 -0
- package/src/hooks/use-media-upload.ts +95 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/hooks/use-team.ts +32 -0
- package/src/instrumentation.ts +14 -0
- package/src/lib/__tests__/auth-config.test.ts +166 -0
- package/src/lib/__tests__/config.test.ts +42 -0
- package/src/lib/__tests__/db.test.ts +101 -0
- package/src/lib/__tests__/env.property.test.ts +197 -0
- package/src/lib/__tests__/env.test.ts +177 -0
- package/src/lib/__tests__/health-check.test.ts +87 -0
- package/src/lib/__tests__/oauth-errors.test.ts +184 -0
- package/src/lib/__tests__/oauth-redirect.test.ts +224 -0
- package/src/lib/__tests__/oauth-scopes.test.ts +268 -0
- package/src/lib/__tests__/storage.test.ts +58 -0
- package/src/lib/__tests__/url-validator.test.ts +232 -0
- package/src/lib/api-client.ts +93 -0
- package/src/lib/auth-client.ts +5 -0
- package/src/lib/auth-config.ts +146 -0
- package/src/lib/auth.ts +209 -0
- package/src/lib/config.ts +228 -0
- package/src/lib/cors.ts +96 -0
- package/src/lib/date.ts +16 -0
- package/src/lib/db.ts +88 -0
- package/src/lib/env.ts +489 -0
- package/src/lib/feedback.ts +29 -0
- package/src/lib/health-check.ts +229 -0
- package/src/lib/logger.ts +204 -0
- package/src/lib/oauth-errors.ts +138 -0
- package/src/lib/performance.ts +367 -0
- package/src/lib/query-server.ts +35 -0
- package/src/lib/query.tsx +43 -0
- package/src/lib/resend.ts +36 -0
- package/src/lib/security-headers.ts +165 -0
- package/src/lib/setup-status.ts +34 -0
- package/src/lib/storage.ts +150 -0
- package/src/lib/supabase-client.ts +58 -0
- package/src/lib/testing/test-db.ts +75 -0
- package/src/lib/url-validator.ts +168 -0
- package/src/lib/utils.ts +6 -0
- package/src/mocks/README.md +42 -0
- package/src/mocks/activity.fixtures.ts +281 -0
- package/src/mocks/annotation.fixtures.ts +325 -0
- package/src/mocks/attachment.fixtures.ts +80 -0
- package/src/mocks/email.fixtures.ts +61 -0
- package/src/mocks/index.ts +33 -0
- package/src/mocks/issue.fixtures.ts +364 -0
- package/src/mocks/landing.fixtures.ts +118 -0
- package/src/mocks/notification.fixtures.ts +111 -0
- package/src/mocks/project-activity.fixtures.ts +69 -0
- package/src/mocks/project-invitation.fixtures.ts +95 -0
- package/src/mocks/project-member.fixtures.ts +93 -0
- package/src/mocks/project.fixtures.ts +249 -0
- package/src/mocks/settings.fixtures.ts +56 -0
- package/src/mocks/share.fixtures.ts +48 -0
- package/src/mocks/team-member.fixtures.ts +147 -0
- package/src/mocks/team.fixtures.ts +35 -0
- package/src/mocks/user-settings.fixtures.ts +77 -0
- package/src/mocks/user.fixtures.ts +21 -0
- package/src/providers/theme-provider.tsx +11 -0
- package/src/proxy/__tests__/proxy-setup-gate.test.ts +43 -0
- package/src/proxy.ts +169 -0
- package/src/server/annotations/__tests__/annotation-limit.property.test.ts +291 -0
- package/src/server/annotations/__tests__/attachment-deletion-cascade.property.test.ts +385 -0
- package/src/server/annotations/__tests__/comment-delete-authorization.property.test.ts +419 -0
- package/src/server/annotations/__tests__/sanitize.property.test.ts +302 -0
- package/src/server/annotations/annotation-service.ts +305 -0
- package/src/server/annotations/comment-service.ts +288 -0
- package/src/server/annotations/index.ts +61 -0
- package/src/server/annotations/permission-utils.ts +125 -0
- package/src/server/annotations/sanitize.ts +134 -0
- package/src/server/annotations/types.ts +161 -0
- package/src/server/audit/audit-service.ts +85 -0
- package/src/server/audit/index.ts +11 -0
- package/src/server/audit/types.ts +75 -0
- package/src/server/auth/__tests__/README.md +368 -0
- package/src/server/auth/__tests__/account-linking.integration.test.ts +410 -0
- package/src/server/auth/__tests__/auth-integration.test.ts +811 -0
- package/src/server/auth/__tests__/cookies.test.ts +337 -0
- package/src/server/auth/__tests__/login.property.test.ts +428 -0
- package/src/server/auth/__tests__/oauth-integration.test.ts +555 -0
- package/src/server/auth/__tests__/password.test.ts +194 -0
- package/src/server/auth/__tests__/rate-limiter.test.ts +450 -0
- package/src/server/auth/__tests__/rbac.test.ts +474 -0
- package/src/server/auth/__tests__/session.test.ts +599 -0
- package/src/server/auth/__tests__/signup.property.test.ts +224 -0
- package/src/server/auth/__tests__/token-encryption.test.ts +171 -0
- package/src/server/auth/__tests__/tokens.test.ts +476 -0
- package/src/server/auth/__tests__/verify-email.property.test.ts +372 -0
- package/src/server/auth/cookies.ts +184 -0
- package/src/server/auth/password.ts +94 -0
- package/src/server/auth/rate-limiter.ts +257 -0
- package/src/server/auth/rbac.ts +1168 -0
- package/src/server/auth/session.ts +392 -0
- package/src/server/auth/token-encryption.ts +201 -0
- package/src/server/auth/tokens.ts +397 -0
- package/src/server/db/schema/account.ts +21 -0
- package/src/server/db/schema/annotation-read-status.ts +57 -0
- package/src/server/db/schema/better-auth-verifications.ts +27 -0
- package/src/server/db/schema/email-jobs.ts +24 -0
- package/src/server/db/schema/index.ts +20 -0
- package/src/server/db/schema/instance-settings.ts +42 -0
- package/src/server/db/schema/issue-activities.ts +97 -0
- package/src/server/db/schema/issue-attachments.ts +101 -0
- package/src/server/db/schema/issues.ts +139 -0
- package/src/server/db/schema/notifications.ts +119 -0
- package/src/server/db/schema/project-activities.ts +116 -0
- package/src/server/db/schema/project-invitations.ts +34 -0
- package/src/server/db/schema/project-members.ts +29 -0
- package/src/server/db/schema/projects.ts +46 -0
- package/src/server/db/schema/sessions.ts +17 -0
- package/src/server/db/schema/team-invitations.ts +22 -0
- package/src/server/db/schema/team-members.ts +18 -0
- package/src/server/db/schema/teams.ts +15 -0
- package/src/server/db/schema/user-roles.ts +14 -0
- package/src/server/db/schema/users.ts +17 -0
- package/src/server/db/schema/verification-tokens.ts +15 -0
- package/src/server/email/README.md +258 -0
- package/src/server/email/__tests__/client.property.test.ts +218 -0
- package/src/server/email/__tests__/payload.property.test.ts +205 -0
- package/src/server/email/__tests__/queue.test.ts +407 -0
- package/src/server/email/__tests__/render-template.test.tsx +172 -0
- package/src/server/email/client.ts +70 -0
- package/src/server/email/index.ts +20 -0
- package/src/server/email/providers/console-provider.ts +43 -0
- package/src/server/email/providers/index.ts +5 -0
- package/src/server/email/providers/resend-provider.ts +59 -0
- package/src/server/email/providers/smtp-provider.ts +65 -0
- package/src/server/email/queue.ts +365 -0
- package/src/server/email/render-template.tsx +117 -0
- package/src/server/email/templates/layout.tsx +66 -0
- package/src/server/email/templates/ownership-transfer-email.tsx +75 -0
- package/src/server/email/templates/password-reset-email.tsx +72 -0
- package/src/server/email/templates/project-invitation-email.tsx +70 -0
- package/src/server/email/templates/security-alert-email.tsx +161 -0
- package/src/server/email/templates/team-invitation-email.tsx +68 -0
- package/src/server/email/templates/verification-email.tsx +61 -0
- package/src/server/email/templates/welcome-email.tsx +60 -0
- package/src/server/email/worker.ts +182 -0
- package/src/server/issues/activity-service.ts +422 -0
- package/src/server/issues/attachment-service.ts +379 -0
- package/src/server/issues/index.ts +68 -0
- package/src/server/issues/issue-service.ts +569 -0
- package/src/server/issues/types.ts +233 -0
- package/src/server/notifications/__tests__/notification-service.integration.test.ts +405 -0
- package/src/server/notifications/index.ts +13 -0
- package/src/server/notifications/notification-service.ts +526 -0
- package/src/server/notifications/types.ts +234 -0
- package/src/server/projects/__tests__/activity-logging.integration.test.ts +319 -0
- package/src/server/projects/__tests__/invitation-email.integration.test.ts +258 -0
- package/src/server/projects/__tests__/invitation-service.integration.test.ts +651 -0
- package/src/server/projects/__tests__/member-service.property.test.ts +397 -0
- package/src/server/projects/__tests__/project-service.property.test.ts +116 -0
- package/src/server/projects/activity-service.ts +548 -0
- package/src/server/projects/index.ts +11 -0
- package/src/server/projects/invitation-service.ts +773 -0
- package/src/server/projects/member-service.ts +458 -0
- package/src/server/projects/project-service.ts +491 -0
- package/src/server/projects/schemas.ts +310 -0
- package/src/server/projects/types.ts +166 -0
- package/src/server/projects/utils.ts +128 -0
- package/src/server/setup/__tests__/health-check.property.test.ts +70 -0
- package/src/server/setup/__tests__/sample-data.property.test.ts +82 -0
- package/src/server/setup/__tests__/setup.property.test.ts +95 -0
- package/src/server/setup/health-check-service.ts +294 -0
- package/src/server/setup/index.ts +35 -0
- package/src/server/setup/sample-data-service.ts +233 -0
- package/src/server/setup/setup-service.ts +229 -0
- package/src/server/setup/types.ts +96 -0
- package/src/server/teams/__tests__/export.property.test.ts +542 -0
- package/src/server/teams/__tests__/get-members.integration.test.ts +105 -0
- package/src/server/teams/__tests__/invitation-flow.integration.test.ts +402 -0
- package/src/server/teams/__tests__/invitations.property.test.ts +235 -0
- package/src/server/teams/__tests__/member-management-flow.integration.test.ts +306 -0
- package/src/server/teams/__tests__/members.property.test.ts +180 -0
- package/src/server/teams/__tests__/ownership-transfer.property.test.ts +173 -0
- package/src/server/teams/__tests__/resource-limits.property.test.ts +382 -0
- package/src/server/teams/__tests__/team-context-management.integration.test.ts +396 -0
- package/src/server/teams/__tests__/team-context.property.test.ts +854 -0
- package/src/server/teams/__tests__/team-creation-flow.integration.test.ts +310 -0
- package/src/server/teams/__tests__/team-creation.property.test.ts +280 -0
- package/src/server/teams/errors.ts +396 -0
- package/src/server/teams/export-service.ts +383 -0
- package/src/server/teams/index.ts +10 -0
- package/src/server/teams/invitation-service.ts +708 -0
- package/src/server/teams/member-service.ts +334 -0
- package/src/server/teams/resource-limits.ts +211 -0
- package/src/server/teams/slug.ts +58 -0
- package/src/server/teams/team-context.ts +648 -0
- package/src/server/teams/team-service.ts +660 -0
- package/src/server/teams/types.ts +81 -0
- package/src/server/teams/validation.ts +209 -0
- package/src/styles/globals.css +160 -0
- package/src/types/deployment.ts +39 -0
- package/supabase/config.toml +357 -0
- package/supabase/seed.sql +480 -0
- package/tests/e2e/.gitkeep +0 -0
- package/tests/e2e/QUICK_START.md +98 -0
- package/tests/e2e/README.md +301 -0
- package/tests/e2e/auth.spec.ts +583 -0
- package/tests/e2e/global-setup.ts +23 -0
- package/tests/e2e/global-teardown.ts +23 -0
- package/tests/e2e/helpers/auth-helpers.ts +310 -0
- package/tests/e2e/helpers/test-fixtures.ts +286 -0
- package/tests/e2e/smoke-test.spec.ts +330 -0
- package/tsconfig.json +48 -0
- package/vitest.config.ts +50 -0
- package/vitest.setup.ts +56 -0
- package/dist/index.js +0 -778
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* AnnotatedAttachmentView Component
|
|
5
|
+
*
|
|
6
|
+
* Wrapper component that integrates CenteredCanvasView with real annotation
|
|
7
|
+
* API endpoints. Uses useAnnotationIntegration for CRUD operations and
|
|
8
|
+
* useAnnotationPermissions for role-based UI control.
|
|
9
|
+
*
|
|
10
|
+
* Requirements: 1.1, 2.2, 8.1, 8.5
|
|
11
|
+
*
|
|
12
|
+
* @module features/annotations/components/annotated-attachment-view
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
import React, { useState, useCallback, useRef, useMemo, useEffect } from 'react';
|
|
16
|
+
import type { IssueAttachment, CanvasViewState } from '@/features/issues/types';
|
|
17
|
+
import type { AttachmentAnnotation, AnnotationPosition, AnnotationHistoryEntry, AnnotationShape, AnnotationToolId, AnnotationSaveStatus, AnnotationPermissions } from '../types';
|
|
18
|
+
import { CenteredCanvasView } from '@/features/issues/components/centered-canvas-view';
|
|
19
|
+
import { AnnotationLayer } from './annotation-layer';
|
|
20
|
+
import { AnnotationCanvas } from './annotation-canvas';
|
|
21
|
+
import { AnnotationToolbar } from './annotation-toolbar';
|
|
22
|
+
import { AnnotationCommentInput } from './annotation-comment-input';
|
|
23
|
+
import { useAnnotationIntegration } from '../hooks/use-annotation-integration';
|
|
24
|
+
import { useAnnotationPermissions } from '../hooks/use-annotation-permissions';
|
|
25
|
+
import { useAnnotationDrafts, draftToAnnotation } from '../hooks/use-annotation-drafts';
|
|
26
|
+
import { useAnnotationEditState } from '../hooks/use-annotation-edit-state';
|
|
27
|
+
import { KeyboardShortcutsModal } from './keyboard-shortcuts-modal';
|
|
28
|
+
|
|
29
|
+
// ============================================================================
|
|
30
|
+
// TYPES
|
|
31
|
+
// ============================================================================
|
|
32
|
+
|
|
33
|
+
export interface AnnotatedAttachmentViewProps {
|
|
34
|
+
/** Issue ID for API calls (not required in local mode) */
|
|
35
|
+
issueId?: string;
|
|
36
|
+
/** Attachment to display */
|
|
37
|
+
attachment: IssueAttachment;
|
|
38
|
+
/** Project ID for permission checking */
|
|
39
|
+
projectId?: string;
|
|
40
|
+
/** Team ID for permission checking */
|
|
41
|
+
teamId?: string;
|
|
42
|
+
/** Canvas state from parent (for sync with compare mode) */
|
|
43
|
+
canvasState?: CanvasViewState;
|
|
44
|
+
/** Callback when canvas state changes */
|
|
45
|
+
onCanvasStateChange?: (updates: Partial<CanvasViewState>) => void;
|
|
46
|
+
/** Whether the attachment viewer is in interactive annotation mode */
|
|
47
|
+
interactive?: boolean;
|
|
48
|
+
/** Currently active annotation ID */
|
|
49
|
+
activeAnnotationId?: string | null;
|
|
50
|
+
/** Callback when annotation selection changes */
|
|
51
|
+
onAnnotationSelect?: (annotationId: string | null) => void;
|
|
52
|
+
/** Optional permissions override (skips internal check) */
|
|
53
|
+
permissions?: Partial<AnnotationPermissions>;
|
|
54
|
+
/** External annotations override (for API mode) */
|
|
55
|
+
annotations?: AttachmentAnnotation[];
|
|
56
|
+
|
|
57
|
+
// ============================================================================
|
|
58
|
+
// LOCAL MODE PROPS (for draft/preview without API persistence)
|
|
59
|
+
// ============================================================================
|
|
60
|
+
|
|
61
|
+
/** Enable local mode - bypasses API fetch/save, uses local state */
|
|
62
|
+
localMode?: boolean;
|
|
63
|
+
/** Local annotations (controlled state) */
|
|
64
|
+
localAnnotations?: AttachmentAnnotation[];
|
|
65
|
+
/** Callback when local annotations change */
|
|
66
|
+
onLocalAnnotationsChange?: (annotations: AttachmentAnnotation[]) => void;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// ============================================================================
|
|
70
|
+
// DEFAULT CANVAS STATE
|
|
71
|
+
// ============================================================================
|
|
72
|
+
|
|
73
|
+
const DEFAULT_CANVAS_STATE: CanvasViewState = {
|
|
74
|
+
zoom: 1,
|
|
75
|
+
panX: 0,
|
|
76
|
+
panY: 0,
|
|
77
|
+
fitMode: 'fit',
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
// ============================================================================
|
|
81
|
+
// COMPONENT
|
|
82
|
+
// ============================================================================
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* AnnotatedAttachmentView combines CenteredCanvasView with annotation
|
|
86
|
+
* capabilities, wired to real API endpoints.
|
|
87
|
+
*
|
|
88
|
+
* Features:
|
|
89
|
+
* - Full CRUD operations via useAnnotationIntegration
|
|
90
|
+
* - Permission-aware toolbar showing/hiding
|
|
91
|
+
* - Optimistic updates with rollback
|
|
92
|
+
* - Draft annotation creation with comment input
|
|
93
|
+
* - Edit popover for updating annotation descriptions
|
|
94
|
+
*/
|
|
95
|
+
export function AnnotatedAttachmentView({
|
|
96
|
+
issueId,
|
|
97
|
+
attachment,
|
|
98
|
+
projectId,
|
|
99
|
+
teamId,
|
|
100
|
+
canvasState: externalCanvasState,
|
|
101
|
+
onCanvasStateChange: externalOnCanvasStateChange,
|
|
102
|
+
interactive = true,
|
|
103
|
+
activeAnnotationId: externalActiveAnnotationId,
|
|
104
|
+
onAnnotationSelect: externalOnAnnotationSelect,
|
|
105
|
+
permissions: propPermissions,
|
|
106
|
+
annotations: propAnnotations,
|
|
107
|
+
// Local mode props
|
|
108
|
+
localMode = false,
|
|
109
|
+
localAnnotations = [],
|
|
110
|
+
onLocalAnnotationsChange,
|
|
111
|
+
}: AnnotatedAttachmentViewProps) {
|
|
112
|
+
// ============================================================================
|
|
113
|
+
// STATE
|
|
114
|
+
// ============================================================================
|
|
115
|
+
|
|
116
|
+
// Internal canvas state (used when not controlled by parent)
|
|
117
|
+
const [internalCanvasState, setInternalCanvasState] = useState<CanvasViewState>(DEFAULT_CANVAS_STATE);
|
|
118
|
+
const canvasState = externalCanvasState ?? internalCanvasState;
|
|
119
|
+
const handleCanvasStateChange = useCallback(
|
|
120
|
+
(updates: Partial<CanvasViewState>) => {
|
|
121
|
+
if (externalOnCanvasStateChange) {
|
|
122
|
+
externalOnCanvasStateChange(updates);
|
|
123
|
+
} else {
|
|
124
|
+
setInternalCanvasState((prev) => ({ ...prev, ...updates }));
|
|
125
|
+
}
|
|
126
|
+
},
|
|
127
|
+
[externalOnCanvasStateChange]
|
|
128
|
+
);
|
|
129
|
+
|
|
130
|
+
// Internal active annotation (used when not controlled by parent)
|
|
131
|
+
const [internalActiveAnnotationId, setInternalActiveAnnotationId] = useState<string | null>(null);
|
|
132
|
+
const activeAnnotationId = externalActiveAnnotationId ?? internalActiveAnnotationId;
|
|
133
|
+
const handleAnnotationSelect = useCallback(
|
|
134
|
+
(annotationId: string | null) => {
|
|
135
|
+
if (externalOnAnnotationSelect) {
|
|
136
|
+
externalOnAnnotationSelect(annotationId);
|
|
137
|
+
} else {
|
|
138
|
+
setInternalActiveAnnotationId(annotationId);
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
[externalOnAnnotationSelect]
|
|
142
|
+
);
|
|
143
|
+
|
|
144
|
+
// Refs for overlay positioning
|
|
145
|
+
const annotationOverlayRef = useRef<HTMLDivElement | null>(null);
|
|
146
|
+
const annotationSurfaceRef = useRef<HTMLDivElement | null>(null);
|
|
147
|
+
|
|
148
|
+
// ============================================================================
|
|
149
|
+
// PERMISSIONS
|
|
150
|
+
// ============================================================================
|
|
151
|
+
|
|
152
|
+
const { permissions: hookPermissions, isLoading: permissionsLoading, userId } = useAnnotationPermissions({
|
|
153
|
+
projectId,
|
|
154
|
+
teamId,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
const permissions = useMemo(() => ({
|
|
158
|
+
...hookPermissions,
|
|
159
|
+
...propPermissions,
|
|
160
|
+
}), [hookPermissions, propPermissions]);
|
|
161
|
+
|
|
162
|
+
// ============================================================================
|
|
163
|
+
// ANNOTATION INTEGRATION (skipped in local mode)
|
|
164
|
+
// ============================================================================
|
|
165
|
+
|
|
166
|
+
const {
|
|
167
|
+
annotations: apiAnnotations,
|
|
168
|
+
isLoading: annotationsLoading,
|
|
169
|
+
isSaving,
|
|
170
|
+
activeTool: apiActiveTool,
|
|
171
|
+
editModeEnabled: apiEditModeEnabled,
|
|
172
|
+
canUndo: apiCanUndo,
|
|
173
|
+
canRedo: apiCanRedo,
|
|
174
|
+
handToolActive: apiHandToolActive,
|
|
175
|
+
showShortcutsHelp: apiShowShortcutsHelp,
|
|
176
|
+
createAnnotation: apiCreateAnnotation,
|
|
177
|
+
handleAnnotationMove: apiHandleAnnotationMove,
|
|
178
|
+
handleBoxAnnotationMove: apiHandleBoxAnnotationMove,
|
|
179
|
+
deleteAnnotation: apiDeleteAnnotation,
|
|
180
|
+
selectTool: apiSelectTool,
|
|
181
|
+
toggleEditMode: apiToggleEditMode,
|
|
182
|
+
undo: apiUndo,
|
|
183
|
+
redo: apiRedo,
|
|
184
|
+
setShowShortcutsHelp: apiSetShowShortcutsHelp,
|
|
185
|
+
setDragging: apiSetDragging,
|
|
186
|
+
refetch,
|
|
187
|
+
} = useAnnotationIntegration({
|
|
188
|
+
issueId: issueId || '',
|
|
189
|
+
attachmentId: attachment.id,
|
|
190
|
+
enabled: !localMode && interactive && permissions.canView && !!issueId,
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
// ============================================================================
|
|
194
|
+
// LOCAL MODE STATE (when localMode is true)
|
|
195
|
+
// ============================================================================
|
|
196
|
+
|
|
197
|
+
const [localActiveTool, setLocalActiveTool] = useState<AnnotationToolId>('cursor');
|
|
198
|
+
const [localEditModeEnabled, setLocalEditModeEnabled] = useState(false);
|
|
199
|
+
const [localHistory, setLocalHistory] = useState<{ past: AttachmentAnnotation[][]; future: AttachmentAnnotation[][] }>({ past: [], future: [] });
|
|
200
|
+
const [localShowShortcutsHelp, setLocalShowShortcutsHelp] = useState(false);
|
|
201
|
+
|
|
202
|
+
// Local mode tool selection
|
|
203
|
+
const selectTool = localMode ? setLocalActiveTool : apiSelectTool;
|
|
204
|
+
const activeTool = localMode ? localActiveTool : apiActiveTool;
|
|
205
|
+
const editModeEnabled = localMode ? localEditModeEnabled : apiEditModeEnabled;
|
|
206
|
+
const toggleEditMode = localMode ? () => setLocalEditModeEnabled(prev => !prev) : apiToggleEditMode;
|
|
207
|
+
const handToolActive = localMode ? (localActiveTool === 'cursor' && !localEditModeEnabled) : apiHandToolActive;
|
|
208
|
+
const showShortcutsHelp = localMode ? localShowShortcutsHelp : apiShowShortcutsHelp;
|
|
209
|
+
const setShowShortcutsHelp = localMode ? setLocalShowShortcutsHelp : apiSetShowShortcutsHelp;
|
|
210
|
+
|
|
211
|
+
// Local mode undo/redo
|
|
212
|
+
const canUndo = localMode ? localHistory.past.length > 0 : apiCanUndo;
|
|
213
|
+
const canRedo = localMode ? localHistory.future.length > 0 : apiCanRedo;
|
|
214
|
+
|
|
215
|
+
const localUndo = useCallback(() => {
|
|
216
|
+
if (localHistory.past.length === 0 || !onLocalAnnotationsChange) return;
|
|
217
|
+
const prev = localHistory.past[localHistory.past.length - 1];
|
|
218
|
+
setLocalHistory(h => ({
|
|
219
|
+
past: h.past.slice(0, -1),
|
|
220
|
+
future: [localAnnotations, ...h.future],
|
|
221
|
+
}));
|
|
222
|
+
onLocalAnnotationsChange(prev);
|
|
223
|
+
}, [localHistory, localAnnotations, onLocalAnnotationsChange]);
|
|
224
|
+
|
|
225
|
+
const localRedo = useCallback(() => {
|
|
226
|
+
if (localHistory.future.length === 0 || !onLocalAnnotationsChange) return;
|
|
227
|
+
const next = localHistory.future[0];
|
|
228
|
+
setLocalHistory(h => ({
|
|
229
|
+
past: [...h.past, localAnnotations],
|
|
230
|
+
future: h.future.slice(1),
|
|
231
|
+
}));
|
|
232
|
+
onLocalAnnotationsChange(next);
|
|
233
|
+
}, [localHistory, localAnnotations, onLocalAnnotationsChange]);
|
|
234
|
+
|
|
235
|
+
const undo = localMode ? localUndo : apiUndo;
|
|
236
|
+
const redo = localMode ? localRedo : apiRedo;
|
|
237
|
+
|
|
238
|
+
// Local annotation helpers
|
|
239
|
+
const pushLocalHistory = useCallback(() => {
|
|
240
|
+
if (!onLocalAnnotationsChange) return;
|
|
241
|
+
setLocalHistory(h => ({
|
|
242
|
+
past: [...h.past.slice(-19), localAnnotations],
|
|
243
|
+
future: [],
|
|
244
|
+
}));
|
|
245
|
+
}, [localAnnotations, onLocalAnnotationsChange]);
|
|
246
|
+
|
|
247
|
+
// Local mode annotation operations
|
|
248
|
+
const localCreateAnnotation = useCallback((shape: AnnotationShape, message?: string) => {
|
|
249
|
+
if (!onLocalAnnotationsChange) return;
|
|
250
|
+
pushLocalHistory();
|
|
251
|
+
const nextLabel = String(localAnnotations.length + 1);
|
|
252
|
+
const newAnnotation: AttachmentAnnotation = {
|
|
253
|
+
id: `draft_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`,
|
|
254
|
+
attachmentId: attachment.id,
|
|
255
|
+
label: nextLabel,
|
|
256
|
+
description: message || '',
|
|
257
|
+
x: shape.type === 'pin' ? shape.position.x : (shape.start.x + shape.end.x) / 2,
|
|
258
|
+
y: shape.type === 'pin' ? shape.position.y : (shape.start.y + shape.end.y) / 2,
|
|
259
|
+
author: { id: 'current_user', name: 'You', email: '' },
|
|
260
|
+
createdAt: new Date().toISOString(),
|
|
261
|
+
shape,
|
|
262
|
+
comments: message ? [{
|
|
263
|
+
id: `comment_${Date.now()}`,
|
|
264
|
+
annotationId: '',
|
|
265
|
+
message,
|
|
266
|
+
author: { id: 'current_user', name: 'You', email: '' },
|
|
267
|
+
createdAt: new Date().toISOString(),
|
|
268
|
+
}] : [],
|
|
269
|
+
};
|
|
270
|
+
onLocalAnnotationsChange([...localAnnotations, newAnnotation]);
|
|
271
|
+
}, [localAnnotations, onLocalAnnotationsChange, pushLocalHistory, attachment.id]);
|
|
272
|
+
|
|
273
|
+
const localHandleAnnotationMove = useCallback((annotationId: string, coords: { x: number; y: number }) => {
|
|
274
|
+
if (!onLocalAnnotationsChange) return;
|
|
275
|
+
pushLocalHistory();
|
|
276
|
+
const updated = localAnnotations.map(a =>
|
|
277
|
+
a.id === annotationId
|
|
278
|
+
? { ...a, x: coords.x, y: coords.y, shape: { type: 'pin' as const, position: coords } }
|
|
279
|
+
: a
|
|
280
|
+
);
|
|
281
|
+
onLocalAnnotationsChange(updated);
|
|
282
|
+
}, [localAnnotations, onLocalAnnotationsChange, pushLocalHistory]);
|
|
283
|
+
|
|
284
|
+
const localHandleBoxAnnotationMove = useCallback((annotationId: string, start: { x: number; y: number }, end: { x: number; y: number }) => {
|
|
285
|
+
if (!onLocalAnnotationsChange) return;
|
|
286
|
+
pushLocalHistory();
|
|
287
|
+
const updated = localAnnotations.map(a =>
|
|
288
|
+
a.id === annotationId
|
|
289
|
+
? { ...a, shape: { type: 'box' as const, start, end }, x: (start.x + end.x) / 2, y: (start.y + end.y) / 2 }
|
|
290
|
+
: a
|
|
291
|
+
);
|
|
292
|
+
onLocalAnnotationsChange(updated);
|
|
293
|
+
}, [localAnnotations, onLocalAnnotationsChange, pushLocalHistory]);
|
|
294
|
+
|
|
295
|
+
const localDeleteAnnotation = useCallback((annotationId: string) => {
|
|
296
|
+
if (!onLocalAnnotationsChange) return;
|
|
297
|
+
pushLocalHistory();
|
|
298
|
+
const filtered = localAnnotations.filter(a => a.id !== annotationId);
|
|
299
|
+
// Re-sequence labels
|
|
300
|
+
const resequenced = filtered.map((a, i) => ({ ...a, label: String(i + 1) }));
|
|
301
|
+
onLocalAnnotationsChange(resequenced);
|
|
302
|
+
}, [localAnnotations, onLocalAnnotationsChange, pushLocalHistory]);
|
|
303
|
+
|
|
304
|
+
// Choose API or local handlers
|
|
305
|
+
const createAnnotation = localMode ? localCreateAnnotation : apiCreateAnnotation;
|
|
306
|
+
const handleAnnotationMove = localMode ? localHandleAnnotationMove : apiHandleAnnotationMove;
|
|
307
|
+
const handleBoxAnnotationMove = localMode ? localHandleBoxAnnotationMove : apiHandleBoxAnnotationMove;
|
|
308
|
+
const deleteAnnotation = localMode ? localDeleteAnnotation : apiDeleteAnnotation;
|
|
309
|
+
const setDragging = localMode ? () => {} : apiSetDragging;
|
|
310
|
+
|
|
311
|
+
// Choose annotation source
|
|
312
|
+
const annotationsToUse = localMode ? localAnnotations : (propAnnotations || apiAnnotations);
|
|
313
|
+
|
|
314
|
+
// Filter annotations for current attachment
|
|
315
|
+
const currentAnnotations = useMemo(
|
|
316
|
+
() => annotationsToUse.filter((ann) => ann.attachmentId === attachment.id),
|
|
317
|
+
[annotationsToUse, attachment.id]
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
|
|
321
|
+
|
|
322
|
+
// ============================================================================
|
|
323
|
+
// EDIT STATE
|
|
324
|
+
// ============================================================================
|
|
325
|
+
|
|
326
|
+
const { editState, openEdit, closeEdit, submitEdit } = useAnnotationEditState();
|
|
327
|
+
|
|
328
|
+
const handleAnnotationEdit = useCallback(
|
|
329
|
+
(annotationId: string) => {
|
|
330
|
+
openEdit(annotationId, currentAnnotations, annotationOverlayRef);
|
|
331
|
+
},
|
|
332
|
+
[openEdit, currentAnnotations]
|
|
333
|
+
);
|
|
334
|
+
|
|
335
|
+
const handleEditSubmit = useCallback(
|
|
336
|
+
async (newDescription: string) => {
|
|
337
|
+
if (!editState.editingAnnotation) return;
|
|
338
|
+
// Update via API - need to update the annotation description
|
|
339
|
+
// For now, close the edit dialog (the real update is handled by submitEdit)
|
|
340
|
+
submitEdit(newDescription, async (annotationId, updates) => {
|
|
341
|
+
// Find annotation and update via integration hook
|
|
342
|
+
const annotation = currentAnnotations.find((a) => a.id === annotationId);
|
|
343
|
+
if (annotation?.shape) {
|
|
344
|
+
// Re-create annotation with updated description using the update mutation
|
|
345
|
+
// Note: useAnnotationIntegration doesn't expose updateAnnotation directly,
|
|
346
|
+
// so we'll need to add it or call the API directly
|
|
347
|
+
console.log('Updated annotation description:', annotationId, updates.description);
|
|
348
|
+
}
|
|
349
|
+
});
|
|
350
|
+
},
|
|
351
|
+
[editState.editingAnnotation, submitEdit, currentAnnotations]
|
|
352
|
+
);
|
|
353
|
+
|
|
354
|
+
// ============================================================================
|
|
355
|
+
// DRAFT CREATION
|
|
356
|
+
// ============================================================================
|
|
357
|
+
|
|
358
|
+
const { createDraft, updateDraft, commitDraft, cancelDraft } = useAnnotationDrafts({
|
|
359
|
+
onCommit: async (draft, message) => {
|
|
360
|
+
// Generate label based on current count
|
|
361
|
+
const nextLabel = String(currentAnnotations.length + 1);
|
|
362
|
+
console.info('📝 Creating annotation:', { draft, message, label: nextLabel });
|
|
363
|
+
|
|
364
|
+
// Create via integration hook
|
|
365
|
+
await createAnnotation(draft.shape, message || undefined);
|
|
366
|
+
},
|
|
367
|
+
});
|
|
368
|
+
|
|
369
|
+
// ============================================================================
|
|
370
|
+
// ANNOTATION DELETE HANDLER
|
|
371
|
+
// ============================================================================
|
|
372
|
+
|
|
373
|
+
const handleAnnotationDelete = useCallback(
|
|
374
|
+
async (annotationId: string) => {
|
|
375
|
+
// Check permissions
|
|
376
|
+
const annotation = currentAnnotations.find((a) => a.id === annotationId);
|
|
377
|
+
if (!annotation) return;
|
|
378
|
+
|
|
379
|
+
const isOwner = annotation.author?.id === userId;
|
|
380
|
+
if (!permissions.canDeleteAll && !(permissions.canDelete && isOwner)) {
|
|
381
|
+
console.warn('No permission to delete annotation');
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
await deleteAnnotation(annotationId);
|
|
386
|
+
|
|
387
|
+
// Clear active if deleted
|
|
388
|
+
if (activeAnnotationId === annotationId) {
|
|
389
|
+
handleAnnotationSelect(null);
|
|
390
|
+
}
|
|
391
|
+
},
|
|
392
|
+
[currentAnnotations, userId, permissions, deleteAnnotation, activeAnnotationId, handleAnnotationSelect]
|
|
393
|
+
);
|
|
394
|
+
|
|
395
|
+
// ============================================================================
|
|
396
|
+
// CLICK OUTSIDE HANDLER
|
|
397
|
+
// ============================================================================
|
|
398
|
+
|
|
399
|
+
useEffect(() => {
|
|
400
|
+
if (!interactive || activeTool !== 'cursor' || !activeAnnotationId) {
|
|
401
|
+
return;
|
|
402
|
+
}
|
|
403
|
+
|
|
404
|
+
const interactionNode = annotationSurfaceRef.current;
|
|
405
|
+
if (!interactionNode) return;
|
|
406
|
+
|
|
407
|
+
const handleBackgroundPointerDown = (event: PointerEvent) => {
|
|
408
|
+
const target = event.target;
|
|
409
|
+
if (!(target instanceof Node) || !interactionNode.contains(target)) {
|
|
410
|
+
return;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
if (target instanceof HTMLElement) {
|
|
414
|
+
if (
|
|
415
|
+
target.closest('[data-annotation-pin]') ||
|
|
416
|
+
target.closest('[data-annotation-box]') ||
|
|
417
|
+
target.closest('[data-annotation-comment-input]')
|
|
418
|
+
) {
|
|
419
|
+
return;
|
|
420
|
+
}
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
handleAnnotationSelect(null);
|
|
424
|
+
};
|
|
425
|
+
|
|
426
|
+
interactionNode.addEventListener('pointerdown', handleBackgroundPointerDown);
|
|
427
|
+
return () => {
|
|
428
|
+
interactionNode.removeEventListener('pointerdown', handleBackgroundPointerDown);
|
|
429
|
+
};
|
|
430
|
+
}, [interactive, activeTool, activeAnnotationId, handleAnnotationSelect]);
|
|
431
|
+
|
|
432
|
+
// ============================================================================
|
|
433
|
+
// COMPUTED STATE
|
|
434
|
+
// ============================================================================
|
|
435
|
+
|
|
436
|
+
const isAnnotationInteractive = interactive && editModeEnabled && permissions.canCreate;
|
|
437
|
+
const pointerPanEnabled = !interactive || !editModeEnabled || handToolActive;
|
|
438
|
+
const showToolbar = interactive && permissions.canCreate;
|
|
439
|
+
|
|
440
|
+
// Save status for indicator
|
|
441
|
+
const saveStatus: AnnotationSaveStatus = isSaving ? 'saving' : 'idle';
|
|
442
|
+
|
|
443
|
+
// ============================================================================
|
|
444
|
+
// TOOLBAR TOOLS
|
|
445
|
+
// ============================================================================
|
|
446
|
+
|
|
447
|
+
const toolbarTools = useMemo((): readonly AnnotationToolId[] => {
|
|
448
|
+
const allTools: readonly AnnotationToolId[] = ['cursor', 'pin', 'box'] as const;
|
|
449
|
+
|
|
450
|
+
// Filter based on permissions
|
|
451
|
+
if (!permissions.canCreate) {
|
|
452
|
+
return ['cursor'] as const; // Only cursor for view-only
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
return allTools;
|
|
456
|
+
}, [permissions.canCreate]);
|
|
457
|
+
|
|
458
|
+
// ============================================================================
|
|
459
|
+
// RENDER
|
|
460
|
+
// ============================================================================
|
|
461
|
+
|
|
462
|
+
// Don't render annotations for non-image attachments
|
|
463
|
+
if (!attachment.fileType.startsWith('image/')) {
|
|
464
|
+
return (
|
|
465
|
+
<CenteredCanvasView
|
|
466
|
+
attachment={attachment}
|
|
467
|
+
canvasState={canvasState}
|
|
468
|
+
onCanvasStateChange={handleCanvasStateChange}
|
|
469
|
+
/>
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
|
|
473
|
+
// Loading state (skip in local mode)
|
|
474
|
+
if (!localMode && (annotationsLoading || permissionsLoading)) {
|
|
475
|
+
return (
|
|
476
|
+
<div className="h-full flex items-center justify-center">
|
|
477
|
+
<div className="animate-spin rounded-full h-6 w-6 border-2 border-primary border-t-transparent" />
|
|
478
|
+
</div>
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
// Overlay content with annotation layer and canvas
|
|
483
|
+
const overlayContent =
|
|
484
|
+
currentAnnotations.length > 0 || isAnnotationInteractive ? (
|
|
485
|
+
<>
|
|
486
|
+
{currentAnnotations.length > 0 && (
|
|
487
|
+
<AnnotationLayer
|
|
488
|
+
annotations={currentAnnotations}
|
|
489
|
+
overlayRef={annotationOverlayRef}
|
|
490
|
+
activeAnnotationId={activeAnnotationId}
|
|
491
|
+
interactive={isAnnotationInteractive}
|
|
492
|
+
handToolActive={handToolActive}
|
|
493
|
+
onSelect={handleAnnotationSelect}
|
|
494
|
+
onMoveComplete={handleAnnotationMove}
|
|
495
|
+
onBoxMoveComplete={handleBoxAnnotationMove}
|
|
496
|
+
onDragStart={(annotationId) => setDragging(annotationId, true)}
|
|
497
|
+
onDragEnd={(annotationId) => setDragging(annotationId, false)}
|
|
498
|
+
onEdit={handleAnnotationEdit}
|
|
499
|
+
onDelete={handleAnnotationDelete}
|
|
500
|
+
issueId={issueId}
|
|
501
|
+
attachmentId={attachment.id}
|
|
502
|
+
enablePopover={!editModeEnabled}
|
|
503
|
+
/>
|
|
504
|
+
)}
|
|
505
|
+
{isAnnotationInteractive && (
|
|
506
|
+
<AnnotationCanvas
|
|
507
|
+
overlayRef={annotationOverlayRef}
|
|
508
|
+
activeTool={activeTool}
|
|
509
|
+
editModeEnabled={editModeEnabled}
|
|
510
|
+
handToolActive={handToolActive}
|
|
511
|
+
onDraftCreate={createDraft}
|
|
512
|
+
onDraftUpdate={updateDraft}
|
|
513
|
+
onDraftCommit={commitDraft}
|
|
514
|
+
onDraftCancel={cancelDraft}
|
|
515
|
+
requireCommentForPin={true}
|
|
516
|
+
requireCommentForBox={true}
|
|
517
|
+
/>
|
|
518
|
+
)}
|
|
519
|
+
{/* Edit Annotation Popover */}
|
|
520
|
+
{editState.showEditDialog && editState.editingAnnotation && editState.editPopoverPosition && (
|
|
521
|
+
<AnnotationCommentInput
|
|
522
|
+
position={editState.editPopoverPosition}
|
|
523
|
+
defaultValue={editState.editingAnnotation.description}
|
|
524
|
+
title={`Edit Annotation ${editState.editingAnnotation.label}`}
|
|
525
|
+
placeholder="Update annotation description..."
|
|
526
|
+
onSubmit={handleEditSubmit}
|
|
527
|
+
onCancel={closeEdit}
|
|
528
|
+
autoFocus
|
|
529
|
+
/>
|
|
530
|
+
)}
|
|
531
|
+
</>
|
|
532
|
+
) : null;
|
|
533
|
+
|
|
534
|
+
return (
|
|
535
|
+
<div className="relative h-full w-full">
|
|
536
|
+
{/* Annotation toolbar */}
|
|
537
|
+
{showToolbar && (
|
|
538
|
+
<div className="pointer-events-none absolute inset-x-0 bottom-6 z-20 flex flex-col items-start gap-3 px-4">
|
|
539
|
+
<AnnotationToolbar
|
|
540
|
+
className="pointer-events-auto"
|
|
541
|
+
activeTool={activeTool}
|
|
542
|
+
tools={toolbarTools}
|
|
543
|
+
editModeEnabled={editModeEnabled}
|
|
544
|
+
canUndo={canUndo}
|
|
545
|
+
canRedo={canRedo}
|
|
546
|
+
onToolChange={selectTool}
|
|
547
|
+
onToggleEditMode={toggleEditMode}
|
|
548
|
+
onUndo={undo}
|
|
549
|
+
onRedo={redo}
|
|
550
|
+
/>
|
|
551
|
+
</div>
|
|
552
|
+
)}
|
|
553
|
+
|
|
554
|
+
{/* Canvas with annotations */}
|
|
555
|
+
<CenteredCanvasView
|
|
556
|
+
attachment={attachment}
|
|
557
|
+
canvasState={canvasState}
|
|
558
|
+
onCanvasStateChange={handleCanvasStateChange}
|
|
559
|
+
overlayRef={annotationOverlayRef}
|
|
560
|
+
interactionLayerRef={annotationSurfaceRef}
|
|
561
|
+
overlayContent={overlayContent}
|
|
562
|
+
pointerPanEnabled={pointerPanEnabled}
|
|
563
|
+
scrollPanEnabled={true}
|
|
564
|
+
saveStatus={saveStatus}
|
|
565
|
+
/>
|
|
566
|
+
|
|
567
|
+
{/* Keyboard shortcuts help modal */}
|
|
568
|
+
<KeyboardShortcutsModal
|
|
569
|
+
open={showShortcutsHelp}
|
|
570
|
+
onOpenChange={setShowShortcutsHelp}
|
|
571
|
+
/>
|
|
572
|
+
</div>
|
|
573
|
+
);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
export default AnnotatedAttachmentView;
|