.github/9
ISSUE_TEMPLATE/3bug_report.md config.yml feature_request.md
workflows/3ci.yml clean-clone.yml release.yml
CODEOWNERS dependabot.yml pull_request_template.md
apps/630
api/250
src/243
common/30
__tests__/3authorize.test.ts bigint-serialization.interceptor.test.ts files-limits.test.ts
filters/1all-exceptions.filter.ts
guards/3auth.guard.ts internal-service.guard.ts rate-limit.guard.ts
interceptors/2actor-context.interceptor.ts bigint-serialization.interceptor.ts
middleware/2idempotency.test.ts idempotency.ts
pipes/1zod-validation.pipe.ts
actor-context.ts audit.service.ts cache.test.ts cache.ts cookies.ts core.module.ts deprecation.ts email.service.ts errors.ts event-bus.ts log-scrubber.test.ts log-scrubber.ts logger.ts permission-cache-bridge.ts prisma.service.ts redis.service.ts trace-metadata.ts types.ts
config/1env.ts
lib/11
__tests__/5crypto.test.ts filter-builder.test.ts jwt.test.ts pagination.test.ts positions.test.ts
authorize.ts crypto.ts filter-builder.ts jwt.ts pagination.ts positions.ts
modules/197
ai/28
__tests__/4ai-writing.test.ts database-ai.test.ts generate-executor.test.ts prompts.test.ts
generator/4executor.ts generate.controller.ts generate.dto.ts generate.service.ts
ai-chat.service.ts ai-rate-limit.ts ai-writing.controller.ts ai-writing.dto.ts ai-writing.service.ts ai.controller.ts ai.module.ts ai.service.ts budget-guard.service.ts database-ai.controller.ts database-ai.dto.ts database-ai.service.ts db-prompts.ts dto.ts gateway-provider.ts ledger.service.ts prompts.ts rag.controller.ts rag.dto.ts rag.service.ts
api-keys/3api-keys.controller.ts api-keys.module.ts api-keys.service.ts
audit/2audit-log.controller.ts audit.module.ts
auth/4auth.controller.ts auth.module.ts auth.service.ts dto.ts
automations/5automations.controller.ts automations.module.ts automations.service.ts dto.ts webhook-incoming.controller.ts
blocks/5
__tests__/1batch-version-cas.test.ts
block.service.ts blocks.controller.ts blocks.module.ts dto.ts
comments/4comments.controller.ts comments.module.ts comments.service.ts dto.ts
databases/9
__tests__/3normalize-select-options.test.ts option-id-canonicalization.test.ts record-open-query-shape.test.ts
database.service.ts databases.controller.ts databases.module.ts dto.ts property-cache-schema.ts query.service.ts
docs/2docs.controller.ts docs.module.ts
files/10
__tests__/1quota.test.ts
dto.ts files.controller.ts files.module.ts files.service.ts quota.ts record.ts s3.ts uploads.controller.ts uploads.service.ts
forms/18debug.controller.ts form.dto.ts forms.controller.ts forms.module.ts forms.service.ts markdown.test.ts markdown.ts optional-auth.guard.ts public-forms.controller.ts public-forms.service.ts question.dto.ts questions.service.ts rate-limit.ts recaptcha.ts slug.ts submissions.controller.ts submissions.service.ts submit-schema.ts
health/3health.controller.ts health.module.ts health.service.ts
integrations/3integrations.controller.ts integrations.module.ts integrations.service.ts
internal/12
__tests__/2flush-query-shape.test.ts internal.endpoints.test.ts
ai-test-seam.controller.ts ai-test-seam.dto.ts ai-test-seam.service.ts internal.controller.ts internal.dto.ts internal.module.ts internal.service.ts test-seam.controller.ts test-seam.dto.ts test-seam.service.ts
notifications/3notifications.controller.ts notifications.module.ts notifications.service.ts
oauth/6
__tests__/1oauth.scopes.test.ts
oauth.controller.ts oauth.module.ts oauth.service.ts scopes.ts token-keys.ts
org/15audit.service.ts embed-preview.controller.ts guards.ts members.service.ts org-admin.controller.ts org-policy.service.ts org.module.ts overview.service.ts policy-effective.controller.ts policy.schema.ts policy.test.ts retention.service.ts totp.test.ts totp.ts two-factor.service.ts
orgs/5dto.ts orgs.controller.ts orgs.module.ts orgs.service.ts util.ts
pages/4dto.ts page.service.ts pages.controller.ts pages.module.ts
scim/15
__tests__/3email-mapping.test.ts etag.test.ts filters.test.ts
etag.ts filters.ts groups.service.ts schemas.ts scim-admin.controller.ts scim-admin.service.ts scim-auth.guard.ts scim-auth.service.ts scim-errors.ts scim.controller.ts scim.module.ts users.service.ts
search/4
__tests__/1search.service.test.ts
search.controller.ts search.module.ts search.service.ts
sessions/3sessions.controller.ts sessions.module.ts sessions.service.ts
share/3share.controller.ts share.module.ts share.service.ts
sso/16
__tests__/4enforcement.test.ts oidc.verify.test.ts provisioning.test.ts saml.validate.test.ts
enforcement.ts oidc.controller.ts oidc.service.ts oidc.ts provisioning.service.ts saml.controller.ts saml.ts schemas.ts sso-admin.controller.ts sso-admin.service.ts sso-secrets.ts sso.module.ts
teams/4dto.ts teams.controller.ts teams.module.ts teams.service.ts
users/4dto.ts users.controller.ts users.module.ts users.service.ts
webhooks/3webhooks.controller.ts webhooks.module.ts webhooks.service.ts
workspaces/4dto.ts workspaces.controller.ts workspaces.module.ts workspaces.service.ts
types/1xmldom.d.ts
app.module.ts constants.ts main.ts
_probe_rawbody.cjs .env.example Dockerfile package.json README.md tsconfig.json vitest.config.ts
realtime/33
src/17auth.ts comments.ts config.ts event-source.ts http-store.ts index.ts metrics.ts notifications.ts page-updated-source.ts presence.ts prisma-store.ts protocol.ts rate-limit.ts room-key.ts rooms.ts server.ts update-log.ts
test/11auth.test.ts config.test.ts event-source.test.ts http-store.test.ts metrics-merge.test.ts page-updated-source.test.ts presence.test.ts protocol.test.ts rate-limit.test.ts rooms.test.ts task-0094-builders.test.ts
.env.example Dockerfile package.json README.md tsconfig.json
web/255
src/244
app/45
__tests__/1theme-tokens.test.ts
(app)/26
w/25
[workspace]/25
ask/1page.tsx
databases/1
[id]/1page.tsx
favorites/1page.tsx
files/1page.tsx
notifications/1page.tsx
page/4
[id]/4
[block]/1page.tsx
share/1page.tsx
layout.tsx page.tsx
search/1page.tsx
settings/10
appearance/1page.tsx
automations/3
[id]/1page.tsx
new/1page.tsx
page.tsx
billing/1page.tsx
developers/1page.tsx
members/1page.tsx
permissions/1page.tsx
teams/1page.tsx
page.tsx
shared/1page.tsx
templates/1page.tsx
trash/1page.tsx
layout.tsx page.tsx
layout.tsx
(auth)/4
login/1page.tsx
register/1page.tsx
reset-password/1page.tsx
layout.tsx
api/2
metrics/1route.ts
v1/1
health/1route.ts
f/1
[slug]/1page.tsx
health/1
ready/1route.ts
org/2
[orgId]/2
admin/2
integrations/1page.tsx
page.tsx
share/1
[id]/1page.tsx
error.tsx global-error.tsx globals.css layout.tsx not-found.tsx page.tsx providers.tsx
components/118
admin/10
org-admin/8ApiKeysTab.tsx AuditTab.tsx MembersTab.tsx OverviewTab.tsx PoliciesTab.tsx RetentionTab.tsx WebhooksTab.tsx WorkspacePicker.tsx
ScimCard.tsx SsoTabs.tsx
ai/6ai-panel.tsx ask-ai-submenu.tsx db-ai-dialog.tsx generate-page-dialog.tsx writing-actions-menu.tsx writing-diff.tsx
automations/5action-editor.tsx condition-editor.tsx lib.ts run-history.tsx trigger-editor.tsx
collaboration/6CursorLayer.tsx OfflineBanner.tsx PresenceBar.tsx README.md ReviewFailedDialog.tsx StatusChip.tsx
comments/3comment-panel.tsx comment-thread.tsx mention-input.tsx
database/27
__tests__/2cell-editor.test.tsx cell-renderer.test.tsx
AiExtractDialog.tsx AiFormulaDialog.tsx AiGenerateDialog.tsx board-view.tsx buttons-panel.tsx calendar-view.tsx cell-editor.tsx cell-renderer.tsx chart-view.tsx database-page-view.tsx database-toolbar.tsx database-view-renderer.tsx db-embedded.tsx filter-builder.tsx form-builder-view.tsx formula-editor.tsx gallery-view.tsx group-builder.tsx list-view.tsx property-editor.tsx record-header.tsx record-panel.tsx sort-builder.tsx table-view.tsx timeline-view.tsx
dialogs/7
__tests__/1move-to-dialog.test.tsx
create-dialog.tsx dialog.tsx file-permissions-dialog.tsx invite-dialog.tsx move-to-dialog.tsx share-dialog.tsx
editor/19
__tests__/3code-block-text.test.ts code-block.test.tsx expandable.test.tsx
block-card.tsx block-renderer.tsx block-save-queue.ts block-toolbar.tsx context-menu.tsx expandable.tsx history-popover.tsx inline-editor.tsx insert-dialog.tsx page-canvas.tsx page-spinner.tsx page-view.tsx selection-toolbar.tsx slash-menu.tsx template-dialog.tsx type-menu.tsx
files/4FileBlock.tsx FileBrowser.tsx FilePicker.tsx PreviewModal.tsx
form/4form-field.tsx form-renderer.tsx form-responses-view.tsx form-view.tsx
layout/8
__tests__/1page-tree-icon.test.tsx
command-palette.tsx factory-logo.tsx page-tree-node.tsx sidebar.tsx theme-provider.tsx topbar.tsx workspace-shell.tsx
mentions/3
__tests__/1mention-model.test.ts
mention-model.ts MentionPopup.tsx
search/3ask-ai-search.tsx results-list.tsx search-dialog.tsx
settings/10
api-keys/4ApiKeyCreateDialog.tsx ApiKeyRevealDialog.tsx ApiKeyTable.tsx ScopesBadge.tsx
webhooks/5CurlExamples.tsx DeliveryInspector.tsx EventExplorer.tsx OverviewTab.tsx WebhooksTab.tsx
settings-shell.tsx
ui/3confirm-dialog.tsx form.tsx toaster.tsx
hooks/21
__tests__/4realtime-frame-handler.test.ts use-blocks.test.ts use-database-options.test.ts use-workspace.test.tsx
realtime-frame-handler.ts use-ai-stream.ts use-auth.ts use-blocks.ts use-database.ts use-db-ai-stream.ts use-forms.ts use-members.ts use-mention-sources.ts use-notifications.ts use-offline-status.ts use-pages.ts use-presence-announcer.ts use-presence-toasts.ts use-presence.ts use-realtime.ts use-workspace.ts
lib/50
__tests__/21ai-database.test.ts ai-generate.test.ts ai-sse.test.ts ai-writing.test.ts api-keys.test.ts api-members.test.ts auth-refresh.test.ts auth-store.test.ts batch-queue-drop.test.ts block-content.test.ts clipboard-import.test.ts code-highlight.test.ts offline-status.test.ts presence-announcer.test.ts presence-color.test.ts presence-cursor.test.ts presence-emitter.test.ts realtime-url.test.ts search.test.ts utils.test.ts writing-diff.test.ts
files/7
__tests__/2picker.test.ts upload.test.ts
api.ts picker.ts upload-store.ts upload.ts use-file-uploads.ts
ai-database.ts ai.ts api-keys.ts api.ts auth-store.ts batch-queue.ts block-content.ts clipboard-import.ts code-highlight.ts constants.ts offline-status.ts org-admin.ts presence-announcer.ts presence-color.ts presence-cursor.ts presence-editor-views.ts presence-emitter.ts query-client.ts realtime.ts search.ts types.ts utils.ts
stores/8
__tests__/1block-patch-store.test.ts
block-patch-store.ts comment-pill-store.ts database-store.ts editor-store.ts offlineQueue.ts presence-store.ts ui-store.ts
instrumentation.ts middleware.ts
.env.example Dockerfile next-env.d.ts next.config.mjs package.json postcss.config.mjs README.md tailwind.config.ts tsconfig.json tsconfig.tsbuildinfo vitest.config.ts
worker/92
src/87
__tests__/13ai-embedding.test.ts ai-request.test.ts ai-usage-budget.test.ts audit-export.test.ts email-decision.test.ts encrypt.test.ts health-search-index-lag.test.ts mime.test.ts retention.test.ts s3-sign.test.ts search-index.test.ts smtp.test.ts webhook-sign.test.ts
health/1server.ts
lib/12
__tests__/1clamav.test.ts
clamav.ts encrypt.ts job-otel.ts mime.ts notify.ts prisma.ts redis-stream.ts redis.ts s3.ts sharp.ts smtp.ts
processors/56
automations/28
__tests__/3condition-evaluator.spec.ts executors.spec.ts run-pipeline.spec.ts
executors/17assign-user.ts call-integration.ts change-status.ts classify.ts create-notification.ts create-page.ts email-cap.ts helpers.ts integration-registry.ts permission.ts record-write.ts registry.ts run-ai-action.ts send-email.ts send-webhook.ts types.ts update-record.ts
condition-evaluator.ts dead-letter.ts log.ts matcher.ts pipeline.ts run-state.ts schedule.ts watchdog.ts
files/15
__tests__/4errors.test.ts scan-gate.test.ts status.test.ts temp.test.ts
steps/4finalize.ts metadata.ts scan.ts thumbnails.ts
cleanup.ts errors.ts generateThumbs.ts processor.ts status.ts temp.ts types.ts
search-index/4builders.ts grants.ts index.ts processor.ts
ai-embedding.ts ai.processor.ts audit-export.ts automations.processor.ts email-decision.processor.ts email.processor.ts maintenance.processor.ts retention.ts webhooks.processor.ts
config.ts events.ts index.ts logger.ts queues.ts
.env.example Dockerfile package.json README.md tsconfig.json
docs/73
api/17ai.md authentication.md automations.md blocks.md comments.md databases.md files.md forms.md openapi.yaml org-admin.md pages.md scim.md search.md sso.md versioning.md webhooks.md workspaces.md
architecture/10ai-architecture.md automation.md backend-architecture.md database-architecture.md frontend-architecture.md realtime-architecture.md search-architecture.md security-architecture.md storage.md system-architecture.md
database/2database-architecture.md redis-keys.md
development/8admin-guide.md coding-standards.md deployment.md development-guide.md files-pipeline.md perf-report.md performance.md testing.md
product/4functional-requirements.md non-functional-requirements.md product-requirements.md ux-requirements.md
requirements/1requirements-matrix.md
security/5audit-report.md files.md forms.md license-allowlist.md security-architecture.md
tasks/16phase-00-foundation.md phase-01-authentication.md phase-02-workspace.md phase-03-pages.md phase-04-editor.md phase-05-databases.md phase-06-relations.md phase-07-collaboration.md phase-08-search.md phase-09-files.md phase-10-forms.md phase-11-automation.md phase-12-ai.md phase-13-api.md phase-14-enterprise.md phase-15-production.md
ui/9ai.md automations.md design-system.md developers.md files.md forms.md org-admin.md scim.md sso.md
support-matrix.md
infrastructure/71
caddy/1Caddyfile
docker/6
init/101-extensions.sql
opensearch/1init-indices.json
.env.docker docker-compose.yml opensearch-init.sh README.md
kubernetes/40
observability/20
alertmanager/1alertmanager.yaml
grafana/8
dashboards/6ai.json api-overview.json infra.json realtime.json search.json workers-queues.json
provisioning/2
dashboards/1dashboards.yaml
datasources/1datasource.yaml
prometheus/3alerts.yaml recording-rules.yaml scrape.yaml
scripts/1sync-sources.mjs
alertmanager.yaml grafana.yaml kustomization.yaml namespace.yaml node-exporter.yaml otel-collector.yaml prometheus.yaml
postgres/7configmap.yaml cronjob-backup.yaml cronjob-opensearch-snapshot.yaml pgbouncer.yaml replica.yaml statefulset.yaml walg-iam-policy.yaml
api.yaml configmap.yaml ingress.yaml kustomization.yaml namespace.yaml networkpolicy.yaml pdb.yaml README.md realtime.yaml redis.yaml secret.example.yaml web.yaml worker.yaml
nginx/2nginx.conf README.md
observability/14
alertmanager/1alertmanager.yaml
grafana/8
dashboards/6ai.json api-overview.json infra.json realtime.json search.json workers-queues.json
provisioning/2
dashboards/1dashboards.yaml
datasources/1datasource.yaml
prometheus/3alerts.yaml recording-rules.yaml scrape.yaml
scripts/1dashboard-completeness.mjs
README.md
terraform/8compute.tf data.tf main.tf network.tf outputs.tf README.md security.tf variables.tf
packages/289
ai/24
src/20
providers/7anthropic.ts google.ts http.ts index.ts openai-compatible.ts rag.test.ts writing.test.ts
schemas/2database.ts generate.ts
adapters.test.ts config.test.ts config.ts gateway.test.ts gateway.ts index.ts tools.test.ts tools.ts types.ts usage.test.ts usage.ts
package.json README.md tsconfig.json vitest.config.ts
auth/11
src/7index.ts passwords.test.ts passwords.ts sessions.test.ts sessions.ts tokens.test.ts tokens.ts
package.json README.md tsconfig.json vitest.config.ts
collaboration/17
src/13awareness.ts codec.test.ts codec.ts index.ts lww.test.ts lww.ts mapping.ts offline.ts outbox.test.ts outbox.ts provider.test.ts provider.ts types.ts
package.json README.md tsconfig.json vitest.config.ts
config/7
src/4eslint.base.js index.ts prettier.base.json tsconfig.base.json
package.json README.md tsconfig.json
database-client/5
src/2index.test.ts index.ts
package.json README.md tsconfig.json
database-engine/33
src/29
filter/2filter.test.ts index.ts
formula/8evaluator.ts formula.test.ts functions.ts index.ts lexer.ts parser.ts types.ts validate.ts
query/6group.ts index.ts paginate.ts pivot.ts query.test.ts sort.ts
relations/2index.ts relations.test.ts
rollups/2index.ts rollups.test.ts
values/5dates.ts index.ts registry.ts types.ts values.test.ts
views/3buttons.ts index.ts views.test.ts
index.ts
package.json README.md tsconfig.json vitest.config.ts
editor/25
src/21
marks/1highlight.ts
nodes/2equation.ts mention.ts
autosave.test.ts autosave.ts clipboard.test.ts clipboard.ts codec.test.ts codec.ts context-menu.test.ts context-menu.ts diff.test.ts diff.ts factory.ts history.test.ts history.ts index.ts positions.ts slash.test.ts slash.ts types.ts
package.json README.md tsconfig.json vitest.config.ts
observability/20
src/16
__tests__/8db-redis-metrics.test.ts metrics.test.ts otel.test.ts pino-otel.test.ts prometheus.test.ts resource.test.ts scrubber.test.ts traceparent.test.ts
index.ts metrics.ts otel.ts pino-otel.ts prometheus.ts resource.ts scrubber.ts traceparent.ts
package.json README.md tsconfig.json vitest.config.ts
permissions/11
src/7index.ts levels.test.ts levels.ts resolve.test.ts resolve.ts rules.test.ts rules.ts
package.json README.md tsconfig.json vitest.config.ts
search/22
src/18chunking.test.ts chunking.ts client.test.ts client.ts embeddings.test.ts embeddings.ts hybrid.test.ts hybrid.ts index.ts indexer.test.ts indexer.ts mapping.test.ts mapping.ts queries.test.ts queries.ts rrf.test.ts rrf.ts types.ts
package.json README.md tsconfig.json vitest.config.ts
shared/61
src/57
dto/17ai.dto.ts auth.dto.test.ts auth.dto.ts block.dto.ts browser-safety.test.ts comment.dto.ts database.dto.test.ts database.dto.ts file.dto.ts formula-ast.ts index.ts notification.dto.ts page.dto.ts search.dto.ts share.dto.ts webhook.dto.ts workspace.dto.ts
events/8audit-catalog.test.ts audit-catalog.ts audit-csv.test.ts audit-csv.ts audit-scope.test.ts audit-scope.ts catalog.test.ts catalog.ts
realtime/6comment-events.ts frames.test.ts frames.ts notification-policy.ts notification-prefs.ts task-0094.test.ts
automation.test.ts automation.ts constants.ts crypto.test.ts crypto.ts env.ts errors.ts events.test.ts events.ts forms.test.ts forms.ts index.ts markdown.test.ts markdown.ts mentions.test.ts mentions.ts net.test.ts net.ts positions.test.ts positions.ts presence.test.ts presence.ts security-headers.ts webhook-delivery.test.ts webhook-delivery.ts webhook-events.ts
package.json README.md tsconfig.json vitest.config.ts
storage/16
src/12client.test.ts client.ts index.ts keys.test.ts keys.ts mime.test.ts mime.ts presign.test.ts presign.ts thumbnails.test.ts thumbnails.ts types.ts
package.json README.md tsconfig.json vitest.config.ts
ui/37
src/33
components/19avatar.tsx badge.tsx button.tsx checkbox.tsx command.tsx context-menu.tsx dialog.tsx dropdown-menu.tsx empty-state.tsx index.ts popover.tsx separator.tsx skeleton.tsx slider.tsx spinner.tsx switch.tsx tabs.tsx toast.tsx tooltip.tsx
color.ts command-filter.test.ts command-filter.ts focus.test.ts focus.ts formatters.test.ts formatters.ts index.ts theme.test.ts theme.ts toast-store.test.ts toast-store.ts tokens.test.ts tokens.ts
package.json README.md tsconfig.json vitest.config.ts
prisma/16
migrations/13
20260927000000_init/1migration.sql
20260928000000_search_documents_content_hash/1migration.sql
20260929000000_workspace_usage_storage_bytes/1migration.sql
20260930000000_form_submitted_notification_type/1migration.sql
20261001000000_ai_phase12/1migration.sql
20261002000000_webhooks_secret_encrypted_dlq/1migration.sql
20261002111436_webhook_delivery_latency/1migration.sql
20261002120000_org_admin_2fa_retention_unique/1migration.sql
20261002215124_audit_export/1migration.sql
20261003210000_perf_indexes_hot_paths/1migration.sql
20261004004500_perf_indexes_hot_paths_2/1migration.sql
migration_lock.toml README.md
schema.prisma seed.ts verify.ts
scripts/7backup-health.ts docs-completeness.mjs generate-openapi.mjs minio-init.ts opensearch-reindex.ts storage-orphans.ts verify-clean-clone.sh
tests/169
e2e/63
.auth/1user.json
fixtures/7
files/6clip.mp4 clip.wav clip.webm hero-1400.png note.docx note.txt
realtime.ts
mocks/2oidc-issuer.ts saml-idp.ts
playwright-report/3
data/2a6557bae9c2714a658968d4eb8534195c08ebda8.png e3092d07d00a16063e46385c02a559a9054fa847.webm
index.html
reports/1files-security.json
specs/34ai-database.spec.ts ai-generate.spec.ts ai-rag.spec.ts ai-security.spec.ts ai-writing.spec.ts ai.spec.ts api-keys.spec.ts appearance-theme.spec.ts auth.spec.ts automation.spec.ts collab-two-tab.spec.ts comments.spec.ts databases.spec.ts default-workspace-alias.spec.ts developers.spec.ts editor.spec.ts files.spec.ts final-flow.spec.ts forms.spec.ts oauth.spec.ts org-admin.spec.ts pages.spec.ts performance.spec.ts presence-cursors.spec.ts qa-paste-toggle.spec.ts realtime.spec.ts scim.spec.ts search-index-lag.spec.ts search.spec.ts sharing.spec.ts sso.spec.ts task-0094-comments-notifications.spec.ts webhooks.spec.ts workspace.spec.ts
test-results-final-flow/3
final-flow-Release-v1-0-fi-6c06b-w-state-carries-sequential--chromium-desktop/2test-failed-1.png trace.zip
.last-run.json
utils/4api.ts dnd.ts search-lag.ts wait.ts
.gitignore fixtures.ts global-setup.ts package.json playwright.config.ts playwright.final-flow.config.ts README.md tsconfig.json
fixtures/1
files/1make-sparse.ts
integration/60
ai-capability/2ai-app.capability.test.ts gateway.capability.test.ts
drill/2seed-drill.mjs verify-restore.mjs
fixtures/5
files/5clip.mp4 clip.wav doc.pdf hero-1400.png note.txt
helpers/3api.ts containers.ts seed.ts
realtime/11control-channel.test.ts convergence.test.ts flush-rebase-http.test.ts handshake.test.ts heartbeat-limits.test.ts lifecycle.test.ts presence.test.ts rebase.test.ts resume.test.ts rt-helpers.ts task-0094-fanout.test.ts
ai-chat.integration.test.ts ai-database.integration.test.ts ai-generate.integration.test.ts ai-rag.integration.test.ts ai-writing.integration.test.ts api-keys.integration.test.ts audit-completeness.integration.test.ts audit-export-s3.integration.test.ts auth.integration.test.ts automation-pipeline.integration.test.ts automations.integration.test.ts blocks.integration.test.ts cache-invalidation.integration.test.ts comments.integration.test.ts databases.integration.test.ts files-lifecycle.integration.test.ts files-pipeline.integration.test.ts files-security.integration.test.ts files.integration.test.ts forms-responses.integration.test.ts forms.integration.test.ts oauth.integration.test.ts openapi.contract.test.ts org-admin.integration.test.ts package.json pages.integration.test.ts permissions.integration.test.ts README.md replica-routing.integration.test.ts retention-engine.integration.test.ts scim.integration.test.ts search.integration.test.ts sso.integration.test.ts tsconfig.json vitest.config.ts webhooks.integration.test.ts workspace.integration.test.ts
performance/28
fixtures/1search-100k.ts
helpers/2seed-100k.mjs seed-1k-load.mjs
reports/7api-load-smoke.json database-load-smoke.json editor-local.json realtime-load.json search-full.json search-last.json search-reduced.json
api-load.js api.js archive.tar database-load.js database.js editor-local.mjs extract-100k-env.mjs package.json README.md realtime-1k.js realtime-load.js realtime.js run-realtime-load.sh search-search.k6.js search-summary.json seed-100k.mjs threshold-breach-demo.js verify-zero-op-loss.mjs
security/16
helpers/1app.ts
audit-report.test.ts auth-paths.test.ts deps.test.ts formula-fuzz.test.ts gitleaks-config.test.ts headers.test.ts images.test.ts oracle.ts package.json permission-fuzz.test.ts rate-limits.test.ts README.md tsconfig.json upload-abuse.test.ts vitest.config.ts
README.md
.dockerignore .env .env.bak-task0125 .env.example .eslintrc.json .gitignore .npmrc .prettierignore .prettierrc.json AGENTS.md ARCHITECTURE.md CHANGELOG.md CONTRIBUTING.md gitleaks.toml LICENSE package.json pnpm-lock.yaml pnpm-workspace.yaml PRODUCT-SPEC.md README.md ROADMAP.md SECURITY.md tsconfig.json turbo.json
slash-menu.tsxapps/web/src/components/editor/slash-menu.tsxraw← editor12,326 B← Back to the app
1"use client";
2 
3/**
4 * Slash menu — appears when the user types "/" in a text block: fuzzy
5 * filtered command list (same groups as the TypeMenu plus "Add database",
6 * "Insert synced block", "Insert template"), full keyboard navigation
7 * (↑/↓, Enter, Esc). Selecting a command inserts a new block after the
8 * current one (the current block is split/kept per command semantics).
9 */
10import { useEffect, useMemo, useRef, useState } from "react";
11import {
12  Bookmark,
13  Braces,
14  Calculator,
15  Database,
16  File as FileIcon,
17  Film,
18  Heading1,
19  Heading2,
20  Heading3,
21  Image as ImageIcon,
22  List,
23  ListOrdered,
24  Minus,
25  Music,
26  Quote,
27  SquareCheck,
28  Table as TableIcon,
29  ToggleRight,
30  Type,
31  Undo2,
32  Wand2
33} from "lucide-react";
34import { cn, fuzzyMatch } from "@/lib/utils";
35import { BLOCK_TYPE_LABELS } from "@/lib/constants";
36import type { BlockType } from "@/lib/types";
37 
38export interface SlashCommand {
39  id: string;
40  label: string;
41  keywords: string;
42  icon: React.ComponentType<{ className?: string }>;
43  /** block type to insert (for plain type commands). */
44  blockType?: BlockType;
45  /** Special insertion (handled by the page-level insert flow). */
46  special?: "image" | "database" | "synced" | "template" | "table";
47  group: string;
48}
49 
50const COMMANDS: SlashCommand[] = [
51  { id: "paragraph", label: "Text", keywords: "paragraph plain text", icon: Type, blockType: "paragraph", group: "Basics" },
52  { id: "h1", label: "Heading 1", keywords: "heading 1 title h1", icon: Heading1, blockType: "heading_1", group: "Basics" },
53  { id: "h2", label: "Heading 2", keywords: "heading 2 subtitle h2", icon: Heading2, blockType: "heading_2", group: "Basics" },
54  { id: "h3", label: "Heading 3", keywords: "heading 3 h3", icon: Heading3, blockType: "heading_3", group: "Basics" },
55  { id: "todo", label: "To-do list", keywords: "todo task checkbox done", icon: SquareCheck, blockType: "todo", group: "Basics" },
56  { id: "quote", label: "Quote", keywords: "blockquote citation", icon: Quote, blockType: "quote", group: "Basics" },
57  { id: "code", label: "Code", keywords: "code snippet programming", icon: Braces, blockType: "code", group: "Basics" },
58  { id: "bullet", label: "Bulleted list", keywords: "bullet unordered list", icon: List, blockType: "bulleted_list", group: "Lists" },
59  { id: "numbered", label: "Numbered list", keywords: "numbered ordered list", icon: ListOrdered, blockType: "numbered_list", group: "Lists" },
60  // "image" is a SPECIAL (not blockType) command: picking it opens the insert
61  // dialog's Image tab (file picker → presigned upload → image block with the
62  // signed URL). A bare image block has no src and no reachable picker, so it
63  // could never actually be uploaded (the renderer's "use Insert image from
64  // the toolbar" hint referenced a toolbar button that does not exist).
65  { id: "image", label: "Image", keywords: "image picture photo upload", icon: ImageIcon, special: "image", group: "Media" },
66  { id: "file", label: "File", keywords: "file attachment document", icon: FileIcon, blockType: "file", group: "Media" },
67  { id: "embed", label: "Embed", keywords: "embed iframe video youtube", icon: Film, blockType: "embed", group: "Media" },
68  { id: "bookmark", label: "Bookmark", keywords: "bookmark link url website", icon: Bookmark, blockType: "bookmark", group: "Media" },
69  { id: "divider", label: "Divider", keywords: "divider separator hr line", icon: Minus, blockType: "divider", group: "Media" },
70  { id: "callout", label: "Callout", keywords: "callout note highlight", icon: Type, blockType: "callout", group: "Media" },
71  { id: "toggle", label: "Toggle list", keywords: "toggle collapsible expand", icon: ToggleRight, blockType: "toggle", group: "Media" },
72  { id: "video", label: "Video", keywords: "video movie clip", icon: Film, blockType: "video", group: "Media" },
73  { id: "audio", label: "Audio", keywords: "audio sound music", icon: Music, blockType: "audio", group: "Media" },
74  { id: "spacer", label: "Spacer", keywords: "spacer space gap", icon: Minus, blockType: "spacer", group: "Media" },
75  { id: "toc", label: "Table of contents", keywords: "toc contents headings outline", icon: List, blockType: "toc", group: "Media" },
76  { id: "columns", label: "Columns", keywords: "columns split 2 3", icon: TableIcon, blockType: "column_list", group: "Media" },
77  // "table" is a SPECIAL (not blockType) command: picking it opens the insert
78  // dialog's Table tab (rows × cols → grid pre-created, like image/database).
79  // A bare table block has no columns/rows, so the renderer draws nothing —
80  // it could never be filled in (verified by probe: thead/tbody both empty).
81  { id: "table", label: "Table", keywords: "table grid rows columns", icon: TableIcon, special: "table", group: "Media" },
82  { id: "equation", label: "Equation", keywords: "equation math latex formula", icon: Calculator, blockType: "equation", group: "Advanced" },
83  { id: "database", label: "Add database", keywords: "database new db table records", icon: Database, special: "database", group: "Advanced" },
84  { id: "linked_database", label: "Linked database", keywords: "linked database embed view existing", icon: TableIcon, blockType: "linked_database", group: "Advanced" },
85  { id: "child_database", label: "Linked database (row)", keywords: "child database embed row", icon: Database, blockType: "child_database", group: "Advanced" },
86  { id: "synced", label: "Insert synced block", keywords: "synced block mirror reference", icon: Undo2, special: "synced", group: "Advanced" },
87  { id: "template", label: "Insert template", keywords: "template insert reuse", icon: Wand2, special: "template", group: "Advanced" }
88];
89 
90export interface SlashMenuProps {
91  /** The typed query after "/". */
92  query: string;
93  /** Position to anchor the menu (caret rect). */
94  anchor: { top: number; left: number };
95  onPick: (command: SlashCommand) => void;
96  onClose: () => void;
97}
98 
99export function SlashMenu({ query, anchor, onPick, onClose }: SlashMenuProps) {
100  const [active, setActive] = useState(0);
101  const listRef = useRef<HTMLUListElement>(null);
102  const rootRef = useRef<HTMLDivElement>(null);
103 
104  // Click-outside dismissal (mirrors TypeMenu). The editor's onBlur path only
105  // covers clicks that BLUR the contenteditable — a click inside the editor's
106  // blank trailing zone (or elsewhere that keeps it focused) leaves the menu
107  // stuck open. A document-level mousedown that lands outside the menu root
108  // closes it regardless of focus.
109  useEffect(() => {
110    const onClick = (e: MouseEvent) => {
111      if (rootRef.current && !rootRef.current.contains(e.target as Node)) onClose();
112    };
113    document.addEventListener("mousedown", onClick);
114    return () => document.removeEventListener("mousedown", onClick);
115  }, [onClose]);
116 
117  const filtered = useMemo(() => {
118    const q = query.toLowerCase();
119    return COMMANDS.filter((c) => fuzzyMatch(q, c.label + " " + c.keywords));
120  }, [query]);
121 
122  // Reset active on filter change; keep it in range.
123  useEffect(() => {
124    setActive(0);
125  }, [query]);
126  useEffect(() => {
127    if (active >= filtered.length) setActive(Math.max(0, filtered.length - 1));
128  }, [filtered.length, active]);
129  useEffect(() => {
130    listRef.current?.querySelector<HTMLElement>(`[data-index="${active}"]`)?.scrollIntoView({ block: "nearest" });
131  }, [active]);
132 
133  useEffect(() => {
134    const onKey = (e: KeyboardEvent) => {
135      if (e.key === "ArrowDown") {
136        e.preventDefault();
137        e.stopPropagation();
138        setActive((a) => Math.min(a + 1, filtered.length - 1));
139      } else if (e.key === "ArrowUp") {
140        e.preventDefault();
141        e.stopPropagation();
142        setActive((a) => Math.max(a - 1, 0));
143      } else if (e.key === "Enter") {
144        e.preventDefault();
145        e.stopPropagation();
146        const cmd = filtered[active];
147        if (cmd) onPick(cmd);
148      } else if (e.key === "Escape") {
149        e.preventDefault();
150        e.stopPropagation();
151        onClose();
152      }
153    };
154    document.addEventListener("keydown", onKey, true);
155    return () => document.removeEventListener("keydown", onKey, true);
156  }, [filtered, active, onPick, onClose]);
157 
158  // Group the filtered list preserving COMMANDS order.
159  const grouped = useMemo(() => {
160    const groups = new Map<string, SlashCommand[]>();
161    for (const c of filtered) {
162      const list = groups.get(c.group) ?? [];
163      list.push(c);
164      groups.set(c.group, list);
165    }
166    return [...groups.entries()];
167  }, [filtered]);
168 
169  let flatIndex = -1;
170 
171  // Keep the menu inside the viewport: the list is height-capped below, so
172  // the whole menu is at most LIST_MAX + the header row. When the caret is
173  // near the bottom (e.g. an empty last block on a dense page), opening
174  // downward would push the lower groups (Media/Advanced — "Add database")
175  // below the fold where they cannot be clicked; flip upward instead.
176  const LIST_MAX = 326;
177  const vh = typeof window !== "undefined" ? window.innerHeight : Number.POSITIVE_INFINITY;
178  const flipUp = anchor.top + LIST_MAX + 40 > vh - 16;
179  const top = flipUp ? Math.max(8, anchor.top - LIST_MAX - 40) : anchor.top;
180 
181  return (
182    <div
183      ref={rootRef}
184      role="dialog"
185      aria-label="Slash commands"
186      data-testid="slash-menu"
187      className="fixed z-[70] w-80 rounded-lg border border-border bg-popover shadow-2xl"
188      style={{ top, left: anchor.left }}
189    >
190      <p className="border-b border-border px-3 py-2 text-xs font-semibold uppercase tracking-wide text-muted-foreground">
191        Basic blocks & commands
192      </p>
193      <ul ref={listRef} className="max-h-[326px] overflow-y-auto p-1" role="listbox">
194        {grouped.length === 0 ? (
195          <li className="px-3 py-4 text-center text-sm text-muted-foreground">No matching command.</li>
196        ) : (
197          grouped.map(([group, cmds]) => (
198            <li key={group}>
199              <p className="px-2 pb-0.5 pt-1 text-[11px] font-medium text-muted-foreground">{group}</p>
200              <ul>
201                {cmds.map((cmd) => {
202                  flatIndex += 1;
203                  const idx = flatIndex;
204                  return (
205                    <li key={cmd.id} role="option" aria-selected={idx === active} data-index={idx}>
206                      <button
207                        type="button"
208                        data-testid={`slash-menu-item-${cmd.id}`}
209                        onMouseEnter={() => setActive(idx)}
210                        // Keep the editor focused: a bare mousedown on a
211                        // button moves focus to it, blurring the
212                        // contenteditable, and InlineEditor's onBlur closes
213                        // this menu — so the click that follows would hit a
214                        // menu that no longer exists (the option is
215                        // un-clickable, verified in the Phase-15 E2E diag).
216                        // preventDefault on mousedown suppresses only the
217                        // focus change, not the synthesized click.
218                        onMouseDown={(e) => e.preventDefault()}
219                        onClick={() => onPick(cmd)}
220                        className={cn(
221                          "flex w-full items-center gap-3 rounded-md px-2 py-1.5 text-left text-sm",
222                          idx === active ? "bg-accent" : "hover:bg-accent/60"
223                        )}
224                      >
225                        <span className="flex size-8 shrink-0 items-center justify-center rounded border border-border bg-background">
226                          <cmd.icon className="size-4 text-muted-foreground" aria-hidden />
227                        </span>
228                        <span className="min-w-0 flex-1">
229                          <span className="block truncate font-medium">{cmd.label}</span>
230                          {cmd.blockType ? (
231                            <span className="block truncate text-xs text-muted-foreground">
232                              {BLOCK_TYPE_LABELS[cmd.blockType]}
233                            </span>
234                          ) : null}
235                        </span>
236                      </button>
237                    </li>
238                  );
239                })}
240              </ul>
241            </li>
242          ))
243        )}
244      </ul>
245    </div>
246  );
247}
248