@rudderhq/server 0.3.4-canary.8 → 0.3.4
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/dist/agent-runtimes/codex-models.d.ts.map +1 -1
- package/dist/agent-runtimes/codex-models.js.map +1 -1
- package/dist/agent-runtimes/cursor-models.js +1 -1
- package/dist/agent-runtimes/cursor-models.js.map +1 -1
- package/dist/agent-runtimes/http/execute.js +1 -1
- package/dist/agent-runtimes/index.d.ts +2 -2
- package/dist/agent-runtimes/index.d.ts.map +1 -1
- package/dist/agent-runtimes/index.js +1 -1
- package/dist/agent-runtimes/index.js.map +1 -1
- package/dist/agent-runtimes/process/execute.js +1 -1
- package/dist/agent-runtimes/process/execute.js.map +1 -1
- package/dist/agent-runtimes/process/test.js +1 -1
- package/dist/agent-runtimes/process/test.js.map +1 -1
- package/dist/agent-runtimes/registry.d.ts.map +1 -1
- package/dist/agent-runtimes/registry.js +14 -14
- package/dist/agent-runtimes/registry.js.map +1 -1
- package/dist/agent-runtimes/types.d.ts +1 -1
- package/dist/agent-runtimes/types.d.ts.map +1 -1
- package/dist/agent-runtimes/utils.d.ts +1 -1
- package/dist/agent-runtimes/utils.d.ts.map +1 -1
- package/dist/agent-runtimes/utils.js +1 -2
- package/dist/agent-runtimes/utils.js.map +1 -1
- package/dist/agent-workspace-key.js +1 -1
- package/dist/agent-workspace-key.js.map +1 -1
- package/dist/auth/better-auth.d.ts +2 -2
- package/dist/auth/better-auth.d.ts.map +1 -1
- package/dist/auth/better-auth.js +1 -1
- package/dist/auth/better-auth.js.map +1 -1
- package/dist/board-claim.d.ts.map +1 -1
- package/dist/board-claim.js +2 -2
- package/dist/board-claim.js.map +1 -1
- package/dist/bootstrap/create-http-app.d.ts.map +1 -1
- package/dist/bootstrap/create-http-app.js +1 -1
- package/dist/bootstrap/create-http-app.js.map +1 -1
- package/dist/bootstrap/plugin-host-runtime.d.ts +16 -16
- package/dist/bootstrap/plugin-host-runtime.d.ts.map +1 -1
- package/dist/bootstrap/plugin-host-runtime.js.map +1 -1
- package/dist/bootstrap/register-api-routes.d.ts.map +1 -1
- package/dist/bootstrap/register-api-routes.js +1 -1
- package/dist/bootstrap/register-api-routes.js.map +1 -1
- package/dist/bootstrap/types.d.ts +2 -2
- package/dist/bootstrap/types.d.ts.map +1 -1
- package/dist/bundled-plugins/plugin-linear/dist/ui/index.js +5 -5
- package/dist/bundled-plugins/plugin-linear/dist/ui/index.js.map +1 -1
- package/dist/bundled-plugins/plugin-linear/dist/worker.js +684 -655
- package/dist/bundled-plugins/plugin-linear/dist/worker.js.map +3 -3
- package/dist/config-file.d.ts.map +1 -1
- package/dist/config-file.js +1 -1
- package/dist/config-file.js.map +1 -1
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +4 -4
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +13 -13
- package/dist/index.js.map +1 -1
- package/dist/langfuse.d.ts.map +1 -1
- package/dist/langfuse.js +1 -1
- package/dist/langfuse.js.map +1 -1
- package/dist/middleware/auth.d.ts +1 -1
- package/dist/middleware/auth.d.ts.map +1 -1
- package/dist/middleware/auth.js +3 -3
- package/dist/middleware/auth.js.map +1 -1
- package/dist/middleware/error-handler.d.ts +1 -1
- package/dist/middleware/error-handler.d.ts.map +1 -1
- package/dist/middleware/index.d.ts +1 -1
- package/dist/middleware/index.d.ts.map +1 -1
- package/dist/middleware/index.js +1 -1
- package/dist/middleware/index.js.map +1 -1
- package/dist/middleware/logger.js +1 -1
- package/dist/middleware/logger.js.map +1 -1
- package/dist/middleware/validate.d.ts +1 -1
- package/dist/middleware/validate.d.ts.map +1 -1
- package/dist/realtime/live-events-ws.d.ts +2 -2
- package/dist/realtime/live-events-ws.d.ts.map +1 -1
- package/dist/realtime/live-events-ws.js +2 -2
- package/dist/realtime/live-events-ws.js.map +1 -1
- package/dist/routes/access-onboarding.helpers.d.ts +2 -2
- package/dist/routes/access-onboarding.helpers.d.ts.map +1 -1
- package/dist/routes/access-onboarding.helpers.js +2 -2
- package/dist/routes/access-onboarding.helpers.js.map +1 -1
- package/dist/routes/access.d.ts +2 -2
- package/dist/routes/access.d.ts.map +1 -1
- package/dist/routes/access.helpers.d.ts +3 -3
- package/dist/routes/access.helpers.d.ts.map +1 -1
- package/dist/routes/access.helpers.js.map +1 -1
- package/dist/routes/access.js +9 -9
- package/dist/routes/access.js.map +1 -1
- package/dist/routes/activity.d.ts.map +1 -1
- package/dist/routes/activity.js +2 -2
- package/dist/routes/activity.js.map +1 -1
- package/dist/routes/agents.d.ts.map +1 -1
- package/dist/routes/agents.js +17 -17
- package/dist/routes/agents.js.map +1 -1
- package/dist/routes/agents.management-routes.d.ts +1 -1
- package/dist/routes/agents.management-routes.d.ts.map +1 -1
- package/dist/routes/agents.management-routes.js +17 -12
- package/dist/routes/agents.management-routes.js.map +1 -1
- package/dist/routes/approvals.d.ts.map +1 -1
- package/dist/routes/approvals.js +5 -5
- package/dist/routes/approvals.js.map +1 -1
- package/dist/routes/assets.d.ts.map +1 -1
- package/dist/routes/assets.js +4 -4
- package/dist/routes/assets.js.map +1 -1
- package/dist/routes/automations.d.ts.map +1 -1
- package/dist/routes/automations.js +3 -3
- package/dist/routes/automations.js.map +1 -1
- package/dist/routes/calendar.d.ts.map +1 -1
- package/dist/routes/calendar.js +3 -3
- package/dist/routes/calendar.js.map +1 -1
- package/dist/routes/chat-issue-assignment-wakeup.d.ts +1 -1
- package/dist/routes/chat-issue-assignment-wakeup.d.ts.map +1 -1
- package/dist/routes/chat-issue-assignment-wakeup.js.map +1 -1
- package/dist/routes/chats.d.ts.map +1 -1
- package/dist/routes/chats.js +45 -23
- package/dist/routes/chats.js.map +1 -1
- package/dist/routes/chats.stream-routes.d.ts +1 -1
- package/dist/routes/chats.stream-routes.d.ts.map +1 -1
- package/dist/routes/chats.stream-routes.js +5 -5
- package/dist/routes/chats.stream-routes.js.map +1 -1
- package/dist/routes/costs.d.ts.map +1 -1
- package/dist/routes/costs.js +4 -4
- package/dist/routes/costs.js.map +1 -1
- package/dist/routes/dashboard.d.ts.map +1 -1
- package/dist/routes/dashboard.js.map +1 -1
- package/dist/routes/execution-workspaces.d.ts.map +1 -1
- package/dist/routes/execution-workspaces.js +3 -3
- package/dist/routes/execution-workspaces.js.map +1 -1
- package/dist/routes/goals.d.ts.map +1 -1
- package/dist/routes/goals.js +1 -1
- package/dist/routes/goals.js.map +1 -1
- package/dist/routes/health.d.ts.map +1 -1
- package/dist/routes/health.js +2 -2
- package/dist/routes/health.js.map +1 -1
- package/dist/routes/index.d.ts +13 -13
- package/dist/routes/index.d.ts.map +1 -1
- package/dist/routes/index.js +13 -13
- package/dist/routes/index.js.map +1 -1
- package/dist/routes/instance-settings.d.ts.map +1 -1
- package/dist/routes/instance-settings.js +41 -5
- package/dist/routes/instance-settings.js.map +1 -1
- package/dist/routes/issues.comments-attachments.d.ts +1 -1
- package/dist/routes/issues.comments-attachments.d.ts.map +1 -1
- package/dist/routes/issues.comments-attachments.js +4 -4
- package/dist/routes/issues.comments-attachments.js.map +1 -1
- package/dist/routes/issues.d.ts.map +1 -1
- package/dist/routes/issues.js +21 -145
- package/dist/routes/issues.js.map +1 -1
- package/dist/routes/issues.mutations.d.ts +1 -1
- package/dist/routes/issues.mutations.d.ts.map +1 -1
- package/dist/routes/issues.mutations.js +6 -37
- package/dist/routes/issues.mutations.js.map +1 -1
- package/dist/routes/llms.d.ts.map +1 -1
- package/dist/routes/llms.js +2 -2
- package/dist/routes/llms.js.map +1 -1
- package/dist/routes/messenger.d.ts.map +1 -1
- package/dist/routes/messenger.js +2 -2
- package/dist/routes/messenger.js.map +1 -1
- package/dist/routes/onboarding.d.ts.map +1 -1
- package/dist/routes/onboarding.js.map +1 -1
- package/dist/routes/organization-skills.d.ts.map +1 -1
- package/dist/routes/organization-skills.js +3 -3
- package/dist/routes/organization-skills.js.map +1 -1
- package/dist/routes/orgs.d.ts.map +1 -1
- package/dist/routes/orgs.js +4 -4
- package/dist/routes/orgs.js.map +1 -1
- package/dist/routes/plugin-ui-static.d.ts.map +1 -1
- package/dist/routes/plugin-ui-static.js +3 -3
- package/dist/routes/plugin-ui-static.js.map +1 -1
- package/dist/routes/plugins.d.ts +2 -2
- package/dist/routes/plugins.d.ts.map +1 -1
- package/dist/routes/plugins.js +7 -7
- package/dist/routes/plugins.js.map +1 -1
- package/dist/routes/plugins.operations-routes.d.ts +1 -1
- package/dist/routes/plugins.operations-routes.d.ts.map +1 -1
- package/dist/routes/plugins.operations-routes.js +4 -4
- package/dist/routes/plugins.operations-routes.js.map +1 -1
- package/dist/routes/projects.d.ts.map +1 -1
- package/dist/routes/projects.js +3 -3
- package/dist/routes/projects.js.map +1 -1
- package/dist/routes/run-intelligence.d.ts.map +1 -1
- package/dist/routes/run-intelligence.js +225 -1
- package/dist/routes/run-intelligence.js.map +1 -1
- package/dist/routes/secrets.d.ts.map +1 -1
- package/dist/routes/secrets.js +2 -2
- package/dist/routes/secrets.js.map +1 -1
- package/dist/routes/sidebar-badges.d.ts.map +1 -1
- package/dist/routes/sidebar-badges.js +3 -3
- package/dist/routes/sidebar-badges.js.map +1 -1
- package/dist/secrets/local-encrypted-provider.d.ts.map +1 -1
- package/dist/secrets/local-encrypted-provider.js +1 -1
- package/dist/secrets/local-encrypted-provider.js.map +1 -1
- package/dist/secrets/provider-registry.d.ts.map +1 -1
- package/dist/secrets/provider-registry.js +2 -2
- package/dist/secrets/provider-registry.js.map +1 -1
- package/dist/services/access.d.ts +17 -17
- package/dist/services/access.d.ts.map +1 -1
- package/dist/services/access.js +1 -1
- package/dist/services/access.js.map +1 -1
- package/dist/services/activity-log.d.ts.map +1 -1
- package/dist/services/activity-log.js +4 -4
- package/dist/services/activity-log.js.map +1 -1
- package/dist/services/activity.d.ts.map +1 -1
- package/dist/services/activity.js +1 -1
- package/dist/services/activity.js.map +1 -1
- package/dist/services/agent-enabled-skills.d.ts.map +1 -1
- package/dist/services/agent-enabled-skills.js +1 -1
- package/dist/services/agent-enabled-skills.js.map +1 -1
- package/dist/services/agent-name-pool.js +1 -1
- package/dist/services/agent-name-pool.js.map +1 -1
- package/dist/services/agent-run-context.d.ts.map +1 -1
- package/dist/services/agent-run-context.js +9 -9
- package/dist/services/agent-run-context.js.map +1 -1
- package/dist/services/agents.d.ts +83 -83
- package/dist/services/agents.d.ts.map +1 -1
- package/dist/services/agents.js +5 -5
- package/dist/services/agents.js.map +1 -1
- package/dist/services/approvals.d.ts +12 -12
- package/dist/services/approvals.d.ts.map +1 -1
- package/dist/services/approvals.js +1 -1
- package/dist/services/approvals.js.map +1 -1
- package/dist/services/assets.d.ts +4 -4
- package/dist/services/assets.d.ts.map +1 -1
- package/dist/services/assets.js +1 -1
- package/dist/services/assets.js.map +1 -1
- package/dist/services/automation-chat-output.d.ts +5 -5
- package/dist/services/automation-chat-output.d.ts.map +1 -1
- package/dist/services/automation-chat-output.js +1 -1
- package/dist/services/automation-chat-output.js.map +1 -1
- package/dist/services/automations.d.ts +29 -29
- package/dist/services/automations.d.ts.map +1 -1
- package/dist/services/automations.js +10 -24
- package/dist/services/automations.js.map +1 -1
- package/dist/services/board-auth.d.ts +11 -11
- package/dist/services/board-auth.d.ts.map +1 -1
- package/dist/services/board-auth.js +2 -2
- package/dist/services/board-auth.js.map +1 -1
- package/dist/services/budgets.d.ts.map +1 -1
- package/dist/services/budgets.js +1 -1
- package/dist/services/budgets.js.map +1 -1
- package/dist/services/calendar.d.ts +15 -15
- package/dist/services/calendar.d.ts.map +1 -1
- package/dist/services/calendar.js +2 -2
- package/dist/services/calendar.js.map +1 -1
- package/dist/services/chat-assistant.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.d.ts +2 -2
- package/dist/services/chat-assistant.helpers.d.ts.map +1 -1
- package/dist/services/chat-assistant.helpers.js +4 -11
- package/dist/services/chat-assistant.helpers.js.map +1 -1
- package/dist/services/chat-assistant.js +3 -3
- package/dist/services/chat-assistant.js.map +1 -1
- package/dist/services/chats.d.ts +113 -113
- package/dist/services/chats.d.ts.map +1 -1
- package/dist/services/chats.helpers.d.ts +5 -10
- package/dist/services/chats.helpers.d.ts.map +1 -1
- package/dist/services/chats.helpers.js +2 -21
- package/dist/services/chats.helpers.js.map +1 -1
- package/dist/services/chats.js +7 -24
- package/dist/services/chats.js.map +1 -1
- package/dist/services/costs.d.ts +2 -2
- package/dist/services/costs.d.ts.map +1 -1
- package/dist/services/costs.js +2 -2
- package/dist/services/costs.js.map +1 -1
- package/dist/services/dashboard.d.ts.map +1 -1
- package/dist/services/dashboard.js +1 -1
- package/dist/services/dashboard.js.map +1 -1
- package/dist/services/documents.d.ts +0 -183
- package/dist/services/documents.d.ts.map +1 -1
- package/dist/services/documents.js +2 -392
- package/dist/services/documents.js.map +1 -1
- package/dist/services/execution-workspaces.d.ts.map +1 -1
- package/dist/services/execution-workspaces.js +1 -1
- package/dist/services/execution-workspaces.js.map +1 -1
- package/dist/services/export-jobs.d.ts.map +1 -1
- package/dist/services/export-jobs.js.map +1 -1
- package/dist/services/finance.d.ts +6 -6
- package/dist/services/finance.d.ts.map +1 -1
- package/dist/services/finance.js +1 -1
- package/dist/services/finance.js.map +1 -1
- package/dist/services/goals.d.ts +30 -30
- package/dist/services/goals.d.ts.map +1 -1
- package/dist/services/goals.js +1 -1
- package/dist/services/goals.js.map +1 -1
- package/dist/services/heartbeat.d.ts +3 -3
- package/dist/services/heartbeat.d.ts.map +1 -1
- package/dist/services/heartbeat.js +3 -3
- package/dist/services/heartbeat.js.map +1 -1
- package/dist/services/hire-hook.js +1 -1
- package/dist/services/hire-hook.js.map +1 -1
- package/dist/services/index.d.ts +31 -31
- package/dist/services/index.d.ts.map +1 -1
- package/dist/services/index.js +31 -31
- package/dist/services/index.js.map +1 -1
- package/dist/services/instance-settings.d.ts +1 -1
- package/dist/services/instance-settings.d.ts.map +1 -1
- package/dist/services/instance-settings.js +1 -1
- package/dist/services/instance-settings.js.map +1 -1
- package/dist/services/issue-activity-filters.js +1 -1
- package/dist/services/issue-activity-filters.js.map +1 -1
- package/dist/services/issue-approvals.d.ts +1 -1
- package/dist/services/issue-approvals.d.ts.map +1 -1
- package/dist/services/issue-approvals.js +1 -1
- package/dist/services/issue-approvals.js.map +1 -1
- package/dist/services/issue-assignment-wakeup.js +1 -1
- package/dist/services/issue-assignment-wakeup.js.map +1 -1
- package/dist/services/issues.comments-attachments.d.ts +6 -6
- package/dist/services/issues.comments-attachments.d.ts.map +1 -1
- package/dist/services/issues.comments-attachments.js +6 -6
- package/dist/services/issues.comments-attachments.js.map +1 -1
- package/dist/services/issues.d.ts +24 -25
- package/dist/services/issues.d.ts.map +1 -1
- package/dist/services/issues.helpers.d.ts.map +1 -1
- package/dist/services/issues.helpers.js +1 -1
- package/dist/services/issues.helpers.js.map +1 -1
- package/dist/services/issues.js +8 -50
- package/dist/services/issues.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.core.d.ts +1 -1
- package/dist/services/knowledge-portability/organization-portability.core.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.core.js +2 -2
- package/dist/services/knowledge-portability/organization-portability.core.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.export.d.ts +1 -1
- package/dist/services/knowledge-portability/organization-portability.export.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.export.js +5 -5
- package/dist/services/knowledge-portability/organization-portability.export.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.files.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.files.js +1 -1
- package/dist/services/knowledge-portability/organization-portability.files.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.import.d.ts +2 -2
- package/dist/services/knowledge-portability/organization-portability.import.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.import.js +2 -2
- package/dist/services/knowledge-portability/organization-portability.import.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.js +1 -1
- package/dist/services/knowledge-portability/organization-portability.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.package.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.package.js +3 -3
- package/dist/services/knowledge-portability/organization-portability.package.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.preview.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.preview.js +2 -2
- package/dist/services/knowledge-portability/organization-portability.preview.js.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.resolve-source.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-portability.resolve-source.js +1 -1
- package/dist/services/knowledge-portability/organization-portability.resolve-source.js.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.catalog.d.ts +1 -1
- package/dist/services/knowledge-portability/organization-skills.catalog.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.catalog.js +4 -5
- package/dist/services/knowledge-portability/organization-skills.catalog.js.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.d.ts +1 -1
- package/dist/services/knowledge-portability/organization-skills.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.js +7 -7
- package/dist/services/knowledge-portability/organization-skills.js.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.scans.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.scans.js +1 -1
- package/dist/services/knowledge-portability/organization-skills.scans.js.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.sources.d.ts.map +1 -1
- package/dist/services/knowledge-portability/organization-skills.sources.js +2 -2
- package/dist/services/knowledge-portability/organization-skills.sources.js.map +1 -1
- package/dist/services/library-entries.d.ts.map +1 -1
- package/dist/services/library-entries.js +1 -1
- package/dist/services/library-entries.js.map +1 -1
- package/dist/services/live-events.d.ts +1 -1
- package/dist/services/live-events.d.ts.map +1 -1
- package/dist/services/live-events.js.map +1 -1
- package/dist/services/managed-workspace-preflight.js +3 -3
- package/dist/services/managed-workspace-preflight.js.map +1 -1
- package/dist/services/messenger.d.ts +1 -1
- package/dist/services/messenger.d.ts.map +1 -1
- package/dist/services/messenger.js +10 -6
- package/dist/services/messenger.js.map +1 -1
- package/dist/services/native-path-picker.d.ts +1 -1
- package/dist/services/native-path-picker.d.ts.map +1 -1
- package/dist/services/native-path-picker.js.map +1 -1
- package/dist/services/operator-profile.d.ts +3 -1
- package/dist/services/operator-profile.d.ts.map +1 -1
- package/dist/services/operator-profile.js +53 -1
- package/dist/services/operator-profile.js.map +1 -1
- package/dist/services/organization-intelligence-profiles.d.ts.map +1 -1
- package/dist/services/organization-intelligence-profiles.js +1 -1
- package/dist/services/organization-intelligence-profiles.js.map +1 -1
- package/dist/services/organization-portability.d.ts +1 -1
- package/dist/services/organization-portability.d.ts.map +1 -1
- package/dist/services/organization-portability.js +1 -1
- package/dist/services/organization-portability.js.map +1 -1
- package/dist/services/organization-skills.d.ts +3 -3
- package/dist/services/organization-skills.d.ts.map +1 -1
- package/dist/services/organization-skills.js +3 -3
- package/dist/services/organization-skills.js.map +1 -1
- package/dist/services/organization-workspace-browser.d.ts.map +1 -1
- package/dist/services/organization-workspace-browser.js +27 -27
- package/dist/services/organization-workspace-browser.js.map +1 -1
- package/dist/services/orgs.d.ts +6 -6
- package/dist/services/orgs.d.ts.map +1 -1
- package/dist/services/orgs.js +2 -2
- package/dist/services/orgs.js.map +1 -1
- package/dist/services/plugin-capability-validator.d.ts +1 -1
- package/dist/services/plugin-capability-validator.d.ts.map +1 -1
- package/dist/services/plugin-config-validator.d.ts.map +1 -1
- package/dist/services/plugin-config-validator.js.map +1 -1
- package/dist/services/plugin-event-bus.d.ts +1 -1
- package/dist/services/plugin-event-bus.d.ts.map +1 -1
- package/dist/services/plugin-host-services.d.ts.map +1 -1
- package/dist/services/plugin-host-services.js +16 -54
- package/dist/services/plugin-host-services.js.map +1 -1
- package/dist/services/plugin-job-coordinator.d.ts +2 -2
- package/dist/services/plugin-job-coordinator.d.ts.map +1 -1
- package/dist/services/plugin-job-coordinator.js +1 -1
- package/dist/services/plugin-job-coordinator.js.map +1 -1
- package/dist/services/plugin-job-scheduler.d.ts.map +1 -1
- package/dist/services/plugin-job-scheduler.js +2 -2
- package/dist/services/plugin-job-scheduler.js.map +1 -1
- package/dist/services/plugin-job-store.d.ts +2 -2
- package/dist/services/plugin-job-store.d.ts.map +1 -1
- package/dist/services/plugin-job-store.js +1 -1
- package/dist/services/plugin-job-store.js.map +1 -1
- package/dist/services/plugin-lifecycle.d.ts +38 -1
- package/dist/services/plugin-lifecycle.d.ts.map +1 -1
- package/dist/services/plugin-lifecycle.js +2 -39
- package/dist/services/plugin-lifecycle.js.map +1 -1
- package/dist/services/plugin-loader.core.d.ts +27 -1
- package/dist/services/plugin-loader.core.d.ts.map +1 -1
- package/dist/services/plugin-loader.core.js +3 -29
- package/dist/services/plugin-loader.core.js.map +1 -1
- package/dist/services/plugin-loader.d.ts +27 -1
- package/dist/services/plugin-loader.d.ts.map +1 -1
- package/dist/services/plugin-loader.helpers.d.ts +29 -3
- package/dist/services/plugin-loader.helpers.d.ts.map +1 -1
- package/dist/services/plugin-loader.helpers.js +1 -27
- package/dist/services/plugin-loader.helpers.js.map +1 -1
- package/dist/services/plugin-loader.js +27 -1
- package/dist/services/plugin-loader.js.map +1 -1
- package/dist/services/plugin-loader.worker-paths.d.ts +26 -0
- package/dist/services/plugin-loader.worker-paths.d.ts.map +1 -1
- package/dist/services/plugin-loader.worker-paths.js +0 -26
- package/dist/services/plugin-loader.worker-paths.js.map +1 -1
- package/dist/services/plugin-log-retention.d.ts.map +1 -1
- package/dist/services/plugin-log-retention.js +1 -1
- package/dist/services/plugin-log-retention.js.map +1 -1
- package/dist/services/plugin-manifest-validator.d.ts +11 -0
- package/dist/services/plugin-manifest-validator.d.ts.map +1 -1
- package/dist/services/plugin-manifest-validator.js +1 -13
- package/dist/services/plugin-manifest-validator.js.map +1 -1
- package/dist/services/plugin-registry.d.ts +35 -35
- package/dist/services/plugin-registry.d.ts.map +1 -1
- package/dist/services/plugin-registry.js +2 -2
- package/dist/services/plugin-registry.js.map +1 -1
- package/dist/services/plugin-runtime-sandbox.d.ts.map +1 -1
- package/dist/services/plugin-runtime-sandbox.js.map +1 -1
- package/dist/services/plugin-secrets-handler.d.ts.map +1 -1
- package/dist/services/plugin-secrets-handler.js +1 -1
- package/dist/services/plugin-secrets-handler.js.map +1 -1
- package/dist/services/plugin-state-store.d.ts +1 -1
- package/dist/services/plugin-state-store.d.ts.map +1 -1
- package/dist/services/plugin-state-store.js +1 -1
- package/dist/services/plugin-state-store.js.map +1 -1
- package/dist/services/plugin-tool-dispatcher.d.ts +3 -3
- package/dist/services/plugin-tool-dispatcher.d.ts.map +1 -1
- package/dist/services/plugin-tool-dispatcher.js +2 -2
- package/dist/services/plugin-tool-dispatcher.js.map +1 -1
- package/dist/services/plugin-tool-registry.d.ts +1 -1
- package/dist/services/plugin-tool-registry.d.ts.map +1 -1
- package/dist/services/plugin-tool-registry.js.map +1 -1
- package/dist/services/plugin-worker-manager.d.ts +1 -1
- package/dist/services/plugin-worker-manager.d.ts.map +1 -1
- package/dist/services/plugin-worker-manager.js +1 -1
- package/dist/services/plugin-worker-manager.js.map +1 -1
- package/dist/services/product-intelligence.d.ts +1 -1
- package/dist/services/product-intelligence.d.ts.map +1 -1
- package/dist/services/product-intelligence.js +3 -3
- package/dist/services/product-intelligence.js.map +1 -1
- package/dist/services/projects.d.ts +4 -4
- package/dist/services/projects.d.ts.map +1 -1
- package/dist/services/projects.js +6 -6
- package/dist/services/projects.js.map +1 -1
- package/dist/services/resource-catalog.d.ts +1 -1
- package/dist/services/resource-catalog.d.ts.map +1 -1
- package/dist/services/resource-catalog.js +1 -1
- package/dist/services/resource-catalog.js.map +1 -1
- package/dist/services/run-intelligence.d.ts.map +1 -1
- package/dist/services/run-intelligence.js +2 -2
- package/dist/services/run-intelligence.js.map +1 -1
- package/dist/services/run-log-store.js +1 -1
- package/dist/services/run-log-store.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.core.d.ts +9 -3
- package/dist/services/runtime-kernel/heartbeat.core.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.core.js +29 -5
- package/dist/services/runtime-kernel/heartbeat.core.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.d.ts +8 -8
- package/dist/services/runtime-kernel/heartbeat.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.execute.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.execute.js +11 -25
- package/dist/services/runtime-kernel/heartbeat.execute.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.js +67 -27
- package/dist/services/runtime-kernel/heartbeat.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.misc.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.misc.js +3 -3
- package/dist/services/runtime-kernel/heartbeat.misc.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.recovery.d.ts +1 -1
- package/dist/services/runtime-kernel/heartbeat.recovery.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.recovery.js +13 -6
- package/dist/services/runtime-kernel/heartbeat.recovery.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.release.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.release.js +6 -5
- package/dist/services/runtime-kernel/heartbeat.release.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.sessions.d.ts +5 -3
- package/dist/services/runtime-kernel/heartbeat.sessions.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.sessions.js +8 -8
- package/dist/services/runtime-kernel/heartbeat.sessions.js.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.wakeup.d.ts.map +1 -1
- package/dist/services/runtime-kernel/heartbeat.wakeup.js +24 -5
- package/dist/services/runtime-kernel/heartbeat.wakeup.js.map +1 -1
- package/dist/services/secrets.d.ts +15 -15
- package/dist/services/secrets.d.ts.map +1 -1
- package/dist/services/secrets.js +1 -1
- package/dist/services/secrets.js.map +1 -1
- package/dist/services/sidebar-badges.d.ts.map +1 -1
- package/dist/services/sidebar-badges.js +1 -1
- package/dist/services/sidebar-badges.js.map +1 -1
- package/dist/services/work-products.d.ts.map +1 -1
- package/dist/services/work-products.js +1 -1
- package/dist/services/work-products.js.map +1 -1
- package/dist/services/workspace-backups.d.ts.map +1 -1
- package/dist/services/workspace-backups.js +5 -5
- package/dist/services/workspace-backups.js.map +1 -1
- package/dist/services/workspace-operation-log-store.js +1 -1
- package/dist/services/workspace-operation-log-store.js.map +1 -1
- package/dist/services/workspace-operations.d.ts.map +1 -1
- package/dist/services/workspace-operations.js +2 -2
- package/dist/services/workspace-operations.js.map +1 -1
- package/dist/services/workspace-runtime.comments.d.ts.map +1 -1
- package/dist/services/workspace-runtime.comments.js.map +1 -1
- package/dist/services/workspace-runtime.d.ts +1 -1
- package/dist/services/workspace-runtime.d.ts.map +1 -1
- package/dist/services/workspace-runtime.helpers.d.ts +1 -1
- package/dist/services/workspace-runtime.helpers.d.ts.map +1 -1
- package/dist/services/workspace-runtime.helpers.js +2 -2
- package/dist/services/workspace-runtime.helpers.js.map +1 -1
- package/dist/services/workspace-runtime.js +1 -1
- package/dist/services/workspace-runtime.js.map +1 -1
- package/dist/services/workspace-runtime.lifecycle.d.ts +1 -1
- package/dist/services/workspace-runtime.lifecycle.d.ts.map +1 -1
- package/dist/services/workspace-runtime.lifecycle.js +1 -1
- package/dist/services/workspace-runtime.lifecycle.js.map +1 -1
- package/dist/services/workspace-runtime.services.d.ts +6 -6
- package/dist/services/workspace-runtime.services.d.ts.map +1 -1
- package/dist/services/workspace-runtime.services.js +4 -4
- package/dist/services/workspace-runtime.services.js.map +1 -1
- package/dist/startup-banner.d.ts.map +1 -1
- package/dist/startup-banner.js.map +1 -1
- package/dist/storage/index.d.ts +1 -1
- package/dist/storage/index.d.ts.map +1 -1
- package/dist/storage/local-disk-provider.d.ts.map +1 -1
- package/dist/storage/local-disk-provider.js +1 -1
- package/dist/storage/local-disk-provider.js.map +1 -1
- package/dist/storage/provider-registry.d.ts.map +1 -1
- package/dist/storage/provider-registry.js.map +1 -1
- package/dist/storage/s3-provider.d.ts.map +1 -1
- package/dist/storage/s3-provider.js +1 -1
- package/dist/storage/s3-provider.js.map +1 -1
- package/dist/storage/service.d.ts +1 -1
- package/dist/storage/service.d.ts.map +1 -1
- package/dist/storage/service.js.map +1 -1
- package/package.json +13 -13
- package/resources/bundled-skills/rudder/SKILL.md +6 -5
- package/resources/bundled-skills/rudder/references/api-reference.md +2 -12
- package/resources/bundled-skills/rudder/references/cli-reference.md +27 -6
- package/skills/rudder/SKILL.md +6 -5
- package/skills/rudder/references/api-reference.md +2 -12
- package/skills/rudder/references/cli-reference.md +27 -6
- package/ui-dist/assets/{_basePickBy-Cr8zzDbY.js → _basePickBy-BPRkwn03.js} +1 -1
- package/ui-dist/assets/{_baseUniq-sD0Whj9u.js → _baseUniq-DBQR9K7D.js} +1 -1
- package/ui-dist/assets/{arc-BHjxNXC2.js → arc-BYIbqxoe.js} +1 -1
- package/ui-dist/assets/{architectureDiagram-2XIMDMQ5-CK0OHS--.js → architectureDiagram-2XIMDMQ5-DC-g3dJW.js} +1 -1
- package/ui-dist/assets/{blockDiagram-WCTKOSBZ-Cj74W9ef.js → blockDiagram-WCTKOSBZ-DjMs5Kif.js} +1 -1
- package/ui-dist/assets/{c4Diagram-IC4MRINW-iMyvchZG.js → c4Diagram-IC4MRINW-EyC6gNun.js} +1 -1
- package/ui-dist/assets/channel-sNdKb0qJ.js +1 -0
- package/ui-dist/assets/{chunk-4BX2VUAB-BPwzDxYB.js → chunk-4BX2VUAB-CqQwdCeK.js} +1 -1
- package/ui-dist/assets/{chunk-55IACEB6-_FH_K0SO.js → chunk-55IACEB6-2JH1ABLK.js} +1 -1
- package/ui-dist/assets/{chunk-FMBD7UC4-BFIjA8FP.js → chunk-FMBD7UC4-DmW8SDqH.js} +1 -1
- package/ui-dist/assets/{chunk-JSJVCQXG-pH62tQGL.js → chunk-JSJVCQXG-mBPGwgWA.js} +1 -1
- package/ui-dist/assets/{chunk-KX2RTZJC-twNpyPKA.js → chunk-KX2RTZJC-C7_J4HUu.js} +1 -1
- package/ui-dist/assets/{chunk-NQ4KR5QH-Cy9BRkAh.js → chunk-NQ4KR5QH-D21euHqO.js} +1 -1
- package/ui-dist/assets/{chunk-QZHKN3VN-n2MyJCAq.js → chunk-QZHKN3VN-BxPMlCBD.js} +1 -1
- package/ui-dist/assets/{chunk-WL4C6EOR-CieOZbkn.js → chunk-WL4C6EOR-BdAFsuJD.js} +1 -1
- package/ui-dist/assets/classDiagram-VBA2DB6C-DmZPXQmS.js +1 -0
- package/ui-dist/assets/classDiagram-v2-RAHNMMFH-DmZPXQmS.js +1 -0
- package/ui-dist/assets/clone-rGjXd_wj.js +1 -0
- package/ui-dist/assets/{cose-bilkent-S5V4N54A-DhyzxJrx.js → cose-bilkent-S5V4N54A-BJ287iyG.js} +1 -1
- package/ui-dist/assets/{dagre-KLK3FWXG-wYfBR59B.js → dagre-KLK3FWXG-BYzByszW.js} +1 -1
- package/ui-dist/assets/{diagram-E7M64L7V-CligHPmt.js → diagram-E7M64L7V-DrQFnpHJ.js} +1 -1
- package/ui-dist/assets/{diagram-IFDJBPK2-Dj5JBdLX.js → diagram-IFDJBPK2-CNESvgjr.js} +1 -1
- package/ui-dist/assets/{diagram-P4PSJMXO-k686w084.js → diagram-P4PSJMXO-49Y767wW.js} +1 -1
- package/ui-dist/assets/{erDiagram-INFDFZHY-fAIWdT-B.js → erDiagram-INFDFZHY-BqtmGrS0.js} +1 -1
- package/ui-dist/assets/{flowDiagram-PKNHOUZH-B1vePt_l.js → flowDiagram-PKNHOUZH-VLhK5NS_.js} +1 -1
- package/ui-dist/assets/{ganttDiagram-A5KZAMGK-D3cVARoP.js → ganttDiagram-A5KZAMGK-Cp1UIECL.js} +1 -1
- package/ui-dist/assets/{gitGraphDiagram-K3NZZRJ6-BGECirgR.js → gitGraphDiagram-K3NZZRJ6-DcL8-75k.js} +1 -1
- package/ui-dist/assets/{graph-CitETerh.js → graph-C-DbOsvM.js} +1 -1
- package/ui-dist/assets/index-23iQQg93.css +1 -0
- package/ui-dist/assets/{index-SNOKb8Lq.js → index-51JHVpQz.js} +1 -1
- package/ui-dist/assets/{index-BcXjXI3h.js → index-AnNz902h.js} +1 -1
- package/ui-dist/assets/{index-DgtF8cey.js → index-BSCpraJI.js} +1 -1
- package/ui-dist/assets/{index-B_MpcRv7.js → index-Bo7Gr_4F.js} +1 -1
- package/ui-dist/assets/{index-DoqsEVd2.js → index-C65_RJTd.js} +1 -1
- package/ui-dist/assets/{index-MwWNRW28.js → index-C94nVjFS.js} +1 -1
- package/ui-dist/assets/index-CNJsvAmo.js +1712 -0
- package/ui-dist/assets/{index-CrCa30X7.js → index-CZcPZRaZ.js} +1 -1
- package/ui-dist/assets/{index-Lptt6HJM.js → index-Cavm1jhe.js} +1 -1
- package/ui-dist/assets/{index-BBslbLws.js → index-Cd3CeR9B.js} +1 -1
- package/ui-dist/assets/{index-CX_Nv9eH.js → index-D2lmj_Wi.js} +1 -1
- package/ui-dist/assets/{index-CZ--q7C7.js → index-DAUBjX0S.js} +1 -1
- package/ui-dist/assets/{index-BITqgNJ0.js → index-DE6bzapv.js} +1 -1
- package/ui-dist/assets/{index-BTtCiPJT.js → index-DIdXyFF1.js} +1 -1
- package/ui-dist/assets/{index-uz2Loz1p.js → index-DLe4_NmT.js} +1 -1
- package/ui-dist/assets/{index-COE8i92O.js → index-DOAgdza1.js} +1 -1
- package/ui-dist/assets/{index-C6xB50WP.js → index-DOucVPsN.js} +1 -1
- package/ui-dist/assets/{index-CJNNfwef.js → index-DUz5QMs0.js} +1 -1
- package/ui-dist/assets/{index-D_DX6X_n.js → index-DbQEfeoc.js} +1 -1
- package/ui-dist/assets/{index-BKgKy7Ci.js → index-DhvVLWir.js} +1 -1
- package/ui-dist/assets/{index-BqKR7vYO.js → index-DwX198fD.js} +1 -1
- package/ui-dist/assets/{index-DF0QiJ_N.js → index-YL127VRA.js} +1 -1
- package/ui-dist/assets/{index-BX_WUzlG.js → index-bF3w-vTG.js} +1 -1
- package/ui-dist/assets/{infoDiagram-LFFYTUFH-Boi_eI6L.js → infoDiagram-LFFYTUFH-BunmB59m.js} +1 -1
- package/ui-dist/assets/{ishikawaDiagram-PHBUUO56-C69Ojbf-.js → ishikawaDiagram-PHBUUO56-Bqo2Qo1y.js} +1 -1
- package/ui-dist/assets/{journeyDiagram-4ABVD52K-CXmWDWGR.js → journeyDiagram-4ABVD52K-CI8V5kqJ.js} +1 -1
- package/ui-dist/assets/{kanban-definition-K7BYSVSG-D423ukIe.js → kanban-definition-K7BYSVSG-BY7W4sUd.js} +1 -1
- package/ui-dist/assets/{layout-BVo--R6n.js → layout-JtFLKgO4.js} +1 -1
- package/ui-dist/assets/{linear-CEf5D25b.js → linear-B7R0ROgK.js} +1 -1
- package/ui-dist/assets/{mermaid.core-B8yXIuCH.js → mermaid.core-CcvtmLjq.js} +4 -4
- package/ui-dist/assets/{mindmap-definition-YRQLILUH-66pKVDF8.js → mindmap-definition-YRQLILUH-BKWcrBN1.js} +1 -1
- package/ui-dist/assets/{pieDiagram-SKSYHLDU-By38UzxE.js → pieDiagram-SKSYHLDU-CClvXL3w.js} +1 -1
- package/ui-dist/assets/{quadrantDiagram-337W2JSQ-BEHUqp8_.js → quadrantDiagram-337W2JSQ-ttcVtMi-.js} +1 -1
- package/ui-dist/assets/{requirementDiagram-Z7DCOOCP-DiPaMDtR.js → requirementDiagram-Z7DCOOCP-Dh0cBE6s.js} +1 -1
- package/ui-dist/assets/{sankeyDiagram-WA2Y5GQK-BJd3QbX3.js → sankeyDiagram-WA2Y5GQK-CNqLZ6mV.js} +1 -1
- package/ui-dist/assets/{sequenceDiagram-2WXFIKYE-elkh6FQM.js → sequenceDiagram-2WXFIKYE-CShv-7OP.js} +1 -1
- package/ui-dist/assets/{stateDiagram-RAJIS63D-pt5sgZAG.js → stateDiagram-RAJIS63D-CSsjNqey.js} +1 -1
- package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-77i_CVwh.js +1 -0
- package/ui-dist/assets/{timeline-definition-YZTLITO2-nyY-lfGa.js → timeline-definition-YZTLITO2-Ce7IADXF.js} +1 -1
- package/ui-dist/assets/{treemap-KZPCXAKY-C7O2CmPl.js → treemap-KZPCXAKY-BwNplvh2.js} +1 -1
- package/ui-dist/assets/{vennDiagram-LZ73GAT5-DUVr0M6o.js → vennDiagram-LZ73GAT5-DWELrMWt.js} +1 -1
- package/ui-dist/assets/{xychartDiagram-JWTSCODW-CBzsesTY.js → xychartDiagram-JWTSCODW-Lo_wyfIy.js} +1 -1
- package/ui-dist/index.html +2 -2
- package/ui-dist/assets/channel-De6pTrlE.js +0 -1
- package/ui-dist/assets/classDiagram-VBA2DB6C-Ce1zW86h.js +0 -1
- package/ui-dist/assets/classDiagram-v2-RAHNMMFH-Ce1zW86h.js +0 -1
- package/ui-dist/assets/clone-3fuEDoMn.js +0 -1
- package/ui-dist/assets/index-QrTAKEQ-.css +0 -1
- package/ui-dist/assets/index-w5fCPWtS.js +0 -1615
- package/ui-dist/assets/stateDiagram-v2-FVOUBMTO-DzUwSA1C.js +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register-api-routes.d.ts","sourceRoot":"","sources":["../../src/bootstrap/register-api-routes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"register-api-routes.d.ts","sourceRoot":"","sources":["../../src/bootstrap/register-api-routes.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,EAAE,EAAE,MAAM,cAAc,CAAC;AA2BvC,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAEnD,wBAAgB,iBAAiB,CAC/B,EAAE,EAAE,EAAE,EACN,IAAI,EAAE,gBAAgB,EACtB,aAAa,EAAE,iBAAiB,8CA0DjC"}
|
|
@@ -13,6 +13,7 @@ import { dashboardRoutes } from "../routes/dashboard.js";
|
|
|
13
13
|
import { runWorkspaceRoutes } from "../routes/execution-workspaces.js";
|
|
14
14
|
import { goalRoutes } from "../routes/goals.js";
|
|
15
15
|
import { healthRoutes } from "../routes/health.js";
|
|
16
|
+
import { instanceSettingsRoutes } from "../routes/instance-settings.js";
|
|
16
17
|
import { issueRoutes } from "../routes/issues.js";
|
|
17
18
|
import { messengerRoutes } from "../routes/messenger.js";
|
|
18
19
|
import { onboardingRoutes } from "../routes/onboarding.js";
|
|
@@ -23,7 +24,6 @@ import { projectRoutes } from "../routes/projects.js";
|
|
|
23
24
|
import { runIntelligenceRoutes } from "../routes/run-intelligence.js";
|
|
24
25
|
import { secretRoutes } from "../routes/secrets.js";
|
|
25
26
|
import { sidebarBadgeRoutes } from "../routes/sidebar-badges.js";
|
|
26
|
-
import { instanceSettingsRoutes } from "../routes/instance-settings.js";
|
|
27
27
|
export function registerApiRoutes(db, opts, pluginRuntime) {
|
|
28
28
|
const api = Router();
|
|
29
29
|
api.use(boardMutationGuard());
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"register-api-routes.js","sourceRoot":"","sources":["../../src/bootstrap/register-api-routes.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"register-api-routes.js","sourceRoot":"","sources":["../../src/bootstrap/register-api-routes.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { Request, RequestHandler } from "express";
|
|
2
1
|
import type { DeploymentExposure, DeploymentMode } from "@rudderhq/shared";
|
|
3
|
-
import type {
|
|
2
|
+
import type { Request, RequestHandler } from "express";
|
|
4
3
|
import type { BetterAuthSessionResult } from "../auth/better-auth.js";
|
|
4
|
+
import type { StorageService } from "../storage/types.js";
|
|
5
5
|
export type UiMode = "none" | "static" | "vite-dev";
|
|
6
6
|
export interface RudderAppOptions {
|
|
7
7
|
uiMode: UiMode;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/bootstrap/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/bootstrap/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,cAAc,EAAE,MAAM,kBAAkB,CAAC;AAC3E,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AACvD,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACtE,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAC;AAE1D,MAAM,MAAM,MAAM,GAAG,MAAM,GAAG,QAAQ,GAAG,UAAU,CAAC;AAEpD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,cAAc,EAAE,cAAc,CAAC;IAC/B,cAAc,EAAE,cAAc,CAAC;IAC/B,kBAAkB,EAAE,kBAAkB,CAAC;IACvC,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,OAAO,CAAC;IACnB,sBAAsB,EAAE,OAAO,CAAC;IAChC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iBAAiB,CAAC,EAAE,cAAc,CAAC;IACnC,cAAc,CAAC,EAAE,CAAC,GAAG,EAAE,OAAO,KAAK,OAAO,CAAC,uBAAuB,GAAG,IAAI,CAAC,CAAC;CAC5E"}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
// src/ui/index.tsx
|
|
2
|
-
import {
|
|
3
|
-
useEffect,
|
|
4
|
-
useMemo,
|
|
5
|
-
useState
|
|
6
|
-
} from "react";
|
|
7
2
|
import {
|
|
8
3
|
usePluginAction,
|
|
9
4
|
usePluginData,
|
|
10
5
|
usePluginToast
|
|
11
6
|
} from "@rudderhq/plugin-sdk/ui";
|
|
7
|
+
import {
|
|
8
|
+
useEffect,
|
|
9
|
+
useMemo,
|
|
10
|
+
useState
|
|
11
|
+
} from "react";
|
|
12
12
|
|
|
13
13
|
// src/constants.ts
|
|
14
14
|
var LINEAR_TOKEN_SETTINGS_URL = "https://linear.app/settings/account/security";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"version": 3,
|
|
3
3
|
"sources": ["../../src/ui/index.tsx", "../../src/constants.ts"],
|
|
4
|
-
"sourcesContent": ["import {\n useEffect,\n useMemo,\n useState,\n type Dispatch,\n type SetStateAction,\n type CSSProperties,\n} from \"react\";\nimport {\n usePluginAction,\n usePluginData,\n usePluginToast,\n type PluginDetailTabProps,\n type PluginPageProps,\n type PluginSettingsPageProps,\n} from \"@rudderhq/plugin-sdk/ui\";\nimport {\n ACTION_KEYS,\n DATA_KEYS,\n LINEAR_IMPORT_ALL_LIMIT,\n LINEAR_PAGE_SIZE,\n LINEAR_TOKEN_SETTINGS_URL,\n RUDDER_STATUS_OPTIONS,\n} from \"../constants.js\";\nimport type {\n ImportLinearIssuesActionResult,\n IssueLinkData,\n LinearIssueRow,\n LinearCatalogData,\n LinearOrganizationMapping,\n LinearPluginConfig,\n LinearStateSummary,\n LinearStateMapping,\n LinearTeamMapping,\n LinearIssuesData,\n PageBootstrapData,\n SettingsCatalogData,\n SettingsBootstrapData,\n} from \"../types.js\";\n\nconst layoutStyles: Record<string, CSSProperties> = {\n shell: {\n display: \"grid\",\n gap: 16,\n color: \"var(--foreground, #111827)\",\n fontFamily: \"ui-sans-serif, system-ui, sans-serif\",\n },\n card: {\n border: \"1px solid var(--border, rgba(15, 23, 42, 0.14))\",\n borderRadius: 8,\n padding: 16,\n background: \"var(--card, var(--background, #fff))\",\n },\n title: {\n fontSize: 22,\n fontWeight: 700,\n margin: 0,\n },\n subtitle: {\n margin: \"6px 0 0\",\n color: \"var(--muted-foreground, rgba(15, 23, 42, 0.68))\",\n fontSize: 14,\n lineHeight: 1.5,\n },\n row: {\n display: \"flex\",\n gap: 12,\n flexWrap: \"wrap\",\n alignItems: \"center\",\n },\n connectionGrid: {\n display: \"grid\",\n gridTemplateColumns: \"repeat(auto-fit, minmax(220px, 1fr))\",\n gap: 12,\n alignItems: \"end\",\n },\n field: {\n display: \"grid\",\n gap: 6,\n minWidth: 180,\n flex: \"1 1 180px\",\n },\n label: {\n fontSize: 12,\n fontWeight: 700,\n color: \"var(--muted-foreground, rgba(15, 23, 42, 0.66))\",\n letterSpacing: 0,\n },\n input: {\n width: \"100%\",\n border: \"1px solid var(--border, rgba(15, 23, 42, 0.18))\",\n borderRadius: 6,\n padding: \"10px 12px\",\n fontSize: 14,\n background: \"var(--background, #fff)\",\n color: \"var(--foreground, #111827)\",\n boxSizing: \"border-box\",\n },\n select: {\n width: \"100%\",\n border: \"1px solid var(--border, rgba(15, 23, 42, 0.18))\",\n borderRadius: 6,\n padding: \"10px 12px\",\n fontSize: 14,\n background: \"var(--background, #fff)\",\n color: \"var(--foreground, #111827)\",\n boxSizing: \"border-box\",\n },\n button: {\n border: \"1px solid var(--border, rgba(15, 23, 42, 0.18))\",\n borderRadius: 6,\n padding: \"10px 14px\",\n fontSize: 14,\n fontWeight: 600,\n background: \"var(--background, #fff)\",\n color: \"var(--foreground, #111827)\",\n cursor: \"pointer\",\n },\n primaryButton: {\n border: \"1px solid var(--primary, #0f172a)\",\n borderRadius: 6,\n padding: \"10px 14px\",\n fontSize: 14,\n fontWeight: 700,\n background: \"var(--primary, #0f172a)\",\n color: \"var(--primary-foreground, #fff)\",\n cursor: \"pointer\",\n },\n subtleButton: {\n border: \"1px solid var(--border, rgba(15, 23, 42, 0.12))\",\n borderRadius: 6,\n padding: \"8px 12px\",\n fontSize: 13,\n fontWeight: 600,\n background: \"var(--secondary, rgba(15, 23, 42, 0.04))\",\n color: \"var(--secondary-foreground, var(--foreground, #111827))\",\n cursor: \"pointer\",\n },\n warning: {\n border: \"1px solid rgba(217, 119, 6, 0.24)\",\n background: \"rgba(251, 191, 36, 0.12)\",\n borderRadius: 8,\n padding: 14,\n fontSize: 14,\n lineHeight: 1.5,\n },\n table: {\n width: \"100%\",\n borderCollapse: \"collapse\",\n fontSize: 14,\n },\n th: {\n textAlign: \"left\",\n fontSize: 12,\n letterSpacing: 0,\n color: \"var(--muted-foreground, rgba(15, 23, 42, 0.62))\",\n padding: \"10px 12px\",\n borderBottom: \"1px solid var(--border, rgba(15, 23, 42, 0.1))\",\n },\n td: {\n padding: \"12px\",\n borderBottom: \"1px solid var(--border, rgba(15, 23, 42, 0.08))\",\n verticalAlign: \"top\",\n },\n pill: {\n display: \"inline-flex\",\n alignItems: \"center\",\n borderRadius: 999,\n padding: \"4px 10px\",\n background: \"var(--secondary, rgba(15, 23, 42, 0.06))\",\n color: \"var(--secondary-foreground, var(--foreground, #111827))\",\n fontSize: 12,\n fontWeight: 600,\n },\n monoLink: {\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n fontSize: 12,\n },\n helpText: {\n fontSize: 13,\n lineHeight: 1.5,\n color: \"var(--muted-foreground, rgba(15, 23, 42, 0.68))\",\n },\n statusLine: {\n marginTop: 14,\n paddingTop: 14,\n borderTop: \"1px solid var(--border, rgba(15, 23, 42, 0.1))\",\n fontSize: 13,\n lineHeight: 1.5,\n color: \"var(--muted-foreground, rgba(15, 23, 42, 0.68))\",\n },\n sectionHeader: {\n display: \"flex\",\n justifyContent: \"space-between\",\n gap: 12,\n alignItems: \"flex-start\",\n flexWrap: \"wrap\",\n },\n teamGrid: {\n display: \"grid\",\n gridTemplateColumns: \"repeat(auto-fit, minmax(220px, 1fr))\",\n gap: 10,\n marginTop: 14,\n },\n teamChoice: {\n display: \"flex\",\n gap: 10,\n alignItems: \"flex-start\",\n border: \"1px solid var(--border, rgba(15, 23, 42, 0.14))\",\n borderRadius: 8,\n padding: 12,\n cursor: \"pointer\",\n background: \"var(--background, transparent)\",\n },\n checkbox: {\n marginTop: 3,\n },\n statusRuleGrid: {\n display: \"grid\",\n gridTemplateColumns: \"repeat(auto-fit, minmax(180px, 1fr))\",\n gap: 10,\n alignItems: \"center\",\n },\n};\n\nconst LINEAR_TOKEN_SECRET_NAME = \"Linear token\";\n\ntype SecretSummary = {\n id: string;\n name: string;\n};\n\nfunction normalizeConfig(config: LinearPluginConfig | null | undefined): LinearPluginConfig {\n const legacyOrganizationMappings = Array.isArray(config?.organizationMappings) ? config.organizationMappings : [];\n const explicitTeamMappings = Array.isArray(config?.teamMappings) ? config.teamMappings : [];\n return {\n apiTokenSecretRef: config?.apiTokenSecretRef ?? \"\",\n teamMappings: explicitTeamMappings.length > 0\n ? explicitTeamMappings\n : mergeLegacyTeamMappings(legacyOrganizationMappings),\n organizationMappings: legacyOrganizationMappings,\n ...(config?.fixtureMode === true ? { fixtureMode: true } : {}),\n };\n}\n\nfunction mergeLegacyTeamMappings(mappings: LinearOrganizationMapping[]): LinearTeamMapping[] {\n const byTeamId = new Map<string, LinearTeamMapping>();\n for (const mapping of mappings) {\n for (const team of mapping.teamMappings ?? []) {\n if (!team.teamId || byTeamId.has(team.teamId)) continue;\n byTeamId.set(team.teamId, team);\n }\n }\n return [...byTeamId.values()];\n}\n\nfunction getOrgPrefix(context: Record<string, unknown>): string | null {\n const orgPrefix = typeof context[\"orgPrefix\"] === \"string\" ? context[\"orgPrefix\"] : null;\n const companyPrefix = typeof context[\"companyPrefix\"] === \"string\" ? context[\"companyPrefix\"] : null;\n return orgPrefix ?? companyPrefix;\n}\n\nfunction getPluginIdFromLocation(): string | null {\n if (typeof window === \"undefined\") return null;\n const match = window.location.pathname.match(/\\/instance\\/settings\\/plugins\\/([^/?#]+)/);\n return match?.[1] ?? null;\n}\n\nasync function apiFetch<T>(path: string, init?: RequestInit): Promise<T> {\n const response = await fetch(path, {\n credentials: \"same-origin\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(init?.headers ?? {}),\n },\n ...init,\n });\n if (!response.ok) {\n const payload = await response.json().catch(async () => ({ error: await response.text() }));\n const message = typeof payload?.error === \"string\"\n ? payload.error\n : typeof payload?.message === \"string\"\n ? payload.message\n : `Request failed (${response.status})`;\n throw new Error(message);\n }\n return await response.json() as T;\n}\n\nfunction formatRudderStatus(status: LinearStateMapping[\"rudderStatus\"]): string {\n return status.replaceAll(\"_\", \" \");\n}\n\nfunction inferRudderStatus(state: LinearStateSummary): LinearStateMapping[\"rudderStatus\"] {\n const type = (state.type ?? \"\").toLowerCase();\n const name = state.name.toLowerCase();\n if (type.includes(\"completed\") || name.includes(\"done\") || name.includes(\"complete\")) return \"done\";\n if (type.includes(\"cancel\") || name.includes(\"cancel\")) return \"cancelled\";\n if (name.includes(\"review\")) return \"in_review\";\n if (type.includes(\"backlog\") || type.includes(\"triage\") || name.includes(\"backlog\") || name.includes(\"triage\")) return \"backlog\";\n if (type.includes(\"started\") || type.includes(\"unstarted\") || name.includes(\"progress\") || name.includes(\"todo\")) return \"todo\";\n return \"backlog\";\n}\n\nfunction buildTeamMappingsFromCatalog(catalog: SettingsCatalogData): LinearTeamMapping[] {\n return catalog.teams.map((team) => buildTeamMappingFromCatalog(team));\n}\n\nfunction buildTeamMappingFromCatalog(\n team: SettingsCatalogData[\"teams\"][number],\n existing?: LinearTeamMapping | null,\n): LinearTeamMapping {\n const existingStatusByStateId = new Map(\n (existing?.stateMappings ?? []).map((state) => [state.linearStateId, state.rudderStatus]),\n );\n return {\n teamId: team.id,\n teamName: team.name,\n stateMappings: team.states.map((state) => ({\n linearStateId: state.id,\n linearStateName: state.name,\n rudderStatus: existingStatusByStateId.get(state.id) ?? inferRudderStatus(state),\n })),\n };\n}\n\nfunction buildTeamMappingsForSelectedTeams(\n catalog: SettingsCatalogData,\n selectedTeamIds: string[],\n existingTeamMappings: LinearTeamMapping[],\n): LinearTeamMapping[] {\n const selected = new Set(selectedTeamIds);\n const existingByTeamId = new Map(existingTeamMappings.map((team) => [team.teamId, team]));\n return catalog.teams\n .filter((team) => selected.has(team.id))\n .map((team) => buildTeamMappingFromCatalog(team, existingByTeamId.get(team.id)));\n}\n\nfunction countMappedStates(teamMappings: LinearTeamMapping[] | null | undefined): number {\n return teamMappings?.reduce((sum, team) => sum + team.stateMappings.length, 0) ?? 0;\n}\n\nfunction summarizeMapping(teamMappings: LinearTeamMapping[] | null | undefined): string {\n if (!teamMappings) return \"No Linear workspace loaded yet.\";\n const teamCount = teamMappings.length;\n const stateCount = countMappedStates(teamMappings);\n return `${teamCount} team${teamCount === 1 ? \"\" : \"s\"} and ${stateCount} workflow state${stateCount === 1 ? \"\" : \"s\"} ready.`;\n}\n\nfunction isMissingSettingsCatalogHandler(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return /No data handler registered/i.test(message) && /settings-catalog/i.test(message);\n}\n\nfunction prepareConfigForSubmit(config: LinearPluginConfig): LinearPluginConfig {\n const teamMappings = config.teamMappings\n .map((team) => ({\n teamId: team.teamId.trim(),\n teamName: team.teamName?.trim() || undefined,\n stateMappings: team.stateMappings\n .map((state) => ({\n linearStateId: state.linearStateId.trim(),\n linearStateName: state.linearStateName?.trim() || undefined,\n rudderStatus: state.rudderStatus,\n }))\n .filter((state) => state.linearStateId),\n }))\n .filter((team) => team.teamId);\n\n return {\n apiTokenSecretRef: config.apiTokenSecretRef?.trim() ?? \"\",\n ...(config.fixtureMode === true ? { fixtureMode: true } : {}),\n teamMappings,\n // Keep a legacy-compatible shape for already-installed manifests that still\n // require organizationMappings during config validation. New runtime code\n // reads the top-level teamMappings field.\n organizationMappings: teamMappings.length > 0 ? [{ orgId: \"__global__\", teamMappings }] : [],\n };\n}\n\nfunction summarizeImportResult(result: ImportLinearIssuesActionResult): string {\n const parts = [`Imported ${result.importedCount}`];\n if (result.duplicateCount > 0) parts.push(`${result.duplicateCount} duplicate`);\n if (result.fallbackCount > 0) parts.push(`${result.fallbackCount} fallback`);\n if (result.adjustedCount > 0) parts.push(`${result.adjustedCount} adjusted`);\n return parts.join(\" / \");\n}\n\nfunction formatRelativeTime(timestamp: string | null | undefined): string {\n if (!timestamp) return \"Unknown\";\n const date = new Date(timestamp);\n if (Number.isNaN(date.getTime())) return timestamp;\n return new Intl.DateTimeFormat(undefined, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n hourCycle: \"h23\",\n }).format(date);\n}\n\nfunction issueHref(orgPrefix: string | null, issueId: string): string {\n return orgPrefix ? `/${orgPrefix}/issues/${issueId}` : `/issues/${issueId}`;\n}\n\nfunction pageHref(orgPrefix: string | null, query?: string): string {\n if (!orgPrefix) return \"/linear\";\n const url = new URL(`/${orgPrefix}/linear`, \"https://local.invalid\");\n if (query) url.searchParams.set(\"q\", query);\n return `${url.pathname}${url.search}`;\n}\n\nfunction linearIssueBoardHref(orgPrefix: string | null | undefined, teamId?: string | null): string {\n const basePath = orgPrefix ? `/${encodeURIComponent(orgPrefix)}/issues` : \"/issues\";\n const url = new URL(basePath, \"https://local.invalid\");\n url.searchParams.set(\"source\", \"linear\");\n if (teamId) url.searchParams.set(\"linearTeamId\", teamId);\n return `${url.pathname}${url.search}`;\n}\n\nfunction readLinearPageUrlFilters() {\n if (typeof window === \"undefined\") {\n return { query: \"\", projectId: \"\", teamId: \"\" };\n }\n const params = new URLSearchParams(window.location.search);\n return {\n query: params.get(\"q\") ?? \"\",\n projectId: params.get(\"linearProjectId\") ?? \"\",\n teamId: params.get(\"linearTeamId\") ?? \"\",\n };\n}\n\ntype FilterState = {\n teamId: string;\n stateId: string;\n projectId: string;\n assigneeId: string;\n query: string;\n};\n\nfunction useLinearFilters(\n initialQuery: string,\n initialProjectId = \"\",\n initialTeamId = \"\",\n): [FilterState, Dispatch<SetStateAction<FilterState>>] {\n const [filters, setFilters] = useState<FilterState>({\n teamId: initialTeamId,\n stateId: \"\",\n projectId: initialProjectId,\n assigneeId: \"\",\n query: initialQuery,\n });\n return [filters, setFilters];\n}\n\nexport function LinearPluginPage({ context }: PluginPageProps) {\n const toast = usePluginToast();\n const importIssues = usePluginAction(ACTION_KEYS.importIssues) as (\n params?: Record<string, unknown>,\n ) => Promise<ImportLinearIssuesActionResult>;\n const orgId = context.orgId ?? \"__missing__\";\n const orgPrefix = getOrgPrefix(context as unknown as Record<string, unknown>);\n const urlFilters = readLinearPageUrlFilters();\n\n const bootstrap = usePluginData<PageBootstrapData>(DATA_KEYS.pageBootstrap, { orgId });\n const catalog = usePluginData<LinearCatalogData>(DATA_KEYS.catalog, { orgId });\n const [filters, setFilters] = useLinearFilters(urlFilters.query, urlFilters.projectId, urlFilters.teamId);\n const [targetProjectId, setTargetProjectId] = useState(\"\");\n const [afterCursor, setAfterCursor] = useState<string | null>(null);\n const [cursorHistory, setCursorHistory] = useState<string[]>([]);\n const [selectedIssueIds, setSelectedIssueIds] = useState<string[]>([]);\n const [importing, setImporting] = useState(false);\n\n const issues = usePluginData<LinearIssuesData>(DATA_KEYS.issues, {\n orgId,\n limit: LINEAR_PAGE_SIZE,\n after: afterCursor ?? undefined,\n teamId: filters.teamId || undefined,\n stateId: filters.stateId || undefined,\n projectId: filters.projectId || undefined,\n assigneeId: filters.assigneeId || undefined,\n query: filters.query || undefined,\n });\n\n useEffect(() => {\n setFilters((current) => {\n if (\n current.query === urlFilters.query &&\n current.projectId === urlFilters.projectId &&\n current.teamId === urlFilters.teamId\n ) {\n return current;\n }\n return {\n ...current,\n query: urlFilters.query,\n projectId: urlFilters.projectId,\n teamId: urlFilters.teamId,\n };\n });\n }, [setFilters, urlFilters.projectId, urlFilters.query, urlFilters.teamId]);\n\n const stateOptions = useMemo(() => {\n if (!catalog.data?.teams?.length) return [];\n const sourceTeams = filters.teamId\n ? catalog.data.teams.filter((team: LinearCatalogData[\"teams\"][number]) => team.id === filters.teamId)\n : catalog.data.teams;\n const deduped = new Map<string, { id: string; name: string }>();\n for (const team of sourceTeams) {\n for (const state of team.states) {\n deduped.set(state.id, { id: state.id, name: state.name });\n }\n }\n return [...deduped.values()];\n }, [catalog.data?.teams, filters.teamId]);\n\n useEffect(() => {\n setAfterCursor(null);\n setCursorHistory([]);\n setSelectedIssueIds([]);\n }, [filters.teamId, filters.stateId, filters.projectId, filters.assigneeId, filters.query]);\n\n useEffect(() => {\n const visibleIds = new Set(issues.data?.rows.map((row: LinearIssueRow) => row.id) ?? []);\n setSelectedIssueIds((current) => {\n const next = current.filter((id) => visibleIds.has(id));\n if (next.length === current.length && next.every((id, index) => id === current[index])) {\n return current;\n }\n return next;\n });\n }, [issues.data?.rows]);\n\n async function handleImport(mode: \"single\" | \"selected\" | \"allMatching\", issueIds?: string[]) {\n if (!targetProjectId) {\n toast({\n title: \"Choose a target project\",\n body: \"Imports are disabled until a Rudder project is selected.\",\n tone: \"warn\",\n });\n return;\n }\n setImporting(true);\n try {\n const result = await importIssues({\n orgId,\n targetProjectId,\n mode,\n issueIds,\n filters: {\n teamId: filters.teamId || undefined,\n stateId: filters.stateId || undefined,\n projectId: filters.projectId || undefined,\n assigneeId: filters.assigneeId || undefined,\n query: filters.query || undefined,\n },\n });\n toast({\n title: \"Linear import complete\",\n body: summarizeImportResult(result),\n tone: \"success\",\n });\n issues.refresh();\n setSelectedIssueIds([]);\n } catch (error) {\n toast({\n title: \"Linear import failed\",\n body: error instanceof Error ? error.message : String(error),\n tone: \"error\",\n });\n } finally {\n setImporting(false);\n }\n }\n\n return (\n <div style={layoutStyles.shell}>\n <section style={layoutStyles.card}>\n <h1 style={layoutStyles.title}>Linear intake</h1>\n <p style={layoutStyles.subtitle}>\n Import Linear issues into a chosen Rudder project. This page is the bulk workspace; the issue tab is the linked detail view.\n </p>\n </section>\n\n {bootstrap.loading ? (\n <section style={layoutStyles.card}>Loading Linear import context\u2026</section>\n ) : !bootstrap.data?.configured ? (\n <section style={{ ...layoutStyles.card, ...layoutStyles.warning }}>\n <strong>Linear is not configured yet.</strong>\n <div style={{ marginTop: 8 }}>{bootstrap.data?.message ?? \"Connect Linear and choose teams in plugin settings.\"}</div>\n <div style={{ marginTop: 12 }}>\n <a href=\"/instance/settings/plugins\" style={layoutStyles.monoLink}>Open plugin settings</a>\n </div>\n </section>\n ) : (\n <>\n <section style={layoutStyles.card}>\n <div style={layoutStyles.row}>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"target-project\">Target Rudder project</label>\n <select\n id=\"target-project\"\n data-testid=\"linear-target-project\"\n style={layoutStyles.select}\n value={targetProjectId}\n onChange={(event) => setTargetProjectId(event.target.value)}\n >\n <option value=\"\">Choose a project</option>\n {(bootstrap.data?.projects ?? []).map((project: PageBootstrapData[\"projects\"][number]) => (\n <option key={project.id} value={project.id}>{project.name}</option>\n ))}\n </select>\n </div>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"linear-team-filter\">Linear team</label>\n <select\n id=\"linear-team-filter\"\n style={layoutStyles.select}\n value={filters.teamId}\n onChange={(event) => setFilters((current) => ({ ...current, teamId: event.target.value, stateId: \"\" }))}\n >\n <option value=\"\">All allowed teams</option>\n {(catalog.data?.teams ?? []).map((team: LinearCatalogData[\"teams\"][number]) => (\n <option key={team.id} value={team.id}>{team.name}</option>\n ))}\n </select>\n </div>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"linear-state-filter\">Workflow state</label>\n <select\n id=\"linear-state-filter\"\n style={layoutStyles.select}\n value={filters.stateId}\n onChange={(event) => setFilters((current) => ({ ...current, stateId: event.target.value }))}\n >\n <option value=\"\">All states</option>\n {stateOptions.map((state) => (\n <option key={state.id} value={state.id}>{state.name}</option>\n ))}\n </select>\n </div>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"linear-project-filter\">Linear project</label>\n <select\n id=\"linear-project-filter\"\n style={layoutStyles.select}\n value={filters.projectId}\n onChange={(event) => setFilters((current) => ({ ...current, projectId: event.target.value }))}\n >\n <option value=\"\">All projects</option>\n {(catalog.data?.projects ?? []).map((project: LinearCatalogData[\"projects\"][number]) => (\n <option key={project.id} value={project.id}>{project.name}</option>\n ))}\n </select>\n </div>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"linear-assignee-filter\">Assignee</label>\n <select\n id=\"linear-assignee-filter\"\n style={layoutStyles.select}\n value={filters.assigneeId}\n onChange={(event) => setFilters((current) => ({ ...current, assigneeId: event.target.value }))}\n >\n <option value=\"\">Anyone</option>\n {(catalog.data?.users ?? []).map((user: LinearCatalogData[\"users\"][number]) => (\n <option key={user.id} value={user.id}>{user.name}</option>\n ))}\n </select>\n </div>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"linear-query-filter\">Search</label>\n <input\n id=\"linear-query-filter\"\n style={layoutStyles.input}\n value={filters.query}\n onChange={(event) => setFilters((current) => ({ ...current, query: event.target.value }))}\n placeholder=\"Identifier, title, or description\"\n />\n </div>\n </div>\n </section>\n\n <section style={layoutStyles.card}>\n <div style={{ ...layoutStyles.row, justifyContent: \"space-between\" }}>\n <div style={layoutStyles.row}>\n <button\n type=\"button\"\n style={layoutStyles.button}\n onClick={() => {\n const rows = issues.data?.rows ?? [];\n const selectableIds = rows\n .filter((row: LinearIssueRow) => !row.imported)\n .map((row: LinearIssueRow) => row.id);\n setSelectedIssueIds(selectableIds);\n }}\n disabled={issues.loading}\n >\n Select current page\n </button>\n <button\n type=\"button\"\n style={layoutStyles.button}\n onClick={() => setSelectedIssueIds([])}\n disabled={selectedIssueIds.length === 0}\n >\n Clear selection\n </button>\n </div>\n <div style={layoutStyles.row}>\n <button\n type=\"button\"\n style={layoutStyles.button}\n disabled={!targetProjectId || selectedIssueIds.length === 0 || importing}\n onClick={() => void handleImport(\"selected\", selectedIssueIds)}\n >\n Import selected\n </button>\n <button\n type=\"button\"\n style={layoutStyles.primaryButton}\n data-testid=\"linear-import-all\"\n disabled={!targetProjectId || importing}\n onClick={() => void handleImport(\"allMatching\")}\n title={`Imports up to ${LINEAR_IMPORT_ALL_LIMIT} matching issues.`}\n >\n Import all matching\n </button>\n </div>\n </div>\n {!targetProjectId && (\n <div style={{ marginTop: 12, ...layoutStyles.warning }}>\n Choose a target Rudder project to enable per-row, selected, or all-matching import actions.\n </div>\n )}\n </section>\n\n <section style={layoutStyles.card}>\n {issues.loading ? (\n <div>Loading Linear issues\u2026</div>\n ) : issues.error ? (\n <div style={layoutStyles.warning}>{issues.error.message}</div>\n ) : (\n <>\n <table style={layoutStyles.table}>\n <thead>\n <tr>\n <th style={layoutStyles.th}></th>\n <th style={layoutStyles.th}>Issue</th>\n <th style={layoutStyles.th}>State</th>\n <th style={layoutStyles.th}>Project</th>\n <th style={layoutStyles.th}>Assignee</th>\n <th style={layoutStyles.th}>Status</th>\n <th style={layoutStyles.th}>Action</th>\n </tr>\n </thead>\n <tbody>\n {(issues.data?.rows ?? []).map((row: LinearIssueRow) => {\n const checked = selectedIssueIds.includes(row.id);\n const sameOrgLink = row.imported && (!row.importedOrgId || row.importedOrgId === context.orgId);\n return (\n <tr key={row.id}>\n <td style={layoutStyles.td}>\n <input\n type=\"checkbox\"\n checked={checked}\n disabled={row.imported}\n onChange={(event) => {\n setSelectedIssueIds((current) => {\n if (event.target.checked) return [...current, row.id];\n return current.filter((id) => id !== row.id);\n });\n }}\n />\n </td>\n <td style={layoutStyles.td}>\n <div style={{ display: \"grid\", gap: 6 }}>\n <a href={row.url} target=\"_blank\" rel=\"noreferrer\">\n <strong>{row.identifier}</strong> {row.title}\n </a>\n <span style={layoutStyles.pill}>{row.team.name}</span>\n </div>\n </td>\n <td style={layoutStyles.td}>{row.state.name}</td>\n <td style={layoutStyles.td}>{row.project?.name ?? \"None\"}</td>\n <td style={layoutStyles.td}>{row.assignee?.name ?? \"Unassigned\"}</td>\n <td style={layoutStyles.td}>\n {row.imported ? (\n <span data-testid={`linear-imported-${row.id}`} style={layoutStyles.pill}>\n Imported\n </span>\n ) : (\n <span style={layoutStyles.pill}>Ready</span>\n )}\n </td>\n <td style={layoutStyles.td}>\n {row.imported ? (\n sameOrgLink && row.importedRudderIssueId ? (\n <a href={issueHref(orgPrefix, row.importedRudderIssueId)}>Open Rudder issue</a>\n ) : (\n <span>Imported elsewhere</span>\n )\n ) : (\n <button\n type=\"button\"\n style={layoutStyles.subtleButton}\n disabled={!targetProjectId || importing}\n onClick={() => void handleImport(\"single\", [row.id])}\n >\n Import\n </button>\n )}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n\n {(issues.data?.rows.length ?? 0) === 0 && (\n <div style={{ marginTop: 16, color: \"rgba(15, 23, 42, 0.68)\" }}>\n No Linear issues matched the current filters.\n </div>\n )}\n\n <div style={{ ...layoutStyles.row, justifyContent: \"space-between\", marginTop: 16 }}>\n <span style={{ fontSize: 13, color: \"rgba(15, 23, 42, 0.68)\" }}>\n Showing {issues.data?.totalShown ?? 0} issue(s).\n </span>\n <div style={layoutStyles.row}>\n <button\n type=\"button\"\n style={layoutStyles.button}\n disabled={cursorHistory.length === 0 || importing}\n onClick={() => {\n setCursorHistory((current) => {\n const nextHistory = [...current];\n const previousCursor = nextHistory.pop() ?? null;\n setAfterCursor(previousCursor);\n return nextHistory;\n });\n }}\n >\n Previous\n </button>\n <button\n type=\"button\"\n style={layoutStyles.button}\n disabled={!issues.data?.hasNextPage || importing}\n onClick={() => {\n if (!issues.data?.endCursor) return;\n setCursorHistory((current) => [...current, afterCursor ?? \"\"]);\n setAfterCursor(issues.data.endCursor);\n }}\n >\n Next\n </button>\n </div>\n </div>\n </>\n )}\n </section>\n </>\n )}\n </div>\n );\n}\n\nexport function LinearIssueTab({ context }: PluginDetailTabProps) {\n const orgId = context.orgId ?? \"__missing__\";\n const orgPrefix = getOrgPrefix(context as unknown as Record<string, unknown>);\n const data = usePluginData<IssueLinkData>(DATA_KEYS.issueLink, {\n orgId,\n issueId: context.entityId,\n });\n\n if (data.loading) {\n return <div style={layoutStyles.card}>Loading Linear issue details\u2026</div>;\n }\n\n if (data.error) {\n return <div style={{ ...layoutStyles.card, ...layoutStyles.warning }}>{data.error.message}</div>;\n }\n\n if (!data.data || !data.data.linked) {\n return (\n <div style={layoutStyles.card}>\n <h2 style={{ marginTop: 0 }}>No linked Linear issue</h2>\n <p style={layoutStyles.subtitle}>\n This Rudder issue has not been imported from Linear yet.\n </p>\n <a href={pageHref(orgPrefix, data.data?.searchQuery ?? \"\")}>Open Linear intake with this issue title as the search query</a>\n </div>\n );\n }\n\n const latest = data.data.latestIssue;\n const link = data.data.link;\n\n return (\n <div style={layoutStyles.shell}>\n <section style={layoutStyles.card}>\n <h2 style={{ marginTop: 0 }}>Linked Linear issue</h2>\n <p style={layoutStyles.subtitle}>\n {link.linearIdentifier} maps to this Rudder issue.\n </p>\n <div style={{ ...layoutStyles.row, marginTop: 12 }}>\n <a href={link.linearUrl} target=\"_blank\" rel=\"noreferrer\">Open in Linear</a>\n <span style={layoutStyles.pill}>{latest?.team.name ?? link.teamName}</span>\n <span style={layoutStyles.pill}>{latest?.state.name ?? link.stateName}</span>\n {latest?.project?.name ? <span style={layoutStyles.pill}>{latest.project.name}</span> : null}\n </div>\n </section>\n\n {data.data.staleReason ? (\n <section style={{ ...layoutStyles.card, ...layoutStyles.warning }}>\n {data.data.staleReason}\n </section>\n ) : null}\n\n <section style={layoutStyles.card}>\n <h3 style={{ marginTop: 0 }}>\n {(latest?.identifier ?? link.linearIdentifier)} {latest?.title ?? link.linearTitle}\n </h3>\n <div style={{ ...layoutStyles.row, marginBottom: 12 }}>\n <span style={layoutStyles.pill}>Updated {formatRelativeTime(latest?.updatedAt ?? link.updatedAt)}</span>\n <span style={layoutStyles.pill}>Imported {formatRelativeTime(link.importedAt)}</span>\n <span style={layoutStyles.pill}>{latest?.assignee?.name ?? \"Unassigned\"}</span>\n </div>\n <div style={{ whiteSpace: \"pre-wrap\", lineHeight: 1.6 }}>\n {latest?.description?.trim() || \"This Linear issue has no description.\"}\n </div>\n </section>\n </div>\n );\n}\n\nexport function LinearPluginSettingsPage(_props: PluginSettingsPageProps) {\n const toast = usePluginToast();\n const bootstrap = usePluginData<SettingsBootstrapData>(DATA_KEYS.settingsBootstrap);\n const [draft, setDraft] = useState<LinearPluginConfig>(normalizeConfig(null));\n const [tokenInput, setTokenInput] = useState(\"\");\n const [settingsCatalog, setSettingsCatalog] = useState<SettingsCatalogData | null>(null);\n const [catalogLoading, setCatalogLoading] = useState(false);\n const [catalogError, setCatalogError] = useState<string | null>(null);\n const [connecting, setConnecting] = useState(false);\n const [saving, setSaving] = useState(false);\n const pluginId = getPluginIdFromLocation();\n\n useEffect(() => {\n if (!bootstrap.data) return;\n const nextDraft = normalizeConfig(bootstrap.data.config);\n setDraft(nextDraft);\n }, [bootstrap.data]);\n\n useEffect(() => {\n if (!pluginId || !draft.apiTokenSecretRef) {\n setSettingsCatalog(null);\n setCatalogError(null);\n setCatalogLoading(false);\n return;\n }\n\n let cancelled = false;\n setCatalogLoading(true);\n setCatalogError(null);\n\n void fetchSettingsCatalog()\n .then((catalog) => {\n if (cancelled) return;\n setSettingsCatalog(catalog);\n setDraft((current) => {\n const normalized = normalizeConfig(current);\n const selectedTeamIds = normalized.teamMappings\n .map((team) => team.teamId)\n .filter(Boolean);\n const nextTeamMappings = selectedTeamIds.length > 0\n ? buildTeamMappingsForSelectedTeams(catalog, selectedTeamIds, normalized.teamMappings)\n : buildTeamMappingsFromCatalog(catalog);\n return {\n ...normalized,\n teamMappings: nextTeamMappings,\n };\n });\n })\n .catch((error) => {\n if (cancelled) return;\n setSettingsCatalog(null);\n setCatalogError(error instanceof Error ? error.message : String(error));\n })\n .finally(() => {\n if (!cancelled) setCatalogLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [draft.apiTokenSecretRef, pluginId]);\n\n const selectedTeamIds = draft.teamMappings\n .map((team) => team.teamId)\n .filter(Boolean);\n const selectedTeamIdSet = new Set(selectedTeamIds);\n const selectedTeamCount = selectedTeamIds.length;\n const catalogTeamCount = settingsCatalog?.teams.length ?? 0;\n const issueBoardHref = linearIssueBoardHref(\n bootstrap.data?.organizations[0]?.issuePrefix ?? null,\n selectedTeamIds[0] ?? null,\n );\n\n async function savePluginConfig(config: LinearPluginConfig) {\n if (!pluginId) throw new Error(\"Unable to resolve plugin id\");\n return await apiFetch(`/api/plugins/${encodeURIComponent(pluginId)}/config`, {\n method: \"POST\",\n body: JSON.stringify({ configJson: prepareConfigForSubmit(config) }),\n });\n }\n\n async function listOrgSecrets(orgId: string): Promise<SecretSummary[]> {\n return await apiFetch<SecretSummary[]>(`/api/orgs/${encodeURIComponent(orgId)}/secrets`);\n }\n\n async function rotateSecret(secretId: string, value: string): Promise<SecretSummary> {\n return await apiFetch<SecretSummary>(`/api/secrets/${encodeURIComponent(secretId)}/rotate`, {\n method: \"POST\",\n body: JSON.stringify({ value }),\n });\n }\n\n async function createLinearTokenSecret(orgId: string, value: string): Promise<SecretSummary> {\n return await apiFetch<SecretSummary>(`/api/orgs/${encodeURIComponent(orgId)}/secrets`, {\n method: \"POST\",\n body: JSON.stringify({\n name: LINEAR_TOKEN_SECRET_NAME,\n value,\n description: \"Used by the Linear plugin to read issues across Rudder organizations.\",\n }),\n });\n }\n\n async function saveLinearTokenSecret(orgId: string, value: string, currentSecretRef: string): Promise<string> {\n if (currentSecretRef) {\n const rotated = await rotateSecret(currentSecretRef, value);\n return rotated.id;\n }\n\n try {\n const created = await createLinearTokenSecret(orgId, value);\n return created.id;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (!/Secret already exists/i.test(message)) throw error;\n\n const existing = (await listOrgSecrets(orgId)).find((secret) => secret.name === LINEAR_TOKEN_SECRET_NAME);\n if (!existing) throw error;\n const rotated = await rotateSecret(existing.id, value);\n return rotated.id;\n }\n }\n\n async function fetchPluginData<T>(key: string, params: Record<string, unknown> = {}, orgId?: string): Promise<T> {\n if (!pluginId) throw new Error(\"Unable to resolve plugin id\");\n const payload = await apiFetch<{ data: T }>(`/api/plugins/${encodeURIComponent(pluginId)}/data/${key}`, {\n method: \"POST\",\n body: JSON.stringify({\n ...(orgId ? { orgId } : {}),\n params: {\n ...params,\n ...(orgId ? { orgId } : {}),\n },\n }),\n });\n return payload.data;\n }\n\n async function fetchSettingsCatalogWithRetry(): Promise<SettingsCatalogData> {\n let lastError: unknown = null;\n for (let attempt = 0; attempt < 5; attempt += 1) {\n try {\n return await fetchPluginData<SettingsCatalogData>(DATA_KEYS.settingsCatalog);\n } catch (error) {\n if (isMissingSettingsCatalogHandler(error)) throw error;\n lastError = error;\n await new Promise((resolve) => window.setTimeout(resolve, 350 + attempt * 250));\n }\n }\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n }\n\n async function refreshPluginRuntime() {\n if (!pluginId) throw new Error(\"Unable to resolve plugin id\");\n await apiFetch(`/api/plugins/${encodeURIComponent(pluginId)}/disable`, {\n method: \"POST\",\n body: JSON.stringify({ reason: \"Refresh Linear plugin after settings update\" }),\n });\n await apiFetch(`/api/plugins/${encodeURIComponent(pluginId)}/enable`, {\n method: \"POST\",\n body: JSON.stringify({}),\n });\n }\n\n async function fetchSettingsCatalog(): Promise<SettingsCatalogData> {\n try {\n return await fetchSettingsCatalogWithRetry();\n } catch (error) {\n if (!isMissingSettingsCatalogHandler(error)) throw error;\n await refreshPluginRuntime();\n return await fetchSettingsCatalogWithRetry();\n }\n }\n\n function toggleTeam(teamId: string) {\n if (!settingsCatalog) return;\n setDraft((current) => {\n const normalized = normalizeConfig(current);\n const nextTeamIds = new Set(normalized.teamMappings.map((team) => team.teamId).filter(Boolean));\n if (nextTeamIds.has(teamId)) {\n nextTeamIds.delete(teamId);\n } else {\n nextTeamIds.add(teamId);\n }\n return {\n ...normalized,\n teamMappings: buildTeamMappingsForSelectedTeams(settingsCatalog, [...nextTeamIds], normalized.teamMappings),\n };\n });\n }\n\n function selectAllTeams() {\n if (!settingsCatalog) return;\n setDraft((current) => {\n const normalized = normalizeConfig(current);\n return {\n ...normalized,\n teamMappings: buildTeamMappingsForSelectedTeams(\n settingsCatalog,\n settingsCatalog.teams.map((team) => team.id),\n normalized.teamMappings,\n ),\n };\n });\n }\n\n function setStatusRule(teamId: string, stateId: string, rudderStatus: LinearStateMapping[\"rudderStatus\"]) {\n setDraft((current) => ({\n ...current,\n teamMappings: current.teamMappings.map((team) => {\n if (team.teamId !== teamId) return team;\n return {\n ...team,\n stateMappings: team.stateMappings.map((state) =>\n state.linearStateId === stateId ? { ...state, rudderStatus } : state,\n ),\n };\n }),\n }));\n }\n\n async function connectLinear() {\n if (!pluginId) {\n toast({ title: \"Unable to resolve plugin id\", tone: \"error\" });\n return;\n }\n\n setConnecting(true);\n try {\n let apiTokenSecretRef = draft.apiTokenSecretRef?.trim() ?? \"\";\n const trimmedToken = tokenInput.trim();\n if (trimmedToken) {\n const secretOrgId = bootstrap.data?.organizations[0]?.id ?? \"\";\n if (!secretOrgId) {\n toast({\n title: \"Create a Rudder organization first\",\n body: \"Rudder needs one organization to store the Linear token reference.\",\n tone: \"warn\",\n });\n return;\n }\n apiTokenSecretRef = await saveLinearTokenSecret(secretOrgId, trimmedToken, apiTokenSecretRef);\n }\n if (!apiTokenSecretRef) {\n toast({\n title: \"Paste a Linear token\",\n body: \"Create one in Linear, paste it here, then connect.\",\n tone: \"warn\",\n });\n return;\n }\n\n const seedConfig = {\n ...draft,\n apiTokenSecretRef,\n };\n await savePluginConfig(seedConfig);\n\n const catalog = await fetchSettingsCatalog();\n if (catalog.teams.length === 0) {\n throw new Error(\"Linear returned no teams for this token.\");\n }\n const generatedTeamMappings = buildTeamMappingsFromCatalog(catalog);\n const nextConfig = prepareConfigForSubmit({\n ...seedConfig,\n teamMappings: generatedTeamMappings,\n });\n await savePluginConfig(nextConfig);\n setSettingsCatalog(catalog);\n setCatalogError(null);\n setDraft(nextConfig);\n setTokenInput(\"\");\n bootstrap.refresh();\n const firstTeamId = generatedTeamMappings[0]?.teamId ?? null;\n const firstOrgPrefix = bootstrap.data?.organizations[0]?.issuePrefix ?? null;\n toast({\n title: \"Linear is ready\",\n body: summarizeMapping(generatedTeamMappings),\n tone: \"success\",\n action: {\n label: \"Open Linear issues\",\n href: linearIssueBoardHref(firstOrgPrefix, firstTeamId),\n },\n });\n } catch (error) {\n toast({\n title: \"Linear connection failed\",\n body: error instanceof Error ? error.message : String(error),\n tone: \"error\",\n });\n } finally {\n setConnecting(false);\n }\n }\n\n async function saveConfig() {\n if (!pluginId) {\n toast({ title: \"Unable to resolve plugin id\", tone: \"error\" });\n return;\n }\n if (draft.apiTokenSecretRef && settingsCatalog && selectedTeamCount === 0) {\n toast({\n title: \"Choose at least one Linear team\",\n body: \"The import page needs one or more teams to show Linear issues.\",\n tone: \"warn\",\n });\n return;\n }\n setSaving(true);\n try {\n await savePluginConfig(draft);\n bootstrap.refresh();\n toast({\n title: \"Linear settings saved\",\n tone: \"success\",\n });\n } catch (error) {\n toast({\n title: \"Failed to save Linear settings\",\n body: error instanceof Error ? error.message : String(error),\n tone: \"error\",\n });\n } finally {\n setSaving(false);\n }\n }\n\n function connectionStatusText(): string {\n if (bootstrap.loading) return \"Loading plugin settings\u2026\";\n if (catalogLoading) return \"Reading teams and workflow states from Linear\u2026\";\n if (catalogError) return `Linear could not be loaded: ${catalogError}`;\n if (settingsCatalog) {\n return `Connected. ${catalogTeamCount} Linear team${catalogTeamCount === 1 ? \"\" : \"s\"} found; ${selectedTeamCount} selected for import.`;\n }\n if (draft.apiTokenSecretRef) return \"Token saved. Refresh from Linear to load teams.\";\n return \"Paste a Linear token to connect this instance.\";\n }\n\n return (\n <div style={layoutStyles.shell}>\n <section key=\"linear-settings-intro\" style={layoutStyles.card}>\n <h2 style={{ marginTop: 0 }}>Linear</h2>\n <p style={layoutStyles.subtitle}>\n Paste a Linear token once. Rudder will read your teams and workflow states, then prepare the import settings automatically.\n </p>\n {bootstrap.data?.fixtureMode ? (\n <div style={{ marginTop: 12, ...layoutStyles.warning }}>\n Fixture mode is enabled in this environment. Linear reads use deterministic test data.\n </div>\n ) : null}\n </section>\n\n <section key=\"linear-settings-connect\" style={layoutStyles.card}>\n <div style={layoutStyles.sectionHeader}>\n <div>\n <h3 style={{ margin: 0 }}>Connect Linear</h3>\n <p style={layoutStyles.subtitle}>\n Paste a token and Rudder will prepare the import setup from Linear.{\" \"}\n <a href={LINEAR_TOKEN_SETTINGS_URL} target=\"_blank\" rel=\"noreferrer\" style={layoutStyles.monoLink}>\n Create a Linear token\n </a>\n .\n </p>\n </div>\n </div>\n <div style={{ ...layoutStyles.connectionGrid, marginTop: 14 }}>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"linear-token\">Linear token</label>\n <input\n id=\"linear-token\"\n data-testid=\"linear-token-input\"\n style={layoutStyles.input}\n type=\"password\"\n autoComplete=\"off\"\n value={tokenInput}\n onChange={(event) => setTokenInput(event.target.value)}\n placeholder={draft.apiTokenSecretRef ? \"Token saved. Paste a new token to replace it.\" : \"Paste a Linear token\"}\n />\n </div>\n <div style={{ display: \"grid\", gap: 6, justifySelf: \"start\" }}>\n <span aria-hidden=\"true\" style={{ ...layoutStyles.label, visibility: \"hidden\" }}>Action</span>\n <button\n type=\"button\"\n style={layoutStyles.primaryButton}\n data-testid=\"linear-connect\"\n onClick={() => void connectLinear()}\n disabled={connecting}\n >\n {connecting ? \"Connecting\u2026\" : draft.apiTokenSecretRef ? \"Refresh from Linear\" : \"Connect Linear\"}\n </button>\n </div>\n </div>\n <div style={{ ...layoutStyles.statusLine, display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", gap: 12, flexWrap: \"wrap\" }}>\n <span>{connectionStatusText()}</span>\n {settingsCatalog && selectedTeamCount > 0 ? (\n <a href={issueBoardHref} style={layoutStyles.monoLink}>Open Linear issues</a>\n ) : null}\n </div>\n </section>\n\n {draft.apiTokenSecretRef ? (\n <section key=\"linear-settings-teams\" style={layoutStyles.card}>\n <div style={layoutStyles.sectionHeader}>\n <div>\n <h3 style={{ margin: 0 }}>Teams to import</h3>\n <p style={layoutStyles.subtitle}>\n Choose the Linear teams that should appear on the import page. Rudder stores the technical details for you.\n </p>\n </div>\n <button\n type=\"button\"\n style={layoutStyles.subtleButton}\n onClick={selectAllTeams}\n disabled={!settingsCatalog || catalogLoading || catalogTeamCount === selectedTeamCount}\n >\n Select all teams\n </button>\n </div>\n\n {catalogLoading ? (\n <p style={layoutStyles.helpText}>Loading teams from Linear\u2026</p>\n ) : catalogError ? (\n <div style={{ marginTop: 14, ...layoutStyles.warning }}>\n <strong>Linear could not be loaded.</strong>\n <div style={{ marginTop: 6 }}>{catalogError}</div>\n </div>\n ) : settingsCatalog ? (\n <>\n <div style={layoutStyles.teamGrid}>\n {settingsCatalog.teams.map((team, index) => {\n const checked = selectedTeamIdSet.has(team.id);\n return (\n <label\n key={`${team.id}-${index}`}\n style={{\n ...layoutStyles.teamChoice,\n borderColor: checked ? \"var(--primary, #2563eb)\" : \"var(--border, rgba(15, 23, 42, 0.14))\",\n background: checked ? \"rgba(37, 99, 235, 0.08)\" : \"var(--background, transparent)\",\n }}\n >\n <input\n data-testid={`linear-team-choice-${team.id}`}\n style={layoutStyles.checkbox}\n type=\"checkbox\"\n checked={checked}\n onChange={() => toggleTeam(team.id)}\n />\n <span>\n <strong>{team.name}</strong>\n <span style={{ display: \"block\", marginTop: 3, ...layoutStyles.helpText }}>\n {team.key} \u00B7 {team.states.length} workflow state{team.states.length === 1 ? \"\" : \"s\"}\n </span>\n </span>\n </label>\n );\n })}\n </div>\n <div style={{ ...layoutStyles.row, justifyContent: \"space-between\", marginTop: 14 }}>\n <span style={layoutStyles.helpText}>\n {selectedTeamCount === 0\n ? \"Choose at least one team before saving.\"\n : `${selectedTeamCount} team${selectedTeamCount === 1 ? \"\" : \"s\"} selected for import.`}\n </span>\n <button\n type=\"button\"\n style={layoutStyles.primaryButton}\n data-testid=\"linear-save-team-choices\"\n onClick={() => void saveConfig()}\n disabled={saving || selectedTeamCount === 0}\n >\n {saving ? \"Saving\u2026\" : \"Save choices\"}\n </button>\n </div>\n </>\n ) : (\n <p style={layoutStyles.helpText}>Refresh from Linear to load teams for this token.</p>\n )}\n </section>\n ) : null}\n\n {settingsCatalog && draft.teamMappings.length > 0 ? (\n <section key=\"linear-settings-status-rules\" style={layoutStyles.card}>\n <details>\n <summary style={{ cursor: \"pointer\", fontWeight: 700 }}>Status rules (optional)</summary>\n <p style={layoutStyles.subtitle}>\n Rudder applies smart defaults from Linear. Change these only if imported issues land in the wrong Rudder status.\n </p>\n <div style={{ display: \"grid\", gap: 18, marginTop: 14 }}>\n {draft.teamMappings.map((teamMapping, teamIndex) => {\n const catalogTeam = settingsCatalog.teams.find((team) => team.id === teamMapping.teamId);\n const states = catalogTeam?.states ?? teamMapping.stateMappings.map((state) => ({\n id: state.linearStateId,\n name: state.linearStateName ?? \"Linear status\",\n type: null,\n }));\n const statusByStateId = new Map(teamMapping.stateMappings.map((state) => [state.linearStateId, state.rudderStatus]));\n return (\n <div key={`${teamMapping.teamId}-${teamIndex}`} style={{ borderTop: \"1px solid var(--border, rgba(15, 23, 42, 0.1))\", paddingTop: 14 }}>\n <h4 style={{ margin: \"0 0 10px\" }}>{teamMapping.teamName ?? catalogTeam?.name ?? \"Linear team\"}</h4>\n <div style={{ display: \"grid\", gap: 8 }}>\n {states.map((state, stateIndex) => (\n <div key={`${teamMapping.teamId}-${state.id}-${stateIndex}`} style={layoutStyles.statusRuleGrid}>\n <div>\n <strong>{state.name}</strong>\n <div style={layoutStyles.helpText}>{state.type ? `${state.type} in Linear` : \"Linear workflow state\"}</div>\n </div>\n <select\n style={layoutStyles.select}\n value={statusByStateId.get(state.id) ?? inferRudderStatus(state)}\n onChange={(event) =>\n setStatusRule(teamMapping.teamId, state.id, event.target.value as LinearStateMapping[\"rudderStatus\"])}\n >\n {RUDDER_STATUS_OPTIONS.map((status) => (\n <option key={`${teamMapping.teamId}-${state.id}-${status}`} value={status}>{formatRudderStatus(status)}</option>\n ))}\n </select>\n </div>\n ))}\n </div>\n </div>\n );\n })}\n </div>\n <div style={{ marginTop: 14 }}>\n <button type=\"button\" style={layoutStyles.primaryButton} onClick={() => void saveConfig()} disabled={saving}>\n {saving ? \"Saving\u2026\" : \"Save status rules\"}\n </button>\n </div>\n </details>\n </section>\n ) : null}\n </div>\n );\n}\n", "import type { Issue } from \"@rudderhq/shared\";\n\nexport const PLUGIN_ID = \"rudder.linear\";\nexport const PLUGIN_VERSION = \"0.1.0\";\nexport const PAGE_ROUTE = \"linear\";\nexport const ENTITY_TYPE_LINEAR_ISSUE_LINK = \"linear_issue_link\";\nexport const ISSUE_LINK_STATE_KEY = \"linear-link\";\nexport const DEFAULT_LINEAR_API_URL = \"https://api.linear.app/graphql\";\nexport const LINEAR_TOKEN_SETTINGS_URL = \"https://linear.app/settings/account/security\";\nexport const LINEAR_PAGE_SIZE = 25;\nexport const LINEAR_IMPORT_ALL_LIMIT = 100;\n\nexport const SLOT_IDS = {\n page: \"linear-page\",\n settingsPage: \"linear-settings-page\",\n issueTab: \"linear-issue-tab\",\n} as const;\n\nexport const EXPORT_NAMES = {\n page: \"LinearPluginPage\",\n settingsPage: \"LinearPluginSettingsPage\",\n issueTab: \"LinearIssueTab\",\n} as const;\n\nexport const DATA_KEYS = {\n settingsBootstrap: \"settings-bootstrap\",\n pageBootstrap: \"page-bootstrap\",\n settingsCatalog: \"settings-catalog\",\n catalog: \"linear-catalog\",\n issues: \"linear-issues\",\n issueLink: \"issue-link\",\n} as const;\n\nexport const ACTION_KEYS = {\n importIssues: \"import-linear-issues\",\n} as const;\n\nexport const RUDDER_STATUS_OPTIONS: Issue[\"status\"][] = [\n \"backlog\",\n \"todo\",\n \"in_progress\",\n \"in_review\",\n \"done\",\n \"blocked\",\n \"cancelled\",\n];\n"],
|
|
4
|
+
"sourcesContent": ["import {\n usePluginAction,\n usePluginData,\n usePluginToast,\n type PluginDetailTabProps,\n type PluginPageProps,\n type PluginSettingsPageProps,\n} from \"@rudderhq/plugin-sdk/ui\";\nimport {\n useEffect,\n useMemo,\n useState,\n type CSSProperties,\n type Dispatch,\n type SetStateAction,\n} from \"react\";\nimport {\n ACTION_KEYS,\n DATA_KEYS,\n LINEAR_IMPORT_ALL_LIMIT,\n LINEAR_PAGE_SIZE,\n LINEAR_TOKEN_SETTINGS_URL,\n RUDDER_STATUS_OPTIONS,\n} from \"../constants.js\";\nimport type {\n ImportLinearIssuesActionResult,\n IssueLinkData,\n LinearCatalogData,\n LinearIssueRow,\n LinearIssuesData,\n LinearOrganizationMapping,\n LinearPluginConfig,\n LinearStateMapping,\n LinearStateSummary,\n LinearTeamMapping,\n PageBootstrapData,\n SettingsBootstrapData,\n SettingsCatalogData,\n} from \"../types.js\";\n\nconst layoutStyles: Record<string, CSSProperties> = {\n shell: {\n display: \"grid\",\n gap: 16,\n color: \"var(--foreground, #111827)\",\n fontFamily: \"ui-sans-serif, system-ui, sans-serif\",\n },\n card: {\n border: \"1px solid var(--border, rgba(15, 23, 42, 0.14))\",\n borderRadius: 8,\n padding: 16,\n background: \"var(--card, var(--background, #fff))\",\n },\n title: {\n fontSize: 22,\n fontWeight: 700,\n margin: 0,\n },\n subtitle: {\n margin: \"6px 0 0\",\n color: \"var(--muted-foreground, rgba(15, 23, 42, 0.68))\",\n fontSize: 14,\n lineHeight: 1.5,\n },\n row: {\n display: \"flex\",\n gap: 12,\n flexWrap: \"wrap\",\n alignItems: \"center\",\n },\n connectionGrid: {\n display: \"grid\",\n gridTemplateColumns: \"repeat(auto-fit, minmax(220px, 1fr))\",\n gap: 12,\n alignItems: \"end\",\n },\n field: {\n display: \"grid\",\n gap: 6,\n minWidth: 180,\n flex: \"1 1 180px\",\n },\n label: {\n fontSize: 12,\n fontWeight: 700,\n color: \"var(--muted-foreground, rgba(15, 23, 42, 0.66))\",\n letterSpacing: 0,\n },\n input: {\n width: \"100%\",\n border: \"1px solid var(--border, rgba(15, 23, 42, 0.18))\",\n borderRadius: 6,\n padding: \"10px 12px\",\n fontSize: 14,\n background: \"var(--background, #fff)\",\n color: \"var(--foreground, #111827)\",\n boxSizing: \"border-box\",\n },\n select: {\n width: \"100%\",\n border: \"1px solid var(--border, rgba(15, 23, 42, 0.18))\",\n borderRadius: 6,\n padding: \"10px 12px\",\n fontSize: 14,\n background: \"var(--background, #fff)\",\n color: \"var(--foreground, #111827)\",\n boxSizing: \"border-box\",\n },\n button: {\n border: \"1px solid var(--border, rgba(15, 23, 42, 0.18))\",\n borderRadius: 6,\n padding: \"10px 14px\",\n fontSize: 14,\n fontWeight: 600,\n background: \"var(--background, #fff)\",\n color: \"var(--foreground, #111827)\",\n cursor: \"pointer\",\n },\n primaryButton: {\n border: \"1px solid var(--primary, #0f172a)\",\n borderRadius: 6,\n padding: \"10px 14px\",\n fontSize: 14,\n fontWeight: 700,\n background: \"var(--primary, #0f172a)\",\n color: \"var(--primary-foreground, #fff)\",\n cursor: \"pointer\",\n },\n subtleButton: {\n border: \"1px solid var(--border, rgba(15, 23, 42, 0.12))\",\n borderRadius: 6,\n padding: \"8px 12px\",\n fontSize: 13,\n fontWeight: 600,\n background: \"var(--secondary, rgba(15, 23, 42, 0.04))\",\n color: \"var(--secondary-foreground, var(--foreground, #111827))\",\n cursor: \"pointer\",\n },\n warning: {\n border: \"1px solid rgba(217, 119, 6, 0.24)\",\n background: \"rgba(251, 191, 36, 0.12)\",\n borderRadius: 8,\n padding: 14,\n fontSize: 14,\n lineHeight: 1.5,\n },\n table: {\n width: \"100%\",\n borderCollapse: \"collapse\",\n fontSize: 14,\n },\n th: {\n textAlign: \"left\",\n fontSize: 12,\n letterSpacing: 0,\n color: \"var(--muted-foreground, rgba(15, 23, 42, 0.62))\",\n padding: \"10px 12px\",\n borderBottom: \"1px solid var(--border, rgba(15, 23, 42, 0.1))\",\n },\n td: {\n padding: \"12px\",\n borderBottom: \"1px solid var(--border, rgba(15, 23, 42, 0.08))\",\n verticalAlign: \"top\",\n },\n pill: {\n display: \"inline-flex\",\n alignItems: \"center\",\n borderRadius: 999,\n padding: \"4px 10px\",\n background: \"var(--secondary, rgba(15, 23, 42, 0.06))\",\n color: \"var(--secondary-foreground, var(--foreground, #111827))\",\n fontSize: 12,\n fontWeight: 600,\n },\n monoLink: {\n fontFamily: \"ui-monospace, SFMono-Regular, Menlo, monospace\",\n fontSize: 12,\n },\n helpText: {\n fontSize: 13,\n lineHeight: 1.5,\n color: \"var(--muted-foreground, rgba(15, 23, 42, 0.68))\",\n },\n statusLine: {\n marginTop: 14,\n paddingTop: 14,\n borderTop: \"1px solid var(--border, rgba(15, 23, 42, 0.1))\",\n fontSize: 13,\n lineHeight: 1.5,\n color: \"var(--muted-foreground, rgba(15, 23, 42, 0.68))\",\n },\n sectionHeader: {\n display: \"flex\",\n justifyContent: \"space-between\",\n gap: 12,\n alignItems: \"flex-start\",\n flexWrap: \"wrap\",\n },\n teamGrid: {\n display: \"grid\",\n gridTemplateColumns: \"repeat(auto-fit, minmax(220px, 1fr))\",\n gap: 10,\n marginTop: 14,\n },\n teamChoice: {\n display: \"flex\",\n gap: 10,\n alignItems: \"flex-start\",\n border: \"1px solid var(--border, rgba(15, 23, 42, 0.14))\",\n borderRadius: 8,\n padding: 12,\n cursor: \"pointer\",\n background: \"var(--background, transparent)\",\n },\n checkbox: {\n marginTop: 3,\n },\n statusRuleGrid: {\n display: \"grid\",\n gridTemplateColumns: \"repeat(auto-fit, minmax(180px, 1fr))\",\n gap: 10,\n alignItems: \"center\",\n },\n};\n\nconst LINEAR_TOKEN_SECRET_NAME = \"Linear token\";\n\ntype SecretSummary = {\n id: string;\n name: string;\n};\n\nfunction normalizeConfig(config: LinearPluginConfig | null | undefined): LinearPluginConfig {\n const legacyOrganizationMappings = Array.isArray(config?.organizationMappings) ? config.organizationMappings : [];\n const explicitTeamMappings = Array.isArray(config?.teamMappings) ? config.teamMappings : [];\n return {\n apiTokenSecretRef: config?.apiTokenSecretRef ?? \"\",\n teamMappings: explicitTeamMappings.length > 0\n ? explicitTeamMappings\n : mergeLegacyTeamMappings(legacyOrganizationMappings),\n organizationMappings: legacyOrganizationMappings,\n ...(config?.fixtureMode === true ? { fixtureMode: true } : {}),\n };\n}\n\nfunction mergeLegacyTeamMappings(mappings: LinearOrganizationMapping[]): LinearTeamMapping[] {\n const byTeamId = new Map<string, LinearTeamMapping>();\n for (const mapping of mappings) {\n for (const team of mapping.teamMappings ?? []) {\n if (!team.teamId || byTeamId.has(team.teamId)) continue;\n byTeamId.set(team.teamId, team);\n }\n }\n return [...byTeamId.values()];\n}\n\nfunction getOrgPrefix(context: Record<string, unknown>): string | null {\n const orgPrefix = typeof context[\"orgPrefix\"] === \"string\" ? context[\"orgPrefix\"] : null;\n const companyPrefix = typeof context[\"companyPrefix\"] === \"string\" ? context[\"companyPrefix\"] : null;\n return orgPrefix ?? companyPrefix;\n}\n\nfunction getPluginIdFromLocation(): string | null {\n if (typeof window === \"undefined\") return null;\n const match = window.location.pathname.match(/\\/instance\\/settings\\/plugins\\/([^/?#]+)/);\n return match?.[1] ?? null;\n}\n\nasync function apiFetch<T>(path: string, init?: RequestInit): Promise<T> {\n const response = await fetch(path, {\n credentials: \"same-origin\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(init?.headers ?? {}),\n },\n ...init,\n });\n if (!response.ok) {\n const payload = await response.json().catch(async () => ({ error: await response.text() }));\n const message = typeof payload?.error === \"string\"\n ? payload.error\n : typeof payload?.message === \"string\"\n ? payload.message\n : `Request failed (${response.status})`;\n throw new Error(message);\n }\n return await response.json() as T;\n}\n\nfunction formatRudderStatus(status: LinearStateMapping[\"rudderStatus\"]): string {\n return status.replaceAll(\"_\", \" \");\n}\n\nfunction inferRudderStatus(state: LinearStateSummary): LinearStateMapping[\"rudderStatus\"] {\n const type = (state.type ?? \"\").toLowerCase();\n const name = state.name.toLowerCase();\n if (type.includes(\"completed\") || name.includes(\"done\") || name.includes(\"complete\")) return \"done\";\n if (type.includes(\"cancel\") || name.includes(\"cancel\")) return \"cancelled\";\n if (name.includes(\"review\")) return \"in_review\";\n if (type.includes(\"backlog\") || type.includes(\"triage\") || name.includes(\"backlog\") || name.includes(\"triage\")) return \"backlog\";\n if (type.includes(\"started\") || type.includes(\"unstarted\") || name.includes(\"progress\") || name.includes(\"todo\")) return \"todo\";\n return \"backlog\";\n}\n\nfunction buildTeamMappingsFromCatalog(catalog: SettingsCatalogData): LinearTeamMapping[] {\n return catalog.teams.map((team) => buildTeamMappingFromCatalog(team));\n}\n\nfunction buildTeamMappingFromCatalog(\n team: SettingsCatalogData[\"teams\"][number],\n existing?: LinearTeamMapping | null,\n): LinearTeamMapping {\n const existingStatusByStateId = new Map(\n (existing?.stateMappings ?? []).map((state) => [state.linearStateId, state.rudderStatus]),\n );\n return {\n teamId: team.id,\n teamName: team.name,\n stateMappings: team.states.map((state) => ({\n linearStateId: state.id,\n linearStateName: state.name,\n rudderStatus: existingStatusByStateId.get(state.id) ?? inferRudderStatus(state),\n })),\n };\n}\n\nfunction buildTeamMappingsForSelectedTeams(\n catalog: SettingsCatalogData,\n selectedTeamIds: string[],\n existingTeamMappings: LinearTeamMapping[],\n): LinearTeamMapping[] {\n const selected = new Set(selectedTeamIds);\n const existingByTeamId = new Map(existingTeamMappings.map((team) => [team.teamId, team]));\n return catalog.teams\n .filter((team) => selected.has(team.id))\n .map((team) => buildTeamMappingFromCatalog(team, existingByTeamId.get(team.id)));\n}\n\nfunction countMappedStates(teamMappings: LinearTeamMapping[] | null | undefined): number {\n return teamMappings?.reduce((sum, team) => sum + team.stateMappings.length, 0) ?? 0;\n}\n\nfunction summarizeMapping(teamMappings: LinearTeamMapping[] | null | undefined): string {\n if (!teamMappings) return \"No Linear workspace loaded yet.\";\n const teamCount = teamMappings.length;\n const stateCount = countMappedStates(teamMappings);\n return `${teamCount} team${teamCount === 1 ? \"\" : \"s\"} and ${stateCount} workflow state${stateCount === 1 ? \"\" : \"s\"} ready.`;\n}\n\nfunction isMissingSettingsCatalogHandler(error: unknown): boolean {\n const message = error instanceof Error ? error.message : String(error);\n return /No data handler registered/i.test(message) && /settings-catalog/i.test(message);\n}\n\nfunction prepareConfigForSubmit(config: LinearPluginConfig): LinearPluginConfig {\n const teamMappings = config.teamMappings\n .map((team) => ({\n teamId: team.teamId.trim(),\n teamName: team.teamName?.trim() || undefined,\n stateMappings: team.stateMappings\n .map((state) => ({\n linearStateId: state.linearStateId.trim(),\n linearStateName: state.linearStateName?.trim() || undefined,\n rudderStatus: state.rudderStatus,\n }))\n .filter((state) => state.linearStateId),\n }))\n .filter((team) => team.teamId);\n\n return {\n apiTokenSecretRef: config.apiTokenSecretRef?.trim() ?? \"\",\n ...(config.fixtureMode === true ? { fixtureMode: true } : {}),\n teamMappings,\n // Keep a legacy-compatible shape for already-installed manifests that still\n // require organizationMappings during config validation. New runtime code\n // reads the top-level teamMappings field.\n organizationMappings: teamMappings.length > 0 ? [{ orgId: \"__global__\", teamMappings }] : [],\n };\n}\n\nfunction summarizeImportResult(result: ImportLinearIssuesActionResult): string {\n const parts = [`Imported ${result.importedCount}`];\n if (result.duplicateCount > 0) parts.push(`${result.duplicateCount} duplicate`);\n if (result.fallbackCount > 0) parts.push(`${result.fallbackCount} fallback`);\n if (result.adjustedCount > 0) parts.push(`${result.adjustedCount} adjusted`);\n return parts.join(\" / \");\n}\n\nfunction formatRelativeTime(timestamp: string | null | undefined): string {\n if (!timestamp) return \"Unknown\";\n const date = new Date(timestamp);\n if (Number.isNaN(date.getTime())) return timestamp;\n return new Intl.DateTimeFormat(undefined, {\n month: \"short\",\n day: \"numeric\",\n year: \"numeric\",\n hour: \"2-digit\",\n minute: \"2-digit\",\n hourCycle: \"h23\",\n }).format(date);\n}\n\nfunction issueHref(orgPrefix: string | null, issueId: string): string {\n return orgPrefix ? `/${orgPrefix}/issues/${issueId}` : `/issues/${issueId}`;\n}\n\nfunction pageHref(orgPrefix: string | null, query?: string): string {\n if (!orgPrefix) return \"/linear\";\n const url = new URL(`/${orgPrefix}/linear`, \"https://local.invalid\");\n if (query) url.searchParams.set(\"q\", query);\n return `${url.pathname}${url.search}`;\n}\n\nfunction linearIssueBoardHref(orgPrefix: string | null | undefined, teamId?: string | null): string {\n const basePath = orgPrefix ? `/${encodeURIComponent(orgPrefix)}/issues` : \"/issues\";\n const url = new URL(basePath, \"https://local.invalid\");\n url.searchParams.set(\"source\", \"linear\");\n if (teamId) url.searchParams.set(\"linearTeamId\", teamId);\n return `${url.pathname}${url.search}`;\n}\n\nfunction readLinearPageUrlFilters() {\n if (typeof window === \"undefined\") {\n return { query: \"\", projectId: \"\", teamId: \"\" };\n }\n const params = new URLSearchParams(window.location.search);\n return {\n query: params.get(\"q\") ?? \"\",\n projectId: params.get(\"linearProjectId\") ?? \"\",\n teamId: params.get(\"linearTeamId\") ?? \"\",\n };\n}\n\ntype FilterState = {\n teamId: string;\n stateId: string;\n projectId: string;\n assigneeId: string;\n query: string;\n};\n\nfunction useLinearFilters(\n initialQuery: string,\n initialProjectId = \"\",\n initialTeamId = \"\",\n): [FilterState, Dispatch<SetStateAction<FilterState>>] {\n const [filters, setFilters] = useState<FilterState>({\n teamId: initialTeamId,\n stateId: \"\",\n projectId: initialProjectId,\n assigneeId: \"\",\n query: initialQuery,\n });\n return [filters, setFilters];\n}\n\nexport function LinearPluginPage({ context }: PluginPageProps) {\n const toast = usePluginToast();\n const importIssues = usePluginAction(ACTION_KEYS.importIssues) as (\n params?: Record<string, unknown>,\n ) => Promise<ImportLinearIssuesActionResult>;\n const orgId = context.orgId ?? \"__missing__\";\n const orgPrefix = getOrgPrefix(context as unknown as Record<string, unknown>);\n const urlFilters = readLinearPageUrlFilters();\n\n const bootstrap = usePluginData<PageBootstrapData>(DATA_KEYS.pageBootstrap, { orgId });\n const catalog = usePluginData<LinearCatalogData>(DATA_KEYS.catalog, { orgId });\n const [filters, setFilters] = useLinearFilters(urlFilters.query, urlFilters.projectId, urlFilters.teamId);\n const [targetProjectId, setTargetProjectId] = useState(\"\");\n const [afterCursor, setAfterCursor] = useState<string | null>(null);\n const [cursorHistory, setCursorHistory] = useState<string[]>([]);\n const [selectedIssueIds, setSelectedIssueIds] = useState<string[]>([]);\n const [importing, setImporting] = useState(false);\n\n const issues = usePluginData<LinearIssuesData>(DATA_KEYS.issues, {\n orgId,\n limit: LINEAR_PAGE_SIZE,\n after: afterCursor ?? undefined,\n teamId: filters.teamId || undefined,\n stateId: filters.stateId || undefined,\n projectId: filters.projectId || undefined,\n assigneeId: filters.assigneeId || undefined,\n query: filters.query || undefined,\n });\n\n useEffect(() => {\n setFilters((current) => {\n if (\n current.query === urlFilters.query &&\n current.projectId === urlFilters.projectId &&\n current.teamId === urlFilters.teamId\n ) {\n return current;\n }\n return {\n ...current,\n query: urlFilters.query,\n projectId: urlFilters.projectId,\n teamId: urlFilters.teamId,\n };\n });\n }, [setFilters, urlFilters.projectId, urlFilters.query, urlFilters.teamId]);\n\n const stateOptions = useMemo(() => {\n if (!catalog.data?.teams?.length) return [];\n const sourceTeams = filters.teamId\n ? catalog.data.teams.filter((team: LinearCatalogData[\"teams\"][number]) => team.id === filters.teamId)\n : catalog.data.teams;\n const deduped = new Map<string, { id: string; name: string }>();\n for (const team of sourceTeams) {\n for (const state of team.states) {\n deduped.set(state.id, { id: state.id, name: state.name });\n }\n }\n return [...deduped.values()];\n }, [catalog.data?.teams, filters.teamId]);\n\n useEffect(() => {\n setAfterCursor(null);\n setCursorHistory([]);\n setSelectedIssueIds([]);\n }, [filters.teamId, filters.stateId, filters.projectId, filters.assigneeId, filters.query]);\n\n useEffect(() => {\n const visibleIds = new Set(issues.data?.rows.map((row: LinearIssueRow) => row.id) ?? []);\n setSelectedIssueIds((current) => {\n const next = current.filter((id) => visibleIds.has(id));\n if (next.length === current.length && next.every((id, index) => id === current[index])) {\n return current;\n }\n return next;\n });\n }, [issues.data?.rows]);\n\n async function handleImport(mode: \"single\" | \"selected\" | \"allMatching\", issueIds?: string[]) {\n if (!targetProjectId) {\n toast({\n title: \"Choose a target project\",\n body: \"Imports are disabled until a Rudder project is selected.\",\n tone: \"warn\",\n });\n return;\n }\n setImporting(true);\n try {\n const result = await importIssues({\n orgId,\n targetProjectId,\n mode,\n issueIds,\n filters: {\n teamId: filters.teamId || undefined,\n stateId: filters.stateId || undefined,\n projectId: filters.projectId || undefined,\n assigneeId: filters.assigneeId || undefined,\n query: filters.query || undefined,\n },\n });\n toast({\n title: \"Linear import complete\",\n body: summarizeImportResult(result),\n tone: \"success\",\n });\n issues.refresh();\n setSelectedIssueIds([]);\n } catch (error) {\n toast({\n title: \"Linear import failed\",\n body: error instanceof Error ? error.message : String(error),\n tone: \"error\",\n });\n } finally {\n setImporting(false);\n }\n }\n\n return (\n <div style={layoutStyles.shell}>\n <section style={layoutStyles.card}>\n <h1 style={layoutStyles.title}>Linear intake</h1>\n <p style={layoutStyles.subtitle}>\n Import Linear issues into a chosen Rudder project. This page is the bulk workspace; the issue tab is the linked detail view.\n </p>\n </section>\n\n {bootstrap.loading ? (\n <section style={layoutStyles.card}>Loading Linear import context\u2026</section>\n ) : !bootstrap.data?.configured ? (\n <section style={{ ...layoutStyles.card, ...layoutStyles.warning }}>\n <strong>Linear is not configured yet.</strong>\n <div style={{ marginTop: 8 }}>{bootstrap.data?.message ?? \"Connect Linear and choose teams in plugin settings.\"}</div>\n <div style={{ marginTop: 12 }}>\n <a href=\"/instance/settings/plugins\" style={layoutStyles.monoLink}>Open plugin settings</a>\n </div>\n </section>\n ) : (\n <>\n <section style={layoutStyles.card}>\n <div style={layoutStyles.row}>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"target-project\">Target Rudder project</label>\n <select\n id=\"target-project\"\n data-testid=\"linear-target-project\"\n style={layoutStyles.select}\n value={targetProjectId}\n onChange={(event) => setTargetProjectId(event.target.value)}\n >\n <option value=\"\">Choose a project</option>\n {(bootstrap.data?.projects ?? []).map((project: PageBootstrapData[\"projects\"][number]) => (\n <option key={project.id} value={project.id}>{project.name}</option>\n ))}\n </select>\n </div>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"linear-team-filter\">Linear team</label>\n <select\n id=\"linear-team-filter\"\n style={layoutStyles.select}\n value={filters.teamId}\n onChange={(event) => setFilters((current) => ({ ...current, teamId: event.target.value, stateId: \"\" }))}\n >\n <option value=\"\">All allowed teams</option>\n {(catalog.data?.teams ?? []).map((team: LinearCatalogData[\"teams\"][number]) => (\n <option key={team.id} value={team.id}>{team.name}</option>\n ))}\n </select>\n </div>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"linear-state-filter\">Workflow state</label>\n <select\n id=\"linear-state-filter\"\n style={layoutStyles.select}\n value={filters.stateId}\n onChange={(event) => setFilters((current) => ({ ...current, stateId: event.target.value }))}\n >\n <option value=\"\">All states</option>\n {stateOptions.map((state) => (\n <option key={state.id} value={state.id}>{state.name}</option>\n ))}\n </select>\n </div>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"linear-project-filter\">Linear project</label>\n <select\n id=\"linear-project-filter\"\n style={layoutStyles.select}\n value={filters.projectId}\n onChange={(event) => setFilters((current) => ({ ...current, projectId: event.target.value }))}\n >\n <option value=\"\">All projects</option>\n {(catalog.data?.projects ?? []).map((project: LinearCatalogData[\"projects\"][number]) => (\n <option key={project.id} value={project.id}>{project.name}</option>\n ))}\n </select>\n </div>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"linear-assignee-filter\">Assignee</label>\n <select\n id=\"linear-assignee-filter\"\n style={layoutStyles.select}\n value={filters.assigneeId}\n onChange={(event) => setFilters((current) => ({ ...current, assigneeId: event.target.value }))}\n >\n <option value=\"\">Anyone</option>\n {(catalog.data?.users ?? []).map((user: LinearCatalogData[\"users\"][number]) => (\n <option key={user.id} value={user.id}>{user.name}</option>\n ))}\n </select>\n </div>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"linear-query-filter\">Search</label>\n <input\n id=\"linear-query-filter\"\n style={layoutStyles.input}\n value={filters.query}\n onChange={(event) => setFilters((current) => ({ ...current, query: event.target.value }))}\n placeholder=\"Identifier, title, or description\"\n />\n </div>\n </div>\n </section>\n\n <section style={layoutStyles.card}>\n <div style={{ ...layoutStyles.row, justifyContent: \"space-between\" }}>\n <div style={layoutStyles.row}>\n <button\n type=\"button\"\n style={layoutStyles.button}\n onClick={() => {\n const rows = issues.data?.rows ?? [];\n const selectableIds = rows\n .filter((row: LinearIssueRow) => !row.imported)\n .map((row: LinearIssueRow) => row.id);\n setSelectedIssueIds(selectableIds);\n }}\n disabled={issues.loading}\n >\n Select current page\n </button>\n <button\n type=\"button\"\n style={layoutStyles.button}\n onClick={() => setSelectedIssueIds([])}\n disabled={selectedIssueIds.length === 0}\n >\n Clear selection\n </button>\n </div>\n <div style={layoutStyles.row}>\n <button\n type=\"button\"\n style={layoutStyles.button}\n disabled={!targetProjectId || selectedIssueIds.length === 0 || importing}\n onClick={() => void handleImport(\"selected\", selectedIssueIds)}\n >\n Import selected\n </button>\n <button\n type=\"button\"\n style={layoutStyles.primaryButton}\n data-testid=\"linear-import-all\"\n disabled={!targetProjectId || importing}\n onClick={() => void handleImport(\"allMatching\")}\n title={`Imports up to ${LINEAR_IMPORT_ALL_LIMIT} matching issues.`}\n >\n Import all matching\n </button>\n </div>\n </div>\n {!targetProjectId && (\n <div style={{ marginTop: 12, ...layoutStyles.warning }}>\n Choose a target Rudder project to enable per-row, selected, or all-matching import actions.\n </div>\n )}\n </section>\n\n <section style={layoutStyles.card}>\n {issues.loading ? (\n <div>Loading Linear issues\u2026</div>\n ) : issues.error ? (\n <div style={layoutStyles.warning}>{issues.error.message}</div>\n ) : (\n <>\n <table style={layoutStyles.table}>\n <thead>\n <tr>\n <th style={layoutStyles.th}></th>\n <th style={layoutStyles.th}>Issue</th>\n <th style={layoutStyles.th}>State</th>\n <th style={layoutStyles.th}>Project</th>\n <th style={layoutStyles.th}>Assignee</th>\n <th style={layoutStyles.th}>Status</th>\n <th style={layoutStyles.th}>Action</th>\n </tr>\n </thead>\n <tbody>\n {(issues.data?.rows ?? []).map((row: LinearIssueRow) => {\n const checked = selectedIssueIds.includes(row.id);\n const sameOrgLink = row.imported && (!row.importedOrgId || row.importedOrgId === context.orgId);\n return (\n <tr key={row.id}>\n <td style={layoutStyles.td}>\n <input\n type=\"checkbox\"\n checked={checked}\n disabled={row.imported}\n onChange={(event) => {\n setSelectedIssueIds((current) => {\n if (event.target.checked) return [...current, row.id];\n return current.filter((id) => id !== row.id);\n });\n }}\n />\n </td>\n <td style={layoutStyles.td}>\n <div style={{ display: \"grid\", gap: 6 }}>\n <a href={row.url} target=\"_blank\" rel=\"noreferrer\">\n <strong>{row.identifier}</strong> {row.title}\n </a>\n <span style={layoutStyles.pill}>{row.team.name}</span>\n </div>\n </td>\n <td style={layoutStyles.td}>{row.state.name}</td>\n <td style={layoutStyles.td}>{row.project?.name ?? \"None\"}</td>\n <td style={layoutStyles.td}>{row.assignee?.name ?? \"Unassigned\"}</td>\n <td style={layoutStyles.td}>\n {row.imported ? (\n <span data-testid={`linear-imported-${row.id}`} style={layoutStyles.pill}>\n Imported\n </span>\n ) : (\n <span style={layoutStyles.pill}>Ready</span>\n )}\n </td>\n <td style={layoutStyles.td}>\n {row.imported ? (\n sameOrgLink && row.importedRudderIssueId ? (\n <a href={issueHref(orgPrefix, row.importedRudderIssueId)}>Open Rudder issue</a>\n ) : (\n <span>Imported elsewhere</span>\n )\n ) : (\n <button\n type=\"button\"\n style={layoutStyles.subtleButton}\n disabled={!targetProjectId || importing}\n onClick={() => void handleImport(\"single\", [row.id])}\n >\n Import\n </button>\n )}\n </td>\n </tr>\n );\n })}\n </tbody>\n </table>\n\n {(issues.data?.rows.length ?? 0) === 0 && (\n <div style={{ marginTop: 16, color: \"rgba(15, 23, 42, 0.68)\" }}>\n No Linear issues matched the current filters.\n </div>\n )}\n\n <div style={{ ...layoutStyles.row, justifyContent: \"space-between\", marginTop: 16 }}>\n <span style={{ fontSize: 13, color: \"rgba(15, 23, 42, 0.68)\" }}>\n Showing {issues.data?.totalShown ?? 0} issue(s).\n </span>\n <div style={layoutStyles.row}>\n <button\n type=\"button\"\n style={layoutStyles.button}\n disabled={cursorHistory.length === 0 || importing}\n onClick={() => {\n setCursorHistory((current) => {\n const nextHistory = [...current];\n const previousCursor = nextHistory.pop() ?? null;\n setAfterCursor(previousCursor);\n return nextHistory;\n });\n }}\n >\n Previous\n </button>\n <button\n type=\"button\"\n style={layoutStyles.button}\n disabled={!issues.data?.hasNextPage || importing}\n onClick={() => {\n if (!issues.data?.endCursor) return;\n setCursorHistory((current) => [...current, afterCursor ?? \"\"]);\n setAfterCursor(issues.data.endCursor);\n }}\n >\n Next\n </button>\n </div>\n </div>\n </>\n )}\n </section>\n </>\n )}\n </div>\n );\n}\n\nexport function LinearIssueTab({ context }: PluginDetailTabProps) {\n const orgId = context.orgId ?? \"__missing__\";\n const orgPrefix = getOrgPrefix(context as unknown as Record<string, unknown>);\n const data = usePluginData<IssueLinkData>(DATA_KEYS.issueLink, {\n orgId,\n issueId: context.entityId,\n });\n\n if (data.loading) {\n return <div style={layoutStyles.card}>Loading Linear issue details\u2026</div>;\n }\n\n if (data.error) {\n return <div style={{ ...layoutStyles.card, ...layoutStyles.warning }}>{data.error.message}</div>;\n }\n\n if (!data.data || !data.data.linked) {\n return (\n <div style={layoutStyles.card}>\n <h2 style={{ marginTop: 0 }}>No linked Linear issue</h2>\n <p style={layoutStyles.subtitle}>\n This Rudder issue has not been imported from Linear yet.\n </p>\n <a href={pageHref(orgPrefix, data.data?.searchQuery ?? \"\")}>Open Linear intake with this issue title as the search query</a>\n </div>\n );\n }\n\n const latest = data.data.latestIssue;\n const link = data.data.link;\n\n return (\n <div style={layoutStyles.shell}>\n <section style={layoutStyles.card}>\n <h2 style={{ marginTop: 0 }}>Linked Linear issue</h2>\n <p style={layoutStyles.subtitle}>\n {link.linearIdentifier} maps to this Rudder issue.\n </p>\n <div style={{ ...layoutStyles.row, marginTop: 12 }}>\n <a href={link.linearUrl} target=\"_blank\" rel=\"noreferrer\">Open in Linear</a>\n <span style={layoutStyles.pill}>{latest?.team.name ?? link.teamName}</span>\n <span style={layoutStyles.pill}>{latest?.state.name ?? link.stateName}</span>\n {latest?.project?.name ? <span style={layoutStyles.pill}>{latest.project.name}</span> : null}\n </div>\n </section>\n\n {data.data.staleReason ? (\n <section style={{ ...layoutStyles.card, ...layoutStyles.warning }}>\n {data.data.staleReason}\n </section>\n ) : null}\n\n <section style={layoutStyles.card}>\n <h3 style={{ marginTop: 0 }}>\n {(latest?.identifier ?? link.linearIdentifier)} {latest?.title ?? link.linearTitle}\n </h3>\n <div style={{ ...layoutStyles.row, marginBottom: 12 }}>\n <span style={layoutStyles.pill}>Updated {formatRelativeTime(latest?.updatedAt ?? link.updatedAt)}</span>\n <span style={layoutStyles.pill}>Imported {formatRelativeTime(link.importedAt)}</span>\n <span style={layoutStyles.pill}>{latest?.assignee?.name ?? \"Unassigned\"}</span>\n </div>\n <div style={{ whiteSpace: \"pre-wrap\", lineHeight: 1.6 }}>\n {latest?.description?.trim() || \"This Linear issue has no description.\"}\n </div>\n </section>\n </div>\n );\n}\n\nexport function LinearPluginSettingsPage(_props: PluginSettingsPageProps) {\n const toast = usePluginToast();\n const bootstrap = usePluginData<SettingsBootstrapData>(DATA_KEYS.settingsBootstrap);\n const [draft, setDraft] = useState<LinearPluginConfig>(normalizeConfig(null));\n const [tokenInput, setTokenInput] = useState(\"\");\n const [settingsCatalog, setSettingsCatalog] = useState<SettingsCatalogData | null>(null);\n const [catalogLoading, setCatalogLoading] = useState(false);\n const [catalogError, setCatalogError] = useState<string | null>(null);\n const [connecting, setConnecting] = useState(false);\n const [saving, setSaving] = useState(false);\n const pluginId = getPluginIdFromLocation();\n\n useEffect(() => {\n if (!bootstrap.data) return;\n const nextDraft = normalizeConfig(bootstrap.data.config);\n setDraft(nextDraft);\n }, [bootstrap.data]);\n\n useEffect(() => {\n if (!pluginId || !draft.apiTokenSecretRef) {\n setSettingsCatalog(null);\n setCatalogError(null);\n setCatalogLoading(false);\n return;\n }\n\n let cancelled = false;\n setCatalogLoading(true);\n setCatalogError(null);\n\n void fetchSettingsCatalog()\n .then((catalog) => {\n if (cancelled) return;\n setSettingsCatalog(catalog);\n setDraft((current) => {\n const normalized = normalizeConfig(current);\n const selectedTeamIds = normalized.teamMappings\n .map((team) => team.teamId)\n .filter(Boolean);\n const nextTeamMappings = selectedTeamIds.length > 0\n ? buildTeamMappingsForSelectedTeams(catalog, selectedTeamIds, normalized.teamMappings)\n : buildTeamMappingsFromCatalog(catalog);\n return {\n ...normalized,\n teamMappings: nextTeamMappings,\n };\n });\n })\n .catch((error) => {\n if (cancelled) return;\n setSettingsCatalog(null);\n setCatalogError(error instanceof Error ? error.message : String(error));\n })\n .finally(() => {\n if (!cancelled) setCatalogLoading(false);\n });\n\n return () => {\n cancelled = true;\n };\n }, [draft.apiTokenSecretRef, pluginId]);\n\n const selectedTeamIds = draft.teamMappings\n .map((team) => team.teamId)\n .filter(Boolean);\n const selectedTeamIdSet = new Set(selectedTeamIds);\n const selectedTeamCount = selectedTeamIds.length;\n const catalogTeamCount = settingsCatalog?.teams.length ?? 0;\n const issueBoardHref = linearIssueBoardHref(\n bootstrap.data?.organizations[0]?.issuePrefix ?? null,\n selectedTeamIds[0] ?? null,\n );\n\n async function savePluginConfig(config: LinearPluginConfig) {\n if (!pluginId) throw new Error(\"Unable to resolve plugin id\");\n return await apiFetch(`/api/plugins/${encodeURIComponent(pluginId)}/config`, {\n method: \"POST\",\n body: JSON.stringify({ configJson: prepareConfigForSubmit(config) }),\n });\n }\n\n async function listOrgSecrets(orgId: string): Promise<SecretSummary[]> {\n return await apiFetch<SecretSummary[]>(`/api/orgs/${encodeURIComponent(orgId)}/secrets`);\n }\n\n async function rotateSecret(secretId: string, value: string): Promise<SecretSummary> {\n return await apiFetch<SecretSummary>(`/api/secrets/${encodeURIComponent(secretId)}/rotate`, {\n method: \"POST\",\n body: JSON.stringify({ value }),\n });\n }\n\n async function createLinearTokenSecret(orgId: string, value: string): Promise<SecretSummary> {\n return await apiFetch<SecretSummary>(`/api/orgs/${encodeURIComponent(orgId)}/secrets`, {\n method: \"POST\",\n body: JSON.stringify({\n name: LINEAR_TOKEN_SECRET_NAME,\n value,\n description: \"Used by the Linear plugin to read issues across Rudder organizations.\",\n }),\n });\n }\n\n async function saveLinearTokenSecret(orgId: string, value: string, currentSecretRef: string): Promise<string> {\n if (currentSecretRef) {\n const rotated = await rotateSecret(currentSecretRef, value);\n return rotated.id;\n }\n\n try {\n const created = await createLinearTokenSecret(orgId, value);\n return created.id;\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n if (!/Secret already exists/i.test(message)) throw error;\n\n const existing = (await listOrgSecrets(orgId)).find((secret) => secret.name === LINEAR_TOKEN_SECRET_NAME);\n if (!existing) throw error;\n const rotated = await rotateSecret(existing.id, value);\n return rotated.id;\n }\n }\n\n async function fetchPluginData<T>(key: string, params: Record<string, unknown> = {}, orgId?: string): Promise<T> {\n if (!pluginId) throw new Error(\"Unable to resolve plugin id\");\n const payload = await apiFetch<{ data: T }>(`/api/plugins/${encodeURIComponent(pluginId)}/data/${key}`, {\n method: \"POST\",\n body: JSON.stringify({\n ...(orgId ? { orgId } : {}),\n params: {\n ...params,\n ...(orgId ? { orgId } : {}),\n },\n }),\n });\n return payload.data;\n }\n\n async function fetchSettingsCatalogWithRetry(): Promise<SettingsCatalogData> {\n let lastError: unknown = null;\n for (let attempt = 0; attempt < 5; attempt += 1) {\n try {\n return await fetchPluginData<SettingsCatalogData>(DATA_KEYS.settingsCatalog);\n } catch (error) {\n if (isMissingSettingsCatalogHandler(error)) throw error;\n lastError = error;\n await new Promise((resolve) => window.setTimeout(resolve, 350 + attempt * 250));\n }\n }\n throw lastError instanceof Error ? lastError : new Error(String(lastError));\n }\n\n async function refreshPluginRuntime() {\n if (!pluginId) throw new Error(\"Unable to resolve plugin id\");\n await apiFetch(`/api/plugins/${encodeURIComponent(pluginId)}/disable`, {\n method: \"POST\",\n body: JSON.stringify({ reason: \"Refresh Linear plugin after settings update\" }),\n });\n await apiFetch(`/api/plugins/${encodeURIComponent(pluginId)}/enable`, {\n method: \"POST\",\n body: JSON.stringify({}),\n });\n }\n\n async function fetchSettingsCatalog(): Promise<SettingsCatalogData> {\n try {\n return await fetchSettingsCatalogWithRetry();\n } catch (error) {\n if (!isMissingSettingsCatalogHandler(error)) throw error;\n await refreshPluginRuntime();\n return await fetchSettingsCatalogWithRetry();\n }\n }\n\n function toggleTeam(teamId: string) {\n if (!settingsCatalog) return;\n setDraft((current) => {\n const normalized = normalizeConfig(current);\n const nextTeamIds = new Set(normalized.teamMappings.map((team) => team.teamId).filter(Boolean));\n if (nextTeamIds.has(teamId)) {\n nextTeamIds.delete(teamId);\n } else {\n nextTeamIds.add(teamId);\n }\n return {\n ...normalized,\n teamMappings: buildTeamMappingsForSelectedTeams(settingsCatalog, [...nextTeamIds], normalized.teamMappings),\n };\n });\n }\n\n function selectAllTeams() {\n if (!settingsCatalog) return;\n setDraft((current) => {\n const normalized = normalizeConfig(current);\n return {\n ...normalized,\n teamMappings: buildTeamMappingsForSelectedTeams(\n settingsCatalog,\n settingsCatalog.teams.map((team) => team.id),\n normalized.teamMappings,\n ),\n };\n });\n }\n\n function setStatusRule(teamId: string, stateId: string, rudderStatus: LinearStateMapping[\"rudderStatus\"]) {\n setDraft((current) => ({\n ...current,\n teamMappings: current.teamMappings.map((team) => {\n if (team.teamId !== teamId) return team;\n return {\n ...team,\n stateMappings: team.stateMappings.map((state) =>\n state.linearStateId === stateId ? { ...state, rudderStatus } : state,\n ),\n };\n }),\n }));\n }\n\n async function connectLinear() {\n if (!pluginId) {\n toast({ title: \"Unable to resolve plugin id\", tone: \"error\" });\n return;\n }\n\n setConnecting(true);\n try {\n let apiTokenSecretRef = draft.apiTokenSecretRef?.trim() ?? \"\";\n const trimmedToken = tokenInput.trim();\n if (trimmedToken) {\n const secretOrgId = bootstrap.data?.organizations[0]?.id ?? \"\";\n if (!secretOrgId) {\n toast({\n title: \"Create a Rudder organization first\",\n body: \"Rudder needs one organization to store the Linear token reference.\",\n tone: \"warn\",\n });\n return;\n }\n apiTokenSecretRef = await saveLinearTokenSecret(secretOrgId, trimmedToken, apiTokenSecretRef);\n }\n if (!apiTokenSecretRef) {\n toast({\n title: \"Paste a Linear token\",\n body: \"Create one in Linear, paste it here, then connect.\",\n tone: \"warn\",\n });\n return;\n }\n\n const seedConfig = {\n ...draft,\n apiTokenSecretRef,\n };\n await savePluginConfig(seedConfig);\n\n const catalog = await fetchSettingsCatalog();\n if (catalog.teams.length === 0) {\n throw new Error(\"Linear returned no teams for this token.\");\n }\n const generatedTeamMappings = buildTeamMappingsFromCatalog(catalog);\n const nextConfig = prepareConfigForSubmit({\n ...seedConfig,\n teamMappings: generatedTeamMappings,\n });\n await savePluginConfig(nextConfig);\n setSettingsCatalog(catalog);\n setCatalogError(null);\n setDraft(nextConfig);\n setTokenInput(\"\");\n bootstrap.refresh();\n const firstTeamId = generatedTeamMappings[0]?.teamId ?? null;\n const firstOrgPrefix = bootstrap.data?.organizations[0]?.issuePrefix ?? null;\n toast({\n title: \"Linear is ready\",\n body: summarizeMapping(generatedTeamMappings),\n tone: \"success\",\n action: {\n label: \"Open Linear issues\",\n href: linearIssueBoardHref(firstOrgPrefix, firstTeamId),\n },\n });\n } catch (error) {\n toast({\n title: \"Linear connection failed\",\n body: error instanceof Error ? error.message : String(error),\n tone: \"error\",\n });\n } finally {\n setConnecting(false);\n }\n }\n\n async function saveConfig() {\n if (!pluginId) {\n toast({ title: \"Unable to resolve plugin id\", tone: \"error\" });\n return;\n }\n if (draft.apiTokenSecretRef && settingsCatalog && selectedTeamCount === 0) {\n toast({\n title: \"Choose at least one Linear team\",\n body: \"The import page needs one or more teams to show Linear issues.\",\n tone: \"warn\",\n });\n return;\n }\n setSaving(true);\n try {\n await savePluginConfig(draft);\n bootstrap.refresh();\n toast({\n title: \"Linear settings saved\",\n tone: \"success\",\n });\n } catch (error) {\n toast({\n title: \"Failed to save Linear settings\",\n body: error instanceof Error ? error.message : String(error),\n tone: \"error\",\n });\n } finally {\n setSaving(false);\n }\n }\n\n function connectionStatusText(): string {\n if (bootstrap.loading) return \"Loading plugin settings\u2026\";\n if (catalogLoading) return \"Reading teams and workflow states from Linear\u2026\";\n if (catalogError) return `Linear could not be loaded: ${catalogError}`;\n if (settingsCatalog) {\n return `Connected. ${catalogTeamCount} Linear team${catalogTeamCount === 1 ? \"\" : \"s\"} found; ${selectedTeamCount} selected for import.`;\n }\n if (draft.apiTokenSecretRef) return \"Token saved. Refresh from Linear to load teams.\";\n return \"Paste a Linear token to connect this instance.\";\n }\n\n return (\n <div style={layoutStyles.shell}>\n <section key=\"linear-settings-intro\" style={layoutStyles.card}>\n <h2 style={{ marginTop: 0 }}>Linear</h2>\n <p style={layoutStyles.subtitle}>\n Paste a Linear token once. Rudder will read your teams and workflow states, then prepare the import settings automatically.\n </p>\n {bootstrap.data?.fixtureMode ? (\n <div style={{ marginTop: 12, ...layoutStyles.warning }}>\n Fixture mode is enabled in this environment. Linear reads use deterministic test data.\n </div>\n ) : null}\n </section>\n\n <section key=\"linear-settings-connect\" style={layoutStyles.card}>\n <div style={layoutStyles.sectionHeader}>\n <div>\n <h3 style={{ margin: 0 }}>Connect Linear</h3>\n <p style={layoutStyles.subtitle}>\n Paste a token and Rudder will prepare the import setup from Linear.{\" \"}\n <a href={LINEAR_TOKEN_SETTINGS_URL} target=\"_blank\" rel=\"noreferrer\" style={layoutStyles.monoLink}>\n Create a Linear token\n </a>\n .\n </p>\n </div>\n </div>\n <div style={{ ...layoutStyles.connectionGrid, marginTop: 14 }}>\n <div style={layoutStyles.field}>\n <label style={layoutStyles.label} htmlFor=\"linear-token\">Linear token</label>\n <input\n id=\"linear-token\"\n data-testid=\"linear-token-input\"\n style={layoutStyles.input}\n type=\"password\"\n autoComplete=\"off\"\n value={tokenInput}\n onChange={(event) => setTokenInput(event.target.value)}\n placeholder={draft.apiTokenSecretRef ? \"Token saved. Paste a new token to replace it.\" : \"Paste a Linear token\"}\n />\n </div>\n <div style={{ display: \"grid\", gap: 6, justifySelf: \"start\" }}>\n <span aria-hidden=\"true\" style={{ ...layoutStyles.label, visibility: \"hidden\" }}>Action</span>\n <button\n type=\"button\"\n style={layoutStyles.primaryButton}\n data-testid=\"linear-connect\"\n onClick={() => void connectLinear()}\n disabled={connecting}\n >\n {connecting ? \"Connecting\u2026\" : draft.apiTokenSecretRef ? \"Refresh from Linear\" : \"Connect Linear\"}\n </button>\n </div>\n </div>\n <div style={{ ...layoutStyles.statusLine, display: \"flex\", alignItems: \"center\", justifyContent: \"space-between\", gap: 12, flexWrap: \"wrap\" }}>\n <span>{connectionStatusText()}</span>\n {settingsCatalog && selectedTeamCount > 0 ? (\n <a href={issueBoardHref} style={layoutStyles.monoLink}>Open Linear issues</a>\n ) : null}\n </div>\n </section>\n\n {draft.apiTokenSecretRef ? (\n <section key=\"linear-settings-teams\" style={layoutStyles.card}>\n <div style={layoutStyles.sectionHeader}>\n <div>\n <h3 style={{ margin: 0 }}>Teams to import</h3>\n <p style={layoutStyles.subtitle}>\n Choose the Linear teams that should appear on the import page. Rudder stores the technical details for you.\n </p>\n </div>\n <button\n type=\"button\"\n style={layoutStyles.subtleButton}\n onClick={selectAllTeams}\n disabled={!settingsCatalog || catalogLoading || catalogTeamCount === selectedTeamCount}\n >\n Select all teams\n </button>\n </div>\n\n {catalogLoading ? (\n <p style={layoutStyles.helpText}>Loading teams from Linear\u2026</p>\n ) : catalogError ? (\n <div style={{ marginTop: 14, ...layoutStyles.warning }}>\n <strong>Linear could not be loaded.</strong>\n <div style={{ marginTop: 6 }}>{catalogError}</div>\n </div>\n ) : settingsCatalog ? (\n <>\n <div style={layoutStyles.teamGrid}>\n {settingsCatalog.teams.map((team, index) => {\n const checked = selectedTeamIdSet.has(team.id);\n return (\n <label\n key={`${team.id}-${index}`}\n style={{\n ...layoutStyles.teamChoice,\n borderColor: checked ? \"var(--primary, #2563eb)\" : \"var(--border, rgba(15, 23, 42, 0.14))\",\n background: checked ? \"rgba(37, 99, 235, 0.08)\" : \"var(--background, transparent)\",\n }}\n >\n <input\n data-testid={`linear-team-choice-${team.id}`}\n style={layoutStyles.checkbox}\n type=\"checkbox\"\n checked={checked}\n onChange={() => toggleTeam(team.id)}\n />\n <span>\n <strong>{team.name}</strong>\n <span style={{ display: \"block\", marginTop: 3, ...layoutStyles.helpText }}>\n {team.key} \u00B7 {team.states.length} workflow state{team.states.length === 1 ? \"\" : \"s\"}\n </span>\n </span>\n </label>\n );\n })}\n </div>\n <div style={{ ...layoutStyles.row, justifyContent: \"space-between\", marginTop: 14 }}>\n <span style={layoutStyles.helpText}>\n {selectedTeamCount === 0\n ? \"Choose at least one team before saving.\"\n : `${selectedTeamCount} team${selectedTeamCount === 1 ? \"\" : \"s\"} selected for import.`}\n </span>\n <button\n type=\"button\"\n style={layoutStyles.primaryButton}\n data-testid=\"linear-save-team-choices\"\n onClick={() => void saveConfig()}\n disabled={saving || selectedTeamCount === 0}\n >\n {saving ? \"Saving\u2026\" : \"Save choices\"}\n </button>\n </div>\n </>\n ) : (\n <p style={layoutStyles.helpText}>Refresh from Linear to load teams for this token.</p>\n )}\n </section>\n ) : null}\n\n {settingsCatalog && draft.teamMappings.length > 0 ? (\n <section key=\"linear-settings-status-rules\" style={layoutStyles.card}>\n <details>\n <summary style={{ cursor: \"pointer\", fontWeight: 700 }}>Status rules (optional)</summary>\n <p style={layoutStyles.subtitle}>\n Rudder applies smart defaults from Linear. Change these only if imported issues land in the wrong Rudder status.\n </p>\n <div style={{ display: \"grid\", gap: 18, marginTop: 14 }}>\n {draft.teamMappings.map((teamMapping, teamIndex) => {\n const catalogTeam = settingsCatalog.teams.find((team) => team.id === teamMapping.teamId);\n const states = catalogTeam?.states ?? teamMapping.stateMappings.map((state) => ({\n id: state.linearStateId,\n name: state.linearStateName ?? \"Linear status\",\n type: null,\n }));\n const statusByStateId = new Map(teamMapping.stateMappings.map((state) => [state.linearStateId, state.rudderStatus]));\n return (\n <div key={`${teamMapping.teamId}-${teamIndex}`} style={{ borderTop: \"1px solid var(--border, rgba(15, 23, 42, 0.1))\", paddingTop: 14 }}>\n <h4 style={{ margin: \"0 0 10px\" }}>{teamMapping.teamName ?? catalogTeam?.name ?? \"Linear team\"}</h4>\n <div style={{ display: \"grid\", gap: 8 }}>\n {states.map((state, stateIndex) => (\n <div key={`${teamMapping.teamId}-${state.id}-${stateIndex}`} style={layoutStyles.statusRuleGrid}>\n <div>\n <strong>{state.name}</strong>\n <div style={layoutStyles.helpText}>{state.type ? `${state.type} in Linear` : \"Linear workflow state\"}</div>\n </div>\n <select\n style={layoutStyles.select}\n value={statusByStateId.get(state.id) ?? inferRudderStatus(state)}\n onChange={(event) =>\n setStatusRule(teamMapping.teamId, state.id, event.target.value as LinearStateMapping[\"rudderStatus\"])}\n >\n {RUDDER_STATUS_OPTIONS.map((status) => (\n <option key={`${teamMapping.teamId}-${state.id}-${status}`} value={status}>{formatRudderStatus(status)}</option>\n ))}\n </select>\n </div>\n ))}\n </div>\n </div>\n );\n })}\n </div>\n <div style={{ marginTop: 14 }}>\n <button type=\"button\" style={layoutStyles.primaryButton} onClick={() => void saveConfig()} disabled={saving}>\n {saving ? \"Saving\u2026\" : \"Save status rules\"}\n </button>\n </div>\n </details>\n </section>\n ) : null}\n </div>\n );\n}\n", "import type { Issue } from \"@rudderhq/shared\";\n\nexport const PLUGIN_ID = \"rudder.linear\";\nexport const PLUGIN_VERSION = \"0.1.0\";\nexport const PAGE_ROUTE = \"linear\";\nexport const ENTITY_TYPE_LINEAR_ISSUE_LINK = \"linear_issue_link\";\nexport const ISSUE_LINK_STATE_KEY = \"linear-link\";\nexport const DEFAULT_LINEAR_API_URL = \"https://api.linear.app/graphql\";\nexport const LINEAR_TOKEN_SETTINGS_URL = \"https://linear.app/settings/account/security\";\nexport const LINEAR_PAGE_SIZE = 25;\nexport const LINEAR_IMPORT_ALL_LIMIT = 100;\n\nexport const SLOT_IDS = {\n page: \"linear-page\",\n settingsPage: \"linear-settings-page\",\n issueTab: \"linear-issue-tab\",\n} as const;\n\nexport const EXPORT_NAMES = {\n page: \"LinearPluginPage\",\n settingsPage: \"LinearPluginSettingsPage\",\n issueTab: \"LinearIssueTab\",\n} as const;\n\nexport const DATA_KEYS = {\n settingsBootstrap: \"settings-bootstrap\",\n pageBootstrap: \"page-bootstrap\",\n settingsCatalog: \"settings-catalog\",\n catalog: \"linear-catalog\",\n issues: \"linear-issues\",\n issueLink: \"issue-link\",\n} as const;\n\nexport const ACTION_KEYS = {\n importIssues: \"import-linear-issues\",\n} as const;\n\nexport const RUDDER_STATUS_OPTIONS: Issue[\"status\"][] = [\n \"backlog\",\n \"todo\",\n \"in_progress\",\n \"in_review\",\n \"done\",\n \"blocked\",\n \"cancelled\",\n];\n"],
|
|
5
5
|
"mappings": "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",
|
|
6
6
|
"names": ["selectedTeamIds"]
|
|
7
7
|
}
|